PageSourceSearch

https://jetkurevdenevenakliyat.com.tr/js/Chart.bundle.js

js jetkurevdenevenakliyat.com.tr collected 2026-09-29 22:07:39 UTC 535,332 bytes, 18,919 lines download raw bytes

1/*!
2 * Chart.js
3 * http://chartjs.org/
4 * Version: 2.7.2
5 *
6 * Copyright 2018 Chart.js Contributors
7 * Released under the MIT license
8 * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
9 */
10(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart = f()}})(function(){var define,module,exports;return (function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){
11/* MIT license */
12var colorNames = require(5);
13
14module.exports = {
15   getRgba: getRgba,
16   getHsla: getHsla,
17   getRgb: getRgb,
18   getHsl: getHsl,
19   getHwb: getHwb,
20   getAlpha: getAlpha,
21
22   hexString: hexString,
23   rgbString: rgbString,
24   rgbaString: rgbaString,
25   percentString: percentString,
26   percentaString: percentaString,
27   hslString: hslString,
28   hslaString: hslaString,
29   hwbString: hwbString,
30   keyword: keyword
31}
32
33function getRgba(string) {
34   if (!string) {
35      return;
36   }
37   var abbr =  /^#([a-fA-F0-9]{3})$/i,
38       hex =  /^#([a-fA-F0-9]{6})$/i,
39       rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
40       per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
41       keyword = /(\w+)/;
42
43   var rgb = [0, 0, 0],
44       a = 1,
45       match = string.match(abbr);
46   if (match) {
47      match = match[1];
48      for (var i = 0; i < rgb.length; i++) {
49         rgb[i] = parseInt(match[i] + match[i], 16);
50      }
51   }
52   else if (match = string.match(hex)) {
53      match = match[1];
54      for (var i = 0; i < rgb.length; i++) {
55         rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
56      }
57   }
58   else if (match = string.match(rgba)) {
59      for (var i = 0; i < rgb.length; i++) {
60         rgb[i] = parseInt(match[i + 1]);
61      }
62      a = parseFloat(match[4]);
63   }
64   else if (match = string.match(per)) {
65      for (var i = 0; i < rgb.length; i++) {
66         rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
67      }
68      a = parseFloat(match[4]);
69   }
70   else if (match = string.match(keyword)) {
71      if (match[1] == "transparent") {
72         return [0, 0, 0, 0];
73      }
74      rgb = colorNames[match[1]];
75      if (!rgb) {
76         return;
77      }
78   }
79
80   for (var i = 0; i < rgb.length; i++) {
81      rgb[i] = scale(rgb[i], 0, 255);
82   }
83   if (!a && a != 0) {
84      a = 1;
85   }
86   else {
87      a = scale(a, 0, 1);
88   }
89   rgb[3] = a;
90   return rgb;
91}
92
93function getHsla(string) {
94   if (!string) {
95      return;
96   }
97   var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
98   var match = string.match(hsl);
99   if (match) {
100      var alpha = parseFloat(match[4]);
101      var h = scale(parseInt(match[1]), 0, 360),
102          s = scale(parseFloat(match[2]), 0, 100),
103          l = scale(parseFloat(match[3]), 0, 100),
104          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
105      return [h, s, l, a];
106   }
107}
108
109function getHwb(string) {
110   if (!string) {
111      return;
112   }
113   var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
114   var match = string.match(hwb);
115   if (match) {
116    var alpha = parseFloat(match[4]);
117      var h = scale(parseInt(match[1]), 0, 360),
118          w = scale(parseFloat(match[2]), 0, 100),
119          b = scale(parseFloat(match[3]), 0, 100),
120          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
121      return [h, w, b, a];
122   }
123}
124
125function getRgb(string) {
126   var rgba = getRgba(string);
127   return rgba && rgba.slice(0, 3);
128}
129
130function getHsl(string) {
131  var hsla = getHsla(string);
132  return hsla && hsla.slice(0, 3);
133}
134
135function getAlpha(string) {
136   var vals = getRgba(string);
137   if (vals) {
138      return vals[3];
139   }
140   else if (vals = getHsla(string)) {
141      return vals[3];
142   }
143   else if (vals = getHwb(string)) {
144      return vals[3];
145   }
146}
147
148// generators
149function hexString(rgb) {
150   return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
151              + hexDouble(rgb[2]);
152}
153
154function rgbString(rgba, alpha) {
vendor: 14,231 bytes, lines 155-759
155   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
156      return rgbaString(rgba, alpha);
157   }
158   return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
159}
160
161function rgbaString(rgba, alpha) {
162   if (alpha === undefined) {
163      alpha = (rgba[3] !== undefined ? rgba[3] : 1);
164   }
165   return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
166           + ", " + alpha + ")";
167}
168
169function percentString(rgba, alpha) {
170   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
171      return percentaString(rgba, alpha);
172   }
173   var r = Math.round(rgba[0]/255 * 100),
174       g = Math.round(rgba[1]/255 * 100),
175       b = Math.round(rgba[2]/255 * 100);
176
177   return "rgb(" + r + "%, " + g + "%, " + b + "%)";
178}
179
180function percentaString(rgba, alpha) {
181   var r = Math.round(rgba[0]/255 * 100),
182       g = Math.round(rgba[1]/255 * 100),
183       b = Math.round(rgba[2]/255 * 100);
184   return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
185}
186
187function hslString(hsla, alpha) {
188   if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
189      return hslaString(hsla, alpha);
190   }
191   return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
192}
193
194function hslaString(hsla, alpha) {
195   if (alpha === undefined) {
196      alpha = (hsla[3] !== undefined ? hsla[3] : 1);
197   }
198   return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
199           + alpha + ")";
200}
201
202// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
203// (hwb have alpha optional & 1 is default value)
204function hwbString(hwb, alpha) {
205   if (alpha === undefined) {
206      alpha = (hwb[3] !== undefined ? hwb[3] : 1);
207   }
208   return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
209           + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
210}
211
212function keyword(rgb) {
213  return reverseNames[rgb.slice(0, 3)];
214}
215
216// helpers
217function scale(num, min, max) {
218   return Math.min(Math.max(min, num), max);
219}
220
221function hexDouble(num) {
222  var str = num.toString(16).toUpperCase();
223  return (str.length < 2) ? "0" + str : str;
224}
225
226
227//create a list of reverse color names
228var reverseNames = {};
229for (var name in colorNames) {
230   reverseNames[colorNames[name]] = name;
231}
232
233},{"5":5}],2:[function(require,module,exports){
234/* MIT license */
235var convert = require(4);
236var string = require(1);
237
238var Color = function (obj) {
239	if (obj instanceof Color) {
240		return obj;
241	}
242	if (!(this instanceof Color)) {
243		return new Color(obj);
244	}
245
246	this.valid = false;
247	this.values = {
248		rgb: [0, 0, 0],
249		hsl: [0, 0, 0],
250		hsv: [0, 0, 0],
251		hwb: [0, 0, 0],
252		cmyk: [0, 0, 0, 0],
253		alpha: 1
254	};
255
256	// parse Color() argument
257	var vals;
258	if (typeof obj === 'string') {
259		vals = string.getRgba(obj);
260		if (vals) {
261			this.setValues('rgb', vals);
262		} else if (vals = string.getHsla(obj)) {
263			this.setValues('hsl', vals);
264		} else if (vals = string.getHwb(obj)) {
265			this.setValues('hwb', vals);
266		}
267	} else if (typeof obj === 'object') {
268		vals = obj;
269		if (vals.r !== undefined || vals.red !== undefined) {
270			this.setValues('rgb', vals);
271		} else if (vals.l !== undefined || vals.lightness !== undefined) {
272			this.setValues('hsl', vals);
273		} else if (vals.v !== undefined || vals.value !== undefined) {
274			this.setValues('hsv', vals);
275		} else if (vals.w !== undefined || vals.whiteness !== undefined) {
276			this.setValues('hwb', vals);
277		} else if (vals.c !== undefined || vals.cyan !== undefined) {
278			this.setValues('cmyk', vals);
279		}
280	}
281};
282
283Color.prototype = {
284	isValid: function () {
285		return this.valid;
286	},
287	rgb: function () {
288		return this.setSpace('rgb', arguments);
289	},
290	hsl: function () {
291		return this.setSpace('hsl', arguments);
292	},
293	hsv: function () {
294		return this.setSpace('hsv', arguments);
295	},
296	hwb: function () {
297		return this.setSpace('hwb', arguments);
298	},
299	cmyk: function () {
300		return this.setSpace('cmyk', arguments);
301	},
302
303	rgbArray: function () {
304		return this.values.rgb;
305	},
306	hslArray: function () {
307		return this.values.hsl;
308	},
309	hsvArray: function () {
310		return this.values.hsv;
311	},
312	hwbArray: function () {
313		var values = this.values;
314		if (values.alpha !== 1) {
315			return values.hwb.concat([values.alpha]);
316		}
317		return values.hwb;
318	},
319	cmykArray: function () {
320		return this.values.cmyk;
321	},
322	rgbaArray: function () {
323		var values = this.values;
324		return values.rgb.concat([values.alpha]);
325	},
326	hslaArray: function () {
327		var values = this.values;
328		return values.hsl.concat([values.alpha]);
329	},
330	alpha: function (val) {
331		if (val === undefined) {
332			return this.values.alpha;
333		}
334		this.setValues('alpha', val);
335		return this;
336	},
337
338	red: function (val) {
339		return this.setChannel('rgb', 0, val);
340	},
341	green: function (val) {
342		return this.setChannel('rgb', 1, val);
343	},
344	blue: function (val) {
345		return this.setChannel('rgb', 2, val);
346	},
347	hue: function (val) {
348		if (val) {
349			val %= 360;
350			val = val < 0 ? 360 + val : val;
351		}
352		return this.setChannel('hsl', 0, val);
353	},
354	saturation: function (val) {
355		return this.setChannel('hsl', 1, val);
356	},
357	lightness: function (val) {
358		return this.setChannel('hsl', 2, val);
359	},
360	saturationv: function (val) {
361		return this.setChannel('hsv', 1, val);
362	},
363	whiteness: function (val) {
364		return this.setChannel('hwb', 1, val);
365	},
366	blackness: function (val) {
367		return this.setChannel('hwb', 2, val);
368	},
369	value: function (val) {
370		return this.setChannel('hsv', 2, val);
371	},
372	cyan: function (val) {
373		return this.setChannel('cmyk', 0, val);
374	},
375	magenta: function (val) {
376		return this.setChannel('cmyk', 1, val);
377	},
378	yellow: function (val) {
379		return this.setChannel('cmyk', 2, val);
380	},
381	black: function (val) {
382		return this.setChannel('cmyk', 3, val);
383	},
384
385	hexString: function () {
386		return string.hexString(this.values.rgb);
387	},
388	rgbString: function () {
389		return string.rgbString(this.values.rgb, this.values.alpha);
390	},
391	rgbaString: function () {
392		return string.rgbaString(this.values.rgb, this.values.alpha);
393	},
394	percentString: function () {
395		return string.percentString(this.values.rgb, this.values.alpha);
396	},
397	hslString: function () {
398		return string.hslString(this.values.hsl, this.values.alpha);
399	},
400	hslaString: function () {
401		return string.hslaString(this.values.hsl, this.values.alpha);
402	},
403	hwbString: function () {
404		return string.hwbString(this.values.hwb, this.values.alpha);
405	},
406	keyword: function () {
407		return string.keyword(this.values.rgb, this.values.alpha);
408	},
409
410	rgbNumber: function () {
411		var rgb = this.values.rgb;
412		return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
413	},
414
415	luminosity: function () {
416		// http://www.w3.org/TR/WCAG20/#relativeluminancedef
417		var rgb = this.values.rgb;
418		var lum = [];
419		for (var i = 0; i < rgb.length; i++) {
420			var chan = rgb[i] / 255;
421			lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
422		}
423		return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
424	},
425
426	contrast: function (color2) {
427		// http://www.w3.org/TR/WCAG20/#contrast-ratiodef
428		var lum1 = this.luminosity();
429		var lum2 = color2.luminosity();
430		if (lum1 > lum2) {
431			return (lum1 + 0.05) / (lum2 + 0.05);
432		}
433		return (lum2 + 0.05) / (lum1 + 0.05);
434	},
435
436	level: function (color2) {
437		var contrastRatio = this.contrast(color2);
438		if (contrastRatio >= 7.1) {
439			return 'AAA';
440		}
441
442		return (contrastRatio >= 4.5) ? 'AA' : '';
443	},
444
445	dark: function () {
446		// YIQ equation from http://24ways.org/2010/calculating-color-contrast
447		var rgb = this.values.rgb;
448		var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
449		return yiq < 128;
450	},
451
452	light: function () {
453		return !this.dark();
454	},
455
456	negate: function () {
457		var rgb = [];
458		for (var i = 0; i < 3; i++) {
459			rgb[i] = 255 - this.values.rgb[i];
460		}
461		this.setValues('rgb', rgb);
462		return this;
463	},
464
465	lighten: function (ratio) {
466		var hsl = this.values.hsl;
467		hsl[2] += hsl[2] * ratio;
468		this.setValues('hsl', hsl);
469		return this;
470	},
471
472	darken: function (ratio) {
473		var hsl = this.values.hsl;
474		hsl[2] -= hsl[2] * ratio;
475		this.setValues('hsl', hsl);
476		return this;
477	},
478
479	saturate: function (ratio) {
480		var hsl = this.values.hsl;
481		hsl[1] += hsl[1] * ratio;
482		this.setValues('hsl', hsl);
483		return this;
484	},
485
486	desaturate: function (ratio) {
487		var hsl = this.values.hsl;
488		hsl[1] -= hsl[1] * ratio;
489		this.setValues('hsl', hsl);
490		return this;
491	},
492
493	whiten: function (ratio) {
494		var hwb = this.values.hwb;
495		hwb[1] += hwb[1] * ratio;
496		this.setValues('hwb', hwb);
497		return this;
498	},
499
500	blacken: function (ratio) {
501		var hwb = this.values.hwb;
502		hwb[2] += hwb[2] * ratio;
503		this.setValues('hwb', hwb);
504		return this;
505	},
506
507	greyscale: function () {
508		var rgb = this.values.rgb;
509		// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
510		var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
511		this.setValues('rgb', [val, val, val]);
512		return this;
513	},
514
515	clearer: function (ratio) {
516		var alpha = this.values.alpha;
517		this.setValues('alpha', alpha - (alpha * ratio));
518		return this;
519	},
520
521	opaquer: function (ratio) {
522		var alpha = this.values.alpha;
523		this.setValues('alpha', alpha + (alpha * ratio));
524		return this;
525	},
526
527	rotate: function (degrees) {
528		var hsl = this.values.hsl;
529		var hue = (hsl[0] + degrees) % 360;
530		hsl[0] = hue < 0 ? 360 + hue : hue;
531		this.setValues('hsl', hsl);
532		return this;
533	},
534
535	/**
536	 * Ported from sass implementation in C
537	 * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
538	 */
539	mix: function (mixinColor, weight) {
540		var color1 = this;
541		var color2 = mixinColor;
542		var p = weight === undefined ? 0.5 : weight;
543
544		var w = 2 * p - 1;
545		var a = color1.alpha() - color2.alpha();
546
547		var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
548		var w2 = 1 - w1;
549
550		return this
551			.rgb(
552				w1 * color1.red() + w2 * color2.red(),
553				w1 * color1.green() + w2 * color2.green(),
554				w1 * color1.blue() + w2 * color2.blue()
555			)
556			.alpha(color1.alpha() * p + color2.alpha() * (1 - p));
557	},
558
559	toJSON: function () {
560		return this.rgb();
561	},
562
563	clone: function () {
564		// NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
565		// making the final build way to big to embed in Chart.js. So let's do it manually,
566		// assuming that values to clone are 1 dimension arrays containing only numbers,
567		// except 'alpha' which is a number.
568		var result = new Color();
569		var source = this.values;
570		var target = result.values;
571		var value, type;
572
573		for (var prop in source) {
574			if (source.hasOwnProperty(prop)) {
575				value = source[prop];
576				type = ({}).toString.call(value);
577				if (type === '[object Array]') {
578					target[prop] = value.slice(0);
579				} else if (type === '[object Number]') {
580					target[prop] = value;
581				} else {
582					console.error('unexpected color value:', value);
583				}
584			}
585		}
586
587		return result;
588	}
589};
590
591Color.prototype.spaces = {
592	rgb: ['red', 'green', 'blue'],
593	hsl: ['hue', 'saturation', 'lightness'],
594	hsv: ['hue', 'saturation', 'value'],
595	hwb: ['hue', 'whiteness', 'blackness'],
596	cmyk: ['cyan', 'magenta', 'yellow', 'black']
597};
598
599Color.prototype.maxes = {
600	rgb: [255, 255, 255],
601	hsl: [360, 100, 100],
602	hsv: [360, 100, 100],
603	hwb: [360, 100, 100],
604	cmyk: [100, 100, 100, 100]
605};
606
607Color.prototype.getValues = function (space) {
608	var values = this.values;
609	var vals = {};
610
611	for (var i = 0; i < space.length; i++) {
612		vals[space.charAt(i)] = values[space][i];
613	}
614
615	if (values.alpha !== 1) {
616		vals.a = values.alpha;
617	}
618
619	// {r: 255, g: 255, b: 255, a: 0.4}
620	return vals;
621};
622
623Color.prototype.setValues = function (space, vals) {
624	var values = this.values;
625	var spaces = this.spaces;
626	var maxes = this.maxes;
627	var alpha = 1;
628	var i;
629
630	this.valid = true;
631
632	if (space === 'alpha') {
633		alpha = vals;
634	} else if (vals.length) {
635		// [10, 10, 10]
636		values[space] = vals.slice(0, space.length);
637		alpha = vals[space.length];
638	} else if (vals[space.charAt(0)] !== undefined) {
639		// {r: 10, g: 10, b: 10}
640		for (i = 0; i < space.length; i++) {
641			values[space][i] = vals[space.charAt(i)];
642		}
643
644		alpha = vals.a;
645	} else if (vals[spaces[space][0]] !== undefined) {
646		// {red: 10, green: 10, blue: 10}
647		var chans = spaces[space];
648
649		for (i = 0; i < space.length; i++) {
650			values[space][i] = vals[chans[i]];
651		}
652
653		alpha = vals.alpha;
654	}
655
656	values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
657
658	if (space === 'alpha') {
659		return false;
660	}
661
662	var capped;
663
664	// cap values of the space prior converting all values
665	for (i = 0; i < space.length; i++) {
666		capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
667		values[space][i] = Math.round(capped);
668	}
669
670	// convert to all the other color spaces
671	for (var sname in spaces) {
672		if (sname !== space) {
673			values[sname] = convert[space][sname](values[space]);
674		}
675	}
676
677	return true;
678};
679
680Color.prototype.setSpace = function (space, args) {
681	var vals = args[0];
682
683	if (vals === undefined) {
684		// color.rgb()
685		return this.getValues(space);
686	}
687
688	// color.rgb(10, 10, 10)
689	if (typeof vals === 'number') {
690		vals = Array.prototype.slice.call(args);
691	}
692
693	this.setValues(space, vals);
694	return this;
695};
696
697Color.prototype.setChannel = function (space, index, val) {
698	var svalues = this.values[space];
699	if (val === undefined) {
700		// color.red()
701		return svalues[index];
702	} else if (val === svalues[index]) {
703		// color.red(color.red())
704		return this;
705	}
706
707	// color.red(100)
708	svalues[index] = val;
709	this.setValues(space, svalues);
710
711	return this;
712};
713
714if (typeof window !== 'undefined') {
715	window.Color = Color;
716}
717
718module.exports = Color;
719
720},{"1":1,"4":4}],3:[function(require,module,exports){
721/* MIT license */
722
723module.exports = {
724  rgb2hsl: rgb2hsl,
725  rgb2hsv: rgb2hsv,
726  rgb2hwb: rgb2hwb,
727  rgb2cmyk: rgb2cmyk,
728  rgb2keyword: rgb2keyword,
729  rgb2xyz: rgb2xyz,
730  rgb2lab: rgb2lab,
731  rgb2lch: rgb2lch,
732
733  hsl2rgb: hsl2rgb,
734  hsl2hsv: hsl2hsv,
735  hsl2hwb: hsl2hwb,
736  hsl2cmyk: hsl2cmyk,
737  hsl2keyword: hsl2keyword,
738
739  hsv2rgb: hsv2rgb,
740  hsv2hsl: hsv2hsl,
741  hsv2hwb: hsv2hwb,
742  hsv2cmyk: hsv2cmyk,
743  hsv2keyword: hsv2keyword,
744
745  hwb2rgb: hwb2rgb,
746  hwb2hsl: hwb2hsl,
747  hwb2hsv: hwb2hsv,
748  hwb2cmyk: hwb2cmyk,
749  hwb2keyword: hwb2keyword,
750
751  cmyk2rgb: cmyk2rgb,
752  cmyk2hsl: cmyk2hsl,
753  cmyk2hsv: cmyk2hsv,
754  cmyk2hwb: cmyk2hwb,
755  cmyk2keyword: cmyk2keyword,
756
757  keyword2rgb: keyword2rgb,
758  keyword2hsl: keyword2hsl,
759  keyword2hsv: keyword2hsv,
760  keyword2hwb: keyword2hwb,
761  keyword2cmyk: keyword2cmyk,
762  keyword2lab: keyword2lab,
763  keyword2xyz: keyword2xyz,
764
765  xyz2rgb: xyz2rgb,
766  xyz2lab: xyz2lab,
767  xyz2lch: xyz2lch,
768
769  lab2xyz: lab2xyz,
770  lab2rgb: lab2rgb,
771  lab2lch: lab2lch,
772
773  lch2lab: lch2lab,
774  lch2xyz: lch2xyz,
775  lch2rgb: lch2rgb
776}
777
778
779function rgb2hsl(rgb) {
780  var r = rgb[0]/255,
781      g = rgb[1]/255,
782      b = rgb[2]/255,
783      min = Math.min(r, g, b),
784      max = Math.max(r, g, b),
785      delta = max - min,
786      h, s, l;
787
788  if (max == min)
789    h = 0;
790  else if (r == max)
791    h = (g - b) / delta;
792  else if (g == max)
793    h = 2 + (b - r) / delta;
794  else if (b == max)
795    h = 4 + (r - g)/ delta;
796
797  h = Math.min(h * 60, 360);
798
799  if (h < 0)
800    h += 360;
801
802  l = (min + max) / 2;
803
804  if (max == min)
805    s = 0;
806  else if (l <= 0.5)
807    s = delta / (max + min);
808  else
809    s = delta / (2 - max - min);
810
811  return [h, s * 100, l * 100];
812}
813
814function rgb2hsv(rgb) {
815  var r = rgb[0],
816      g = rgb[1],
817      b = rgb[2],
818      min = Math.min(r, g, b),
819      max = Math.max(r, g, b),
820      delta = max - min,
821      h, s, v;
822
823  if (max == 0)
824    s = 0;
825  else
826    s = (delta/max * 1000)/10;
827
828  if (max == min)
829    h = 0;
830  else if (r == max)
831    h = (g - b) / delta;
832  else if (g == max)
833    h = 2 + (b - r) / delta;
834  else if (b == max)
835    h = 4 + (r - g) / delta;
836
837  h = Math.min(h * 60, 360);
838
839  if (h < 0)
840    h += 360;
841
842  v = ((max / 255) * 1000) / 10;
843
844  return [h, s, v];
845}
846
847function rgb2hwb(rgb) {
848  var r = rgb[0],
849      g = rgb[1],
850      b = rgb[2],
851      h = rgb2hsl(rgb)[0],
852      w = 1/255 * Math.min(r, Math.min(g, b)),
853      b = 1 - 1/255 * Math.max(r, Math.max(g, b));
854
855  return [h, w * 100, b * 100];
856}
857
858function rgb2cmyk(rgb) {
859  var r = rgb[0] / 255,
860      g = rgb[1] / 255,
861      b = rgb[2] / 255,
862      c, m, y, k;
863
864  k = Math.min(1 - r, 1 - g, 1 - b);
865  c = (1 - r - k) / (1 - k) || 0;
866  m = (1 - g - k) / (1 - k) || 0;
867  y = (1 - b - k) / (1 - k) || 0;
868  return [c * 100, m * 100, y * 100, k * 100];
869}
870
871function rgb2keyword(rgb) {
872  return reverseKeywords[JSON.stringify(rgb)];
873}
874
875function rgb2xyz(rgb) {
876  var r = rgb[0] / 255,
877      g = rgb[1] / 255,
878      b = rgb[2] / 255;
879
880  // assume sRGB
881  r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
882  g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
883  b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
884
885  var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
886  var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
887  var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
888
889  return [x * 100, y *100, z * 100];
890}
891
892function rgb2lab(rgb) {
893  var xyz = rgb2xyz(rgb),
894        x = xyz[0],
895        y = xyz[1],
896        z = xyz[2],
897        l, a, b;
898
899  x /= 95.047;
900  y /= 100;
901  z /= 108.883;
902
903  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
904  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
905  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
906
907  l = (116 * y) - 16;
908  a = 500 * (x - y);
909  b = 200 * (y - z);
910
911  return [l, a, b];
912}
913
914function rgb2lch(args) {
915  return lab2lch(rgb2lab(args));
916}
917
918function hsl2rgb(hsl) {
919  var h = hsl[0] / 360,
920      s = hsl[1] / 100,
921      l = hsl[2] / 100,
922      t1, t2, t3, rgb, val;
923
924  if (s == 0) {
925    val = l * 255;
926    return [val, val, val];
927  }
928
929  if (l < 0.5)
930    t2 = l * (1 + s);
931  else
932    t2 = l + s - l * s;
933  t1 = 2 * l - t2;
934
935  rgb = [0, 0, 0];
936  for (var i = 0; i < 3; i++) {
937    t3 = h + 1 / 3 * - (i - 1);
938    t3 < 0 && t3++;
939    t3 > 1 && t3--;
940
941    if (6 * t3 < 1)
942      val = t1 + (t2 - t1) * 6 * t3;
943    else if (2 * t3 < 1)
944      val = t2;
945    else if (3 * t3 < 2)
946      val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
947    else
948      val = t1;
949
950    rgb[i] = val * 255;
951  }
952
953  return rgb;
954}
955
956function hsl2hsv(hsl) {
957  var h = hsl[0],
958      s = hsl[1] / 100,
959      l = hsl[2] / 100,
960      sv, v;
961
962  if(l === 0) {
963      // no need to do calc on black
964      // also avoids divide by 0 error
965      return [0, 0, 0];
966  }
967
968  l *= 2;
969  s *= (l <= 1) ? l : 2 - l;
970  v = (l + s) / 2;
971  sv = (2 * s) / (l + s);
972  return [h, sv * 100, v * 100];
973}
974
975function hsl2hwb(args) {
976  return rgb2hwb(hsl2rgb(args));
977}
978
979function hsl2cmyk(args) {
980  return rgb2cmyk(hsl2rgb(args));
981}
982
983function hsl2keyword(args) {
984  return rgb2keyword(hsl2rgb(args));
985}
986
987
988function hsv2rgb(hsv) {
989  var h = hsv[0] / 60,
990      s = hsv[1] / 100,
991      v = hsv[2] / 100,
992      hi = Math.floor(h) % 6;
993
994  var f = h - Math.floor(h),
995      p = 255 * v * (1 - s),
996      q = 255 * v * (1 - (s * f)),
997      t = 255 * v * (1 - (s * (1 - f))),
998      v = 255 * v;
999
1000  switch(hi) {
1001    case 0:
1002      return [v, t, p];
1003    case 1:
1004      return [q, v, p];
1005    case 2:
1006      return [p, v, t];
1007    case 3:
1008      return [p, q, v];
1009    case 4:
1010      return [t, p, v];
1011    case 5:
1012      return [v, p, q];
1013  }
1014}
1015
1016function hsv2hsl(hsv) {
1017  var h = hsv[0],
1018      s = hsv[1] / 100,
1019      v = hsv[2] / 100,
1020      sl, l;
1021
1022  l = (2 - s) * v;
1023  sl = s * v;
1024  sl /= (l <= 1) ? l : 2 - l;
1025  sl = sl || 0;
1026  l /= 2;
1027  return [h, sl * 100, l * 100];
1028}
1029
1030function hsv2hwb(args) {
1031  return rgb2hwb(hsv2rgb(args))
1032}
1033
1034function hsv2cmyk(args) {
1035  return rgb2cmyk(hsv2rgb(args));
1036}
1037
1038function hsv2keyword(args) {
1039  return rgb2keyword(hsv2rgb(args));
1040}
1041
1042// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
1043function hwb2rgb(hwb) {
1044  var h = hwb[0] / 360,
1045      wh = hwb[1] / 100,
1046      bl = hwb[2] / 100,
1047      ratio = wh + bl,
1048      i, v, f, n;
1049
1050  // wh + bl cant be > 1
1051  if (ratio > 1) {
1052    wh /= ratio;
1053    bl /= ratio;
1054  }
1055
1056  i = Math.floor(6 * h);
1057  v = 1 - bl;
1058  f = 6 * h - i;
1059  if ((i & 0x01) != 0) {
1060    f = 1 - f;
1061  }
1062  n = wh + f * (v - wh);  // linear interpolation
1063
1064  switch (i) {
1065    default:
1066    case 6:
1067    case 0: r = v; g = n; b = wh; break;
1068    case 1: r = n; g = v; b = wh; break;
1069    case 2: r = wh; g = v; b = n; break;
1070    case 3: r = wh; g = n; b = v; break;
1071    case 4: r = n; g = wh; b = v; break;
1072    case 5: r = v; g = wh; b = n; break;
1073  }
1074
1075  return [r * 255, g * 255, b * 255];
1076}
1077
1078function hwb2hsl(args) {
1079  return rgb2hsl(hwb2rgb(args));
1080}
1081
1082function hwb2hsv(args) {
1083  return rgb2hsv(hwb2rgb(args));
1084}
1085
1086function hwb2cmyk(args) {
1087  return rgb2cmyk(hwb2rgb(args));
1088}
1089
1090function hwb2keyword(args) {
1091  return rgb2keyword(hwb2rgb(args));
1092}
1093
1094function cmyk2rgb(cmyk) {
1095  var c = cmyk[0] / 100,
1096      m = cmyk[1] / 100,
1097      y = cmyk[2] / 100,
1098      k = cmyk[3] / 100,
1099      r, g, b;
1100
1101  r = 1 - Math.min(1, c * (1 - k) + k);
1102  g = 1 - Math.min(1, m * (1 - k) + k);
1103  b = 1 - Math.min(1, y * (1 - k) + k);
1104  return [r * 255, g * 255, b * 255];
1105}
1106
1107function cmyk2hsl(args) {
1108  return rgb2hsl(cmyk2rgb(args));
1109}
1110
1111function cmyk2hsv(args) {
1112  return rgb2hsv(cmyk2rgb(args));
1113}
1114
1115function cmyk2hwb(args) {
1116  return rgb2hwb(cmyk2rgb(args));
1117}
1118
1119function cmyk2keyword(args) {
1120  return rgb2keyword(cmyk2rgb(args));
1121}
1122
1123
1124function xyz2rgb(xyz) {
1125  var x = xyz[0] / 100,
1126      y = xyz[1] / 100,
1127      z = xyz[2] / 100,
1128      r, g, b;
1129
1130  r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
1131  g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
1132  b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
1133
1134  // assume sRGB
1135  r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
1136    : r = (r * 12.92);
1137
1138  g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
1139    : g = (g * 12.92);
1140
1141  b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
1142    : b = (b * 12.92);
1143
1144  r = Math.min(Math.max(0, r), 1);
1145  g = Math.min(Math.max(0, g), 1);
1146  b = Math.min(Math.max(0, b), 1);
1147
1148  return [r * 255, g * 255, b * 255];
1149}
1150
1151function xyz2lab(xyz) {
1152  var x = xyz[0],
1153      y = xyz[1],
1154      z = xyz[2],
1155      l, a, b;
1156
1157  x /= 95.047;
1158  y /= 100;
1159  z /= 108.883;
1160
1161  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
1162  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
1163  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
1164
1165  l = (116 * y) - 16;
1166  a = 500 * (x - y);
1167  b = 200 * (y - z);
1168
1169  return [l, a, b];
1170}
1171
1172function xyz2lch(args) {
1173  return lab2lch(xyz2lab(args));
1174}
1175
1176function lab2xyz(lab) {
1177  var l = lab[0],
1178      a = lab[1],
1179      b = lab[2],
1180      x, y, z, y2;
1181
1182  if (l <= 8) {
1183    y = (l * 100) / 903.3;
1184    y2 = (7.787 * (y / 100)) + (16 / 116);
1185  } else {
1186    y = 100 * Math.pow((l + 16) / 116, 3);
1187    y2 = Math.pow(y / 100, 1/3);
1188  }
1189
1190  x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
1191
1192  z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
1193
1194  return [x, y, z];
1195}
1196
1197function lab2lch(lab) {
1198  var l = lab[0],
1199      a = lab[1],
1200      b = lab[2],
1201      hr, h, c;
1202
1203  hr = Math.atan2(b, a);
1204  h = hr * 360 / 2 / Math.PI;
1205  if (h < 0) {
1206    h += 360;
1207  }
1208  c = Math.sqrt(a * a + b * b);
1209  return [l, c, h];
1210}
1211
1212function lab2rgb(args) {
1213  return xyz2rgb(lab2xyz(args));
1214}
1215
1216function lch2lab(lch) {
1217  var l = lch[0],
1218      c = lch[1],
1219      h = lch[2],
1220      a, b, hr;
1221
1222  hr = h / 360 * 2 * Math.PI;
1223  a = c * Math.cos(hr);
1224  b = c * Math.sin(hr);
1225  return [l, a, b];
1226}
1227
1228function lch2xyz(args) {
1229  return lab2xyz(lch2lab(args));
1230}
1231
1232function lch2rgb(args) {
1233  return lab2rgb(lch2lab(args));
1234}
1235
1236function keyword2rgb(keyword) {
1237  return cssKeywords[keyword];
1238}
1239
1240function keyword2hsl(args) {
1241  return rgb2hsl(keyword2rgb(args));
1242}
1243
1244function keyword2hsv(args) {
1245  return rgb2hsv(keyword2rgb(args));
1246}
1247
1248function keyword2hwb(args) {
1249  return rgb2hwb(keyword2rgb(args));
1250}
1251
1252function keyword2cmyk(args) {
1253  return rgb2cmyk(keyword2rgb(args));
1254}
1255
1256function keyword2lab(args) {
1257  return rgb2lab(keyword2rgb(args));
1258}
1259
1260function keyword2xyz(args) {
1261  return rgb2xyz(keyword2rgb(args));
1262}
1263
1264var cssKeywords = {
1265  aliceblue:  [240,248,255],
1266  antiquewhite: [250,235,215],
1267  aqua: [0,255,255],
1268  aquamarine: [127,255,212],
1269  azure:  [240,255,255],
1270  beige:  [245,245,220],
1271  bisque: [255,228,196],
1272  black:  [0,0,0],
1273  blanchedalmond: [255,235,205],
1274  blue: [0,0,255],
1275  blueviolet: [138,43,226],
1276  brown:  [165,42,42],
1277  burlywood:  [222,184,135],
1278  cadetblue:  [95,158,160],
1279  chartreuse: [127,255,0],
1280  chocolate:  [210,105,30],
1281  coral:  [255,127,80],
1282  cornflowerblue: [100,149,237],
1283  cornsilk: [255,248,220],
1284  crimson:  [220,20,60],
1285  cyan: [0,255,255],
1286  darkblue: [0,0,139],
1287  darkcyan: [0,139,139],
1288  darkgoldenrod:  [184,134,11],
1289  darkgray: [169,169,169],
1290  darkgreen:  [0,100,0],
1291  darkgrey: [169,169,169],
1292  darkkhaki:  [189,183,107],
1293  darkmagenta:  [139,0,139],
1294  darkolivegreen: [85,107,47],
1295  darkorange: [255,140,0],
1296  darkorchid: [153,50,204],
1297  darkred:  [139,0,0],
1298  darksalmon: [233,150,122],
1299  darkseagreen: [143,188,143],
1300  darkslateblue:  [72,61,139],
1301  darkslategray:  [47,79,79],
1302  darkslategrey:  [47,79,79],
1303  darkturquoise:  [0,206,209],
1304  darkviolet: [148,0,211],
1305  deeppink: [255,20,147],
1306  deepskyblue:  [0,191,255],
1307  dimgray:  [105,105,105],
1308  dimgrey:  [105,105,105],
1309  dodgerblue: [30,144,255],
1310  firebrick:  [178,34,34],
1311  floralwhite:  [255,250,240],
1312  forestgreen:  [34,139,34],
1313  fuchsia:  [255,0,255],
1314  gainsboro:  [220,220,220],
1315  ghostwhite: [248,248,255],
1316  gold: [255,215,0],
1317  goldenrod:  [218,165,32],
1318  gray: [128,128,128],
1319  green:  [0,128,0],
1320  greenyellow:  [173,255,47],
1321  grey: [128,128,128],
1322  honeydew: [240,255,240],
1323  hotpink:  [255,105,180],
1324  indianred:  [205,92,92],
1325  indigo: [75,0,130],
1326  ivory:  [255,255,240],
1327  khaki:  [240,230,140],
1328  lavender: [230,230,250],
1329  lavenderblush:  [255,240,245],
1330  lawngreen:  [124,252,0],
1331  lemonchiffon: [255,250,205],
1332  lightblue:  [173,216,230],
1333  lightcoral: [240,128,128],
1334  lightcyan:  [224,255,255],
1335  lightgoldenrodyellow: [250,250,210],
1336  lightgray:  [211,211,211],
1337  lightgreen: [144,238,144],
1338  lightgrey:  [211,211,211],
1339  lightpink:  [255,182,193],
1340  lightsalmon:  [255,160,122],
1341  lightseagreen:  [32,178,170],
1342  lightskyblue: [135,206,250],
1343  lightslategray: [119,136,153],
1344  lightslategrey: [119,136,153],
1345  lightsteelblue: [176,196,222],
1346  lightyellow:  [255,255,224],
1347  lime: [0,255,0],
1348  limegreen:  [50,205,50],
1349  linen:  [250,240,230],
1350  magenta:  [255,0,255],
1351  maroon: [128,0,0],
1352  mediumaquamarine: [102,205,170],
1353  mediumblue: [0,0,205],
1354  mediumorchid: [186,85,211],
1355  mediumpurple: [147,112,219],
1356  mediumseagreen: [60,179,113],
1357  mediumslateblue:  [123,104,238],
1358  mediumspringgreen:  [0,250,154],
1359  mediumturquoise:  [72,209,204],
1360  mediumvioletred:  [199,21,133],
1361  midnightblue: [25,25,112],
1362  mintcream:  [245,255,250],
1363  mistyrose:  [255,228,225],
1364  moccasin: [255,228,181],
1365  navajowhite:  [255,222,173],
1366  navy: [0,0,128],
1367  oldlace:  [253,245,230],
1368  olive:  [128,128,0],
1369  olivedrab:  [107,142,35],
1370  orange: [255,165,0],
1371  orangered:  [255,69,0],
1372  orchid: [218,112,214],
1373  palegoldenrod:  [238,232,170],
1374  palegreen:  [152,251,152],
1375  paleturquoise:  [175,238,238],
1376  palevioletred:  [219,112,147],
1377  papayawhip: [255,239,213],
1378  peachpuff:  [255,218,185],
1379  peru: [205,133,63],
1380  pink: [255,192,203],
1381  plum: [221,160,221],
1382  powderblue: [176,224,230],
1383  purple: [128,0,128],
1384  rebeccapurple: [102, 51, 153],
1385  red:  [255,0,0],
1386  rosybrown:  [188,143,143],
1387  royalblue:  [65,105,225],
1388  saddlebrown:  [139,69,19],
1389  salmon: [250,128,114],
1390  sandybrown: [244,164,96],
1391  seagreen: [46,139,87],
1392  seashell: [255,245,238],
1393  sienna: [160,82,45],
1394  silver: [192,192,192],
1395  skyblue:  [135,206,235],
1396  slateblue:  [106,90,205],
1397  slategray:  [112,128,144],
1398  slategrey:  [112,128,144],
1399  snow: [255,250,250],
1400  springgreen:  [0,255,127],
1401  steelblue:  [70,130,180],
1402  tan:  [210,180,140],
1403  teal: [0,128,128],
1404  thistle:  [216,191,216],
1405  tomato: [255,99,71],
1406  turquoise:  [64,224,208],
1407  violet: [238,130,238],
1408  wheat:  [245,222,179],
1409  white:  [255,255,255],
1410  whitesmoke: [245,245,245],
1411  yellow: [255,255,0],
1412  yellowgreen:  [154,205,50]
1413};
1414
1415var reverseKeywords = {};
1416for (var key in cssKeywords) {
1417  reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
1418}
1419
1420},{}],4:[function(require,module,exports){
1421var conversions = require(3);
1422
1423var convert = function() {
1424   return new Converter();
1425}
1426
1427for (var func in conversions) {
1428  // export Raw versions
1429  convert[func + "Raw"] =  (function(func) {
1430    // accept array or plain args
1431    return function(arg) {
1432      if (typeof arg == "number")
1433        arg = Array.prototype.slice.call(arguments);
1434      return conversions[func](arg);
1435    }
1436  })(func);
1437
1438  var pair = /(\w+)2(\w+)/.exec(func),
1439      from = pair[1],
1440      to = pair[2];
1441
1442  // export rgb2hsl and ["rgb"]["hsl"]
1443  convert[from] = convert[from] || {};
1444
1445  convert[from][to] = convert[func] = (function(func) { 
1446    return function(arg) {
1447      if (typeof arg == "number")
1448        arg = Array.prototype.slice.call(arguments);
1449      
1450      var val = conversions[func](arg);
1451      if (typeof val == "string" || val === undefined)
1452        return val; // keyword
1453
1454      for (var i = 0; i < val.length; i++)
1455        val[i] = Math.round(val[i]);
1456      return val;
1457    }
1458  })(func);
1459}
1460
1461
1462/* Converter does lazy conversion and caching */
1463var Converter = function() {
1464   this.convs = {};
1465};
1466
1467/* Either get the values for a space or
1468  set the values for a space, depending on args */
1469Converter.prototype.routeSpace = function(space, args) {
1470   var values = args[0];
1471   if (values === undefined) {
1472      // color.rgb()
1473      return this.getValues(space);
1474   }
1475   // color.rgb(10, 10, 10)
1476   if (typeof values == "number") {
1477      values = Array.prototype.slice.call(args);        
1478   }
1479
1480   return this.setValues(space, values);
1481};
1482  
1483/* Set the values for a space, invalidating cache */
1484Converter.prototype.setValues = function(space, values) {
1485   this.space = space;
1486   this.convs = {};
1487   this.convs[space] = values;
1488   return this;
1489};
1490
1491/* Get the values for a space. If there's already
1492  a conversion for the space, fetch it, otherwise
1493  compute it */
1494Converter.prototype.getValues = function(space) {
1495   var vals = this.convs[space];
1496   if (!vals) {
1497      var fspace = this.space,
1498          from = this.convs[fspace];
1499      vals = convert[fspace][space](from);
1500
1501      this.convs[space] = vals;
1502   }
1503  return vals;
1504};
1505
1506["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
1507   Converter.prototype[space] = function(vals) {
1508      return this.routeSpace(space, arguments);
1509   }
1510});
1511
1512module.exports = convert;
1513},{"3":3}],5:[function(require,module,exports){
1514'use strict'
1515
1516module.exports = {
1517	"aliceblue": [240, 248, 255],
1518	"antiquewhite": [250, 235, 215],
1519	"aqua": [0, 255, 255],
1520	"aquamarine": [127, 255, 212],
1521	"azure": [240, 255, 255],
1522	"beige": [245, 245, 220],
1523	"bisque": [255, 228, 196],
1524	"black": [0, 0, 0],
1525	"blanchedalmond": [255, 235, 205],
1526	"blue": [0, 0, 255],
1527	"blueviolet": [138, 43, 226],
1528	"brown": [165, 42, 42],
1529	"burlywood": [222, 184, 135],
1530	"cadetblue": [95, 158, 160],
1531	"chartreuse": [127, 255, 0],
1532	"chocolate": [210, 105, 30],
1533	"coral": [255, 127, 80],
1534	"cornflowerblue": [100, 149, 237],
1535	"cornsilk": [255, 248, 220],
1536	"crimson": [220, 20, 60],
1537	"cyan": [0, 255, 255],
1538	"darkblue": [0, 0, 139],
1539	"darkcyan": [0, 139, 139],
1540	"darkgoldenrod": [184, 134, 11],
1541	"darkgray": [169, 169, 169],
1542	"darkgreen": [0, 100, 0],
1543	"darkgrey": [169, 169, 169],
1544	"darkkhaki": [189, 183, 107],
1545	"darkmagenta": [139, 0, 139],
1546	"darkolivegreen": [85, 107, 47],
1547	"darkorange": [255, 140, 0],
1548	"darkorchid": [153, 50, 204],
1549	"darkred": [139, 0, 0],
1550	"darksalmon": [233, 150, 122],
1551	"darkseagreen": [143, 188, 143],
1552	"darkslateblue": [72, 61, 139],
1553	"darkslategray": [47, 79, 79],
1554	"darkslategrey": [47, 79, 79],
1555	"darkturquoise": [0, 206, 209],
1556	"darkviolet": [148, 0, 211],
1557	"deeppink": [255, 20, 147],
1558	"deepskyblue": [0, 191, 255],
1559	"dimgray": [105, 105, 105],
1560	"dimgrey": [105, 105, 105],
1561	"dodgerblue": [30, 144, 255],
1562	"firebrick": [178, 34, 34],
1563	"floralwhite": [255, 250, 240],
1564	"forestgreen": [34, 139, 34],
1565	"fuchsia": [255, 0, 255],
1566	"gainsboro": [220, 220, 220],
1567	"ghostwhite": [248, 248, 255],
1568	"gold": [255, 215, 0],
1569	"goldenrod": [218, 165, 32],
1570	"gray": [128, 128, 128],
1571	"green": [0, 128, 0],
1572	"greenyellow": [173, 255, 47],
1573	"grey": [128, 128, 128],
1574	"honeydew": [240, 255, 240],
1575	"hotpink": [255, 105, 180],
1576	"indianred": [205, 92, 92],
1577	"indigo": [75, 0, 130],
1578	"ivory": [255, 255, 240],
1579	"khaki": [240, 230, 140],
1580	"lavender": [230, 230, 250],
1581	"lavenderblush": [255, 240, 245],
1582	"lawngreen": [124, 252, 0],
1583	"lemonchiffon": [255, 250, 205],
1584	"lightblue": [173, 216, 230],
1585	"lightcoral": [240, 128, 128],
1586	"lightcyan": [224, 255, 255],
1587	"lightgoldenrodyellow": [250, 250, 210],
1588	"lightgray": [211, 211, 211],
1589	"lightgreen": [144, 238, 144],
1590	"lightgrey": [211, 211, 211],
1591	"lightpink": [255, 182, 193],
1592	"lightsalmon": [255, 160, 122],
1593	"lightseagreen": [32, 178, 170],
1594	"lightskyblue": [135, 206, 250],
1595	"lightslategray": [119, 136, 153],
1596	"lightslategrey": [119, 136, 153],
1597	"lightsteelblue": [176, 196, 222],
1598	"lightyellow": [255, 255, 224],
1599	"lime": [0, 255, 0],
1600	"limegreen": [50, 205, 50],
1601	"linen": [250, 240, 230],
1602	"magenta": [255, 0, 255],
1603	"maroon": [128, 0, 0],
1604	"mediumaquamarine": [102, 205, 170],
1605	"mediumblue": [0, 0, 205],
1606	"mediumorchid": [186, 85, 211],
1607	"mediumpurple": [147, 112, 219],
1608	"mediumseagreen": [60, 179, 113],
1609	"mediumslateblue": [123, 104, 238],
1610	"mediumspringgreen": [0, 250, 154],
1611	"mediumturquoise": [72, 209, 204],
1612	"mediumvioletred": [199, 21, 133],
1613	"midnightblue": [25, 25, 112],
1614	"mintcream": [245, 255, 250],
1615	"mistyrose": [255, 228, 225],
1616	"moccasin": [255, 228, 181],
1617	"navajowhite": [255, 222, 173],
1618	"navy": [0, 0, 128],
1619	"oldlace": [253, 245, 230],
1620	"olive": [128, 128, 0],
1621	"olivedrab": [107, 142, 35],
1622	"orange": [255, 165, 0],
1623	"orangered": [255, 69, 0],
1624	"orchid": [218, 112, 214],
1625	"palegoldenrod": [238, 232, 170],
1626	"palegreen": [152, 251, 152],
1627	"paleturquoise": [175, 238, 238],
1628	"palevioletred": [219, 112, 147],
1629	"papayawhip": [255, 239, 213],
1630	"peachpuff": [255, 218, 185],
1631	"peru": [205, 133, 63],
1632	"pink": [255, 192, 203],
1633	"plum": [221, 160, 221],
1634	"powderblue": [176, 224, 230],
1635	"purple": [128, 0, 128],
1636	"rebeccapurple": [102, 51, 153],
1637	"red": [255, 0, 0],
1638	"rosybrown": [188, 143, 143],
1639	"royalblue": [65, 105, 225],
1640	"saddlebrown": [139, 69, 19],
1641	"salmon": [250, 128, 114],
1642	"sandybrown": [244, 164, 96],
1643	"seagreen": [46, 139, 87],
1644	"seashell": [255, 245, 238],
1645	"sienna": [160, 82, 45],
1646	"silver": [192, 192, 192],
1647	"skyblue": [135, 206, 235],
1648	"slateblue": [106, 90, 205],
1649	"slategray": [112, 128, 144],
1650	"slategrey": [112, 128, 144],
1651	"snow": [255, 250, 250],
1652	"springgreen": [0, 255, 127],
1653	"steelblue": [70, 130, 180],
1654	"tan": [210, 180, 140],
1655	"teal": [0, 128, 128],
1656	"thistle": [216, 191, 216],
1657	"tomato": [255, 99, 71],
1658	"turquoise": [64, 224, 208],
1659	"violet": [238, 130, 238],
1660	"wheat": [245, 222, 179],
1661	"white": [255, 255, 255],
1662	"whitesmoke": [245, 245, 245],
1663	"yellow": [255, 255, 0],
1664	"yellowgreen": [154, 205, 50]
1665};
1666
1667},{}],6:[function(require,module,exports){
1668//! moment.js
1669//! version : 2.20.1
1670//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
1671//! license : MIT
1672//! momentjs.com
1673
1674;(function (global, factory) {
1675    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
1676    typeof define === 'function' && define.amd ? define(factory) :
1677    global.moment = factory()
1678}(this, (function () { 'use strict';
1679
1680var hookCallback;
1681
1682function hooks () {
1683    return hookCallback.apply(null, arguments);
1684}
1685
1686// This is done to register the method called with moment()
1687// without creating circular dependencies.
1688function setHookCallback (callback) {
1689    hookCallback = callback;
1690}
1691
1692function isArray(input) {
1693    return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
1694}
1695
1696function isObject(input) {
1697    // IE8 will treat undefined and null as object if it wasn't for
1698    // input != null
1699    return input != null && Object.prototype.toString.call(input) === '[object Object]';
1700}
1701
1702function isObjectEmpty(obj) {
1703    if (Object.getOwnPropertyNames) {
1704        return (Object.getOwnPropertyNames(obj).length === 0);
1705    } else {
1706        var k;
1707        for (k in obj) {
1708            if (obj.hasOwnProperty(k)) {
1709                return false;
vendor: 22,951 bytes, lines 1710-2587
1710            }
1711        }
1712        return true;
1713    }
1714}
1715
1716function isUndefined(input) {
1717    return input === void 0;
1718}
1719
1720function isNumber(input) {
1721    return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
1722}
1723
1724function isDate(input) {
1725    return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
1726}
1727
1728function map(arr, fn) {
1729    var res = [], i;
1730    for (i = 0; i < arr.length; ++i) {
1731        res.push(fn(arr[i], i));
1732    }
1733    return res;
1734}
1735
1736function hasOwnProp(a, b) {
1737    return Object.prototype.hasOwnProperty.call(a, b);
1738}
1739
1740function extend(a, b) {
1741    for (var i in b) {
1742        if (hasOwnProp(b, i)) {
1743            a[i] = b[i];
1744        }
1745    }
1746
1747    if (hasOwnProp(b, 'toString')) {
1748        a.toString = b.toString;
1749    }
1750
1751    if (hasOwnProp(b, 'valueOf')) {
1752        a.valueOf = b.valueOf;
1753    }
1754
1755    return a;
1756}
1757
1758function createUTC (input, format, locale, strict) {
1759    return createLocalOrUTC(input, format, locale, strict, true).utc();
1760}
1761
1762function defaultParsingFlags() {
1763    // We need to deep clone this object.
1764    return {
1765        empty           : false,
1766        unusedTokens    : [],
1767        unusedInput     : [],
1768        overflow        : -2,
1769        charsLeftOver   : 0,
1770        nullInput       : false,
1771        invalidMonth    : null,
1772        invalidFormat   : false,
1773        userInvalidated : false,
1774        iso             : false,
1775        parsedDateParts : [],
1776        meridiem        : null,
1777        rfc2822         : false,
1778        weekdayMismatch : false
1779    };
1780}
1781
1782function getParsingFlags(m) {
1783    if (m._pf == null) {
1784        m._pf = defaultParsingFlags();
1785    }
1786    return m._pf;
1787}
1788
1789var some;
1790if (Array.prototype.some) {
1791    some = Array.prototype.some;
1792} else {
1793    some = function (fun) {
1794        var t = Object(this);
1795        var len = t.length >>> 0;
1796
1797        for (var i = 0; i < len; i++) {
1798            if (i in t && fun.call(this, t[i], i, t)) {
1799                return true;
1800            }
1801        }
1802
1803        return false;
1804    };
1805}
1806
1807function isValid(m) {
1808    if (m._isValid == null) {
1809        var flags = getParsingFlags(m);
1810        var parsedParts = some.call(flags.parsedDateParts, function (i) {
1811            return i != null;
1812        });
1813        var isNowValid = !isNaN(m._d.getTime()) &&
1814            flags.overflow < 0 &&
1815            !flags.empty &&
1816            !flags.invalidMonth &&
1817            !flags.invalidWeekday &&
1818            !flags.weekdayMismatch &&
1819            !flags.nullInput &&
1820            !flags.invalidFormat &&
1821            !flags.userInvalidated &&
1822            (!flags.meridiem || (flags.meridiem && parsedParts));
1823
1824        if (m._strict) {
1825            isNowValid = isNowValid &&
1826                flags.charsLeftOver === 0 &&
1827                flags.unusedTokens.length === 0 &&
1828                flags.bigHour === undefined;
1829        }
1830
1831        if (Object.isFrozen == null || !Object.isFrozen(m)) {
1832            m._isValid = isNowValid;
1833        }
1834        else {
1835            return isNowValid;
1836        }
1837    }
1838    return m._isValid;
1839}
1840
1841function createInvalid (flags) {
1842    var m = createUTC(NaN);
1843    if (flags != null) {
1844        extend(getParsingFlags(m), flags);
1845    }
1846    else {
1847        getParsingFlags(m).userInvalidated = true;
1848    }
1849
1850    return m;
1851}
1852
1853// Plugins that add properties should also add the key here (null value),
1854// so we can properly clone ourselves.
1855var momentProperties = hooks.momentProperties = [];
1856
1857function copyConfig(to, from) {
1858    var i, prop, val;
1859
1860    if (!isUndefined(from._isAMomentObject)) {
1861        to._isAMomentObject = from._isAMomentObject;
1862    }
1863    if (!isUndefined(from._i)) {
1864        to._i = from._i;
1865    }
1866    if (!isUndefined(from._f)) {
1867        to._f = from._f;
1868    }
1869    if (!isUndefined(from._l)) {
1870        to._l = from._l;
1871    }
1872    if (!isUndefined(from._strict)) {
1873        to._strict = from._strict;
1874    }
1875    if (!isUndefined(from._tzm)) {
1876        to._tzm = from._tzm;
1877    }
1878    if (!isUndefined(from._isUTC)) {
1879        to._isUTC = from._isUTC;
1880    }
1881    if (!isUndefined(from._offset)) {
1882        to._offset = from._offset;
1883    }
1884    if (!isUndefined(from._pf)) {
1885        to._pf = getParsingFlags(from);
1886    }
1887    if (!isUndefined(from._locale)) {
1888        to._locale = from._locale;
1889    }
1890
1891    if (momentProperties.length > 0) {
1892        for (i = 0; i < momentProperties.length; i++) {
1893            prop = momentProperties[i];
1894            val = from[prop];
1895            if (!isUndefined(val)) {
1896                to[prop] = val;
1897            }
1898        }
1899    }
1900
1901    return to;
1902}
1903
1904var updateInProgress = false;
1905
1906// Moment prototype object
1907function Moment(config) {
1908    copyConfig(this, config);
1909    this._d = new Date(config._d != null ? config._d.getTime() : NaN);
1910    if (!this.isValid()) {
1911        this._d = new Date(NaN);
1912    }
1913    // Prevent infinite loop in case updateOffset creates new moment
1914    // objects.
1915    if (updateInProgress === false) {
1916        updateInProgress = true;
1917        hooks.updateOffset(this);
1918        updateInProgress = false;
1919    }
1920}
1921
1922function isMoment (obj) {
1923    return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
1924}
1925
1926function absFloor (number) {
1927    if (number < 0) {
1928        // -0 -> 0
1929        return Math.ceil(number) || 0;
1930    } else {
1931        return Math.floor(number);
1932    }
1933}
1934
1935function toInt(argumentForCoercion) {
1936    var coercedNumber = +argumentForCoercion,
1937        value = 0;
1938
1939    if (coercedNumber !== 0 && isFinite(coercedNumber)) {
1940        value = absFloor(coercedNumber);
1941    }
1942
1943    return value;
1944}
1945
1946// compare two arrays, return the number of differences
1947function compareArrays(array1, array2, dontConvert) {
1948    var len = Math.min(array1.length, array2.length),
1949        lengthDiff = Math.abs(array1.length - array2.length),
1950        diffs = 0,
1951        i;
1952    for (i = 0; i < len; i++) {
1953        if ((dontConvert && array1[i] !== array2[i]) ||
1954            (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
1955            diffs++;
1956        }
1957    }
1958    return diffs + lengthDiff;
1959}
1960
1961function warn(msg) {
1962    if (hooks.suppressDeprecationWarnings === false &&
1963            (typeof console !==  'undefined') && console.warn) {
1964        console.warn('Deprecation warning: ' + msg);
1965    }
1966}
1967
1968function deprecate(msg, fn) {
1969    var firstTime = true;
1970
1971    return extend(function () {
1972        if (hooks.deprecationHandler != null) {
1973            hooks.deprecationHandler(null, msg);
1974        }
1975        if (firstTime) {
1976            var args = [];
1977            var arg;
1978            for (var i = 0; i < arguments.length; i++) {
1979                arg = '';
1980                if (typeof arguments[i] === 'object') {
1981                    arg += '\n[' + i + '] ';
1982                    for (var key in arguments[0]) {
1983                        arg += key + ': ' + arguments[0][key] + ', ';
1984                    }
1985                    arg = arg.slice(0, -2); // Remove trailing comma and space
1986                } else {
1987                    arg = arguments[i];
1988                }
1989                args.push(arg);
1990            }
1991            warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
1992            firstTime = false;
1993        }
1994        return fn.apply(this, arguments);
1995    }, fn);
1996}
1997
1998var deprecations = {};
1999
2000function deprecateSimple(name, msg) {
2001    if (hooks.deprecationHandler != null) {
2002        hooks.deprecationHandler(name, msg);
2003    }
2004    if (!deprecations[name]) {
2005        warn(msg);
2006        deprecations[name] = true;
2007    }
2008}
2009
2010hooks.suppressDeprecationWarnings = false;
2011hooks.deprecationHandler = null;
2012
2013function isFunction(input) {
2014    return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
2015}
2016
2017function set (config) {
2018    var prop, i;
2019    for (i in config) {
2020        prop = config[i];
2021        if (isFunction(prop)) {
2022            this[i] = prop;
2023        } else {
2024            this['_' + i] = prop;
2025        }
2026    }
2027    this._config = config;
2028    // Lenient ordinal parsing accepts just a number in addition to
2029    // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
2030    // TODO: Remove "ordinalParse" fallback in next major release.
2031    this._dayOfMonthOrdinalParseLenient = new RegExp(
2032        (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
2033            '|' + (/\d{1,2}/).source);
2034}
2035
2036function mergeConfigs(parentConfig, childConfig) {
2037    var res = extend({}, parentConfig), prop;
2038    for (prop in childConfig) {
2039        if (hasOwnProp(childConfig, prop)) {
2040            if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
2041                res[prop] = {};
2042                extend(res[prop], parentConfig[prop]);
2043                extend(res[prop], childConfig[prop]);
2044            } else if (childConfig[prop] != null) {
2045                res[prop] = childConfig[prop];
2046            } else {
2047                delete res[prop];
2048            }
2049        }
2050    }
2051    for (prop in parentConfig) {
2052        if (hasOwnProp(parentConfig, prop) &&
2053                !hasOwnProp(childConfig, prop) &&
2054                isObject(parentConfig[prop])) {
2055            // make sure changes to properties don't modify parent config
2056            res[prop] = extend({}, res[prop]);
2057        }
2058    }
2059    return res;
2060}
2061
2062function Locale(config) {
2063    if (config != null) {
2064        this.set(config);
2065    }
2066}
2067
2068var keys;
2069
2070if (Object.keys) {
2071    keys = Object.keys;
2072} else {
2073    keys = function (obj) {
2074        var i, res = [];
2075        for (i in obj) {
2076            if (hasOwnProp(obj, i)) {
2077                res.push(i);
2078            }
2079        }
2080        return res;
2081    };
2082}
2083
2084var defaultCalendar = {
2085    sameDay : '[Today at] LT',
2086    nextDay : '[Tomorrow at] LT',
2087    nextWeek : 'dddd [at] LT',
2088    lastDay : '[Yesterday at] LT',
2089    lastWeek : '[Last] dddd [at] LT',
2090    sameElse : 'L'
2091};
2092
2093function calendar (key, mom, now) {
2094    var output = this._calendar[key] || this._calendar['sameElse'];
2095    return isFunction(output) ? output.call(mom, now) : output;
2096}
2097
2098var defaultLongDateFormat = {
2099    LTS  : 'h:mm:ss A',
2100    LT   : 'h:mm A',
2101    L    : 'MM/DD/YYYY',
2102    LL   : 'MMMM D, YYYY',
2103    LLL  : 'MMMM D, YYYY h:mm A',
2104    LLLL : 'dddd, MMMM D, YYYY h:mm A'
2105};
2106
2107function longDateFormat (key) {
2108    var format = this._longDateFormat[key],
2109        formatUpper = this._longDateFormat[key.toUpperCase()];
2110
2111    if (format || !formatUpper) {
2112        return format;
2113    }
2114
2115    this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
2116        return val.slice(1);
2117    });
2118
2119    return this._longDateFormat[key];
2120}
2121
2122var defaultInvalidDate = 'Invalid date';
2123
2124function invalidDate () {
2125    return this._invalidDate;
2126}
2127
2128var defaultOrdinal = '%d';
2129var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
2130
2131function ordinal (number) {
2132    return this._ordinal.replace('%d', number);
2133}
2134
2135var defaultRelativeTime = {
2136    future : 'in %s',
2137    past   : '%s ago',
2138    s  : 'a few seconds',
2139    ss : '%d seconds',
2140    m  : 'a minute',
2141    mm : '%d minutes',
2142    h  : 'an hour',
2143    hh : '%d hours',
2144    d  : 'a day',
2145    dd : '%d days',
2146    M  : 'a month',
2147    MM : '%d months',
2148    y  : 'a year',
2149    yy : '%d years'
2150};
2151
2152function relativeTime (number, withoutSuffix, string, isFuture) {
2153    var output = this._relativeTime[string];
2154    return (isFunction(output)) ?
2155        output(number, withoutSuffix, string, isFuture) :
2156        output.replace(/%d/i, number);
2157}
2158
2159function pastFuture (diff, output) {
2160    var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
2161    return isFunction(format) ? format(output) : format.replace(/%s/i, output);
2162}
2163
2164var aliases = {};
2165
2166function addUnitAlias (unit, shorthand) {
2167    var lowerCase = unit.toLowerCase();
2168    aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
2169}
2170
2171function normalizeUnits(units) {
2172    return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
2173}
2174
2175function normalizeObjectUnits(inputObject) {
2176    var normalizedInput = {},
2177        normalizedProp,
2178        prop;
2179
2180    for (prop in inputObject) {
2181        if (hasOwnProp(inputObject, prop)) {
2182            normalizedProp = normalizeUnits(prop);
2183            if (normalizedProp) {
2184                normalizedInput[normalizedProp] = inputObject[prop];
2185            }
2186        }
2187    }
2188
2189    return normalizedInput;
2190}
2191
2192var priorities = {};
2193
2194function addUnitPriority(unit, priority) {
2195    priorities[unit] = priority;
2196}
2197
2198function getPrioritizedUnits(unitsObj) {
2199    var units = [];
2200    for (var u in unitsObj) {
2201        units.push({unit: u, priority: priorities[u]});
2202    }
2203    units.sort(function (a, b) {
2204        return a.priority - b.priority;
2205    });
2206    return units;
2207}
2208
2209function zeroFill(number, targetLength, forceSign) {
2210    var absNumber = '' + Math.abs(number),
2211        zerosToFill = targetLength - absNumber.length,
2212        sign = number >= 0;
2213    return (sign ? (forceSign ? '+' : '') : '-') +
2214        Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
2215}
2216
2217var 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;
2218
2219var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
2220
2221var formatFunctions = {};
2222
2223var formatTokenFunctions = {};
2224
2225// token:    'M'
2226// padded:   ['MM', 2]
2227// ordinal:  'Mo'
2228// callback: function () { this.month() + 1 }
2229function addFormatToken (token, padded, ordinal, callback) {
2230    var func = callback;
2231    if (typeof callback === 'string') {
2232        func = function () {
2233            return this[callback]();
2234        };
2235    }
2236    if (token) {
2237        formatTokenFunctions[token] = func;
2238    }
2239    if (padded) {
2240        formatTokenFunctions[padded[0]] = function () {
2241            return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
2242        };
2243    }
2244    if (ordinal) {
2245        formatTokenFunctions[ordinal] = function () {
2246            return this.localeData().ordinal(func.apply(this, arguments), token);
2247        };
2248    }
2249}
2250
2251function removeFormattingTokens(input) {
2252    if (input.match(/\[[\s\S]/)) {
2253        return input.replace(/^\[|\]$/g, '');
2254    }
2255    return input.replace(/\\/g, '');
2256}
2257
2258function makeFormatFunction(format) {
2259    var array = format.match(formattingTokens), i, length;
2260
2261    for (i = 0, length = array.length; i < length; i++) {
2262        if (formatTokenFunctions[array[i]]) {
2263            array[i] = formatTokenFunctions[array[i]];
2264        } else {
2265            array[i] = removeFormattingTokens(array[i]);
2266        }
2267    }
2268
2269    return function (mom) {
2270        var output = '', i;
2271        for (i = 0; i < length; i++) {
2272            output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
2273        }
2274        return output;
2275    };
2276}
2277
2278// format date using native date object
2279function formatMoment(m, format) {
2280    if (!m.isValid()) {
2281        return m.localeData().invalidDate();
2282    }
2283
2284    format = expandFormat(format, m.localeData());
2285    formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
2286
2287    return formatFunctions[format](m);
2288}
2289
2290function expandFormat(format, locale) {
2291    var i = 5;
2292
2293    function replaceLongDateFormatTokens(input) {
2294        return locale.longDateFormat(input) || input;
2295    }
2296
2297    localFormattingTokens.lastIndex = 0;
2298    while (i >= 0 && localFormattingTokens.test(format)) {
2299        format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
2300        localFormattingTokens.lastIndex = 0;
2301        i -= 1;
2302    }
2303
2304    return format;
2305}
2306
2307var match1         = /\d/;            //       0 - 9
2308var match2         = /\d\d/;          //      00 - 99
2309var match3         = /\d{3}/;         //     000 - 999
2310var match4         = /\d{4}/;         //    0000 - 9999
2311var match6         = /[+-]?\d{6}/;    // -999999 - 999999
2312var match1to2      = /\d\d?/;         //       0 - 99
2313var match3to4      = /\d\d\d\d?/;     //     999 - 9999
2314var match5to6      = /\d\d\d\d\d\d?/; //   99999 - 999999
2315var match1to3      = /\d{1,3}/;       //       0 - 999
2316var match1to4      = /\d{1,4}/;       //       0 - 9999
2317var match1to6      = /[+-]?\d{1,6}/;  // -999999 - 999999
2318
2319var matchUnsigned  = /\d+/;           //       0 - inf
2320var matchSigned    = /[+-]?\d+/;      //    -inf - inf
2321
2322var matchOffset    = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
2323var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
2324
2325var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
2326
2327// any word (or two) characters or numbers including two/three word month in arabic.
2328// includes scottish gaelic two word and hyphenated months
2329var 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;
2330
2331
2332var regexes = {};
2333
2334function addRegexToken (token, regex, strictRegex) {
2335    regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
2336        return (isStrict && strictRegex) ? strictRegex : regex;
2337    };
2338}
2339
2340function getParseRegexForToken (token, config) {
2341    if (!hasOwnProp(regexes, token)) {
2342        return new RegExp(unescapeFormat(token));
2343    }
2344
2345    return regexes[token](config._strict, config._locale);
2346}
2347
2348// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
2349function unescapeFormat(s) {
2350    return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
2351        return p1 || p2 || p3 || p4;
2352    }));
2353}
2354
2355function regexEscape(s) {
2356    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
2357}
2358
2359var tokens = {};
2360
2361function addParseToken (token, callback) {
2362    var i, func = callback;
2363    if (typeof token === 'string') {
2364        token = [token];
2365    }
2366    if (isNumber(callback)) {
2367        func = function (input, array) {
2368            array[callback] = toInt(input);
2369        };
2370    }
2371    for (i = 0; i < token.length; i++) {
2372        tokens[token[i]] = func;
2373    }
2374}
2375
2376function addWeekParseToken (token, callback) {
2377    addParseToken(token, function (input, array, config, token) {
2378        config._w = config._w || {};
2379        callback(input, config._w, config, token);
2380    });
2381}
2382
2383function addTimeToArrayFromToken(token, input, config) {
2384    if (input != null && hasOwnProp(tokens, token)) {
2385        tokens[token](input, config._a, config, token);
2386    }
2387}
2388
2389var YEAR = 0;
2390var MONTH = 1;
2391var DATE = 2;
2392var HOUR = 3;
2393var MINUTE = 4;
2394var SECOND = 5;
2395var MILLISECOND = 6;
2396var WEEK = 7;
2397var WEEKDAY = 8;
2398
2399// FORMATTING
2400
2401addFormatToken('Y', 0, 0, function () {
2402    var y = this.year();
2403    return y <= 9999 ? '' + y : '+' + y;
2404});
2405
2406addFormatToken(0, ['YY', 2], 0, function () {
2407    return this.year() % 100;
2408});
2409
2410addFormatToken(0, ['YYYY',   4],       0, 'year');
2411addFormatToken(0, ['YYYYY',  5],       0, 'year');
2412addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
2413
2414// ALIASES
2415
2416addUnitAlias('year', 'y');
2417
2418// PRIORITIES
2419
2420addUnitPriority('year', 1);
2421
2422// PARSING
2423
2424addRegexToken('Y',      matchSigned);
2425addRegexToken('YY',     match1to2, match2);
2426addRegexToken('YYYY',   match1to4, match4);
2427addRegexToken('YYYYY',  match1to6, match6);
2428addRegexToken('YYYYYY', match1to6, match6);
2429
2430addParseToken(['YYYYY', 'YYYYYY'], YEAR);
2431addParseToken('YYYY', function (input, array) {
2432    array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
2433});
2434addParseToken('YY', function (input, array) {
2435    array[YEAR] = hooks.parseTwoDigitYear(input);
2436});
2437addParseToken('Y', function (input, array) {
2438    array[YEAR] = parseInt(input, 10);
2439});
2440
2441// HELPERS
2442
2443function daysInYear(year) {
2444    return isLeapYear(year) ? 366 : 365;
2445}
2446
2447function isLeapYear(year) {
2448    return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
2449}
2450
2451// HOOKS
2452
2453hooks.parseTwoDigitYear = function (input) {
2454    return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
2455};
2456
2457// MOMENTS
2458
2459var getSetYear = makeGetSet('FullYear', true);
2460
2461function getIsLeapYear () {
2462    return isLeapYear(this.year());
2463}
2464
2465function makeGetSet (unit, keepTime) {
2466    return function (value) {
2467        if (value != null) {
2468            set$1(this, unit, value);
2469            hooks.updateOffset(this, keepTime);
2470            return this;
2471        } else {
2472            return get(this, unit);
2473        }
2474    };
2475}
2476
2477function get (mom, unit) {
2478    return mom.isValid() ?
2479        mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
2480}
2481
2482function set$1 (mom, unit, value) {
2483    if (mom.isValid() && !isNaN(value)) {
2484        if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
2485            mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
2486        }
2487        else {
2488            mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
2489        }
2490    }
2491}
2492
2493// MOMENTS
2494
2495function stringGet (units) {
2496    units = normalizeUnits(units);
2497    if (isFunction(this[units])) {
2498        return this[units]();
2499    }
2500    return this;
2501}
2502
2503
2504function stringSet (units, value) {
2505    if (typeof units === 'object') {
2506        units = normalizeObjectUnits(units);
2507        var prioritized = getPrioritizedUnits(units);
2508        for (var i = 0; i < prioritized.length; i++) {
2509            this[prioritized[i].unit](units[prioritized[i].unit]);
2510        }
2511    } else {
2512        units = normalizeUnits(units);
2513        if (isFunction(this[units])) {
2514            return this[units](value);
2515        }
2516    }
2517    return this;
2518}
2519
2520function mod(n, x) {
2521    return ((n % x) + x) % x;
2522}
2523
2524var indexOf;
2525
2526if (Array.prototype.indexOf) {
2527    indexOf = Array.prototype.indexOf;
2528} else {
2529    indexOf = function (o) {
2530        // I know
2531        var i;
2532        for (i = 0; i < this.length; ++i) {
2533            if (this[i] === o) {
2534                return i;
2535            }
2536        }
2537        return -1;
2538    };
2539}
2540
2541function daysInMonth(year, month) {
2542    if (isNaN(year) || isNaN(month)) {
2543        return NaN;
2544    }
2545    var modMonth = mod(month, 12);
2546    year += (month - modMonth) / 12;
2547    return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);
2548}
2549
2550// FORMATTING
2551
2552addFormatToken('M', ['MM', 2], 'Mo', function () {
2553    return this.month() + 1;
2554});
2555
2556addFormatToken('MMM', 0, 0, function (format) {
2557    return this.localeData().monthsShort(this, format);
2558});
2559
2560addFormatToken('MMMM', 0, 0, function (format) {
2561    return this.localeData().months(this, format);
2562});
2563
2564// ALIASES
2565
2566addUnitAlias('month', 'M');
2567
2568// PRIORITY
2569
2570addUnitPriority('month', 8);
2571
2572// PARSING
2573
2574addRegexToken('M',    match1to2);
2575addRegexToken('MM',   match1to2, match2);
2576addRegexToken('MMM',  function (isStrict, locale) {
2577    return locale.monthsShortRegex(isStrict);
2578});
2579addRegexToken('MMMM', function (isStrict, locale) {
2580    return locale.monthsRegex(isStrict);
2581});
2582
2583addParseToken(['M', 'MM'], function (input, array) {
2584    array[MONTH] = toInt(input) - 1;
2585});
2586
2587addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
vendor: 24,092 bytes, lines 2588-3372
2588    var month = config._locale.monthsParse(input, token, config._strict);
2589    // if we didn't find a month name, mark the date as invalid.
2590    if (month != null) {
2591        array[MONTH] = month;
2592    } else {
2593        getParsingFlags(config).invalidMonth = input;
2594    }
2595});
2596
2597// LOCALES
2598
2599var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
2600var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
2601function localeMonths (m, format) {
2602    if (!m) {
2603        return isArray(this._months) ? this._months :
2604            this._months['standalone'];
2605    }
2606    return isArray(this._months) ? this._months[m.month()] :
2607        this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
2608}
2609
2610var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
2611function localeMonthsShort (m, format) {
2612    if (!m) {
2613        return isArray(this._monthsShort) ? this._monthsShort :
2614            this._monthsShort['standalone'];
2615    }
2616    return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
2617        this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
2618}
2619
2620function handleStrictParse(monthName, format, strict) {
2621    var i, ii, mom, llc = monthName.toLocaleLowerCase();
2622    if (!this._monthsParse) {
2623        // this is not used
2624        this._monthsParse = [];
2625        this._longMonthsParse = [];
2626        this._shortMonthsParse = [];
2627        for (i = 0; i < 12; ++i) {
2628            mom = createUTC([2000, i]);
2629            this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
2630            this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
2631        }
2632    }
2633
2634    if (strict) {
2635        if (format === 'MMM') {
2636            ii = indexOf.call(this._shortMonthsParse, llc);
2637            return ii !== -1 ? ii : null;
2638        } else {
2639            ii = indexOf.call(this._longMonthsParse, llc);
2640            return ii !== -1 ? ii : null;
2641        }
2642    } else {
2643        if (format === 'MMM') {
2644            ii = indexOf.call(this._shortMonthsParse, llc);
2645            if (ii !== -1) {
2646                return ii;
2647            }
2648            ii = indexOf.call(this._longMonthsParse, llc);
2649            return ii !== -1 ? ii : null;
2650        } else {
2651            ii = indexOf.call(this._longMonthsParse, llc);
2652            if (ii !== -1) {
2653                return ii;
2654            }
2655            ii = indexOf.call(this._shortMonthsParse, llc);
2656            return ii !== -1 ? ii : null;
2657        }
2658    }
2659}
2660
2661function localeMonthsParse (monthName, format, strict) {
2662    var i, mom, regex;
2663
2664    if (this._monthsParseExact) {
2665        return handleStrictParse.call(this, monthName, format, strict);
2666    }
2667
2668    if (!this._monthsParse) {
2669        this._monthsParse = [];
2670        this._longMonthsParse = [];
2671        this._shortMonthsParse = [];
2672    }
2673
2674    // TODO: add sorting
2675    // Sorting makes sure if one month (or abbr) is a prefix of another
2676    // see sorting in computeMonthsParse
2677    for (i = 0; i < 12; i++) {
2678        // make the regex if we don't have it already
2679        mom = createUTC([2000, i]);
2680        if (strict && !this._longMonthsParse[i]) {
2681            this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
2682            this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
2683        }
2684        if (!strict && !this._monthsParse[i]) {
2685            regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
2686            this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
2687        }
2688        // test the regex
2689        if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
2690            return i;
2691        } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
2692            return i;
2693        } else if (!strict && this._monthsParse[i].test(monthName)) {
2694            return i;
2695        }
2696    }
2697}
2698
2699// MOMENTS
2700
2701function setMonth (mom, value) {
2702    var dayOfMonth;
2703
2704    if (!mom.isValid()) {
2705        // No op
2706        return mom;
2707    }
2708
2709    if (typeof value === 'string') {
2710        if (/^\d+$/.test(value)) {
2711            value = toInt(value);
2712        } else {
2713            value = mom.localeData().monthsParse(value);
2714            // TODO: Another silent failure?
2715            if (!isNumber(value)) {
2716                return mom;
2717            }
2718        }
2719    }
2720
2721    dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
2722    mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
2723    return mom;
2724}
2725
2726function getSetMonth (value) {
2727    if (value != null) {
2728        setMonth(this, value);
2729        hooks.updateOffset(this, true);
2730        return this;
2731    } else {
2732        return get(this, 'Month');
2733    }
2734}
2735
2736function getDaysInMonth () {
2737    return daysInMonth(this.year(), this.month());
2738}
2739
2740var defaultMonthsShortRegex = matchWord;
2741function monthsShortRegex (isStrict) {
2742    if (this._monthsParseExact) {
2743        if (!hasOwnProp(this, '_monthsRegex')) {
2744            computeMonthsParse.call(this);
2745        }
2746        if (isStrict) {
2747            return this._monthsShortStrictRegex;
2748        } else {
2749            return this._monthsShortRegex;
2750        }
2751    } else {
2752        if (!hasOwnProp(this, '_monthsShortRegex')) {
2753            this._monthsShortRegex = defaultMonthsShortRegex;
2754        }
2755        return this._monthsShortStrictRegex && isStrict ?
2756            this._monthsShortStrictRegex : this._monthsShortRegex;
2757    }
2758}
2759
2760var defaultMonthsRegex = matchWord;
2761function monthsRegex (isStrict) {
2762    if (this._monthsParseExact) {
2763        if (!hasOwnProp(this, '_monthsRegex')) {
2764            computeMonthsParse.call(this);
2765        }
2766        if (isStrict) {
2767            return this._monthsStrictRegex;
2768        } else {
2769            return this._monthsRegex;
2770        }
2771    } else {
2772        if (!hasOwnProp(this, '_monthsRegex')) {
2773            this._monthsRegex = defaultMonthsRegex;
2774        }
2775        return this._monthsStrictRegex && isStrict ?
2776            this._monthsStrictRegex : this._monthsRegex;
2777    }
2778}
2779
2780function computeMonthsParse () {
2781    function cmpLenRev(a, b) {
2782        return b.length - a.length;
2783    }
2784
2785    var shortPieces = [], longPieces = [], mixedPieces = [],
2786        i, mom;
2787    for (i = 0; i < 12; i++) {
2788        // make the regex if we don't have it already
2789        mom = createUTC([2000, i]);
2790        shortPieces.push(this.monthsShort(mom, ''));
2791        longPieces.push(this.months(mom, ''));
2792        mixedPieces.push(this.months(mom, ''));
2793        mixedPieces.push(this.monthsShort(mom, ''));
2794    }
2795    // Sorting makes sure if one month (or abbr) is a prefix of another it
2796    // will match the longer piece.
2797    shortPieces.sort(cmpLenRev);
2798    longPieces.sort(cmpLenRev);
2799    mixedPieces.sort(cmpLenRev);
2800    for (i = 0; i < 12; i++) {
2801        shortPieces[i] = regexEscape(shortPieces[i]);
2802        longPieces[i] = regexEscape(longPieces[i]);
2803    }
2804    for (i = 0; i < 24; i++) {
2805        mixedPieces[i] = regexEscape(mixedPieces[i]);
2806    }
2807
2808    this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
2809    this._monthsShortRegex = this._monthsRegex;
2810    this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
2811    this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
2812}
2813
2814function createDate (y, m, d, h, M, s, ms) {
2815    // can't just apply() to create a date:
2816    // https://stackoverflow.com/q/181348
2817    var date = new Date(y, m, d, h, M, s, ms);
2818
2819    // the date constructor remaps years 0-99 to 1900-1999
2820    if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
2821        date.setFullYear(y);
2822    }
2823    return date;
2824}
2825
2826function createUTCDate (y) {
2827    var date = new Date(Date.UTC.apply(null, arguments));
2828
2829    // the Date.UTC function remaps years 0-99 to 1900-1999
2830    if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
2831        date.setUTCFullYear(y);
2832    }
2833    return date;
2834}
2835
2836// start-of-first-week - start-of-year
2837function firstWeekOffset(year, dow, doy) {
2838    var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
2839        fwd = 7 + dow - doy,
2840        // first-week day local weekday -- which local weekday is fwd
2841        fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
2842
2843    return -fwdlw + fwd - 1;
2844}
2845
2846// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
2847function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
2848    var localWeekday = (7 + weekday - dow) % 7,
2849        weekOffset = firstWeekOffset(year, dow, doy),
2850        dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
2851        resYear, resDayOfYear;
2852
2853    if (dayOfYear <= 0) {
2854        resYear = year - 1;
2855        resDayOfYear = daysInYear(resYear) + dayOfYear;
2856    } else if (dayOfYear > daysInYear(year)) {
2857        resYear = year + 1;
2858        resDayOfYear = dayOfYear - daysInYear(year);
2859    } else {
2860        resYear = year;
2861        resDayOfYear = dayOfYear;
2862    }
2863
2864    return {
2865        year: resYear,
2866        dayOfYear: resDayOfYear
2867    };
2868}
2869
2870function weekOfYear(mom, dow, doy) {
2871    var weekOffset = firstWeekOffset(mom.year(), dow, doy),
2872        week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
2873        resWeek, resYear;
2874
2875    if (week < 1) {
2876        resYear = mom.year() - 1;
2877        resWeek = week + weeksInYear(resYear, dow, doy);
2878    } else if (week > weeksInYear(mom.year(), dow, doy)) {
2879        resWeek = week - weeksInYear(mom.year(), dow, doy);
2880        resYear = mom.year() + 1;
2881    } else {
2882        resYear = mom.year();
2883        resWeek = week;
2884    }
2885
2886    return {
2887        week: resWeek,
2888        year: resYear
2889    };
2890}
2891
2892function weeksInYear(year, dow, doy) {
2893    var weekOffset = firstWeekOffset(year, dow, doy),
2894        weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
2895    return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
2896}
2897
2898// FORMATTING
2899
2900addFormatToken('w', ['ww', 2], 'wo', 'week');
2901addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
2902
2903// ALIASES
2904
2905addUnitAlias('week', 'w');
2906addUnitAlias('isoWeek', 'W');
2907
2908// PRIORITIES
2909
2910addUnitPriority('week', 5);
2911addUnitPriority('isoWeek', 5);
2912
2913// PARSING
2914
2915addRegexToken('w',  match1to2);
2916addRegexToken('ww', match1to2, match2);
2917addRegexToken('W',  match1to2);
2918addRegexToken('WW', match1to2, match2);
2919
2920addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
2921    week[token.substr(0, 1)] = toInt(input);
2922});
2923
2924// HELPERS
2925
2926// LOCALES
2927
2928function localeWeek (mom) {
2929    return weekOfYear(mom, this._week.dow, this._week.doy).week;
2930}
2931
2932var defaultLocaleWeek = {
2933    dow : 0, // Sunday is the first day of the week.
2934    doy : 6  // The week that contains Jan 1st is the first week of the year.
2935};
2936
2937function localeFirstDayOfWeek () {
2938    return this._week.dow;
2939}
2940
2941function localeFirstDayOfYear () {
2942    return this._week.doy;
2943}
2944
2945// MOMENTS
2946
2947function getSetWeek (input) {
2948    var week = this.localeData().week(this);
2949    return input == null ? week : this.add((input - week) * 7, 'd');
2950}
2951
2952function getSetISOWeek (input) {
2953    var week = weekOfYear(this, 1, 4).week;
2954    return input == null ? week : this.add((input - week) * 7, 'd');
2955}
2956
2957// FORMATTING
2958
2959addFormatToken('d', 0, 'do', 'day');
2960
2961addFormatToken('dd', 0, 0, function (format) {
2962    return this.localeData().weekdaysMin(this, format);
2963});
2964
2965addFormatToken('ddd', 0, 0, function (format) {
2966    return this.localeData().weekdaysShort(this, format);
2967});
2968
2969addFormatToken('dddd', 0, 0, function (format) {
2970    return this.localeData().weekdays(this, format);
2971});
2972
2973addFormatToken('e', 0, 0, 'weekday');
2974addFormatToken('E', 0, 0, 'isoWeekday');
2975
2976// ALIASES
2977
2978addUnitAlias('day', 'd');
2979addUnitAlias('weekday', 'e');
2980addUnitAlias('isoWeekday', 'E');
2981
2982// PRIORITY
2983addUnitPriority('day', 11);
2984addUnitPriority('weekday', 11);
2985addUnitPriority('isoWeekday', 11);
2986
2987// PARSING
2988
2989addRegexToken('d',    match1to2);
2990addRegexToken('e',    match1to2);
2991addRegexToken('E',    match1to2);
2992addRegexToken('dd',   function (isStrict, locale) {
2993    return locale.weekdaysMinRegex(isStrict);
2994});
2995addRegexToken('ddd',   function (isStrict, locale) {
2996    return locale.weekdaysShortRegex(isStrict);
2997});
2998addRegexToken('dddd',   function (isStrict, locale) {
2999    return locale.weekdaysRegex(isStrict);
3000});
3001
3002addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
3003    var weekday = config._locale.weekdaysParse(input, token, config._strict);
3004    // if we didn't get a weekday name, mark the date as invalid
3005    if (weekday != null) {
3006        week.d = weekday;
3007    } else {
3008        getParsingFlags(config).invalidWeekday = input;
3009    }
3010});
3011
3012addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
3013    week[token] = toInt(input);
3014});
3015
3016// HELPERS
3017
3018function parseWeekday(input, locale) {
3019    if (typeof input !== 'string') {
3020        return input;
3021    }
3022
3023    if (!isNaN(input)) {
3024        return parseInt(input, 10);
3025    }
3026
3027    input = locale.weekdaysParse(input);
3028    if (typeof input === 'number') {
3029        return input;
3030    }
3031
3032    return null;
3033}
3034
3035function parseIsoWeekday(input, locale) {
3036    if (typeof input === 'string') {
3037        return locale.weekdaysParse(input) % 7 || 7;
3038    }
3039    return isNaN(input) ? null : input;
3040}
3041
3042// LOCALES
3043
3044var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
3045function localeWeekdays (m, format) {
3046    if (!m) {
3047        return isArray(this._weekdays) ? this._weekdays :
3048            this._weekdays['standalone'];
3049    }
3050    return isArray(this._weekdays) ? this._weekdays[m.day()] :
3051        this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
3052}
3053
3054var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
3055function localeWeekdaysShort (m) {
3056    return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
3057}
3058
3059var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
3060function localeWeekdaysMin (m) {
3061    return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
3062}
3063
3064function handleStrictParse$1(weekdayName, format, strict) {
3065    var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
3066    if (!this._weekdaysParse) {
3067        this._weekdaysParse = [];
3068        this._shortWeekdaysParse = [];
3069        this._minWeekdaysParse = [];
3070
3071        for (i = 0; i < 7; ++i) {
3072            mom = createUTC([2000, 1]).day(i);
3073            this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
3074            this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
3075            this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
3076        }
3077    }
3078
3079    if (strict) {
3080        if (format === 'dddd') {
3081            ii = indexOf.call(this._weekdaysParse, llc);
3082            return ii !== -1 ? ii : null;
3083        } else if (format === 'ddd') {
3084            ii = indexOf.call(this._shortWeekdaysParse, llc);
3085            return ii !== -1 ? ii : null;
3086        } else {
3087            ii = indexOf.call(this._minWeekdaysParse, llc);
3088            return ii !== -1 ? ii : null;
3089        }
3090    } else {
3091        if (format === 'dddd') {
3092            ii = indexOf.call(this._weekdaysParse, llc);
3093            if (ii !== -1) {
3094                return ii;
3095            }
3096            ii = indexOf.call(this._shortWeekdaysParse, llc);
3097            if (ii !== -1) {
3098                return ii;
3099            }
3100            ii = indexOf.call(this._minWeekdaysParse, llc);
3101            return ii !== -1 ? ii : null;
3102        } else if (format === 'ddd') {
3103            ii = indexOf.call(this._shortWeekdaysParse, llc);
3104            if (ii !== -1) {
3105                return ii;
3106            }
3107            ii = indexOf.call(this._weekdaysParse, llc);
3108            if (ii !== -1) {
3109                return ii;
3110            }
3111            ii = indexOf.call(this._minWeekdaysParse, llc);
3112            return ii !== -1 ? ii : null;
3113        } else {
3114            ii = indexOf.call(this._minWeekdaysParse, llc);
3115            if (ii !== -1) {
3116                return ii;
3117            }
3118            ii = indexOf.call(this._weekdaysParse, llc);
3119            if (ii !== -1) {
3120                return ii;
3121            }
3122            ii = indexOf.call(this._shortWeekdaysParse, llc);
3123            return ii !== -1 ? ii : null;
3124        }
3125    }
3126}
3127
3128function localeWeekdaysParse (weekdayName, format, strict) {
3129    var i, mom, regex;
3130
3131    if (this._weekdaysParseExact) {
3132        return handleStrictParse$1.call(this, weekdayName, format, strict);
3133    }
3134
3135    if (!this._weekdaysParse) {
3136        this._weekdaysParse = [];
3137        this._minWeekdaysParse = [];
3138        this._shortWeekdaysParse = [];
3139        this._fullWeekdaysParse = [];
3140    }
3141
3142    for (i = 0; i < 7; i++) {
3143        // make the regex if we don't have it already
3144
3145        mom = createUTC([2000, 1]).day(i);
3146        if (strict && !this._fullWeekdaysParse[i]) {
3147            this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
3148            this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
3149            this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
3150        }
3151        if (!this._weekdaysParse[i]) {
3152            regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
3153            this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
3154        }
3155        // test the regex
3156        if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
3157            return i;
3158        } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
3159            return i;
3160        } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
3161            return i;
3162        } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
3163            return i;
3164        }
3165    }
3166}
3167
3168// MOMENTS
3169
3170function getSetDayOfWeek (input) {
3171    if (!this.isValid()) {
3172        return input != null ? this : NaN;
3173    }
3174    var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
3175    if (input != null) {
3176        input = parseWeekday(input, this.localeData());
3177        return this.add(input - day, 'd');
3178    } else {
3179        return day;
3180    }
3181}
3182
3183function getSetLocaleDayOfWeek (input) {
3184    if (!this.isValid()) {
3185        return input != null ? this : NaN;
3186    }
3187    var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
3188    return input == null ? weekday : this.add(input - weekday, 'd');
3189}
3190
3191function getSetISODayOfWeek (input) {
3192    if (!this.isValid()) {
3193        return input != null ? this : NaN;
3194    }
3195
3196    // behaves the same as moment#day except
3197    // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
3198    // as a setter, sunday should belong to the previous week.
3199
3200    if (input != null) {
3201        var weekday = parseIsoWeekday(input, this.localeData());
3202        return this.day(this.day() % 7 ? weekday : weekday - 7);
3203    } else {
3204        return this.day() || 7;
3205    }
3206}
3207
3208var defaultWeekdaysRegex = matchWord;
3209function weekdaysRegex (isStrict) {
3210    if (this._weekdaysParseExact) {
3211        if (!hasOwnProp(this, '_weekdaysRegex')) {
3212            computeWeekdaysParse.call(this);
3213        }
3214        if (isStrict) {
3215            return this._weekdaysStrictRegex;
3216        } else {
3217            return this._weekdaysRegex;
3218        }
3219    } else {
3220        if (!hasOwnProp(this, '_weekdaysRegex')) {
3221            this._weekdaysRegex = defaultWeekdaysRegex;
3222        }
3223        return this._weekdaysStrictRegex && isStrict ?
3224            this._weekdaysStrictRegex : this._weekdaysRegex;
3225    }
3226}
3227
3228var defaultWeekdaysShortRegex = matchWord;
3229function weekdaysShortRegex (isStrict) {
3230    if (this._weekdaysParseExact) {
3231        if (!hasOwnProp(this, '_weekdaysRegex')) {
3232            computeWeekdaysParse.call(this);
3233        }
3234        if (isStrict) {
3235            return this._weekdaysShortStrictRegex;
3236        } else {
3237            return this._weekdaysShortRegex;
3238        }
3239    } else {
3240        if (!hasOwnProp(this, '_weekdaysShortRegex')) {
3241            this._weekdaysShortRegex = defaultWeekdaysShortRegex;
3242        }
3243        return this._weekdaysShortStrictRegex && isStrict ?
3244            this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
3245    }
3246}
3247
3248var defaultWeekdaysMinRegex = matchWord;
3249function weekdaysMinRegex (isStrict) {
3250    if (this._weekdaysParseExact) {
3251        if (!hasOwnProp(this, '_weekdaysRegex')) {
3252            computeWeekdaysParse.call(this);
3253        }
3254        if (isStrict) {
3255            return this._weekdaysMinStrictRegex;
3256        } else {
3257            return this._weekdaysMinRegex;
3258        }
3259    } else {
3260        if (!hasOwnProp(this, '_weekdaysMinRegex')) {
3261            this._weekdaysMinRegex = defaultWeekdaysMinRegex;
3262        }
3263        return this._weekdaysMinStrictRegex && isStrict ?
3264            this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
3265    }
3266}
3267
3268
3269function computeWeekdaysParse () {
3270    function cmpLenRev(a, b) {
3271        return b.length - a.length;
3272    }
3273
3274    var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
3275        i, mom, minp, shortp, longp;
3276    for (i = 0; i < 7; i++) {
3277        // make the regex if we don't have it already
3278        mom = createUTC([2000, 1]).day(i);
3279        minp = this.weekdaysMin(mom, '');
3280        shortp = this.weekdaysShort(mom, '');
3281        longp = this.weekdays(mom, '');
3282        minPieces.push(minp);
3283        shortPieces.push(shortp);
3284        longPieces.push(longp);
3285        mixedPieces.push(minp);
3286        mixedPieces.push(shortp);
3287        mixedPieces.push(longp);
3288    }
3289    // Sorting makes sure if one weekday (or abbr) is a prefix of another it
3290    // will match the longer piece.
3291    minPieces.sort(cmpLenRev);
3292    shortPieces.sort(cmpLenRev);
3293    longPieces.sort(cmpLenRev);
3294    mixedPieces.sort(cmpLenRev);
3295    for (i = 0; i < 7; i++) {
3296        shortPieces[i] = regexEscape(shortPieces[i]);
3297        longPieces[i] = regexEscape(longPieces[i]);
3298        mixedPieces[i] = regexEscape(mixedPieces[i]);
3299    }
3300
3301    this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
3302    this._weekdaysShortRegex = this._weekdaysRegex;
3303    this._weekdaysMinRegex = this._weekdaysRegex;
3304
3305    this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
3306    this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
3307    this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
3308}
3309
3310// FORMATTING
3311
3312function hFormat() {
3313    return this.hours() % 12 || 12;
3314}
3315
3316function kFormat() {
3317    return this.hours() || 24;
3318}
3319
3320addFormatToken('H', ['HH', 2], 0, 'hour');
3321addFormatToken('h', ['hh', 2], 0, hFormat);
3322addFormatToken('k', ['kk', 2], 0, kFormat);
3323
3324addFormatToken('hmm', 0, 0, function () {
3325    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
3326});
3327
3328addFormatToken('hmmss', 0, 0, function () {
3329    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
3330        zeroFill(this.seconds(), 2);
3331});
3332
3333addFormatToken('Hmm', 0, 0, function () {
3334    return '' + this.hours() + zeroFill(this.minutes(), 2);
3335});
3336
3337addFormatToken('Hmmss', 0, 0, function () {
3338    return '' + this.hours() + zeroFill(this.minutes(), 2) +
3339        zeroFill(this.seconds(), 2);
3340});
3341
3342function meridiem (token, lowercase) {
3343    addFormatToken(token, 0, 0, function () {
3344        return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
3345    });
3346}
3347
3348meridiem('a', true);
3349meridiem('A', false);
3350
3351// ALIASES
3352
3353addUnitAlias('hour', 'h');
3354
3355// PRIORITY
3356addUnitPriority('hour', 13);
3357
3358// PARSING
3359
3360function matchMeridiem (isStrict, locale) {
3361    return locale._meridiemParse;
3362}
3363
3364addRegexToken('a',  matchMeridiem);
3365addRegexToken('A',  matchMeridiem);
3366addRegexToken('H',  match1to2);
3367addRegexToken('h',  match1to2);
3368addRegexToken('k',  match1to2);
3369addRegexToken('HH', match1to2, match2);
3370addRegexToken('hh', match1to2, match2);
3371addRegexToken('kk', match1to2, match2);
3372
vendor: 18,399 bytes, lines 3373-3945
3373addRegexToken('hmm', match3to4);
3374addRegexToken('hmmss', match5to6);
3375addRegexToken('Hmm', match3to4);
3376addRegexToken('Hmmss', match5to6);
3377
3378addParseToken(['H', 'HH'], HOUR);
3379addParseToken(['k', 'kk'], function (input, array, config) {
3380    var kInput = toInt(input);
3381    array[HOUR] = kInput === 24 ? 0 : kInput;
3382});
3383addParseToken(['a', 'A'], function (input, array, config) {
3384    config._isPm = config._locale.isPM(input);
3385    config._meridiem = input;
3386});
3387addParseToken(['h', 'hh'], function (input, array, config) {
3388    array[HOUR] = toInt(input);
3389    getParsingFlags(config).bigHour = true;
3390});
3391addParseToken('hmm', function (input, array, config) {
3392    var pos = input.length - 2;
3393    array[HOUR] = toInt(input.substr(0, pos));
3394    array[MINUTE] = toInt(input.substr(pos));
3395    getParsingFlags(config).bigHour = true;
3396});
3397addParseToken('hmmss', function (input, array, config) {
3398    var pos1 = input.length - 4;
3399    var pos2 = input.length - 2;
3400    array[HOUR] = toInt(input.substr(0, pos1));
3401    array[MINUTE] = toInt(input.substr(pos1, 2));
3402    array[SECOND] = toInt(input.substr(pos2));
3403    getParsingFlags(config).bigHour = true;
3404});
3405addParseToken('Hmm', function (input, array, config) {
3406    var pos = input.length - 2;
3407    array[HOUR] = toInt(input.substr(0, pos));
3408    array[MINUTE] = toInt(input.substr(pos));
3409});
3410addParseToken('Hmmss', function (input, array, config) {
3411    var pos1 = input.length - 4;
3412    var pos2 = input.length - 2;
3413    array[HOUR] = toInt(input.substr(0, pos1));
3414    array[MINUTE] = toInt(input.substr(pos1, 2));
3415    array[SECOND] = toInt(input.substr(pos2));
3416});
3417
3418// LOCALES
3419
3420function localeIsPM (input) {
3421    // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
3422    // Using charAt should be more compatible.
3423    return ((input + '').toLowerCase().charAt(0) === 'p');
3424}
3425
3426var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
3427function localeMeridiem (hours, minutes, isLower) {
3428    if (hours > 11) {
3429        return isLower ? 'pm' : 'PM';
3430    } else {
3431        return isLower ? 'am' : 'AM';
3432    }
3433}
3434
3435
3436// MOMENTS
3437
3438// Setting the hour should keep the time, because the user explicitly
3439// specified which hour he wants. So trying to maintain the same hour (in
3440// a new timezone) makes sense. Adding/subtracting hours does not follow
3441// this rule.
3442var getSetHour = makeGetSet('Hours', true);
3443
3444// months
3445// week
3446// weekdays
3447// meridiem
3448var baseConfig = {
3449    calendar: defaultCalendar,
3450    longDateFormat: defaultLongDateFormat,
3451    invalidDate: defaultInvalidDate,
3452    ordinal: defaultOrdinal,
3453    dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
3454    relativeTime: defaultRelativeTime,
3455
3456    months: defaultLocaleMonths,
3457    monthsShort: defaultLocaleMonthsShort,
3458
3459    week: defaultLocaleWeek,
3460
3461    weekdays: defaultLocaleWeekdays,
3462    weekdaysMin: defaultLocaleWeekdaysMin,
3463    weekdaysShort: defaultLocaleWeekdaysShort,
3464
3465    meridiemParse: defaultLocaleMeridiemParse
3466};
3467
3468// internal storage for locale config files
3469var locales = {};
3470var localeFamilies = {};
3471var globalLocale;
3472
3473function normalizeLocale(key) {
3474    return key ? key.toLowerCase().replace('_', '-') : key;
3475}
3476
3477// pick the locale from the array
3478// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
3479// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
3480function chooseLocale(names) {
3481    var i = 0, j, next, locale, split;
3482
3483    while (i < names.length) {
3484        split = normalizeLocale(names[i]).split('-');
3485        j = split.length;
3486        next = normalizeLocale(names[i + 1]);
3487        next = next ? next.split('-') : null;
3488        while (j > 0) {
3489            locale = loadLocale(split.slice(0, j).join('-'));
3490            if (locale) {
3491                return locale;
3492            }
3493            if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
3494                //the next array item is better than a shallower substring of this one
3495                break;
3496            }
3497            j--;
3498        }
3499        i++;
3500    }
3501    return null;
3502}
3503
3504function loadLocale(name) {
3505    var oldLocale = null;
3506    // TODO: Find a better way to register and load all the locales in Node
3507    if (!locales[name] && (typeof module !== 'undefined') &&
3508            module && module.exports) {
3509        try {
3510            oldLocale = globalLocale._abbr;
3511            var aliasedRequire = require;
3512            aliasedRequire('./locale/' + name);
3513            getSetGlobalLocale(oldLocale);
3514        } catch (e) {}
3515    }
3516    return locales[name];
3517}
3518
3519// This function will load locale and then set the global locale.  If
3520// no arguments are passed in, it will simply return the current global
3521// locale key.
3522function getSetGlobalLocale (key, values) {
3523    var data;
3524    if (key) {
3525        if (isUndefined(values)) {
3526            data = getLocale(key);
3527        }
3528        else {
3529            data = defineLocale(key, values);
3530        }
3531
3532        if (data) {
3533            // moment.duration._locale = moment._locale = data;
3534            globalLocale = data;
3535        }
3536    }
3537
3538    return globalLocale._abbr;
3539}
3540
3541function defineLocale (name, config) {
3542    if (config !== null) {
3543        var parentConfig = baseConfig;
3544        config.abbr = name;
3545        if (locales[name] != null) {
3546            deprecateSimple('defineLocaleOverride',
3547                    'use moment.updateLocale(localeName, config) to change ' +
3548                    'an existing locale. moment.defineLocale(localeName, ' +
3549                    'config) should only be used for creating a new locale ' +
3550                    'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
3551            parentConfig = locales[name]._config;
3552        } else if (config.parentLocale != null) {
3553            if (locales[config.parentLocale] != null) {
3554                parentConfig = locales[config.parentLocale]._config;
3555            } else {
3556                if (!localeFamilies[config.parentLocale]) {
3557                    localeFamilies[config.parentLocale] = [];
3558                }
3559                localeFamilies[config.parentLocale].push({
3560                    name: name,
3561                    config: config
3562                });
3563                return null;
3564            }
3565        }
3566        locales[name] = new Locale(mergeConfigs(parentConfig, config));
3567
3568        if (localeFamilies[name]) {
3569            localeFamilies[name].forEach(function (x) {
3570                defineLocale(x.name, x.config);
3571            });
3572        }
3573
3574        // backwards compat for now: also set the locale
3575        // make sure we set the locale AFTER all child locales have been
3576        // created, so we won't end up with the child locale set.
3577        getSetGlobalLocale(name);
3578
3579
3580        return locales[name];
3581    } else {
3582        // useful for testing
3583        delete locales[name];
3584        return null;
3585    }
3586}
3587
3588function updateLocale(name, config) {
3589    if (config != null) {
3590        var locale, tmpLocale, parentConfig = baseConfig;
3591        // MERGE
3592        tmpLocale = loadLocale(name);
3593        if (tmpLocale != null) {
3594            parentConfig = tmpLocale._config;
3595        }
3596        config = mergeConfigs(parentConfig, config);
3597        locale = new Locale(config);
3598        locale.parentLocale = locales[name];
3599        locales[name] = locale;
3600
3601        // backwards compat for now: also set the locale
3602        getSetGlobalLocale(name);
3603    } else {
3604        // pass null for config to unupdate, useful for tests
3605        if (locales[name] != null) {
3606            if (locales[name].parentLocale != null) {
3607                locales[name] = locales[name].parentLocale;
3608            } else if (locales[name] != null) {
3609                delete locales[name];
3610            }
3611        }
3612    }
3613    return locales[name];
3614}
3615
3616// returns locale data
3617function getLocale (key) {
3618    var locale;
3619
3620    if (key && key._locale && key._locale._abbr) {
3621        key = key._locale._abbr;
3622    }
3623
3624    if (!key) {
3625        return globalLocale;
3626    }
3627
3628    if (!isArray(key)) {
3629        //short-circuit everything else
3630        locale = loadLocale(key);
3631        if (locale) {
3632            return locale;
3633        }
3634        key = [key];
3635    }
3636
3637    return chooseLocale(key);
3638}
3639
3640function listLocales() {
3641    return keys(locales);
3642}
3643
3644function checkOverflow (m) {
3645    var overflow;
3646    var a = m._a;
3647
3648    if (a && getParsingFlags(m).overflow === -2) {
3649        overflow =
3650            a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :
3651            a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
3652            a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
3653            a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :
3654            a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :
3655            a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
3656            -1;
3657
3658        if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
3659            overflow = DATE;
3660        }
3661        if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
3662            overflow = WEEK;
3663        }
3664        if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
3665            overflow = WEEKDAY;
3666        }
3667
3668        getParsingFlags(m).overflow = overflow;
3669    }
3670
3671    return m;
3672}
3673
3674// Pick the first defined of two or three arguments.
3675function defaults(a, b, c) {
3676    if (a != null) {
3677        return a;
3678    }
3679    if (b != null) {
3680        return b;
3681    }
3682    return c;
3683}
3684
3685function currentDateArray(config) {
3686    // hooks is actually the exported moment object
3687    var nowValue = new Date(hooks.now());
3688    if (config._useUTC) {
3689        return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
3690    }
3691    return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
3692}
3693
3694// convert an array to a date.
3695// the array should mirror the parameters below
3696// note: all values past the year are optional and will default to the lowest possible value.
3697// [year, month, day , hour, minute, second, millisecond]
3698function configFromArray (config) {
3699    var i, date, input = [], currentDate, expectedWeekday, yearToUse;
3700
3701    if (config._d) {
3702        return;
3703    }
3704
3705    currentDate = currentDateArray(config);
3706
3707    //compute day of the year from weeks and weekdays
3708    if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
3709        dayOfYearFromWeekInfo(config);
3710    }
3711
3712    //if the day of the year is set, figure out what it is
3713    if (config._dayOfYear != null) {
3714        yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
3715
3716        if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
3717            getParsingFlags(config)._overflowDayOfYear = true;
3718        }
3719
3720        date = createUTCDate(yearToUse, 0, config._dayOfYear);
3721        config._a[MONTH] = date.getUTCMonth();
3722        config._a[DATE] = date.getUTCDate();
3723    }
3724
3725    // Default to current date.
3726    // * if no year, month, day of month are given, default to today
3727    // * if day of month is given, default month and year
3728    // * if month is given, default only year
3729    // * if year is given, don't default anything
3730    for (i = 0; i < 3 && config._a[i] == null; ++i) {
3731        config._a[i] = input[i] = currentDate[i];
3732    }
3733
3734    // Zero out whatever was not defaulted, including time
3735    for (; i < 7; i++) {
3736        config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
3737    }
3738
3739    // Check for 24:00:00.000
3740    if (config._a[HOUR] === 24 &&
3741            config._a[MINUTE] === 0 &&
3742            config._a[SECOND] === 0 &&
3743            config._a[MILLISECOND] === 0) {
3744        config._nextDay = true;
3745        config._a[HOUR] = 0;
3746    }
3747
3748    config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
3749    expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay();
3750
3751    // Apply timezone offset from input. The actual utcOffset can be changed
3752    // with parseZone.
3753    if (config._tzm != null) {
3754        config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
3755    }
3756
3757    if (config._nextDay) {
3758        config._a[HOUR] = 24;
3759    }
3760
3761    // check for mismatching day of week
3762    if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
3763        getParsingFlags(config).weekdayMismatch = true;
3764    }
3765}
3766
3767function dayOfYearFromWeekInfo(config) {
3768    var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
3769
3770    w = config._w;
3771    if (w.GG != null || w.W != null || w.E != null) {
3772        dow = 1;
3773        doy = 4;
3774
3775        // TODO: We need to take the current isoWeekYear, but that depends on
3776        // how we interpret now (local, utc, fixed offset). So create
3777        // a now version of current config (take local/utc/offset flags, and
3778        // create now).
3779        weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
3780        week = defaults(w.W, 1);
3781        weekday = defaults(w.E, 1);
3782        if (weekday < 1 || weekday > 7) {
3783            weekdayOverflow = true;
3784        }
3785    } else {
3786        dow = config._locale._week.dow;
3787        doy = config._locale._week.doy;
3788
3789        var curWeek = weekOfYear(createLocal(), dow, doy);
3790
3791        weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
3792
3793        // Default to current week.
3794        week = defaults(w.w, curWeek.week);
3795
3796        if (w.d != null) {
3797            // weekday -- low day numbers are considered next week
3798            weekday = w.d;
3799            if (weekday < 0 || weekday > 6) {
3800                weekdayOverflow = true;
3801            }
3802        } else if (w.e != null) {
3803            // local weekday -- counting starts from begining of week
3804            weekday = w.e + dow;
3805            if (w.e < 0 || w.e > 6) {
3806                weekdayOverflow = true;
3807            }
3808        } else {
3809            // default to begining of week
3810            weekday = dow;
3811        }
3812    }
3813    if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
3814        getParsingFlags(config)._overflowWeeks = true;
3815    } else if (weekdayOverflow != null) {
3816        getParsingFlags(config)._overflowWeekday = true;
3817    } else {
3818        temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
3819        config._a[YEAR] = temp.year;
3820        config._dayOfYear = temp.dayOfYear;
3821    }
3822}
3823
3824// iso 8601 regex
3825// 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)
3826var 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)?)?$/;
3827var 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)?)?$/;
3828
3829var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
3830
3831var isoDates = [
3832    ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
3833    ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
3834    ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
3835    ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
3836    ['YYYY-DDD', /\d{4}-\d{3}/],
3837    ['YYYY-MM', /\d{4}-\d\d/, false],
3838    ['YYYYYYMMDD', /[+-]\d{10}/],
3839    ['YYYYMMDD', /\d{8}/],
3840    // YYYYMM is NOT allowed by the standard
3841    ['GGGG[W]WWE', /\d{4}W\d{3}/],
3842    ['GGGG[W]WW', /\d{4}W\d{2}/, false],
3843    ['YYYYDDD', /\d{7}/]
3844];
3845
3846// iso time formats and regexes
3847var isoTimes = [
3848    ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
3849    ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
3850    ['HH:mm:ss', /\d\d:\d\d:\d\d/],
3851    ['HH:mm', /\d\d:\d\d/],
3852    ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
3853    ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
3854    ['HHmmss', /\d\d\d\d\d\d/],
3855    ['HHmm', /\d\d\d\d/],
3856    ['HH', /\d\d/]
3857];
3858
3859var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
3860
3861// date from iso format
3862function configFromISO(config) {
3863    var i, l,
3864        string = config._i,
3865        match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
3866        allowTime, dateFormat, timeFormat, tzFormat;
3867
3868    if (match) {
3869        getParsingFlags(config).iso = true;
3870
3871        for (i = 0, l = isoDates.length; i < l; i++) {
3872            if (isoDates[i][1].exec(match[1])) {
3873                dateFormat = isoDates[i][0];
3874                allowTime = isoDates[i][2] !== false;
3875                break;
3876            }
3877        }
3878        if (dateFormat == null) {
3879            config._isValid = false;
3880            return;
3881        }
3882        if (match[3]) {
3883            for (i = 0, l = isoTimes.length; i < l; i++) {
3884                if (isoTimes[i][1].exec(match[3])) {
3885                    // match[2] should be 'T' or space
3886                    timeFormat = (match[2] || ' ') + isoTimes[i][0];
3887                    break;
3888                }
3889            }
3890            if (timeFormat == null) {
3891                config._isValid = false;
3892                return;
3893            }
3894        }
3895        if (!allowTime && timeFormat != null) {
3896            config._isValid = false;
3897            return;
3898        }
3899        if (match[4]) {
3900            if (tzRegex.exec(match[4])) {
3901                tzFormat = 'Z';
3902            } else {
3903                config._isValid = false;
3904                return;
3905            }
3906        }
3907        config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
3908        configFromStringAndFormat(config);
3909    } else {
3910        config._isValid = false;
3911    }
3912}
3913
3914// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
3915var 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}))$/;
3916
3917function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
3918    var result = [
3919        untruncateYear(yearStr),
3920        defaultLocaleMonthsShort.indexOf(monthStr),
3921        parseInt(dayStr, 10),
3922        parseInt(hourStr, 10),
3923        parseInt(minuteStr, 10)
3924    ];
3925
3926    if (secondStr) {
3927        result.push(parseInt(secondStr, 10));
3928    }
3929
3930    return result;
3931}
3932
3933function untruncateYear(yearStr) {
3934    var year = parseInt(yearStr, 10);
3935    if (year <= 49) {
3936        return 2000 + year;
3937    } else if (year <= 999) {
3938        return 1900 + year;
3939    }
3940    return year;
3941}
3942
3943function preprocessRFC2822(s) {
3944    // Remove comments and folding whitespace and replace multiple-spaces with a single space
3945    return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').trim(
vendor: 6,917 bytes, lines 3945-4174
3945);
3946}
3947
3948function checkWeekday(weekdayStr, parsedInput, config) {
3949    if (weekdayStr) {
3950        // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
3951        var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
3952            weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
3953        if (weekdayProvided !== weekdayActual) {
3954            getParsingFlags(config).weekdayMismatch = true;
3955            config._isValid = false;
3956            return false;
3957        }
3958    }
3959    return true;
3960}
3961
3962var obsOffsets = {
3963    UT: 0,
3964    GMT: 0,
3965    EDT: -4 * 60,
3966    EST: -5 * 60,
3967    CDT: -5 * 60,
3968    CST: -6 * 60,
3969    MDT: -6 * 60,
3970    MST: -7 * 60,
3971    PDT: -7 * 60,
3972    PST: -8 * 60
3973};
3974
3975function calculateOffset(obsOffset, militaryOffset, numOffset) {
3976    if (obsOffset) {
3977        return obsOffsets[obsOffset];
3978    } else if (militaryOffset) {
3979        // the only allowed military tz is Z
3980        return 0;
3981    } else {
3982        var hm = parseInt(numOffset, 10);
3983        var m = hm % 100, h = (hm - m) / 100;
3984        return h * 60 + m;
3985    }
3986}
3987
3988// date and time from ref 2822 format
3989function configFromRFC2822(config) {
3990    var match = rfc2822.exec(preprocessRFC2822(config._i));
3991    if (match) {
3992        var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
3993        if (!checkWeekday(match[1], parsedArray, config)) {
3994            return;
3995        }
3996
3997        config._a = parsedArray;
3998        config._tzm = calculateOffset(match[8], match[9], match[10]);
3999
4000        config._d = createUTCDate.apply(null, config._a);
4001        config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
4002
4003        getParsingFlags(config).rfc2822 = true;
4004    } else {
4005        config._isValid = false;
4006    }
4007}
4008
4009// date from iso format or fallback
4010function configFromString(config) {
4011    var matched = aspNetJsonRegex.exec(config._i);
4012
4013    if (matched !== null) {
4014        config._d = new Date(+matched[1]);
4015        return;
4016    }
4017
4018    configFromISO(config);
4019    if (config._isValid === false) {
4020        delete config._isValid;
4021    } else {
4022        return;
4023    }
4024
4025    configFromRFC2822(config);
4026    if (config._isValid === false) {
4027        delete config._isValid;
4028    } else {
4029        return;
4030    }
4031
4032    // Final attempt, use Input Fallback
4033    hooks.createFromInputFallback(config);
4034}
4035
4036hooks.createFromInputFallback = deprecate(
4037    'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
4038    'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
4039    'discouraged and will be removed in an upcoming major release. Please refer to ' +
4040    'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
4041    function (config) {
4042        config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
4043    }
4044);
4045
4046// constant that refers to the ISO standard
4047hooks.ISO_8601 = function () {};
4048
4049// constant that refers to the RFC 2822 form
4050hooks.RFC_2822 = function () {};
4051
4052// date from string and format string
4053function configFromStringAndFormat(config) {
4054    // TODO: Move this to another part of the creation flow to prevent circular deps
4055    if (config._f === hooks.ISO_8601) {
4056        configFromISO(config);
4057        return;
4058    }
4059    if (config._f === hooks.RFC_2822) {
4060        configFromRFC2822(config);
4061        return;
4062    }
4063    config._a = [];
4064    getParsingFlags(config).empty = true;
4065
4066    // This array is used to make a Date, either with `new Date` or `Date.UTC`
4067    var string = '' + config._i,
4068        i, parsedInput, tokens, token, skipped,
4069        stringLength = string.length,
4070        totalParsedInputLength = 0;
4071
4072    tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
4073
4074    for (i = 0; i < tokens.length; i++) {
4075        token = tokens[i];
4076        parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
4077        // console.log('token', token, 'parsedInput', parsedInput,
4078        //         'regex', getParseRegexForToken(token, config));
4079        if (parsedInput) {
4080            skipped = string.substr(0, string.indexOf(parsedInput));
4081            if (skipped.length > 0) {
4082                getParsingFlags(config).unusedInput.push(skipped);
4083            }
4084            string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
4085            totalParsedInputLength += parsedInput.length;
4086        }
4087        // don't parse if it's not a known token
4088        if (formatTokenFunctions[token]) {
4089            if (parsedInput) {
4090                getParsingFlags(config).empty = false;
4091            }
4092            else {
4093                getParsingFlags(config).unusedTokens.push(token);
4094            }
4095            addTimeToArrayFromToken(token, parsedInput, config);
4096        }
4097        else if (config._strict && !parsedInput) {
4098            getParsingFlags(config).unusedTokens.push(token);
4099        }
4100    }
4101
4102    // add remaining unparsed input length to the string
4103    getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
4104    if (string.length > 0) {
4105        getParsingFlags(config).unusedInput.push(string);
4106    }
4107
4108    // clear _12h flag if hour is <= 12
4109    if (config._a[HOUR] <= 12 &&
4110        getParsingFlags(config).bigHour === true &&
4111        config._a[HOUR] > 0) {
4112        getParsingFlags(config).bigHour = undefined;
4113    }
4114
4115    getParsingFlags(config).parsedDateParts = config._a.slice(0);
4116    getParsingFlags(config).meridiem = config._meridiem;
4117    // handle meridiem
4118    config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
4119
4120    configFromArray(config);
4121    checkOverflow(config);
4122}
4123
4124
4125function meridiemFixWrap (locale, hour, meridiem) {
4126    var isPm;
4127
4128    if (meridiem == null) {
4129        // nothing to do
4130        return hour;
4131    }
4132    if (locale.meridiemHour != null) {
4133        return locale.meridiemHour(hour, meridiem);
4134    } else if (locale.isPM != null) {
4135        // Fallback
4136        isPm = locale.isPM(meridiem);
4137        if (isPm && hour < 12) {
4138            hour += 12;
4139        }
4140        if (!isPm && hour === 12) {
4141            hour = 0;
4142        }
4143        return hour;
4144    } else {
4145        // this is not supposed to happen
4146        return hour;
4147    }
4148}
4149
4150// date from string and array of format strings
4151function configFromStringAndArray(config) {
4152    var tempConfig,
4153        bestMoment,
4154
4155        scoreToBeat,
4156        i,
4157        currentScore;
4158
4159    if (config._f.length === 0) {
4160        getParsingFlags(config).invalidFormat = true;
4161        config._d = new Date(NaN);
4162        return;
4163    }
4164
4165    for (i = 0; i < config._f.length; i++) {
4166        currentScore = 0;
4167        tempConfig = copyConfig({}, config);
4168        if (config._useUTC != null) {
4169            tempConfig._useUTC = config._useUTC;
4170        }
4171        tempConfig._f = config._f[i];
4172        configFromStringAndFormat(tempConfig);
4173
4174        if (!isValid
vendor: 9,914 bytes, lines 4174-4530
4174(tempConfig)) {
4175            continue;
4176        }
4177
4178        // if there is any input that was not parsed add a penalty for that format
4179        currentScore += getParsingFlags(tempConfig).charsLeftOver;
4180
4181        //or tokens
4182        currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
4183
4184        getParsingFlags(tempConfig).score = currentScore;
4185
4186        if (scoreToBeat == null || currentScore < scoreToBeat) {
4187            scoreToBeat = currentScore;
4188            bestMoment = tempConfig;
4189        }
4190    }
4191
4192    extend(config, bestMoment || tempConfig);
4193}
4194
4195function configFromObject(config) {
4196    if (config._d) {
4197        return;
4198    }
4199
4200    var i = normalizeObjectUnits(config._i);
4201    config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
4202        return obj && parseInt(obj, 10);
4203    });
4204
4205    configFromArray(config);
4206}
4207
4208function createFromConfig (config) {
4209    var res = new Moment(checkOverflow(prepareConfig(config)));
4210    if (res._nextDay) {
4211        // Adding is smart enough around DST
4212        res.add(1, 'd');
4213        res._nextDay = undefined;
4214    }
4215
4216    return res;
4217}
4218
4219function prepareConfig (config) {
4220    var input = config._i,
4221        format = config._f;
4222
4223    config._locale = config._locale || getLocale(config._l);
4224
4225    if (input === null || (format === undefined && input === '')) {
4226        return createInvalid({nullInput: true});
4227    }
4228
4229    if (typeof input === 'string') {
4230        config._i = input = config._locale.preparse(input);
4231    }
4232
4233    if (isMoment(input)) {
4234        return new Moment(checkOverflow(input));
4235    } else if (isDate(input)) {
4236        config._d = input;
4237    } else if (isArray(format)) {
4238        configFromStringAndArray(config);
4239    } else if (format) {
4240        configFromStringAndFormat(config);
4241    }  else {
4242        configFromInput(config);
4243    }
4244
4245    if (!isValid(config)) {
4246        config._d = null;
4247    }
4248
4249    return config;
4250}
4251
4252function configFromInput(config) {
4253    var input = config._i;
4254    if (isUndefined(input)) {
4255        config._d = new Date(hooks.now());
4256    } else if (isDate(input)) {
4257        config._d = new Date(input.valueOf());
4258    } else if (typeof input === 'string') {
4259        configFromString(config);
4260    } else if (isArray(input)) {
4261        config._a = map(input.slice(0), function (obj) {
4262            return parseInt(obj, 10);
4263        });
4264        configFromArray(config);
4265    } else if (isObject(input)) {
4266        configFromObject(config);
4267    } else if (isNumber(input)) {
4268        // from milliseconds
4269        config._d = new Date(input);
4270    } else {
4271        hooks.createFromInputFallback(config);
4272    }
4273}
4274
4275function createLocalOrUTC (input, format, locale, strict, isUTC) {
4276    var c = {};
4277
4278    if (locale === true || locale === false) {
4279        strict = locale;
4280        locale = undefined;
4281    }
4282
4283    if ((isObject(input) && isObjectEmpty(input)) ||
4284            (isArray(input) && input.length === 0)) {
4285        input = undefined;
4286    }
4287    // object construction must be done this way.
4288    // https://github.com/moment/moment/issues/1423
4289    c._isAMomentObject = true;
4290    c._useUTC = c._isUTC = isUTC;
4291    c._l = locale;
4292    c._i = input;
4293    c._f = format;
4294    c._strict = strict;
4295
4296    return createFromConfig(c);
4297}
4298
4299function createLocal (input, format, locale, strict) {
4300    return createLocalOrUTC(input, format, locale, strict, false);
4301}
4302
4303var prototypeMin = deprecate(
4304    'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
4305    function () {
4306        var other = createLocal.apply(null, arguments);
4307        if (this.isValid() && other.isValid()) {
4308            return other < this ? this : other;
4309        } else {
4310            return createInvalid();
4311        }
4312    }
4313);
4314
4315var prototypeMax = deprecate(
4316    'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
4317    function () {
4318        var other = createLocal.apply(null, arguments);
4319        if (this.isValid() && other.isValid()) {
4320            return other > this ? this : other;
4321        } else {
4322            return createInvalid();
4323        }
4324    }
4325);
4326
4327// Pick a moment m from moments so that m[fn](other) is true for all
4328// other. This relies on the function fn to be transitive.
4329//
4330// moments should either be an array of moment objects or an array, whose
4331// first element is an array of moment objects.
4332function pickBy(fn, moments) {
4333    var res, i;
4334    if (moments.length === 1 && isArray(moments[0])) {
4335        moments = moments[0];
4336    }
4337    if (!moments.length) {
4338        return createLocal();
4339    }
4340    res = moments[0];
4341    for (i = 1; i < moments.length; ++i) {
4342        if (!moments[i].isValid() || moments[i][fn](res)) {
4343            res = moments[i];
4344        }
4345    }
4346    return res;
4347}
4348
4349// TODO: Use [].sort instead?
4350function min () {
4351    var args = [].slice.call(arguments, 0);
4352
4353    return pickBy('isBefore', args);
4354}
4355
4356function max () {
4357    var args = [].slice.call(arguments, 0);
4358
4359    return pickBy('isAfter', args);
4360}
4361
4362var now = function () {
4363    return Date.now ? Date.now() : +(new Date());
4364};
4365
4366var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
4367
4368function isDurationValid(m) {
4369    for (var key in m) {
4370        if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
4371            return false;
4372        }
4373    }
4374
4375    var unitHasDecimal = false;
4376    for (var i = 0; i < ordering.length; ++i) {
4377        if (m[ordering[i]]) {
4378            if (unitHasDecimal) {
4379                return false; // only allow non-integers for smallest unit
4380            }
4381            if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
4382                unitHasDecimal = true;
4383            }
4384        }
4385    }
4386
4387    return true;
4388}
4389
4390function isValid$1() {
4391    return this._isValid;
4392}
4393
4394function createInvalid$1() {
4395    return createDuration(NaN);
4396}
4397
4398function Duration (duration) {
4399    var normalizedInput = normalizeObjectUnits(duration),
4400        years = normalizedInput.year || 0,
4401        quarters = normalizedInput.quarter || 0,
4402        months = normalizedInput.month || 0,
4403        weeks = normalizedInput.week || 0,
4404        days = normalizedInput.day || 0,
4405        hours = normalizedInput.hour || 0,
4406        minutes = normalizedInput.minute || 0,
4407        seconds = normalizedInput.second || 0,
4408        milliseconds = normalizedInput.millisecond || 0;
4409
4410    this._isValid = isDurationValid(normalizedInput);
4411
4412    // representation for dateAddRemove
4413    this._milliseconds = +milliseconds +
4414        seconds * 1e3 + // 1000
4415        minutes * 6e4 + // 1000 * 60
4416        hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
4417    // Because of dateAddRemove treats 24 hours as different from a
4418    // day when working around DST, we need to store them separately
4419    this._days = +days +
4420        weeks * 7;
4421    // It is impossible to translate months into days without knowing
4422    // which months you are are talking about, so we have to store
4423    // it separately.
4424    this._months = +months +
4425        quarters * 3 +
4426        years * 12;
4427
4428    this._data = {};
4429
4430    this._locale = getLocale();
4431
4432    this._bubble();
4433}
4434
4435function isDuration (obj) {
4436    return obj instanceof Duration;
4437}
4438
4439function absRound (number) {
4440    if (number < 0) {
4441        return Math.round(-1 * number) * -1;
4442    } else {
4443        return Math.round(number);
4444    }
4445}
4446
4447// FORMATTING
4448
4449function offset (token, separator) {
4450    addFormatToken(token, 0, 0, function () {
4451        var offset = this.utcOffset();
4452        var sign = '+';
4453        if (offset < 0) {
4454            offset = -offset;
4455            sign = '-';
4456        }
4457        return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
4458    });
4459}
4460
4461offset('Z', ':');
4462offset('ZZ', '');
4463
4464// PARSING
4465
4466addRegexToken('Z',  matchShortOffset);
4467addRegexToken('ZZ', matchShortOffset);
4468addParseToken(['Z', 'ZZ'], function (input, array, config) {
4469    config._useUTC = true;
4470    config._tzm = offsetFromString(matchShortOffset, input);
4471});
4472
4473// HELPERS
4474
4475// timezone chunker
4476// '+10:00' > ['10',  '00']
4477// '-1530'  > ['-15', '30']
4478var chunkOffset = /([\+\-]|\d\d)/gi;
4479
4480function offsetFromString(matcher, string) {
4481    var matches = (string || '').match(matcher);
4482
4483    if (matches === null) {
4484        return null;
4485    }
4486
4487    var chunk   = matches[matches.length - 1] || [];
4488    var parts   = (chunk + '').match(chunkOffset) || ['-', 0, 0];
4489    var minutes = +(parts[1] * 60) + toInt(parts[2]);
4490
4491    return minutes === 0 ?
4492      0 :
4493      parts[0] === '+' ? minutes : -minutes;
4494}
4495
4496// Return a moment from input, that is local/utc/zone equivalent to model.
4497function cloneWithOffset(input, model) {
4498    var res, diff;
4499    if (model._isUTC) {
4500        res = model.clone();
4501        diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
4502        // Use low-level api, because this fn is low-level api.
4503        res._d.setTime(res._d.valueOf() + diff);
4504        hooks.updateOffset(res, false);
4505        return res;
4506    } else {
4507        return createLocal(input).local();
4508    }
4509}
4510
4511function getDateOffset (m) {
4512    // On Firefox.24 Date#getTimezoneOffset returns a floating point.
4513    // https://github.com/moment/moment/pull/1871
4514    return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
4515}
4516
4517// HOOKS
4518
4519// This function will be called whenever a moment is mutated.
4520// It is intended to keep the offset in sync with the timezone.
4521hooks.updateOffset = function () {};
4522
4523// MOMENTS
4524
4525// keepLocalTime = true means only change the timezone, without
4526// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
4527// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
4528// +0200, so we adjust the time as needed, to be valid.
4529//
4530// Keeping the time actually adds/subtracts (one hour)
vendor: 19,497 bytes, lines 4531-5182
4531// from the actual represented time. That is why we call updateOffset
4532// a second time. In case it wants us to change the offset again
4533// _changeInProgress == true case, then we have to adjust, because
4534// there is no such time in the given timezone.
4535function getSetOffset (input, keepLocalTime, keepMinutes) {
4536    var offset = this._offset || 0,
4537        localAdjust;
4538    if (!this.isValid()) {
4539        return input != null ? this : NaN;
4540    }
4541    if (input != null) {
4542        if (typeof input === 'string') {
4543            input = offsetFromString(matchShortOffset, input);
4544            if (input === null) {
4545                return this;
4546            }
4547        } else if (Math.abs(input) < 16 && !keepMinutes) {
4548            input = input * 60;
4549        }
4550        if (!this._isUTC && keepLocalTime) {
4551            localAdjust = getDateOffset(this);
4552        }
4553        this._offset = input;
4554        this._isUTC = true;
4555        if (localAdjust != null) {
4556            this.add(localAdjust, 'm');
4557        }
4558        if (offset !== input) {
4559            if (!keepLocalTime || this._changeInProgress) {
4560                addSubtract(this, createDuration(input - offset, 'm'), 1, false);
4561            } else if (!this._changeInProgress) {
4562                this._changeInProgress = true;
4563                hooks.updateOffset(this, true);
4564                this._changeInProgress = null;
4565            }
4566        }
4567        return this;
4568    } else {
4569        return this._isUTC ? offset : getDateOffset(this);
4570    }
4571}
4572
4573function getSetZone (input, keepLocalTime) {
4574    if (input != null) {
4575        if (typeof input !== 'string') {
4576            input = -input;
4577        }
4578
4579        this.utcOffset(input, keepLocalTime);
4580
4581        return this;
4582    } else {
4583        return -this.utcOffset();
4584    }
4585}
4586
4587function setOffsetToUTC (keepLocalTime) {
4588    return this.utcOffset(0, keepLocalTime);
4589}
4590
4591function setOffsetToLocal (keepLocalTime) {
4592    if (this._isUTC) {
4593        this.utcOffset(0, keepLocalTime);
4594        this._isUTC = false;
4595
4596        if (keepLocalTime) {
4597            this.subtract(getDateOffset(this), 'm');
4598        }
4599    }
4600    return this;
4601}
4602
4603function setOffsetToParsedOffset () {
4604    if (this._tzm != null) {
4605        this.utcOffset(this._tzm, false, true);
4606    } else if (typeof this._i === 'string') {
4607        var tZone = offsetFromString(matchOffset, this._i);
4608        if (tZone != null) {
4609            this.utcOffset(tZone);
4610        }
4611        else {
4612            this.utcOffset(0, true);
4613        }
4614    }
4615    return this;
4616}
4617
4618function hasAlignedHourOffset (input) {
4619    if (!this.isValid()) {
4620        return false;
4621    }
4622    input = input ? createLocal(input).utcOffset() : 0;
4623
4624    return (this.utcOffset() - input) % 60 === 0;
4625}
4626
4627function isDaylightSavingTime () {
4628    return (
4629        this.utcOffset() > this.clone().month(0).utcOffset() ||
4630        this.utcOffset() > this.clone().month(5).utcOffset()
4631    );
4632}
4633
4634function isDaylightSavingTimeShifted () {
4635    if (!isUndefined(this._isDSTShifted)) {
4636        return this._isDSTShifted;
4637    }
4638
4639    var c = {};
4640
4641    copyConfig(c, this);
4642    c = prepareConfig(c);
4643
4644    if (c._a) {
4645        var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
4646        this._isDSTShifted = this.isValid() &&
4647            compareArrays(c._a, other.toArray()) > 0;
4648    } else {
4649        this._isDSTShifted = false;
4650    }
4651
4652    return this._isDSTShifted;
4653}
4654
4655function isLocal () {
4656    return this.isValid() ? !this._isUTC : false;
4657}
4658
4659function isUtcOffset () {
4660    return this.isValid() ? this._isUTC : false;
4661}
4662
4663function isUtc () {
4664    return this.isValid() ? this._isUTC && this._offset === 0 : false;
4665}
4666
4667// ASP.NET json date format regex
4668var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
4669
4670// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
4671// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
4672// and further modified to allow for strings containing both week and day
4673var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
4674
4675function createDuration (input, key) {
4676    var duration = input,
4677        // matching against regexp is expensive, do it on demand
4678        match = null,
4679        sign,
4680        ret,
4681        diffRes;
4682
4683    if (isDuration(input)) {
4684        duration = {
4685            ms : input._milliseconds,
4686            d  : input._days,
4687            M  : input._months
4688        };
4689    } else if (isNumber(input)) {
4690        duration = {};
4691        if (key) {
4692            duration[key] = input;
4693        } else {
4694            duration.milliseconds = input;
4695        }
4696    } else if (!!(match = aspNetRegex.exec(input))) {
4697        sign = (match[1] === '-') ? -1 : 1;
4698        duration = {
4699            y  : 0,
4700            d  : toInt(match[DATE])                         * sign,
4701            h  : toInt(match[HOUR])                         * sign,
4702            m  : toInt(match[MINUTE])                       * sign,
4703            s  : toInt(match[SECOND])                       * sign,
4704            ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
4705        };
4706    } else if (!!(match = isoRegex.exec(input))) {
4707        sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1;
4708        duration = {
4709            y : parseIso(match[2], sign),
4710            M : parseIso(match[3], sign),
4711            w : parseIso(match[4], sign),
4712            d : parseIso(match[5], sign),
4713            h : parseIso(match[6], sign),
4714            m : parseIso(match[7], sign),
4715            s : parseIso(match[8], sign)
4716        };
4717    } else if (duration == null) {// checks for null or undefined
4718        duration = {};
4719    } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
4720        diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
4721
4722        duration = {};
4723        duration.ms = diffRes.milliseconds;
4724        duration.M = diffRes.months;
4725    }
4726
4727    ret = new Duration(duration);
4728
4729    if (isDuration(input) && hasOwnProp(input, '_locale')) {
4730        ret._locale = input._locale;
4731    }
4732
4733    return ret;
4734}
4735
4736createDuration.fn = Duration.prototype;
4737createDuration.invalid = createInvalid$1;
4738
4739function parseIso (inp, sign) {
4740    // We'd normally use ~~inp for this, but unfortunately it also
4741    // converts floats to ints.
4742    // inp may be undefined, so careful calling replace on it.
4743    var res = inp && parseFloat(inp.replace(',', '.'));
4744    // apply sign while we're at it
4745    return (isNaN(res) ? 0 : res) * sign;
4746}
4747
4748function positiveMomentsDifference(base, other) {
4749    var res = {milliseconds: 0, months: 0};
4750
4751    res.months = other.month() - base.month() +
4752        (other.year() - base.year()) * 12;
4753    if (base.clone().add(res.months, 'M').isAfter(other)) {
4754        --res.months;
4755    }
4756
4757    res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
4758
4759    return res;
4760}
4761
4762function momentsDifference(base, other) {
4763    var res;
4764    if (!(base.isValid() && other.isValid())) {
4765        return {milliseconds: 0, months: 0};
4766    }
4767
4768    other = cloneWithOffset(other, base);
4769    if (base.isBefore(other)) {
4770        res = positiveMomentsDifference(base, other);
4771    } else {
4772        res = positiveMomentsDifference(other, base);
4773        res.milliseconds = -res.milliseconds;
4774        res.months = -res.months;
4775    }
4776
4777    return res;
4778}
4779
4780// TODO: remove 'name' arg after deprecation is removed
4781function createAdder(direction, name) {
4782    return function (val, period) {
4783        var dur, tmp;
4784        //invert the arguments, but complain about it
4785        if (period !== null && !isNaN(+period)) {
4786            deprecateSimple(name, 'moment().' + name  + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
4787            'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
4788            tmp = val; val = period; period = tmp;
4789        }
4790
4791        val = typeof val === 'string' ? +val : val;
4792        dur = createDuration(val, period);
4793        addSubtract(this, dur, direction);
4794        return this;
4795    };
4796}
4797
4798function addSubtract (mom, duration, isAdding, updateOffset) {
4799    var milliseconds = duration._milliseconds,
4800        days = absRound(duration._days),
4801        months = absRound(duration._months);
4802
4803    if (!mom.isValid()) {
4804        // No op
4805        return;
4806    }
4807
4808    updateOffset = updateOffset == null ? true : updateOffset;
4809
4810    if (months) {
4811        setMonth(mom, get(mom, 'Month') + months * isAdding);
4812    }
4813    if (days) {
4814        set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
4815    }
4816    if (milliseconds) {
4817        mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
4818    }
4819    if (updateOffset) {
4820        hooks.updateOffset(mom, days || months);
4821    }
4822}
4823
4824var add      = createAdder(1, 'add');
4825var subtract = createAdder(-1, 'subtract');
4826
4827function getCalendarFormat(myMoment, now) {
4828    var diff = myMoment.diff(now, 'days', true);
4829    return diff < -6 ? 'sameElse' :
4830            diff < -1 ? 'lastWeek' :
4831            diff < 0 ? 'lastDay' :
4832            diff < 1 ? 'sameDay' :
4833            diff < 2 ? 'nextDay' :
4834            diff < 7 ? 'nextWeek' : 'sameElse';
4835}
4836
4837function calendar$1 (time, formats) {
4838    // We want to compare the start of today, vs this.
4839    // Getting start-of-today depends on whether we're local/utc/offset or not.
4840    var now = time || createLocal(),
4841        sod = cloneWithOffset(now, this).startOf('day'),
4842        format = hooks.calendarFormat(this, sod) || 'sameElse';
4843
4844    var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
4845
4846    return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
4847}
4848
4849function clone () {
4850    return new Moment(this);
4851}
4852
4853function isAfter (input, units) {
4854    var localInput = isMoment(input) ? input : createLocal(input);
4855    if (!(this.isValid() && localInput.isValid())) {
4856        return false;
4857    }
4858    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
4859    if (units === 'millisecond') {
4860        return this.valueOf() > localInput.valueOf();
4861    } else {
4862        return localInput.valueOf() < this.clone().startOf(units).valueOf();
4863    }
4864}
4865
4866function isBefore (input, units) {
4867    var localInput = isMoment(input) ? input : createLocal(input);
4868    if (!(this.isValid() && localInput.isValid())) {
4869        return false;
4870    }
4871    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
4872    if (units === 'millisecond') {
4873        return this.valueOf() < localInput.valueOf();
4874    } else {
4875        return this.clone().endOf(units).valueOf() < localInput.valueOf();
4876    }
4877}
4878
4879function isBetween (from, to, units, inclusivity) {
4880    inclusivity = inclusivity || '()';
4881    return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
4882        (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
4883}
4884
4885function isSame (input, units) {
4886    var localInput = isMoment(input) ? input : createLocal(input),
4887        inputMs;
4888    if (!(this.isValid() && localInput.isValid())) {
4889        return false;
4890    }
4891    units = normalizeUnits(units || 'millisecond');
4892    if (units === 'millisecond') {
4893        return this.valueOf() === localInput.valueOf();
4894    } else {
4895        inputMs = localInput.valueOf();
4896        return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
4897    }
4898}
4899
4900function isSameOrAfter (input, units) {
4901    return this.isSame(input, units) || this.isAfter(input,units);
4902}
4903
4904function isSameOrBefore (input, units) {
4905    return this.isSame(input, units) || this.isBefore(input,units);
4906}
4907
4908function diff (input, units, asFloat) {
4909    var that,
4910        zoneDelta,
4911        delta, output;
4912
4913    if (!this.isValid()) {
4914        return NaN;
4915    }
4916
4917    that = cloneWithOffset(input, this);
4918
4919    if (!that.isValid()) {
4920        return NaN;
4921    }
4922
4923    zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
4924
4925    units = normalizeUnits(units);
4926
4927    switch (units) {
4928        case 'year': output = monthDiff(this, that) / 12; break;
4929        case 'month': output = monthDiff(this, that); break;
4930        case 'quarter': output = monthDiff(this, that) / 3; break;
4931        case 'second': output = (this - that) / 1e3; break; // 1000
4932        case 'minute': output = (this - that) / 6e4; break; // 1000 * 60
4933        case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 60
4934        case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst
4935        case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst
4936        default: output = this - that;
4937    }
4938
4939    return asFloat ? output : absFloor(output);
4940}
4941
4942function monthDiff (a, b) {
4943    // difference in months
4944    var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
4945        // b is in (anchor - 1 month, anchor + 1 month)
4946        anchor = a.clone().add(wholeMonthDiff, 'months'),
4947        anchor2, adjust;
4948
4949    if (b - anchor < 0) {
4950        anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
4951        // linear across the month
4952        adjust = (b - anchor) / (anchor - anchor2);
4953    } else {
4954        anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
4955        // linear across the month
4956        adjust = (b - anchor) / (anchor2 - anchor);
4957    }
4958
4959    //check for negative zero, return zero if negative zero
4960    return -(wholeMonthDiff + adjust) || 0;
4961}
4962
4963hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
4964hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
4965
4966function toString () {
4967    return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
4968}
4969
4970function toISOString(keepOffset) {
4971    if (!this.isValid()) {
4972        return null;
4973    }
4974    var utc = keepOffset !== true;
4975    var m = utc ? this.clone().utc() : this;
4976    if (m.year() < 0 || m.year() > 9999) {
4977        return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
4978    }
4979    if (isFunction(Date.prototype.toISOString)) {
4980        // native implementation is ~50x faster, use it when we can
4981        if (utc) {
4982            return this.toDate().toISOString();
4983        } else {
4984            return new Date(this._d.valueOf()).toISOString().replace('Z', formatMoment(m, 'Z'));
4985        }
4986    }
4987    return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
4988}
4989
4990/**
4991 * Return a human readable representation of a moment that can
4992 * also be evaluated to get a new moment which is the same
4993 *
4994 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
4995 */
4996function inspect () {
4997    if (!this.isValid()) {
4998        return 'moment.invalid(/* ' + this._i + ' */)';
4999    }
5000    var func = 'moment';
5001    var zone = '';
5002    if (!this.isLocal()) {
5003        func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
5004        zone = 'Z';
5005    }
5006    var prefix = '[' + func + '("]';
5007    var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
5008    var datetime = '-MM-DD[T]HH:mm:ss.SSS';
5009    var suffix = zone + '[")]';
5010
5011    return this.format(prefix + year + datetime + suffix);
5012}
5013
5014function format (inputString) {
5015    if (!inputString) {
5016        inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
5017    }
5018    var output = formatMoment(this, inputString);
5019    return this.localeData().postformat(output);
5020}
5021
5022function from (time, withoutSuffix) {
5023    if (this.isValid() &&
5024            ((isMoment(time) && time.isValid()) ||
5025             createLocal(time).isValid())) {
5026        return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
5027    } else {
5028        return this.localeData().invalidDate();
5029    }
5030}
5031
5032function fromNow (withoutSuffix) {
5033    return this.from(createLocal(), withoutSuffix);
5034}
5035
5036function to (time, withoutSuffix) {
5037    if (this.isValid() &&
5038            ((isMoment(time) && time.isValid()) ||
5039             createLocal(time).isValid())) {
5040        return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
5041    } else {
5042        return this.localeData().invalidDate();
5043    }
5044}
5045
5046function toNow (withoutSuffix) {
5047    return this.to(createLocal(), withoutSuffix);
5048}
5049
5050// If passed a locale key, it will set the locale for this
5051// instance.  Otherwise, it will return the locale configuration
5052// variables for this instance.
5053function locale (key) {
5054    var newLocaleData;
5055
5056    if (key === undefined) {
5057        return this._locale._abbr;
5058    } else {
5059        newLocaleData = getLocale(key);
5060        if (newLocaleData != null) {
5061            this._locale = newLocaleData;
5062        }
5063        return this;
5064    }
5065}
5066
5067var lang = deprecate(
5068    'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
5069    function (key) {
5070        if (key === undefined) {
5071            return this.localeData();
5072        } else {
5073            return this.locale(key);
5074        }
5075    }
5076);
5077
5078function localeData () {
5079    return this._locale;
5080}
5081
5082function startOf (units) {
5083    units = normalizeUnits(units);
5084    // the following switch intentionally omits break keywords
5085    // to utilize falling through the cases.
5086    switch (units) {
5087        case 'year':
5088            this.month(0);
5089            /* falls through */
5090        case 'quarter':
5091        case 'month':
5092            this.date(1);
5093            /* falls through */
5094        case 'week':
5095        case 'isoWeek':
5096        case 'day':
5097        case 'date':
5098            this.hours(0);
5099            /* falls through */
5100        case 'hour':
5101            this.minutes(0);
5102            /* falls through */
5103        case 'minute':
5104            this.seconds(0);
5105            /* falls through */
5106        case 'second':
5107            this.milliseconds(0);
5108    }
5109
5110    // weeks are a special case
5111    if (units === 'week') {
5112        this.weekday(0);
5113    }
5114    if (units === 'isoWeek') {
5115        this.isoWeekday(1);
5116    }
5117
5118    // quarters are also special
5119    if (units === 'quarter') {
5120        this.month(Math.floor(this.month() / 3) * 3);
5121    }
5122
5123    return this;
5124}
5125
5126function endOf (units) {
5127    units = normalizeUnits(units);
5128    if (units === undefined || units === 'millisecond') {
5129        return this;
5130    }
5131
5132    // 'date' is an alias for 'day', so it should be considered as such.
5133    if (units === 'date') {
5134        units = 'day';
5135    }
5136
5137    return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
5138}
5139
5140function valueOf () {
5141    return this._d.valueOf() - ((this._offset || 0) * 60000);
5142}
5143
5144function unix () {
5145    return Math.floor(this.valueOf() / 1000);
5146}
5147
5148function toDate () {
5149    return new Date(this.valueOf());
5150}
5151
5152function toArray () {
5153    var m = this;
5154    return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
5155}
5156
5157function toObject () {
5158    var m = this;
5159    return {
5160        years: m.year(),
5161        months: m.month(),
5162        date: m.date(),
5163        hours: m.hours(),
5164        minutes: m.minutes(),
5165        seconds: m.seconds(),
5166        milliseconds: m.milliseconds()
5167    };
5168}
5169
5170function toJSON () {
5171    // new Date(NaN).toJSON() === null
5172    return this.isValid() ? this.toISOString() : null;
5173}
5174
5175function isValid$2 () {
5176    return isValid(this);
5177}
5178
5179function parsingFlags () {
5180    return extend({}, getParsingFlags(this));
5181}
5182
vendor: 11,961 bytes, lines 5183-5654
5183function invalidAt () {
5184    return getParsingFlags(this).overflow;
5185}
5186
5187function creationData() {
5188    return {
5189        input: this._i,
5190        format: this._f,
5191        locale: this._locale,
5192        isUTC: this._isUTC,
5193        strict: this._strict
5194    };
5195}
5196
5197// FORMATTING
5198
5199addFormatToken(0, ['gg', 2], 0, function () {
5200    return this.weekYear() % 100;
5201});
5202
5203addFormatToken(0, ['GG', 2], 0, function () {
5204    return this.isoWeekYear() % 100;
5205});
5206
5207function addWeekYearFormatToken (token, getter) {
5208    addFormatToken(0, [token, token.length], 0, getter);
5209}
5210
5211addWeekYearFormatToken('gggg',     'weekYear');
5212addWeekYearFormatToken('ggggg',    'weekYear');
5213addWeekYearFormatToken('GGGG',  'isoWeekYear');
5214addWeekYearFormatToken('GGGGG', 'isoWeekYear');
5215
5216// ALIASES
5217
5218addUnitAlias('weekYear', 'gg');
5219addUnitAlias('isoWeekYear', 'GG');
5220
5221// PRIORITY
5222
5223addUnitPriority('weekYear', 1);
5224addUnitPriority('isoWeekYear', 1);
5225
5226
5227// PARSING
5228
5229addRegexToken('G',      matchSigned);
5230addRegexToken('g',      matchSigned);
5231addRegexToken('GG',     match1to2, match2);
5232addRegexToken('gg',     match1to2, match2);
5233addRegexToken('GGGG',   match1to4, match4);
5234addRegexToken('gggg',   match1to4, match4);
5235addRegexToken('GGGGG',  match1to6, match6);
5236addRegexToken('ggggg',  match1to6, match6);
5237
5238addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
5239    week[token.substr(0, 2)] = toInt(input);
5240});
5241
5242addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
5243    week[token] = hooks.parseTwoDigitYear(input);
5244});
5245
5246// MOMENTS
5247
5248function getSetWeekYear (input) {
5249    return getSetWeekYearHelper.call(this,
5250            input,
5251            this.week(),
5252            this.weekday(),
5253            this.localeData()._week.dow,
5254            this.localeData()._week.doy);
5255}
5256
5257function getSetISOWeekYear (input) {
5258    return getSetWeekYearHelper.call(this,
5259            input, this.isoWeek(), this.isoWeekday(), 1, 4);
5260}
5261
5262function getISOWeeksInYear () {
5263    return weeksInYear(this.year(), 1, 4);
5264}
5265
5266function getWeeksInYear () {
5267    var weekInfo = this.localeData()._week;
5268    return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
5269}
5270
5271function getSetWeekYearHelper(input, week, weekday, dow, doy) {
5272    var weeksTarget;
5273    if (input == null) {
5274        return weekOfYear(this, dow, doy).year;
5275    } else {
5276        weeksTarget = weeksInYear(input, dow, doy);
5277        if (week > weeksTarget) {
5278            week = weeksTarget;
5279        }
5280        return setWeekAll.call(this, input, week, weekday, dow, doy);
5281    }
5282}
5283
5284function setWeekAll(weekYear, week, weekday, dow, doy) {
5285    var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
5286        date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
5287
5288    this.year(date.getUTCFullYear());
5289    this.month(date.getUTCMonth());
5290    this.date(date.getUTCDate());
5291    return this;
5292}
5293
5294// FORMATTING
5295
5296addFormatToken('Q', 0, 'Qo', 'quarter');
5297
5298// ALIASES
5299
5300addUnitAlias('quarter', 'Q');
5301
5302// PRIORITY
5303
5304addUnitPriority('quarter', 7);
5305
5306// PARSING
5307
5308addRegexToken('Q', match1);
5309addParseToken('Q', function (input, array) {
5310    array[MONTH] = (toInt(input) - 1) * 3;
5311});
5312
5313// MOMENTS
5314
5315function getSetQuarter (input) {
5316    return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
5317}
5318
5319// FORMATTING
5320
5321addFormatToken('D', ['DD', 2], 'Do', 'date');
5322
5323// ALIASES
5324
5325addUnitAlias('date', 'D');
5326
5327// PRIOROITY
5328addUnitPriority('date', 9);
5329
5330// PARSING
5331
5332addRegexToken('D',  match1to2);
5333addRegexToken('DD', match1to2, match2);
5334addRegexToken('Do', function (isStrict, locale) {
5335    // TODO: Remove "ordinalParse" fallback in next major release.
5336    return isStrict ?
5337      (locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
5338      locale._dayOfMonthOrdinalParseLenient;
5339});
5340
5341addParseToken(['D', 'DD'], DATE);
5342addParseToken('Do', function (input, array) {
5343    array[DATE] = toInt(input.match(match1to2)[0]);
5344});
5345
5346// MOMENTS
5347
5348var getSetDayOfMonth = makeGetSet('Date', true);
5349
5350// FORMATTING
5351
5352addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
5353
5354// ALIASES
5355
5356addUnitAlias('dayOfYear', 'DDD');
5357
5358// PRIORITY
5359addUnitPriority('dayOfYear', 4);
5360
5361// PARSING
5362
5363addRegexToken('DDD',  match1to3);
5364addRegexToken('DDDD', match3);
5365addParseToken(['DDD', 'DDDD'], function (input, array, config) {
5366    config._dayOfYear = toInt(input);
5367});
5368
5369// HELPERS
5370
5371// MOMENTS
5372
5373function getSetDayOfYear (input) {
5374    var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
5375    return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
5376}
5377
5378// FORMATTING
5379
5380addFormatToken('m', ['mm', 2], 0, 'minute');
5381
5382// ALIASES
5383
5384addUnitAlias('minute', 'm');
5385
5386// PRIORITY
5387
5388addUnitPriority('minute', 14);
5389
5390// PARSING
5391
5392addRegexToken('m',  match1to2);
5393addRegexToken('mm', match1to2, match2);
5394addParseToken(['m', 'mm'], MINUTE);
5395
5396// MOMENTS
5397
5398var getSetMinute = makeGetSet('Minutes', false);
5399
5400// FORMATTING
5401
5402addFormatToken('s', ['ss', 2], 0, 'second');
5403
5404// ALIASES
5405
5406addUnitAlias('second', 's');
5407
5408// PRIORITY
5409
5410addUnitPriority('second', 15);
5411
5412// PARSING
5413
5414addRegexToken('s',  match1to2);
5415addRegexToken('ss', match1to2, match2);
5416addParseToken(['s', 'ss'], SECOND);
5417
5418// MOMENTS
5419
5420var getSetSecond = makeGetSet('Seconds', false);
5421
5422// FORMATTING
5423
5424addFormatToken('S', 0, 0, function () {
5425    return ~~(this.millisecond() / 100);
5426});
5427
5428addFormatToken(0, ['SS', 2], 0, function () {
5429    return ~~(this.millisecond() / 10);
5430});
5431
5432addFormatToken(0, ['SSS', 3], 0, 'millisecond');
5433addFormatToken(0, ['SSSS', 4], 0, function () {
5434    return this.millisecond() * 10;
5435});
5436addFormatToken(0, ['SSSSS', 5], 0, function () {
5437    return this.millisecond() * 100;
5438});
5439addFormatToken(0, ['SSSSSS', 6], 0, function () {
5440    return this.millisecond() * 1000;
5441});
5442addFormatToken(0, ['SSSSSSS', 7], 0, function () {
5443    return this.millisecond() * 10000;
5444});
5445addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
5446    return this.millisecond() * 100000;
5447});
5448addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
5449    return this.millisecond() * 1000000;
5450});
5451
5452
5453// ALIASES
5454
5455addUnitAlias('millisecond', 'ms');
5456
5457// PRIORITY
5458
5459addUnitPriority('millisecond', 16);
5460
5461// PARSING
5462
5463addRegexToken('S',    match1to3, match1);
5464addRegexToken('SS',   match1to3, match2);
5465addRegexToken('SSS',  match1to3, match3);
5466
5467var token;
5468for (token = 'SSSS'; token.length <= 9; token += 'S') {
5469    addRegexToken(token, matchUnsigned);
5470}
5471
5472function parseMs(input, array) {
5473    array[MILLISECOND] = toInt(('0.' + input) * 1000);
5474}
5475
5476for (token = 'S'; token.length <= 9; token += 'S') {
5477    addParseToken(token, parseMs);
5478}
5479// MOMENTS
5480
5481var getSetMillisecond = makeGetSet('Milliseconds', false);
5482
5483// FORMATTING
5484
5485addFormatToken('z',  0, 0, 'zoneAbbr');
5486addFormatToken('zz', 0, 0, 'zoneName');
5487
5488// MOMENTS
5489
5490function getZoneAbbr () {
5491    return this._isUTC ? 'UTC' : '';
5492}
5493
5494function getZoneName () {
5495    return this._isUTC ? 'Coordinated Universal Time' : '';
5496}
5497
5498var proto = Moment.prototype;
5499
5500proto.add               = add;
5501proto.calendar          = calendar$1;
5502proto.clone             = clone;
5503proto.diff              = diff;
5504proto.endOf             = endOf;
5505proto.format            = format;
5506proto.from              = from;
5507proto.fromNow           = fromNow;
5508proto.to                = to;
5509proto.toNow             = toNow;
5510proto.get               = stringGet;
5511proto.invalidAt         = invalidAt;
5512proto.isAfter           = isAfter;
5513proto.isBefore          = isBefore;
5514proto.isBetween         = isBetween;
5515proto.isSame            = isSame;
5516proto.isSameOrAfter     = isSameOrAfter;
5517proto.isSameOrBefore    = isSameOrBefore;
5518proto.isValid           = isValid$2;
5519proto.lang              = lang;
5520proto.locale            = locale;
5521proto.localeData        = localeData;
5522proto.max               = prototypeMax;
5523proto.min               = prototypeMin;
5524proto.parsingFlags      = parsingFlags;
5525proto.set               = stringSet;
5526proto.startOf           = startOf;
5527proto.subtract          = subtract;
5528proto.toArray           = toArray;
5529proto.toObject          = toObject;
5530proto.toDate            = toDate;
5531proto.toISOString       = toISOString;
5532proto.inspect           = inspect;
5533proto.toJSON            = toJSON;
5534proto.toString          = toString;
5535proto.unix              = unix;
5536proto.valueOf           = valueOf;
5537proto.creationData      = creationData;
5538
5539// Year
5540proto.year       = getSetYear;
5541proto.isLeapYear = getIsLeapYear;
5542
5543// Week Year
5544proto.weekYear    = getSetWeekYear;
5545proto.isoWeekYear = getSetISOWeekYear;
5546
5547// Quarter
5548proto.quarter = proto.quarters = getSetQuarter;
5549
5550// Month
5551proto.month       = getSetMonth;
5552proto.daysInMonth = getDaysInMonth;
5553
5554// Week
5555proto.week           = proto.weeks        = getSetWeek;
5556proto.isoWeek        = proto.isoWeeks     = getSetISOWeek;
5557proto.weeksInYear    = getWeeksInYear;
5558proto.isoWeeksInYear = getISOWeeksInYear;
5559
5560// Day
5561proto.date       = getSetDayOfMonth;
5562proto.day        = proto.days             = getSetDayOfWeek;
5563proto.weekday    = getSetLocaleDayOfWeek;
5564proto.isoWeekday = getSetISODayOfWeek;
5565proto.dayOfYear  = getSetDayOfYear;
5566
5567// Hour
5568proto.hour = proto.hours = getSetHour;
5569
5570// Minute
5571proto.minute = proto.minutes = getSetMinute;
5572
5573// Second
5574proto.second = proto.seconds = getSetSecond;
5575
5576// Millisecond
5577proto.millisecond = proto.milliseconds = getSetMillisecond;
5578
5579// Offset
5580proto.utcOffset            = getSetOffset;
5581proto.utc                  = setOffsetToUTC;
5582proto.local                = setOffsetToLocal;
5583proto.parseZone            = setOffsetToParsedOffset;
5584proto.hasAlignedHourOffset = hasAlignedHourOffset;
5585proto.isDST                = isDaylightSavingTime;
5586proto.isLocal              = isLocal;
5587proto.isUtcOffset          = isUtcOffset;
5588proto.isUtc                = isUtc;
5589proto.isUTC                = isUtc;
5590
5591// Timezone
5592proto.zoneAbbr = getZoneAbbr;
5593proto.zoneName = getZoneName;
5594
5595// Deprecations
5596proto.dates  = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
5597proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
5598proto.years  = deprecate('years accessor is deprecated. Use year instead', getSetYear);
5599proto.zone   = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
5600proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
5601
5602function createUnix (input) {
5603    return createLocal(input * 1000);
5604}
5605
5606function createInZone () {
5607    return createLocal.apply(null, arguments).parseZone();
5608}
5609
5610function preParsePostFormat (string) {
5611    return string;
5612}
5613
5614var proto$1 = Locale.prototype;
5615
5616proto$1.calendar        = calendar;
5617proto$1.longDateFormat  = longDateFormat;
5618proto$1.invalidDate     = invalidDate;
5619proto$1.ordinal         = ordinal;
5620proto$1.preparse        = preParsePostFormat;
5621proto$1.postformat      = preParsePostFormat;
5622proto$1.relativeTime    = relativeTime;
5623proto$1.pastFuture      = pastFuture;
5624proto$1.set             = set;
5625
5626// Month
5627proto$1.months            =        localeMonths;
5628proto$1.monthsShort       =        localeMonthsShort;
5629proto$1.monthsParse       =        localeMonthsParse;
5630proto$1.monthsRegex       = monthsRegex;
5631proto$1.monthsShortRegex  = monthsShortRegex;
5632
5633// Week
5634proto$1.week = localeWeek;
5635proto$1.firstDayOfYear = localeFirstDayOfYear;
5636proto$1.firstDayOfWeek = localeFirstDayOfWeek;
5637
5638// Day of Week
5639proto$1.weekdays       =        localeWeekdays;
5640proto$1.weekdaysMin    =        localeWeekdaysMin;
5641proto$1.weekdaysShort  =        localeWeekdaysShort;
5642proto$1.weekdaysParse  =        localeWeekdaysParse;
5643
5644proto$1.weekdaysRegex       =        weekdaysRegex;
5645proto$1.weekdaysShortRegex  =        weekdaysShortRegex;
5646proto$1.weekdaysMinRegex    =        weekdaysMinRegex;
5647
5648// Hours
5649proto$1.isPM = localeIsPM;
5650proto$1.meridiem = localeMeridiem;
5651
5652function get$1 (format, index, field, setter) {
5653    var locale = getLocale();
5654    var utc = createUTC().set(setter, index);
vendor: 7,931 bytes, lines 5655-5947
5655    return locale[field](utc, format);
5656}
5657
5658function listMonthsImpl (format, index, field) {
5659    if (isNumber(format)) {
5660        index = format;
5661        format = undefined;
5662    }
5663
5664    format = format || '';
5665
5666    if (index != null) {
5667        return get$1(format, index, field, 'month');
5668    }
5669
5670    var i;
5671    var out = [];
5672    for (i = 0; i < 12; i++) {
5673        out[i] = get$1(format, i, field, 'month');
5674    }
5675    return out;
5676}
5677
5678// ()
5679// (5)
5680// (fmt, 5)
5681// (fmt)
5682// (true)
5683// (true, 5)
5684// (true, fmt, 5)
5685// (true, fmt)
5686function listWeekdaysImpl (localeSorted, format, index, field) {
5687    if (typeof localeSorted === 'boolean') {
5688        if (isNumber(format)) {
5689            index = format;
5690            format = undefined;
5691        }
5692
5693        format = format || '';
5694    } else {
5695        format = localeSorted;
5696        index = format;
5697        localeSorted = false;
5698
5699        if (isNumber(format)) {
5700            index = format;
5701            format = undefined;
5702        }
5703
5704        format = format || '';
5705    }
5706
5707    var locale = getLocale(),
5708        shift = localeSorted ? locale._week.dow : 0;
5709
5710    if (index != null) {
5711        return get$1(format, (index + shift) % 7, field, 'day');
5712    }
5713
5714    var i;
5715    var out = [];
5716    for (i = 0; i < 7; i++) {
5717        out[i] = get$1(format, (i + shift) % 7, field, 'day');
5718    }
5719    return out;
5720}
5721
5722function listMonths (format, index) {
5723    return listMonthsImpl(format, index, 'months');
5724}
5725
5726function listMonthsShort (format, index) {
5727    return listMonthsImpl(format, index, 'monthsShort');
5728}
5729
5730function listWeekdays (localeSorted, format, index) {
5731    return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
5732}
5733
5734function listWeekdaysShort (localeSorted, format, index) {
5735    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
5736}
5737
5738function listWeekdaysMin (localeSorted, format, index) {
5739    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
5740}
5741
5742getSetGlobalLocale('en', {
5743    dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
5744    ordinal : function (number) {
5745        var b = number % 10,
5746            output = (toInt(number % 100 / 10) === 1) ? 'th' :
5747            (b === 1) ? 'st' :
5748            (b === 2) ? 'nd' :
5749            (b === 3) ? 'rd' : 'th';
5750        return number + output;
5751    }
5752});
5753
5754// Side effect imports
5755hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
5756hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
5757
5758var mathAbs = Math.abs;
5759
5760function abs () {
5761    var data           = this._data;
5762
5763    this._milliseconds = mathAbs(this._milliseconds);
5764    this._days         = mathAbs(this._days);
5765    this._months       = mathAbs(this._months);
5766
5767    data.milliseconds  = mathAbs(data.milliseconds);
5768    data.seconds       = mathAbs(data.seconds);
5769    data.minutes       = mathAbs(data.minutes);
5770    data.hours         = mathAbs(data.hours);
5771    data.months        = mathAbs(data.months);
5772    data.years         = mathAbs(data.years);
5773
5774    return this;
5775}
5776
5777function addSubtract$1 (duration, input, value, direction) {
5778    var other = createDuration(input, value);
5779
5780    duration._milliseconds += direction * other._milliseconds;
5781    duration._days         += direction * other._days;
5782    duration._months       += direction * other._months;
5783
5784    return duration._bubble();
5785}
5786
5787// supports only 2.0-style add(1, 's') or add(duration)
5788function add$1 (input, value) {
5789    return addSubtract$1(this, input, value, 1);
5790}
5791
5792// supports only 2.0-style subtract(1, 's') or subtract(duration)
5793function subtract$1 (input, value) {
5794    return addSubtract$1(this, input, value, -1);
5795}
5796
5797function absCeil (number) {
5798    if (number < 0) {
5799        return Math.floor(number);
5800    } else {
5801        return Math.ceil(number);
5802    }
5803}
5804
5805function bubble () {
5806    var milliseconds = this._milliseconds;
5807    var days         = this._days;
5808    var months       = this._months;
5809    var data         = this._data;
5810    var seconds, minutes, hours, years, monthsFromDays;
5811
5812    // if we have a mix of positive and negative values, bubble down first
5813    // check: https://github.com/moment/moment/issues/2166
5814    if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
5815            (milliseconds <= 0 && days <= 0 && months <= 0))) {
5816        milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
5817        days = 0;
5818        months = 0;
5819    }
5820
5821    // The following code bubbles up values, see the tests for
5822    // examples of what that means.
5823    data.milliseconds = milliseconds % 1000;
5824
5825    seconds           = absFloor(milliseconds / 1000);
5826    data.seconds      = seconds % 60;
5827
5828    minutes           = absFloor(seconds / 60);
5829    data.minutes      = minutes % 60;
5830
5831    hours             = absFloor(minutes / 60);
5832    data.hours        = hours % 24;
5833
5834    days += absFloor(hours / 24);
5835
5836    // convert days to months
5837    monthsFromDays = absFloor(daysToMonths(days));
5838    months += monthsFromDays;
5839    days -= absCeil(monthsToDays(monthsFromDays));
5840
5841    // 12 months -> 1 year
5842    years = absFloor(months / 12);
5843    months %= 12;
5844
5845    data.days   = days;
5846    data.months = months;
5847    data.years  = years;
5848
5849    return this;
5850}
5851
5852function daysToMonths (days) {
5853    // 400 years have 146097 days (taking into account leap year rules)
5854    // 400 years have 12 months === 4800
5855    return days * 4800 / 146097;
5856}
5857
5858function monthsToDays (months) {
5859    // the reverse of daysToMonths
5860    return months * 146097 / 4800;
5861}
5862
5863function as (units) {
5864    if (!this.isValid()) {
5865        return NaN;
5866    }
5867    var days;
5868    var months;
5869    var milliseconds = this._milliseconds;
5870
5871    units = normalizeUnits(units);
5872
5873    if (units === 'month' || units === 'year') {
5874        days   = this._days   + milliseconds / 864e5;
5875        months = this._months + daysToMonths(days);
5876        return units === 'month' ? months : months / 12;
5877    } else {
5878        // handle milliseconds separately because of floating point math errors (issue #1867)
5879        days = this._days + Math.round(monthsToDays(this._months));
5880        switch (units) {
5881            case 'week'   : return days / 7     + milliseconds / 6048e5;
5882            case 'day'    : return days         + milliseconds / 864e5;
5883            case 'hour'   : return days * 24    + milliseconds / 36e5;
5884            case 'minute' : return days * 1440  + milliseconds / 6e4;
5885            case 'second' : return days * 86400 + milliseconds / 1000;
5886            // Math.floor prevents floating point math errors here
5887            case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
5888            default: throw new Error('Unknown unit ' + units);
5889        }
5890    }
5891}
5892
5893// TODO: Use this.as('ms')?
5894function valueOf$1 () {
5895    if (!this.isValid()) {
5896        return NaN;
5897    }
5898    return (
5899        this._milliseconds +
5900        this._days * 864e5 +
5901        (this._months % 12) * 2592e6 +
5902        toInt(this._months / 12) * 31536e6
5903    );
5904}
5905
5906function makeAs (alias) {
5907    return function () {
5908        return this.as(alias);
5909    };
5910}
5911
5912var asMilliseconds = makeAs('ms');
5913var asSeconds      = makeAs('s');
5914var asMinutes      = makeAs('m');
5915var asHours        = makeAs('h');
5916var asDays         = makeAs('d');
5917var asWeeks        = makeAs('w');
5918var asMonths       = makeAs('M');
5919var asYears        = makeAs('y');
5920
5921function clone$1 () {
5922    return createDuration(this);
5923}
5924
5925function get$2 (units) {
5926    units = normalizeUnits(units);
5927    return this.isValid() ? this[units + 's']() : NaN;
5928}
5929
5930function makeGetter(name) {
5931    return function () {
5932        return this.isValid() ? this._data[name] : NaN;
5933    };
5934}
5935
5936var milliseconds = makeGetter('milliseconds');
5937var seconds      = makeGetter('seconds');
5938var minutes      = makeGetter('minutes');
5939var hours        = makeGetter('hours');
5940var days         = makeGetter('days');
5941var months       = makeGetter('months');
5942var years        = makeGetter('years');
5943
5944function weeks () {
5945    return absFloor(this.days() / 7);
5946}
5947
vendor: 6,285 bytes, lines 5948-6144
5948var round = Math.round;
5949var thresholds = {
5950    ss: 44,         // a few seconds to seconds
5951    s : 45,         // seconds to minute
5952    m : 45,         // minutes to hour
5953    h : 22,         // hours to day
5954    d : 26,         // days to month
5955    M : 11          // months to year
5956};
5957
5958// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
5959function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
5960    return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
5961}
5962
5963function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
5964    var duration = createDuration(posNegDuration).abs();
5965    var seconds  = round(duration.as('s'));
5966    var minutes  = round(duration.as('m'));
5967    var hours    = round(duration.as('h'));
5968    var days     = round(duration.as('d'));
5969    var months   = round(duration.as('M'));
5970    var years    = round(duration.as('y'));
5971
5972    var a = seconds <= thresholds.ss && ['s', seconds]  ||
5973            seconds < thresholds.s   && ['ss', seconds] ||
5974            minutes <= 1             && ['m']           ||
5975            minutes < thresholds.m   && ['mm', minutes] ||
5976            hours   <= 1             && ['h']           ||
5977            hours   < thresholds.h   && ['hh', hours]   ||
5978            days    <= 1             && ['d']           ||
5979            days    < thresholds.d   && ['dd', days]    ||
5980            months  <= 1             && ['M']           ||
5981            months  < thresholds.M   && ['MM', months]  ||
5982            years   <= 1             && ['y']           || ['yy', years];
5983
5984    a[2] = withoutSuffix;
5985    a[3] = +posNegDuration > 0;
5986    a[4] = locale;
5987    return substituteTimeAgo.apply(null, a);
5988}
5989
5990// This function allows you to set the rounding function for relative time strings
5991function getSetRelativeTimeRounding (roundingFunction) {
5992    if (roundingFunction === undefined) {
5993        return round;
5994    }
5995    if (typeof(roundingFunction) === 'function') {
5996        round = roundingFunction;
5997        return true;
5998    }
5999    return false;
6000}
6001
6002// This function allows you to set a threshold for relative time strings
6003function getSetRelativeTimeThreshold (threshold, limit) {
6004    if (thresholds[threshold] === undefined) {
6005        return false;
6006    }
6007    if (limit === undefined) {
6008        return thresholds[threshold];
6009    }
6010    thresholds[threshold] = limit;
6011    if (threshold === 's') {
6012        thresholds.ss = limit - 1;
6013    }
6014    return true;
6015}
6016
6017function humanize (withSuffix) {
6018    if (!this.isValid()) {
6019        return this.localeData().invalidDate();
6020    }
6021
6022    var locale = this.localeData();
6023    var output = relativeTime$1(this, !withSuffix, locale);
6024
6025    if (withSuffix) {
6026        output = locale.pastFuture(+this, output);
6027    }
6028
6029    return locale.postformat(output);
6030}
6031
6032var abs$1 = Math.abs;
6033
6034function sign(x) {
6035    return ((x > 0) - (x < 0)) || +x;
6036}
6037
6038function toISOString$1() {
6039    // for ISO strings we do not use the normal bubbling rules:
6040    //  * milliseconds bubble up until they become hours
6041    //  * days do not bubble at all
6042    //  * months bubble up until they become years
6043    // This is because there is no context-free conversion between hours and days
6044    // (think of clock changes)
6045    // and also not between days and months (28-31 days per month)
6046    if (!this.isValid()) {
6047        return this.localeData().invalidDate();
6048    }
6049
6050    var seconds = abs$1(this._milliseconds) / 1000;
6051    var days         = abs$1(this._days);
6052    var months       = abs$1(this._months);
6053    var minutes, hours, years;
6054
6055    // 3600 seconds -> 60 minutes -> 1 hour
6056    minutes           = absFloor(seconds / 60);
6057    hours             = absFloor(minutes / 60);
6058    seconds %= 60;
6059    minutes %= 60;
6060
6061    // 12 months -> 1 year
6062    years  = absFloor(months / 12);
6063    months %= 12;
6064
6065
6066    // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
6067    var Y = years;
6068    var M = months;
6069    var D = days;
6070    var h = hours;
6071    var m = minutes;
6072    var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
6073    var total = this.asSeconds();
6074
6075    if (!total) {
6076        // this is the same as C#'s (Noda) and python (isodate)...
6077        // but not other JS (goog.date)
6078        return 'P0D';
6079    }
6080
6081    var totalSign = total < 0 ? '-' : '';
6082    var ymSign = sign(this._months) !== sign(total) ? '-' : '';
6083    var daysSign = sign(this._days) !== sign(total) ? '-' : '';
6084    var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
6085
6086    return totalSign + 'P' +
6087        (Y ? ymSign + Y + 'Y' : '') +
6088        (M ? ymSign + M + 'M' : '') +
6089        (D ? daysSign + D + 'D' : '') +
6090        ((h || m || s) ? 'T' : '') +
6091        (h ? hmsSign + h + 'H' : '') +
6092        (m ? hmsSign + m + 'M' : '') +
6093        (s ? hmsSign + s + 'S' : '');
6094}
6095
6096var proto$2 = Duration.prototype;
6097
6098proto$2.isValid        = isValid$1;
6099proto$2.abs            = abs;
6100proto$2.add            = add$1;
6101proto$2.subtract       = subtract$1;
6102proto$2.as             = as;
6103proto$2.asMilliseconds = asMilliseconds;
6104proto$2.asSeconds      = asSeconds;
6105proto$2.asMinutes      = asMinutes;
6106proto$2.asHours        = asHours;
6107proto$2.asDays         = asDays;
6108proto$2.asWeeks        = asWeeks;
6109proto$2.asMonths       = asMonths;
6110proto$2.asYears        = asYears;
6111proto$2.valueOf        = valueOf$1;
6112proto$2._bubble        = bubble;
6113proto$2.clone          = clone$1;
6114proto$2.get            = get$2;
6115proto$2.milliseconds   = milliseconds;
6116proto$2.seconds        = seconds;
6117proto$2.minutes        = minutes;
6118proto$2.hours          = hours;
6119proto$2.days           = days;
6120proto$2.weeks          = weeks;
6121proto$2.months         = months;
6122proto$2.years          = years;
6123proto$2.humanize       = humanize;
6124proto$2.toISOString    = toISOString$1;
6125proto$2.toString       = toISOString$1;
6126proto$2.toJSON         = toISOString$1;
6127proto$2.locale         = locale;
6128proto$2.localeData     = localeData;
6129
6130// Deprecations
6131proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
6132proto$2.lang = lang;
6133
6134// Side effect imports
6135
6136// FORMATTING
6137
6138addFormatToken('X', 0, 0, 'unix');
6139addFormatToken('x', 0, 0, 'valueOf');
6140
6141// PARSING
6142
6143addRegexToken('x', matchSigned);
6144addRegexToken('X', matchTimestamp);
6145addParseToken('X', function (input, array, config) {
6146    config._d = new Date(parseFloat(input, 10) * 1000);
6147});
6148addParseToken('x', function (input, array, config) {
6149    config._d = new Date(toInt(input));
6150});
6151
6152// Side effect imports
6153
6154
6155hooks.version = '2.20.1';
6156
6157setHookCallback(createLocal);
6158
6159hooks.fn                    = proto;
6160hooks.min                   = min;
6161hooks.max                   = max;
6162hooks.now                   = now;
6163hooks.utc                   = createUTC;
6164hooks.unix                  = createUnix;
6165hooks.months                = listMonths;
6166hooks.isDate                = isDate;
6167hooks.locale                = getSetGlobalLocale;
6168hooks.invalid               = createInvalid;
6169hooks.duration              = createDuration;
6170hooks.isMoment              = isMoment;
6171hooks.weekdays              = listWeekdays;
6172hooks.parseZone             = createInZone;
6173hooks.localeData            = getLocale;
6174hooks.isDuration            = isDuration;
6175hooks.monthsShort           = listMonthsShort;
6176hooks.weekdaysMin           = listWeekdaysMin;
6177hooks.defineLocale          = defineLocale;
6178hooks.updateLocale          = updateLocale;
6179hooks.locales               = listLocales;
6180hooks.weekdaysShort         = listWeekdaysShort;
6181hooks.normalizeUnits        = normalizeUnits;
6182hooks.relativeTimeRounding  = getSetRelativeTimeRounding;
6183hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
6184hooks.calendarFormat        = getCalendarFormat;
6185hooks.prototype             = proto;
6186
6187// currently HTML5 input type only supports 24-hour formats
6188hooks.HTML5_FMT = {
6189    DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',             // <input type="datetime-local" />
6190    DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',  // <input type="datetime-local" step="1" />
6191    DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',   // <input type="datetime-local" step="0.001" />
6192    DATE: 'YYYY-MM-DD',                             // <input type="date" />
6193    TIME: 'HH:mm',                                  // <input type="time" />
6194    TIME_SECONDS: 'HH:mm:ss',                       // <input type="time" step="1" />
6195    TIME_MS: 'HH:mm:ss.SSS',                        // <input type="time" step="0.001" />
6196    WEEK: 'YYYY-[W]WW',                             // <input type="week" />
6197    MONTH: 'YYYY-MM'                                // <input type="month" />
6198};
6199
6200return hooks;
6201
6202})));
6203
6204},{}],7:[function(require,module,exports){
6205/**
6206 * @namespace Chart
6207 */
6208var Chart = require(29)();
6209
6210Chart.helpers = require(45);
6211
6212// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
6213require(27)(Chart);
6214
6215Chart.defaults = require(25);
6216Chart.Element = require(26);
6217Chart.elements = require(40);
6218Chart.Interaction = require(28);
6219Chart.layouts = require(30);
6220Chart.platform = require(48);
6221Chart.plugins = require(31);
6222Chart.Ticks = require(34);
6223
6224require(22)(Chart);
6225require(23)(Chart);
6226require(24)(Chart);
6227require(33)(Chart);
6228require(32)(Chart);
6229require(35)(Chart);
6230
6231require(55)(Chart);
6232require(53)(Chart);
6233require(54)(Chart);
6234require(56)(Chart);
6235require(57)(Chart);
6236require(58)(Chart);
6237
6238// Controllers must be loaded after elements
6239// See Chart.core.datasetController.dataElementType
6240require(15)(Chart);
6241require(16)(Chart);
6242require(17)(Chart);
6243require(18)(Chart);
6244require(19)(Chart);
6245require(20)(Chart);
6246require(21)(Chart);
6247
6248require(8)(Chart);
6249require(9)(Chart);
6250require(10)(Chart);
6251require(11)(Chart);
6252require(12)(Chart);
6253require(13)(Chart);
6254require(14)(Chart);
6255
6256// Loading built-it plugins
6257var plugins = require(49);
6258for (var k in plugins) {
6259	if (plugins.hasOwnProperty(k)) {
6260		Chart.plugins.register(plugins[k]);
6261	}
6262}
6263
6264Chart.platform.initialize();
6265
6266module.exports = Chart;
6267if (typeof window !== 'undefined') {
6268	window.Chart = Chart;
6269}
6270
6271// DEPRECATIONS
6272
6273/**
6274 * Provided for backward compatibility, not available anymore
6275 * @namespace Chart.Legend
6276 * @deprecated since version 2.1.5
6277 * @todo remove at version 3
6278 * @private
6279 */
6280Chart.Legend = plugins.legend._element;
6281
6282/**
6283 * Provided for backward compatibility, not available anymore
6284 * @namespace Chart.Title
6285 * @deprecated since version 2.1.5
6286 * @todo remove at version 3
6287 * @private
6288 */
6289Chart.Title = plugins.title._element;
6290
6291/**
6292 * Provided for backward compatibility, use Chart.plugins instead
6293 * @namespace Chart.pluginService
6294 * @deprecated since version 2.1.5
6295 * @todo remove at version 3
6296 * @private
6297 */
6298Chart.pluginService = Chart.plugins;
6299
6300/**
6301 * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
6302 * effect, instead simply create/register plugins via plain JavaScript objects.
6303 * @interface Chart.PluginBase
6304 * @deprecated since version 2.5.0
6305 * @todo remove at version 3
6306 * @private
6307 */
6308Chart.PluginBase = Chart.Element.extend({});
6309
6310/**
6311 * Provided for backward compatibility, use Chart.helpers.canvas instead.
6312 * @namespace Chart.canvasHelpers
6313 * @deprecated since version 2.6.0
6314 * @todo remove at version 3
6315 * @private
6316 */
6317Chart.canvasHelpers = Chart.helpers.canvas;
6318
6319/**
6320 * Provided for backward compatibility, use Chart.layouts instead.
6321 * @namespace Chart.layoutService
6322 * @deprecated since version 2.8.0
6323 * @todo remove at version 3
6324 * @private
6325 */
6326Chart.layoutService = Chart.layouts;
6327
6328},{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"34":34,"35":35,"40":40,"45":45,"48":48,"49":49,"53":53,"54":54,"55":55,"56":56,"57":57,"58":58,"8":8,"9":9}],8:[function(require,module,exports){
6329'use strict';
6330
6331module.exports = function(Chart) {
6332
6333	Chart.Bar = function(context, config) {
6334		config.type = 'bar';
6335
6336		return new Chart(context, config);
6337	};
6338
6339};
6340
6341},{}],9:[function(require,module,exports){
6342'use strict';
6343
6344module.exports = function(Chart) {
6345
6346	Chart.Bubble = function(context, config) {
6347		config.type = 'bubble';
6348		return new Chart(context, config);
6349	};
6350
6351};
6352
6353},{}],10:[function(require,module,exports){
6354'use strict';
6355
6356module.exports = function(Chart) {
6357
6358	Chart.Doughnut = function(context, config) {
6359		config.type = 'doughnut';
6360
6361		return new Chart(context, config);
6362	};
6363
6364};
6365
6366},{}],11:[function(require,module,exports){
6367'use strict';
6368
6369module.exports = function(Chart) {
6370
6371	Chart.Line = function(context, config) {
6372		config.type = 'line';
6373
6374		return new Chart(context, config);
6375	};
6376
6377};
6378
6379},{}],12:[function(require,module,exports){
6380'use strict';
6381
6382module.exports = function(Chart) {
6383
6384	Chart.PolarArea = function(context, config) {
6385		config.type = 'polarArea';
6386
6387		return new Chart(context, config);
6388	};
6389
6390};
6391
6392},{}],13:[function(require,module,exports){
6393'use strict';
6394
6395module.exports = function(Chart) {
6396
6397	Chart.Radar = function(context, config) {
6398		config.type = 'radar';
6399
6400		return new Chart(context, config);
6401	};
6402
6403};
6404
6405},{}],14:[function(require,module,exports){
6406'use strict';
6407
6408module.exports = function(Chart) {
6409	Chart.Scatter = function(context, config) {
6410		config.type = 'scatter';
6411		return new Chart(context, config);
6412	};
6413};
6414
6415},{}],15:[function(require,module,exports){
6416'use strict';
6417
6418var defaults = require(25);
6419var elements = require(40);
6420var helpers = require(45);
6421
6422defaults._set('bar', {
6423	hover: {
6424		mode: 'label'
6425	},
6426
6427	scales: {
6428		xAxes: [{
6429			type: 'category',
6430
6431			// Specific to Bar Controller
6432			categoryPercentage: 0.8,
6433			barPercentage: 0.9,
6434
6435			// offset settings
6436			offset: true,
6437
6438			// grid line settings
6439			gridLines: {
6440				offsetGridLines: true
6441			}
6442		}],
6443
6444		yAxes: [{
6445			type: 'linear'
6446		}]
6447	}
6448});
6449
6450defaults._set('horizontalBar', {
6451	hover: {
6452		mode: 'index',
6453		axis: 'y'
6454	},
6455
6456	scales: {
6457		xAxes: [{
6458			type: 'linear',
6459			position: 'bottom'
6460		}],
6461
6462		yAxes: [{
6463			position: 'left',
6464			type: 'category',
6465
6466			// Specific to Horizontal Bar Controller
6467			categoryPercentage: 0.8,
6468			barPercentage: 0.9,
6469
6470			// offset settings
6471			offset: true,
6472
6473			// grid line settings
6474			gridLines: {
6475				offsetGridLines: true
6476			}
6477		}]
6478	},
6479
6480	elements: {
6481		rectangle: {
6482			borderSkipped: 'left'
6483		}
6484	},
6485
6486	tooltips: {
6487		callbacks: {
6488			title: function(item, data) {
6489				// Pick first xLabel for now
6490				var title = '';
6491
6492				if (item.length > 0) {
6493					if (item[0].yLabel) {
6494						title = item[0].yLabel;
6495					} else if (data.labels.length > 0 && item[0].index < data.labels.length) {
6496						title = data.labels[item[0].index];
6497					}
6498				}
6499
6500				return title;
6501			},
6502
6503			label: function(item, data) {
6504				var datasetLabel = data.datasets[item.datasetIndex].label || '';
6505				return datasetLabel + ': ' + item.xLabel;
6506			}
6507		},
6508		mode: 'index',
6509		axis: 'y'
6510	}
6511});
6512
6513/**
6514 * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
6515 * @private
6516 */
6517function computeMinSampleSize(scale, pixels) {
6518	var min = scale.isHorizontal() ? scale.width : scale.height;
6519	var ticks = scale.getTicks();
6520	var prev, curr, i, ilen;
6521
6522	for (i = 1, ilen = pixels.length; i < ilen; ++i) {
6523		min = Math.min(min, pixels[i] - pixels[i - 1]);
6524	}
6525
6526	for (i = 0, ilen = ticks.length; i < ilen; ++i) {
6527		curr = scale.getPixelForTick(i);
6528		min = i > 0 ? Math.min(min, curr - prev) : min;
6529		prev = curr;
6530	}
6531
6532	return min;
6533}
6534
6535/**
6536 * Computes an "ideal" category based on the absolute bar thickness or, if undefined or null,
6537 * uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This
6538 * mode currently always generates bars equally sized (until we introduce scriptable options?).
6539 * @private
6540 */
6541function computeFitCategoryTraits(index, ruler, options) {
6542	var thickness = options.barThickness;
6543	var count = ruler.stackCount;
6544	var curr = ruler.pixels[index];
6545	var size, ratio;
6546
6547	if (helpers.isNullOrUndef(thickness)) {
6548		size = ruler.min * options.categoryPercentage;
6549		ratio = options.barPercentage;
6550	} else {
6551		// When bar thickness is enforced, category and bar percentages are ignored.
6552		// Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
6553		// and deprecate barPercentage since this value is ignored when thickness is absolute.
6554		size = thickness * count;
6555		ratio = 1;
6556	}
6557
6558	return {
6559		chunk: size / count,
6560		ratio: ratio,
6561		start: curr - (size / 2)
6562	};
6563}
6564
6565/**
6566 * Computes an "optimal" category that globally arranges bars side by side (no gap when
6567 * percentage options are 1), based on the previous and following categories. This mode
6568 * generates bars with different widths when data are not evenly spaced.
6569 * @private
6570 */
6571function computeFlexCategoryTraits(index, ruler, options) {
6572	var pixels = ruler.pixels;
6573	var curr = pixels[index];
6574	var prev = index > 0 ? pixels[index - 1] : null;
6575	var next = index < pixels.length - 1 ? pixels[index + 1] : null;
6576	var percent = options.categoryPercentage;
6577	var start, size;
6578
6579	if (prev === null) {
6580		// first data: its size is double based on the next point or,
6581		// if it's also the last data, we use the scale end extremity.
6582		prev = curr - (next === null ? ruler.end - curr : next - curr);
6583	}
6584
6585	if (next === null) {
6586		// last data: its size is also double based on the previous point.
6587		next = curr + curr - prev;
6588	}
6589
6590	start = curr - ((curr - prev) / 2) * percent;
6591	size = ((next - prev) / 2) * percent;
6592
6593	return {
6594		chunk: size / ruler.stackCount,
6595		ratio: options.barPercentage,
6596		start: start
6597	};
6598}
6599
6600module.exports = function(Chart) {
6601
6602	Chart.controllers.bar = Chart.DatasetController.extend({
6603
6604		dataElementType: elements.Rectangle,
6605
6606		initialize: function() {
6607			var me = this;
6608			var meta;
6609
6610			Chart.DatasetController.prototype.initialize.apply(me, arguments);
6611
6612			meta = me.getMeta();
6613			meta.stack = me.getDataset().stack;
6614			meta.bar = true;
6615		},
6616
6617		update: function(reset) {
6618			var me = this;
6619			var rects = me.getMeta().data;
6620			var i, ilen;
6621
6622			me._ruler = me.getRuler();
6623
6624			for (i = 0, ilen = rects.length; i < ilen; ++i) {
6625				me.updateElement(rects[i], i, reset);
6626			}
6627		},
6628
6629		updateElement: function(rectangle, index, reset) {
6630			var me = this;
6631			var chart = me.chart;
6632			var meta = me.getMeta();
6633			var dataset = me.getDataset();
6634			var custom = rectangle.custom || {};
6635			var rectangleOptions = chart.options.elements.rectangle;
6636
6637			rectangle._xScale = me.getScaleForId(meta.xAxisID);
6638			rectangle._yScale = me.getScaleForId(meta.yAxisID);
6639			rectangle._datasetIndex = me.index;
6640			rectangle._index = index;
6641
6642			rectangle._model = {
6643				datasetLabel: dataset.label,
6644				label: chart.data.labels[index],
6645				borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
6646				backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
6647				borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
6648				borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
6649			};
6650
6651			me.updateElementGeometry(rectangle, index, reset);
6652
6653			rectangle.pivot();
6654		},
6655
6656		/**
6657		 * @private
6658		 */
6659		updateElementGeometry: function(rectangle, index, reset) {
6660			var me = this;
6661			var model = rectangle._model;
6662			var vscale = me.getValueScale();
6663			var base = vscale.getBasePixel();
6664			var horizontal = vscale.isHorizontal();
6665			var ruler = me._ruler || me.getRuler();
6666			var vpixels = me.calculateBarValuePixels(me.index, index);
6667			var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
6668
6669			model.horizontal = horizontal;
6670			model.base = reset ? base : vpixels.base;
6671			model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
6672			model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
6673			model.height = horizontal ? ipixels.size : undefined;
6674			model.width = horizontal ? undefined : ipixels.size;
6675		},
6676
6677		/**
6678		 * @private
6679		 */
6680		getValueScaleId: function() {
6681			return this.getMeta().yAxisID;
6682		},
6683
6684		/**
6685		 * @private
6686		 */
6687		getIndexScaleId: function() {
6688			return this.getMeta().xAxisID;
6689		},
6690
6691		/**
6692		 * @private
6693		 */
6694		getValueScale: function() {
6695			return this.getScaleForId(this.getValueScaleId());
6696		},
6697
6698		/**
6699		 * @private
6700		 */
6701		getIndexScale: function() {
6702			return this.getScaleForId(this.getIndexScaleId());
6703		},
6704
6705		/**
6706		 * Returns the stacks based on groups and bar visibility.
6707		 * @param {Number} [last] - The dataset index
6708		 * @returns {Array} The stack list
6709		 * @private
6710		 */
6711		_getStacks: function(last) {
6712			var me = this;
6713			var chart = me.chart;
6714			var scale = me.getIndexScale();
6715			var stacked = scale.options.stacked;
6716			var ilen = last === undefined ? chart.data.datasets.length : last + 1;
6717			var stacks = [];
6718			var i, meta;
6719
6720			for (i = 0; i < ilen; ++i) {
6721				meta = chart.getDatasetMeta(i);
6722				if (meta.bar && chart.isDatasetVisible(i) &&
6723					(stacked === false ||
6724					(stacked === true && stacks.indexOf(meta.stack) === -1) ||
6725					(stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
6726					stacks.push(meta.stack);
6727				}
6728			}
6729
6730			return stacks;
6731		},
6732
6733		/**
6734		 * Returns the effective number of stacks based on groups and bar visibility.
6735		 * @private
6736		 */
6737		getStackCount: function() {
6738			return this._getStacks().length;
6739		},
6740
6741		/**
6742		 * Returns the stack index for the given dataset based on groups and bar visibility.
6743		 * @param {Number} [datasetIndex] - The dataset index
6744		 * @param {String} [name] - The stack name to find
6745		 * @returns {Number} The stack index
6746		 * @private
6747		 */
6748		getStackIndex: function(datasetIndex, name) {
6749			var stacks = this._getStacks(datasetIndex);
6750			var index = (name !== undefined)
6751				? stacks.indexOf(name)
6752				: -1; // indexOf returns -1 if element is not present
6753
6754			return (index === -1)
6755				? stacks.length - 1
6756				: index;
6757		},
6758
6759		/**
6760		 * @private
6761		 */
6762		getRuler: function() {
6763			var me = this;
6764			var scale = me.getIndexScale();
6765			var stackCount = me.getStackCount();
6766			var datasetIndex = me.index;
6767			var isHorizontal = scale.isHorizontal();
6768			var start = isHorizontal ? scale.left : scale.top;
6769			var end = start + (isHorizontal ? scale.width : scale.height);
6770			var pixels = [];
6771			var i, ilen, min;
6772
6773			for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
6774				pixels.push(scale.getPixelForValue(null, i, datasetIndex));
6775			}
6776
6777			min = helpers.isNullOrUndef(scale.options.barThickness)
6778				? computeMinSampleSize(scale, pixels)
6779				: -1;
6780
6781			return {
6782				min: min,
6783				pixels: pixels,
6784				start: start,
6785				end: end,
6786				stackCount: stackCount,
6787				scale: scale
6788			};
6789		},
6790
6791		/**
6792		 * Note: pixel values are not clamped to the scale area.
6793		 * @private
6794		 */
6795		calculateBarValuePixels: function(datasetIndex, index) {
6796			var me = this;
6797			var chart = me.chart;
6798			var meta = me.getMeta();
6799			var scale = me.getValueScale();
6800			var datasets = chart.data.datasets;
6801			var value = scale.getRightValue(datasets[datasetIndex].data[index]);
6802			var stacked = scale.options.stacked;
6803			var stack = meta.stack;
6804			var start = 0;
6805			var i, imeta, ivalue, base, head, size;
6806
6807			if (stacked || (stacked === undefined && stack !== undefined)) {
6808				for (i = 0; i < datasetIndex; ++i) {
6809					imeta = chart.getDatasetMeta(i);
6810
6811					if (imeta.bar &&
6812						imeta.stack === stack &&
6813						imeta.controller.getValueScaleId() === scale.id &&
6814						chart.isDatasetVisible(i)) {
6815
6816						ivalue = scale.getRightValue(datasets[i].data[index]);
6817						if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
6818							start += ivalue;
6819						}
6820					}
6821				}
6822			}
6823
6824			base = scale.getPixelForValue(start);
6825			head = scale.getPixelForValue(start + value);
6826			size = (head - base) / 2;
6827
6828			return {
6829				size: size,
6830				base: base,
6831				head: head,
6832				center: head + size / 2
6833			};
6834		},
6835
6836		/**
6837		 * @private
6838		 */
6839		calculateBarIndexPixels: function(datasetIndex, index, ruler) {
6840			var me = this;
6841			var options = ruler.scale.options;
6842			var range = options.barThickness === 'flex'
6843				? computeFlexCategoryTraits(index, ruler, options)
6844				: computeFitCategoryTraits(index, ruler, options);
6845
6846			var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
6847			var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
6848			var size = Math.min(
6849				helpers.valueOrDefault(options.maxBarThickness, Infinity),
6850				range.chunk * range.ratio);
6851
6852			return {
6853				base: center - size / 2,
6854				head: center + size / 2,
6855				center: center,
6856				size: size
6857			};
6858		},
6859
6860		draw: function() {
6861			var me = this;
6862			var chart = me.chart;
6863			var scale = me.getValueScale();
6864			var rects = me.getMeta().data;
6865			var dataset = me.getDataset();
6866			var ilen = rects.length;
6867			var i = 0;
6868
6869			helpers.canvas.clipArea(chart.ctx, chart.chartArea);
6870
6871			for (; i < ilen; ++i) {
6872				if (!isNaN(scale.getRightValue(dataset.data[i]))) {
6873					rects[i].draw();
6874				}
6875			}
6876
6877			helpers.canvas.unclipArea(chart.ctx);
6878		},
6879
6880		setHoverStyle: function(rectangle) {
6881			var dataset = this.chart.data.datasets[rectangle._datasetIndex];
6882			var index = rectangle._index;
6883			var custom = rectangle.custom || {};
6884			var model = rectangle._model;
6885
6886			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
6887			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor));
6888			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
6889		},
6890
6891		removeHoverStyle: function(rectangle) {
6892			var dataset = this.chart.data.datasets[rectangle._datasetIndex];
6893			var index = rectangle._index;
6894			var custom = rectangle.custom || {};
6895			var model = rectangle._model;
6896			var rectangleElementOptions = this.chart.options.elements.rectangle;
6897
6898			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor);
6899			model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor);
6900			model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth);
6901		}
6902	});
6903
6904	Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
6905		/**
6906		 * @private
6907		 */
6908		getValueScaleId: function() {
6909			return this.getMeta().xAxisID;
6910		},
6911
6912		/**
6913		 * @private
6914		 */
6915		getIndexScaleId: function() {
6916			return this.getMeta().yAxisID;
6917		}
6918	});
6919};
6920
6921},{"25":25,"40":40,"45":45}],16:[function(require,module,exports){
6922'use strict';
6923
6924var defaults = require(25);
6925var elements = require(40);
6926var helpers = require(45);
6927
6928defaults._set('bubble', {
6929	hover: {
6930		mode: 'single'
6931	},
6932
6933	scales: {
6934		xAxes: [{
6935			type: 'linear', // bubble should probably use a linear scale by default
6936			position: 'bottom',
6937			id: 'x-axis-0' // need an ID so datasets can reference the scale
6938		}],
6939		yAxes: [{
6940			type: 'linear',
6941			position: 'left',
6942			id: 'y-axis-0'
6943		}]
6944	},
6945
6946	tooltips: {
6947		callbacks: {
6948			title: function() {
6949				// Title doesn't make sense for scatter since we format the data as a point
6950				return '';
6951			},
6952			label: function(item, data) {
6953				var datasetLabel = data.datasets[item.datasetIndex].label || '';
6954				var dataPoint = data.datasets[item.datasetIndex].data[item.index];
6955				return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')';
6956			}
6957		}
6958	}
6959});
6960
6961
6962module.exports = function(Chart) {
6963
6964	Chart.controllers.bubble = Chart.DatasetController.extend({
6965		/**
6966		 * @protected
6967		 */
6968		dataElementType: elements.Point,
6969
6970		/**
6971		 * @protected
6972		 */
6973		update: function(reset) {
6974			var me = this;
6975			var meta = me.getMeta();
6976			var points = meta.data;
6977
6978			// Update Points
6979			helpers.each(points, function(point, index) {
6980				me.updateElement(point, index, reset);
6981			});
6982		},
6983
6984		/**
6985		 * @protected
6986		 */
6987		updateElement: function(point, index, reset) {
6988			var me = this;
6989			var meta = me.getMeta();
6990			var custom = point.custom || {};
6991			var xScale = me.getScaleForId(meta.xAxisID);
6992			var yScale = me.getScaleForId(meta.yAxisID);
6993			var options = me._resolveElementOptions(point, index);
6994			var data = me.getDataset().data[index];
6995			var dsIndex = me.index;
6996
6997			var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
6998			var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
6999
7000			point._xScale = xScale;
7001			point._yScale = yScale;
7002			point._options = options;
7003			point._datasetIndex = dsIndex;
7004			point._index = index;
7005			point._model = {
7006				backgroundColor: options.backgroundColor,
7007				borderColor: options.borderColor,
7008				borderWidth: options.borderWidth,
7009				hitRadius: options.hitRadius,
7010				pointStyle: options.pointStyle,
7011				radius: reset ? 0 : options.radius,
7012				skip: custom.skip || isNaN(x) || isNaN(y),
7013				x: x,
7014				y: y,
7015			};
7016
7017			point.pivot();
7018		},
7019
7020		/**
7021		 * @protected
7022		 */
7023		setHoverStyle: function(point) {
7024			var model = point._model;
7025			var options = point._options;
7026
7027			model.backgroundColor = helpers.valueOrDefault(options.hoverBackgroun
7027dColor, helpers.getHoverColor(options.backgroundColor));
7028			model.borderColor = helpers.valueOrDefault(options.hoverBorderColor, helpers.getHoverColor(options.borderColor));
7029			model.borderWidth = helpers.valueOrDefault(options.hoverBorderWidth, options.borderWidth);
7030			model.radius = options.radius + options.hoverRadius;
7031		},
7032
7033		/**
7034		 * @protected
7035		 */
7036		removeHoverStyle: function(point) {
7037			var model = point._model;
7038			var options = point._options;
7039
7040			model.backgroundColor = options.backgroundColor;
7041			model.borderColor = options.borderColor;
7042			model.borderWidth = options.borderWidth;
7043			model.radius = options.radius;
7044		},
7045
7046		/**
7047		 * @private
7048		 */
7049		_resolveElementOptions: function(point, index) {
7050			var me = this;
7051			var chart = me.chart;
7052			var datasets = chart.data.datasets;
7053			var dataset = datasets[me.index];
7054			var custom = point.custom || {};
7055			var options = chart.options.elements.point;
7056			var resolve = helpers.options.resolve;
7057			var data = dataset.data[index];
7058			var values = {};
7059			var i, ilen, key;
7060
7061			// Scriptable options
7062			var context = {
7063				chart: chart,
7064				dataIndex: index,
7065				dataset: dataset,
7066				datasetIndex: me.index
7067			};
7068
7069			var keys = [
7070				'backgroundColor',
7071				'borderColor',
7072				'borderWidth',
7073				'hoverBackgroundColor',
7074				'hoverBorderColor',
7075				'hoverBorderWidth',
7076				'hoverRadius',
7077				'hitRadius',
7078				'pointStyle'
7079			];
7080
7081			for (i = 0, ilen = keys.length; i < ilen; ++i) {
7082				key = keys[i];
7083				values[key] = resolve([
7084					custom[key],
7085					dataset[key],
7086					options[key]
7087				], context, index);
7088			}
7089
7090			// Custom radius resolution
7091			values.radius = resolve([
7092				custom.radius,
7093				data ? data.r : undefined,
7094				dataset.radius,
7095				options.radius
7096			], context, index);
7097
7098			return values;
7099		}
7100	});
7101};
7102
7103},{"25":25,"40":40,"45":45}],17:[function(require,module,exports){
7104'use strict';
7105
7106var defaults = require(25);
7107var elements = require(40);
7108var helpers = require(45);
7109
7110defaults._set('doughnut', {
7111	animation: {
7112		// Boolean - Whether we animate the rotation of the Doughnut
7113		animateRotate: true,
7114		// Boolean - Whether we animate scaling the Doughnut from the centre
7115		animateScale: false
7116	},
7117	hover: {
7118		mode: 'single'
7119	},
7120	legendCallback: function(chart) {
7121		var text = [];
7122		text.push('<ul class="' + chart.id + '-legend">');
7123
7124		var data = chart.data;
7125		var datasets = data.datasets;
7126		var labels = data.labels;
7127
7128		if (datasets.length) {
7129			for (var i = 0; i < datasets[0].data.length; ++i) {
7130				text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
7131				if (labels[i]) {
7132					text.push(labels[i]);
7133				}
7134				text.push('</li>');
7135			}
7136		}
7137
7138		text.push('</ul>');
7139		return text.join('');
7140	},
7141	legend: {
7142		labels: {
7143			generateLabels: function(chart) {
7144				var data = chart.data;
7145				if (data.labels.length && data.datasets.length) {
7146					return data.labels.map(function(label, i) {
7147						var meta = chart.getDatasetMeta(0);
7148						var ds = data.datasets[0];
7149						var arc = meta.data[i];
7150						var custom = arc && arc.custom || {};
7151						var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
7152						var arcOpts = chart.options.elements.arc;
7153						var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
7154						var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
7155						var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
7156
7157						return {
7158							text: label,
7159							fillStyle: fill,
7160							strokeStyle: stroke,
7161							lineWidth: bw,
7162							hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
7163
7164							// Extra data used for toggling the correct item
7165							index: i
7166						};
7167					});
7168				}
7169				return [];
7170			}
7171		},
7172
7173		onClick: function(e, legendItem) {
7174			var index = legendItem.index;
7175			var chart = this.chart;
7176			var i, ilen, meta;
7177
7178			for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
7179				meta = chart.getDatasetMeta(i);
7180				// toggle visibility of index if exists
7181				if (meta.data[index]) {
7182					meta.data[index].hidden = !meta.data[index].hidden;
7183				}
7184			}
7185
7186			chart.update();
7187		}
7188	},
7189
7190	// The percentage of the chart that we cut out of the middle.
7191	cutoutPercentage: 50,
7192
7193	// The rotation of the chart, where the first data arc begins.
7194	rotation: Math.PI * -0.5,
7195
7196	// The total circumference of the chart.
7197	circumference: Math.PI * 2.0,
7198
7199	// Need to override these to give a nice default
7200	tooltips: {
7201		callbacks: {
7202			title: function() {
7203				return '';
7204			},
7205			label: function(tooltipItem, data) {
7206				var dataLabel = data.labels[tooltipItem.index];
7207				var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
7208
7209				if (helpers.isArray(dataLabel)) {
7210					// show value on first line of multiline label
7211					// need to clone because we are changing the value
7212					dataLabel = dataLabel.slice();
7213					dataLabel[0] += value;
7214				} else {
7215					dataLabel += value;
7216				}
7217
7218				return dataLabel;
7219			}
7220		}
7221	}
7222});
7223
7224defaults._set('pie', helpers.clone(defaults.doughnut));
7225defaults._set('pie', {
7226	cutoutPercentage: 0
7227});
7228
7229module.exports = function(Chart) {
7230
7231	Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
7232
7233		dataElementType: elements.Arc,
7234
7235		linkScales: helpers.noop,
7236
7237		// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
7238		getRingIndex: function(datasetIndex) {
7239			var ringIndex = 0;
7240
7241			for (var j = 0; j < datasetIndex; ++j) {
7242				if (this.chart.isDatasetVisible(j)) {
7243					++ringIndex;
7244				}
7245			}
7246
7247			return ringIndex;
7248		},
7249
7250		update: function(reset) {
7251			var me = this;
7252			var chart = me.chart;
7253			var chartArea = chart.chartArea;
7254			var opts = chart.options;
7255			var arcOpts = opts.elements.arc;
7256			var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth;
7257			var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth;
7258			var minSize = Math.min(availableWidth, availableHeight);
7259			var offset = {x: 0, y: 0};
7260			var meta = me.getMeta();
7261			var cutoutPercentage = opts.cutoutPercentage;
7262			var circumference = opts.circumference;
7263
7264			// If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
7265			if (circumference < Math.PI * 2.0) {
7266				var startAngle = opts.rotation % (Math.PI * 2.0);
7267				startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
7268				var endAngle = startAngle + circumference;
7269				var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
7270				var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
7271				var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
7272				var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
7273				var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
7274				var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
7275				var cutout = cutoutPercentage / 100.0;
7276				var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
7277				var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
7278				var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
7279				minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
7280				offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
7281			}
7282
7283			chart.borderWidth = me.getMaxBorderWidth(meta.data);
7284			chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
7285			chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
7286			chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
7287			chart.offsetX = offset.x * chart.outerRadius;
7288			chart.offsetY = offset.y * chart.outerRadius;
7289
7290			meta.total = me.calculateTotal();
7291
7292			me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
7293			me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);
7294
7295			helpers.each(meta.data, function(arc, index) {
7296				me.updateElement(arc, index, reset);
7297			});
7298		},
7299
7300		updateElement: function(arc, index, reset) {
7301			var me = this;
7302			var chart = me.chart;
7303			var chartArea = chart.chartArea;
7304			var opts = chart.options;
7305			var animationOpts = opts.animation;
7306			var centerX = (chartArea.left + chartArea.right) / 2;
7307			var centerY = (chartArea.top + chartArea.bottom) / 2;
7308			var startAngle = opts.rotation; // non reset case handled later
7309			var endAngle = opts.rotation; // non reset case handled later
7310			var dataset = me.getDataset();
7311			var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
7312			var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
7313			var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
7314			var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
7315
7316			helpers.extend(arc, {
7317				// Utility
7318				_datasetIndex: me.index,
7319				_index: index,
7320
7321				// Desired view properties
7322				_model: {
7323					x: centerX + chart.offsetX,
7324					y: centerY + chart.offsetY,
7325					startAngle: startAngle,
7326					endAngle: endAngle,
7327					circumference: circumference,
7328					outerRadius: outerRadius,
7329					innerRadius: innerRadius,
7330					label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
7331				}
7332			});
7333
7334			var model = arc._model;
7335			// Resets the visual styles
7336			this.removeHoverStyle(arc);
7337
7338			// Set correct angles if not resetting
7339			if (!reset || !animationOpts.animateRotate) {
7340				if (index === 0) {
7341					model.startAngle = opts.rotation;
7342				} else {
7343					model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
7344				}
7345
7346				model.endAngle = model.startAngle + model.circumference;
7347			}
7348
7349			arc.pivot();
7350		},
7351
7352		removeHoverStyle: function(arc) {
7353			Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
7354		},
7355
7356		calculateTotal: function() {
7357			var dataset = this.getDataset();
7358			var meta = this.getMeta();
7359			var total = 0;
7360			var value;
7361
7362			helpers.each(meta.data, function(element, index) {
7363				value = dataset.data[index];
7364				if (!isNaN(value) && !element.hidden) {
7365					total += Math.abs(value);
7366				}
7367			});
7368
7369			/* if (total === 0) {
7370				total = NaN;
7371			}*/
7372
7373			return total;
7374		},
7375
7376		calculateCircumference: function(value) {
7377			var total = this.getMeta().total;
7378			if (total > 0 && !isNaN(value)) {
7379				return (Math.PI * 2.0) * (Math.abs(value) / total);
7380			}
7381			return 0;
7382		},
7383
7384		// gets the max border or hover width to properly scale pie charts
7385		getMaxBorderWidth: function(arcs) {
7386			var max = 0;
7387			var index = this.index;
7388			var length = arcs.length;
7389			var borderWidth;
7390			var hoverWidth;
7391
7392			for (var i = 0; i < length; i++) {
7393				borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0;
7394				hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;
7395
7396				max = borderWidth > max ? borderWidth : max;
7397				max = hoverWidth > max ? hoverWidth : max;
7398			}
7399			return max;
7400		}
7401	});
7402};
7403
7404},{"25":25,"40":40,"45":45}],18:[function(require,module,exports){
7405'use strict';
7406
7407var defaults = require(25);
7408var elements = require(40);
7409var helpers = require(45);
7410
7411defaults._set('line', {
7412	showLines: true,
7413	spanGaps: false,
7414
7415	hover: {
7416		mode: 'label'
7417	},
7418
7419	scales: {
7420		xAxes: [{
7421			type: 'category',
7422			id: 'x-axis-0'
7423		}],
7424		yAxes: [{
7425			type: 'linear',
7426			id: 'y-axis-0'
7427		}]
7428	}
7429});
7430
7431module.exports = function(Chart) {
7432
7433	function lineEnabled(dataset, options) {
7434		return helpers.valueOrDefault(dataset.showLine, options.showLines);
7435	}
7436
7437	Chart.controllers.line = Chart.DatasetController.extend({
7438
7439		datasetElementType: elements.Line,
7440
7441		dataElementType: elements.Point,
7442
7443		update: function(reset) {
7444			var me = this;
7445			var meta = me.getMeta();
7446			var line = meta.dataset;
7447			var points = meta.data || [];
7448			var options = me.chart.options;
7449			var lineElementOptions = options.elements.line;
7450			var scale = me.getScaleForId(meta.yAxisID);
7451			var i, ilen, custom;
7452			var dataset = me.getDataset();
7453			var showLine = lineEnabled(dataset, options);
7454
7455			// Update Line
7456			if (showLine) {
7457				custom = line.custom || {};
7458
7459				// Compatibility: If the properties are defined with only the old name, use those values
7460				if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
7461					dataset.lineTension = dataset.tension;
7462				}
7463
7464				// Utility
7465				line._scale = scale;
7466				line._datasetIndex = me.index;
7467				// Data
7468				line._children = points;
7469				// Model
7470				line._model = {
7471					// Appearance
7472					// The default behavior of lines is to break at null values, according
7473					// to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
7474					// This option gives lines the ability to span gaps
7475					spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps,
7476					tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
7477					backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
7478					borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
7479					borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
7480					borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
7481					borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
7482					borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
7483					borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
7484					fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
7485					steppedLine: custom.steppedLine ? custom.steppedLine : helpers.valueOrDefault(dataset.steppedLine, lineElementOptions.stepped),
7486					cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.valueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode),
7487				};
7488
7489				line.pivot();
7490			}
7491
7492			// Update Points
7493			for (i = 0, ilen = points.length; i < ilen; ++i) {
7494				me.updateElement(points[i], i, reset);
7495			}
7496
7497			if (showLine && line._model.tension !== 0) {
7498				me.updateBezierControlPoints();
7499			}
7500
7501			// Now pivot the point for animation
7502			for (i = 0, ilen = points.length; i < ilen; ++i) {
7503				points[i].pivot();
7504			}
7505		},
7506
7507		getPointBackgroundColor: function(point, index) {
7508			var backgroundColor = this.chart.options.elements.point.backgroundColor;
7509			var dataset = this.getDataset();
7510			var custom = point.custom || {};
7511
7512			if (custom.backgroundColor) {
7513				backgroundColor = custom.backgroundColor;
7514			}
7514 else if (dataset.pointBackgroundColor) {
7515				backgroundColor = helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
7516			} else if (dataset.backgroundColor) {
7517				backgroundColor = dataset.backgroundColor;
7518			}
7519
7520			return backgroundColor;
7521		},
7522
7523		getPointBorderColor: function(point, index) {
7524			var borderColor = this.chart.options.elements.point.borderColor;
7525			var dataset = this.getDataset();
7526			var custom = point.custom || {};
7527
7528			if (custom.borderColor) {
7529				borderColor = custom.borderColor;
7530			} else if (dataset.pointBorderColor) {
7531				borderColor = helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
7532			} else if (dataset.borderColor) {
7533				borderColor = dataset.borderColor;
7534			}
7535
7536			return borderColor;
7537		},
7538
7539		getPointBorderWidth: function(point, index) {
7540			var borderWidth = this.chart.options.elements.point.borderWidth;
7541			var dataset = this.getDataset();
7542			var custom = point.custom || {};
7543
7544			if (!isNaN(custom.borderWidth)) {
7545				borderWidth = custom.borderWidth;
7546			} else if (!isNaN(dataset.pointBorderWidth) || helpers.isArray(dataset.pointBorderWidth)) {
7547				borderWidth = helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
7548			} else if (!isNaN(dataset.borderWidth)) {
7549				borderWidth = dataset.borderWidth;
7550			}
7551
7552			return borderWidth;
7553		},
7554
7555		updateElement: function(point, index, reset) {
7556			var me = this;
7557			var meta = me.getMeta();
7558			var custom = point.custom || {};
7559			var dataset = me.getDataset();
7560			var datasetIndex = me.index;
7561			var value = dataset.data[index];
7562			var yScale = me.getScaleForId(meta.yAxisID);
7563			var xScale = me.getScaleForId(meta.xAxisID);
7564			var pointOptions = me.chart.options.elements.point;
7565			var x, y;
7566
7567			// Compatibility: If the properties are defined with only the old name, use those values
7568			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
7569				dataset.pointRadius = dataset.radius;
7570			}
7571			if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
7572				dataset.pointHitRadius = dataset.hitRadius;
7573			}
7574
7575			x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
7576			y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
7577
7578			// Utility
7579			point._xScale = xScale;
7580			point._yScale = yScale;
7581			point._datasetIndex = datasetIndex;
7582			point._index = index;
7583
7584			// Desired view properties
7585			point._model = {
7586				x: x,
7587				y: y,
7588				skip: custom.skip || isNaN(x) || isNaN(y),
7589				// Appearance
7590				radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
7591				pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
7592				backgroundColor: me.getPointBackgroundColor(point, index),
7593				borderColor: me.getPointBorderColor(point, index),
7594				borderWidth: me.getPointBorderWidth(point, index),
7595				tension: meta.dataset._model ? meta.dataset._model.tension : 0,
7596				steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false,
7597				// Tooltip
7598				hitRadius: custom.hitRadius || helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
7599			};
7600		},
7601
7602		calculatePointY: function(value, index, datasetIndex) {
7603			var me = this;
7604			var chart = me.chart;
7605			var meta = me.getMeta();
7606			var yScale = me.getScaleForId(meta.yAxisID);
7607			var sumPos = 0;
7608			var sumNeg = 0;
7609			var i, ds, dsMeta;
7610
7611			if (yScale.options.stacked) {
7612				for (i = 0; i < datasetIndex; i++) {
7613					ds = chart.data.datasets[i];
7614					dsMeta = chart.getDatasetMeta(i);
7615					if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
7616						var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
7617						if (stackedRightValue < 0) {
7618							sumNeg += stackedRightValue || 0;
7619						} else {
7620							sumPos += stackedRightValue || 0;
7621						}
7622					}
7623				}
7624
7625				var rightValue = Number(yScale.getRightValue(value));
7626				if (rightValue < 0) {
7627					return yScale.getPixelForValue(sumNeg + rightValue);
7628				}
7629				return yScale.getPixelForValue(sumPos + rightValue);
7630			}
7631
7632			return yScale.getPixelForValue(value);
7633		},
7634
7635		updateBezierControlPoints: function() {
7636			var me = this;
7637			var meta = me.getMeta();
7638			var area = me.chart.chartArea;
7639			var points = (meta.data || []);
7640			var i, ilen, point, model, controlPoints;
7641
7642			// Only consider points that are drawn in case the spanGaps option is used
7643			if (meta.dataset._model.spanGaps) {
7644				points = points.filter(function(pt) {
7645					return !pt._model.skip;
7646				});
7647			}
7648
7649			function capControlPoint(pt, min, max) {
7650				return Math.max(Math.min(pt, max), min);
7651			}
7652
7653			if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
7654				helpers.splineCurveMonotone(points);
7655			} else {
7656				for (i = 0, ilen = points.length; i < ilen; ++i) {
7657					point = points[i];
7658					model = point._model;
7659					controlPoints = helpers.splineCurve(
7660						helpers.previousItem(points, i)._model,
7661						model,
7662						helpers.nextItem(points, i)._model,
7663						meta.dataset._model.tension
7664					);
7665					model.controlPointPreviousX = controlPoints.previous.x;
7666					model.controlPointPreviousY = controlPoints.previous.y;
7667					model.controlPointNextX = controlPoints.next.x;
7668					model.controlPointNextY = controlPoints.next.y;
7669				}
7670			}
7671
7672			if (me.chart.options.elements.line.capBezierPoints) {
7673				for (i = 0, ilen = points.length; i < ilen; ++i) {
7674					model = points[i]._model;
7675					model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
7676					model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
7677					model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
7678					model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
7679				}
7680			}
7681		},
7682
7683		draw: function() {
7684			var me = this;
7685			var chart = me.chart;
7686			var meta = me.getMeta();
7687			var points = meta.data || [];
7688			var area = chart.chartArea;
7689			var ilen = points.length;
7690			var i = 0;
7691
7692			helpers.canvas.clipArea(chart.ctx, area);
7693
7694			if (lineEnabled(me.getDataset(), chart.options)) {
7695				meta.dataset.draw();
7696			}
7697
7698			helpers.canvas.unclipArea(chart.ctx);
7699
7700			// Draw the points
7701			for (; i < ilen; ++i) {
7702				points[i].draw(area);
7703			}
7704		},
7705
7706		setHoverStyle: function(point) {
7707			// Point
7708			var dataset = this.chart.data.datasets[point._datasetIndex];
7709			var index = point._index;
7710			var custom = point.custom || {};
7711			var model = point._model;
7712
7713			model.radius = custom.hoverRadius || helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
7714			model.backgroundColor = custom.hoverBackgroundColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
7715			model.borderColor = custom.hoverBorderColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
7716			model.borderWidth = custom.hoverBorderWidth || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
7717		},
7718
7719		removeHoverStyle: function(point) {
7720			var me = this;
7721			var dataset = me.chart.data.datasets[point._datasetIndex];
7722			var index = point._index;
7723			var custom = point.custom || {};
7724			var model = point._model;
7725
7726			// Compatibility: If the properties are defined with only the old name, use those values
7727			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
7728				dataset.pointRadius = dataset.radius;
7729			}
7730
7731			model.radius = custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius);
7732			model.backgroundColor = me.getPointBackgroundColor(point, index);
7733			model.borderColor = me.getPointBorderColor(point, index);
7734			model.borderWidth = me.getPointBorderWidth(point, index);
7735		}
7736	});
7737};
7738
7739},{"25":25,"40":40,"45":45}],19:[function(require,module,exports){
7740'use strict';
7741
7742var defaults = require(25);
7743var elements = require(40);
7744var helpers = require(45);
7745
7746defaults._set('polarArea', {
7747	scale: {
7748		type: 'radialLinear',
7749		angleLines: {
7750			display: false
7751		},
7752		gridLines: {
7753			circular: true
7754		},
7755		pointLabels: {
7756			display: false
7757		},
7758		ticks: {
7759			beginAtZero: true
7760		}
7761	},
7762
7763	// Boolean - Whether to animate the rotation of the chart
7764	animation: {
7765		animateRotate: true,
7766		animateScale: true
7767	},
7768
7769	startAngle: -0.5 * Math.PI,
7770	legendCallback: function(chart) {
7771		var text = [];
7772		text.push('<ul class="' + chart.id + '-legend">');
7773
7774		var data = chart.data;
7775		var datasets = data.datasets;
7776		var labels = data.labels;
7777
7778		if (datasets.length) {
7779			for (var i = 0; i < datasets[0].data.length; ++i) {
7780				text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
7781				if (labels[i]) {
7782					text.push(labels[i]);
7783				}
7784				text.push('</li>');
7785			}
7786		}
7787
7788		text.push('</ul>');
7789		return text.join('');
7790	},
7791	legend: {
7792		labels: {
7793			generateLabels: function(chart) {
7794				var data = chart.data;
7795				if (data.labels.length && data.datasets.length) {
7796					return data.labels.map(function(label, i) {
7797						var meta = chart.getDatasetMeta(0);
7798						var ds = data.datasets[0];
7799						var arc = meta.data[i];
7800						var custom = arc.custom || {};
7801						var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
7802						var arcOpts = chart.options.elements.arc;
7803						var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
7804						var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
7805						var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
7806
7807						return {
7808							text: label,
7809							fillStyle: fill,
7810							strokeStyle: stroke,
7811							lineWidth: bw,
7812							hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
7813
7814							// Extra data used for toggling the correct item
7815							index: i
7816						};
7817					});
7818				}
7819				return [];
7820			}
7821		},
7822
7823		onClick: function(e, legendItem) {
7824			var index = legendItem.index;
7825			var chart = this.chart;
7826			var i, ilen, meta;
7827
7828			for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
7829				meta = chart.getDatasetMeta(i);
7830				meta.data[index].hidden = !meta.data[index].hidden;
7831			}
7832
7833			chart.update();
7834		}
7835	},
7836
7837	// Need to override these to give a nice default
7838	tooltips: {
7839		callbacks: {
7840			title: function() {
7841				return '';
7842			},
7843			label: function(item, data) {
7844				return data.labels[item.index] + ': ' + item.yLabel;
7845			}
7846		}
7847	}
7848});
7849
7850module.exports = function(Chart) {
7851
7852	Chart.controllers.polarArea = Chart.DatasetController.extend({
7853
7854		dataElementType: elements.Arc,
7855
7856		linkScales: helpers.noop,
7857
7858		update: function(reset) {
7859			var me = this;
7860			var chart = me.chart;
7861			var chartArea = chart.chartArea;
7862			var meta = me.getMeta();
7863			var opts = chart.options;
7864			var arcOpts = opts.elements.arc;
7865			var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
7866			chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
7867			chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
7868			chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
7869
7870			me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
7871			me.innerRadius = me.outerRadius - chart.radiusLength;
7872
7873			meta.count = me.countVisibleElements();
7874
7875			helpers.each(meta.data, function(arc, index) {
7876				me.updateElement(arc, index, reset);
7877			});
7878		},
7879
7880		updateElement: function(arc, index, reset) {
7881			var me = this;
7882			var chart = me.chart;
7883			var dataset = me.getDataset();
7884			var opts = chart.options;
7885			var animationOpts = opts.animation;
7886			var scale = chart.scale;
7887			var labels = chart.data.labels;
7888
7889			var circumference = me.calculateCircumference(dataset.data[index]);
7890			var centerX = scale.xCenter;
7891			var centerY = scale.yCenter;
7892
7893			// If there is NaN data before us, we need to calculate the starting angle correctly.
7894			// We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
7895			var visibleCount = 0;
7896			var meta = me.getMeta();
7897			for (var i = 0; i < index; ++i) {
7898				if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
7899					++visibleCount;
7900				}
7901			}
7902
7903			// var negHalfPI = -0.5 * Math.PI;
7904			var datasetStartAngle = opts.startAngle;
7905			var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
7906			var startAngle = datasetStartAngle + (circumference * visibleCount);
7907			var endAngle = startAngle + (arc.hidden ? 0 : circumference);
7908
7909			var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
7910
7911			helpers.extend(arc, {
7912				// Utility
7913				_datasetIndex: me.index,
7914				_index: index,
7915				_scale: scale,
7916
7917				// Desired view properties
7918				_model: {
7919					x: centerX,
7920					y: centerY,
7921					innerRadius: 0,
7922					outerRadius: reset ? resetRadius : distance,
7923					startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
7924					endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
7925					label: helpers.valueAtIndexOrDefault(labels, index, labels[index])
7926				}
7927			});
7928
7929			// Apply border and fill style
7930			me.removeHoverStyle(arc);
7931
7932			arc.pivot();
7933		},
7934
7935		removeHoverStyle: function(arc) {
7936			Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
7937		},
7938
7939		countVisibleElements: function() {
7940			var dataset = this.getDataset();
7941			var meta = this.getMeta();
7942			var count = 0;
7943
7944			helpers.each(meta.data, function(element, index) {
7945				if (!isNaN(dataset.data[index]) && !element.hidden) {
7946					count++;
7947				}
7948			});
7949
7950			return count;
7951		},
7952
7953		calculateCircumference: function(value) {
7954			var count = this.getMeta().count;
7955			if (count > 0 && !isNaN(value)) {
7956				return (2 * Math.PI) / count;
7957			}
7958			return 0;
7959		}
7960	});
7961};
7962
7963},{"25":25,"40":40,"45":45}],20:[function(require,module,exports){
7964'use strict';
7965
7966var defaults = require(25);
7967var elements = require(40);
7968var helpers = require(45);
7969
7970defaults._set('radar', {
7971	scale: {
7972		type: 'radialLinear'
7973	},
7974	elements: {
7975		line: {
7976			tension: 0 // no bezier in radar
7977		}
7978	}
7979});
7980
7981module.exports = function(Chart) {
7982
7983	Chart.controllers.radar = Chart.DatasetController.extend({
7984
7985		datasetElementType: elements.Line,
7986
7987		dataElementType: elements.Point,
7988
7989		linkScales: helpers.noop,
7990
7991		update: function(reset) {
7992			var me = this;
7993			var meta = me.getMeta();
7994			var line = meta.dataset;
7995			var points = meta.data;
7996			var custom = line.custom || {};
7997			var dataset = me.getDataset();
7998			var lineElementOptions = me.chart.options.elements.line;
7999			var scale = me.chart.scale;
8000
8001			// Compatibility: If the properties are defined with only the old name, use those values
8002			if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
8003				dataset.lineTension = dataset.tension;
8004			}
8005
8006			helpers.extend(meta.dataset, {
8007				// Utility
8008				_datasetIndex: me.index,
8009				_scale: scale,
8010				// Data
8011				_children: points,
8012				_loop: true,
8013				// Model
8014				_model: {
8015					// Appearance
8016					tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
8017					backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
8018					borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
8019					borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
8020					fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
8021					borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
8022					borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
8023					borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
8024					borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
8025				}
8026			});
8027
8028			meta.dataset.pivot();
8029
8030			// Update Points
8031			helpers.each(points, function(point, index) {
8032				me.updateElement(point, index, reset);
8033			}, me);
8034
8035			// Update bezier control points
8036			me.updateBezierControlPoints();
8037		},
8038		updateElement: function(point, index, reset) {
8039			var me = this;
8040			var custom = point.custom || {};
8041			var dataset = me.getDataset();
8042			var scale = me.chart.scale;
8043			var pointElementOptions = me.chart.options.elements.point;
8044			var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
8045
8046			// Compatibility: If the properties are defined with only the old name, use those values
8047			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
8048				dataset.pointRadius = dataset.radius;
8049			}
8050			if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
8051				dataset.pointHitRadius = dataset.hitRadius;
8052			}
8053
8054			helpers.extend(point, {
8055				// Utility
8056				_datasetIndex: me.index,
8057				_index: index,
8058				_scale: scale,
8059
8060				// Desired view properties
8061				_model: {
8062					x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
8063					y: reset ? scale.yCenter : pointPosition.y,
8064
8065					// Appearance
8066					tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
8067					radius: custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
8068					backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroun
8068dColor, index, pointElementOptions.backgroundColor),
8069					borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
8070					borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
8071					pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),
8072
8073					// Tooltip
8074					hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius)
8075				}
8076			});
8077
8078			point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
8079		},
8080		updateBezierControlPoints: function() {
8081			var chartArea = this.chart.chartArea;
8082			var meta = this.getMeta();
8083
8084			helpers.each(meta.data, function(point, index) {
8085				var model = point._model;
8086				var controlPoints = helpers.splineCurve(
8087					helpers.previousItem(meta.data, index, true)._model,
8088					model,
8089					helpers.nextItem(meta.data, index, true)._model,
8090					model.tension
8091				);
8092
8093				// Prevent the bezier going outside of the bounds of the graph
8094				model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left);
8095				model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top);
8096
8097				model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left);
8098				model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top);
8099
8100				// Now pivot the point for animation
8101				point.pivot();
8102			});
8103		},
8104
8105		setHoverStyle: function(point) {
8106			// Point
8107			var dataset = this.chart.data.datasets[point._datasetIndex];
8108			var custom = point.custom || {};
8109			var index = point._index;
8110			var model = point._model;
8111
8112			model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
8113			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
8114			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
8115			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
8116		},
8117
8118		removeHoverStyle: function(point) {
8119			var dataset = this.chart.data.datasets[point._datasetIndex];
8120			var custom = point.custom || {};
8121			var index = point._index;
8122			var model = point._model;
8123			var pointElementOptions = this.chart.options.elements.point;
8124
8125			model.radius = custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius);
8126			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroun
8126dColor, index, pointElementOptions.backgroundColor);
8127			model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor);
8128			model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth);
8129		}
8130	});
8131};
8132
8133},{"25":25,"40":40,"45":45}],21:[function(require,module,exports){
8134'use strict';
8135
8136var defaults = require(25);
8137
8138defaults._set('scatter', {
8139	hover: {
8140		mode: 'single'
8141	},
8142
8143	scales: {
8144		xAxes: [{
8145			id: 'x-axis-1',    // need an ID so datasets can reference the scale
8146			type: 'linear',    // scatter should not use a category axis
8147			position: 'bottom'
8148		}],
8149		yAxes: [{
8150			id: 'y-axis-1',
8151			type: 'linear',
8152			position: 'left'
8153		}]
8154	},
8155
8156	showLines: false,
8157
8158	tooltips: {
8159		callbacks: {
8160			title: function() {
8161				return '';     // doesn't make sense for scatter since data are formatted as a point
8162			},
8163			label: function(item) {
8164				return '(' + item.xLabel + ', ' + item.yLabel + ')';
8165			}
8166		}
8167	}
8168});
8169
8170module.exports = function(Chart) {
8171
8172	// Scatter charts use line controllers
8173	Chart.controllers.scatter = Chart.controllers.line;
8174
8175};
8176
8177},{"25":25}],22:[function(require,module,exports){
8178/* global window: false */
8179'use strict';
8180
8181var defaults = require(25);
8182var Element = require(26);
8183var helpers = require(45);
8184
8185defaults._set('global', {
8186	animation: {
8187		duration: 1000,
8188		easing: 'easeOutQuart',
8189		onProgress: helpers.noop,
8190		onComplete: helpers.noop
8191	}
8192});
8193
8194module.exports = function(Chart) {
8195
8196	Chart.Animation = Element.extend({
8197		chart: null, // the animation associated chart instance
8198		currentStep: 0, // the current animation step
8199		numSteps: 60, // default number of steps
8200		easing: '', // the easing to use for this animation
8201		render: null, // render function used by the animation service
8202
8203		onAnimationProgress: null, // user specified callback to fire on each step of the animation
8204		onAnimationComplete: null, // user specified callback to fire when the animation finishes
8205	});
8206
8207	Chart.animationService = {
8208		frameDuration: 17,
8209		animations: [],
8210		dropFrames: 0,
8211		request: null,
8212
8213		/**
8214		 * @param {Chart} chart - The chart to animate.
8215		 * @param {Chart.Animation} animation - The animation that we will animate.
8216		 * @param {Number} duration - The animation duration in ms.
8217		 * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
8218		 */
8219		addAnimation: function(chart, animation, duration, lazy) {
8220			var animations = this.animations;
8221			var i, ilen;
8222
8223			animation.chart = chart;
8224
8225			if (!lazy) {
8226				chart.animating = true;
8227			}
8228
8229			for (i = 0, ilen = animations.length; i < ilen; ++i) {
8230				if (animations[i].chart === chart) {
8231					animations[i] = animation;
8232					return;
8233				}
8234			}
8235
8236			animations.push(animation);
8237
8238			// If there are no animations queued, manually kickstart a digest, for lack of a better word
8239			if (animations.length === 1) {
8240				this.requestAnimationFrame();
8241			}
8242		},
8243
8244		cancelAnimation: function(chart) {
8245			var index = helpers.findIndex(this.animations, function(animation) {
8246				return animation.chart === chart;
8247			});
8248
8249			if (index !== -1) {
8250				this.animations.splice(index, 1);
8251				chart.animating = false;
8252			}
8253		},
8254
8255		requestAnimationFrame: function() {
8256			var me = this;
8257			if (me.request === null) {
8258				// Skip animation frame requests until the active one is executed.
8259				// This can happen when processing mouse events, e.g. 'mousemove'
8260				// and 'mouseout' events will trigger multiple renders.
8261				me.request = helpers.requestAnimFrame.call(window, function() {
8262					me.request = null;
8263					me.startDigest();
8264				});
8265			}
8266		},
8267
8268		/**
8269		 * @private
8270		 */
8271		startDigest: function() {
8272			var me = this;
8273			var startTime = Date.now();
8274			var framesToDrop = 0;
8275
8276			if (me.dropFrames > 1) {
8277				framesToDrop = Math.floor(me.dropFrames);
8278				me.dropFrames = me.dropFrames % 1;
8279			}
8280
8281			me.advance(1 + framesToDrop);
8282
8283			var endTime = Date.now();
8284
8285			me.dropFrames += (endTime - startTime) / me.frameDuration;
8286
8287			// Do we have more stuff to animate?
8288			if (me.animations.length > 0) {
8289				me.requestAnimationFrame();
8290			}
8291		},
8292
8293		/**
8294		 * @private
8295		 */
8296		advance: function(count) {
8297			var animations = this.animations;
8298			var animation, chart;
8299			var i = 0;
8300
8301			while (i < animations.length) {
8302				animation = animations[i];
8303				chart = animation.chart;
8304
8305				animation.currentStep = (animation.currentStep || 0) + count;
8306				animation.currentStep = Math.min(animation.currentStep, animation.numSteps);
8307
8308				helpers.callback(animation.render, [chart, animation], chart);
8309				helpers.callback(animation.onAnimationProgress, [animation], chart);
8310
8311				if (animation.currentStep >= animation.numSteps) {
8312					helpers.callback(animation.onAnimationComplete, [animation], chart);
8313					chart.animating = false;
8314					animations.splice(i, 1);
8315				} else {
8316					++i;
8317				}
8318			}
8319		}
8320	};
8321
8322	/**
8323	 * Provided for backward compatibility, use Chart.Animation instead
8324	 * @prop Chart.Animation#animationObject
8325	 * @deprecated since version 2.6.0
8326	 * @todo remove at version 3
8327	 */
8328	Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
8329		get: function() {
8330			return this;
8331		}
8332	});
8333
8334	/**
8335	 * Provided for backward compatibility, use Chart.Animation#chart instead
8336	 * @prop Chart.Animation#chartInstance
8337	 * @deprecated since version 2.6.0
8338	 * @todo remove at version 3
8339	 */
8340	Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
8341		get: function() {
8342			return this.chart;
8343		},
8344		set: function(value) {
8345			this.chart = value;
8346		}
8347	});
8348
8349};
8350
8351},{"25":25,"26":26,"45":45}],23:[function(require,module,exports){
8352'use strict';
8353
8354var defaults = require(25);
8355var helpers = require(45);
8356var Interaction = require(28);
8357var layouts = require(30);
8358var platform = require(48);
8359var plugins = require(31);
8360
8361module.exports = function(Chart) {
8362
8363	// Create a dictionary of chart types, to allow for extension of existing types
8364	Chart.types = {};
8365
8366	// Store a reference to each instance - allowing us to globally resize chart instances on window resize.
8367	// Destroy method on the chart will remove the instance of the chart from this reference.
8368	Chart.instances = {};
8369
8370	// Controllers available for dataset visualization eg. bar, line, slice, etc.
8371	Chart.controllers = {};
8372
8373	/**
8374	 * Initializes the given config with global and chart default values.
8375	 */
8376	function initConfig(config) {
8377		config = config || {};
8378
8379		// Do NOT use configMerge() for the data object because this method merges arrays
8380		// and so would change references to labels and datasets, preventing data updates.
8381		var data = config.data = config.data || {};
8382		data.datasets = data.datasets || [];
8383		data.labels = data.labels || [];
8384
8385		config.options = helpers.configMerge(
8386			defaults.global,
8387			defaults[config.type],
8388			config.options || {});
8389
8390		return config;
8391	}
8392
8393	/**
8394	 * Updates the config of the chart
8395	 * @param chart {Chart} chart to update the options for
8396	 */
8397	function updateConfig(chart) {
8398		var newOptions = chart.options;
8399
8400		helpers.each(chart.scales, function(scale) {
8401			layouts.removeBox(chart, scale);
8402		});
8403
8404		newOptions = helpers.configMerge(
8405			Chart.defaults.global,
8406			Chart.defaults[chart.config.type],
8407			newOptions);
8408
8409		chart.options = chart.config.options = newOptions;
8410		chart.ensureScalesHaveIDs();
8411		chart.buildOrUpdateScales();
8412		// Tooltip
8413		chart.tooltip._options = newOptions.tooltips;
8414		chart.tooltip.initialize();
8415	}
8416
8417	function positionIsHorizontal(position) {
8418		return position === 'top' || position === 'bottom';
8419	}
8420
8421	helpers.extend(Chart.prototype, /** @lends Chart */ {
8422		/**
8423		 * @private
8424		 */
8425		construct: function(item, config) {
8426			var me = this;
8427
8428			config = initConfig(config);
8429
8430			var context = platform.acquireContext(item, config);
8431			var canvas = context && context.canvas;
8432			var height = canvas && canvas.height;
8433			var width = canvas && canvas.width;
8434
8435			me.id = helpers.uid();
8436			me.ctx = context;
8437			me.canvas = canvas;
8438			me.config = config;
8439			me.width = width;
8440			me.height = height;
8441			me.aspectRatio = height ? width / height : null;
8442			me.options = config.options;
8443			me._bufferedRender = false;
vendor: 10,788 bytes, lines 8444-8842
8444
8445			/**
8446			 * Provided for backward compatibility, Chart and Chart.Controller have been merged,
8447			 * the "instance" still need to be defined since it might be called from plugins.
8448			 * @prop Chart#chart
8449			 * @deprecated since version 2.6.0
8450			 * @todo remove at version 3
8451			 * @private
8452			 */
8453			me.chart = me;
8454			me.controller = me; // chart.chart.controller #inception
8455
8456			// Add the chart instance to the global namespace
8457			Chart.instances[me.id] = me;
8458
8459			// Define alias to the config data: `chart.data === chart.config.data`
8460			Object.defineProperty(me, 'data', {
8461				get: function() {
8462					return me.config.data;
8463				},
8464				set: function(value) {
8465					me.config.data = value;
8466				}
8467			});
8468
8469			if (!context || !canvas) {
8470				// The given item is not a compatible context2d element, let's return before finalizing
8471				// the chart initialization but after setting basic chart / controller properties that
8472				// can help to figure out that the chart is not valid (e.g chart.canvas !== null);
8473				// https://github.com/chartjs/Chart.js/issues/2807
8474				console.error("Failed to create chart: can't acquire context from the given item");
8475				return;
8476			}
8477
8478			me.initialize();
8479			me.update();
8480		},
8481
8482		/**
8483		 * @private
8484		 */
8485		initialize: function() {
8486			var me = this;
8487
8488			// Before init plugin notification
8489			plugins.notify(me, 'beforeInit');
8490
8491			helpers.retinaScale(me, me.options.devicePixelRatio);
8492
8493			me.bindEvents();
8494
8495			if (me.options.responsive) {
8496				// Initial resize before chart draws (must be silent to preserve initial animations).
8497				me.resize(true);
8498			}
8499
8500			// Make sure scales have IDs and are built before we build any controllers.
8501			me.ensureScalesHaveIDs();
8502			me.buildOrUpdateScales();
8503			me.initToolTip();
8504
8505			// After init plugin notification
8506			plugins.notify(me, 'afterInit');
8507
8508			return me;
8509		},
8510
8511		clear: function() {
8512			helpers.canvas.clear(this);
8513			return this;
8514		},
8515
8516		stop: function() {
8517			// Stops any current animation loop occurring
8518			Chart.animationService.cancelAnimation(this);
8519			return this;
8520		},
8521
8522		resize: function(silent) {
8523			var me = this;
8524			var options = me.options;
8525			var canvas = me.canvas;
8526			var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;
8527
8528			// the canvas render width and height will be casted to integers so make sure that
8529			// the canvas display style uses the same integer values to avoid blurring effect.
8530
8531			// Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collased
8532			var newWidth = Math.max(0, Math.floor(helpers.getMaximumWidth(canvas)));
8533			var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas)));
8534
8535			if (me.width === newWidth && me.height === newHeight) {
8536				return;
8537			}
8538
8539			canvas.width = me.width = newWidth;
8540			canvas.height = me.height = newHeight;
8541			canvas.style.width = newWidth + 'px';
8542			canvas.style.height = newHeight + 'px';
8543
8544			helpers.retinaScale(me, options.devicePixelRatio);
8545
8546			if (!silent) {
8547				// Notify any plugins about the resize
8548				var newSize = {width: newWidth, height: newHeight};
8549				plugins.notify(me, 'resize', [newSize]);
8550
8551				// Notify of resize
8552				if (me.options.onResize) {
8553					me.options.onResize(me, newSize);
8554				}
8555
8556				me.stop();
8557				me.update(me.options.responsiveAnimationDuration);
8558			}
8559		},
8560
8561		ensureScalesHaveIDs: function() {
8562			var options = this.options;
8563			var scalesOptions = options.scales || {};
8564			var scaleOptions = options.scale;
8565
8566			helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) {
8567				xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
8568			});
8569
8570			helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) {
8571				yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
8572			});
8573
8574			if (scaleOptions) {
8575				scaleOptions.id = scaleOptions.id || 'scale';
8576			}
8577		},
8578
8579		/**
8580		 * Builds a map of scale ID to scale object for future lookup.
8581		 */
8582		buildOrUpdateScales: function() {
8583			var me = this;
8584			var options = me.options;
8585			var scales = me.scales || {};
8586			var items = [];
8587			var updated = Object.keys(scales).reduce(function(obj, id) {
8588				obj[id] = false;
8589				return obj;
8590			}, {});
8591
8592			if (options.scales) {
8593				items = items.concat(
8594					(options.scales.xAxes || []).map(function(xAxisOptions) {
8595						return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
8596					}),
8597					(options.scales.yAxes || []).map(function(yAxisOptions) {
8598						return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
8599					})
8600				);
8601			}
8602
8603			if (options.scale) {
8604				items.push({
8605					options: options.scale,
8606					dtype: 'radialLinear',
8607					isDefault: true,
8608					dposition: 'chartArea'
8609				});
8610			}
8611
8612			helpers.each(items, function(item) {
8613				var scaleOptions = item.options;
8614				var id = scaleOptions.id;
8615				var scaleType = helpers.valueOrDefault(scaleOptions.type, item.dtype);
8616
8617				if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
8618					scaleOptions.position = item.dposition;
8619				}
8620
8621				updated[id] = true;
8622				var scale = null;
8623				if (id in scales && scales[id].type === scaleType) {
8624					scale = scales[id];
8625					scale.options = scaleOptions;
8626					scale.ctx = me.ctx;
8627					scale.chart = me;
8628				} else {
8629					var scaleClass = Chart.scaleService.getScaleConstructor(scaleType);
8630					if (!scaleClass) {
8631						return;
8632					}
8633					scale = new scaleClass({
8634						id: id,
8635						type: scaleType,
8636						options: scaleOptions,
8637						ctx: me.ctx,
8638						chart: me
8639					});
8640					scales[scale.id] = scale;
8641				}
8642
8643				scale.mergeTicksOptions();
8644
8645				// TODO(SB): I think we should be able to remove this custom case (options.scale)
8646				// and consider it as a regular scale part of the "scales"" map only! This would
8647				// make the logic easier and remove some useless? custom code.
8648				if (item.isDefault) {
8649					me.scale = scale;
8650				}
8651			});
8652			// clear up discarded scales
8653			helpers.each(updated, function(hasUpdated, id) {
8654				if (!hasUpdated) {
8655					delete scales[id];
8656				}
8657			});
8658
8659			me.scales = scales;
8660
8661			Chart.scaleService.addScalesToLayout(this);
8662		},
8663
8664		buildOrUpdateControllers: function() {
8665			var me = this;
8666			var types = [];
8667			var newControllers = [];
8668
8669			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
8670				var meta = me.getDatasetMeta(datasetIndex);
8671				var type = dataset.type || me.config.type;
8672
8673				if (meta.type && meta.type !== type) {
8674					me.destroyDatasetMeta(datasetIndex);
8675					meta = me.getDatasetMeta(datasetIndex);
8676				}
8677				meta.type = type;
8678
8679				types.push(meta.type);
8680
8681				if (meta.controller) {
8682					meta.controller.updateIndex(datasetIndex);
8683					meta.controller.linkScales();
8684				} else {
8685					var ControllerClass = Chart.controllers[meta.type];
8686					if (ControllerClass === undefined) {
8687						throw new Error('"' + meta.type + '" is not a chart type.');
8688					}
8689
8690					meta.controller = new ControllerClass(me, datasetIndex);
8691					newControllers.push(meta.controller);
8692				}
8693			}, me);
8694
8695			return newControllers;
8696		},
8697
8698		/**
8699		 * Reset the elements of all datasets
8700		 * @private
8701		 */
8702		resetElements: function() {
8703			var me = this;
8704			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
8705				me.getDatasetMeta(datasetIndex).controller.reset();
8706			}, me);
8707		},
8708
8709		/**
8710		* Resets the chart back to it's state before the initial animation
8711		*/
8712		reset: function() {
8713			this.resetElements();
8714			this.tooltip.initialize();
8715		},
8716
8717		update: function(config) {
8718			var me = this;
8719
8720			if (!config || typeof config !== 'object') {
8721				// backwards compatibility
8722				config = {
8723					duration: config,
8724					lazy: arguments[1]
8725				};
8726			}
8727
8728			updateConfig(me);
8729
8730			// plugins options references might have change, let's invalidate the cache
8731			// https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
8732			plugins._invalidate(me);
8733
8734			if (plugins.notify(me, 'beforeUpdate') === false) {
8735				return;
8736			}
8737
8738			// In case the entire data object changed
8739			me.tooltip._data = me.data;
8740
8741			// Make sure dataset controllers are updated and new controllers are reset
8742			var newControllers = me.buildOrUpdateControllers();
8743
8744			// Make sure all dataset controllers have correct meta data counts
8745			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
8746				me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
8747			}, me);
8748
8749			me.updateLayout();
8750
8751			// Can only reset the new controllers after the scales have been updated
8752			if (me.options.animation && me.options.animation.duration) {
8753				helpers.each(newControllers, function(controller) {
8754					controller.reset();
8755				});
8756			}
8757
8758			me.updateDatasets();
8759
8760			// Need to reset tooltip in case it is displayed with elements that are removed
8761			// after update.
8762			me.tooltip.initialize();
8763
8764			// Last active contains items that were previously in the tooltip.
8765			// When we reset the tooltip, we need to clear it
8766			me.lastActive = [];
8767
8768			// Do this before render so that any plugins that need final scale updates can use it
8769			plugins.notify(me, 'afterUpdate');
8770
8771			if (me._bufferedRender) {
8772				me._bufferedRequest = {
8773					duration: config.duration,
8774					easing: config.easing,
8775					lazy: config.lazy
8776				};
8777			} else {
8778				me.render(config);
8779			}
8780		},
8781
8782		/**
8783		 * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
8784		 * hook, in which case, plugins will not be called on `afterLayout`.
8785		 * @private
8786		 */
8787		updateLayout: function() {
8788			var me = this;
8789
8790			if (plugins.notify(me, 'beforeLayout') === false) {
8791				return;
8792			}
8793
8794			layouts.update(this, this.width, this.height);
8795
8796			/**
8797			 * Provided for backward compatibility, use `afterLayout` instead.
8798			 * @method IPlugin#afterScaleUpdate
8799			 * @deprecated since version 2.5.0
8800			 * @todo remove at version 3
8801			 * @private
8802			 */
8803			plugins.notify(me, 'afterScaleUpdate');
8804			plugins.notify(me, 'afterLayout');
8805		},
8806
8807		/**
8808		 * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
8809		 * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
8810		 * @private
8811		 */
8812		updateDatasets: function() {
8813			var me = this;
8814
8815			if (plugins.notify(me, 'beforeDatasetsUpdate') === false) {
8816				return;
8817			}
8818
8819			for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
8820				me.updateDataset(i);
8821			}
8822
8823			plugins.notify(me, 'afterDatasetsUpdate');
8824		},
8825
8826		/**
8827		 * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
8828		 * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
8829		 * @private
8830		 */
8831		updateDataset: function(index) {
8832			var me = this;
8833			var meta = me.getDatasetMeta(index);
8834			var args = {
8835				meta: meta,
8836				index: index
8837			};
8838
8839			if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
8840				return;
8841			}
8842
8843			meta.controller.update();
8844
8845			plugins.notify(me, 'afterDatasetUpdate', [args]);
8846		},
8847
8848		render: function(config) {
8849			var me = this;
8850
8851			if (!config || typeof config !== 'object') {
8852				// backwards compatibility
8853				config = {
8854					duration: config,
8855					lazy: arguments[1]
8856				};
8857			}
8858
8859			var duration = config.duration;
8860			var lazy = config.lazy;
8861
8862			if (plugins.notify(me, 'beforeRender') === false) {
8863				return;
8864			}
8865
8866			var animationOptions = me.options.animation;
8867			var onComplete = function(animation) {
8868				plugins.notify(me, 'afterRender');
8869				helpers.callback(animationOptions && animationOptions.onComplete, [animation], me);
8870			};
8871
8872			if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
8873				var animation = new Chart.Animation({
8874					numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
8875					easing: config.easing || animationOptions.easing,
8876
8877					render: function(chart, animationObject) {
8878						var easingFunction = helpers.easing.effects[animationObject.easing];
8879						var currentStep = animationObject.currentStep;
8880						var stepDecimal = currentStep / animationObject.numSteps;
8881
8882						chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
8883					},
8884
8885					onAnimationProgress: animationOptions.onProgress,
8886					onAnimationComplete: onComplete
8887				});
8888
8889				Chart.animationService.addAnimation(me, animation, duration, lazy);
8890			} else {
8891				me.draw();
8892
8893				// See https://github.com/chartjs/Chart.js/issues/3781
8894				onComplete(new Chart.Animation({numSteps: 0, chart: me}));
8895			}
8896
8897			return me;
8898		},
8899
8900		draw: function(easingValue) {
8901			var me = this;
8902
8903			me.clear();
8904
8905			if (helpers.isNullOrUndef(easingValue)) {
8906				easingValue = 1;
8907			}
8908
8909			me.transition(easingValue);
8910
8911			if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
8912				return;
8913			}
8914
8915			// Draw all the scales
8916			helpers.each(me.boxes, function(box) {
8917				box.draw(me.chartArea);
8918			}, me);
8919
8920			if (me.scale) {
8921				me.scale.draw();
8922			}
8923
8924			me.drawDatasets(easingValue);
8925			me._drawTooltip(easingValue);
8926
8927			plugins.notify(me, 'afterDraw', [easingValue]);
8928		},
8929
8930		/**
8931		 * @private
8932		 */
8933		transition: function(easingValue) {
8934			var me = this;
8935
8936			for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {
8937				if (me.isDatasetVisible(i)) {
8938					me.getDatasetMeta(i).controller.transition(easingValue);
8939				}
8940			}
8941
8942			me.tooltip.transition(easingValue);
8943		},
8944
8945		/**
8946		 * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
8947		 * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
8948		 * @private
8949		 */
8950		drawDatasets: function(easingValue) {
8951			var me = this;
8952
8953			if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
8954				return;
8955			}
8956
8957			// Draw datasets reversed to support proper line stacking
8958			for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) {
8959				if (me.isDatasetVisible(i)) {
8960					me.drawDataset(i, easingValue);
8961				}
8962			}
8963
8964			plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
8965		},
8966
8967		/**
8968		 * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
8969		 * hook, in which case, plugins will not be called on `afterDatasetDraw`.
8970		 * @private
8971		 */
8972		drawDataset: function(index, easingValue) {
8973			var me = this;
8974			var meta = me.getDatasetMeta(index);
8975			var args = {
8976				meta: meta,
8977				index: index,
8978				easingValue: easingValue
8979			};
8980
8981			if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
8982				return;
8983			}
8984
8985			meta.controller.draw(easingValue);
8986
8987			plugins.notify(me, 'afterDatasetDraw', [args]);
8988		},
8989
8990		/**
8991		 * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`
8992		 * hook, in which case, plugins will not be called on `afterTooltipDraw`.
8993		 * @private
8994		 */
8995		_drawTooltip: function(easingValue) {
8996			var me = this;
8997			var tooltip = me.tooltip;
8998			var args = {
8999				tooltip: tooltip,
9000				easingValue: easingValue
9001			};
9002
9003			if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
9004				return;
9005			}
9006
9007			tooltip.draw();
9008
9009			plugins.notify(me, 'afterTooltipDraw', [args]);
9010		},
9011
9012		// Get the single element that was clicked on
vendor: 45,871 bytes, lines 9013-10617
9013		// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
9014		getElementAtEvent: function(e) {
9015			return Interaction.modes.single(this, e);
9016		},
9017
9018		getElementsAtEvent: function(e) {
9019			return Interaction.modes.label(this, e, {intersect: true});
9020		},
9021
9022		getElementsAtXAxis: function(e) {
9023			return Interaction.modes['x-axis'](this, e, {intersect: true});
9024		},
9025
9026		getElementsAtEventForMode: function(e, mode, options) {
9027			var method = Interaction.modes[mode];
9028			if (typeof method === 'function') {
9029				return method(this, e, options);
9030			}
9031
9032			return [];
9033		},
9034
9035		getDatasetAtEvent: function(e) {
9036			return Interaction.modes.dataset(this, e, {intersect: true});
9037		},
9038
9039		getDatasetMeta: function(datasetIndex) {
9040			var me = this;
9041			var dataset = me.data.datasets[datasetIndex];
9042			if (!dataset._meta) {
9043				dataset._meta = {};
9044			}
9045
9046			var meta = dataset._meta[me.id];
9047			if (!meta) {
9048				meta = dataset._meta[me.id] = {
9049					type: null,
9050					data: [],
9051					dataset: null,
9052					controller: null,
9053					hidden: null,			// See isDatasetVisible() comment
9054					xAxisID: null,
9055					yAxisID: null
9056				};
9057			}
9058
9059			return meta;
9060		},
9061
9062		getVisibleDatasetCount: function() {
9063			var count = 0;
9064			for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
9065				if (this.isDatasetVisible(i)) {
9066					count++;
9067				}
9068			}
9069			return count;
9070		},
9071
9072		isDatasetVisible: function(datasetIndex) {
9073			var meta = this.getDatasetMeta(datasetIndex);
9074
9075			// meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
9076			// the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
9077			return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
9078		},
9079
9080		generateLegend: function() {
9081			return this.options.legendCallback(this);
9082		},
9083
9084		/**
9085		 * @private
9086		 */
9087		destroyDatasetMeta: function(datasetIndex) {
9088			var id = this.id;
9089			var dataset = this.data.datasets[datasetIndex];
9090			var meta = dataset._meta && dataset._meta[id];
9091
9092			if (meta) {
9093				meta.controller.destroy();
9094				delete dataset._meta[id];
9095			}
9096		},
9097
9098		destroy: function() {
9099			var me = this;
9100			var canvas = me.canvas;
9101			var i, ilen;
9102
9103			me.stop();
9104
9105			// dataset controllers need to cleanup associated data
9106			for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
9107				me.destroyDatasetMeta(i);
9108			}
9109
9110			if (canvas) {
9111				me.unbindEvents();
9112				helpers.canvas.clear(me);
9113				platform.releaseContext(me.ctx);
9114				me.canvas = null;
9115				me.ctx = null;
9116			}
9117
9118			plugins.notify(me, 'destroy');
9119
9120			delete Chart.instances[me.id];
9121		},
9122
9123		toBase64Image: function() {
9124			return this.canvas.toDataURL.apply(this.canvas, arguments);
9125		},
9126
9127		initToolTip: function() {
9128			var me = this;
9129			me.tooltip = new Chart.Tooltip({
9130				_chart: me,
9131				_chartInstance: me, // deprecated, backward compatibility
9132				_data: me.data,
9133				_options: me.options.tooltips
9134			}, me);
9135		},
9136
9137		/**
9138		 * @private
9139		 */
9140		bindEvents: function() {
9141			var me = this;
9142			var listeners = me._listeners = {};
9143			var listener = function() {
9144				me.eventHandler.apply(me, arguments);
9145			};
9146
9147			helpers.each(me.options.events, function(type) {
9148				platform.addEventListener(me, type, listener);
9149				listeners[type] = listener;
9150			});
9151
9152			// Elements used to detect size change should not be injected for non responsive charts.
9153			// See https://github.com/chartjs/Chart.js/issues/2210
9154			if (me.options.responsive) {
9155				listener = function() {
9156					me.resize();
9157				};
9158
9159				platform.addEventListener(me, 'resize', listener);
9160				listeners.resize = listener;
9161			}
9162		},
9163
9164		/**
9165		 * @private
9166		 */
9167		unbindEvents: function() {
9168			var me = this;
9169			var listeners = me._listeners;
9170			if (!listeners) {
9171				return;
9172			}
9173
9174			delete me._listeners;
9175			helpers.each(listeners, function(listener, type) {
9176				platform.removeEventListener(me, type, listener);
9177			});
9178		},
9179
9180		updateHoverStyle: function(elements, mode, enabled) {
9181			var method = enabled ? 'setHoverStyle' : 'removeHoverStyle';
9182			var element, i, ilen;
9183
9184			for (i = 0, ilen = elements.length; i < ilen; ++i) {
9185				element = elements[i];
9186				if (element) {
9187					this.getDatasetMeta(element._datasetIndex).controller[method](element);
9188				}
9189			}
9190		},
9191
9192		/**
9193		 * @private
9194		 */
9195		eventHandler: function(e) {
9196			var me = this;
9197			var tooltip = me.tooltip;
9198
9199			if (plugins.notify(me, 'beforeEvent', [e]) === false) {
9200				return;
9201			}
9202
9203			// Buffer any update calls so that renders do not occur
9204			me._bufferedRender = true;
9205			me._bufferedRequest = null;
9206
9207			var changed = me.handleEvent(e);
9208			// for smooth tooltip animations issue #4989
9209			// the tooltip should be the source of change
9210			// Animation check workaround:
9211			// tooltip._start will be null when tooltip isn't animating
9212			if (tooltip) {
9213				changed = tooltip._start
9214					? tooltip.handleEvent(e)
9215					: changed | tooltip.handleEvent(e);
9216			}
9217
9218			plugins.notify(me, 'afterEvent', [e]);
9219
9220			var bufferedRequest = me._bufferedRequest;
9221			if (bufferedRequest) {
9222				// If we have an update that was triggered, we need to do a normal render
9223				me.render(bufferedRequest);
9224			} else if (changed && !me.animating) {
9225				// If entering, leaving, or changing elements, animate the change via pivot
9226				me.stop();
9227
9228				// We only need to render at this point. Updating will cause scales to be
9229				// recomputed generating flicker & using more memory than necessary.
9230				me.render(me.options.hover.animationDuration, true);
9231			}
9232
9233			me._bufferedRender = false;
9234			me._bufferedRequest = null;
9235
9236			return me;
9237		},
9238
9239		/**
9240		 * Handle an event
9241		 * @private
9242		 * @param {IEvent} event the event to handle
9243		 * @return {Boolean} true if the chart needs to re-render
9244		 */
9245		handleEvent: function(e) {
9246			var me = this;
9247			var options = me.options || {};
9248			var hoverOptions = options.hover;
9249			var changed = false;
9250
9251			me.lastActive = me.lastActive || [];
9252
9253			// Find Active Elements for hover and tooltips
9254			if (e.type === 'mouseout') {
9255				me.active = [];
9256			} else {
9257				me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
9258			}
9259
9260			// Invoke onHover hook
9261			// Need to call with native event here to not break backwards compatibility
9262			helpers.callback(options.onHover || options.hover.onHover, [e.native, me.active], me);
9263
9264			if (e.type === 'mouseup' || e.type === 'click') {
9265				if (options.onClick) {
9266					// Use e.native here for backwards compatibility
9267					options.onClick.call(me, e.native, me.active);
9268				}
9269			}
9270
9271			// Remove styling for last active (even if it may still be active)
9272			if (me.lastActive.length) {
9273				me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
9274			}
9275
9276			// Built in hover styling
9277			if (me.active.length && hoverOptions.mode) {
9278				me.updateHoverStyle(me.active, hoverOptions.mode, true);
9279			}
9280
9281			changed = !helpers.arrayEquals(me.active, me.lastActive);
9282
9283			// Remember Last Actives
9284			me.lastActive = me.active;
9285
9286			return changed;
9287		}
9288	});
9289
9290	/**
9291	 * Provided for backward compatibility, use Chart instead.
9292	 * @class Chart.Controller
9293	 * @deprecated since version 2.6.0
9294	 * @todo remove at version 3
9295	 * @private
9296	 */
9297	Chart.Controller = Chart;
9298};
9299
9300},{"25":25,"28":28,"30":30,"31":31,"45":45,"48":48}],24:[function(require,module,exports){
9301'use strict';
9302
9303var helpers = require(45);
9304
9305module.exports = function(Chart) {
9306
9307	var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
9308
9309	/**
9310	 * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
9311	 * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
9312	 * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
9313	 */
9314	function listenArrayEvents(array, listener) {
9315		if (array._chartjs) {
9316			array._chartjs.listeners.push(listener);
9317			return;
9318		}
9319
9320		Object.defineProperty(array, '_chartjs', {
9321			configurable: true,
9322			enumerable: false,
9323			value: {
9324				listeners: [listener]
9325			}
9326		});
9327
9328		arrayEvents.forEach(function(key) {
9329			var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
9330			var base = array[key];
9331
9332			Object.defineProperty(array, key, {
9333				configurable: true,
9334				enumerable: false,
9335				value: function() {
9336					var args = Array.prototype.slice.call(arguments);
9337					var res = base.apply(this, args);
9338
9339					helpers.each(array._chartjs.listeners, function(object) {
9340						if (typeof object[method] === 'function') {
9341							object[method].apply(object, args);
9342						}
9343					});
9344
9345					return res;
9346				}
9347			});
9348		});
9349	}
9350
9351	/**
9352	 * Removes the given array event listener and cleanup extra attached properties (such as
9353	 * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
9354	 */
9355	function unlistenArrayEvents(array, listener) {
9356		var stub = array._chartjs;
9357		if (!stub) {
9358			return;
9359		}
9360
9361		var listeners = stub.listeners;
9362		var index = listeners.indexOf(listener);
9363		if (index !== -1) {
9364			listeners.splice(index, 1);
9365		}
9366
9367		if (listeners.length > 0) {
9368			return;
9369		}
9370
9371		arrayEvents.forEach(function(key) {
9372			delete array[key];
9373		});
9374
9375		delete array._chartjs;
9376	}
9377
9378	// Base class for all dataset controllers (line, bar, etc)
9379	Chart.DatasetController = function(chart, datasetIndex) {
9380		this.initialize(chart, datasetIndex);
9381	};
9382
9383	helpers.extend(Chart.DatasetController.prototype, {
9384
9385		/**
9386		 * Element type used to generate a meta dataset (e.g. Chart.element.Line).
9387		 * @type {Chart.core.element}
9388		 */
9389		datasetElementType: null,
9390
9391		/**
9392		 * Element type used to generate a meta data (e.g. Chart.element.Point).
9393		 * @type {Chart.core.element}
9394		 */
9395		dataElementType: null,
9396
9397		initialize: function(chart, datasetIndex) {
9398			var me = this;
9399			me.chart = chart;
9400			me.index = datasetIndex;
9401			me.linkScales();
9402			me.addElements();
9403		},
9404
9405		updateIndex: function(datasetIndex) {
9406			this.index = datasetIndex;
9407		},
9408
9409		linkScales: function() {
9410			var me = this;
9411			var meta = me.getMeta();
9412			var dataset = me.getDataset();
9413
9414			if (meta.xAxisID === null || !(meta.xAxisID in me.chart.scales)) {
9415				meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
9416			}
9417			if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) {
9418				meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
9419			}
9420		},
9421
9422		getDataset: function() {
9423			return this.chart.data.datasets[this.index];
9424		},
9425
9426		getMeta: function() {
9427			return this.chart.getDatasetMeta(this.index);
9428		},
9429
9430		getScaleForId: function(scaleID) {
9431			return this.chart.scales[scaleID];
9432		},
9433
9434		reset: function() {
9435			this.update(true);
9436		},
9437
9438		/**
9439		 * @private
9440		 */
9441		destroy: function() {
9442			if (this._data) {
9443				unlistenArrayEvents(this._data, this);
9444			}
9445		},
9446
9447		createMetaDataset: function() {
9448			var me = this;
9449			var type = me.datasetElementType;
9450			return type && new type({
9451				_chart: me.chart,
9452				_datasetIndex: me.index
9453			});
9454		},
9455
9456		createMetaData: function(index) {
9457			var me = this;
9458			var type = me.dataElementType;
9459			return type && new type({
9460				_chart: me.chart,
9461				_datasetIndex: me.index,
9462				_index: index
9463			});
9464		},
9465
9466		addElements: function() {
9467			var me = this;
9468			var meta = me.getMeta();
9469			var data = me.getDataset().data || [];
9470			var metaData = meta.data;
9471			var i, ilen;
9472
9473			for (i = 0, ilen = data.length; i < ilen; ++i) {
9474				metaData[i] = metaData[i] || me.createMetaData(i);
9475			}
9476
9477			meta.dataset = meta.dataset || me.createMetaDataset();
9478		},
9479
9480		addElementAndReset: function(index) {
9481			var element = this.createMetaData(index);
9482			this.getMeta().data.splice(index, 0, element);
9483			this.updateElement(element, index, true);
9484		},
9485
9486		buildOrUpdateElements: function() {
9487			var me = this;
9488			var dataset = me.getDataset();
9489			var data = dataset.data || (dataset.data = []);
9490
9491			// In order to correctly handle data addition/deletion animation (an thus simulate
9492			// real-time charts), we need to monitor these data modifications and synchronize
9493			// the internal meta data accordingly.
9494			if (me._data !== data) {
9495				if (me._data) {
9496					// This case happens when the user replaced the data array instance.
9497					unlistenArrayEvents(me._data, me);
9498				}
9499
9500				listenArrayEvents(data, me);
9501				me._data = data;
9502			}
9503
9504			// Re-sync meta data in case the user replaced the data array or if we missed
9505			// any updates and so make sure that we handle number of datapoints changing.
9506			me.resyncElements();
9507		},
9508
9509		update: helpers.noop,
9510
9511		transition: function(easingValue) {
9512			var meta = this.getMeta();
9513			var elements = meta.data || [];
9514			var ilen = elements.length;
9515			var i = 0;
9516
9517			for (; i < ilen; ++i) {
9518				elements[i].transition(easingValue);
9519			}
9520
9521			if (meta.dataset) {
9522				meta.dataset.transition(easingValue);
9523			}
9524		},
9525
9526		draw: function() {
9527			var meta = this.getMeta();
9528			var elements = meta.data || [];
9529			var ilen = elements.length;
9530			var i = 0;
9531
9532			if (meta.dataset) {
9533				meta.dataset.draw();
9534			}
9535
9536			for (; i < ilen; ++i) {
9537				elements[i].draw();
9538			}
9539		},
9540
9541		removeHoverStyle: function(element, elementOpts) {
9542			var dataset = this.chart.data.datasets[element._datasetIndex];
9543			var index = element._index;
9544			var custom = element.custom || {};
9545			var valueOrDefault = helpers.valueAtIndexOrDefault;
9546			var model = element._model;
9547
9548			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
9549			model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
9550			model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
9551		},
9552
9553		setHoverStyle: function(element) {
9554			var dataset = this.chart.data.datasets[element._datasetIndex];
9555			var index = element._index;
9556			var custom = element.custom || {};
9557			var valueOrDefault = helpers.valueAtIndexOrDefault;
9558			var getHoverColor = helpers.getHoverColor;
9559			var model = element._model;
9560
9561			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
9562			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
9563			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
9564		},
9565
9566		/**
9567		 * @private
9568		 */
9569		resyncElements: function() {
9570			var me = this;
9571			var meta = me.getMeta();
9572			var data = me.getDataset().data;
9573			var numMeta = meta.data.length;
9574			var numData = data.length;
9575
9576			if (numData < numMeta) {
9577				meta.data.splice(numData, numMeta - numData);
9578			} else if (numData > numMeta) {
9579				me.insertElements(numMeta, numData - numMeta);
9580			}
9581		},
9582
9583		/**
9584		 * @private
9585		 */
9586		insertElements: function(start, count) {
9587			for (var i = 0; i < count; ++i) {
9588				this.addElementAndReset(start + i);
9589			}
9590		},
9591
9592		/**
9593		 * @private
9594		 */
9595		onDataPush: function() {
9596			this.insertElements(this.getDataset().data.length - 1, arguments.length);
9597		},
9598
9599		/**
9600		 * @private
9601		 */
9602		onDataPop: function() {
9603			this.getMeta().data.pop();
9604		},
9605
9606		/**
9607		 * @private
9608		 */
9609		onDataShift: function() {
9610			this.getMeta().data.shift();
9611		},
9612
9613		/**
9614		 * @private
9615		 */
9616		onDataSplice: function(start, count) {
9617			this.getMeta().data.splice(start, count);
9618			this.insertElements(start, arguments.length - 2);
9619		},
9620
9621		/**
9622		 * @private
9623		 */
9624		onDataUnshift: function() {
9625			this.insertElements(0, arguments.length);
9626		}
9627	});
9628
9629	Chart.DatasetController.extend = helpers.inherits;
9630};
9631
9632},{"45":45}],25:[function(require,module,exports){
9633'use strict';
9634
9635var helpers = require(45);
9636
9637module.exports = {
9638	/**
9639	 * @private
9640	 */
9641	_set: function(scope, values) {
9642		return helpers.merge(this[scope] || (this[scope] = {}), values);
9643	}
9644};
9645
9646},{"45":45}],26:[function(require,module,exports){
9647'use strict';
9648
9649var color = require(2);
9650var helpers = require(45);
9651
9652function interpolate(start, view, model, ease) {
9653	var keys = Object.keys(model);
9654	var i, ilen, key, actual, origin, target, type, c0, c1;
9655
9656	for (i = 0, ilen = keys.length; i < ilen; ++i) {
9657		key = keys[i];
9658
9659		target = model[key];
9660
9661		// if a value is added to the model after pivot() has been called, the view
9662		// doesn't contain it, so let's initialize the view to the target value.
9663		if (!view.hasOwnProperty(key)) {
9664			view[key] = target;
9665		}
9666
9667		actual = view[key];
9668
9669		if (actual === target || key[0] === '_') {
9670			continue;
9671		}
9672
9673		if (!start.hasOwnProperty(key)) {
9674			start[key] = actual;
9675		}
9676
9677		origin = start[key];
9678
9679		type = typeof target;
9680
9681		if (type === typeof origin) {
9682			if (type === 'string') {
9683				c0 = color(origin);
9684				if (c0.valid) {
9685					c1 = color(target);
9686					if (c1.valid) {
9687						view[key] = c1.mix(c0, ease).rgbString();
9688						continue;
9689					}
9690				}
9691			} else if (type === 'number' && isFinite(origin) && isFinite(target)) {
9692				view[key] = origin + (target - origin) * ease;
9693				continue;
9694			}
9695		}
9696
9697		view[key] = target;
9698	}
9699}
9700
9701var Element = function(configuration) {
9702	helpers.extend(this, configuration);
9703	this.initialize.apply(this, arguments);
9704};
9705
9706helpers.extend(Element.prototype, {
9707
9708	initialize: function() {
9709		this.hidden = false;
9710	},
9711
9712	pivot: function() {
9713		var me = this;
9714		if (!me._view) {
9715			me._view = helpers.clone(me._model);
9716		}
9717		me._start = {};
9718		return me;
9719	},
9720
9721	transition: function(ease) {
9722		var me = this;
9723		var model = me._model;
9724		var start = me._start;
9725		var view = me._view;
9726
9727		// No animation -> No Transition
9728		if (!model || ease === 1) {
9729			me._view = model;
9730			me._start = null;
9731			return me;
9732		}
9733
9734		if (!view) {
9735			view = me._view = {};
9736		}
9737
9738		if (!start) {
9739			start = me._start = {};
9740		}
9741
9742		interpolate(start, view, model, ease);
9743
9744		return me;
9745	},
9746
9747	tooltipPosition: function() {
9748		return {
9749			x: this._model.x,
9750			y: this._model.y
9751		};
9752	},
9753
9754	hasValue: function() {
9755		return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
9756	}
9757});
9758
9759Element.extend = helpers.inherits;
9760
9761module.exports = Element;
9762
9763},{"2":2,"45":45}],27:[function(require,module,exports){
9764/* global window: false */
9765/* global document: false */
9766'use strict';
9767
9768var color = require(2);
9769var defaults = require(25);
9770var helpers = require(45);
9771
9772module.exports = function(Chart) {
9773
9774	// -- Basic js utility methods
9775
9776	helpers.configMerge = function(/* objects ... */) {
9777		return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
9778			merger: function(key, target, source, options) {
9779				var tval = target[key] || {};
9780				var sval = source[key];
9781
9782				if (key === 'scales') {
9783					// scale config merging is complex. Add our own function here for that
9784					target[key] = helpers.scaleMerge(tval, sval);
9785				} else if (key === 'scale') {
9786					// used in polar area & radar charts since there is only one scale
9787					target[key] = helpers.merge(tval, [Chart.scaleService.getScaleDefaults(sval.type), sval]);
9788				} else {
9789					helpers._merger(key, target, source, options);
9790				}
9791			}
9792		});
9793	};
9794
9795	helpers.scaleMerge = function(/* objects ... */) {
9796		return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
9797			merger: function(key, target, source, options) {
9798				if (key === 'xAxes' || key === 'yAxes') {
9799					var slen = source[key].length;
9800					var i, type, scale;
9801
9802					if (!target[key]) {
9803						target[key] = [];
9804					}
9805
9806					for (i = 0; i < slen; ++i) {
9807						scale = source[key][i];
9808						type = helpers.valueOrDefault(scale.type, key === 'xAxes' ? 'category' : 'linear');
9809
9810						if (i >= target[key].length) {
9811							target[key].push({});
9812						}
9813
9814						if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) {
9815							// new/untyped scale or type changed: let's apply the new defaults
9816							// then merge source scale to correctly overwrite the defaults.
9817							helpers.merge(target[key][i], [Chart.scaleService.getScaleDefaults(type), scale]);
9818						} else {
9819							// scales type are the same
9820							helpers.merge(target[key][i], scale);
9821						}
9822					}
9823				} else {
9824					helpers._merger(key, target, source, options);
9825				}
9826			}
9827		});
9828	};
9829
9830	helpers.where = function(collection, filterCallback) {
9831		if (helpers.isArray(collection) && Array.prototype.filter) {
9832			return collection.filter(filterCallback);
9833		}
9834		var filtered = [];
9835
9836		helpers.each(collection, function(item) {
9837			if (filterCallback(item)) {
9838				filtered.push(item);
9839			}
9840		});
9841
9842		return filtered;
9843	};
9844	helpers.findIndex = Array.prototype.findIndex ?
9845		function(array, callback, scope) {
9846			return array.findIndex(callback, scope);
9847		} :
9848		function(array, callback, scope) {
9849			scope = scope === undefined ? array : scope;
9850			for (var i = 0, ilen = array.length; i < ilen; ++i) {
9851				if (callback.call(scope, array[i], i, array)) {
9852					return i;
9853				}
9854			}
9855			return -1;
9856		};
9857	helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
9858		// Default to start of the array
9859		if (helpers.isNullOrUndef(startIndex)) {
9860			startIndex = -1;
9861		}
9862		for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
9863			var currentItem = arrayToSearch[i];
9864			if (filterCallback(currentItem)) {
9865				return currentItem;
9866			}
9867		}
9868	};
9869	helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
9870		// Default to end of the array
9871		if (helpers.isNullOrUndef(startIndex)) {
9872			startIndex = arrayToSearch.length;
9873		}
9874		for (var i = startIndex - 1; i >= 0; i--) {
9875			var currentItem = arrayToSearch[i];
9876			if (filterCallback(currentItem)) {
9877				return currentItem;
9878			}
9879		}
9880	};
9881
9882	// -- Math methods
9883	helpers.isNumber = function(n) {
9884		return !isNaN(parseFloat(n)) && isFinite(n);
9885	};
9886	helpers.almostEquals = function(x, y, epsilon) {
9887		return Math.abs(x - y) < epsilon;
9888	};
9889	helpers.almostWhole = function(x, epsilon) {
9890		var rounded = Math.round(x);
9891		return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
9892	};
9893	helpers.max = function(array) {
9894		return array.reduce(function(max, value) {
9895			if (!isNaN(value)) {
9896				return Math.max(max, value);
9897			}
9898			return max;
9899		}, Number.NEGATIVE_INFINITY);
9900	};
9901	helpers.min = function(array) {
9902		return array.reduce(function(min, value) {
9903			if (!isNaN(value)) {
9904				return Math.min(min, value);
9905			}
9906			return min;
9907		}, Number.POSITIVE_INFINITY);
9908	};
9909	helpers.sign = Math.sign ?
9910		function(x) {
9911			return Math.sign(x);
9912		} :
9913		function(x) {
9914			x = +x; // convert to a number
9915			if (x === 0 || isNaN(x)) {
9916				return x;
9917			}
9918			return x > 0 ? 1 : -1;
9919		};
9920	helpers.log10 = Math.log10 ?
9921		function(x) {
9922			return Math.log10(x);
9923		} :
9924		function(x) {
9925			var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
9926			// Check for whole powers of 10,
9927			// which due to floating point rounding error should be corrected.
9928			var powerOf10 = Math.round(exponent);
9929			var isPowerOf10 = x === Math.pow(10, powerOf10);
9930
9931			return isPowerOf10 ? powerOf10 : exponent;
9932		};
9933	helpers.toRadians = function(degrees) {
9934		return degrees * (Math.PI / 180);
9935	};
9936	helpers.toDegrees = function(radians) {
9937		return radians * (180 / Math.PI);
9938	};
9939	// Gets the angle from vertical upright to the point about a centre.
9940	helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
9941		var distanceFromXCenter = anglePoint.x - centrePoint.x;
9942		var distanceFromYCenter = anglePoint.y - centrePoint.y;
9943		var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
9944
9945		var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
9946
9947		if (angle < (-0.5 * Math.PI)) {
9948			angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
9949		}
9950
9951		return {
9952			angle: angle,
9953			distance: radialDistanceFromCenter
9954		};
9955	};
9956	helpers.distanceBetweenPoints = function(pt1, pt2) {
9957		return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
9958	};
9959	helpers.aliasPixel = function(pixelWidth) {
9960		return (pixelWidth % 2 === 0) ? 0 : 0.5;
9961	};
9962	helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
9963		// Props to Rob Spencer at scaled innovation for his post on splining between points
9964		// http://scaledinnovation.com/analytics/splines/aboutSplines.html
9965
9966		// This function must also respect "skipped" points
9967
9968		var previous = firstPoint.skip ? middlePoint : firstPoint;
9969		var current = middlePoint;
9970		var next = afterPoint.skip ? middlePoint : afterPoint;
9971
9972		var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
9973		var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
9974
9975		var s01 = d01 / (d01 + d12);
9976		var s12 = d12 / (d01 + d12);
9977
9978		// If all points are the same, s01 & s02 will be inf
9979		s01 = isNaN(s01) ? 0 : s01;
9980		s12 = isNaN(s12) ? 0 : s12;
9981
9982		var fa = t * s01; // scaling factor for triangle Ta
9983		var fb = t * s12;
9984
9985		return {
9986			previous: {
9987				x: current.x - fa * (next.x - previous.x),
9988				y: current.y - fa * (next.y - previous.y)
9989			},
9990			next: {
9991				x: current.x + fb * (next.x - previous.x),
9992				y: current.y + fb * (next.y - previous.y)
9993			}
9994		};
9995	};
9996	helpers.EPSILON = Number.EPSILON || 1e-14;
9997	helpers.splineCurveMonotone = function(points) {
9998		// This function calculates Bézier control points in a similar way than |splineCurve|,
9999		// but preserves monotonicity of the provided data and ensures no local extremums are added
10000		// between the dataset discrete points due to the interpolation.
10001		// See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
10002
10003		var pointsWithTangents = (points || []).map(function(point) {
10004			return {
10005				model: point._model,
10006				deltaK: 0,
10007				mK: 0
10008			};
10009		});
10010
10011		// Calculate slopes (deltaK) and initialize tangents (mK)
10012		var pointsLen = pointsWithTangents.length;
10013		var i, pointBefore, pointCurrent, pointAfter;
10014		for (i = 0; i < pointsLen; ++i) {
10015			pointCurrent = pointsWithTangents[i];
10016			if (pointCurrent.model.skip) {
10017				continue;
10018			}
10019
10020			pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
10021			pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
10022			if (pointAfter && !pointAfter.model.skip) {
10023				var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
10024
10025				// In the case of two points that appear at the same x pixel, slopeDeltaX is 0
10026				pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
10027			}
10028
10029			if (!pointBefore || pointBefore.model.skip) {
10030				pointCurrent.mK = pointCurrent.deltaK;
10031			} else if (!pointAfter || pointAfter.model.skip) {
10032				pointCurrent.mK = pointBefore.deltaK;
10033			} else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
10034				pointCurrent.mK = 0;
10035			} else {
10036				pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
10037			}
10038		}
10039
10040		// Adjust tangents to ensure monotonic properties
10041		var alphaK, betaK, tauK, squaredMagnitude;
10042		for (i = 0; i < pointsLen - 1; ++i) {
10043			pointCurrent = pointsWithTangents[i];
10044			pointAfter = pointsWithTangents[i + 1];
10045			if (pointCurrent.model.skip || pointAfter.model.skip) {
10046				continue;
10047			}
10048
10049			if (helpers.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
10050				pointCurrent.mK = pointAfter.mK = 0;
10051				continue;
10052			}
10053
10054			alphaK = pointCurrent.mK / pointCurrent.deltaK;
10055			betaK = pointAfter.mK / pointCurrent.deltaK;
10056			squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
10057			if (squaredMagnitude <= 9) {
10058				continue;
10059			}
10060
10061			tauK = 3 / Math.sqrt(squaredMagnitude);
10062			pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
10063			pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
10064		}
10065
10066		// Compute control points
10067		var deltaX;
10068		for (i = 0; i < pointsLen; ++i) {
10069			pointCurrent = pointsWithTangents[i];
10070			if (pointCurrent.model.skip) {
10071				continue;
10072			}
10073
10074			pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
10075			pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
10076			if (pointBefore && !pointBefore.model.skip) {
10077				deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
10078				pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
10079				pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
10080			}
10081			if (pointAfter && !pointAfter.model.skip) {
10082				deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
10083				pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
10084				pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
10085			}
10086		}
10087	};
10088	helpers.nextItem = function(collection, index, loop) {
10089		if (loop) {
10090			return index >= collection.length - 1 ? collection[0] : collection[index + 1];
10091		}
10092		return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
10093	};
10094	helpers.previousItem = function(collection, index, loop) {
10095		if (loop) {
10096			return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
10097		}
10098		return index <= 0 ? collection[0] : collection[index - 1];
10099	};
10100	// Implementation of the nice number algorithm used in determining where axis labels will go
10101	helpers.niceNum = function(range, round) {
10102		var exponent = Math.floor(helpers.log10(range));
10103		var fraction = range / Math.pow(10, exponent);
10104		var niceFraction;
10105
10106		if (round) {
10107			if (fraction < 1.5) {
10108				niceFraction = 1;
10109			} else if (fraction < 3) {
10110				niceFraction = 2;
10111			} else if (fraction < 7) {
10112				niceFraction = 5;
10113			} else {
10114				niceFraction = 10;
10115			}
10116		} else if (fraction <= 1.0) {
10117			niceFraction = 1;
10118		} else if (fraction <= 2) {
10119			niceFraction = 2;
10120		} else if (fraction <= 5) {
10121			niceFraction = 5;
10122		} else {
10123			niceFraction = 10;
10124		}
10125
10126		return niceFraction * Math.pow(10, exponent);
10127	};
10128	// Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
10129	helpers.requestAnimFrame = (function() {
10130		if (typeof window === 'undefined') {
10131			return function(callback) {
10132				callback();
10133			};
10134		}
10135		return window.requestAnimationFrame ||
10136			window.webkitRequestAnimationFrame ||
10137			window.mozRequestAnimationFrame ||
10138			window.oRequestAnimationFrame ||
10139			window.msRequestAnimationFrame ||
10140			function(callback) {
10141				return window.setTimeout(callback, 1000 / 60);
10142			};
10143	}());
10144	// -- DOM methods
10145	helpers.getRelativePosition = function(evt, chart) {
10146		var mouseX, mouseY;
10147		var e = evt.originalEvent || evt;
10148		var canvas = evt.currentTarget || evt.srcElement;
10149		var boundingRect = canvas.getBoundingClientRect();
10150
10151		var touches = e.touches;
10152		if (touches && touches.length > 0) {
10153			mouseX = touches[0].clientX;
10154			mouseY = touches[0].clientY;
10155
10156		} else {
10157			mouseX = e.clientX;
10158			mouseY = e.clientY;
10159		}
10160
10161		// Scale mouse coordinates into canvas coordinates
10162		// by following the pattern laid out by 'jerryj' in the comments of
10163		// http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
10164		var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
10165		var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
10166		var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
10167		var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
10168		var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
10169		var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
10170
10171		// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
10172		// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
10173		mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
10174		mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
10175
10176		return {
10177			x: mouseX,
10178			y: mouseY
10179		};
10180
10181	};
10182
10183	// Private helper function to convert max-width/max-height values that may be percentages into a number
10184	function parseMaxStyle(styleValue, node, parentProperty) {
10185		var valueInPixels;
10186		if (typeof styleValue === 'string') {
10187			valueInPixels = parseInt(styleValue, 10);
10188
10189			if (styleValue.indexOf('%') !== -1) {
10190				// percentage * size in dimension
10191				valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
10192			}
10193		} else {
10194			valueInPixels = styleValue;
10195		}
10196
10197		return valueInPixels;
10198	}
10199
10200	/**
10201	 * Returns if the given value contains an effective constraint.
10202	 * @private
10203	 */
10204	function isConstrainedValue(value) {
10205		return value !== undefined && value !== null && value !== 'none';
10206	}
10207
10208	// Private helper to get a constraint dimension
10209	// @param domNode : the node to check the constraint on
10210	// @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
10211	// @param percentageProperty : property of parent to use when calculating width as a percentage
10212	// @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
10213	function getConstraintDimension(domNode, maxStyle, percentageProperty) {
10214		var view = document.defaultView;
10215		var parentNode = domNode.parentNode;
10216		var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
10217		var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
10218		var hasCNode = isConstrainedValue(constrainedNode);
10219		var hasCContainer = isConstrainedValue(constrainedContainer);
10220		var infinity = Number.POSITIVE_INFINITY;
10221
10222		if (hasCNode || hasCContainer) {
10223			return Math.min(
10224				hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
10225				hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
10226		}
10227
10228		return 'none';
10229	}
10230	// returns Number or undefined if no constraint
10231	helpers.getConstraintWidth = function(domNode) {
10232		return getConstraintDimension(domNode, 'max-width', 'clientWidth');
10233	};
10234	// returns Number or undefined if no constraint
10235	helpers.getConstraintHeight = function(domNode) {
10236		return getConstraintDimension(domNode, 'max-height', 'clientHeight');
10237	};
10238	helpers.getMaximumWidth = function(domNode) {
10239		var container = domNode.parentNode;
10240		if (!container) {
10241			return domNode.clientWidth;
10242		}
10243
10244		var paddingLeft = parseInt(helpers.getStyle(container, 'padding-left'), 10);
10245		var paddingRight = parseInt(helpers.getStyle(container, 'padding-right'), 10);
10246		var w = container.clientWidth - paddingLeft - paddingRight;
10247		var cw = helpers.getConstraintWidth(domNode);
10248		return isNaN(cw) ? w : Math.min(w, cw);
10249	};
10250	helpers.getMaximumHeight = function(domNode) {
10251		var container = domNode.parentNode;
10252		if (!container) {
10253			return domNode.clientHeight;
10254		}
10255
10256		var paddingTop = parseInt(helpers.getStyle(container, 'padding-top'), 10);
10257		var paddingBottom = parseInt(helpers.getStyle(container, 'padding-bottom'), 10);
10258		var h = container.clientHeight - paddingTop - paddingBottom;
10259		var ch = helpers.getConstraintHeight(domNode);
10260		return isNaN(ch) ? h : Math.min(h, ch);
10261	};
10262	helpers.getStyle = function(el, property) {
10263		return el.currentStyle ?
10264			el.currentStyle[property] :
10265			document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
10266	};
10267	helpers.retinaScale = function(chart, forceRatio) {
10268		var pixelRatio = chart.currentDevicePixelRatio = forceRatio || window.devicePixelRatio || 1;
10269		if (pixelRatio === 1) {
10270			return;
10271		}
10272
10273		var canvas = chart.canvas;
10274		var height = chart.height;
10275		var width = chart.width;
10276
10277		canvas.height = height * pixelRatio;
10278		canvas.width = width * pixelRatio;
10279		chart.ctx.scale(pixelRatio, pixelRatio);
10280
10281		// If no style has been set on the canvas, the render size is used as display size,
10282		// making the chart visually bigger, so let's enforce it to the "correct" values.
10283		// See https://github.com/chartjs/Chart.js/issues/3575
10284		if (!canvas.style.height && !canvas.style.width) {
10285			canvas.style.height = height + 'px';
10286			canvas.style.width = width + 'px';
10287		}
10288	};
10289	// -- Canvas methods
10290	helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
10291		return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
10292	};
10293	helpers.longestText = function(ctx, font, arrayOfThings, cache) {
10294		cache = cache || {};
10295		var data = cache.data = cache.data || {};
10296		var gc = cache.garbageCollect = cache.garbageCollect || [];
10297
10298		if (cache.font !== font) {
10299			data = cache.data = {};
10300			gc = cache.garbageCollect = [];
10301			cache.font = font;
10302		}
10303
10304		ctx.font = font;
10305		var longest = 0;
10306		helpers.each(arrayOfThings, function(thing) {
10307			// Undefined strings and arrays should not be measured
10308			if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
10309				longest = helpers.measureText(ctx, data, gc, longest, thing);
10310			} else if (helpers.isArray(thing)) {
10311				// if it is an array lets measure each element
10312				// to do maybe simplify this function a bit so we can do this more recursively?
10313				helpers.each(thing, function(nestedThing) {
10314					// Undefined strings and arrays should not be measured
10315					if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
10316						longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
10317					}
10318				});
10319			}
10320		});
10321
10322		var gcLen = gc.length / 2;
10323		if (gcLen > arrayOfThings.length) {
10324			for (var i = 0; i < gcLen; i++) {
10325				delete data[gc[i]];
10326			}
10327			gc.splice(0, gcLen);
10328		}
10329		return longest;
10330	};
10331	helpers.measureText = function(ctx, data, gc, longest, string) {
10332		var textWidth = data[string];
10333		if (!textWidth) {
10334			textWidth = data[string] = ctx.measureText(string).width;
10335			gc.push(string);
10336		}
10337		if (textWidth > longest) {
10338			longest = textWidth;
10339		}
10340		return longest;
10341	};
10342	helpers.numberOfLabelLines = function(arrayOfThings) {
10343		var numberOfLines = 1;
10344		helpers.each(arrayOfThings, function(thing) {
10345			if (helpers.isArray(thing)) {
10346				if (thing.length > numberOfLines) {
10347					numberOfLines = thing.length;
10348				}
10349			}
10350		});
10351		return numberOfLines;
10352	};
10353
10354	helpers.color = !color ?
10355		function(value) {
10356			console.error('Color.js not found!');
10357			return value;
10358		} :
10359		function(value) {
10360			/* global CanvasGradient */
10361			if (value instanceof CanvasGradient) {
10362				value = defaults.global.defaultColor;
10363			}
10364
10365			return color(value);
10366		};
10367
10368	helpers.getHoverColor = function(colorValue) {
10369		/* global CanvasPattern */
10370		return (colorValue instanceof CanvasPattern) ?
10371			colorValue :
10372			helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
10373	};
10374};
10375
10376},{"2":2,"25":25,"45":45}],28:[function(require,module,exports){
10377'use strict';
10378
10379var helpers = require(45);
10380
10381/**
10382 * Helper function to get relative position for an event
10383 * @param {Event|IEvent} event - The event to get the position for
10384 * @param {Chart} chart - The chart
10385 * @returns {Point} the event position
10386 */
10387function getRelativePosition(e, chart) {
10388	if (e.native) {
10389		return {
10390			x: e.x,
10391			y: e.y
10392		};
10393	}
10394
10395	return helpers.getRelativePosition(e, chart);
10396}
10397
10398/**
10399 * Helper function to traverse all of the visible elements in the chart
10400 * @param chart {chart} the chart
10401 * @param handler {Function} the callback to execute for each visible item
10402 */
10403function parseVisibleItems(chart, handler) {
10404	var datasets = chart.data.datasets;
10405	var meta, i, j, ilen, jlen;
10406
10407	for (i = 0, ilen = datasets.length; i < ilen; ++i) {
10408		if (!chart.isDatasetVisible(i)) {
10409			continue;
10410		}
10411
10412		meta = chart.getDatasetMeta(i);
10413		for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
10414			var element = meta.data[j];
10415			if (!element._view.skip) {
10416				handler(element);
10417			}
10418		}
10419	}
10420}
10421
10422/**
10423 * Helper function to get the items that intersect the event position
10424 * @param items {ChartElement[]} elements to filter
10425 * @param position {Point} the point to be nearest to
10426 * @return {ChartElement[]} the nearest items
10427 */
10428function getIntersectItems(chart, position) {
10429	var elements = [];
10430
10431	parseVisibleItems(chart, function(element) {
10432		if (element.inRange(position.x, position.y)) {
10433			elements.push(element);
10434		}
10435	});
10436
10437	return elements;
10438}
10439
10440/**
10441 * Helper function to get the items nearest to the event position considering all visible items in teh chart
10442 * @param chart {Chart} the chart to look at elements from
10443 * @param position {Point} the point to be nearest to
10444 * @param intersect {Boolean} if true, only consider items that intersect the position
10445 * @param distanceMetric {Function} function to provide the distance between points
10446 * @return {ChartElement[]} the nearest items
10447 */
10448function getNearestItems(chart, position, intersect, distanceMetric) {
10449	var minDistance = Number.POSITIVE_INFINITY;
10450	var nearestItems = [];
10451
10452	parseVisibleItems(chart, function(element) {
10453		if (intersect && !element.inRange(position.x, position.y)) {
10454			return;
10455		}
10456
10457		var center = element.getCenterPoint();
10458		var distance = distanceMetric(position, center);
10459
10460		if (distance < minDistance) {
10461			nearestItems = [element];
10462			minDistance = distance;
10463		} else if (distance === minDistance) {
10464			// Can have multiple items at the same distance in which case we sort by size
10465			nearestItems.push(element);
10466		}
10467	});
10468
10469	return nearestItems;
10470}
10471
10472/**
10473 * Get a distance metric function for two points based on the
10474 * axis mode setting
10475 * @param {String} axis the axis mode. x|y|xy
10476 */
10477function getDistanceMetricForAxis(axis) {
10478	var useX = axis.indexOf('x') !== -1;
10479	var useY = axis.indexOf('y') !== -1;
10480
10481	return function(pt1, pt2) {
10482		var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
10483		var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
10484		return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
10485	};
10486}
10487
10488function indexMode(chart, e, options) {
10489	var position = getRelativePosition(e, chart);
10490	// Default axis for index mode is 'x' to match old behaviour
10491	options.axis = options.axis || 'x';
10492	var distanceMetric = getDistanceMetricForAxis(options.axis);
10493	var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
10494	var elements = [];
10495
10496	if (!items.length) {
10497		return [];
10498	}
10499
10500	chart.data.datasets.forEach(function(dataset, datasetIndex) {
10501		if (chart.isDatasetVisible(datasetIndex)) {
10502			var meta = chart.getDatasetMeta(datasetIndex);
10503			var element = meta.data[items[0]._index];
10504
10505			// don't count items that are skipped (null data)
10506			if (element && !element._view.skip) {
10507				elements.push(element);
10508			}
10509		}
10510	});
10511
10512	return elements;
10513}
10514
10515/**
10516 * @interface IInteractionOptions
10517 */
10518/**
10519 * If true, only consider items that intersect the point
10520 * @name IInterfaceOptions#boolean
10521 * @type Boolean
10522 */
10523
10524/**
10525 * Contains interaction related functions
10526 * @namespace Chart.Interaction
10527 */
10528module.exports = {
10529	// Helper function for different modes
10530	modes: {
10531		single: function(chart, e) {
10532			var position = getRelativePosition(e, chart);
10533			var elements = [];
10534
10535			parseVisibleItems(chart, function(element) {
10536				if (element.inRange(position.x, position.y)) {
10537					elements.push(element);
10538					return elements;
10539				}
10540			});
10541
10542			return elements.slice(0, 1);
10543		},
10544
10545		/**
10546		 * @function Chart.Interaction.modes.label
10547		 * @deprecated since version 2.4.0
10548		 * @todo remove at version 3
10549		 * @private
10550		 */
10551		label: indexMode,
10552
10553		/**
10554		 * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
10555		 * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
10556		 * @function Chart.Interaction.modes.index
10557		 * @since v2.4.0
10558		 * @param chart {chart} the chart we are returning items from
10559		 * @param e {Event} the event we are find things at
10560		 * @param options {IInteractionOptions} options to use during interaction
10561		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10562		 */
10563		index: indexMode,
10564
10565		/**
10566		 * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
10567		 * If the options.intersect is false, we find the nearest item and return the items in that dataset
10568		 * @function Chart.Interaction.modes.dataset
10569		 * @param chart {chart} the chart we are returning items from
10570		 * @param e {Event} the event we are find things at
10571		 * @param options {IInteractionOptions} options to use during interaction
10572		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10573		 */
10574		dataset: function(chart, e, options) {
10575			var position = getRelativePosition(e, chart);
10576			options.axis = options.axis || 'xy';
10577			var distanceMetric = getDistanceMetricForAxis(options.axis);
10578			var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
10579
10580			if (items.length > 0) {
10581				items = chart.getDatasetMeta(items[0]._datasetIndex).data;
10582			}
10583
10584			return items;
10585		},
10586
10587		/**
10588		 * @function Chart.Interaction.modes.x-axis
10589		 * @deprecated since version 2.4.0. Use index mode and intersect == true
10590		 * @todo remove at version 3
10591		 * @private
10592		 */
10593		'x-axis': function(chart, e) {
10594			return indexMode(chart, e, {intersect: false});
10595		},
10596
10597		/**
10598		 * Point mode returns all elements that hit test based on the event position
10599		 * of the event
10600		 * @function Chart.Interaction.modes.intersect
10601		 * @param chart {chart} the chart we are returning items from
10602		 * @param e {Event} the event we are find things at
10603		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10604		 */
10605		point: function(chart, e) {
10606			var position = getRelativePosition(e, chart);
10607			return getIntersectItems(chart, position);
10608		},
10609
10610		/**
10611		 * nearest mode returns the element closest to the point
10612		 * @function Chart.Interaction.modes.intersect
10613		 * @param chart {chart} the chart we are returning items from
10614		 * @param e {Event} the event we are find things at
10615		 * @param options {IInteractionOptions} options to use
10616		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10617		 */
10618		nearest: function(chart, e, options) {
10619			var position = getRelativePosition(e, chart);
10620			options.axis = options.axis || 'xy';
10621			var distanceMetric = getDistanceMetricForAxis(options.axis);
10622			var nearestItems = getNearestItems(chart, position, options.intersect, distanceMetric);
10623
10624			// We have multiple items at the same distance from the event. Now sort by smallest
10625			if (nearestItems.length > 1) {
10626				nearestItems.sort(function(a, b) {
10627					var sizeA = a.getArea();
10628					var sizeB = b.getArea();
10629					var ret = sizeA - sizeB;
10630
10631					if (ret === 0) {
10632						// if equal sort by dataset index
10633						ret = a._datasetIndex - b._datasetIndex;
10634					}
10635
10636					return ret;
10637				});
10638			}
10639
10640			// Return only 1 item
10641			return nearestItems.slice(0, 1);
10642		},
10643
10644		/**
10645		 * x mode returns the elements that hit-test at the current x coordinate
10646		 * @function Chart.Interaction.modes.x
10647		 * @param chart {chart} the chart we are returning items from
10648		 * @param e {Event} the event we are find things at
10649		 * @param options {IInteractionOptions} options to use
10650		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10651		 */
10652		x: function(chart, e, options) {
10653			var position = getRelativePosition(e, chart);
10654			var items = [];
10655			var intersectsItem = false;
10656
10657			parseVisibleItems(chart, function(element) {
10658				if (element.inXRange(position.x)) {
10659					items.push(element);
10660				}
10661
10662				if (element.inRange(position.x, position.y)) {
10663					intersectsItem = true;
10664				}
10665			});
10666
10667			// If we want to trigger on an intersect and we don't have any items
10668			// that intersect the position, return nothing
10669			if (options.intersect && !intersectsItem) {
10670				items = [];
10671			}
10672			return items;
10673		},
10674
10675		/**
10676		 * y mode returns the elements that hit-test at the current y coordinate
10677		 * @function Chart.Interaction.modes.y
10678		 * @param chart {chart} the chart we are returning items from
10679		 * @param e {Event} the event we are find things at
10680		 * @param options {IInteractionOptions} options to use
10681		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10682		 */
10683		y: function(chart, e, options) {
10684			var position = getRelativePosition(e, chart);
10685			var items = [];
10686			var intersectsItem = false;
10687
10688			parseVisibleItems(chart, function(element) {
10689				if (element.inYRange(position.y)) {
10690					items.push(element);
10691				}
10692
10693				if (element.inRange(position.x, position.y)) {
10694					intersectsItem = true;
10695				}
10696			});
10697
10698			// If we want to trigger on an intersect and we don't have any items
10699			// that intersect the position, return nothing
10700			if (options.intersect && !intersectsItem) {
10701				items = [];
10702			}
10703			return items;
10704		}
10705	}
10706};
10707
10708},{"45":45}],29:[function(require,module,exports){
10709'use strict';
10710
10711var defaults = require(25);
10712
10713defaults._set('global', {
10714	responsive: true,
10715	responsiveAnimationDuration: 0,
10716	maintainAspectRatio: true,
10717	events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
10718	hover: {
10719		onHover: null,
10720		mode: 'nearest',
10721		intersect: true,
10722		animationDuration: 400
10723	},
10724	onClick: null,
10725	defaultColor: 'rgba(0,0,0,0.1)',
10726	defaultFontColor: '#666',
10727	defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
10728	defaultFontSize: 12,
10729	defaultFontStyle: 'normal',
10730	showLines: true,
10731
10732	// Element defaults defined in element extensions
10733	elements: {},
10734
10735	// Layout options such as padding
10736	layout: {
10737		padding: {
10738			top: 0,
10739			right: 0,
10740			bottom: 0,
10741			left: 0
10742		}
10743	}
10744});
10745
10746module.exports = function() {
10747
10748	// Occupy the global variable of Chart, and create a simple base class
10749	var Chart = function(item, config) {
10750		this.construct(item, config);
10751		return this;
10752	};
10753
10754	Chart.Chart = Chart;
10755
10756	return Chart;
10757};
10758
10759},{"25":25}],30:[function(require,module,exports){
10760'use strict';
10761
10762var helpers = require(45);
10763
10764function filterByPosition(array, position) {
10765	return helpers.where(array, function(v) {
10766		return v.position === position;
10767	});
10768}
10769
10770function sortByWeight(array, reverse) {
10771	array.forEach(function(v, i) {
10772		v._tmpIndex_ = i;
10773		return v;
10774	});
10775	array.sort(function(a, b) {
10776		var v0 = reverse ? b : a;
10777		var v1 = reverse ? a : b;
10778		return v0.weight === v1.weight ?
10779			v0._tmpIndex_ - v1._tmpIndex_ :
10780			v0.weight - v1.weight;
10781	});
10782	array.forEach(function(v) {
10783		delete v._tmpIndex_;
10784	});
10785}
10786
10787/**
10788 * @interface ILayoutItem
10789 * @prop {String} position - The position of the item in the chart layout. Possible values are
10790 * 'left', 'top', 'right', 'bottom', and 'chartArea'
10791 * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
10792 * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
10793 * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
10794 * @prop {Function} update - Takes two parameters: width and height. Returns size of item
10795 * @prop {Function} getPadding -  Returns an object with padding on the edges
10796 * @prop {Number} width - Width of item. Must be valid after update()
10797 * @prop {Number} height - Height of item. Must be valid after update()
10798 * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
10799 * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
10800 * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
10801 * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
10802 */
10803
10804// The layout service is very self explanatory.  It's responsible for the layout within a chart.
10805// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
10806// It is this service's responsibility of carrying out that layout.
10807module.exports = {
10808	defaults: {},
10809
10810	/**
10811	 * Register a box to a chart.
10812	 * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
10813	 * @param {Chart} chart - the chart to use
10814	 * @param {ILayoutItem} item - the item to add to be layed out
10815	 */
10816	addBox: function(chart, item) {
10817		if (!chart.boxes) {
10818			chart.boxes = [];
10819		}
10820
10821		// initialize item with default values
10822		item.fullWidth = item.fullWidth || false;
10823		item.position = item.position || 'top';
10824		item.weight = item.weight || 0;
10825
10826		chart.boxes.push(item);
10827	},
10828
10829	/**
10830	 * Remove a layoutItem from a chart
10831	 * @param {Chart} chart - the chart to remove the box from
10832	 * @param {Object} layoutItem - the item to remove from the layout
10833	 */
10834	removeBox: function(chart, layoutItem) {
10835		var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
10836		if (index !== -1) {
10837			chart.boxes.splice(index, 1);
10838		}
10839	},
10840
10841	/**
10842	 * Sets (or updates) options on the given `item`.
10843	 * @param {Chart} chart - the chart in which the item lives (or will be added to)
10844	 * @param {Object} item - the item to configure with the given options
10845	 * @param {Object} options - the new item options.
10846	 */
10847	configure: function(chart, item, options) {
10848		var props = ['fullWidth', 'position', 'weight'];
10849		var ilen = props.length;
10850		var i = 0;
10851		var prop;
10852
10853		for (; i < ilen; ++i) {
10854			prop = props[i];
10855			if (options.hasOwnProperty(prop)) {
10856				item[prop] = options[prop];
10857			}
10858		}
10859	},
10860
10861	/**
10862	 * Fits boxes of the given chart into the given size by having each box measure itself
10863	 * then running a fitting algorithm
10864	 * @param {Chart} chart - the chart
10865	 * @param {Number} width - the width to fit into
10866	 * @param {Number} height - the height to fit into
10867	 */
10868	update: function(chart, width, height) {
10869		if (!chart) {
10870			return;
10871		}
10872
10873		var layoutOptions = chart.options.layout || {};
10874		var padding = helpers.options.toPadding(layoutOptions.padding);
10875		var leftPadding = padding.left;
10876		var rightPadding = padding.right;
10877		var topPadding = padding.top;
10878		var bottomPadding = padding.bottom;
10879
10880		var leftBoxes = filterByPosition(chart.boxes, 'left');
10881		var rightBoxes = filterByPosition(chart.boxes, 'right');
10882		var topBoxes = filterByPosition(chart.boxes, 'top');
10883		var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
10884		var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');
10885
10886		// Sort boxes by weight. A higher weight is further away from the chart area
10887		sortByWeight(leftBoxes, true);
10888		sortByWeight(rightBoxes, false);
10889		sortByWeight(topBoxes, true);
10890		sortByWeight(bottomBoxes, false);
10891
10892		// Essentially we now have any number of boxes on each of the 4 sides.
10893		// Our canvas looks like the following.
10894		// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
10895		// B1 is the bottom axis
10896		// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
10897		// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
10898		// an error will be thrown.
10899		//
10900		// |----------------------------------------------------|
10901		// |                  T1 (Full Width)                   |
10902		// |----------------------------------------------------|
10903		// |    |    |                 T2                  |    |
10904		// |    |----|-------------------------------------|----|
10905		// |    |    | C1 |                           | C2 |    |
10906		// |    |    |----|                           |----|    |
10907		// |    |    |                                     |    |
10908		// | L1 | L2 |           ChartArea (C0)            | R1 |
10909		// |    |    |                                     |    |
10910		// |    |    |----|                           |----|    |
10911		// |    |    | C3 |                           | C4 |    |
10912		// |    |----|-------------------------------------|----|
10913		// |    |    |                 B1                  |    |
10914		// |----------------------------------------------------|
10915		// |                  B2 (Full Width)                   |
10916		// |----------------------------------------------------|
10917		//
10918		// What we do to find the best sizing, we do the following
10919		// 1. Determine the minimum size of the chart area.
10920		// 2. Split the remaining width equally between each vertical axis
10921		// 3. Split the remaining height equally between each horizontal axis
10922		// 4. Give each layout the maximum size it can be. The layout will return it's minimum size
10923		// 5. Adjust the sizes of each axis based on it's minimum reported size.
10924		// 6. Refit each axis
10925		// 7. Position each axis in the final location
10926		// 8. Tell the chart the final location of the chart area
10927		// 9. Tell any axes that overlay the chart area the positions of the chart area
10928
10929		// Step 1
10930		var chartWidth = width - leftPadding - rightPadding;
10931		var chartHeight = height - topPadding - bottomPadding;
10932		var chartAreaWidth = chartWidth / 2; // min 50%
10933		var chartAreaHeight = chartHeight / 2; // min 50%
10934
10935		// Step 2
10936		var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
10937
10938		// Step 3
10939		var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
10940
10941		// Step 4
10942		var maxChartAreaWidth = chartWidth;
10943		var maxChartAreaHeight = chartHeight;
10944		var minBoxSizes = [];
10945
10946		function getMinimumBoxSize(box) {
10947			var minSize;
10948			var isHorizontal = box.isHorizontal();
10949
10950			if (isHorizontal) {
10951				minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
10952				maxChartAreaHeight -= minSize.height;
10953			} else {
10954				minSize = box.update(verticalBoxWidth, maxChartAreaHeight);
10955				maxChartAreaWidth -= minSize.width;
10956			}
10957
10958			minBoxSizes.push({
10959				horizontal: isHorizontal,
10960				minSize: minSize,
10961				box: box,
10962			});
10963		}
10964
10965		helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
10966
10967		// If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
10968		var maxHorizontalLeftPadding = 0;
10969		var maxHorizontalRightPadding = 0;
10970		var maxVerticalTopPadding = 0;
10971		var maxVerticalBottomPadding = 0;
10972
10973		helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
10974			if (horizontalBox.getPadding) {
10975				var boxPadding = horizontalBox.getPadding();
10976				maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
10977				maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
10978			}
10979		});
10980
10981		helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
10982			if (verticalBox.getPadding) {
10983				var boxPadding = verticalBox.getPadding();
10984				maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
10985				maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
10986			}
10987		});
10988
10989		// At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
10990		// be if the axes are drawn at their minimum sizes.
10991		// Steps 5 & 6
10992		var totalLeftBoxesWidth = leftPadding;
10993		var totalRightBoxesWidth = rightPadding;
10994		var totalTopBoxesHeight = topPadding;
10995		var totalBottomBoxesHeight = bottomPadding;
10996
10997		// Function to fit a box
10998		function fitBox(box) {
10999			var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBox) {
11000				return minBox.box === box;
11001			});
11002
11003			if (minBoxSize) {
11004				if (box.isHorizontal()) {
11005					var scaleMargin = {
11006						left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
11007						right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
11008						top: 0,
11009						bottom: 0
11010					};
11011
11012					// Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
11013					// on the margin. Sometimes they need to increase in size slightly
11014					box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
11015				} else {
11016					box.update(minBoxSize.minSize.width, maxChartAreaHeight);
11017				}
11018			}
11019		}
11020
11021		// Update, and calculate the left and right margins for the horizontal boxes
11022		helpers.each(leftBoxes.concat(rightBoxes), fitBox);
11023
11024		helpers.each(leftBoxes, function(box) {
11025			totalLeftBoxesWidth += box.width;
11026		});
11027
11028		helpers.each(rightBoxes, function(box) {
11029			totalRightBoxesWidth += box.width;
11030		});
11031
11032		// Set the Left and Right margins for the horizontal boxes
11033		helpers.each(topBoxes.concat(bottomBoxes), fitBox);
11034
11035		// Figure out how much margin is on the top and bottom of the vertical boxes
11036		helpers.each(topBoxes, function(box) {
11037			totalTopBoxesHeight += box.height;
11038		});
11039
11040		helpers.each(bottomBoxes, function(box) {
11041			totalBottomBoxesHeight += box.height;
11042		});
11043
11044		function finalFitVerticalBox(box) {
11045			var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) {
11046				return minSize.box === box;
11047			});
11048
11049			var scaleMargin = {
11050				left: 0,
11051				right: 0,
11052				top: totalTopBoxesHeight,
11053				bottom: totalBottomBoxesHeight
11054			};
11055
11056			if (minBoxSize) {
11057				box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
11058			}
11059		}
11060
11061		// Let the left layout know the final margin
11062		helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
11063
11064		// Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
11065		totalLeftBoxesWidth = leftPadding;
11066		totalRightBoxesWidth = rightPadding;
11067		totalTopBoxesHeight = topPadding;
11068		totalBottomBoxesHeight = bottomPadding;
11069
11070		helpers.each(leftBoxes, function(box) {
11071			totalLeftBoxesWidth += box.width;
11072		});
11073
11074		helpers.each(rightBoxes, function(box) {
11075			totalRightBoxesWidth += box.width;
11076		});
11077
11078		helpers.each(topBoxes, function(box) {
11079			totalTopBoxesHeight += box.height;
11080		});
11081		helpers.each(bottomBoxes, function(box) {
11082			totalBottomBoxesHeight += box.height;
11083		});
11084
11085		// We may be adding some padding to account for rotated x axis labels
11086		var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
11087		totalLeftBoxesWidth += leftPaddingAddition;
11088		totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);
11089
11090		var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
11091		totalTopBoxesHeight += topPaddingAddition;
11092		totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);
11093
11094		// Figure out if our chart area changed. This would occur if the dataset layout label rotation
11095		// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
11096		// without calling `fit` again
11097		var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
11098		var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
11099
11100		if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
11101			helpers.each(leftBoxes, function(box) {
11102				box.height = newMaxChartAreaHeight;
11103			});
11104
11105			helpers.each(rightBoxes, function(box) {
11106				box.height = newMaxChartAreaHeight;
11107			});
11108
11109			helpers.each(topBoxes, function(box) {
11110				if (!box.fullWidth) {
11111					box.width = newMaxChartAreaWidth;
11112				}
11113			});
11114
11115			helpers.each(bottomBoxes, function(box) {
11116				if (!box.fullWidth) {
11117					box.width = newMaxChartAreaWidth;
11118				}
11119			});
11120
11121			maxChartAreaHeight = newMaxChartAreaHeight;
11122			maxChartAreaWidth = newMaxChartAreaWidth;
11123		}
11124
11125		// Step 7 - Position the boxes
11126		var left = leftPadding + leftPaddingAddition;
11127		var top = topPadding + topPaddingAddition;
11128
11129		function placeBox(box) {
11130			if (box.isHorizontal()) {
11131				box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
11132				box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
11133				box.top = top;
11134				box.bottom = top + box.height;
11135
11136				// Move to next point
11137				top = box.bottom;
11138
11139			} else {
11140
11141				box.left = left;
11142				box.right = left + box.width;
11143				box.top = totalTopBoxesHeight;
11144				box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
11145
11146				// Move to next point
11147				left = box.right;
11148			}
11149		}
11150
11151		helpers.each(leftBoxes.concat(topBoxes), placeBox);
11152
11153		// Account for chart width and height
11154		left += maxChartAreaWidth;
11155		top += maxChartAreaHeight;
11156
11157		helpers.each(rightBoxes, placeBox);
11158		helpers.each(bottomBoxes, placeBox);
11159
11160		// Step 8
11161		chart.chartArea = {
11162			left: totalLeftBoxesWidth,
11163			top: totalTopBoxesHeight,
11164			right: totalLeftBoxesWidth + maxChartAreaWidth,
11165			bottom: totalTopBoxesHeight + maxChartAreaHeight
11166		};
11167
11168		// Step 9
11169		helpers.each(chartAreaBoxes, function(box) {
11170			box.left = chart.chartArea.left;
11171			box.top = chart.chartArea.top;
11172			box.right = chart.chartArea.right;
11173			box.bottom = chart.chartArea.bottom;
11174
11175			box.update(maxChartAreaWidth, maxChartAreaHeight);
11176		});
11177	}
11178};
11179
11180},{"45":45}],31:[function(require,module,exports){
11181'use strict';
11182
11183var defaults = require(25);
11184var helpers = require(45);
11185
11186defaults._set('global', {
11187	plugins: {}
11188});
11189
11190/**
11191 * The plugin service singleton
11192 * @namespace Chart.plugins
11193 * @since 2.1.0
11194 */
11195module.exports = {
11196	/**
11197	 * Globally registered plugins.
11198	 * @private
11199	 */
11200	_plugins: [],
11201
11202	/**
11203	 * This identifier is used to invalidate the descriptors cache attached to each chart
11204	 * when a global plugin is registered or unregistered. In this case, the cache ID is
11205	 * incremented and descriptors are regenerated during following API calls.
11206	 * @private
11207	 */
11208	_cacheId: 0,
11209
11210	/**
11211	 * Registers the given plugin(s) if not already registered.
11212	 * @param {Array|Object} plugins plugin instance(s).
11213	 */
11214	register: function(plugins) {
11215		var p = this._plugins;
11216		([]).concat(plugins).forEach(function(plugin) {
11217			if (p.indexOf(plugin) === -1) {
11218				p.push(plugin);
11219			}
11220		});
11221
11222		this._cacheId++;
11223	},
11224
11225	/**
11226	 * Unregisters the given plugin(s) only if registered.
11227	 * @param {Array|Object} plugins plugin instance(s).
11228	 */
11229	unregister: function(plugins) {
11230		var p = this._plugins;
11231		([]).concat(plugins).forEach(function(plugin) {
11232			var idx = p.indexOf(plugin);
11233			if (idx !== -1) {
11234				p.splice(idx, 1);
11235			}
11236		});
11237
11238		this._cacheId++;
11239	},
11240
11241	/**
11242	 * Remove all registered plugins.
11243	 * @since 2.1.5
11244	 */
11245	clear: function() {
11246		this._plugins = [];
11247		this._cacheId++;
11248	},
11249
11250	/**
11251	 * Returns the number of registered plugins?
11252	 * @returns {Number}
11253	 * @since 2.1.5
11254	 */
11255	count: function() {
11256		return this._plugins.length;
11257	},
11258
11259	/**
11260	 * Returns all registered plugin instances.
11261	 * @returns {Array} array of plugin objects.
11262	 * @since 2.1.5
11263	 */
11264	getAll: function() {
11265		return this._plugins;
11266	},
11267
11268	/**
11269	 * Calls enabled plugins for `chart` on the specified hook and with the given args.
11270	 * This method immediately returns as soon as a plugin explicitly returns false. The
11271	 * returned value can be used, for instance, to interrupt the current action.
11272	 * @param {Object} chart - The chart instance for which plugins should be called.
11273	 * @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
11274	 * @param {Array} [args] - Extra arguments to apply to the hook call.
11275	 * @returns {Boolean} false if any of the plugins return false, else returns true.
11276	 */
11277	notify: function(chart, hook, args) {
11278		var descriptors = this.descriptors(chart);
11279		var ilen = descriptors.length;
11280		var i, descriptor, plugin, params, method;
11281
11282		for (i = 0; i < ilen; ++i) {
11283			descriptor = descriptors[i];
11284			plugin = descriptor.plugin;
11285			method = plugin[hook];
11286			if (typeof method === 'function') {
11287				params = [chart].concat(args || []);
11288				params.push(descriptor.options);
11289				if (method.apply(plugin, params) === false) {
11290					return false;
11291				}
11292			}
11293		}
11294
11295		return true;
11296	},
11297
11298	/**
11299	 * Returns descriptors of enabled plugins for the given chart.
11300	 * @returns {Array} [{ plugin, options }]
11301	 * @private
11302	 */
11303	descriptors: function(chart) {
11304		var cache = chart.$plugins || (chart.$plugins = {});
11305		if (cache.id === this._cacheId) {
11306			return cache.descriptors;
11307		}
11308
11309		var plugins = [];
11310		var descriptors = [];
11311		var config = (chart && chart.config) || {};
11312		var options = (config.options && config.options.plugins) || {};
11313
vendor: 9,411 bytes, lines 11314-11542
11314		this._plugins.concat(config.plugins || []).forEach(function(plugin) {
11315			var idx = plugins.indexOf(plugin);
11316			if (idx !== -1) {
11317				return;
11318			}
11319
11320			var id = plugin.id;
11321			var opts = options[id];
11322			if (opts === false) {
11323				return;
11324			}
11325
11326			if (opts === true) {
11327				opts = helpers.clone(defaults.global.plugins[id]);
11328			}
11329
11330			plugins.push(plugin);
11331			descriptors.push({
11332				plugin: plugin,
11333				options: opts || {}
11334			});
11335		});
11336
11337		cache.descriptors = descriptors;
11338		cache.id = this._cacheId;
11339		return descriptors;
11340	},
11341
11342	/**
11343	 * Invalidates cache for the given chart: descriptors hold a reference on plugin option,
11344	 * but in some cases, this reference can be changed by the user when updating options.
11345	 * https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
11346	 * @private
11347	 */
11348	_invalidate: function(chart) {
11349		delete chart.$plugins;
11350	}
11351};
11352
11353/**
11354 * Plugin extension hooks.
11355 * @interface IPlugin
11356 * @since 2.1.0
11357 */
11358/**
11359 * @method IPlugin#beforeInit
11360 * @desc Called before initializing `chart`.
11361 * @param {Chart.Controller} chart - The chart instance.
11362 * @param {Object} options - The plugin options.
11363 */
11364/**
11365 * @method IPlugin#afterInit
11366 * @desc Called after `chart` has been initialized and before the first update.
11367 * @param {Chart.Controller} chart - The chart instance.
11368 * @param {Object} options - The plugin options.
11369 */
11370/**
11371 * @method IPlugin#beforeUpdate
11372 * @desc Called before updating `chart`. If any plugin returns `false`, the update
11373 * is cancelled (and thus subsequent render(s)) until another `update` is triggered.
11374 * @param {Chart.Controller} chart - The chart instance.
11375 * @param {Object} options - The plugin options.
11376 * @returns {Boolean} `false` to cancel the chart update.
11377 */
11378/**
11379 * @method IPlugin#afterUpdate
11380 * @desc Called after `chart` has been updated and before rendering. Note that this
11381 * hook will not be called if the chart update has been previously cancelled.
11382 * @param {Chart.Controller} chart - The chart instance.
11383 * @param {Object} options - The plugin options.
11384 */
11385/**
11386 * @method IPlugin#beforeDatasetsUpdate
11387 * @desc Called before updating the `chart` datasets. If any plugin returns `false`,
11388 * the datasets update is cancelled until another `update` is triggered.
11389 * @param {Chart.Controller} chart - The chart instance.
11390 * @param {Object} options - The plugin options.
11391 * @returns {Boolean} false to cancel the datasets update.
11392 * @since version 2.1.5
11393*/
11394/**
11395 * @method IPlugin#afterDatasetsUpdate
11396 * @desc Called after the `chart` datasets have been updated. Note that this hook
11397 * will not be called if the datasets update has been previously cancelled.
11398 * @param {Chart.Controller} chart - The chart instance.
11399 * @param {Object} options - The plugin options.
11400 * @since version 2.1.5
11401 */
11402/**
11403 * @method IPlugin#beforeDatasetUpdate
11404 * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin
11405 * returns `false`, the datasets update is cancelled until another `update` is triggered.
11406 * @param {Chart} chart - The chart instance.
11407 * @param {Object} args - The call arguments.
11408 * @param {Number} args.index - The dataset index.
11409 * @param {Object} args.meta - The dataset metadata.
11410 * @param {Object} options - The plugin options.
11411 * @returns {Boolean} `false` to cancel the chart datasets drawing.
11412 */
11413/**
11414 * @method IPlugin#afterDatasetUpdate
11415 * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note
11416 * that this hook will not be called if the datasets update has been previously cancelled.
11417 * @param {Chart} chart - The chart instance.
11418 * @param {Object} args - The call arguments.
11419 * @param {Number} args.index - The dataset index.
11420 * @param {Object} args.meta - The dataset metadata.
11421 * @param {Object} options - The plugin options.
11422 */
11423/**
11424 * @method IPlugin#beforeLayout
11425 * @desc Called before laying out `chart`. If any plugin returns `false`,
11426 * the layout update is cancelled until another `update` is triggered.
11427 * @param {Chart.Controller} chart - The chart instance.
11428 * @param {Object} options - The plugin options.
11429 * @returns {Boolean} `false` to cancel the chart layout.
11430 */
11431/**
11432 * @method IPlugin#afterLayout
11433 * @desc Called after the `chart` has been layed out. Note that this hook will not
11434 * be called if the layout update has been previously cancelled.
11435 * @param {Chart.Controller} chart - The chart instance.
11436 * @param {Object} options - The plugin options.
11437 */
11438/**
11439 * @method IPlugin#beforeRender
11440 * @desc Called before rendering `chart`. If any plugin returns `false`,
11441 * the rendering is cancelled until another `render` is triggered.
11442 * @param {Chart.Controller} chart - The chart instance.
11443 * @param {Object} options - The plugin options.
11444 * @returns {Boolean} `false` to cancel the chart rendering.
11445 */
11446/**
11447 * @method IPlugin#afterRender
11448 * @desc Called after the `chart` has been fully rendered (and animation completed). Note
11449 * that this hook will not be called if the rendering has been previously cancelled.
11450 * @param {Chart.Controller} chart - The chart instance.
11451 * @param {Object} options - The plugin options.
11452 */
11453/**
11454 * @method IPlugin#beforeDraw
11455 * @desc Called before drawing `chart` at every animation frame specified by the given
11456 * easing value. If any plugin returns `false`, the frame drawing is cancelled until
11457 * another `render` is triggered.
11458 * @param {Chart.Controller} chart - The chart instance.
11459 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11460 * @param {Object} options - The plugin options.
11461 * @returns {Boolean} `false` to cancel the chart drawing.
11462 */
11463/**
11464 * @method IPlugin#afterDraw
11465 * @desc Called after the `chart` has been drawn for the specific easing value. Note
11466 * that this hook will not be called if the drawing has been previously cancelled.
11467 * @param {Chart.Controller} chart - The chart instance.
11468 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11469 * @param {Object} options - The plugin options.
11470 */
11471/**
11472 * @method IPlugin#beforeDatasetsDraw
11473 * @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
11474 * the datasets drawing is cancelled until another `render` is triggered.
11475 * @param {Chart.Controller} chart - The chart instance.
11476 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11477 * @param {Object} options - The plugin options.
11478 * @returns {Boolean} `false` to cancel the chart datasets drawing.
11479 */
11480/**
11481 * @method IPlugin#afterDatasetsDraw
11482 * @desc Called after the `chart` datasets have been drawn. Note that this hook
11483 * will not be called if the datasets drawing has been previously cancelled.
11484 * @param {Chart.Controller} chart - The chart instance.
11485 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11486 * @param {Object} options - The plugin options.
11487 */
11488/**
11489 * @method IPlugin#beforeDatasetDraw
11490 * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets
11491 * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing
11492 * is cancelled until another `render` is triggered.
11493 * @param {Chart} chart - The chart instance.
11494 * @param {Object} args - The call arguments.
11495 * @param {Number} args.index - The dataset index.
11496 * @param {Object} args.meta - The dataset metadata.
11497 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11498 * @param {Object} options - The plugin options.
11499 * @returns {Boolean} `false` to cancel the chart datasets drawing.
11500 */
11501/**
11502 * @method IPlugin#afterDatasetDraw
11503 * @desc Called after the `chart` datasets at the given `args.index` have been drawn
11504 * (datasets are drawn in the reverse order). Note that this hook will not be called
11505 * if the datasets drawing has been previously cancelled.
11506 * @param {Chart} chart - The chart instance.
11507 * @param {Object} args - The call arguments.
11508 * @param {Number} args.index - The dataset index.
11509 * @param {Object} args.meta - The dataset metadata.
11510 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11511 * @param {Object} options - The plugin options.
11512 */
11513/**
11514 * @method IPlugin#beforeTooltipDraw
11515 * @desc Called before drawing the `tooltip`. If any plugin returns `false`,
11516 * the tooltip drawing is cancelled until another `render` is triggered.
11517 * @param {Chart} chart - The chart instance.
11518 * @param {Object} args - The call arguments.
11519 * @param {Object} args.tooltip - The tooltip.
11520 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11521 * @param {Object} options - The plugin options.
11522 * @returns {Boolean} `false` to cancel the chart tooltip drawing.
11523 */
11524/**
11525 * @method IPlugin#afterTooltipDraw
11526 * @desc Called after drawing the `tooltip`. Note that this hook will not
11527 * be called if the tooltip drawing has been previously cancelled.
11528 * @param {Chart} chart - The chart instance.
11529 * @param {Object} args - The call arguments.
11530 * @param {Object} args.tooltip - The tooltip.
11531 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11532 * @param {Object} options - The plugin options.
11533 */
11534/**
11535 * @method IPlugin#beforeEvent
11536 * @desc Called before processing the specified `event`. If any plugin returns `false`,
11537 * the event will be discarded.
11538 * @param {Chart.Controller} chart - The chart instance.
11539 * @param {IEvent} event - The event object.
11540 * @param {Object} options - The plugin options.
11541 */
11542/**
11543 * @method IPlugin#afterEvent
11544 * @desc Called after the `event` has been consumed. Note that this hook
11545 * will not be called if the `event` has been previously discarded.
11546 * @param {Chart.Controller} chart - The chart instance.
11547 * @param {IEvent} event - The event object.
11548 * @param {Object} options - The plugin options.
11549 */
11550/**
11551 * @method IPlugin#resize
11552 * @desc Called after the chart as been resized.
11553 * @param {Chart.Controller} chart - The chart instance.
11554 * @param {Number} size - The new canvas display size (eq. canvas.style width & height).
11555 * @param {Object} options - The plugin options.
11556 */
11557/**
11558 * @method IPlugin#destroy
11559 * @desc Called after the chart as been destroyed.
11560 * @param {Chart.Controller} chart - The chart instance.
11561 * @param {Object} options - The plugin options.
11562 */
11563
11564},{"25":25,"45":45}],32:[function(require,module,exports){
11565'use strict';
11566
11567var defaults = require(25);
11568var Element = require(26);
11569var helpers = require(45);
11570var Ticks = require(34);
11571
11572defaults._set('scale', {
11573	display: true,
11574	position: 'left',
11575	offset: false,
11576
11577	// grid line settings
11578	gridLines: {
11579		display: true,
11580		color: 'rgba(0, 0, 0, 0.1)',
11581		lineWidth: 1,
11582		drawBorder: true,
11583		drawOnChartArea: true,
11584		drawTicks: true,
11585		tickMarkLength: 10,
11586		zeroLineWidth: 1,
11587		zeroLineColor: 'rgba(0,0,0,0.25)',
11588		zeroLineBorderDash: [],
11589		zeroLineBorderDashOffset: 0.0,
11590		offsetGridLines: false,
11591		borderDash: [],
11592		borderDashOffset: 0.0
11593	},
11594
11595	// scale label
11596	scaleLabel: {
11597		// display property
11598		display: false,
11599
11600		// actual label
11601		labelString: '',
11602
11603		// line height
11604		lineHeight: 1.2,
11605
11606		// top/bottom padding
11607		padding: {
11608			top: 4,
11609			bottom: 4
11610		}
11611	},
11612
11613	// label settings
11614	ticks: {
11615		beginAtZero: false,
11616		minRotation: 0,
11617		maxRotation: 50,
11618		mirror: false,
11619		padding: 0,
11620		reverse: false,
11621		display: true,
11622		autoSkip: true,
11623		autoSkipPadding: 0,
11624		labelOffset: 0,
11625		// We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
11626		callback: Ticks.formatters.values,
11627		minor: {},
11628		major: {}
11629	}
11630});
11631
11632function labelsFromTicks(ticks) {
11633	var labels = [];
11634	var i, ilen;
11635
11636	for (i = 0, ilen = ticks.length; i < ilen; ++i) {
11637		labels.push(ticks[i].label);
11638	}
11639
11640	return labels;
11641}
11642
11643function getLineValue(scale, index, offsetGridLines) {
11644	var lineValue = scale.getPixelForTick(index);
11645
11646	if (offsetGridLines) {
11647		if (index === 0) {
11648			lineValue -= (scale.getPixelForTick(1) - lineValue) / 2;
11649		} else {
11650			lineValue -= (lineValue - scale.getPixelForTick(index - 1)) / 2;
11651		}
11652	}
11653	return lineValue;
11654}
11655
11656module.exports = function(Chart) {
11657
11658	function computeTextSize(context, tick, font) {
11659		return helpers.isArray(tick) ?
11660			helpers.longestText(context, font, tick) :
11661			context.measureText(tick).width;
11662	}
11663
11664	function parseFontOptions(options) {
11665		var valueOrDefault = helpers.valueOrDefault;
11666		var globalDefaults = defaults.global;
11667		var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
11668		var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
11669		var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);
11670
11671		return {
11672			size: size,
11673			style: style,
11674			family: family,
11675			font: helpers.fontString(size, style, family)
11676		};
11677	}
11678
11679	function parseLineHeight(options) {
11680		return helpers.options.toLineHeight(
11681			helpers.valueOrDefault(options.lineHeight, 1.2),
11682			helpers.valueOrDefault(options.fontSize, defaults.global.defaultFontSize));
11683	}
11684
11685	Chart.Scale = Element.extend({
11686		/**
11687		 * Get the padding needed for the scale
11688		 * @method getPadding
11689		 * @private
11690		 * @returns {Padding} the necessary padding
11691		 */
11692		getPadding: function() {
11693			var me = this;
11694			return {
11695				left: me.paddingLeft || 0,
11696				top: me.paddingTop || 0,
11697				right: me.paddingRight || 0,
11698				bottom: me.paddingBottom || 0
11699			};
11700		},
11701
11702		/**
11703		 * Returns the scale tick objects ({label, major})
11704		 * @since 2.7
11705		 */
11706		getTicks: function() {
11707			return this._ticks;
11708		},
11709
11710		// These methods are ordered by lifecyle. Utilities then follow.
11711		// Any function defined here is inherited by all scale types.
11712		// Any function can be extended by the scale type
11713
11714		mergeTicksOptions: function() {
11715			var ticks = this.options.ticks;
11716			if (ticks.minor === false) {
11717				ticks.minor = {
11718					display: false
11719				};
11720			}
11721			if (ticks.major === false) {
11722				ticks.major = {
11723					display: false
11724				};
11725			}
11726			for (var key in ticks) {
11727				if (key !== 'major' && key !== 'minor') {
11728					if (typeof ticks.minor[key] === 'undefined') {
11729						ticks.minor[key] = ticks[key];
11730					}
11731					if (typeof ticks.major[key] === 'undefined') {
11732						ticks.major[key] = ticks[key];
11733					}
11734				}
11735			}
11736		},
11737		beforeUpdate: function() {
11738			helpers.callback(this.options.beforeUpdate, [this]);
11739		},
11740		update: function(maxWidth, maxHeight, margins) {
11741			var me = this;
11742			var i, ilen, labels, label, ticks, tick;
11743
11744			// Update Lifecycle - Probably don't want to ever extend or over
11744write this function ;)
11745			me.beforeUpdate();
11746
11747			// Absorb the master measurements
11748			me.maxWidth = maxWidth;
11749			me.maxHeight = maxHeight;
11750			me.margins = helpers.extend({
11751				left: 0,
11752				right: 0,
11753				top: 0,
11754				bottom: 0
11755			}, margins);
11756			me.longestTextCache = me.longestTextCache || {};
11757
11758			// Dimensions
11759			me.beforeSetDimensions();
11760			me.setDimensions();
11761			me.afterSetDimensions();
11762
11763			// Data min/max
11764			me.beforeDataLimits();
11765			me.determineDataLimits();
11766			me.afterDataLimits();
11767
11768			// Ticks - `this.ticks` is now DEPRECATED!
11769			// Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
11770			// and must not be accessed directly from outside this class. `this.ticks` being
11771			// around for long time and not marked as private, we can't change its structure
11772			// without unexpected breaking changes. If you need to access the scale ticks,
11773			// use scale.getTicks() instead.
11774
11775			me.beforeBuildTicks();
11776
11777			// New implementations should return an array of objects but for BACKWARD COMPAT,
11778			// we still support no return (`this.ticks` internally set by calling this method).
11779			ticks = me.buildTicks() || [];
11780
11781			me.afterBuildTicks();
11782
11783			me.beforeTickToLabelConversion();
11784
11785			// New implementations should return the formatted tick labels but for BACKWARD
11786			// COMPAT, we still support no return (`this.ticks` internally changed by calling
11787			// this method and supposed to contain only string values).
11788			labels = me.convertTicksToLabels(ticks) || me.ticks;
11789
11790			me.afterTickToLabelConversion();
11791
11792			me.ticks = labels;   // BACKWARD COMPATIBILITY
11793
11794			// IMPORTANT: from this point, we consider that `this.ticks` will NEVER change!
11795
11796			// BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
11797			for (i = 0, ilen = labels.length; i < ilen; ++i) {
11798				label = labels[i];
11799				tick = ticks[i];
11800				if (!tick) {
11801					ticks.push(tick = {
11802						label: label,
11803						major: false
11804					});
11805				} else {
11806					tick.label = label;
11807				}
11808			}
11809
11810			me._ticks = ticks;
11811
11812			// Tick Rotation
11813			me.beforeCalculateTickRotation();
11814			me.calculateTickRotation();
11815			me.afterCalculateTickRotation();
11816			// Fit
11817			me.beforeFit();
11818			me.fit();
11819			me.afterFit();
11820			//
11821			me.afterUpdate();
11822
11823			return me.minSize;
11824
11825		},
11826		afterUpdate: function() {
11827			helpers.callback(this.options.afterUpdate, [this]);
11828		},
11829
11830		//
11831
11832		beforeSetDimensions: function() {
11833			helpers.callback(this.options.beforeSetDimensions, [this]);
11834		},
11835		setDimensions: function() {
11836			var me = this;
11837			// Set the unconstrained dimension before label rotation
11838			if (me.isHorizontal()) {
11839				// Reset position before calculating rotation
11840				me.width = me.maxWidth;
11841				me.left = 0;
11842				me.right = me.width;
11843			} else {
11844				me.height = me.maxHeight;
11845
11846				// Reset position before calculating rotation
11847				me.top = 0;
11848				me.bottom = me.height;
11849			}
11850
11851			// Reset padding
11852			me.paddingLeft = 0;
11853			me.paddingTop = 0;
11854			me.paddingRight = 0;
11855			me.paddingBottom = 0;
11856		},
11857		afterSetDimensions: function() {
11858			helpers.callback(this.options.afterSetDimensions, [this]);
11859		},
11860
11861		// Data limits
11862		beforeDataLimits: function() {
11863			helpers.callback(this.options.beforeDataLimits, [this]);
11864		},
11865		determineDataLimits: helpers.noop,
11866		afterDataLimits: function() {
11867			helpers.callback(this.options.afterDataLimits, [this]);
11868		},
11869
11870		//
11871		beforeBuildTicks: function() {
11872			helpers.callback(this.options.beforeBuildTicks, [this]);
11873		},
11874		buildTicks: helpers.noop,
11875		afterBuildTicks: function() {
11876			helpers.callback(this.options.afterBuildTicks, [this]);
11877		},
11878
11879		beforeTickToLabelConversion: function() {
11880			helpers.callback(this.options.beforeTickToLabelConversion, [this]);
11881		},
11882		convertTicksToLabels: function() {
11883			var me = this;
11884			// Convert ticks to strings
11885			var tickOpts = me.options.ticks;
11886			me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
11887		},
11888		afterTickToLabelConversion: function() {
11889			helpers.callback(this.options.afterTickToLabelConversion, [this]);
11890		},
11891
11892		//
11893
11894		beforeCalculateTickRotation: function() {
11895			helpers.callback(this.options.beforeCalculateTickRotation, [this]);
11896		},
11897		calculateTickRotation: function() {
11898			var me = this;
11899			var context = me.ctx;
11900			var tickOpts = me.options.ticks;
11901			var labels = labelsFromTicks(me._ticks);
11902
11903			// Get the width of each grid by calculating the difference
11904			// between x offsets between 0 and 1.
11905			var tickFont = parseFontOptions(tickOpts);
11906			context.font = tickFont.font;
11907
11908			var labelRotation = tickOpts.minRotation || 0;
11909
11910			if (labels.length && me.options.display && me.isHorizontal()) {
11911				var originalLabelWidth = helpers.longestText(context, tickFont.font, labels, me.longestTextCache);
11912				var labelWidth = originalLabelWidth;
11913				var cosRotation, sinRotation;
11914
11915				// Allow 3 pixels x2 padding either side for label readability
11916				var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
11917
11918				// Max label rotation can be set or default to 90 - also act as a loop counter
11919				while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
11920					var angleRadians = helpers.toRadians(labelRotation);
11921					cosRotation = Math.cos(angleRadians);
11922					sinRotation = Math.sin(angleRadians);
11923
11924					if (sinRotation * originalLabelWidth > me.maxHeight) {
11925						// go back one step
11926						labelRotation--;
11927						break;
11928					}
11929
11930					labelRotation++;
11931					labelWidth = cosRotation * originalLabelWidth;
11932				}
11933			}
11934
11935			me.labelRotation = labelRotation;
11936		},
11937		afterCalculateTickRotation: function() {
11938			helpers.callback(this.options.afterCalculateTickRotation, [this]);
11939		},
11940
11941		//
11942
11943		beforeFit: function() {
11944			helpers.callback(this.options.beforeFit, [this]);
11945		},
11946		fit: function() {
11947			var me = this;
11948			// Reset
11949			var minSize = me.minSize = {
11950				width: 0,
11951				height: 0
11952			};
11953
11954			var labels = labelsFromTicks(me._ticks);
11955
11956			var opts = me.options;
11957			var tickOpts = opts.ticks;
11958			var scaleLabelOpts = opts.scaleLabel;
11959			var gridLineOpts = opts.gridLines;
11960			var display = opts.display;
11961			var isHorizontal = me.isHorizontal();
11962
11963			var tickFont = parseFontOptions(tickOpts);
11964			var tickMarkLength = opts.gridLines.tickMarkLength;
11965
11966			// Width
11967			if (isHorizontal) {
11968				// subtract the margins to line up with the chartArea if we are a full width scale
11969				minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
11970			} else {
11971				minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
11972			}
11973
11974			// height
11975			if (isHorizontal) {
11976				minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
11977			} else {
11978				minSize.height = me.maxHeight; // fill all the height
11979			}
11980
11981			// Are we showing a title for the scale?
11982			if (scaleLabelOpts.display && display) {
11983				var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);
11984				var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding);
11985				var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height;
11986
11987				if (isHorizontal) {
11988					minSize.height += deltaHeight;
11989				} else {
11990					minSize.width += deltaHeight;
11991				}
11992			}
11993
11994			// Don't bother fitting the ticks if we are not showing them
11995			if (tickOpts.display && display) {
11996				var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, labels, me.longestTextCache);
11997				var tallestLabelHeightInLines = helpers.numberOfLabelLines(labels);
11998				var lineSpace = tickFont.size * 0.5;
11999				var tickPadding = me.options.ticks.padding;
12000
12001				if (isHorizontal) {
12002					// A horizontal axis is more constrained by the height.
12003					me.longestLabelWidth = largestTextWidth;
12004
12005					var angleRadians = helpers.toRadians(me.labelRotation);
12006					var cosRotation = Math.cos(angleRadians);
12007					var sinRotation = Math.sin(angleRadians);
12008
12009					// TODO - improve this calculation
12010					var labelHeight = (sinRotation * largestTextWidth)
12011						+ (tickFont.size * tallestLabelHeightInLines)
12012						+ (lineSpace * (tallestLabelHeightInLines - 1))
12013						+ lineSpace; // padding
12014
12015					minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
12016
12017					me.ctx.font = tickFont.font;
12018					var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font);
12019					var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font);
12020
12021					// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
12022					// which means that the right padding is dominated by the font height
12023					if (me.labelRotation !== 0) {
12024						me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
12025						me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3;
12026					} else {
12027						me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
12028						me.paddingRight = lastLabelWidth / 2 + 3;
12029					}
12030				} else {
12031					// A vertical axis is more constrained by the width. Labels are the
12032					// dominant factor here, so get that length first and account for padding
12033					if (tickOpts.mirror) {
12034						largestTextWidth = 0;
12035					} else {
12036						// use lineSpace for consistency with horizontal axis
12037						// tickPadding is not implemented for horizontal
12038						largestTextWidth += tickPadding + lineSpace;
12039					}
12040
12041					minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
12042
12043					me.paddingTop = tickFont.size / 2;
12044					me.paddingBottom = tickFont.size / 2;
12045				}
12046			}
12047
12048			me.handleMargins();
12049
12050			me.width = minSize.width;
12051			me.height = minSize.height;
12052		},
12053
12054		/**
12055		 * Handle margins and padding interactions
12056		 * @private
12057		 */
12058		handleMargins: function() {
12059			var me = this;
12060			if (me.margins) {
12061				me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
12062				me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
12063				me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
12064				me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
12065			}
12066		},
12067
12068		afterFit: function() {
12069			helpers.callback(this.options.afterFit, [this]);
12070		},
12071
12072		// Shared Methods
12073		isHorizontal: function() {
12074			return this.options.position === 'top' || this.options.position === 'bottom';
12075		},
12076		isFullWidth: function() {
12077			return (this.options.fullWidth);
12078		},
12079
12080		// 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
12081		getRightValue: function(rawValue) {
12082			// Null and undefined values first
12083			if (helpers.isNullOrUndef(rawValue)) {
12084				return NaN;
12085			}
12086			// isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
12087			if (typeof rawValue === 'number' && !isFinite(rawValue)) {
12088				return NaN;
12089			}
12090			// If it is in fact an object, dive in one more level
12091			if (rawValue) {
12092				if (this.isHorizontal()) {
12093					if (rawValue.x !== undefined) {
12094						return this.getRightValue(rawValue.x);
12095					}
12096				} else if (rawValue.y !== undefined) {
12097					return this.getRightValue(rawValue.y);
12098				}
12099			}
12100
12101			// Value is good, return it
12102			return rawValue;
12103		},
12104
12105		/**
12106		 * Used to get the value to display in the tooltip for the data at the given index
12107		 * @param index
12108		 * @param datasetIndex
12109		 */
12110		getLabelForIndex: helpers.noop,
12111
12112		/**
12113		 * Returns the location of the given data point. Value can either be an index or a numerical value
12114		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12115		 * @param value
12116		 * @param index
12117		 * @param datasetIndex
12118		 */
12119		getPixelForValue: helpers.noop,
12120
12121		/**
12122		 * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
12123		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12124		 * @param pixel
12125		 */
12126		getValueForPixel: helpers.noop,
12127
12128		/**
12129		 * Returns the location of the tick at the given index
12130		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12131		 */
12132		getPixelForTick: function(index) {
12133			var me = this;
12134			var offset = me.options.offset;
12135			if (me.isHorizontal()) {
12136				var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
12137				var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
12138				var pixel = (tickWidth * index) + me.paddingLeft;
12139
12140				if (offset) {
12141					pixel += tickWidth / 2;
12142				}
12143
12144				var finalVal = me.left + Math.round(pixel);
12145				finalVal += me.isFullWidth() ? me.margins.left : 0;
12146				return finalVal;
12147			}
12148			var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
12149			return me.top + (index * (innerHeight / (me._ticks.length - 1)));
12150		},
12151
12152		/**
12153		 * Utility for getting the pixel location of a percentage of scale
12154		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12155		 */
12156		getPixelForDecimal: function(decimal) {
12157			var me = this;
12158			if (me.isHorizontal()) {
12159				var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
12160				var valueOffset = (innerWidth * decimal) + me.paddingLeft;
12161
12162				var finalVal = me.left + Math.round(valueOffset);
12163				finalVal += me.isFullWidth() ? me.margins.left : 0;
12164				return finalVal;
12165			}
12166			return me.top + (decimal * me.height);
12167		},
12168
12169		/**
12170		 * Returns the pixel for the minimum chart value
12171		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12172		 */
12173		getBasePixel: function() {
12174			return this.getPixelForValue(this.getBaseValue());
12175		},
12176
12177		getBaseValue: function() {
12178			var me = this;
12179			var min = me.min;
12180			var max = me.max;
12181
12182			return me.beginAtZero ? 0 :
12183				min < 0 && max < 0 ? max :
12184				min > 0 && max > 0 ? min :
12185				0;
12186		},
12187
12188		/**
12189		 * Returns a subset of ticks to be plotted to avoid overlapping labels.
12190		 * @private
12191		 */
12192		_autoSkip: function(ticks) {
12193			var skipRatio;
12194			var me = this;
12195			var isHorizontal = me.isHorizontal();
12196			var optionTicks = me.options.ticks.minor;
12197			var tickCount = ticks.length;
12198			var labelRotationRadians = helpers.toRadians(me.labelRotation);
12199			var cosRotation = Math.cos(labelRotationRadians);
12200			var longestRotatedLabel = me.longestLabelWidth * cosRotation;
12201			var result = [];
12202			var i, tick, shouldSkip;
12203
12204			// figure out the maximum number of gridlines to show
12205			var maxTicks;
12206			if (optionTicks.maxTicksLimit) {
12207				maxTicks = optionTicks.maxTicksLimit;
12208			}
12209
12210			if (isHorizontal) {
12211				skipRatio = false;
12212
12213				if ((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount > (me.width - (me.paddingLeft + me.paddingRight))) {
12214					skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount) / (me.width - (me.paddingLeft + me.paddingRight)));
12215				}
12216
12217				// if they defined a max number of optionTicks,
12218				// increase skipRatio until that number is met
12219				if (maxTicks && tickCount > maxTicks) {
12220					skipRatio = Math.max(skipRatio, Math.floor(tickCount / maxTicks));
12221				}
12222			}
12223
12224			for (i = 0; i < tickCount; i++) {
12225				tick = ticks[i];
12226
12227				// Since we always show the last tick,we need may need to hide the last shown one before
12228				shouldSkip = (skipRatio > 1 && i % skipRatio > 0) || (i % skipRatio === 0 && i + skipRatio >= tickCount);
12229				if (shouldSkip && i !== tickCount - 1) {
12230					// leave tick in place but make sure it's not displayed (#4635)
12231					delete tick.label;
12232				}
12233				result.push(tick);
12234			}
12235			return result;
12236		},
12237
12238		// Actually draw the scale on the canvas
12239		// @param {rectangle} chartArea : the area of the chart to draw full grid lines on
12240		draw: function(chartArea) {
12241			var me = this;
12242			var options = me.options;
12243			if (!options.display) {
12244				return;
12245			}
12246
12247			var context = me.ctx;
12248			var globalDefaults = defaults.global;
12249			var optionTicks = options.ticks.minor;
12250			var optionMajorTicks = options.ticks.major || optionTicks;
12251			var gridLines = options.gridLines;
12252			var scaleLabel = options.scaleLabel;
12253
12254			var isRotated = me.labelRotation !== 0;
12255			var isHorizontal = me.isHorizontal();
12256
12257			var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
12258			var tickFontColor = helpers.valueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
12259			var tickFont = parseFontOptions(optionTicks);
12260			var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor);
12261			var majorTickFont = parseFontOptions(optionMajorTicks);
12262
12263			var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
12264
12265			var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
12266			var scaleLabelFont = parseFontOptions(scaleLabel);
12267			var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
12268			var labelRotationRadians = helpers.toRadians(me.labelRotation);
12269
12270			var itemsToDraw = [];
12271
12272			var axisWidth = me.options.gridLines.lineWidth;
12273			var xTickStart = options.position === 'right' ? me.right : me.right - axisWidth - tl;
12274			var xTickEnd = options.position === 'right' ? me.right + tl : me.right;
12275			var yTickStart = options.position === 'bottom' ? me.top + axisWidth : me.bottom - tl - axisWidth;
12276			var yTickEnd = options.position === 'bottom' ? me.top + axisWidth + tl : me.bottom + axisWidth;
12277
12278			helpers.each(ticks, function(tick, index) {
12279				// autoskipper skipped this tick (#4635)
12280				if (helpers.isNullOrUndef(tick.label)) {
12281					return;
12282				}
12283
12284				var label = tick.label;
12285				var lineWidth, lineColor, borderDash, borderDashOffset;
12286				if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
12287					// Draw the first index specially
12288					lineWidth = gridLines.zeroLineWidth;
12289					lineColor = gridLines.zeroLineColor;
12290					borderDash = gridLines.zeroLineBorderDash;
12291					borderDashOffset = gridLines.zeroLineBorderDashOffset;
12292				} else {
12293					lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, index);
12294					lineColor = helpers.valueAtIndexOrDefault(gridLines.color, index);
12295					borderDash = helpers.valueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
12296					borderDashOffset = helpers.valueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
12297				}
12298
12299				// Common properties
12300				var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
12301				var textAlign = 'middle';
12302				var textBaseline = 'middle';
12303				var tickPadding = optionTicks.padding;
12304
12305				if (isHorizontal) {
12306					var labelYOffset = tl + tickPadding;
12307
12308					if (options.position === 'bottom') {
12309						// bottom
12310						textBaseline = !isRotated ? 'top' : 'middle';
12311						textAlign = !isRotated ? 'center' : 'right';
12312						labelY = me.top + labelYOffset;
12313					} else {
12314						// top
12315						textBaseline = !isRotated ? 'bottom' : 'middle';
12316						textAlign = !isRotated ? 'center' : 'left';
12317						labelY = me.bottom - labelYOffset;
12318					}
12319
12320					var xLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
12321					if (xLineValue < me.left) {
12322						lineColor = 'rgba(0,0,0,0)';
12323					}
12324					xLineValue += helpers.aliasPixel(lineWidth);
12325
12326					labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
12327
12328					tx1 = tx2 = x1 = x2 = xLineValue;
12329					ty1 = yTickStart;
12330					ty2 = yTickEnd;
12331					y1 = chartArea.top;
12332					y2 = chartArea.bottom + axisWidth;
12333				} else {
12334					var isLeft = options.position === 'left';
12335					var labelXOffset;
12336
12337					if (optionTicks.mirror) {
12338						textAlign = isLeft ? 'left' : 'right';
12339						labelXOffset = tickPadding;
12340					} else {
12341						textAlign = isLeft ? 'right' : 'left';
12342						labelXOffset = tl + tickPadding;
12343					}
12344
12345					labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
12346
12347					var yLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
12348					if (yLineValue < me.top) {
12349						lineColor = 'rgba(0,0,0,0)';
12350					}
12351					yLineValue += helpers.aliasPixel(lineWidth);
12352
12353					labelY = me.getPixelForTick(index) + optionTicks.labelOffset;
12354
12355					tx1 = xTickStart;
12356					tx2 = xTickEnd;
12357					x1 = chartArea.left;
12358					x2 = chartArea.right + axisWidth;
12359					ty1 = ty2 = y1 = y2 = yLineValue;
12360				}
12361
12362				itemsToDraw.push({
12363					tx1: tx1,
12364					ty1: ty1,
12365					tx2: tx2,
12366					ty2: ty2,
12367					x1: x1,
12368					y1: y1,
12369					x2: x2,
12370					y2: y2,
12371					labelX: labelX,
12372					labelY: labelY,
12373					glWidth: lineWidth,
12374					glColor: lineColor,
12375					glBorderDash: borderDash,
12376					glBorderDashOffset: borderDashOffset,
12377					rotation: -1 * labelRotationRadians,
12378					label: label,
12379					major: tick.major,
12380					textBaseline: textBaseline,
12381					textAlign: textAlign
12382				});
12383			});
12384
12385			// Draw all of the tick labels, tick marks, and grid lines at the correct places
12386			helpers.each(itemsToDraw, function(itemToDraw) {
12387				if (gridLines.display) {
12388					context.save();
12389					context.lineWidth = itemToDraw.glWidth;
12390					context.strokeStyle = itemToDraw.glColor;
12391					if (context.setLineDash) {
12392						context.setLineDash(itemToDraw.glBorderDash);
12393						context.lineDashOffset = itemToDraw.glBorderDashOffset;
12394					}
12395
12396					context.beginPath();
12397
12398					if (gridLines.drawTicks) {
12399						context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
12400						context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
12401					}
12402
12403					if (gridLines.drawOnChartArea) {
12404						context.moveTo(itemToDraw.x1, itemToDraw.y1);
12405						context.lineTo(itemToDraw.x2, itemToDraw.y2);
12406					}
12407
12408					context.stroke();
12409					context.restore();
12410				}
12411
12412				if (optionTicks.display) {
12413					// Make sure we draw text in the correct color and font
12414					context.save();
12415					context.translate(itemToDraw.labelX, itemToDraw.labelY);
12416					context.rotate(itemToDraw.rotation);
12417					context.font = itemToDraw.major ? majorTickFont.font : tickFont.font;
12418					context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
12419					context.textBaseline = itemToDraw.textBaseline;
12420					context.textAlign = itemToDraw.textAlign;
12421
12422					var label = itemToDraw.label;
12423					if (helpers.isArray(label)) {
12424						var lineCount = label.length;
12425						var lineHeight = tickFont.size * 1.5;
12426						var y = me.isHorizontal() ? 0 : -lineHeight * (lineCount - 1) / 2;
12427
12428						for (var i = 0; i < lineCount; ++i) {
12429							// We just make sure the multiline element is a string here..
12430							context.fillText('' + label[i], 0, y);
12431							// apply same lineSpacing as calculated @ L#320
12432							y += lineHeight;
12433						}
12434					} else {
12435						context.fillText(label, 0, 0);
12436					}
12437					context.restore();
12438				}
12439			});
12440
12441			if (scaleLabel.display) {
12442				// Draw the scale label
12443				var scaleLabelX;
12444				var scaleLabelY;
12445				var rotation = 0;
12446				var halfLineHeight = parseLineHeight(scaleLabel) / 2;
12447
12448				if (isHorizontal) {
12449					scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
12450					scaleLabelY = options.position === 'bottom'
12451						? me.bottom - halfLineHeight - scaleLabelPadding.bottom
12452						: me.top + halfLineHeight + scaleLabelPadding.top;
12453				} else {
12454					var isLeft = options.position === 'left';
12455					scaleLabelX = isLeft
12456						? me.left + halfLineHeight + scaleLabelPadding.top
12457						: me.right - halfLineHeight - scaleLabelPadding.top;
12458					scaleLabelY = me.top + ((me.bottom - me.top) / 2);
12459					rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
12460				}
12461
12462				context.save();
12463				context.translate(scaleLabelX, scaleLabelY);
12464				context.rotate(rotation);
12465				context.textAlign = 'center';
12466				context.textBaseline = 'middle';
12467				context.fillStyle = scaleLabelFontColor; // render in correct colour
12468				context.font = scaleLabelFont.font;
12469				context.fillText(scaleLabel.labelString, 0, 0);
12470				context.restore();
12471			}
12472
12473			if (gridLines.drawBorder) {
12474				// Draw the line at the edge of the axis
12475				context.lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0);
12476				context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0);
12477				var x1 = me.left;
12478				var x2 = me.right + axisWidth;
12479				var y1 = me.top;
12480				var y2 = me.bottom + axisWidth;
12481
12482				var aliasPixel = helpers.aliasPixel(context.lineWidth);
12483				if (isHorizontal) {
12484					y1 = y2 = options.position === 'top' ? me.bottom : me.top;
12485					y1 += aliasPixel;
12486					y2 += aliasPixel;
12487				} else {
12488					x1 = x2 = options.position === 'left' ? me.right : me.left;
12489					x1 += aliasPixel;
12490					x2 += aliasPixel;
12491				}
12492
12493				context.beginPath();
12494				context.moveTo(x1, y1);
12495				context.lineTo(x2, y2);
12496				context.stroke();
12497			}
12498		}
12499	});
12500};
12501
12502},{"25":25,"26":26,"34":34,"45":45}],33:[function(require,module,exports){
12503'use strict';
12504
12505var defaults = require(25);
12506var helpers = require(45);
12507var layouts = require(30);
12508
12509module.exports = function(Chart) {
12510
12511	Chart.scaleService = {
12512		// Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
12513		// use the new chart options to grab the correct scale
12514		constructors: {},
12515		// Use a registration function so that we can move to an ES6 map when we no longer need to support
12516		// old browsers
12517
12518		// Scale config defaults
12519		defaults: {},
12520		registerScaleType: function(type, scaleConstructor, scaleDefaults) {
12521			this.constructors[type] = scaleConstructor;
12522			this.defaults[type] = helpers.clone(scaleDefaults);
12523		},
12524		getScaleConstructor: function(type) {
12525			return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
12526		},
12527		getScaleDefaults: function(type) {
12528			// Return the scale defaults merged with the global settings so that we always use the latest ones
12529			return this.defaults.hasOwnProperty(type) ? helpers.merge({}, [defaults.scale, this.defaults[type]]) : {};
12530		},
12531		updateScaleDefaults: function(type, additions) {
12532			var me = this;
12533			if (me.defaults.hasOwnProperty(type)) {
12534				me.defaults[type] = helpers.extend(me.defaults[type], additions);
12535			}
12536		},
12537		addScalesToLayout: function(chart) {
12538			// Adds each scale to the chart.boxes array to be sized accordingly
12539			helpers.each(chart.scales, function(scale) {
12540				// Set ILayoutItem parameters for backwards compatibility
12541				scale.fullWidth = scale.options.fullWidth;
12542				scale.position = scale.options.position;
12543				scale.weight = scale.options.weight;
12544				layouts.addBox(chart, scale);
12545			});
12546		}
12547	};
12548};
12549
12550},{"25":25,"30":30,"45":45}],34:[function(require,module,exports){
12551'use strict';
12552
12553var helpers = require(45);
12554
12555/**
12556 * Namespace to hold static tick generation functions
12557 * @namespace Chart.Ticks
12558 */
12559module.exports = {
12560	/**
12561	 * Namespace to hold formatters for different types of ticks
12562	 * @namespace Chart.Ticks.formatters
12563	 */
12564	formatters: {
12565		/**
12566		 * Formatter for value labels
12567		 * @method Chart.Ticks.formatters.values
12568		 * @param value the value to display
12569		 * @return {String|Array} the label to display
12570		 */
12571		values: function(value) {
12572			return helpers.isArray(value) ? value : '' + value;
12573		},
12574
12575		/**
12576		 * Formatter for linear numeric ticks
12577		 * @method Chart.Ticks.formatters.linear
12578		 * @param tickValue {Number} the value to be formatted
12579		 * @param index {Number} the position of the tickValue parameter in the ticks array
12580		 * @param ticks {Array<Number>} the list of ticks being converted
12581		 * @return {String} string representation of the tickValue parameter
12582		 */
12583		linear: function(tickValue, index, ticks) {
12584			// If we have lots of ticks, don't use the ones
12585			var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
12586
12587			// If we have a number like 2.5 as the delta, figure out how many decimal places we need
12588			if (Math.abs(delta) > 1) {
12589				if (tickValue !== Math.floor(tickValue)) {
12590					// not an integer
12591					delta = tickValue - Math.floor(tickValue);
12592				}
12593			}
12594
12595			var logDelta = helpers.log10(Math.abs(delta));
12596			var tickString = '';
12597
12598			if (tickValue !== 0) {
12599				var numDecimal = -1 * Math.floor(logDelta);
12600				numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
12601				tickString = tickValue.toFixed(numDecimal);
12602			} else {
12603				tickString = '0'; // never show decimal places for 0
12604			}
12605
12606			return tickString;
12607		},
12608
12609		logarithmic: function(tickValue, index, ticks) {
12610			var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue))));
12611
12612			if (tickValue === 0) {
12613				return '0';
12614			} else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
12615				return tickValue.toExponential();
12616			}
12617			return '';
12618		}
12619	}
12620};
12621
12622},{"45":45}],35:[function(require,module,exports){
12623'use strict';
12624
12625var defaults = require(25);
12626var Element = require(26);
12627var helpers = require(45);
12628
12629defaults._set('global', {
12630	tooltips: {
12631		enabled: true,
12632		custom: null,
12633		mode: 'nearest',
12634		position: 'average',
12635		intersect: true,
12636		backgroundColor: 'rgba(0,0,0,0.8)',
12637		titleFontStyle: 'bold',
12638		titleSpacing: 2,
12639		titleMarginBottom: 6,
12640		titleFontColor: '#fff',
12641		titleAlign: 'left',
12642		bodySpacing: 2,
12643		bodyFontColor: '#fff',
12644		bodyAlign: 'left',
12645		footerFontStyle: 'bold',
12646		footerSpacing: 2,
12647		footerMarginTop: 6,
12648		footerFontColor: '#fff',
12649		footerAlign: 'left',
12650		yPadding: 6,
12651		xPadding: 6,
12652		caretPadding: 2,
12653		caretSize: 5,
12654		cornerRadius: 6,
12655		multiKeyBackground: '#fff',
12656		displayColors: true,
12657		borderColor: 'rgba(0,0,0,0)',
12658		borderWidth: 0,
12659		callbacks: {
12660			// Args are: (tooltipItems, data)
12661			beforeTitle: helpers.noop,
12662			title: function(tooltipItems, data) {
12663				// Pick first xLabel for now
12664				var title = '';
12665				var labels = data.labels;
12666				var labelCount = labels ? labels.length : 0;
12667
12668				if (tooltipItems.length > 0) {
12669					var item = tooltipItems[0];
12670
12671					if (item.xLabel) {
12672						title = item.xLabel;
12673					} else if (labelCount > 0 && item.index < labelCount) {
12674						title = labels[item.index];
12675					}
12676				}
12677
12678				return title;
12679			},
12680			afterTitle: helpers.noop,
12681
12682			// Args are: (tooltipItems, data)
12683			beforeBody: helpers.noop,
12684
12685			// Args are: (tooltipItem, data)
12686			beforeLabel: helpers.noop,
12687			label: function(tooltipItem, data) {
12688				var label = data.datasets[tooltipItem.datasetIndex].label || '';
12689
12690				if (label) {
12691					label += ': ';
12692				}
12693				label += tooltipItem.yLabel;
12694				return label;
12695			},
12696			labelColor: function(tooltipItem, chart) {
12697				var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
12698				var activeElement = meta.data[tooltipItem.index];
12699				var view = activeElement._view;
12700				return {
12701					borderColor: view.borderColor,
12702					backgroundColor: view.backgroundColor
12703				};
12704			},
12705			labelTextColor: function() {
12706				return this._options.bodyFontColor;
12707			},
12708			afterLabel: helpers.noop,
12709
12710			// Args are: (tooltipItems, data)
12711			afterBody: helpers.noop,
12712
12713			// Args are: (tooltipItems, data)
12714			beforeFooter: helpers.noop,
12715			footer: helpers.noop,
12716			afterFooter: helpers.noop
12717		}
12718	}
12719});
12720
12721module.exports = function(Chart) {
12722
12723	/**
12724 	 * Helper method to merge the opacity into a color
12725 	 */
vendor: 9,332 bytes, lines 12726-13029
12726	function mergeOpacity(colorString, opacity) {
12727		var color = helpers.color(colorString);
12728		return color.alpha(opacity * color.alpha()).rgbaString();
12729	}
12730
12731	// Helper to push or concat based on if the 2nd parameter is an array or not
12732	function pushOrConcat(base, toPush) {
12733		if (toPush) {
12734			if (helpers.isArray(toPush)) {
12735				// base = base.concat(toPush);
12736				Array.prototype.push.apply(base, toPush);
12737			} else {
12738				base.push(toPush);
12739			}
12740		}
12741
12742		return base;
12743	}
12744
12745	// Private helper to create a tooltip item model
12746	// @param element : the chart element (point, arc, bar) to create the tooltip item for
12747	// @return : new tooltip item
12748	function createTooltipItem(element) {
12749		var xScale = element._xScale;
12750		var yScale = element._yScale || element._scale; // handle radar || polarArea charts
12751		var index = element._index;
12752		var datasetIndex = element._datasetIndex;
12753
12754		return {
12755			xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
12756			yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
12757			index: index,
12758			datasetIndex: datasetIndex,
12759			x: element._model.x,
12760			y: element._model.y
12761		};
12762	}
12763
12764	/**
12765	 * Helper to get the reset model for the tooltip
12766	 * @param tooltipOpts {Object} the tooltip options
12767	 */
12768	function getBaseModel(tooltipOpts) {
12769		var globalDefaults = defaults.global;
12770		var valueOrDefault = helpers.valueOrDefault;
12771
12772		return {
12773			// Positioning
12774			xPadding: tooltipOpts.xPadding,
12775			yPadding: tooltipOpts.yPadding,
12776			xAlign: tooltipOpts.xAlign,
12777			yAlign: tooltipOpts.yAlign,
12778
12779			// Body
12780			bodyFontColor: tooltipOpts.bodyFontColor,
12781			_bodyFontFamily: valueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
12782			_bodyFontStyle: valueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
12783			_bodyAlign: tooltipOpts.bodyAlign,
12784			bodyFontSize: valueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
12785			bodySpacing: tooltipOpts.bodySpacing,
12786
12787			// Title
12788			titleFontColor: tooltipOpts.titleFontColor,
12789			_titleFontFamily: valueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
12790			_titleFontStyle: valueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
12791			titleFontSize: valueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
12792			_titleAlign: tooltipOpts.titleAlign,
12793			titleSpacing: tooltipOpts.titleSpacing,
12794			titleMarginBottom: tooltipOpts.titleMarginBottom,
12795
12796			// Footer
12797			footerFontColor: tooltipOpts.footerFontColor,
12798			_footerFontFamily: valueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
12799			_footerFontStyle: valueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
12800			footerFontSize: valueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
12801			_footerAlign: tooltipOpts.footerAlign,
12802			footerSpacing: tooltipOpts.footerSpacing,
12803			footerMarginTop: tooltipOpts.footerMarginTop,
12804
12805			// Appearance
12806			caretSize: tooltipOpts.caretSize,
12807			cornerRadius: tooltipOpts.cornerRadius,
12808			backgroundColor: tooltipOpts.backgroundColor,
12809			opacity: 0,
12810			legendColorBackground: tooltipOpts.multiKeyBackground,
12811			displayColors: tooltipOpts.displayColors,
12812			borderColor: tooltipOpts.borderColor,
12813			borderWidth: tooltipOpts.borderWidth
12814		};
12815	}
12816
12817	/**
12818	 * Get the size of the tooltip
12819	 */
12820	function getTooltipSize(tooltip, model) {
12821		var ctx = tooltip._chart.ctx;
12822
12823		var height = model.yPadding * 2; // Tooltip Padding
12824		var width = 0;
12825
12826		// Count of all lines in the body
12827		var body = model.body;
12828		var combinedBodyLength = body.reduce(function(count, bodyItem) {
12829			return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
12830		}, 0);
12831		combinedBodyLength += model.beforeBody.length + model.afterBody.length;
12832
12833		var titleLineCount = model.title.length;
12834		var footerLineCount = model.footer.length;
12835		var titleFontSize = model.titleFontSize;
12836		var bodyFontSize = model.bodyFontSize;
12837		var footerFontSize = model.footerFontSize;
12838
12839		height += titleLineCount * titleFontSize; // Title Lines
12840		height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
12841		height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
12842		height += combinedBodyLength * bodyFontSize; // Body Lines
12843		height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
12844		height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
12845		height += footerLineCount * (footerFontSize); // Footer Lines
12846		height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
12847
12848		// Title width
12849		var widthPadding = 0;
12850		var maxLineWidth = function(line) {
12851			width = Math.max(width, ctx.measureText(line).width + widthPadding);
12852		};
12853
12854		ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
12855		helpers.each(model.title, maxLineWidth);
12856
12857		// Body width
12858		ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
12859		helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
12860
12861		// Body lines may include some extra width due to the color box
12862		widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
12863		helpers.each(body, function(bodyItem) {
12864			helpers.each(bodyItem.before, maxLineWidth);
12865			helpers.each(bodyItem.lines, maxLineWidth);
12866			helpers.each(bodyItem.after, maxLineWidth);
12867		});
12868
12869		// Reset back to 0
12870		widthPadding = 0;
12871
12872		// Footer width
12873		ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
12874		helpers.each(model.footer, maxLineWidth);
12875
12876		// Add padding
12877		width += 2 * model.xPadding;
12878
12879		return {
12880			width: width,
12881			height: height
12882		};
12883	}
12884
12885	/**
12886	 * Helper to get the alignment of a tooltip given the size
12887	 */
12888	function determineAlignment(tooltip, size) {
12889		var model = tooltip._model;
12890		var chart = tooltip._chart;
12891		var chartArea = tooltip._chart.chartArea;
12892		var xAlign = 'center';
12893		var yAlign = 'center';
12894
12895		if (model.y < size.height) {
12896			yAlign = 'top';
12897		} else if (model.y > (chart.height - size.height)) {
12898			yAlign = 'bottom';
12899		}
12900
12901		var lf, rf; // functions to determine left, right alignment
12902		var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
12903		var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
12904		var midX = (chartArea.left + chartArea.right) / 2;
12905		var midY = (chartArea.top + chartArea.bottom) / 2;
12906
12907		if (yAlign === 'center') {
12908			lf = function(x) {
12909				return x <= midX;
12910			};
12911			rf = function(x) {
12912				return x > midX;
12913			};
12914		} else {
12915			lf = function(x) {
12916				return x <= (size.width / 2);
12917			};
12918			rf = function(x) {
12919				return x >= (chart.width - (size.width / 2));
12920			};
12921		}
12922
12923		olf = function(x) {
12924			return x + size.width + model.caretSize + model.caretPadding > chart.width;
12925		};
12926		orf = function(x) {
12927			return x - size.width - model.caretSize - model.caretPadding < 0;
12928		};
12929		yf = function(y) {
12930			return y <= midY ? 'top' : 'bottom';
12931		};
12932
12933		if (lf(model.x)) {
12934			xAlign = 'left';
12935
12936			// Is tooltip too wide and goes over the right side of the chart.?
12937			if (olf(model.x)) {
12938				xAlign = 'center';
12939				yAlign = yf(model.y);
12940			}
12941		} else if (rf(model.x)) {
12942			xAlign = 'right';
12943
12944			// Is tooltip too wide and goes outside left edge of canvas?
12945			if (orf(model.x)) {
12946				xAlign = 'center';
12947				yAlign = yf(model.y);
12948			}
12949		}
12950
12951		var opts = tooltip._options;
12952		return {
12953			xAlign: opts.xAlign ? opts.xAlign : xAlign,
12954			yAlign: opts.yAlign ? opts.yAlign : yAlign
12955		};
12956	}
12957
12958	/**
12959	 * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
12960	 */
12961	function getBackgroundPoint(vm, size, alignment, chart) {
12962		// Background Position
12963		var x = vm.x;
12964		var y = vm.y;
12965
12966		var caretSize = vm.caretSize;
12967		var caretPadding = vm.caretPadding;
12968		var cornerRadius = vm.cornerRadius;
12969		var xAlign = alignment.xAlign;
12970		var yAlign = alignment.yAlign;
12971		var paddingAndSize = caretSize + caretPadding;
12972		var radiusAndPadding = cornerRadius + caretPadding;
12973
12974		if (xAlign === 'right') {
12975			x -= size.width;
12976		} else if (xAlign === 'center') {
12977			x -= (size.width / 2);
12978			if (x + size.width > chart.width) {
12979				x = chart.width - size.width;
12980			}
12981			if (x < 0) {
12982				x = 0;
12983			}
12984		}
12985
12986		if (yAlign === 'top') {
12987			y += paddingAndSize;
12988		} else if (yAlign === 'bottom') {
12989			y -= size.height + paddingAndSize;
12990		} else {
12991			y -= (size.height / 2);
12992		}
12993
12994		if (yAlign === 'center') {
12995			if (xAlign === 'left') {
12996				x += paddingAndSize;
12997			} else if (xAlign === 'right') {
12998				x -= paddingAndSize;
12999			}
13000		} else if (xAlign === 'left') {
13001			x -= radiusAndPadding;
13002		} else if (xAlign === 'right') {
13003			x += radiusAndPadding;
13004		}
13005
13006		return {
13007			x: x,
13008			y: y
13009		};
13010	}
13011
13012	Chart.Tooltip = Element.extend({
13013		initialize: function() {
13014			this._model = getBaseModel(this._options);
13015			this._lastActive = [];
13016		},
13017
13018		// Get the title
13019		// Args are: (tooltipItem, data)
13020		getTitle: function() {
13021			var me = this;
13022			var opts = me._options;
13023			var callbacks = opts.callbacks;
13024
13025			var beforeTitle = callbacks.beforeTitle.apply(me, arguments);
13026			var title = callbacks.title.apply(me, arguments);
13027			var afterTitle = callbacks.afterTitle.apply(me, arguments);
13028
13029			var lines = [];
13030			lines = pushOrConcat(lines, beforeTitle);
13031			lines = pushOrConcat(lines, title);
13032			lines = pushOrConcat(lines, afterTitle);
13033
13034			return lines;
13035		},
13036
13037		// Args are: (tooltipItem, data)
13038		getBeforeBody: function() {
13039			var lines = this._options.callbacks.beforeBody.apply(this, arguments);
13040			return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
13041		},
13042
13043		// Args are: (tooltipItem, data)
13044		getBody: function(tooltipItems, data) {
13045			var me = this;
13046			var callbacks = me._options.callbacks;
13047			var bodyItems = [];
13048
13049			helpers.each(tooltipItems, function(tooltipItem) {
13050				var bodyItem = {
13051					before: [],
13052					lines: [],
13053					after: []
13054				};
13055				pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
13056				pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
13057				pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));
13058
13059				bodyItems.push(bodyItem);
13060			});
13061
13062			return bodyItems;
13063		},
13064
13065		// Args are: (tooltipItem, data)
13066		getAfterBody: function() {
13067			var lines = this._options.callbacks.afterBody.apply(this, arguments);
13068			return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
13069		},
13070
13071		// Get the footer and beforeFooter and afterFooter lines
13072		// Args are: (tooltipItem, data)
13073		getFooter: function() {
13074			var me = this;
13075			var callbacks = me._options.callbacks;
13076
13077			var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
13078			var footer = callbacks.footer.apply(me, arguments);
13079			var afterFooter = callbacks.afterFooter.apply(me, arguments);
13080
13081			var lines = [];
13082			lines = pushOrConcat(lines, beforeFooter);
13083			lines = pushOrConcat(lines, footer);
13084			lines = pushOrConcat(lines, afterFooter);
13085
13086			return lines;
13087		},
13088
13089		update: function(changed) {
13090			var me = this;
13091			var opts = me._options;
13092
13093			// Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
13094			// 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
13095			// which breaks any animations.
13096			var existingModel = me._model;
13097			var model = me._model = getBaseModel(opts);
13098			var active = me._active;
13099
13100			var data = me._data;
13101
13102			// In the case where active.length === 0 we need to keep these at existing values for good animations
13103			var alignment = {
13104				xAlign: existingModel.xAlign,
13105				yAlign: existingModel.yAlign
13106			};
13107			var backgroundPoint = {
13108				x: existingModel.x,
13109				y: existingModel.y
13110			};
13111			var tooltipSize = {
13112				width: existingModel.width,
13113				height: existingModel.height
13114			};
13115			var tooltipPosition = {
13116				x: existingModel.caretX,
13117				y: existingModel.caretY
13118			};
13119
13120			var i, len;
13121
13122			if (active.length) {
13123				model.opacity = 1;
13124
13125				var labelColors = [];
13126				var labelTextColors = [];
13127				tooltipPosition = Chart.Tooltip.positioners[opts.position].call(me, active, me._eventPosition);
13128
13129				var tooltipItems = [];
13130				for (i = 0, len = active.length; i < len; ++i) {
13131					tooltipItems.push(createTooltipItem(active[i]));
13132				}
13133
13134				// If the user provided a filter function, use it to modify the tooltip items
13135				if (opts.filter) {
13136					tooltipItems = tooltipItems.filter(function(a) {
13137						return opts.filter(a, data);
13138					});
13139				}
13140
13141				// If the user provided a sorting function, use it to modify the tooltip items
13142				if (opts.itemSort) {
13143					tooltipItems = tooltipItems.sort(function(a, b) {
13144						return opts.itemSort(a, b, data);
13145					});
13146				}
13147
13148				// Determine colors for boxes
13149				helpers.each(tooltipItems, function(tooltipItem) {
13150					labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
13151					labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart));
13152				});
13153
13154
13155				// Build the Text Lines
13156				model.title = me.getTitle(tooltipItems, data);
13157				model.beforeBody = me.getBeforeBody(tooltipItems, data);
13158				model.body = me.getBody(tooltipItems, data);
13159				model.afterBody = me.getAfterBody(tooltipItems, data);
13160				model.footer = me.getFooter(tooltipItems, data);
13161
13162				// Initial positioning and colors
13163				model.x = Math.round(tooltipPosition.x);
13164				model.y = Math.round(tooltipPosition.y);
13165				model.caretPadding = opts.caretPadding;
13166				model.labelColors = labelColors;
13167				model.labelTextColors = labelTextColors;
13168
13169				// data points
13170				model.dataPoints = tooltipItems;
13171
13172				// We need to determine alignment of the tooltip
13173				tooltipSize = getTooltipSize(this, model);
13174				alignment = determineAlignment(this, tooltipSize);
13175				// Final Size and Position
13176				backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart);
13177			} else {
13178				model.opacity = 0;
13179			}
13180
13181			model.xAlign = alignment.xAlign;
13182			model.yAlign = alignment.yAlign;
13183			model.x = backgroundPoint.x;
13184			model.y = backgroundPoint.y;
13185			model.width = tooltipSize.width;
13186			model.height = tooltipSize.height;
13187
13188			// Point where the caret on the tooltip points to
13189			model.caretX = tooltipPosition.x;
13190			model.caretY = tooltipPosition.y;
13191
13192			me._model = model;
13193
13194			if (changed && opts.custom) {
13195				opts.custom.call(me, model);
13196			}
13197
13198			return me;
13199		},
13200		drawCaret: function(tooltipPoint, size) {
13201			var ctx = this._chart.ctx;
13202			var vm = this._view;
13203			var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
13204
13205			ctx.lineTo(caretPosition.x1, caretPosition.y1);
13206			ctx.lineTo(caretPosition.x2, caretPosition.y2);
13207			ctx.lineTo(caretPosition.x3, caretPosition.y3);
13208		},
13209		getCaretPosition: function(tooltipPoint, size, vm) {
13210			var x1, x2, x3, y1, y2, y3;
13211			var caretSize = vm.caretSize;
13212			var cornerRadius = vm.cornerRadius;
13213			var xAlign = vm.xAlign;
13214			var yAlign = vm.yAlign;
13215			var ptX = tooltipPoint.x;
13216			var ptY = tooltipPoint.y;
13217			var width = size.width;
13218			var height = size.height;
13219
13220			if (yAlign === 'center') {
13221				y2 = ptY + (height / 2);
13222
13223				if (xAlign === 'left') {
13224					x1 = ptX;
13225					x2 = x1 - caretSize;
13226					x3 = x1;
13227
13228					y1 = y2 + caretSize;
13229					y3 = y2 - caretSize;
13230				} else {
13231					x1 = ptX + width;
13232					x2 = x1 + caretSize;
13233					x3 = x1;
13234
13235					y1 = y2 - caretSize;
13236					y3 = y2 + caretSize;
13237				}
13238			} else {
13239				if (xAlign === 'left') {
13240					x2 = ptX + cornerRadius + (caretSize);
13241					x1 = x2 - caretSize;
13242					x3 = x2 + caretSize;
13243				} else if (xAlign === 'right') {
13244					x2 = ptX + width - cornerRadius - caretSize;
13245					x1 = x2 - caretSize;
13246					x3 = x2 + caretSize;
13247				} else {
13248					x2 = vm.caretX;
13249					x1 = x2 - caretSize;
13250					x3 = x2 + caretSize;
13251				}
13252				if (yAlign === 'top') {
13253					y1 = ptY;
13254					y2 = y1 - caretSize;
13255					y3 = y1;
13256				} else {
13257					y1 = ptY + height;
13258					y2 = y1 + caretSize;
13259					y3 = y1;
13260					// invert drawing order
13261					var tmp = x3;
13262					x3 = x1;
13263					x1 = tmp;
13264				}
13265			}
13266			return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
13267		},
13268		drawTitle: function(pt, vm, ctx, opacity) {
13269			var title = vm.title;
13270
13271			if (title.length) {
13272				ctx.textAlign = vm._titleAlign;
13273				ctx.textBaseline = 'top';
13274
13275				var titleFontSize = vm.titleFontSize;
13276				var titleSpacing = vm.titleSpacing;
13277
13278				ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
13279				ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
13280
13281				var i, len;
13282				for (i = 0, len = title.length; i < len; ++i) {
13283					ctx.fillText(title[i], pt.x, pt.y);
13284					pt.y += titleFontSize + titleSpacing; // Line Height and spacing
13285
13286					if (i + 1 === title.length) {
13287						pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
13288					}
13289				}
13290			}
13291		},
13292		drawBody: function(pt, vm, ctx, opacity) {
13293			var bodyFontSize = vm.bodyFontSize;
13294			var bodySpacing = vm.bodySpacing;
13295			var body = vm.body;
13296
13297			ctx.textAlign = vm._bodyAlign;
13298			ctx.textBaseline = 'top';
13299			ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
13300
13301			// Before Body
13302			var xLinePadding = 0;
13303			var fillLineOfText = function(line) {
13304				ctx.fillText(line, pt.x + xLinePadding, pt.y);
13305				pt.y += bodyFontSize + bodySpacing;
13306			};
13307
13308			// Before body lines
13309			ctx.fillStyle = mergeOpacity(vm.bodyFontColor, opacity);
13310			helpers.each(vm.beforeBody, fillLineOfText);
13311
13312			var drawColorBoxes = vm.displayColors;
13313			xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
13314
13315			// Draw body lines now
13316			helpers.each(body, function(bodyItem, i) {
13317				var textColor = mergeOpacity(vm.labelTextColors[i], opacity);
13318				ctx.fillStyle = textColor;
13319				helpers.each(bodyItem.before, fillLineOfText);
13320
13321				helpers.each(bodyItem.lines, function(line) {
13322					// Draw Legend-like boxes if needed
13323					if (drawColorBoxes) {
13324						// Fill a white rect so that colours merge nicely if the opacity is < 1
13325						ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
13326						ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
13327
13328						// Border
13329						ctx.lineWidth = 1;
13330						ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
13331						ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
13332
13333						// Inner square
13334						ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
13335						ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
13336						ctx.fillStyle = textColor;
13337					}
13338
13339					fillLineOfText(line);
13340				});
13341
13342				helpers.each(bodyItem.after, fillLineOfText);
13343			});
13344
13345			// Reset back to 0 for after body
13346			xLinePadding = 0;
13347
13348			// After body lines
13349			helpers.each(vm.afterBody, fillLineOfText);
13350			pt.y -= bodySpacing; // Remove last body spacing
13351		},
13352		drawFooter: function(pt, vm, ctx, opacity) {
13353			var footer = vm.footer;
13354
13355			if (footer.length) {
13356				pt.y += vm.footerMarginTop;
13357
13358				ctx.textAlign = vm._footerAlign;
13359				ctx.textBaseline = 'top';
13360
13361				ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
13362				ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
13363
13364				helpers.each(footer, function(line) {
13365					ctx.fillText(line, pt.x, pt.y);
13366					pt.y += vm.footerFontSize + vm.footerSpacing;
13367				});
13368			}
13369		},
13370		drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
13371			ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
13372			ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
13373			ctx.lineWidth = vm.borderWidth;
13374			var xAlign = vm.xAlign;
13375			var yAlign = vm.yAlign;
13376			var x = pt.x;
13377			var y = pt.y;
13378			var width = tooltipSize.width;
13379			var height = tooltipSize.height;
13380			var radius = vm.cornerRadius;
13381
13382			ctx.beginPath();
13383			ctx.moveTo(x + radius, y);
13384			if (yAlign === 'top') {
13385				this.drawCaret(pt, tooltipSize);
13386			}
13387			ctx.lineTo(x + width - radius, y);
13388			ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
13389			if (yAlign === 'center' && xAlign === 'right') {
13390				this.drawCaret(pt, tooltipSize);
13391			}
13392			ctx.lineTo(x + width, y + height - radius);
13393			ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
13394			if (yAlign === 'bottom') {
13395				this.drawCaret(pt, tooltipSize);
13396			}
13397			ctx.lineTo(x + radius, y + height);
13398			ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
13399			if (yAlign === 'center' && xAlign === 'left') {
13400				this.drawCaret(pt, tooltipSize);
13401			}
13402			ctx.lineTo(x, y + radius);
13403			ctx.quadraticCurveTo(x, y, x + radius, y);
13404			ctx.closePath();
13405
13406			ctx.fill();
13407
13408			if (vm.borderWidth > 0) {
13409				ctx.stroke();
13410			}
13411		},
13412		draw: function() {
13413			var ctx = this._chart.ctx;
13414			var vm = this._view;
13415
13416			if (vm.opacity === 0) {
13417				return;
13418			}
13419
13420			var tooltipSize = {
13421				width: vm.width,
13422				height: vm.height
13423			};
13424			var pt = {
13425				x: vm.x,
13426				y: vm.y
13427			};
13428
13429			// IE11/Edge does not like very small opacities, so snap to 0
13430			var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
13431
13432			// Truthy/falsey value for empty tooltip
13433			var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
13434
13435			if (this._options.enabled && hasTooltipContent) {
13436				// Draw Background
13437				this.drawBackground(pt, vm, ctx, tooltipSize, opacity);
13438
13439				// Draw Title, Body, and Footer
13440				pt.x += vm.xPadding;
13441				pt.y += vm.yPadding;
13442
13443				// Titles
13444				this.drawTitle(pt, vm, ctx, opacity);
13445
13446				// Body
13447				this.drawBody(pt, vm, ctx, opacity);
13448
13449				// Footer
13450				this.drawFooter(pt, vm, ctx, opacity);
13451			}
13452		},
13453
13454		/**
13455		 * Handle an event
13456		 * @private
13457		 * @param {IEvent} event - The event to handle
13458		 * @returns {Boolean} true if the tooltip changed
13459		 */
13460		handleEvent: function(e) {
13461			var me = this;
13462			var options = me._options;
13463			var changed = false;
13464
13465			me._lastActive = me._lastActive || [];
13466
13467			// Find Active Elements for tooltips
13468			if (e.type === 'mouseout') {
13469				me._active = [];
13470			} else {
13471				me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
13472			}
13473
13474			// Remember Last Actives
13475			changed = !helpers.arrayEquals(me._active, me._lastActive);
13476
13477			// Only handle target event on tooltip change
13478			if (changed) {
13479				me._lastActive = me._active;
13480
13481				if (options.enabled || options.custom) {
13482					me._eventPosition = {
13483						x: e.x,
13484						y: e.y
13485					};
13486
13487					me.update(true);
13488					me.pivot();
13489				}
13490			}
13491
13492			return changed;
13493		}
13494	});
13495
13496	/**
13497	 * @namespace Chart.Tooltip.positioners
13498	 */
13499	Chart.Tooltip.positioners = {
13500		/**
13501		 * Average mode places the tooltip at the average position of the elements shown
13502		 * @function Chart.Tooltip.positioners.average
13503		 * @param elements {ChartElement[]} the elements being displayed in the tooltip
13504		 * @returns {Point} tooltip position
13505		 */
13506		average: function(elements) {
13507			if (!elements.length) {
13508				return false;
13509			}
13510
13511			var i, len;
13512			var x = 0;
13513			var y = 0;
13514			var count = 0;
13515
13516			for (i = 0, len = elements.length; i < len; ++i) {
13517				var el = elements[i];
13518				if (el && el.hasValue()) {
13519					var pos = el.tooltipPosition();
13520					x += pos.x;
13521					y += pos.y;
13522					++count;
13523				}
13524			}
13525
13526			return {
13527				x: Math.round(x / count),
13528				y: Math.round(y / count)
13529			};
13530		},
13531
13532		/**
13533		 * Gets the tooltip position nearest of the item nearest to the event position
13534		 * @function Chart.Tooltip.positioners.nearest
13535		 * @param elements {Chart.Element[]} the tooltip elements
13536		 * @param eventPosition {Point} the position of the event in canvas coordinates
13537		 * @returns {Point} the tooltip position
13538		 */
13539		nearest: function(elements, eventPosition) {
13540			var x = eventPosition.x;
13541			var y = eventPosition.y;
13542			var minDistance = Number.POSITIVE_INFINITY;
13543			var i, len, nearestElement;
13544
13545			for (i = 0, len = elements.length; i < len; ++i) {
13546				var el = elements[i];
13547				if (el && el.hasValue()) {
13548					var center = el.getCenterPoint();
13549					var d = helpers.distanceBetweenPoints(eventPosition, center);
13550
13551					if (d < minDistance) {
13552						minDistance = d;
13553						nearestElement = el;
13554					}
13555				}
13556			}
13557
13558			if (nearestElement) {
13559				var tp = nearestElement.tooltipPosition();
13560				x = tp.x;
13561				y = tp.y;
13562			}
13563
13564			return {
13565				x: x,
13566				y: y
13567			};
13568		}
13569	};
13570};
13571
13572},{"25":25,"26":26,"45":45}],36:[function(require,module,exports){
13573'use strict';
13574
13575var defaults = require(25);
13576var Element = require(26);
13577var helpers = require(45);
13578
13579defaults._set('global', {
13580	elements: {
13581		arc: {
13582			backgroundColor: defaults.global.defaultColor,
13583			borderColor: '#fff',
13584			borderWidth: 2
13585		}
13586	}
13587});
13588
13589module.exports = Element.extend({
13590	inLabelRange: function(mouseX) {
13591		var vm = this._view;
13592
13593		if (vm) {
13594			return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
13595		}
13596		return false;
13597	},
13598
13599	inRange: function(chartX, chartY) {
13600		var vm = this._view;
13601
13602		if (vm) {
13603			var pointRelativePosition = helpers.getAngleFromPoint(vm, {x: chartX, y: chartY});
13604			var	angle = pointRelativePosition.angle;
13605			var distance = pointRelativePosition.distance;
13606
13607			// Sanitise angle range
13608			var startAngle = vm.startAngle;
13609			var endAngle = vm.endAngle;
13610			while (endAngle < startAngle) {
13611				endAngle += 2.0 * Math.PI;
13612			}
13613			while (angle > endAngle) {
13614				angle -= 2.0 * Math.PI;
13615			}
13616			while (angle < startAngle) {
13617				angle += 2.0 * Math.PI;
13618			}
13619
13620			// Check if within the range of the open/close angle
13621			var betweenAngles = (angle >= startAngle && angle <= endAngle);
13622			var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
13623
13624			return (betweenAngles && withinRadius);
13625		}
13626		return false;
13627	},
13628
13629	getCenterPoint: function() {
13630		var vm = this._view;
13631		var halfAngle = (vm.startAngle + vm.endAngle) / 2;
13632		var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
13633		return {
13634			x: vm.x + Math.cos(halfAngle) * halfRadius,
13635			y: vm.y + Math.sin(halfAngle) * halfRadius
13636		};
13637	},
13638
13639	getArea: function() {
13640		var vm = this._view;
13641		return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
13642	},
13643
13644	tooltipPosition: function() {
13645		var vm = this._view;
13646		var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
13647		var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
13648
13649		return {
13650			x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
13651			y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
13652		};
13653	},
13654
13655	draw: function() {
13656		var ctx = this._chart.ctx;
13657		var vm = this._view;
13658		var sA = vm.startAngle;
13659		var eA = vm.endAngle;
13660
13661		ctx.beginPath();
13662
13663		ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
13664		ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
13665
13666		ctx.closePath();
13667		ctx.strokeStyle = vm.borderColor;
13668		ctx.lineWidth = vm.borderWidth;
13669
13670		ctx.fillStyle = vm.backgroundColor;
13671
13672		ctx.fill();
13673		ctx.lineJoin = 'bevel';
13674
13675		if (vm.borderWidth) {
13676			ctx.stroke();
13677		}
13678	}
13679});
13680
13681},{"25":25,"26":26,"45":45}],37:[function(require,module,exports){
13682'use strict';
13683
13684var defaults = require(25);
13685var Element = require(26);
13686var helpers = require(45);
13687
13688var globalDefaults = defaults.global;
13689
13690defaults._set('global', {
13691	elements: {
13692		line: {
13693			tension: 0.4,
13694			backgroundColor: globalDefaults.defaultColor,
13695			borderWidth: 3,
13696			borderColor: globalDefaults.defaultColor,
13697			borderCapStyle: 'butt',
13698			borderDash: [],
13699			borderDashOffset: 0.0,
13700			borderJoinStyle: 'miter',
13701			capBezierPoints: true,
13702			fill: true, // do we fill in the area between the line and its base axis
13703		}
13704	}
13705});
13706
13707module.exports = Element.extend({
13708	draw: function() {
13709		var me = this;
13710		var vm = me._view;
13711		var ctx = me._chart.ctx;
13712		var spanGaps = vm.spanGaps;
13713		var points = me._children.slice(); // clone array
13714		var globalOptionLineElements = globalDefaults.elements.line;
13715		var lastDrawnIndex = -1;
13716		var index, current, previous, currentVM;
13717
13718		// If we are looping, adding the first point again
13719		if (me._loop && points.length) {
13720			points.push(points[0]);
13721		}
13722
13723		ctx.save();
13724
13725		// Stroke Line Options
13726		ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
13727
13728		// IE 9 and 10 do not support line dash
13729		if (ctx.setLineDash) {
13730			ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
13731		}
13732
13733		ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
13734		ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
13735		ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
13736		ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
13737
13738		// Stroke Line
13739		ctx.beginPath();
13740		lastDrawnIndex = -1;
13741
13742		for (index = 0; index < points.length; ++index) {
13743			current = points[index];
13744			previous = helpers.previousItem(points, index);
13745			currentVM = current._view;
13746
13747			// First point moves to it's starting position no matter what
13748			if (index === 0) {
13749				if (!currentVM.skip) {
13750					ctx.moveTo(currentVM.x, currentVM.y);
13751					lastDrawnIndex = index;
13752				}
13753			} else {
13754				previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
13755
13756				if (!currentVM.skip) {
13757					if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
13758						// There was a gap and this is the first point after the gap
13759						ctx.moveTo(currentVM.x, currentVM.y);
13760					} else {
13761						// Line to next point
13762						helpers.canvas.lineTo(ctx, previous._view, current._view);
13763					}
13764					lastDrawnIndex = index;
13765				}
13766			}
13767		}
13768
13769		ctx.stroke();
13770		ctx.restore();
13771	}
13772});
13773
13774},{"25":25,"26":26,"45":45}],38:[function(require,module,exports){
13775'use strict';
13776
13777var defaults = require(25);
13778var Element = require(26);
13779var helpers = require(45);
13780
13781var defaultColor = defaults.global.defaultColor;
13782
13783defaults._set('global', {
13784	elements: {
13785		point: {
13786			radius: 3,
13787			pointStyle: 'circle',
13788			backgroundColor: defaultColor,
13789			borderColor: defaultColor,
13790			borderWidth: 1,
13791			// Hover
13792			hitRadius: 1,
13793			hoverRadius: 4,
13794			hoverBorderWidth: 1
13795		}
13796	}
13797});
13798
13799function xRange(mouseX) {
13800	var vm = this._view;
13801	return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false;
13802}
13803
13804function yRange(mouseY) {
13805	var vm = this._view;
13806	return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false;
13807}
13808
13809module.exports = Element.extend({
13810	inRange: function(mouseX, mouseY) {
13811		var vm = this._view;
13812		return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
13813	},
13814
13815	inLabelRange: xRange,
13816	inXRange: xRange,
13817	inYRange: yRange,
13818
13819	getCenterPoint: function() {
13820		var vm = this._view;
13821		return {
13822			x: vm.x,
13823			y: vm.y
13824		};
13825	},
13826
13827	getArea: function() {
13828		return Math.PI * Math.pow(this._view.radius, 2);
13829	},
13830
13831	tooltipPosition: function() {
13832		var vm = this._view;
13833		return {
13834			x: vm.x,
13835			y: vm.y,
13836			padding: vm.radius + vm.borderWidth
13837		};
13838	},
13839
13840	draw: function(chartArea) {
13841		var vm = this._view;
13842		var model = this._model;
13843		var ctx = this._chart.ctx;
13844		var pointStyle = vm.pointStyle;
13845		var radius = vm.radius;
13846		var x = vm.x;
13847		var y = vm.y;
13848		var color = helpers.color;
13849		var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
13850		var ratio = 0;
13851
13852		if (vm.skip) {
13853			return;
13854		}
13855
13856		ctx.strokeStyle = vm.borderColor || defaultColor;
13857		ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth);
13858		ctx.fillStyle = vm.backgroundColor || defaultColor;
13859
13860		// Cliping for Points.
13861		// going out from inner charArea?
13862		if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right * errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom * errMargin < model.y))) {
13863			// Point fade out
13864			if (model.x < chartArea.left) {
13865				ratio = (x - model.x) / (chartArea.left - model.x);
13866			} else if (chartArea.right * errMargin < model.x) {
13867				ratio = (model.x - x) / (model.x - chartArea.right);
13868			} else if (model.y < chartArea.top) {
13869				ratio = (y - model.y) / (chartArea.top - model.y);
13870			} else if (chartArea.bottom * errMargin < model.y) {
13871				ratio = (model.y - y) / (model.y - chartArea.bottom);
13872			}
13873			ratio = Math.round(ratio * 100) / 100;
13874			ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
13875			ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
13876		}
13877
13878		helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y);
13879	}
13880});
13881
13882},{"25":25,"26":26,"45":45}],39:[function(require,module,exports){
13883'use strict';
13884
13885var defaults = require(25);
13886var Element = require(26);
13887
13888defaults._set('global', {
13889	elements: {
13890		rectangle: {
13891			backgroundColor: defaults.global.defaultColor,
13892			borderColor: defaults.global.defaultColor,
13893			borderSkipped: 'bottom',
13894			borderWidth: 0
13895		}
13896	}
13897});
13898
13899function isVertical(bar) {
13900	return bar._view.width !== undefined;
13901}
13902
13903/**
13904 * Helper function to get the bounds of the bar regardless of the orientation
13905 * @param bar {Chart.Element.Rectangle} the bar
13906 * @return {Bounds} bounds of the bar
13907 * @private
13908 */
13909function getBarBounds(bar) {
13910	var vm = bar._view;
13911	var x1, x2, y1, y2;
13912
13913	if (isVertical(bar)) {
13914		// vertical
13915		var halfWidth = vm.width / 2;
13916		x1 = vm.x - halfWidth;
13917		x2 = vm.x + halfWidth;
13918		y1 = Math.min(vm.y, vm.base);
13919		y2 = Math.max(vm.y, vm.base);
13920	} else {
13921		// horizontal bar
13922		var halfHeight = vm.height / 2;
13923		x1 = Math.min(vm.x, vm.base);
13924		x2 = Math.max(vm.x, vm.base);
13925		y1 = vm.y - halfHeight;
13926		y2 = vm.y + halfHeight;
13927	}
13928
13929	return {
13930		left: x1,
13931		top: y1,
13932		right: x2,
13933		bottom: y2
13934	};
13935}
13936
13937module.exports = Element.extend({
13938	draw: function() {
13939		var ctx = this._chart.ctx;
13940		var vm = this._view;
13941		var left, right, top, bottom, signX, signY, borderSkipped;
13942		var borderWidth = vm.borderWidth;
13943
13944		if (!vm.horizontal) {
13945			// bar
13946			left = vm.x - vm.width / 2;
13947			right = vm.x + vm.width / 2;
13948			top = vm.y;
13949			bottom = vm.base;
13950			signX = 1;
13951			signY = bottom > top ? 1 : -1;
13952			borderSkipped = vm.borderSkipped || 'bottom';
13953		} else {
13954			// horizontal bar
13955			left = vm.base;
13956			right = vm.x;
13957			top = vm.y - vm.height / 2;
13958			bottom = vm.y + vm.height / 2;
13959			signX = right > left ? 1 : -1;
13960			signY = 1;
13961			borderSkipped = vm.borderSkipped || 'left';
13962		}
13963
13964		// Canvas doesn't allow us to stroke inside the width so we can
13965		// adjust the sizes to fit if we're setting a stroke on the line
13966		if (borderWidth) {
13967			// borderWidth shold be less than bar width and bar height.
13968			var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
13969			borderWidth = borderWidth > barSize ? barSize : borderWidth;
13970			var halfStroke = borderWidth / 2;
13971			// Adjust borderWidth when bar top position is near vm.base(zero).
13972			var borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
13973			var borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
13974			var borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
13975			var borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
13976			// not become a vertical line?
13977			if (borderLeft !== borderRight) {
13978				top = borderTop;
13979				bottom = borderBottom;
13980			}
13981			// not become a horizontal line?
13982			if (borderTop !== borderBottom) {
13983				left = borderLeft;
13984				right = borderRight;
13985			}
13986		}
13987
13988		ctx.beginPath();
13989		ctx.fillStyle = vm.backgroundColor;
13990		ctx.strokeStyle = vm.borderColor;
13991		ctx.lineWidth = borderWidth;
13992
13993		// Corner points, from bottom-left to bottom-right clockwise
13994		// | 1 2 |
13995		// | 0 3 |
13996		var corners = [
13997			[left, bottom],
13998			[left, top],
13999			[right, top],
14000			[right, bottom]
14001		];
14002
14003		// Find first (starting) corner with fallback to 'bottom'
14004		var borders = ['bottom', 'left', 'top', 'right'];
14005		var startCorner = borders.indexOf(borderSkipped, 0);
14006		if (startCorner === -1) {
14007			startCorner = 0;
14008		}
14009
14010		function cornerAt(index) {
14011			return corners[(startCorner + index) % 4];
14012		}
14013
14014		// Draw rectangle from 'startCorner'
14015		var corner = cornerAt(0);
14016		ctx.moveTo(corner[0], corner[1]);
14017
14018		for (var i = 1; i < 4; i++) {
14019			corner = cornerAt(i);
14020			ctx.lineTo(corner[0], corner[1]);
14021		}
14022
14023		ctx.fill();
14024		if (borderWidth) {
14025			ctx.stroke();
14026		}
14027	},
14028
14029	height: function() {
14030		var vm = this._view;
14031		return vm.base - vm.y;
14032	},
14033
14034	inRange: function(mouseX, mouseY) {
14035		var inRange = false;
14036
14037		if (this._view) {
14038			var bounds = getBarBounds(this);
14039			inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
14040		}
14041
14042		return inRange;
14043	},
14044
14045	inLabelRange: function(mouseX, mouseY) {
14046		var me = this;
14047		if (!me._view) {
14048			return false;
14049		}
14050
14051		var inRange = false;
14052		var bounds = getBarBounds(me);
14053
14054		if (isVertical(me)) {
14055			inRange = mouseX >= bounds.left && mouseX <= bounds.right;
14056		} else {
14057			inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
14058		}
14059
14060		return inRange;
14061	},
14062
14063	inXRange: function(mouseX) {
14064		var bounds = getBarBounds(this);
14065		return mouseX >= bounds.left && mouseX <= bounds.right;
14066	},
14067
14068	inYRange: function(mouseY) {
14069		var bounds = getBarBounds(this);
14070		return mouseY >= bounds.top && mouseY <= bounds.bottom;
14071	},
14072
14073	getCenterPoint: function() {
14074		var vm = this._view;
14075		var x, y;
14076		if (isVertical(this)) {
14077			x = vm.x;
14078			y = (vm.y + vm.base) / 2;
14079		} else {
14080			x = (vm.x + vm.base) / 2;
14081			y = vm.y;
14082		}
14083
14084		return {x: x, y: y};
14085	},
14086
14087	getArea: function() {
14088		var vm = this._view;
14089		return vm.width * Math.abs(vm.y - vm.base);
14090	},
14091
14092	tooltipPosition: function() {
14093		var vm = this._view;
14094		return {
14095			x: vm.x,
14096			y: vm.y
14097		};
14098	}
14099});
14100
14101},{"25":25,"26":26}],40:[function(require,module,exports){
14102'use strict';
14103
14104module.exports = {};
14105module.exports.Arc = require(36);
14106module.exports.Line = require(37);
14107module.exports.Point = require(38);
14108module.exports.Rectangle = require(39);
14109
14110},{"36":36,"37":37,"38":38,"39":39}],41:[function(require,module,exports){
14111'use strict';
14112
14113var helpers = require(42);
14114
14115/**
14116 * @namespace Chart.helpers.canvas
14117 */
14118var exports = module.exports = {
14119	/**
14120	 * Clears the entire canvas associated to the given `chart`.
14121	 * @param {Chart} chart - The chart for which to clear the canvas.
14122	 */
14123	clear: function(chart) {
14124		chart.ctx.clearRect(0, 0, chart.width, chart.height);
14125	},
14126
14127	/**
14128	 * Creates a "path" for a rectangle with rounded corners at position (x, y) with a
14129	 * given size (width, height) and the same `radius` for all corners.
14130	 * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
14131	 * @param {Number} x - The x axis of the coordinate for the rectangle starting point.
14132	 * @param {Number} y - The y axis of the coordinate for the rectangle starting point.
14133	 * @param {Number} width - The rectangle's width.
14134	 * @param {Number} height - The rectangle's height.
14135	 * @param {Number} radius - The rounded amount (in pixels) for the four corners.
14136	 * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?
14137	 */
14138	roundedRect: function(ctx, x, y, width, height, radius) {
14139		if (radius) {
14140			var rx = Math.min(radius, width / 2);
14141			var ry = Math.min(radius, height / 2);
14142
14143			ctx.moveTo(x + rx, y);
14144			ctx.lineTo(x + width - rx, y);
14145			ctx.quadraticCurveTo(x + width, y, x + width, y + ry);
14146			ctx.lineTo(x + width, y + height - ry);
14147			ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height);
14148			ctx.lineTo(x + rx, y + height);
14149			ctx.quadraticCurveTo(x, y + height, x, y + height - ry);
14150			ctx.lineTo(x, y + ry);
14151			ctx.quadraticCurveTo(x, y, x + rx, y);
14152		} else {
14153			ctx.rect(x, y, width, height);
14154		}
14155	},
14156
14157	drawPoint: function(ctx, style, radius, x, y) {
14158		var type, edgeLength, xOffset, yOffset, height, size;
14159
14160		if (style && typeof style === 'object') {
14161			type = style.toString();
14162			if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
14163				ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
14164				return;
14165			}
14166		}
14167
14168		if (isNaN(radius) || radius <= 0) {
14169			return;
14170		}
14171
14172		switch (style) {
14173		// Default includes circle
14174		default:
14175			ctx.beginPath();
14176			ctx.arc(x, y, radius, 0, Math.PI * 2);
14177			ctx.closePath();
14178			ctx.fill();
14179			break;
14180		case 'triangle':
14181			ctx.beginPath();
14182			edgeLength = 3 * radius / Math.sqrt(3);
14183			height = edgeLength * Math.sqrt(3) / 2;
14184			ctx.moveTo(x - edgeLength / 2, y + height / 3);
14185			ctx.lineTo(x + edgeLength / 2, y + height / 3);
14186			ctx.lineTo(x, y - 2 * height / 3);
14187			ctx.closePath();
14188			ctx.fill();
14189			break;
14190		case 'rect':
14191			size = 1 / Math.SQRT2 * radius;
14192			ctx.beginPath();
14193			ctx.fillRect(x - size, y - size, 2 * size, 2 * size);
14194			ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
14195			break;
14196		case 'rectRounded':
14197			var offset = radius / Math.SQRT2;
14198			var leftX = x - offset;
14199			var topY = y - offset;
14200			var sideSize = Math.SQRT2 * radius;
14201			ctx.beginPath();
14202			this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2);
14203			ctx.closePath();
14204			ctx.fill();
14205			break;
14206		case 'rectRot':
14207			size = 1 / Math.SQRT2 * radius;
14208			ctx.beginPath();
14209			ctx.moveTo(x - size, y);
14210			ctx.lineTo(x, y + size);
14211			ctx.lineTo(x + size, y);
14212			ctx.lineTo(x, y - size);
14213			ctx.closePath();
14214			ctx.fill();
14215			break;
14216		case 'cross':
14217			ctx.beginPath();
14218			ctx.moveTo(x, y + radius);
14219			ctx.lineTo(x, y - radius);
14220			ctx.moveTo(x - radius, y);
14221			ctx.lineTo(x + radius, y);
14222			ctx.closePath();
14223			break;
14224		case 'crossRot':
14225			ctx.beginPath();
14226			xOffset = Math.cos(Math.PI / 4) * radius;
14227			yOffset = Math.sin(Math.PI / 4) * radius;
14228			ctx.moveTo(x - xOffset, y - yOffset);
14229			ctx.lineTo(x + xOffset, y + yOffset);
14230			ctx.moveTo(x - xOffset, y + yOffset);
14231			ctx.lineTo(x + xOffset, y - yOffset);
14232			ctx.closePath();
14233			break;
14234		case 'star':
14235			ctx.beginPath();
14236			ctx.moveTo(x, y + radius);
14237			ctx.lineTo(x, y - radius);
14238			ctx.moveTo(x - radius, y);
14239			ctx.lineTo(x + radius, y);
14240			xOffset = Math.cos(Math.PI / 4) * radius;
14241			yOffset = Math.sin(Math.PI / 4) * radius;
14242			ctx.moveTo(x - xOffset, y - yOffset);
14243			ctx.lineTo(x + xOffset, y + yOffset);
14244			ctx.moveTo(x - xOffset, y + yOffset);
14245			ctx.lineTo(x + xOffset, y - yOffset);
14246			ctx.closePath();
14247			break;
14248		case 'line':
14249			ctx.beginPath();
14250			ctx.moveTo(x - radius, y);
14251			ctx.lineTo(x + radius, y);
14252			ctx.closePath();
14253			break;
14254		case 'dash':
14255			ctx.beginPath();
14256			ctx.moveTo(x, y);
14257			ctx.lineTo(x + radius, y);
14258			ctx.closePath();
14259			break;
14260		}
14261
14262		ctx.stroke();
14263	},
14264
14265	clipArea: function(ctx, area) {
14266		ctx.save();
14267		ctx.beginPath();
14268		ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
14269		ctx.clip();
14270	},
14271
14272	unclipArea: function(ctx) {
14273		ctx.restore();
14274	},
14275
14276	lineTo: function(ctx, previous, target, flip) {
14277		if (target.steppedLine) {
14278			if ((target.steppedLine === 'after' && !flip) || (target.steppedLine !== 'after' && flip)) {
14279				ctx.lineTo(previous.x, target.y);
14280			} else {
14281				ctx.lineTo(target.x, previous.y);
14282			}
14283			ctx.lineTo(target.x, target.y);
14284			return;
14285		}
14286
14287		if (!target.tension) {
14288			ctx.lineTo(target.x, target.y);
14289			return;
14290		}
14291
14292		ctx.bezierCurveTo(
14293			flip ? previous.controlPointPreviousX : previous.controlPointNextX,
14294			flip ? previous.controlPointPreviousY : previous.controlPointNextY,
14295			flip ? target.controlPointNextX : target.controlPointPreviousX,
14296			flip ? target.controlPointNextY : target.controlPointPreviousY,
14297			target.x,
14298			target.y);
14299	}
14300};
14301
14302// DEPRECATIONS
14303
14304/**
14305 * Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
14306 * @namespace Chart.helpers.clear
14307 * @deprecated since version 2.7.0
14308 * @todo remove at version 3
14309 * @private
14310 */
14311helpers.clear = exports.clear;
14312
14313/**
14314 * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
14315 * @namespace Chart.helpers.drawRoundedRectangle
14316 * @deprecated since version 2.7.0
14317 * @todo remove at version 3
14318 * @private
14319 */
14320helpers.drawRoundedRectangle = function(ctx) {
14321	ctx.beginPath();
14322	exports.roundedRect.apply(exports, arguments);
14323	ctx.closePath();
14324};
14325
14326},{"42":42}],42:[function(require,module,exports){
14327'use strict';
14328
14329/**
14330 * @namespace Chart.helpers
14331 */
14332var helpers = {
14333	/**
14334	 * An empty function that can be used, for example, for optional callback.
14335	 */
14336	noop: function() {},
14337
14338	/**
14339	 * Returns a unique id, sequentially generated from a global variable.
14340	 * @returns {Number}
14341	 * @function
14342	 */
14343	uid: (function() {
14344		var id = 0;
14345		return function() {
14346			return id++;
14347		};
14348	}()),
14349
14350	/**
14351	 * Returns true if `value` is neither null nor undefined, else returns false.
14352	 * @param {*} value - The value to test.
14353	 * @returns {Boolean}
14354	 * @since 2.7.0
14355	 */
14356	isNullOrUndef: function(value) {
14357		return value === null || typeof value === 'undefined';
14358	},
14359
14360	/**
14361	 * Returns true if `value` is an array, else returns false.
14362	 * @param {*} value - The value to test.
14363	 * @returns {Boolean}
14364	 * @function
14365	 */
14366	isArray: Array.isArray ? Array.isArray : function(value) {
14367		return Object.prototype.toString.call(value) === '[object Array]';
14368	},
14369
14370	/**
14371	 * Returns true if `value` is an object (excluding null), else returns false.
14372	 * @param {*} value - The value to test.
14373	 * @returns {Boolean}
14374	 * @since 2.7.0
14375	 */
14376	isObject: function(value) {
14377		return value !== null && Object.prototype.toString.call(value) === '[object Object]';
14378	},
14379
14380	/**
14381	 * Returns `value` if defined, else returns `defaultValue`.
14382	 * @param {*} value - The value to return if defined.
14383	 * @param {*} defaultValue - The value to return if `value` is undefined.
14384	 * @returns {*}
14385	 */
14386	valueOrDefault: function(value, defaultValue) {
14387		return typeof value === 'undefined' ? defaultValue : value;
14388	},
14389
14390	/**
14391	 * Returns value at the given `index` in array if defined, else returns `defaultValue`.
14392	 * @param {Array} value - The array to lookup for value at `index`.
14393	 * @param {Number} index - The index in `value` to lookup for value.
14394	 * @param {*} defaultValue - The value to return if `value[index]` is undefined.
14395	 * @returns {*}
14396	 */
14397	valueAtIndexOrDefault: function(value, index, defaultValue) {
14398		return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
14399	},
14400
14401	/**
14402	 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
14403	 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
14404	 * @param {Function} fn - The function to call.
14405	 * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
14406	 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
14407	 * @returns {*}
14408	 */
14409	callback: function(fn, args, thisArg) {
14410		if (fn && typeof fn.call === 'function') {
14411			return fn.apply(thisArg, args);
14412		}
14413	},
14414
14415	/**
14416	 * Note(SB) for performance sake, this method should only be used when loopable type
14417	 * is unknown or in none intensive code (not called often and small loopable). Else
14418	 * it's preferable to use a regular for() loop and save extra function calls.
14419	 * @param {Object|Array} loopable - The object or array to be iterated.
14420	 * @param {Function} fn - The function to call for each item.
14421	 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
14422	 * @param {Boolean} [reverse] - If true, iterates backward on the loopable.
14423	 */
14424	each: function(loopable, fn, thisArg, reverse) {
14425		var i, len, keys;
14426		if (helpers.isArray(loopable)) {
14427			len = loopable.length;
14428			if (reverse) {
14429				for (i = len - 1; i >= 0; i--) {
14430					fn.call(thisArg, loopable[i], i);
14431				}
14432			} else {
14433				for (i = 0; i < len; i++) {
14434					fn.call(thisArg, loopable[i], i);
14435				}
14436			}
14437		} else if (helpers.isObject(loopable)) {
14438			keys = Object.keys(loopable);
14439			len = keys.length;
14440			for (i = 0; i < len; i++) {
14441				fn.call(thisArg, loopable[keys[i]], keys[i]);
14442			}
14443		}
14444	},
14445
14446	/**
14447	 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
14448	 * @see http://stackoverflow.com/a/14853974
14449	 * @param {Array} a0 - The array to compare
14450	 * @param {Array} a1 - The array to compare
14451	 * @returns {Boolean}
14452	 */
14453	arrayEquals: function(a0, a1) {
14454		var i, ilen, v0, v1;
14455
14456		if (!a0 || !a1 || a0.length !== a1.length) {
14457			return false;
vendor: 10,367 bytes, lines 14458-14911
14458		}
14459
14460		for (i = 0, ilen = a0.length; i < ilen; ++i) {
14461			v0 = a0[i];
14462			v1 = a1[i];
14463
14464			if (v0 instanceof Array && v1 instanceof Array) {
14465				if (!helpers.arrayEquals(v0, v1)) {
14466					return false;
14467				}
14468			} else if (v0 !== v1) {
14469				// NOTE: two different object instances will never be equal: {x:20} != {x:20}
14470				return false;
14471			}
14472		}
14473
14474		return true;
14475	},
14476
14477	/**
14478	 * Returns a deep copy of `source` without keeping references on objects and arrays.
14479	 * @param {*} source - The value to clone.
14480	 * @returns {*}
14481	 */
14482	clone: function(source) {
14483		if (helpers.isArray(source)) {
14484			return source.map(helpers.clone);
14485		}
14486
14487		if (helpers.isObject(source)) {
14488			var target = {};
14489			var keys = Object.keys(source);
14490			var klen = keys.length;
14491			var k = 0;
14492
14493			for (; k < klen; ++k) {
14494				target[keys[k]] = helpers.clone(source[keys[k]]);
14495			}
14496
14497			return target;
14498		}
14499
14500		return source;
14501	},
14502
14503	/**
14504	 * The default merger when Chart.helpers.merge is called without merger option.
14505	 * Note(SB): this method is also used by configMerge and scaleMerge as fallback.
14506	 * @private
14507	 */
14508	_merger: function(key, target, source, options) {
14509		var tval = target[key];
14510		var sval = source[key];
14511
14512		if (helpers.isObject(tval) && helpers.isObject(sval)) {
14513			helpers.merge(tval, sval, options);
14514		} else {
14515			target[key] = helpers.clone(sval);
14516		}
14517	},
14518
14519	/**
14520	 * Merges source[key] in target[key] only if target[key] is undefined.
14521	 * @private
14522	 */
14523	_mergerIf: function(key, target, source) {
14524		var tval = target[key];
14525		var sval = source[key];
14526
14527		if (helpers.isObject(tval) && helpers.isObject(sval)) {
14528			helpers.mergeIf(tval, sval);
14529		} else if (!target.hasOwnProperty(key)) {
14530			target[key] = helpers.clone(sval);
14531		}
14532	},
14533
14534	/**
14535	 * Recursively deep copies `source` properties into `target` with the given `options`.
14536	 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
14537	 * @param {Object} target - The target object in which all sources are merged into.
14538	 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
14539	 * @param {Object} [options] - Merging options:
14540	 * @param {Function} [options.merger] - The merge method (key, target, source, options)
14541	 * @returns {Object} The `target` object.
14542	 */
14543	merge: function(target, source, options) {
14544		var sources = helpers.isArray(source) ? source : [source];
14545		var ilen = sources.length;
14546		var merge, i, keys, klen, k;
14547
14548		if (!helpers.isObject(target)) {
14549			return target;
14550		}
14551
14552		options = options || {};
14553		merge = options.merger || helpers._merger;
14554
14555		for (i = 0; i < ilen; ++i) {
14556			source = sources[i];
14557			if (!helpers.isObject(source)) {
14558				continue;
14559			}
14560
14561			keys = Object.keys(source);
14562			for (k = 0, klen = keys.length; k < klen; ++k) {
14563				merge(keys[k], target, source, options);
14564			}
14565		}
14566
14567		return target;
14568	},
14569
14570	/**
14571	 * Recursively deep copies `source` properties into `target` *only* if not defined in target.
14572	 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
14573	 * @param {Object} target - The target object in which all sources are merged into.
14574	 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
14575	 * @returns {Object} The `target` object.
14576	 */
14577	mergeIf: function(target, source) {
14578		return helpers.merge(target, source, {merger: helpers._mergerIf});
14579	},
14580
14581	/**
14582	 * Applies the contents of two or more objects together into the first object.
14583	 * @param {Object} target - The target object in which all objects are merged into.
14584	 * @param {Object} arg1 - Object containing additional properties to merge in target.
14585	 * @param {Object} argN - Additional objects containing properties to merge in target.
14586	 * @returns {Object} The `target` object.
14587	 */
14588	extend: function(target) {
14589		var setFn = function(value, key) {
14590			target[key] = value;
14591		};
14592		for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
14593			helpers.each(arguments[i], setFn);
14594		}
14595		return target;
14596	},
14597
14598	/**
14599	 * Basic javascript inheritance based on the model created in Backbone.js
14600	 */
14601	inherits: function(extensions) {
14602		var me = this;
14603		var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
14604			return me.apply(this, arguments);
14605		};
14606
14607		var Surrogate = function() {
14608			this.constructor = ChartElement;
14609		};
14610
14611		Surrogate.prototype = me.prototype;
14612		ChartElement.prototype = new Surrogate();
14613		ChartElement.extend = helpers.inherits;
14614
14615		if (extensions) {
14616			helpers.extend(ChartElement.prototype, extensions);
14617		}
14618
14619		ChartElement.__super__ = me.prototype;
14620		return ChartElement;
14621	}
14622};
14623
14624module.exports = helpers;
14625
14626// DEPRECATIONS
14627
14628/**
14629 * Provided for backward compatibility, use Chart.helpers.callback instead.
14630 * @function Chart.helpers.callCallback
14631 * @deprecated since version 2.6.0
14632 * @todo remove at version 3
14633 * @private
14634 */
14635helpers.callCallback = helpers.callback;
14636
14637/**
14638 * Provided for backward compatibility, use Array.prototype.indexOf instead.
14639 * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
14640 * @function Chart.helpers.indexOf
14641 * @deprecated since version 2.7.0
14642 * @todo remove at version 3
14643 * @private
14644 */
14645helpers.indexOf = function(array, item, fromIndex) {
14646	return Array.prototype.indexOf.call(array, item, fromIndex);
14647};
14648
14649/**
14650 * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
14651 * @function Chart.helpers.getValueOrDefault
14652 * @deprecated since version 2.7.0
14653 * @todo remove at version 3
14654 * @private
14655 */
14656helpers.getValueOrDefault = helpers.valueOrDefault;
14657
14658/**
14659 * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
14660 * @function Chart.helpers.getValueAtIndexOrDefault
14661 * @deprecated since version 2.7.0
14662 * @todo remove at version 3
14663 * @private
14664 */
14665helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
14666
14667},{}],43:[function(require,module,exports){
14668'use strict';
14669
14670var helpers = require(42);
14671
14672/**
14673 * Easing functions adapted from Robert Penner's easing equations.
14674 * @namespace Chart.helpers.easingEffects
14675 * @see http://www.robertpenner.com/easing/
14676 */
14677var effects = {
14678	linear: function(t) {
14679		return t;
14680	},
14681
14682	easeInQuad: function(t) {
14683		return t * t;
14684	},
14685
14686	easeOutQuad: function(t) {
14687		return -t * (t - 2);
14688	},
14689
14690	easeInOutQuad: function(t) {
14691		if ((t /= 0.5) < 1) {
14692			return 0.5 * t * t;
14693		}
14694		return -0.5 * ((--t) * (t - 2) - 1);
14695	},
14696
14697	easeInCubic: function(t) {
14698		return t * t * t;
14699	},
14700
14701	easeOutCubic: function(t) {
14702		return (t = t - 1) * t * t + 1;
14703	},
14704
14705	easeInOutCubic: function(t) {
14706		if ((t /= 0.5) < 1) {
14707			return 0.5 * t * t * t;
14708		}
14709		return 0.5 * ((t -= 2) * t * t + 2);
14710	},
14711
14712	easeInQuart: function(t) {
14713		return t * t * t * t;
14714	},
14715
14716	easeOutQuart: function(t) {
14717		return -((t = t - 1) * t * t * t - 1);
14718	},
14719
14720	easeInOutQuart: function(t) {
14721		if ((t /= 0.5) < 1) {
14722			return 0.5 * t * t * t * t;
14723		}
14724		return -0.5 * ((t -= 2) * t * t * t - 2);
14725	},
14726
14727	easeInQuint: function(t) {
14728		return t * t * t * t * t;
14729	},
14730
14731	easeOutQuint: function(t) {
14732		return (t = t - 1) * t * t * t * t + 1;
14733	},
14734
14735	easeInOutQuint: function(t) {
14736		if ((t /= 0.5) < 1) {
14737			return 0.5 * t * t * t * t * t;
14738		}
14739		return 0.5 * ((t -= 2) * t * t * t * t + 2);
14740	},
14741
14742	easeInSine: function(t) {
14743		return -Math.cos(t * (Math.PI / 2)) + 1;
14744	},
14745
14746	easeOutSine: function(t) {
14747		return Math.sin(t * (Math.PI / 2));
14748	},
14749
14750	easeInOutSine: function(t) {
14751		return -0.5 * (Math.cos(Math.PI * t) - 1);
14752	},
14753
14754	easeInExpo: function(t) {
14755		return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
14756	},
14757
14758	easeOutExpo: function(t) {
14759		return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
14760	},
14761
14762	easeInOutExpo: function(t) {
14763		if (t === 0) {
14764			return 0;
14765		}
14766		if (t === 1) {
14767			return 1;
14768		}
14769		if ((t /= 0.5) < 1) {
14770			return 0.5 * Math.pow(2, 10 * (t - 1));
14771		}
14772		return 0.5 * (-Math.pow(2, -10 * --t) + 2);
14773	},
14774
14775	easeInCirc: function(t) {
14776		if (t >= 1) {
14777			return t;
14778		}
14779		return -(Math.sqrt(1 - t * t) - 1);
14780	},
14781
14782	easeOutCirc: function(t) {
14783		return Math.sqrt(1 - (t = t - 1) * t);
14784	},
14785
14786	easeInOutCirc: function(t) {
14787		if ((t /= 0.5) < 1) {
14788			return -0.5 * (Math.sqrt(1 - t * t) - 1);
14789		}
14790		return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
14791	},
14792
14793	easeInElastic: function(t) {
14794		var s = 1.70158;
14795		var p = 0;
14796		var a = 1;
14797		if (t === 0) {
14798			return 0;
14799		}
14800		if (t === 1) {
14801			return 1;
14802		}
14803		if (!p) {
14804			p = 0.3;
14805		}
14806		if (a < 1) {
14807			a = 1;
14808			s = p / 4;
14809		} else {
14810			s = p / (2 * Math.PI) * Math.asin(1 / a);
14811		}
14812		return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
14813	},
14814
14815	easeOutElastic: function(t) {
14816		var s = 1.70158;
14817		var p = 0;
14818		var a = 1;
14819		if (t === 0) {
14820			return 0;
14821		}
14822		if (t === 1) {
14823			return 1;
14824		}
14825		if (!p) {
14826			p = 0.3;
14827		}
14828		if (a < 1) {
14829			a = 1;
14830			s = p / 4;
14831		} else {
14832			s = p / (2 * Math.PI) * Math.asin(1 / a);
14833		}
14834		return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
14835	},
14836
14837	easeInOutElastic: function(t) {
14838		var s = 1.70158;
14839		var p = 0;
14840		var a = 1;
14841		if (t === 0) {
14842			return 0;
14843		}
14844		if ((t /= 0.5) === 2) {
14845			return 1;
14846		}
14847		if (!p) {
14848			p = 0.45;
14849		}
14850		if (a < 1) {
14851			a = 1;
14852			s = p / 4;
14853		} else {
14854			s = p / (2 * Math.PI) * Math.asin(1 / a);
14855		}
14856		if (t < 1) {
14857			return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
14858		}
14859		return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
14860	},
14861	easeInBack: function(t) {
14862		var s = 1.70158;
14863		return t * t * ((s + 1) * t - s);
14864	},
14865
14866	easeOutBack: function(t) {
14867		var s = 1.70158;
14868		return (t = t - 1) * t * ((s + 1) * t + s) + 1;
14869	},
14870
14871	easeInOutBack: function(t) {
14872		var s = 1.70158;
14873		if ((t /= 0.5) < 1) {
14874			return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
14875		}
14876		return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
14877	},
14878
14879	easeInBounce: function(t) {
14880		return 1 - effects.easeOutBounce(1 - t);
14881	},
14882
14883	easeOutBounce: function(t) {
14884		if (t < (1 / 2.75)) {
14885			return 7.5625 * t * t;
14886		}
14887		if (t < (2 / 2.75)) {
14888			return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
14889		}
14890		if (t < (2.5 / 2.75)) {
14891			return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
14892		}
14893		return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
14894	},
14895
14896	easeInOutBounce: function(t) {
14897		if (t < 0.5) {
14898			return effects.easeInBounce(t * 2) * 0.5;
14899		}
14900		return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
14901	}
14902};
14903
14904module.exports = {
14905	effects: effects
14906};
14907
14908// DEPRECATIONS
14909
14910/**
14911 * Provided for backward compatibility, use Chart.helpers.easing.effects instead.
14912 * @function Chart.helpers.easingEffects
14913 * @deprecated since version 2.7.0
14914 * @todo remove at version 3
14915 * @private
14916 */
14917helpers.easingEffects = effects;
14918
14919},{"42":42}],44:[function(require,module,exports){
14920'use strict';
14921
14922var helpers = require(42);
14923
14924/**
14925 * @alias Chart.helpers.options
14926 * @namespace
14927 */
14928module.exports = {
14929	/**
14930	 * Converts the given line height `value` in pixels for a specific font `size`.
14931	 * @param {Number|String} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
14932	 * @param {Number} size - The font size (in pixels) used to resolve relative `value`.
14933	 * @returns {Number} The effective line height in pixels (size * 1.2 if value is invalid).
14934	 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
14935	 * @since 2.7.0
14936	 */
14937	toLineHeight: function(value, size) {
14938		var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
14939		if (!matches || matches[1] === 'normal') {
14940			return size * 1.2;
14941		}
14942
14943		value = +matches[2];
14944
14945		switch (matches[3]) {
14946		case 'px':
14947			return value;
14948		case '%':
14949			value /= 100;
14950			break;
14951		default:
14952			break;
14953		}
14954
14955		return size * value;
14956	},
14957
14958	/**
14959	 * Converts the given value into a padding object with pre-computed width/height.
14960	 * @param {Number|Object} value - If a number, set the value to all TRBL component,
14961	 *  else, if and object, use defined properties and sets undefined ones to 0.
14962	 * @returns {Object} The padding values (top, right, bottom, left, width, height)
14963	 * @since 2.7.0
14964	 */
14965	toPadding: function(value) {
14966		var t, r, b, l;
14967
14968		if (helpers.isObject(value)) {
14969			t = +value.top || 0;
14970			r = +value.right || 0;
14971			b = +value.bottom || 0;
14972			l = +value.left || 0;
14973		} else {
14974			t = r = b = l = +value || 0;
14975		}
14976
14977		return {
14978			top: t,
14979			right: r,
14980			bottom: b,
14981			left: l,
14982			height: t + b,
14983			width: l + r
14984		};
14985	},
14986
14987	/**
14988	 * Evaluates the given `inputs` sequentially and returns the first defined value.
14989	 * @param {Array[]} inputs - An array of values, falling back to the last value.
14990	 * @param {Object} [context] - If defined and the current value is a function, the value
14991	 * is called with `context` as first argument and the result becomes the new input.
14992	 * @param {Number} [index] - If defined and the current value is an array, the value
14993	 * at `index` become the new input.
14994	 * @since 2.7.0
14995	 */
14996	resolve: function(inputs, context, index) {
14997		var i, ilen, value;
14998
14999		for (i = 0, ilen = inputs.length; i < ilen; ++i) {
15000			value = inputs[i];
15001			if (value === undefined) {
15002				continue;
15003			}
15004			if (context !== undefined && typeof value === 'function') {
15005				value = value(context);
15006			}
15007			if (index !== undefined && helpers.isArray(value)) {
15008				value = value[index];
15009			}
15010			if (value !== undefined) {
15011				return value;
15012			}
15013		}
15014	}
15015};
15016
15017},{"42":42}],45:[function(require,module,exports){
15018'use strict';
15019
15020module.exports = require(42);
15021module.exports.easing = require(43);
15022module.exports.canvas = require(41);
15023module.exports.options = require(44);
15024
15025},{"41":41,"42":42,"43":43,"44":44}],46:[function(require,module,exports){
15026/**
15027 * Platform fallback implementation (minimal).
15028 * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939
15029 */
15030
15031module.exports = {
15032	acquireContext: function(item) {
15033		if (item && item.canvas) {
15034			// Support for any object associated to a canvas (including a context2d)
15035			item = item.canvas;
15036		}
15037
15038		return item && item.getContext('2d') || null;
15039	}
15040};
15041
15042},{}],47:[function(require,module,exports){
15043/**
15044 * Chart.Platform implementation for targeting a web browser
15045 */
15046
15047'use strict';
15048
15049var helpers = require(45);
15050
15051var EXPANDO_KEY = '$chartjs';
15052var CSS_PREFIX = 'chartjs-';
15053var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';
15054var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';
15055var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];
15056
15057/**
15058 * DOM event types -> Chart.js event types.
15059 * Note: only events with different types are mapped.
15060 * @see https://developer.mozilla.org/en-US/docs/Web/Events
15061 */
15062var EVENT_TYPES = {
15063	touchstart: 'mousedown',
15064	touchmove: 'mousemove',
15065	touchend: 'mouseup',
15066	pointerenter: 'mouseenter',
15067	pointerdown: 'mousedown',
15068	pointermove: 'mousemove',
15069	pointerup: 'mouseup',
15070	pointerleave: 'mouseout',
15071	pointerout: 'mouseout'
15072};
15073
15074/**
15075 * The "used" size is the final value of a dimension property after all calculations have
15076 * been performed. This method uses the computed style of `element` but returns undefined
15077 * if the computed style is not expressed in pixels. That can happen in some cases where
15078 * `element` has a size relative to its parent and this last one is not yet displayed,
15079 * for example because of `display: none` on a parent node.
15080 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
15081 * @returns {Number} Size in pixels or undefined if unknown.
15082 */
15083function readUsedSize(element, property) {
15084	var value = helpers.getStyle(element, property);
15085	var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
15086	return matches ? Number(matches[1]) : undefined;
15087}
15088
15089/**
15090 * Initializes the canvas style and render size without modifying the canvas display size,
15091 * since responsiveness is handled by the controller.resize() method. The config is used
15092 * to determine the aspect ratio to apply in case no explicit height has been specified.
15093 */
15094function initCanvas(canvas, config) {
15095	var style = canvas.style;
15096
15097	// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
15098	// returns null or '' if no explicit value has been set to the canvas attribute.
15099	var renderHeight = canvas.getAttribute('height');
15100	var renderWidth = canvas.getAttribute('width');
15101
15102	// Chart.js modifies some canvas values that we want to restore on de
15102stroy
15103	canvas[EXPANDO_KEY] = {
15104		initial: {
15105			height: renderHeight,
15106			width: renderWidth,
15107			style: {
15108				display: style.display,
15109				height: style.height,
15110				width: style.width
15111			}
15112		}
15113	};
15114
15115	// Force canvas to display as block to avoid extra space caused by inline
15116	// elements, which would interfere with the responsive resize process.
15117	// https://github.com/chartjs/Chart.js/issues/2538
15118	style.display = style.display || 'block';
15119
15120	if (renderWidth === null || renderWidth === '') {
15121		var displayWidth = readUsedSize(canvas, 'width');
15122		if (displayWidth !== undefined) {
15123			canvas.width = displayWidth;
15124		}
15125	}
15126
15127	if (renderHeight === null || renderHeight === '') {
15128		if (canvas.style.height === '') {
15129			// If no explicit render height and style height, let's apply the aspect ratio,
15130			// which one can be specified by the user but also by charts as default option
15131			// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
15132			canvas.height = canvas.width / (config.options.aspectRatio || 2);
15133		} else {
15134			var displayHeight = readUsedSize(canvas, 'height');
15135			if (displayWidth !== undefined) {
15136				canvas.height = displayHeight;
15137			}
15138		}
15139	}
15140
15141	return canvas;
15142}
15143
15144/**
15145 * Detects support for options object argument in addEventListener.
15146 * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
15147 * @private
15148 */
15149var supportsEventListenerOptions = (function() {
15150	var supports = false;
15151	try {
15152		var options = Object.defineProperty({}, 'passive', {
15153			get: function() {
15154				supports = true;
15155			}
15156		});
15157		window.addEventListener('e', null, options);
15158	} catch (e) {
15159		// continue regardless of error
15160	}
15161	return supports;
15162}());
15163
15164// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
15165// https://github.com/chartjs/Chart.js/issues/4287
15166var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;
15167
15168function addEventListener(node, type, listener) {
15169	node.addEventListener(type, listener, eventListenerOptions);
15170}
15171
15172function removeEventListener(node, type, listener) {
15173	node.removeEventListener(type, listener, eventListenerOptions);
15174}
15175
15176function createEvent(type, chart, x, y, nativeEvent) {
15177	return {
15178		type: type,
15179		chart: chart,
15180		native: nativeEvent || null,
15181		x: x !== undefined ? x : null,
15182		y: y !== undefined ? y : null,
15183	};
15184}
15185
15186function fromNativeEvent(event, chart) {
15187	var type = EVENT_TYPES[event.type] || event.type;
15188	var pos = helpers.getRelativePosition(event, chart);
15189	return createEvent(type, chart, pos.x, pos.y, event);
15190}
15191
15192function throttled(fn, thisArg) {
15193	var ticking = false;
15194	var args = [];
15195
15196	return function() {
15197		args = Array.prototype.slice.call(arguments);
15198		thisArg = thisArg || this;
15199
15200		if (!ticking) {
15201			ticking = true;
15202			helpers.requestAnimFrame.call(window, function() {
15203				ticking = false;
15204				fn.apply(thisArg, args);
15205			});
15206		}
15207	};
15208}
15209
15210// Implementation based on https://github.com/marcj/css-element-queries
15211function createResizer(handler) {
15212	var resizer = document.createElement('div');
15213	var cls = CSS_PREFIX + 'size-monitor';
15214	var maxSize = 1000000;
15215	var style =
15216		'position:absolute;' +
15217		'left:0;' +
15218		'top:0;' +
15219		'right:0;' +
15220		'bottom:0;' +
15221		'overflow:hidden;' +
15222		'pointer-events:none;' +
15223		'visibility:hidden;' +
15224		'z-index:-1;';
15225
15226	resizer.style.cssText = style;
15227	resizer.className = cls;
15228	resizer.innerHTML =
15229		'<div class="' + cls + '-expand" style="' + style + '">' +
15230			'<div style="' +
15231				'position:absolute;' +
15232				'width:' + maxSize + 'px;' +
15233				'height:' + maxSize + 'px;' +
15234				'left:0;' +
15235				'top:0">' +
15236			'</div>' +
15237		'</div>' +
15238		'<div class="' + cls + '-shrink" style="' + style + '">' +
15239			'<div style="' +
15240				'position:absolute;' +
15241				'width:200%;' +
15242				'height:200%;' +
15243				'left:0; ' +
15244				'top:0">' +
15245			'</div>' +
15246		'</div>';
15247
15248	var expand = resizer.childNodes[0];
15249	var shrink = resizer.childNodes[1];
15250
15251	resizer._reset = function() {
15252		expand.scrollLeft = maxSize;
15253		expand.scrollTop = maxSize;
15254		shrink.scrollLeft = maxSize;
15255		shrink.scrollTop = maxSize;
15256	};
15257	var onScroll = function() {
15258		resizer._reset();
15259		handler();
15260	};
15261
15262	addEventListener(expand, 'scroll', onScroll.bind(expand, 'expand'));
15263	addEventListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));
15264
15265	return resizer;
15266}
15267
15268// https://davidwalsh.name/detect-node-insertion
15269function watchForRender(node, handler) {
15270	var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
15271	var proxy = expando.renderProxy = function(e) {
15272		if (e.animationName === CSS_RENDER_ANIMATION) {
15273			handler();
15274		}
15275	};
15276
15277	helpers.each(ANIMATION_START_EVENTS, function(type) {
15278		addEventListener(node, type, proxy);
15279	});
15280
15281	// #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class
15282	// is removed then added back immediately (same animation frame?). Accessing the
15283	// `offsetParent` property will force a reflow and re-evaluate the CSS animation.
15284	// https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics
15285	// https://github.com/chartjs/Chart.js/issues/4737
15286	expando.reflow = !!node.offsetParent;
15287
15288	node.classList.add(CSS_RENDER_MONITOR);
15289}
15290
15291function unwatchForRender(node) {
15292	var expando = node[EXPANDO_KEY] || {};
15293	var proxy = expando.renderProxy;
15294
15295	if (proxy) {
15296		helpers.each(ANIMATION_START_EVENTS, function(type) {
15297			removeEventListener(node, type, proxy);
15298		});
15299
15300		delete expando.renderProxy;
15301	}
15302
15303	node.classList.remove(CSS_RENDER_MONITOR);
15304}
15305
15306function addResizeListener(node, listener, chart) {
15307	var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
15308
15309	// Let's keep track of this added resizer and thus avoid DOM query when removing it.
15310	var resizer = expando.resizer = createResizer(throttled(function() {
15311		if (expando.resizer) {
15312			return listener(createEvent('resize', chart));
15313		}
15314	}));
15315
15316	// The resizer needs to be attached to the node parent, so we first need to be
15317	// sure that `node` is attached to the DOM before injecting the resizer element.
15318	watchForRender(node, function() {
15319		if (expando.resizer) {
15320			var container = node.parentNode;
15321			if (container && container !== resizer.parentNode) {
15322				container.insertBefore(resizer, container.firstChild);
15323			}
15324
15325			// The container size might have changed, let's reset the resizer state.
15326			resizer._reset();
15327		}
15328	});
15329}
15330
15331function removeResizeListener(node) {
15332	var expando = node[EXPANDO_KEY] || {};
15333	var resizer = expando.resizer;
15334
15335	delete expando.resizer;
15336	unwatchForRender(node);
15337
15338	if (resizer && resizer.parentNode) {
15339		resizer.parentNode.removeChild(resizer);
15340	}
15341}
15342
15343function injectCSS(platform, css) {
15344	// http://stackoverflow.com/q/3922139
15345	var style = platform._style || document.createElement('style');
15346	if (!platform._style) {
15347		platform._style = style;
15348		css = '/* Chart.js */\n' + css;
15349		style.setAttribute('type', 'text/css');
15350		document.getElementsByTagName('head')[0].appendChild(style);
15351	}
15352
15353	style.appendChild(document.createTextNode(css));
15354}
15355
15356module.exports = {
15357	/**
15358	 * This property holds whether this platform is enabled for the current environment.
15359	 * Currently used by platform.js to select the proper implementation.
15360	 * @private
15361	 */
15362	_enabled: typeof window !== 'undefined' && typeof document !== 'undefined',
15363
15364	initialize: function() {
15365		var keyframes = 'from{opacity:0.99}to{opacity:1}';
15366
15367		injectCSS(this,
15368			// DOM rendering detection
15369			// https://davidwalsh.name/detect-node-insertion
15370			'@-webkit-keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
15371			'@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
15372			'.' + CSS_RENDER_MONITOR + '{' +
15373				'-webkit-animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
15374				'animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
15375			'}'
15376		);
15377	},
15378
15379	acquireContext: function(item, config) {
15380		if (typeof item === 'string') {
15381			item = document.getElementById(item);
15382		} else if (item.length) {
15383			// Support for array based queries (such as jQuery)
15384			item = item[0];
15385		}
15386
15387		if (item && item.canvas) {
15388			// Support for any object associated to a canvas (including a context2d)
15389			item = item.canvas;
15390		}
15391
15392		// To prevent canvas fingerprinting, some add-ons undefine the getContext
15393		// method, for example: https://github.com/kkapsner/CanvasBlocker
15394		// https://github.com/chartjs/Chart.js/issues/2807
15395		var context = item && item.getContext && item.getContext('2d');
15396
15397		// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
15398		// inside an iframe or when running in a protected environment. We could guess the
15399		// types from their toString() value but let's keep things flexible and assume it's
15400		// a sufficient condition if the item has a context2D which has item as `canvas`.
15401		// https://github.com/chartjs/Chart.js/issues/3887
15402		// https://github.com/chartjs/Chart.js/issues/4102
15403		// https://github.com/chartjs/Chart.js/issues/4152
15404		if (context && context.canvas === item) {
15405			initCanvas(item, config);
15406			return context;
15407		}
15408
15409		return null;
15410	},
15411
15412	releaseContext: function(context) {
15413		var canvas = context.canvas;
15414		if (!canvas[EXPANDO_KEY]) {
15415			return;
15416		}
15417
15418		var initial = canvas[EXPANDO_KEY].initial;
15419		['height', 'width'].forEach(function(prop) {
15420			var value = initial[prop];
15421			if (helpers.isNullOrUndef(value)) {
15422				canvas.removeAttribute(prop);
15423			} else {
15424				canvas.setAttribute(prop, value);
15425			}
15426		});
15427
15428		helpers.each(initial.style || {}, function(value, key) {
15429			canvas.style[key] = value;
15430		});
15431
15432		// The canvas render size might have been changed (and thus the state stack discarded),
15433		// we can't use save() and restore() to restore the initial state. So make sure that at
15434		// least the canvas context is reset to the default state by setting the canvas width.
15435		// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
15436		canvas.width = canvas.width;
15437
15438		delete canvas[EXPANDO_KEY];
15439	},
15440
15441	addEventListener: function(chart, type, listener) {
15442		var canvas = chart.canvas;
15443		if (type === 'resize') {
15444			// Note: the resize event is not supported on all browsers.
15445			addResizeListener(canvas, listener, chart);
15446			return;
15447		}
15448
15449		var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {});
15450		var proxies = expando.proxies || (expando.proxies = {});
15451		var proxy = proxies[chart.id + '_' + type] = function(event) {
15452			listener(fromNativeEvent(event, chart));
15453		};
15454
15455		addEventListener(canvas, type, proxy);
15456	},
15457
15458	removeEventListener: function(chart, type, listener) {
15459		var canvas = chart.canvas;
15460		if (type === 'resize') {
15461			// Note: the resize event is not supported on all browsers.
15462			removeResizeListener(canvas, listener);
15463			return;
15464		}
15465
15466		var expando = listener[EXPANDO_KEY] || {};
15467		var proxies = expando.proxies || {};
15468		var proxy = proxies[chart.id + '_' + type];
15469		if (!proxy) {
15470			return;
15471		}
15472
15473		removeEventListener(canvas, type, proxy);
15474	}
15475};
15476
15477// DEPRECATIONS
15478
15479/**
15480 * Provided for backward compatibility, use EventTarget.addEventListener instead.
15481 * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
15482 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
15483 * @function Chart.helpers.addEvent
15484 * @deprecated since version 2.7.0
15485 * @todo remove at version 3
15486 * @private
15487 */
15488helpers.addEvent = addEventListener;
15489
15490/**
15491 * Provided for backward compatibility, use EventTarget.removeEventListener instead.
15492 * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
15493 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
15494 * @function Chart.helpers.removeEvent
15495 * @deprecated since version 2.7.0
15496 * @todo remove at version 3
15497 * @private
15498 */
15499helpers.removeEvent = removeEventListener;
15500
15501},{"45":45}],48:[function(require,module,exports){
15502'use strict';
15503
15504var helpers = require(45);
15505var basic = require(46);
15506var dom = require(47);
15507
15508// @TODO Make possible to select another platform at build time.
15509var implementation = dom._enabled ? dom : basic;
15510
15511/**
15512 * @namespace Chart.platform
15513 * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
15514 * @since 2.4.0
15515 */
15516module.exports = helpers.extend({
15517	/**
15518	 * @since 2.7.0
15519	 */
15520	initialize: function() {},
15521
15522	/**
15523	 * Called at chart construction time, returns a context2d instance implementing
15524	 * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
15525	 * @param {*} item - The native item from which to acquire context (platform specific)
15526	 * @param {Object} options - The chart options
15527	 * @returns {CanvasRenderingContext2D} context2d instance
15528	 */
15529	acquireContext: function() {},
15530
15531	/**
15532	 * Called at chart destruction time, releases any resources associated to the context
15533	 * previously returned by the acquireContext() method.
15534	 * @param {CanvasRenderingContext2D} context - The context2d instance
15535	 * @returns {Boolean} true if the method succeeded, else false
15536	 */
15537	releaseContext: function() {},
15538
15539	/**
15540	 * Registers the specified listener on the given chart.
15541	 * @param {Chart} chart - Chart from which to listen for event
15542	 * @param {String} type - The ({@link IEvent}) type to listen for
15543	 * @param {Function} listener - Receives a notification (an object that implements
15544	 * the {@link IEvent} interface) when an event of the specified type occurs.
15545	 */
15546	addEventListener: function() {},
15547
15548	/**
15549	 * Removes the specified listener previously registered with addEventListener.
15550	 * @param {Chart} chart -Chart from which to remove the listener
15551	 * @param {String} type - The ({@link IEvent}) type to remove
15552	 * @param {Function} listener - The listener function to remove from the event target.
15553	 */
15554	removeEventListener: function() {}
15555
15556}, implementation);
15557
15558/**
15559 * @interface IPlatform
15560 * Allows abstracting platform dependencies away from the chart
15561 * @borrows Chart.platform.acquireContext as acquireContext
15562 * @borrows Chart.platform.releaseContext as releaseContext
15563 * @borrows Chart.platform.addEventListener as addEventListener
15564 * @borrows Chart.platform.removeEventListener as removeEventListener
15565 */
15566
15567/**
15568 * @interface IEvent
15569 * @prop {String} type - The event type name, possible values are:
15570 * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
15571 * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
15572 * @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
15573 * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
15574 * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
15575 */
15576
15577},{"45":45,"46":46,"47":47}],49:[function(require,module,exports){
15578'use strict';
15579
15580module.exports = {};
15581module.exports.filler = require(50);
15582module.exports.legend = require(51);
15583module.exports.title = require(52);
15584
15585},{"50":50,"51":51,"52":52}],50:[function(require,module,exports){
15586/**
15587 * Plugin based on discussion from the following Chart.js issues:
15588 * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569
15589 * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897
15590 */
15591
15592'use strict';
15593
15594var defaults = require(25);
15595var elements = require(40);
15596var helpers = require(45);
15597
15598defaults._set('global', {
15599	plugins: {
15600		filler: {
15601			propagate: true
15602		}
15603	}
15604});
15605
15606var mappers = {
15607	dataset: function(source) {
15608		var index = source.fill;
15609		var chart = source.chart;
15610		var meta = chart.getDatasetMeta(index);
15611		var visible = meta && chart.isDatasetVisible(index);
15612		var points = (visible && meta.dataset._children) || [];
15613		var length = points.length || 0;
15614
15615		return !length ? null : function(point, i) {
15616			return (i < length && points[i]._view) || null;
15617		};
15618	},
15619
15620	boundary: function(source) {
15621		var boundary = source.boundary;
15622		var x = boundary ? boundary.x : null;
15623		var y = boundary ? boundary.y : null;
15624
15625		return function(point) {
15626			return {
15627				x: x === null ? point.x : x,
15628				y: y === null ? point.y : y,
15629			};
15630		};
15631	}
15632};
15633
15634// @todo if (fill[0] === '#')
15635function decodeFill(el, index, count) {
15636	var model = el._model || {};
15637	var fill = model.fill;
15638	var target;
15639
15640	if (fill === undefined) {
15641		fill = !!model.backgroundColor;
15642	}
15643
15644	if (fill === false || fill === null) {
15645		return false;
15646	}
15647
15648	if (fill === true) {
15649		return 'origin';
15650	}
15651
15652	target = parseFloat(fill, 10);
15653	if (isFinite(target) && Math.floor(target) === target) {
15654		if (fill[0] === '-' || fill[0] === '+') {
15655			target = index + target;
15656		}
15657
15658		if (target === index || target < 0 || target >= count) {
15659			return false;
15660		}
15661
15662		return target;
15663	}
15664
15665	switch (fill) {
15666	// compatibility
15667	case 'bottom':
15668		return 'start';
15669	case 'top':
15670		return 'end';
15671	case 'zero':
15672		return 'origin';
15673	// supported boundaries
15674	case 'origin':
15675	case 'start':
15676	case 'end':
15677		return fill;
15678	// invalid fill values
15679	default:
15680		return false;
15681	}
15682}
15683
15684function computeBoundary(source) {
15685	var model = source.el._model || {};
15686	var scale = source.el._scale || {};
15687	var fill = source.fill;
15688	var target = null;
15689	var horizontal;
15690
15691	if (isFinite(fill)) {
15692		return null;
15693	}
15694
15695	// Backward compatibility: until v3, we still need to support boundary values set on
15696	// the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
15697	// controllers might still use it (e.g. the Smith chart).
15698
15699	if (fill === 'start') {
15700		target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom;
15701	} else if (fill === 'end') {
15702		target = model.scaleTop === undefined ? scale.top : model.scaleTop;
15703	} else if (model.scaleZero !== undefined) {
15704		target = model.scaleZero;
15705	} else if (scale.getBasePosition) {
15706		target = scale.getBasePosition();
15707	} else if (scale.getBasePixel) {
15708		target = scale.getBasePixel();
15709	}
15710
15711	if (target !== undefined && target !== null) {
15712		if (target.x !== undefined && target.y !== undefined) {
15713			return target;
15714		}
15715
15716		if (typeof target === 'number' && isFinite(target)) {
15717			horizontal = scale.isHorizontal();
15718			return {
15719				x: horizontal ? target : null,
15720				y: horizontal ? null : target
15721			};
15722		}
15723	}
15724
15725	return null;
15726}
15727
15728function resolveTarget(sources, index, propagate) {
15729	var source = sources[index];
15730	var fill = source.fill;
15731	var visited = [index];
15732	var target;
15733
15734	if (!propagate) {
15735		return fill;
15736	}
15737
15738	while (fill !== false && visited.indexOf(fill) === -1) {
15739		if (!isFinite(fill)) {
15740			return fill;
15741		}
15742
15743		target = sources[fill];
15744		if (!target) {
15745			return false;
15746		}
15747
15748		if (target.visible) {
15749			return fill;
15750		}
15751
15752		visited.push(fill);
15753		fill = target.fill;
15754	}
15755
15756	return false;
15757}
15758
15759function createMapper(source) {
15760	var fill = source.fill;
15761	var type = 'dataset';
15762
15763	if (fill === false) {
15764		return null;
15765	}
15766
15767	if (!isFinite(fill)) {
15768		type = 'boundary';
15769	}
15770
15771	return mappers[type](source);
15772}
15773
15774function isDrawable(point) {
15775	return point && !point.skip;
15776}
15777
15778function drawArea(ctx, curve0, curve1, len0, len1) {
15779	var i;
15780
15781	if (!len0 || !len1) {
15782		return;
15783	}
15784
15785	// building first area curve (normal)
15786	ctx.moveTo(curve0[0].x, curve0[0].y);
15787	for (i = 1; i < len0; ++i) {
15788		helpers.canvas.lineTo(ctx, curve0[i - 1], curve0[i]);
15789	}
15790
15791	// joining the two area curves
15792	ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);
15793
15794	// building opposite area curve (reverse)
15795	for (i = len1 - 1; i > 0; --i) {
15796		helpers.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true);
15797	}
15798}
15799
15800function doFill(ctx, points, mapper, view, color, loop) {
15801	var count = points.length;
15802	var span = view.spanGaps;
15803	var curve0 = [];
15804	var curve1 = [];
15805	var len0 = 0;
15806	var len1 = 0;
15807	var i, ilen, index, p0, p1, d0, d1;
15808
15809	ctx.beginPath();
15810
15811	for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
15812		index = i % count;
15813		p0 = points[index]._view;
15814		p1 = mapper(p0, index, view);
15815		d0 = isDrawable(p0);
15816		d1 = isDrawable(p1);
15817
15818		if (d0 && d1) {
15819			len0 = curve0.push(p0);
15820			len1 = curve1.push(p1);
15821		} else if (len0 && len1) {
15822			if (!span) {
15823				drawArea(ctx, curve0, curve1, len0, len1);
15824				len0 = len1 = 0;
15825				curve0 = [];
15826				curve1 = [];
15827			} else {
15828				if (d0) {
15829					curve0.push(p0);
15830				}
15831				if (d1) {
15832					curve1.push(p1);
15833				}
15834			}
15835		}
15836	}
15837
15838	drawArea(ctx, curve0, curve1, len0, len1);
15839
15840	ctx.closePath();
15841	ctx.fillStyle = color;
15842	ctx.fill();
15843}
15844
15845module.exports = {
15846	id: 'filler',
15847
15848	afterDatasetsUpdate: function(chart, options) {
15849		var count = (chart.data.datasets || []).length;
15850		var propagate = options.propagate;
15851		var sources = [];
15852		var meta, i, el, source;
15853
15854		for (i = 0; i < count; ++i) {
15855			meta = chart.getDatasetMeta(i);
15856			el = meta.dataset;
15857			source = null;
15858
15859			if (el && el._model && el instanceof elements.Line) {
15860				source = {
15861					visible: chart.isDatasetVisible(i),
15862					fill: decodeFill(el, i, count),
15863					chart: chart,
15864					el: el
15865				};
15866			}
15867
15868			meta.$filler = source;
15869			sources.push(source);
15870		}
15871
15872		for (i = 0; i < count; ++i) {
15873			source = sources[i];
15874			if (!source) {
15875				continue;
15876			}
15877
15878			source.fill = resolveTarget(sources, i, propagate);
15879			source.boundary = computeBoundary(source);
15880			source.mapper = createMapper(source);
15881		}
15882	},
15883
15884	beforeDatasetDraw: function(chart, args) {
15885		var meta = args.meta.$filler;
15886		if (!meta) {
15887			return;
15888		}
15889
15890		var ctx = chart.ctx;
15891		var el = meta.el;
15892		var view = el._view;
15893		var points = el._children || [];
15894		var mapper = meta.mapper;
15895		var color = view.backgroundColor || defaults.global.defaultColor;
15896
15897		if (mapper && color && points.length) {
15898			helpers.canvas.clipArea(ctx, chart.chartArea);
15899			doFill(ctx, points, mapper, view, color, el._loop);
15900			helpers.canvas.unclipArea(ctx);
15901		}
15902	}
15903};
15904
15905},{"25":25,"40":40,"45":45}],51:[function(require,module,exports){
15906'use strict';
15907
15908var defaults = require(25);
15909var Element = require(26);
15910var helpers = require(45);
15911var layouts = require(30);
15912
15913var noop = helpers.noop;
15914
15915defaults._set('global', {
15916	legend: {
15917		display: true,
15918		position: 'top',
15919		fullWidth: true,
15920		reverse: false,
15921		weight: 1000,
15922
15923		// a callback that will handle
15924		onClick: function(e, legendItem) {
15925			var index = legendItem.datasetIndex;
15926			var ci = this.chart;
15927			var meta = ci.getDatasetMeta(index);
15928
15929			// See controller.isDatasetVisible comment
15930			meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
15931
15932			// We hid a dataset ... rerender the chart
15933			ci.update();
15934		},
15935
15936		onHover: null,
15937
15938		labels: {
15939			boxWidth: 40,
15940			padding: 10,
15941			// Generates labels shown in the legend
15942			// Valid properties to return:
15943			// text : text to display
15944			// fillStyle : fill of coloured box
15945			// strokeStyle: stroke of coloured box
15946			// hidden : if this legend item refers to a hidden item
15947			// lineCap : cap style for line
15948			// lineDash
15949			// lineDashOffset :
15950			// lineJoin :
15951			// lineWidth :
15952			generateLabels: function(chart) {
15953				var data = chart.data;
15954				return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
15955					return {
15956						text: dataset.label,
15957						fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
15958						hidden: !chart.isDatasetVisible(i),
15959						lineCap: dataset.borderCapStyle,
15960						lineDash: dataset.borderDash,
15961						lineDashOffset: dataset.borderDashOffset,
15962						lineJoin: dataset.borderJoinStyle,
15963						lineWidth: dataset.borderWidth,
15964						strokeStyle: dataset.borderColor,
15965						pointStyle: dataset.pointStyle,
15966
15967						// Below is extra data used for toggling the datasets
15968						datasetIndex: i
15969					};
15970				}, this) : [];
15971			}
15972		}
15973	},
15974
15975	legendCallback: function(chart) {
15976		var text = [];
15977		text.push('<ul class="' + chart.id + '-legend">');
15978		for (var i = 0; i < chart.data.datasets.length; i++) {
15979			text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
15980			if (chart.data.datasets[i].label) {
15981				text.push(chart.data.datasets[i].label);
15982			}
15983			text.push('</li>');
15984		}
15985		text.push('</ul>');
15986		return text.join('');
15987	}
15988});
15989
15990/**
15991 * Helper function to get the box width based on the usePointStyle option
15992 * @param labelopts {Object} the label options on the legend
15993 * @param fontSize {Number} the label font size
15994 * @return {Number} width of the color box area
15995 */
15996function getBoxWidth(labelOpts, fontSize) {
15997	return labelOpts.usePointStyle ?
15998		fontSize * Math.SQRT2 :
15999		labelOpts.boxWidth;
16000}
16001
16002/**
16003 * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
16004 */
16005var Legend = Element.extend({
16006
16007	initialize: function(config) {
16008		helpers.extend(this, config);
16009
16010		// Contains hit boxes for each dataset (in dataset order)
16011		this.legendHitBoxes = [];
16012
16013		// Are we in doughnut mode which has a different data type
16014		this.doughnutMode = false;
16015	},
16016
16017	// These methods are ordered by lifecycle. Utilities then follow.
16018	// Any function defined here is inherited by all legend types.
16019	// Any function can be extended by the legend type
16020
16021	beforeUpdate: noop,
16022	update: function(maxWidth, maxHeight, margins) {
16023		var me = this;
16024
16025		// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
16026		me.beforeUpdate();
16027
16028		// Absorb the master measurements
16029		me.maxWidth = maxWidth;
16030		me.maxHeight = maxHeight;
16031		me.margins = margins;
16032
16033		// Dimensions
16034		me.beforeSetDimensions();
16035		me.setDimensions();
16036		me.afterSetDimensions();
16037		// Labels
16038		me.beforeBuildLabels();
16039		me.buildLabels();
16040		me.afterBuildLabels();
16041
16042		// Fit
16043		me.beforeFit();
16044		me.fit();
16045		me.afterFit();
16046		//
16047		me.afterUpdate();
16048
16049		return me.minSize;
16050	},
16051	afterUpdate: noop,
16052
16053	//
16054
16055	beforeSetDimensions: noop,
16056	setDimensions: function() {
16057		var me = this;
16058		// Set the unconstrained dimension before label rotation
16059		if (me.isHorizontal()) {
16060			// Reset position before calculating rotation
16061			me.width = me.maxWidth;
16062			me.left = 0;
16063			me.right = me.width;
16064		} else {
16065			me.height = me.maxHeight;
16066
16067			// Reset position before calculating rotation
16068			me.top = 0;
16069			me.bottom = me.height;
16070		}
16071
16072		// Reset padding
16073		me.paddingLeft = 0;
16074		me.paddingTop = 0;
16075		me.paddingRight = 0;
16076		me.paddingBottom = 0;
16077
16078		// Reset minSize
16079		me.minSize = {
16080			width: 0,
16081			height: 0
16082		};
16083	},
16084	afterSetDimensions: noop,
16085
16086	//
16087
16088	beforeBuildLabels: noop,
16089	buildLabels: function() {
16090		var me = this;
16091		var labelOpts = me.options.labels || {};
16092		var legendItems = helpers.callback(labelOpts.generateLabels, [me.chart], me) || [];
16093
16094		if (labelOpts.filter) {
16095			legendItems = legendItems.filter(function(item) {
16096				return labelOpts.filter(item, me.chart.data);
16097			});
16098		}
16099
16100		if (me.options.reverse) {
16101			legendItems.reverse();
16102		}
16103
16104		me.legendItems = legendItems;
16105	},
16106	afterBuildLabels: noop,
16107
16108	//
16109
16110	beforeFit: noop,
16111	fit: function() {
16112		var me = this;
16113		var opts = me.options;
16114		var labelOpts = opts.labels;
16115		var display = opts.display;
16116
16117		var ctx = me.ctx;
16118
16119		var globalDefault = defaults.global;
16120		var valueOrDefault = helpers.valueOrDefault;
16121		var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
16122		var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
16123		var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
16124		var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
16125
16126		// Reset hit boxes
16127		var hitboxes = me.legendHitBoxes = [];
16128
16129		var minSize = me.minSize;
16130		var isHorizontal = me.isHorizontal();
16131
16132		if (isHorizontal) {
16133			minSize.width = me.maxWidth; // fill all the width
16134			minSize.height = display ? 10 : 0;
16135		} else {
16136			minSize.width = display ? 10 : 0;
16137			minSize.height = me.maxHeight; // fill all the height
16138		}
16139
16140		// Increase sizes here
16141		if (display) {
16142			ctx.font = labelFont;
16143
16144			if (isHorizontal) {
16145				// Labels
16146
16147				// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
16148				var lineWidths = me.lineWidths = [0];
16149				var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0;
16150
16151				ctx.textAlign = 'left';
16152				ctx.textBaseline = 'top';
16153
16154				helpers.each(me.legendItems, function(legendItem, i) {
16155					var boxWidth = getBoxWidth(labelOpts, fontSize);
16156					var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
16157
16158					if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) {
16159						totalHeight += fontSize + (labelOpts.padding);
16160						lineWidths[lineWidths.length] = me.left;
16161					}
16162
16163					// Store the hitbox width and height here. Final position will be updated in `draw`
16164					hitboxes[i] = {
16165						left: 0,
16166						top: 0,
16167						width: width,
16168						height: fontSize
16169					};
16170
16171					lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
16172				});
16173
16174				minSize.height += totalHeight;
16175
16176			} else {
16177				var vPadding = labelOpts.padding;
16178				var columnWidths = me.columnWidths = [];
16179				var totalWidth = labelOpts.padding;
16180				var currentColWidth = 0;
16181				var currentColHeight = 0;
16182				var itemHeight = fontSize + vPadding;
16183
16184				helpers.each(me.legendItems, function(legendItem, i) {
16185					var boxWidth = getBoxWidth(labelOpts, fontSize);
16186					var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
16187
16188					// If too tall, go to new column
16189					if (currentColHeight + itemHeight > minSize.height) {
16190						totalWidth += currentColWidth + labelOpts.padding;
16191						columnWidths.push(currentColWidth); // previous column width
16192
16193						currentColWidth = 0;
16194						currentColHeight = 0;
16195					}
16196
16197					// Get max width
16198					currentColWidth = Math.max(currentColWidth, itemWidth);
16199					currentColHeight += itemHeight;
16200
16201					// Store the hitbox width and height here. Final position will be updated in `draw`
16202					hitboxes[i] = {
16203						left: 0,
16204						top: 0,
16205						width: itemWidth,
16206						height: fontSize
16207					};
16208				});
16209
16210				totalWidth += currentColWidth;
16211				columnWidths.push(currentColWidth);
16212				minSize.width += totalWidth;
16213			}
16214		}
16215
16216		me.width = minSize.width;
16217		me.height = minSize.height;
16218	},
16219	afterFit: noop,
16220
16221	// Shared Methods
16222	isHorizontal: function() {
16223		return this.options.position === 'top' || this.options.position === 'bottom';
16224	},
16225
16226	// Actually draw the legend on the canvas
16227	draw: function() {
16228		var me = this;
16229		var opts = me.options;
16230		var labelOpts = opts.labels;
16231		var globalDefault = defaults.global;
16232		var lineDefault = globalDefault.elements.line;
16233		var legendWidth = me.width;
16234		var lineWidths = me.lineWidths;
16235
16236		if (opts.display) {
16237			var ctx = me.ctx;
16238			var valueOrDefault = helpers.valueOrDefault;
16239			var fontColor = valueOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor);
16240			var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
16241			var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
16242			var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
16243			var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
16244			var cursor;
16245
16246			// Canvas setup
16247			ctx.textAlign = 'left';
16248			ctx.textBaseline = 'middle';
16249			ctx.lineWidth = 0.5;
16250			ctx.strokeStyle = fontColor; // for strikethrough effect
16251			ctx.fillStyle = fontColor; // render in correct colour
16252			ctx.font = labelFont;
16253
16254			var boxWidth = getBoxWidth(labelOpts, fontSize);
16255			var hitboxes = me.legendHitBoxes;
16256
16257			// current position
16258			var drawLegendBox = function(x, y, legendItem) {
16259				if (isNaN(boxWidth) || boxWidth <= 0) {
16260					return;
16261				}
16262
16263				// Set the ctx for the box
16264				ctx.save();
16265
16266				ctx.fillStyle = valueOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
16267				ctx.lineCap = valueOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
16268				ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
16269				ctx.lineJoin = valueOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
16270				ctx.lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
16271				ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
16272				var isLineWidthZero = (valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);
16273
16274				if (ctx.setLineDash) {
16275					// IE 9 and 10 do not support line dash
16276					ctx.setLineDash(valueOrDefault(legendItem.lineDash, lineDefault.borderDash));
16277				}
16278
16279				if (opts.labels && opts.labels.usePointStyle) {
16280					// Recalculate x and y for drawPoint() because its expecting
16281					// x and y to be center of figure (instead of top left)
16282					var radius = fontSize * Math.SQRT2 / 2;
16283					var offSet = radius / Math.SQRT2;
16284					var centerX = x + offSet;
16285					var centerY = y + offSet;
16286
16287					// Draw pointStyle as legend symbol
16288					helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
16289				} else {
16290					// Draw box as legend symbol
16291					if (!isLineWidthZero) {
16292						ctx.strokeRect(x, y, boxWidth, fontSize);
16293					}
16294					ctx.fillRect(x, y, boxWidth, fontSize);
16295				}
16296
16297				ctx.restore();
16298			};
16299			var fillText = function(x, y, legendItem, textWidth) {
16300				var halfFontSize = fontSize / 2;
16301				var xLeft = boxWidth + halfFontSize + x;
16302				var yMiddle = y + halfFontSize;
16303
16304				ctx.fillText(legendItem.text, xLeft, yMiddle);
16305
16306				if (legendItem.hidden) {
16307					// Strikethrough the text if hidden
16308					ctx.beginPath();
16309					ctx.lineWidth = 2;
16310					ctx.moveTo(xLeft, yMiddle);
16311					ctx.lineTo(xLeft + textWidth, yMiddle);
16312					ctx.stroke();
16313				}
16314			};
16315
16316			// Horizontal
16317			var isHorizontal = me.isHorizontal();
16318			if (isHorizontal) {
16319				cursor = {
16320					x: me.left + ((legendWidth - lineWidths[0]) / 2),
16321					y: me.top + labelOpts.padding,
16322					line: 0
16323				};
16324			} else {
16325				cursor = {
16326					x: me.left + labelOpts.padding,
16327					y: me.top + labelOpts.padding,
16328					line: 0
16329				};
16330			}
16331
16332			var itemHeight = fontSize + labelOpts.padding;
16333			helpers.each(me.legendItems, function(legendItem, i) {
16334				var textWidth = ctx.measureText(legendItem.text).width;
16335				var width = boxWidth + (fontSize / 2) + textWidth;
16336				var x = cursor.x;
16337				var y = cursor.y;
16338
16339				if (isHorizontal) {
16340					if (x + width >= legendWidth) {
16341						y = cursor.y += itemHeight;
16342						cursor.line++;
16343						x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
16344					}
16345				} else if (y + itemHeight > me.bottom) {
16346					x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
16347					y = cursor.y = me.top + labelOpts.padding;
16348					cursor.line++;
16349				}
16350
16351				drawLegendBox(x, y, legendItem);
16352
16353				hitboxes[i].left = x;
16354				hitboxes[i].top = y;
16355
16356				// Fill the actual label
16357				fillText(x, y, legendItem, textWidth);
16358
16359				if (isHorizontal) {
16360					cursor.x += width + (labelOpts.padding);
16361				} else {
16362					cursor.y += itemHeight;
16363				}
16364
16365			});
16366		}
16367	},
16368
16369	/**
16370	 * Handle an event
16371	 * @private
16372	 * @param {IEvent} event - The event to handle
16373	 * @return {Boolean} true if a change occured
16374	 */
16375	handleEvent: function(e) {
16376		var me = this;
16377		var opts = me.options;
16378		var type = e.type === 'mouseup' ? 'click' : e.type;
16379		var changed = false;
16380
16381		if (type === 'mousemove') {
16382			if (!opts.onHover) {
16383				return;
16384			}
16385		} else if (type === 'click') {
16386			if (!opts.onClick) {
16387				return;
16388			}
16389		} else {
16390			return;
16391		}
16392
16393		// Chart event already has relative position in it
16394		var x = e.x;
16395		var y = e.y;
16396
16397		if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
16398			// See if we are touching one of the dataset boxes
16399			var lh = me.legendHitBoxes;
16400			for (var i = 0; i < lh.length; ++i) {
16401				var hitBox = lh[i];
16402
16403				if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
16404					// Touching an element
16405					if (type === 'click') {
16406						// use e.native for backwards compatibility
16407						opts.onClick.call(me, e.native, me.legendItems[i]);
16408						changed = true;
16409						break;
16410					} else if (type === 'mousemove') {
16411						// use e.native for backwards compatibility
16412						opts.onHover.call(me, e.native, me.legendItems[i]);
16413						changed = true;
16414						break;
16415					}
16416				}
16417			}
16418		}
16419
16420		return changed;
16421	}
16422});
16423
16424function createNewLegendAndAttach(chart, legendOpts) {
16425	var legend = new Legend({
16426		ctx: chart.ctx,
16427		options: legendOpts,
16428		chart: chart
16429	});
16430
16431	layouts.configure(chart, legend, legendOpts);
16432	layouts.addBox(chart, legend);
16433	chart.legend = legend;
16434}
16435
16436module.exports = {
16437	id: 'legend',
16438
16439	/**
16440	 * Backward compatibility: since 2.1.5, the legend is registered as a plugin, making
16441	 * Chart.Legend obsolete. To avoid a breaking change, we export the Legend as part of
16442	 * the plugin, which one will be re-exposed in the chart.js file.
16443	 * https://github.com/chartjs/Chart.js/pull/2640
16444	 * @private
16445	 */
16446	_element: Legend,
16447
16448	beforeInit: function(chart) {
16449		var legendOpts = chart.options.legend;
16450
16451		if (legendOpts) {
16452			createNewLegendAndAttach(chart, legendOpts);
16453		}
16454	},
16455
16456	beforeUpdate: function(chart) {
16457		var legendOpts = chart.options.legend;
16458		var legend = chart.legend;
16459
16460		if (legendOpts) {
16461			helpers.mergeIf(legendOpts, defaults.global.legend);
16462
16463			if (legend) {
16464				layouts.configure(chart, legend, legendOpts);
16465				legend.options = legendOpts;
16466			} else {
16467				createNewLegendAndAttach(chart, legendOpts);
16468			}
16469		} else if (legend) {
16470			layouts.removeBox(chart, legend);
16471			delete chart.legend;
16472		}
16473	},
16474
16475	afterEvent: function(chart, e) {
16476		var legend = chart.legend;
16477		if (legend) {
16478			legend.handleEvent(e);
16479		}
16480	}
16481};
16482
16483},{"25":25,"26":26,"30":30,"45":45}],52:[function(require,module,exports){
16484'use strict';
16485
16486var defaults = require(25);
16487var Element = require(26);
16488var helpers = require(45);
16489var layouts = require(30);
16490
16491var noop = helpers.noop;
16492
16493defaults._set('global', {
16494	title: {
16495		display: false,
16496		fontStyle: 'bold',
16497		fullWidth: true,
16498		lineHeight: 1.2,
16499		padding: 10,
16500		position: 'top',
16501		text: '',
16502		weight: 2000         // by default greater than legend (1000) to be above
16503	}
16504});
16505
16506/**
16507 * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
16508 */
16509var Title = Element.extend({
16510	initialize: function(config) {
16511		var me = this;
16512		helpers.extend(me, config);
16513
16514		// Contains hit boxes for each dataset (in dataset order)
16515		me.legendHitBoxes = [];
16516	},
16517
16518	// These methods are ordered by lifecycle. Utilities then follow.
16519
16520	beforeUpdate: noop,
16521	update: function(maxWidth, maxHeight, margins) {
16522		var me = this;
16523
16524		// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
16525		me.beforeUpdate();
16526
16527		// Absorb the master measurements
16528		me.maxWidth = maxWidth;
16529		me.maxHeight = maxHeight;
16530		me.margins = margins;
16531
16532		// Dimensions
16533		me.beforeSetDimensions();
16534		me.setDimensions();
16535		me.afterSetDimensions();
16536		// Labels
16537		me.beforeBuildLabels();
16538		me.buildLabels();
16539		me.afterBuildLabels();
16540
16541		// Fit
16542		me.beforeFit();
16543		me.fit();
16544		me.afterFit();
16545		//
16546		me.afterUpdate();
16547
16548		return me.minSize;
16549
16550	},
16551	afterUpdate: noop,
16552
16553	//
16554
16555	beforeSetDimensions: noop,
16556	setDimensions: function() {
16557		var me = this;
16558		// Set the unconstrained dimension before label rotation
16559		if (me.isHorizontal()) {
16560			// Reset position before calculating rotation
16561			me.width = me.maxWidth;
16562			me.left = 0;
16563			me.right = me.width;
16564		} else {
16565			me.height = me.maxHeight;
16566
16567			// Reset position before calculating rotation
16568			me.top = 0;
16569			me.bottom = me.height;
16570		}
16571
16572		// Reset padding
16573		me.paddingLeft = 0;
16574		me.paddingTop = 0;
16575		me.paddingRight = 0;
16576		me.paddingBottom = 0;
16577
16578		// Reset minSize
16579		me.minSize = {
16580			width: 0,
16581			height: 0
16582		};
16583	},
16584	afterSetDimensions: noop,
16585
16586	//
16587
16588	beforeBuildLabels: noop,
16589	buildLabels: noop,
16590	afterBuildLabels: noop,
16591
16592	//
16593
16594	beforeFit: noop,
16595	fit: function() {
16596		var me = this;
16597		var valueOrDefault = helpers.valueOrDefault;
16598		var opts = me.options;
16599		var display = opts.display;
16600		var fontSize = valueOrDefault(opts.fontSize, defaults.global.defaultFontSize);
16601		var minSize = me.minSize;
16602		var lineCount = helpers.isArray(opts.text) ? opts.text.length : 1;
16603		var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
16604		var textSize = display ? (lineCount * lineHeight) + (opts.padding * 2) : 0;
16605
16606		if (me.isHorizontal()) {
16607			minSize.width = me.maxWidth; // fill all the width
16608			minSize.height = textSize;
16609		} else {
16610			minSize.width = textSize;
16611			minSize.height = me.maxHeight; // fill all the height
16612		}
16613
16614		me.width = minSize.width;
16615		me.height = minSize.height;
16616
16617	},
16618	afterFit: noop,
16619
16620	// Shared Methods
16621	isHorizontal: function() {
16622		var pos = this.options.position;
16623		return pos === 'top' || pos === 'bottom';
16624	},
16625
16626	// Actually draw the title block on the canvas
16627	draw: function() {
16628		var me = this;
16629		var ctx = me.ctx;
16630		var valueOrDefault = helpers.valueOrDefault;
16631		var opts = me.options;
16632		var globalDefaults = defaults.global;
16633
16634		if (opts.display) {
16635			var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize);
16636			var fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle);
16637			var fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily);
16638			var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily);
16639			var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
16640			var offset = lineHeight / 2 + opts.padding;
16641			var rotation = 0;
16642			var top = me.top;
16643			var left = me.left;
16644			var bottom = me.bottom;
16645			var right = me.right;
16646			var maxWidth, titleX, titleY;
16647
16648			ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
16649			ctx.font = titleFont;
16650
16651			// Horizontal
16652			if (me.isHorizontal()) {
16653				titleX = left + ((right - left) / 2); // midpoint of the width
16654				titleY = top + offset;
16655				maxWidth = right - left;
16656			} else {
16657				titleX = opts.position === 'left' ? left + offset : right - offset;
16658				titleY = top + ((bottom - top) / 2);
16659				maxWidth = bottom - top;
16660				rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
16661			}
16662
16663			ctx.save();
16664			ctx.translate(titleX, titleY);
16665			ctx.rotate(rotation);
16666			ctx.textAlign = 'center';
16667			ctx.textBaseline = 'middle';
16668
16669			var text = opts.text;
16670			if (helpers.isArray(text)) {
16671				var y = 0;
16672				for (var i = 0; i < text.length; ++i) {
16673					ctx.fillText(text[i], 0, y, maxWidth);
16674					y += lineHeight;
16675				}
16676			} else {
16677				ctx.fillText(text, 0, 0, maxWidth);
16678			}
16679
16680			ctx.restore();
16681		}
16682	}
16683});
16684
16685function createNewTitleBlockAndAttach(chart, titleOpts) {
16686	var title = new Title({
16687		ctx: chart.ctx,
16688		options: titleOpts,
16689		chart: chart
16690	});
16691
16692	layouts.configure(chart, title, titleOpts);
16693	layouts.addBox(chart, title);
16694	chart.titleBlock = title;
16695}
16696
16697module.exports = {
16698	id: 'title',
16699
16700	/**
16701	 * Backward compatibility: since 2.1.5, the title is registered as a plugin, making
16702	 * Chart.Title obsolete. To avoid a breaking change, we export the Title as part of
16703	 * the plugin, which one will be re-exposed in the chart.js file.
16704	 * https://github.com/chartjs/Chart.js/pull/2640
16705	 * @private
16706	 */
16707	_element: Title,
16708
16709	beforeInit: function(chart) {
16710		var titleOpts = chart.options.title;
16711
16712		if (titleOpts) {
16713			createNewTitleBlockAndAttach(chart, titleOpts);
16714		}
16715	},
16716
16717	beforeUpdate: function(chart) {
16718		var titleOpts = chart.options.title;
16719		var titleBlock = chart.titleBlock;
16720
16721		if (titleOpts) {
16722			helpers.mergeIf(titleOpts, defaults.global.title);
16723
16724			if (titleBlock) {
16725				layouts.configure(chart, titleBlock, titleOpts);
16726				titleBlock.options = titleOpts;
16727			} else {
16728				createNewTitleBlockAndAttach(chart, titleOpts);
16729			}
16730		} else if (titleBlock) {
16731			layouts.removeBox(chart, titleBlock);
16732			delete chart.titleBlock;
16733		}
16734	}
16735};
16736
16737},{"25":25,"26":26,"30":30,"45":45}],53:[function(require,module,exports){
16738'use strict';
16739
16740module.exports = function(Chart) {
16741
16742	// Default config for a category scale
16743	var defaultConfig = {
16744		position: 'bottom'
16745	};
16746
16747	var DatasetScale = Chart.Scale.extend({
16748		/**
16749		* Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
16750		* else fall back to data.labels
16751		* @private
16752		*/
16753		getLabels: function() {
16754			var data = this.chart.data;
16755			return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
16756		},
16757
16758		determineDataLimits: function() {
16759			var me = this;
16760			var labels = me.getLabels();
16761			me.minIndex = 0;
16762			me.maxIndex = labels.length - 1;
16763			var findIndex;
16764
16765			if (me.options.ticks.min !== undefined) {
16766				// user specified min value
16767				findIndex = labels.indexOf(me.options.ticks.min);
16768				me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
16769			}
16770
16771			if (me.options.ticks.max !== undefined) {
16772				// user specified max value
16773				findIndex = labels.indexOf(me.options.ticks.max);
16774				me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
16775			}
16776
16777			me.min = labels[me.minIndex];
16778			me.max = labels[me.maxIndex];
16779		},
16780
16781		buildTicks: function() {
16782			var me = this;
16783			var labels = me.getLabels();
16784			// If we are viewing some subset of labels, slice the original array
16785			me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
16786		},
16787
16788		getLabelForIndex: function(index, datasetIndex) {
16789			var me = this;
16790			var data = me.chart.data;
16791			var isHorizontal = me.isHorizontal();
16792
16793			if (data.yLabels && !isHorizontal) {
16794				return me.getRightValue(data.datasets[datasetIndex].data[index]);
16795			}
16796			return me.ticks[index - me.minIndex];
16797		},
16798
16799		// Used to get data value locations.  Value can either be an index or a numerical value
16800		getPixelForValue: function(value, index) {
16801			var me = this;
16802			var offset = me.options.offset;
16803			// 1 is added because we need the length but we have the indexes
16804			var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1);
16805
16806			// If value is a data object, then index is the index in the data array,
16807			// not the index of the scale. We need to change that.
16808			var valueCategory;
16809			if (value !== undefined && value !== null) {
16810				valueCategory = me.isHorizontal() ? value.x : value.y;
16811			}
16812			if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
16813				var labels = me.getLabels();
16814				value = valueCategory || value;
16815				var idx = labels.indexOf(value);
16816				index = idx !== -1 ? idx : index;
16817			}
16818
16819			if (me.isHorizontal()) {
16820				var valueWidth = me.width / offsetAmt;
16821				var widthOffset = (valueWidth * (index - me.minIndex));
16822
16823				if (offset) {
16824					widthOffset += (valueWidth / 2);
16825				}
16826
16827				return me.left + Math.round(widthOffset);
16828			}
16829			var valueHeight = me.height / offsetAmt;
16830			var heightOffset = (valueHeight * (index - me.minIndex));
16831
16832			if (offset) {
16833				heightOffset += (valueHeight / 2);
16834			}
16835
16836			return me.top + Math.round(heightOffset);
16837		},
16838		getPixelForTick: function(index) {
16839			return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
16840		},
16841		getValueForPixel: function(pixel) {
16842			var me = this;
16843			var offset = me.options.offset;
16844			var value;
16845			var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
16846			var horz = me.isHorizontal();
16847			var valueDimension = (horz ? me.width : me.height) / offsetAmt;
16848
16849			pixel -= horz ? me.left : me.top;
16850
16851			if (offset) {
16852				pixel -= (valueDimension / 2);
16853			}
16854
16855			if (pixel <= 0) {
16856				value = 0;
16857			} else {
16858				value = Math.round(pixel / valueDimension);
16859			}
16860
16861			return value + me.minIndex;
16862		},
16863		getBasePixel: function() {
16864			return this.bottom;
16865		}
16866	});
16867
16868	Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig);
16869
16870};
16871
16872},{}],54:[function(require,module,exports){
16873'use strict';
16874
16875var defaults = require(25);
16876var helpers = require(45);
16877var Ticks = require(34);
16878
16879module.exports = function(Chart) {
16880
16881	var defaultConfig = {
16882		position: 'left',
16883		ticks: {
16884			callback: Ticks.formatters.linear
16885		}
16886	};
16887
16888	var LinearScale = Chart.LinearScaleBase.extend({
16889
16890		determineDataLimits: function() {
16891			var me = this;
16892			var opts = me.options;
16893			var chart = me.chart;
16894			var data = chart.data;
16895			var datasets = data.datasets;
16896			var isHorizontal = me.isHorizontal();
16897			var DEFAULT_MIN = 0;
16898			var DEFAULT_MAX = 1;
16899
16900			function IDMatches(meta) {
16901				return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
16902			}
16903
16904			// First Calculate the range
16905			me.min = null;
16906			me.max = null;
16907
16908			var hasStacks = opts.stacked;
16909			if (hasStacks === undefined) {
16910				helpers.each(datasets, function(dataset, datasetIndex) {
16911					if (hasStacks) {
16912						return;
16913					}
16914
16915					var meta = chart.getDatasetMeta(datasetIndex);
16916					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
16917						meta.stack !== undefined) {
16918						hasStacks = true;
16919					}
16920				});
16921			}
16922
16923			if (opts.stacked || hasStacks) {
16924				var valuesPerStack = {};
16925
16926				helpers.each(datasets, function(dataset, datasetIndex) {
16927					var meta = chart.getDatasetMeta(datasetIndex);
16928					var key = [
16929						meta.type,
16930						// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
16931						((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
16932						meta.stack
16933					].join('.');
16934
16935					if (valuesPerStack[key] === undefined) {
16936						valuesPerStack[key] = {
16937							positiveValues: [],
16938							negativeValues: []
16939						};
16940					}
16941
16942					// Store these per type
16943					var positiveValues = valuesPerStack[key].positiveValues;
16944					var negativeValues = valuesPerStack[key].negativeValues;
16945
16946					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
16947						helpers.each(dataset.data, function(rawValue, index) {
16948							var value = +me.getRightValue(rawValue);
16949							if (isNaN(value) || meta.data[index].hidden) {
16950								return;
16951							}
16952
16953							positiveValues[index] = positiveValues[index] || 0;
16954							negativeValues[index] = negativeValues[index] || 0;
16955
16956							if (opts.relativePoints) {
16957								positiveValues[index] = 100;
16958							} else if (value < 0) {
16959								negativeValues[index] += value;
16960							} else {
16961								positiveValues[index] += value;
16962							}
16963						});
16964					}
16965				});
16966
16967				helpers.each(valuesPerStack, function(valuesForType) {
16968					var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
16969					var minVal = helpers.min(values);
16970					var maxVal = helpers.max(values);
16971					me.min = me.min === null ? minVal : Math.min(me.min, minVal);
16972					me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
16973				});
16974
16975			} else {
16976				helpers.each(datasets, function(dataset, datasetIndex) {
16977					var meta = chart.getDatasetMeta(datasetIndex);
16978					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
16979						helpers.each(dataset.data, function(rawValue, index) {
16980							var value = +me.getRightValue(rawValue);
16981							if (isNaN(value) || meta.data[index].hidden) {
16982								return;
16983							}
16984
16985							if (me.min === null) {
16986								me.min = value;
16987							} else if (value < me.min) {
16988								me.min = value;
16989							}
16990
16991							if (me.max === null) {
16992								me.max = value;
16993							} else if (value > me.max) {
16994								me.max = value;
16995							}
16996						});
16997					}
16998				});
16999			}
17000
17001			me.min = isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
17002			me.max = isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;
17003
17004			// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
17005			this.handleTickRangeOptions();
17006		},
17007		getTickLimit: function() {
17008			var maxTicks;
17009			var me = this;
17010			var tickOpts = me.options.ticks;
17011
17012			if (me.isHorizontal()) {
17013				maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
17014			} else {
17015				// The factor of 2 used to scale the font size has been experimentally determined.
17016				var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize);
17017				maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
17018			}
17019
17020			return maxTicks;
17021		},
17022		// Called after the ticks are built. We need
17023		handleDirectionalChanges: function() {
17024			if (!this.isHorizontal()) {
17025				// We are in a vertical orientation. The top value is the highest. So reverse the array
17026				this.ticks.reverse();
17027			}
17028		},
17029		getLabelForIndex: function(index, datasetIndex) {
17030			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
17031		},
17032		// Utils
17033		getPixelForValue: function(value) {
17034			// This must be called after fit has been run so that
17035			// this.left, this.top, this.right, and this.bottom have been defined
17036			var me = this;
17037			var start = me.start;
17038
17039			var rightValue = +me.getRightValue(value);
17040			var pixel;
17041			var range = me.end - start;
17042
17043			if (me.isHorizontal()) {
17044				pixel = me.left + (me.width / range * (rightValue - start));
17045			} else {
17046				pixel = me.bottom - (me.height / range * (rightValue - start));
17047			}
17048			return pixel;
17049		},
17050		getValueForPixel: function(pixel) {
17051			var me = this;
17052			var isHorizontal = me.isHorizontal();
17053			var innerDimension = isHorizontal ? me.width : me.height;
17054			var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
17055			return me.start + ((me.end - me.start) * offset);
17056		},
17057		getPixelForTick: function(index) {
17058			return this.getPixelForValue(this.ticksAsNumbers[index]);
17059		}
17060	});
17061	Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig);
17062
17063};
17064
17065},{"25":25,"34":34,"45":45}],55:[function(require,module,exports){
17066'use strict';
17067
17068var helpers = require(45);
17069
17070/**
17071 * Generate a set of linear ticks
17072 * @param generationOptions the options used to generate the ticks
17073 * @param dataRange the range of the data
17074 * @returns {Array<Number>} array of tick values
17075 */
17076function generateTicks(generationOptions, dataRange) {
17077	var ticks = [];
17078	// To get a "nice" value for the tick spacing, we will use the appropriately named
17079	// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
17080	// for details.
17081
17082	var spacing;
17083	if (generationOptions.stepSize && generationOptions.stepSize > 0) {
17084		spacing = generationOptions.stepSize;
17085	} else {
17086		var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
17087		spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
17088	}
17089	var niceMin = Math.floor(dataRange.min / spacing) * spacing;
17090	var niceMax = Math.ceil(dataRange.max / spacing) * spacing;
17091
17092	// If min, max and stepSize is set and they make an evenly spaced scale use it.
17093	if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
17094		// If very close to our whole number, use it.
17095		if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
17096			niceMin = generationOptions.min;
17097			niceMax = generationOptions.max;
17098		}
17099	}
17100
17101	var numSpaces = (niceMax - niceMin) / spacing;
17102	// If very close to our rounded value, use it.
17103	if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
17104		numSpaces = Math.round(numSpaces);
17105	} else {
17106		numSpaces = Math.ceil(numSpaces);
17107	}
17108
17109	var precision = 1;
17110	if (spacing < 1) {
17111		precision = Math.pow(10, spacing.toString().length - 2);
17112		niceMin = Math.round(niceMin * precision) / precision;
17113		niceMax = Math.round(niceMax * precision) / precision;
17114	}
17115	ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
17116	for (var j = 1; j < numSpaces; ++j) {
17117		ticks.push(Math.round((niceMin + j * spacing) * precision) / precision);
17118	}
17119	ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
17120
17121	return ticks;
17122}
17123
17124
17125module.exports = function(Chart) {
17126
17127	var noop = helpers.noop;
17128
17129	Chart.LinearScaleBase = Chart.Scale.extend({
17130		getRightValue: function(value) {
17131			if (typeof value === 'string') {
17132				return +value;
17133			}
17134			return Chart.Scale.prototype.getRightValue.call(this, value);
17135		},
17136
17137		handleTickRangeOptions: function() {
17138			var me = this;
17139			var opts = me.options;
17140			var tickOpts = opts.ticks;
17141
17142			// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
17143			// do nothing since that would make the chart weird. If the user really wants a weird chart
17144			// axis, they can manually override it
17145			if (tickOpts.beginAtZero) {
17146				var minSign = helpers.sign(me.min);
17147				var maxSign = helpers.sign(me.max);
17148
17149				if (minSign < 0 && maxSign < 0) {
17150					// move the top up to 0
17151					me.max = 0;
17152				} else if (minSign > 0 && maxSign > 0) {
17153					// move the bottom down to 0
17154					me.min = 0;
17155				}
17156			}
17157
17158			var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined;
17159			var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined;
17160
17161			if (tickOpts.min !== undefined) {
17162				me.min = tickOpts.min;
17163			} else if (tickOpts.suggestedMin !== undefined) {
17164				if (me.min === null) {
17165					me.min = tickOpts.suggestedMin;
17166				} else {
17167					me.min = Math.min(me.min, tickOpts.suggestedMin);
17168				}
17169			}
17170
17171			if (tickOpts.max !== undefined) {
17172				me.max = tickOpts.max;
17173			} else if (tickOpts.suggestedMax !== undefined) {
17174				if (me.max === null) {
17175					me.max = tickOpts.suggestedMax;
17176				} else {
17177					me.max = Math.max(me.max, tickOpts.suggestedMax);
17178				}
17179			}
17180
17181			if (setMin !== setMax) {
17182				// We set the min or the max but not both.
17183				// So ensure that our range is good
17184				// Inverted or 0 length range can happen when
17185				// ticks.min is set, and no datasets are visible
17186				if (me.min >= me.max) {
17187					if (setMin) {
17188						me.max = me.min + 1;
17189					} else {
17190						me.min = me.max - 1;
17191					}
17192				}
17193			}
17194
17195			if (me.min === me.max) {
17196				me.max++;
17197
17198				if (!tickOpts.beginAtZero) {
17199					me.min--;
17200				}
17201			}
17202		},
17203		getTickLimit: noop,
17204		handleDirectionalChanges: noop,
17205
17206		buildTicks: function() {
17207			var me = this;
17208			var opts = me.options;
17209			var tickOpts = opts.ticks;
17210
17211			// Figure out what the max number of ticks we can support it is based on the size of
17212			// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
17213			// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
17214			// the graph. Make sure we always have at least 2 ticks
17215			var maxTicks = me.getTickLimit();
17216			maxTicks = Math.max(2, maxTicks);
17217
17218			var numericGeneratorOptions = {
17219				maxTicks: maxTicks,
17220				min: tickOpts.min,
17221				max: tickOpts.max,
17222				stepSize: helpers.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
17223			};
17224			var ticks = me.ticks = generateTicks(numericGeneratorOptions, me);
17225
17226			me.handleDirectionalChanges();
17227
17228			// At this point, we need to update our max and min given the tick values since we have expanded the
17229			// range of the scale
17230			me.max = helpers.max(ticks);
17231			me.min = helpers.min(ticks);
17232
17233			if (tickOpts.reverse) {
17234				ticks.reverse();
17235
17236				me.start = me.max;
17237				me.end = me.min;
17238			} else {
17239				me.start = me.min;
17240				me.end = me.max;
17241			}
17242		},
17243		convertTicksToLabels: function() {
17244			var me = this;
17245			me.ticksAsNumbers = me.ticks.slice();
17246			me.zeroLineIndex = me.ticks.indexOf(0);
17247
17248			Chart.Scale.prototype.convertTicksToLabels.call(me);
17249		}
17250	});
17251};
17252
17253},{"45":45}],56:[function(require,module,exports){
17254'use strict';
17255
17256var helpers = require(45);
17257var Ticks = require(34);
17258
17259/**
17260 * Generate a set of logarithmic ticks
17261 * @param generationOptions the options used to generate the ticks
17262 * @param dataRange the range of the data
17263 * @returns {Array<Number>} array of tick values
17264 */
17265function generateTicks(generationOptions, dataRange) {
17266	var ticks = [];
17267	var valueOrDefault = helpers.valueOrDefault;
17268
17269	// Figure out what the max number of ticks we can support it is based on the size of
17270	// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
17271	// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
17272	// the graph
17273	var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
17274
17275	var endExp = Math.floor(helpers.log10(dataRange.max));
17276	var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
17277	var exp, significand;
17278
17279	if (tickVal === 0) {
17280		exp = Math.floor(helpers.log10(dataRange.minNotZero));
17281		significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
17282
17283		ticks.push(tickVal);
17284		tickVal = significand * Math.pow(10, exp);
17285	} else {
17286		exp = Math.floor(helpers.log10(tickVal));
17287		significand = Math.floor(tickVal / Math.pow(10, exp));
17288	}
17289	var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
17290
17291	do {
17292		ticks.push(tickVal);
17293
17294		++significand;
17295		if (significand === 10) {
17296			significand = 1;
17297			++exp;
17298			precision = exp >= 0 ? 1 : precision;
17299		}
17300
17301		tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
17302	} while (exp < endExp || (exp === endExp && significand < endSignificand));
17303
17304	var lastTick = valueOrDefault(generationOptions.max, tickVal);
17305	ticks.push(lastTick);
17306
17307	return ticks;
17308}
17309
17310
17311module.exports = function(Chart) {
17312
17313	var defaultConfig = {
17314		position: 'left',
17315
17316		// label settings
17317		ticks: {
17318			callback: Ticks.formatters.logarithmic
17319		}
17320	};
17321
17322	var LogarithmicScale = Chart.Scale.extend({
17323		determineDataLimits: function() {
17324			var me = this;
17325			var opts = me.options;
17326			var chart = me.chart;
17327			var data = chart.data;
17328			var datasets = data.datasets;
17329			var isHorizontal = me.isHorizontal();
17330			function IDMatches(meta) {
17331				return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
17332			}
17333
17334			// Calculate Range
17335			me.min = null;
17336			me.max = null;
17337			me.minNotZero = null;
17338
17339			var hasStacks = opts.stacked;
17340			if (hasStacks === undefined) {
17341				helpers.each(datasets, function(dataset, datasetIndex) {
17342					if (hasStacks) {
17343						return;
17344					}
17345
17346					var meta = chart.getDatasetMeta(datasetIndex);
17347					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
17348						meta.stack !== undefined) {
17349						hasStacks = true;
17350					}
17351				});
17352			}
17353
17354			if (opts.stacked || hasStacks) {
17355				var valuesPerStack = {};
17356
17357				helpers.each(datasets, function(dataset, datasetIndex) {
17358					var meta = chart.getDatasetMeta(datasetIndex);
17359					var key = [
17360						meta.type,
17361						// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
17362						((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
17363						meta.stack
17364					].join('.');
17365
17366					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
17367						if (valuesPerStack[key] === undefined) {
17368							valuesPerStack[key] = [];
17369						}
17370
17371						helpers.each(dataset.data, function(rawValue, index) {
17372							var values = valuesPerStack[key];
17373							var value = +me.getRightValue(rawValue);
17374							// invalid, hidden and negative values are ignored
17375							if (isNaN(value) || meta.data[index].hidden || value < 0) {
17376								return;
17377							}
17378							values[index] = values[index] || 0;
17379							values[index] += value;
17380						});
17381					}
17382				});
17383
17384				helpers.each(valuesPerStack, function(valuesForType) {
17385					if (valuesForType.length > 0) {
17386						var minVal = helpers.min(valuesForType);
17387						var maxVal = helpers.max(valuesForType);
17388						me.min = me.min === null ? minVal : Math.min(me.min, minVal);
17389						me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
17390					}
17391				});
17392
17393			} else {
17394				helpers.each(datasets, function(dataset, datasetIndex) {
17395					var meta = chart.getDatasetMeta(datasetIndex);
17396					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
17397						helpers.each(dataset.data, function(rawValue, index) {
17398							var value = +me.getRightValue(rawValue);
17399							// invalid, hidden and negative values are ignored
17400							if (isNaN(value) || meta.data[index].hidden || value < 0) {
17401								return;
17402							}
17403
17404							if (me.min === null) {
17405								me.min = value;
17406							} else if (value < me.min) {
17407								me.min = value;
17408							}
17409
17410							if (me.max === null) {
17411								me.max = value;
17412							} else if (value > me.max) {
17413								me.max = value;
17414							}
17415
17416							if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
17417								me.minNotZero = value;
17418							}
17419						});
17420					}
17421				});
17422			}
17423
17424			// Common base implementation to handle ticks.min, ticks.max
17425			this.handleTickRangeOptions();
17426		},
17427		handleTickRangeOptions: function() {
17428			var me = this;
17429			var opts = me.options;
17430			var tickOpts = opts.ticks;
17431			var valueOrDefault = helpers.valueOrDefault;
17432			var DEFAULT_MIN = 1;
17433			var DEFAULT_MAX = 10;
17434
17435			me.min = valueOrDefault(tickOpts.min, me.min);
17436			me.max = valueOrDefault(tickOpts.max, me.max);
17437
17438			if (me.min === me.max) {
17439				if (me.min !== 0 && me.min !== null) {
17440					me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
17441					me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
17442				} else {
17443					me.min = DEFAULT_MIN;
17444					me.max = DEFAULT_MAX;
17445				}
17446			}
17447			if (me.min === null) {
17448				me.min = Math.pow(10, Math.floor(helpers.log10(me.max)) - 1);
17449			}
17450			if (me.max === null) {
17451				me.max = me.min !== 0
17452					? Math.pow(10, Math.floor(helpers.log10(me.min)) + 1)
17453					: DEFAULT_MAX;
17454			}
17455			if (me.minNotZero === null) {
17456				if (me.min > 0) {
17457					me.minNotZero = me.min;
17458				} else if (me.max < 1) {
17459					me.minNotZero = Math.pow(10, Math.floor(helpers.log10(me.max)));
17460				} else {
17461					me.minNotZero = DEFAULT_MIN;
17462				}
17463			}
17464		},
17465		buildTicks: function() {
17466			var me = this;
17467			var opts = me.options;
17468			var tickOpts = opts.ticks;
17469			var reverse = !me.isHorizontal();
17470
17471			var generationOptions = {
17472				min: tickOpts.min,
17473				max: tickOpts.max
17474			};
17475			var ticks = me.ticks = generateTicks(generationOptions, me);
17476
17477			// At this point, we need to update our max and min given the tick values since we have expanded the
17478			// range of the scale
17479			me.max = helpers.max(ticks);
17480			me.min = helpers.min(ticks);
17481
17482			if (tickOpts.reverse) {
17483				reverse = !reverse;
17484				me.start = me.max;
17485				me.end = me.min;
17486			} else {
17487				me.start = me.min;
17488				me.end = me.max;
17489			}
17490			if (reverse) {
17491				ticks.reverse();
17492			}
17493		},
17494		convertTicksToLabels: function() {
17495			this.tickValues = this.ticks.slice();
17496
17497			Chart.Scale.prototype.convertTicksToLabels.call(this);
17498		},
17499		// Get the correct tooltip label
17500		getLabelForIndex: function(index, datasetIndex) {
17501			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
17502		},
17503		getPixelForTick: function(index) {
17504			return this.getPixelForValue(this.tickValues[index]);
17505		},
17506		/**
17507		 * Returns the value of the first tick.
17508		 * @param {Number} value - The minimum not zero value.
17509		 * @return {Number} The first tick value.
17510		 * @private
17511		 */
17512		_getFirstTickValue: function(value) {
17513			var exp = Math.floor(helpers.log10(value));
17514			var significand = Math.floor(value / Math.pow(10, exp));
17515
17516			return significand * Math.pow(10, exp);
17517		},
17518		getPixelForValue: function(value) {
17519			var me = this;
17520			var reverse = me.options.ticks.reverse;
17521			var log10 = helpers.log10;
17522			var firstTickValue = me._getFirstTickValue(me.minNotZero);
17523			var offset = 0;
17524			var innerDimension, pixel, start, end, sign;
17525
17526			value = +me.getRightValue(value);
17527			if (reverse) {
17528				start = me.end;
17529				end = me.start;
17530				sign = -1;
17531			} else {
17532				start = me.start;
17533				end = me.end;
17534				sign = 1;
17535			}
17536			if (me.isHorizontal()) {
17537				innerDimension = me.width;
17538				pixel = reverse ? me.right : me.left;
17539			} else {
17540				innerDimension = me.height;
17541				sign *= -1; // invert, since the upper-left corner of the canvas is at pixel (0, 0)
17542				pixel = reverse ? me.top : me.bottom;
17543			}
17544			if (value !== start) {
17545				if (start === 0) { // include zero tick
17546					offset = helpers.getValueOrDefault(
17547						me.options.ticks.fontSize,
17548						Chart.defaults.global.defaultFontSize
17549					);
17550					innerDimension -= offset;
17551					start = firstTickValue;
17552				}
17553				if (value !== 0) {
17554					offset += innerDimension / (log10(end) - log10(start)) * (log10(value) - log10(start));
17555				}
17556				pixel += sign * offset;
17557			}
17558			return pixel;
17559		},
17560		getValueForPixel: function(pixel) {
17561			var me = this;
17562			var reverse = me.options.ticks.reverse;
17563			var log10 = helpers.log10;
17564			var firstTickValue = me._getFirstTickValue(me.minNotZero);
17565			var innerDimension, start, end, value;
17566
17567			if (reverse) {
17568				start = me.end;
17569				end = me.start;
17570			} else {
17571				start = me.start;
17572				end = me.end;
17573			}
17574			if (me.isHorizontal()) {
17575				innerDimension = me.width;
17576				value = reverse ? me.right - pixel : pixel - me.left;
17577			} else {
17578				innerDimension = me.height;
17579				value = reverse ? pixel - me.top : me.bottom - pixel;
17580			}
17581			if (value !== start) {
17582				if (start === 0) { // include zero tick
17583					var offset = helpers.getValueOrDefault(
17584						me.options.ticks.fontSize,
17585						Chart.defaults.global.defaultFontSize
17586					);
17587					value -= offset;
17588					innerDimension -= offset;
17589					start = firstTickValue;
17590				}
17591				value *= log10(end) - log10(start);
17592				value /= innerDimension;
17593				value = Math.pow(10, log10(start) + value);
17594			}
17595			return value;
17596		}
17597	});
17598	Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig);
17599
17600};
17601
17602},{"34":34,"45":45}],57:[function(require,module,exports){
17603'use strict';
17604
17605var defaults = require(25);
17606var helpers = require(45);
17607var Ticks = require(34);
17608
17609module.exports = function(Chart) {
17610
17611	var globalDefaults = defaults.global;
17612
17613	var defaultConfig = {
17614		display: true,
17615
17616		// Boolean - Whether to animate scaling the chart from the centre
17617		animate: true,
17618		position: 'chartArea',
17619
17620		angleLines: {
17621			display: true,
17622			color: 'rgba(0, 0, 0, 0.1)',
17623			lineWidth: 1
17624		},
17625
17626		gridLines: {
17627			circular: false
17628		},
17629
17630		// label settings
17631		ticks: {
17632			// Boolean - Show a backdrop to the scale label
17633			showLabelBackdrop: true,
17634
17635			// String - The colour of the label backdrop
17636			backdropColor: 'rgba(255,255,255,0.75)',
17637
17638			// Number - The backdrop padding above & below the label in pixels
17639			backdropPaddingY: 2,
17640
17641			// Number - The backdrop padding to the side of the label in pixels
17642			backdropPaddingX: 2,
17643
17644			callback: Ticks.formatters.linear
17645		},
17646
17647		pointLabels: {
17648			// Boolean - if true, show point labels
17649			display: true,
17650
17651			// Number - Point label font size in pixels
17652			fontSize: 10,
17653
17654			// Function - Used to convert point labels
17655			callback: function(label) {
17656				return label;
17657			}
17658		}
17659	};
17660
17661	function getValueCount(scale) {
17662		var opts = scale.options;
17663		return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
17664	}
17665
17666	function getPointLabelFontOptions(scale) {
17667		var pointLabelOptions = scale.options.pointLabels;
17668		var fontSize = helpers.valueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
17669		var fontStyle = helpers.valueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
17670		var fontFamily = helpers.valueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
17671		var font = helpers.fontString(fontSize, fontStyle, fontFamily);
17672
17673		return {
17674			size: fontSize,
17675			style: fontStyle,
17676			family: fontFamily,
17677			font: font
17678		};
17679	}
17680
17681	function measureLabelSize(ctx, fontSize, label) {
17682		if (helpers.isArray(label)) {
17683			return {
17684				w: helpers.longestText(ctx, ctx.font, label),
17685				h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
17686			};
17687		}
17688
17689		return {
17690			w: ctx.measureText(label).width,
17691			h: fontSize
17692		};
17693	}
17694
17695	function determineLimits(angle, pos, size, min, max) {
17696		if (angle === min || angle === max) {
17697			return {
17698				start: pos - (size / 2),
17699				end: pos + (size / 2)
17700			};
17701		} else if (angle < min || angle > max) {
17702			return {
17703				start: pos - size - 5,
17704				end: pos
17705			};
17706		}
17707
17708		return {
17709			start: pos,
17710			end: pos + size + 5
17711		};
17712	}
17713
17714	/**
17715	 * Helper function to fit a radial linear scale with point labels
17716	 */
17717	function fitWithPointLabels(scale) {
17718		/*
17719		 * Right, this is really confusing and there is a lot of maths going on here
17720		 * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
17721		 *
17722		 * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
17723		 *
17724		 * Solution:
17725		 *
17726		 * We assume the radius of the polygon is half the size of the canvas at first
17727		 * at each index we check if the text overlaps.
17728		 *
17729		 * Where it does, we store that angle and that index.
17730		 *
17731		 * After finding the largest index and angle we calculate how much we need to remove
17732		 * from the shape radius to move the point inwards by that x.
17733		 *
17734		 * We average the left and right distances to get the maximum shape radius that can fit in the box
17735		 * along with labels.
17736		 *
17737		 * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
17738		 * on each side, removing that from the size, halving it and adding the left x protrusion width.
17739		 *
17740		 * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
17741		 * and position it in the most space efficient manner
17742		 *
17743		 * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
17744		 */
17745
17746		var plFont = getPointLabelFontOptions(scale);
17747
17748		// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
17749		// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
17750		var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
17751		var furthestLimits = {
17752			r: scale.width,
17753			l: 0,
17754			t: scale.height,
17755			b: 0
17756		};
17757		var furthestAngles = {};
17758		var i, textSize, pointPosition;
17759
17760		scale.ctx.font = plFont.font;
17761		scale._pointLabelSizes = [];
17762
17763		var valueCount = getValueCount(scale);
17764		for (i = 0; i < valueCount; i++) {
17765			pointPosition = scale.getPointPosition(i, largestPossibleRadius);
17766			textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
17767			scale._pointLabelSizes[i] = textSize;
17768
17769			// Add quarter circle to make degree 0 mean top of circle
17770			var angleRadians = scale.getIndexAngle(i);
17771			var angle = helpers.toDegrees(angleRadians) % 360;
17772			var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
17773			var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
17774
17775			if (hLimits.start < furthestLimits.l) {
17776				furthestLimits.l = hLimits.start;
17777				furthestAngles.l = angleRadians;
17778			}
17779
17780			if (hLimits.end > furthestLimits.r) {
17781				furthestLimits.r = hLimits.end;
17782				furthestAngles.r = angleRadians;
17783			}
17784
17785			if (vLimits.start < furthestLimits.t) {
17786				furthestLimits.t = vLimits.start;
17787				furthestAngles.t = angleRadians;
17788			}
17789
17790			if (vLimits.end > furthestLimits.b) {
17791				furthestLimits.b = vLimits.end;
17792				furthestAngles.b = angleRadians;
17793			}
17794		}
17795
17796		scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
17797	}
17798
17799	/**
17800	 * Helper function to fit a radial linear scale with no point labels
17801	 */
17802	function fit(scale) {
17803		var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
17804		scale.drawingArea = Math.round(largestPossibleRadius);
17805		scale.setCenterPoint(0, 0, 0, 0);
17806	}
17807
17808	function getTextAlignForAngle(angle) {
17809		if (angle === 0 || angle === 180) {
17810			return 'center';
17811		} else if (angle < 180) {
17812			return 'left';
17813		}
17814
17815		return 'right';
17816	}
17817
17818	function fillText(ctx, text, position, fontSize) {
17819		if (helpers.isArray(text)) {
17820			var y = position.y;
17821			var spacing = 1.5 * fontSize;
17822
17823			for (var i = 0; i < text.length; ++i) {
17824				ctx.fillText(text[i], position.x, y);
17825				y += spacing;
17826			}
17827		} else {
17828			ctx.fillText(text, position.x, position.y);
17829		}
17830	}
17831
17832	function adjustPointPositionForLabelHeight(angle, textSize, position) {
17833		if (angle === 90 || angle === 270) {
17834			position.y -= (textSize.h / 2);
17835		} else if (angle > 270 || angle < 90) {
17836			position.y -= textSize.h;
17837		}
17838	}
17839
17840	function drawPointLabels(scale) {
17841		var ctx = scale.ctx;
17842		var opts = scale.options;
17843		var angleLineOpts = opts.angleLines;
17844		var pointLabelOpts = opts.pointLabels;
17845
17846		ctx.lineWidth = angleLineOpts.lineWidth;
17847		ctx.strokeStyle = angleLineOpts.color;
17848
17849		var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
17850
17851		// Point Label Font
17852		var plFont = getPointLabelFontOptions(scale);
17853
17854		ctx.textBaseline = 'top';
17855
17856		for (var i = getValueCount(scale) - 1; i >= 0; i--) {
17857			if (angleLineOpts.display) {
17858				var outerPosition = scale.getPointPosition(i, outerDistance);
17859				ctx.beginPath();
17860				ctx.moveTo(scale.xCenter, scale.yCenter);
17861				ctx.lineTo(outerPosition.x, outerPosition.y);
17862				ctx.stroke();
17863				ctx.closePath();
17864			}
17865
17866			if (pointLabelOpts.display) {
17867				// Extra 3px out for some label spacing
17868				var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);
17869
17870				// Keep this in loop since we may support array properties here
17871				var pointLabelFontColor = helpers.valueAtIndexOrDefault(pointLabelOpts.fontColor, i, globalDefaults.defaultFontColor);
17872				ctx.font = plFont.font;
17873				ctx.fillStyle = pointLabelFontColor;
17874
17875				var angleRadians = scale.getIndexAngle(i);
17876				var angle = helpers.toDegrees(angleRadians);
17877				ctx.textAlign = getTextAlignForAngle(angle);
17878				adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
17879				fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
17880			}
17881		}
17882	}
17883
17884	function drawRadiusLine(scale, gridLineOpts, radius, index) {
17885		var ctx = scale.ctx;
17886		ctx.strokeStyle = helpers.valueAtIndexOrDefault(gridLineOpts.color, index - 1);
17887		ctx.lineWidth = helpers.valueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
17888
17889		if (scale.options.gridLines.circular) {
17890			// Draw circular arcs between the points
17891			ctx.beginPath();
17892			ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
17893			ctx.closePath();
17894			ctx.stroke();
17895		} else {
17896			// Draw straight lines connecting each index
17897			var valueCount = getValueCount(scale);
17898
17899			if (valueCount === 0) {
17900				return;
17901			}
17902
17903			ctx.beginPath();
17904			var pointPosition = scale.getPointPosition(0, radius);
17905			ctx.moveTo(pointPosition.x, pointPosition.y);
17906
17907			for (var i = 1; i < valueCount; i++) {
17908				pointPosition = scale.getPointPosition(i, radius);
17909				ctx.lineTo(pointPosition.x, pointPosition.y);
17910			}
17911
17912			ctx.closePath();
17913			ctx.stroke();
17914		}
17915	}
17916
17917	function numberOrZero(param) {
17918		return helpers.isNumber(param) ? param : 0;
17919	}
17920
17921	var LinearRadialScale = Chart.LinearScaleBase.extend({
17922		setDimensions: function() {
17923			var me = this;
17924			var opts = me.options;
17925			var tickOpts = opts.ticks;
17926			// Set the unconstrained dimension before label rotation
17927			me.width = me.maxWidth;
17928			me.height = me.maxHeight;
17929			me.xCenter = Math.round(me.width / 2);
17930			me.yCenter = Math.round(me.height / 2);
17931
17932			var minSize = helpers.min([me.height, me.width]);
17933			var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
17934			me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
17935		},
17936		determineDataLimits: function() {
17937			var me = this;
17938			var chart = me.chart;
17939			var min = Number.POSITIVE_INFINITY;
17940			var max = Number.NEGATIVE_INFINITY;
17941
17942			helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
17943				if (chart.isDatasetVisible(datasetIndex)) {
17944					var meta = chart.getDatasetMeta(datasetIndex);
17945
17946					helpers.each(dataset.data, function(rawValue, index) {
17947						var value = +me.getRightValue(rawValue);
17948						if (isNaN(value) || meta.data[index].hidden) {
17949							return;
17950						}
17951
17952						min = Math.min(value, min);
17953						max = Math.max(value, max);
17954					});
17955				}
17956			});
17957
17958			me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
17959			me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
17960
17961			// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
17962			me.handleTickRangeOptions();
17963		},
17964		getTickLimit: function() {
17965			var tickOpts = this.options.ticks;
17966			var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
17967			return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
17968		},
17969		convertTicksToLabels: function() {
17970			var me = this;
17971
17972			Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);
17973
17974			// Point labels
17975			me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
17976		},
17977		getLabelForIndex: function(index, datasetIndex) {
17978			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
17979		},
17980		fit: function() {
17981			if (this.options.pointLabels.display) {
17982				fitWithPointLabels(this);
17983			} else {
17984				fit(this);
17985			}
17986		},
17987		/**
17988		 * Set radius reductions and determine new radius and center point
17989		 * @private
17990		 */
17991		setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
17992			var me = this;
17993			var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
17994			var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
17995			var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
17996			var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);
17997
17998			radiusReductionLeft = numberOrZero(radiusReductionLeft);
17999			radiusReductionRight = numberOrZero(radiusReductionRight);
18000			radiusReductionTop = numberOrZero(radiusReductionTop);
18001			radiusReductionBottom = numberOrZero(radiusReductionBottom);
18002
18003			me.drawingArea = Math.min(
18004				Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
18005				Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
18006			me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
18007		},
18008		setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
18009			var me = this;
18010			var maxRight = me.width - rightMovement - me.drawingArea;
18011			var maxLeft = leftMovement + me.drawingArea;
18012			var maxTop = topMovement + me.drawingArea;
18013			var maxBottom = me.height - bottomMovement - me.drawingArea;
18014
18015			me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
18016			me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
18017		},
18018
18019		getIndexAngle: function(index) {
18020			var angleMultiplier = (Math.PI * 2) / getValueCount(this);
18021			var startAngle = this.chart.options && this.chart.options.startAngle ?
18022				this.chart.options.startAngle :
18023				0;
18024
18025			var startAngleRadians = startAngle * Math.PI * 2 / 360;
18026
18027			// Start from the top instead of right, so remove a quarter of the circle
18028			return index * angleMultiplier + startAngleRadians;
18029		},
18030		getDistanceFromCenterForValue: function(value) {
18031			var me = this;
18032
18033			if (value === null) {
18034				return 0; // null always in center
18035			}
18036
18037			// Take into account half font size + the yPadding of the top value
18038			var scalingFactor = me.drawingArea / (me.max - me.min);
18039			if (me.options.ticks.reverse) {
18040				return (me.max - value) * scalingFactor;
18041			}
18042			return (value - me.min) * scalingFactor;
18043		},
18044		getPointPosition: function(index, distanceFromCenter) {
18045			var me = this;
18046			var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
18047			return {
18048				x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
18049				y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
18050			};
18051		},
18052		getPointPositionForValue: function(index, value) {
18053			return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
18054		},
18055
18056		getBasePosition: function() {
18057			var me = this;
18058			var min = me.min;
18059			var max = me.max;
18060
18061			return me.getPointPositionForValue(0,
18062				me.beginAtZero ? 0 :
18063				min < 0 && max < 0 ? max :
18064				min > 0 && max > 0 ? min :
18065				0);
18066		},
18067
18068		draw: function() {
18069			var me = this;
18070			var opts = me.options;
18071			var gridLineOpts = opts.gridLines;
18072			var tickOpts = opts.ticks;
18073			var valueOrDefault = helpers.valueOrDefault;
18074
18075			if (opts.display) {
18076				var ctx = me.ctx;
18077				var startAngle = this.getIndexAngle(0);
18078
18079				// Tick Font
18080				var tickFontSize = valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
18081				var tickFontStyle = valueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
18082				var tickFontFamily = valueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
18083				var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
18084
18085				helpers.each(me.ticks, function(label, index) {
18086					// Don't draw a centre value (if it is minimum)
18087					if (index > 0 || tickOpts.reverse) {
18088						var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
18089
18090						// Draw circular lines around the scale
18091						if (gridLineOpts.display && index !== 0) {
18092							drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
18093						}
18094
18095						if (tickOpts.display) {
18096							var tickFontColor = valueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
18097							ctx.font = tickLabelFont;
18098
18099							ctx.save();
18100							ctx.translate(me.xCenter, me.yCenter);
18101							ctx.rotate(startAngle);
18102
18103							if (tickOpts.showLabelBackdrop) {
18104								var labelWidth = ctx.measureText(label).width;
18105								ctx.fillStyle = tickOpts.backdropColor;
18106								ctx.fillRect(
18107									-labelWidth / 2 - tickOpts.backdropPaddingX,
18108									-yCenterOffset - tickFontSize / 2 - tickOpts.backdropPaddingY,
18109									labelWidth + tickOpts.backdropPaddingX * 2,
18110									tickFontSize + tickOpts.backdropPaddingY * 2
18111								);
18112							}
18113
18114							ctx.textAlign = 'center';
18115							ctx.textBaseline = 'middle';
18116							ctx.fillStyle = tickFontColor;
18117							ctx.fillText(label, 0, -yCenterOffset);
18118							ctx.restore();
18119						}
18120					}
18121				});
18122
18123				if (opts.angleLines.display || opts.pointLabels.display) {
18124					drawPointLabels(me);
18125				}
18126			}
18127		}
18128	});
18129	Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig);
18130
18131};
18132
18133},{"25":25,"34":34,"45":45}],58:[function(require,module,exports){
18134/* global window: false */
18135'use strict';
18136
18137var moment = require(6);
18138moment = typeof moment === 'function' ? moment : window.moment;
18139
18140var defaults = require(25);
18141var helpers = require(45);
18142
18143// Integer constants are from the ES6 spec.
18144var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
18145var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
18146
18147var INTERVALS = {
18148	millisecond: {
18149		common: true,
18150		size: 1,
18151		steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
18152	},
18153	second: {
18154		common: true,
18155		size: 1000,
18156		steps: [1, 2, 5, 10, 30]
18157	},
18158	minute: {
18159		common: true,
18160		size: 60000,
18161		steps: [1, 2, 5, 10, 30]
18162	},
18163	hour: {
18164		common: true,
18165		size: 3600000,
18166		steps: [1, 2, 3, 6, 12]
18167	},
18168	day: {
18169		common: true,
18170		size: 86400000,
18171		steps: [1, 2, 5]
18172	},
18173	week: {
18174		common: false,
18175		size: 604800000,
18176		steps: [1, 2, 3, 4]
18177	},
18178	month: {
18179		common: true,
18180		size: 2.628e9,
18181		steps: [1, 2, 3]
18182	},
18183	quarter: {
18184		common: false,
18185		size: 7.884e9,
18186		steps: [1, 2, 3, 4]
18187	},
18188	year: {
18189		common: true,
18190		size: 3.154e10
18191	}
18192};
18193
18194var UNITS = Object.keys(INTERVALS);
18195
18196function sorter(a, b) {
18197	return a - b;
18198}
18199
18200function arrayUnique(items) {
18201	var hash = {};
18202	var out = [];
18203	var i, ilen, item;
18204
18205	for (i = 0, ilen = items.length; i < ilen; ++i) {
18206		item = items[i];
18207		if (!hash[item]) {
18208			hash[item] = true;
18209			out.push(item);
18210		}
18211	}
18212
18213	return out;
18214}
18215
18216/**
18217 * Returns an array of {time, pos} objects used to interpolate a specific `time` or position
18218 * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is
18219 * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other
18220 * extremity (left + width or top + height). Note that it would be more optimized to directly
18221 * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need
18222 * to create the lookup table. The table ALWAYS contains at least two items: min and max.
18223 *
18224 * @param {Number[]} timestamps - timestamps sorted from lowest to highest.
18225 * @param {String} distribution - If 'linear', timestamps will be spread linearly along the min
18226 * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}.
18227 * If 'series', timestamps will be positioned at the same distance from each other. In this
18228 * case, only timestamps that break the time linearity are registered, meaning that in the
18229 * best case, all timestamps are linear, the table contains only min and max.
18230 */
18231function buildLookupTable(timestamps, min, max, distribution) {
18232	if (distribution === 'linear' || !timestamps.length) {
18233		return [
18234			{time: min, pos: 0},
18235			{time: max, pos: 1}
18236		];
18237	}
18238
18239	var table = [];
18240	var items = [min];
18241	var i, ilen, prev, curr, next;
18242
18243	for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
18244		curr = timestamps[i];
18245		if (curr > min && curr < max) {
18246			items.push(curr);
18247		}
18248	}
18249
18250	items.push(max);
18251
18252	for (i = 0, ilen = items.length; i < ilen; ++i) {
18253		next = items[i + 1];
18254		prev = items[i - 1];
18255		curr = items[i];
18256
18257		// only add points that breaks the scale linearity
18258		if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) {
18259			table.push({time: curr, pos: i / (ilen - 1)});
18260		}
18261	}
18262
18263	return table;
18264}
18265
18266// @see adapted from http://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/
18267function lookup(table, key, value) {
18268	var lo = 0;
18269	var hi = table.length - 1;
18270	var mid, i0, i1;
18271
18272	while (lo >= 0 && lo <= hi) {
18273		mid = (lo + hi) >> 1;
18274		i0 = table[mid - 1] || null;
18275		i1 = table[mid];
18276
18277		if (!i0) {
18278			// given value is outside table (before first item)
18279			return {lo: null, hi: i1};
18280		} else if (i1[key] < value) {
18281			lo = mid + 1;
18282		} else if (i0[key] > value) {
18283			hi = mid - 1;
18284		} else {
18285			return {lo: i0, hi: i1};
18286		}
18287	}
18288
18289	// given value is outside table (after last item)
18290	return {lo: i1, hi: null};
18291}
18292
18293/**
18294 * Linearly interpolates the given source `value` using the table items `skey` values and
18295 * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos')
18296 * returns the position for a timestamp equal to 42. If value is out of bounds, values at
18297 * index [0, 1] or [n - 1, n] are used for the interpolation.
18298 */
18299function interpolate(table, skey, sval, tkey) {
18300	var range = lookup(table, skey, sval);
18301
18302	// Note: the lookup table ALWAYS contains at least 2 items (min and max)
18303	var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo;
18304	var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi;
18305
18306	var span = next[skey] - prev[skey];
18307	var ratio = span ? (sval - prev[skey]) / span : 0;
18308	var offset = (next[tkey] - prev[tkey]) * ratio;
18309
18310	return prev[tkey] + offset;
18311}
18312
18313/**
18314 * Convert the given value to a moment object using the given time options.
18315 * @see http://momentjs.com/docs/#/parsing/
18316 */
18317function momentify(value, options) {
18318	var parser = options.parser;
18319	var format = options.parser || options.format;
18320
18321	if (typeof parser === 'function') {
18322		return parser(value);
18323	}
18324
18325	if (typeof value === 'string' && typeof format === 'string') {
18326		return moment(value, format);
18327	}
18328
18329	if (!(value instanceof moment)) {
18330		value = moment(value);
18331	}
18332
18333	if (value.isValid()) {
18334		return value;
18335	}
18336
18337	// Labels are in an incompatible moment format and no `parser` has been provided.
18338	// The user might still use the deprecated `format` option to convert his inputs.
18339	if (typeof format === 'function') {
18340		return format(value);
18341	}
18342
18343	return value;
18344}
18345
18346function parse(input, scale) {
18347	if (helpers.isNullOrUndef(input)) {
18348		return null;
18349	}
18350
18351	var options = scale.options.time;
18352	var value = momentify(scale.getRightValue(input), options);
18353	if (!value.isValid()) {
18354		return null;
18355	}
18356
18357	if (options.round) {
18358		value.startOf(options.round);
18359	}
18360
18361	return value.valueOf();
18362}
18363
18364/**
18365 * Returns the number of unit to skip to be able to display up to `capacity` number of ticks
18366 * in `unit` for the given `min` / `max` range and respecting the interval steps constraints.
18367 */
18368function determineStepSize(min, max, unit, capacity) {
18369	var range = max - min;
18370	var interval = INTERVALS[unit];
18371	var milliseconds = interval.size;
18372	var steps = interval.steps;
18373	var i, ilen, factor;
18374
18375	if (!steps) {
18376		return Math.ceil(range / (capacity * milliseconds));
18377	}
18378
18379	for (i = 0, ilen = steps.length; i < ilen; ++i) {
18380		factor = steps[i];
18381		if (Math.ceil(range / (milliseconds * factor)) <= capacity) {
18382			break;
18383		}
18384	}
18385
18386	return factor;
18387}
18388
18389/**
18390 * Figures out what unit results in an appropriate number of auto-generated ticks
18391 */
18392function determineUnitForAutoTicks(minUnit, min, max, capacity) {
18393	var ilen = UNITS.length;
18394	var i, interval, factor;
18395
18396	for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
18397		interval = INTERVALS[UNITS[i]];
18398		factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER;
18399
18400		if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
18401			return UNITS[i];
18402		}
18403	}
18404
18405	return UNITS[ilen - 1];
18406}
18407
18408/**
18409 * Figures out what unit to format a set of ticks with
18410 */
18411function determineUnitForFormatting(ticks, minUnit, min, max) {
18412	var duration = moment.duration(moment(max).diff(moment(min)));
18413	var ilen = UNITS.length;
18414	var i, unit;
18415
18416	for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) {
18417		unit = UNITS[i];
18418		if (INTERVALS[unit].common && duration.as(unit) >= ticks.length) {
18419			return unit;
18420		}
18421	}
18422
18423	return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
18424}
18425
18426function determineMajorUnit(unit) {
18427	for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
18428		if (INTERVALS[UNITS[i]].common) {
18429			return UNITS[i];
18430		}
18431	}
18432}
18433
18434/**
18435 * Generates a maximum of `capacity` timestamps between min and max, rounded to the
18436 * `minor` unit, aligned on the `major` unit and using the given scale time `options`.
18437 * Important: this method can return ticks outside the min and max range, it's the
18438 * responsibility of the calling code to clamp values if needed.
18439 */
18440function generate(min, max, capacity, options) {
18441	var timeOpts = options.time;
18442	var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
18443	var major = determineMajorUnit(minor);
18444	var stepSize = helpers.valueOrDefault(timeOpts.stepSize, timeOpts.unitStepSize);
18445	var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
18446	var majorTicksEnabled = options.ticks.major.enabled;
18447	var interval = INTERVALS[minor];
18448	var first = moment(min);
18449	var last = moment(max);
18450	var ticks = [];
18451	var time;
18452
18453	if (!stepSize) {
18454		stepSize = determineStepSize(min, max, minor, capacity);
18455	}
18456
18457	// For 'week' unit, handle the first day of week option
18458	if (weekday) {
18459		first = first.isoWeekday(weekday);
18460		last = last.isoWeekday(weekday);
18461	}
18462
18463	// Align first/last ticks on unit
18464	first = first.startOf(weekday ? 'day' : minor);
18465	last = last.startOf(weekday ? 'day' : minor);
18466
18467	// Make sure that the last tick include max
18468	if (last < max) {
18469		last.add(1, minor);
18470	}
18471
18472	time = moment(first);
18473
18474	if (majorTicksEnabled && major && !weekday && !timeOpts.round) {
18475		// Align the first tick on the previous `minor` unit aligned on the `major` unit:
18476		// we first aligned time on the previous `major` unit then add the number of full
18477		// stepSize there is between first and the previous major time.
18478		time.startOf(major);
18479		time.add(~~((first - time) / (interval.size * stepSize)) * stepSize, minor);
18480	}
18481
18482	for (; time < last; time.add(stepSize, minor)) {
18483		ticks.push(+time);
18484	}
18485
18486	ticks.push(+time);
18487
18488	return ticks;
18489}
18490
18491/**
18492 * Returns the right and left offsets from edges in the form of {left, right}.
18493 * Offsets are added when the `offset` option is true.
18494 */
18495function computeOffsets(table, ticks, min, max, options) {
18496	var left = 0;
18497	var right = 0;
18498	var upper, lower;
18499
18500	if (options.offset && ticks.length) {
18501		if (!options.time.min) {
18502			upper = ticks.length > 1 ? ticks[1] : max;
18503			lower = ticks[0];
18504			left = (
18505				interpolate(table, 'time', upper, 'pos') -
18506				interpolate(table, 'time', lower, 'pos')
18507			) / 2;
18508		}
18509		if (!options.time.max) {
18510			upper = ticks[ticks.length - 1];
18511			lower = ticks.length > 1 ? ticks[ticks.length - 2] : min;
18512			right = (
18513				interpolate(table, 'time', upper, 'pos') -
18514				interpolate(table, 'time', lower, 'pos')
18515			) / 2;
18516		}
18517	}
18518
18519	return {left: left, right: right};
18520}
18521
18522function ticksFromTimestamps(values, majorUnit) {
18523	var ticks = [];
18524	var i, ilen, value, major;
18525
18526	for (i = 0, ilen = values.length; i < ilen; ++i) {
18527		value = values[i];
18528		major = majorUnit ? value === +moment(value).startOf(majorUnit) : false;
18529
18530		ticks.push({
18531			value: value,
18532			major: major
18533		});
18534	}
18535
18536	return ticks;
18537}
18538
18539function determineLabelFormat(data, timeOpts) {
18540	var i, momentDate, hasTime;
18541	var ilen = data.length;
18542
18543	// find the label with the most parts (milliseconds, minutes, etc.)
18544	// format all labels with the same level of detail as the most specific label
18545	for (i = 0; i < ilen; i++) {
18546		momentDate = momentify(data[i], timeOpts);
18547		if (momentDate.millisecond() !== 0) {
18548			return 'MMM D, YYYY h:mm:ss.SSS a';
18549		}
18550		if (momentDate.second() !== 0 || momentDate.minute() !== 0 || momentDate.hour() !== 0) {
18551			hasTime = true;
18552		}
18553	}
18554	if (hasTime) {
18555		return 'MMM D, YYYY h:mm:ss a';
18556	}
18557	return 'MMM D, YYYY';
18558}
18559
18560module.exports = function(Chart) {
18561
18562	var defaultConfig = {
18563		position: 'bottom',
18564
18565		/**
18566		 * Data distribution along the scale:
18567		 * - 'linear': data are spread according to their time (distances can vary),
18568		 * - 'series': data are spread at the same distance from each other.
18569		 * @see https://github.com/chartjs/Chart.js/pull/4507
18570		 * @since 2.7.0
18571		 */
18572		distribution: 'linear',
18573
18574		/**
18575		 * Scale boundary strategy (bypassed by min/max time options)
18576		 * - `data`: make sure data are fully visible, ticks outside are removed
18577		 * - `ticks`: make sure ticks are fully visible, data outside are truncated
18578		 * @see https://github.com/chartjs/Chart.js/pull/4556
18579		 * @since 2.7.0
18580		 */
18581		bounds: 'data',
18582
18583		time: {
18584			parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
18585			format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
18586			unit: false, // false == automatic or override with week, month, year, etc.
18587			round: false, // none, or override with week, month, year, etc.
18588			displayFormat: false, // DEPRECATED
18589			isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
18590			minUnit: 'millisecond',
18591
18592			// defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
18593			displayFormats: {
18594				millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
18595				second: 'h:mm:ss a', // 11:20:01 AM
18596				minute: 'h:mm a', // 11:20 AM
18597				hour: 'hA', // 5PM
18598				day: 'MMM D', // Sep 4
18599				week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
18600				month: 'MMM YYYY', // Sept 2015
18601				quarter: '[Q]Q - YYYY', // Q3
18602				year: 'YYYY' // 2015
18603			},
18604		},
18605		ticks: {
18606			autoSkip: false,
18607
18608			/**
18609			 * Ticks generation input values:
18610			 * - 'auto': generates "optimal" ticks based on scale size and time options.
18611			 * - 'data': generates ticks from data (including labels from data {t|x|y} objects).
18612			 * - 'labels': generates ticks from user given `data.labels` values ONLY.
18613			 * @see https://github.com/chartjs/Chart.js/pull/4507
18614			 * @since 2.7.0
18615			 */
18616			source: 'auto',
18617
18618			major: {
18619				enabled: false
18620			}
18621		}
18622	};
18623
18624	var TimeScale = Chart.Scale.extend({
18625		initialize: function() {
18626			if (!moment) {
18627				throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
18628			}
18629
18630			this.mergeTicksOptions();
18631
18632			Chart.Scale.prototype.initialize.call(this);
18633		},
18634
18635		update: function() {
18636			var me = this;
18637			var options = me.options;
18638
18639			// DEPRECATIONS: output a message only one time per update
18640			if (options.time && options.time.format) {
18641				console.warn('options.time.format is deprecated and replaced by options.time.parser.');
18642			}
18643
18644			return Chart.Scale.prototype.update.apply(me, arguments);
18645		},
18646
18647		/**
18648		 * Allows data to be referenced via 't' attribute
18649		 */
18650		getRightValue: function(rawValue) {
18651			if (rawValue && rawValue.t !== undefined) {
18652				rawValue = rawValue.t;
18653			}
18654			return Chart.Scale.prototype.getRightValue.call(this, rawValue);
18655		},
18656
18657		determineDataLimits: function() {
18658			var me = this;
18659			var chart = me.chart;
18660			var timeOpts = me.options.time;
18661			var unit = timeOpts.unit || 'day';
18662			var min = MAX_INTEGER;
18663			var max = MIN_INTEGER;
18664			var timestamps = [];
18665			var datasets = [];
18666			var labels = [];
18667			var i, j, ilen, jlen, data, timestamp;
18668
18669			// Convert labels to timestamps
18670			for (i = 0, ilen = chart.data.labels.length; i < ilen; ++i) {
18671				labels.push(parse(chart.data.labels[i], me));
18672			}
18673
18674			// Convert data to timestamps
18675			for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
18676				if (chart.isDatasetVisible(i)) {
18677					data = chart.data.datasets[i].data;
18678
18679					// Let's consider that all data have the same format.
18680					if (helpers.isObject(data[0])) {
18681						datasets[i] = [];
18682
18683						for (j = 0, jlen = data.length; j < jlen; ++j) {
18684							timestamp = parse(data[j], me);
18685							timestamps.push(timestamp);
18686							datasets[i][j] = timestamp;
18687						}
18688					} else {
18689						timestamps.push.apply(timestamps, labels);
18690						datasets[i] = labels.slice(0);
18691					}
18692				} else {
18693					datasets[i] = [];
18694				}
18695			}
18696
18697			if (labels.length) {
18698				// Sort labels **after** data have been converted
18699				labels = arrayUnique(labels).sort(sorter);
18700				min = Math.min(min, labels[0]);
18701				max = Math.max(max, labels[labels.length - 1]);
18702			}
18703
18704			if (timestamps.length) {
18705				timestamps = arrayUnique(timestamps).sort(sorter);
18706				min = Math.min(min, timestamps[0]);
18707				max = Math.max(max, timestamps[timestamps.length - 1]);
18708			}
18709
18710			min = parse(timeOpts.min, me) || min;
18711			max = parse(timeOpts.max, me) || max;
18712
18713			// In case there is no valid min/max, set limits based on unit time option
18714			min = min === MAX_INTEGER ? +moment().startOf(unit) : min;
18715			max = max === MIN_INTEGER ? +moment().endOf(unit) + 1 : max;
18716
18717			// Make sure that max is strictly higher than min (required by the lookup table)
18718			me.min = Math.min(min, max);
18719			me.max = Math.max(min + 1, max);
18720
18721			// PRIVATE
18722			me._horizontal = me.isHorizontal();
18723			me._table = [];
18724			me._timestamps = {
18725				data: timestamps,
18726				datasets: datasets,
18727				labels: labels
18728			};
18729		},
18730
18731		buildTicks: function() {
18732			var me = this;
18733			var min = me.min;
18734			var max = me.max;
18735			var options = me.options;
18736			var timeOpts = options.time;
18737			var timestamps = [];
18738			var ticks = [];
18739			var i, ilen, timestamp;
18740
18741			switch (options.ticks.source) {
18742			case 'data':
18743				timestamps = me._timestamps.data;
18744				break;
18745			case 'labels':
18746				timestamps = me._timestamps.labels;
18747				break;
18748			case 'auto':
18749			default:
18750				timestamps = generate(min, max, me.getLabelCapacity(min), options);
18751			}
18752
18753			if (options.bounds === 'ticks' && timestamps.length) {
18754				min = timestamps[0];
18755				max = timestamps[timestamps.length - 1];
18756			}
18757
18758			// Enforce limits with user min/max options
18759			min = parse(timeOpts.min, me) || min;
18760			max = parse(timeOpts.max, me) || max;
18761
18762			// Remove ticks outside the min/max range
18763			for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
18764				timestamp = timestamps[i];
18765				if (timestamp >= min && timestamp <= max) {
18766					ticks.push(timestamp);
18767				}
18768			}
18769
18770			me.min = min;
18771			me.max = max;
18772
18773			// PRIVATE
18774			me._unit = timeOpts.unit || determineUnitForFormatting(ticks, timeOpts.minUnit, me.min, me.max);
18775			me._majorUnit = determineMajorUnit(me._unit);
18776			me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution);
18777			me._offsets = computeOffsets(me._table, ticks, min, max, options);
18778			me._labelFormat = determineLabelFormat(me._timestamps.data, timeOpts);
18779
18780			return ticksFromTimestamps(ticks, me._majorUnit);
18781		},
18782
18783		getLabelForIndex: function(index, datasetIndex) {
18784			var me = this;
18785			var data = me.chart.data;
18786			var timeOpts = me.options.time;
18787			var label = data.labels && index < data.labels.length ? data.labels[index] : '';
18788			var value = data.datasets[datasetIndex].data[index];
18789
18790			if (helpers.isObject(value)) {
18791				label = me.getRightValue(value);
18792			}
18793			if (timeOpts.tooltipFormat) {
18794				return momentify(label, timeOpts).format(timeOpts.tooltipFormat);
18795			}
18796			if (typeof label === 'string') {
18797				return label;
18798			}
18799
18800			return momentify(label, timeOpts).format(me._labelFormat);
18801		},
18802
18803		/**
18804		 * Function to format an individual tick mark
18805		 * @private
18806		 */
18807		tickFormatFunction: function(tick, index, ticks, formatOverride) {
18808			var me = this;
18809			var options = me.options;
18810			var time = tick.valueOf();
18811			var formats = options.time.displayFormats;
18812			var minorFormat = formats[me._unit];
18813			var majorUnit = me._majorUnit;
18814			var majorFormat = formats[majorUnit];
18815			var majorTime = tick.clone().startOf(majorUnit).valueOf();
18816			var majorTickOpts = options.ticks.major;
18817			var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime;
18818			var label = tick.format(formatOverride ? formatOverride : major ? majorFormat : minorFormat);
18819			var tickOpts = major ? majorTickOpts : options.ticks.minor;
18820			var formatter = helpers.valueOrDefault(tickOpts.callback, tickOpts.userCallback);
18821
18822			return formatter ? formatter(label, index, ticks) : label;
18823		},
18824
18825		convertTicksToLabels: function(ticks) {
18826			var labels = [];
18827			var i, ilen;
18828
18829			for (i = 0, ilen = ticks.length; i < ilen; ++i) {
18830				labels.push(this.tickFormatFunction(moment(ticks[i].value), i, ticks));
18831			}
18832
18833			return labels;
18834		},
18835
18836		/**
18837		 * @private
18838		 */
18839		getPixelForOffset: function(time) {
18840			var me = this;
18841			var size = me._horizontal ? me.width : me.height;
18842			var start = me._horizontal ? me.left : me.top;
18843			var pos = interpolate(me._table, 'time', time, 'pos');
18844
18845			return start + size * (me._offsets.left + pos) / (me._offsets.left + 1 + me._offsets.right);
18846		},
18847
18848		getPixelForValue: function(value, index, datasetIndex) {
18849			var me = this;
18850			var time = null;
18851
18852			if (index !== undefined && datasetIndex !== undefined) {
18853				time = me._timestamps.datasets[datasetIndex][index];
18854			}
18855
18856			if (time === null) {
18857				time = parse(value, me);
18858			}
18859
18860			if (time !== null) {
18861				return me.getPixelForOffset(time);
18862			}
18863		},
18864
18865		getPixelForTick: function(index) {
18866			var ticks = this.getTicks();
18867			return index >= 0 && index < ticks.length ?
18868				this.getPixelForOffset(ticks[index].value) :
18869				null;
18870		},
18871
18872		getValueForPixel: function(pixel) {
18873			var me = this;
18874			var size = me._horizontal ? me.width : me.height;
18875			var start = me._horizontal ? me.left : me.top;
18876			var pos = (size ? (pixel - start) / size : 0) * (me._offsets.left + 1 + me._offsets.left) - me._offsets.right;
18877			var time = interpolate(me._table, 'pos', pos, 'time');
18878
18879			return moment(time);
18880		},
18881
18882		/**
18883		 * Crude approximation of what the label width might be
18884		 * @private
18885		 */
18886		getLabelWidth: function(label) {
18887			var me = this;
18888			var ticksOpts = me.options.ticks;
18889			var tickLabelWidth = me.ctx.measureText(label).width;
18890			var angle = helpers.toRadians(ticksOpts.maxRotation);
18891			var cosRotation = Math.cos(angle);
18892			var sinRotation = Math.sin(angle);
18893			var tickFontSize = helpers.valueOrDefault(ticksOpts.fontSize, defaults.global.defaultFontSize);
18894
18895			return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
18896		},
18897
18898		/**
18899		 * @private
18900		 */
18901		getLabelCapacity: function(exampleTime) {
18902			var me = this;
18903
18904			var formatOverride = me.options.time.displayFormats.millisecond;	// Pick the longest format for guestimation
18905
18906			var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, [], formatOverride);
18907			var tickLabelWidth = me.getLabelWidth(exampleLabel);
18908			var innerWidth = me.isHorizontal() ? me.width : me.height;
18909
18910			var capacity = Math.floor(innerWidth / tickLabelWidth);
18911			return capacity > 0 ? capacity : 1;
18912		}
18913	});
18914
18915	Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig);
18916};
18917
18918},{"25":25,"45":45,"6":6}]},{},[7])(7)
18919});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.