PageSourceSearch

https://remisse21.com.pe/wp-content/themes/beglide/plugins/chart/Chart.bundle.min.js?ver=7.1.2

js remisse21.com.pe collected 2026-10-02 01:08:33 UTC 554,337 bytes, 18,923 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: 12,479 bytes, lines 155-644
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	brown: function (val) {
382		return this.setChannel('cmyk', 2, val);
383	},
384	black: function (val) {
385		return this.setChannel('cmyk', 3, val);
386	},
387
388	hexString: function () {
389		return string.hexString(this.values.rgb);
390	},
391	rgbString: function () {
392		return string.rgbString(this.values.rgb, this.values.alpha);
393	},
394	rgbaString: function () {
395		return string.rgbaString(this.values.rgb, this.values.alpha);
396	},
397	percentString: function () {
398		return string.percentString(this.values.rgb, this.values.alpha);
399	},
400	hslString: function () {
401		return string.hslString(this.values.hsl, this.values.alpha);
402	},
403	hslaString: function () {
404		return string.hslaString(this.values.hsl, this.values.alpha);
405	},
406	hwbString: function () {
407		return string.hwbString(this.values.hwb, this.values.alpha);
408	},
409	keyword: function () {
410		return string.keyword(this.values.rgb, this.values.alpha);
411	},
412
413	rgbNumber: function () {
414		var rgb = this.values.rgb;
415		return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
416	},
417
418	luminosity: function () {
419		// http://www.w3.org/TR/WCAG20/#relativeluminancedef
420		var rgb = this.values.rgb;
421		var lum = [];
422		for (var i = 0; i < rgb.length; i++) {
423			var chan = rgb[i] / 255;
424			lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
425		}
426		return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
427	},
428
429	contrast: function (color2) {
430		// http://www.w3.org/TR/WCAG20/#contrast-ratiodef
431		var lum1 = this.luminosity();
432		var lum2 = color2.luminosity();
433		if (lum1 > lum2) {
434			return (lum1 + 0.05) / (lum2 + 0.05);
435		}
436		return (lum2 + 0.05) / (lum1 + 0.05);
437	},
438
439	level: function (color2) {
440		var contrastRatio = this.contrast(color2);
441		if (contrastRatio >= 7.1) {
442			return 'AAA';
443		}
444
445		return (contrastRatio >= 4.5) ? 'AA' : '';
446	},
447
448	dark: function () {
449		// YIQ equation from http://24ways.org/2010/calculating-color-contrast
450		var rgb = this.values.rgb;
451		var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
452		return yiq < 128;
453	},
454
455	light: function () {
456		return !this.dark();
457	},
458
459	negate: function () {
460		var rgb = [];
461		for (var i = 0; i < 3; i++) {
462			rgb[i] = 255 - this.values.rgb[i];
463		}
464		this.setValues('rgb', rgb);
465		return this;
466	},
467
468	lighten: function (ratio) {
469		var hsl = this.values.hsl;
470		hsl[2] += hsl[2] * ratio;
471		this.setValues('hsl', hsl);
472		return this;
473	},
474
475	darken: function (ratio) {
476		var hsl = this.values.hsl;
477		hsl[2] -= hsl[2] * ratio;
478		this.setValues('hsl', hsl);
479		return this;
480	},
481
482	saturate: function (ratio) {
483		var hsl = this.values.hsl;
484		hsl[1] += hsl[1] * ratio;
485		this.setValues('hsl', hsl);
486		return this;
487	},
488
489	desaturate: function (ratio) {
490		var hsl = this.values.hsl;
491		hsl[1] -= hsl[1] * ratio;
492		this.setValues('hsl', hsl);
493		return this;
494	},
495
496	whiten: function (ratio) {
497		var hwb = this.values.hwb;
498		hwb[1] += hwb[1] * ratio;
499		this.setValues('hwb', hwb);
500		return this;
501	},
502
503	blacken: function (ratio) {
504		var hwb = this.values.hwb;
505		hwb[2] += hwb[2] * ratio;
506		this.setValues('hwb', hwb);
507		return this;
508	},
509
510	greyscale: function () {
511		var rgb = this.values.rgb;
512		// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
513		var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
514		this.setValues('rgb', [val, val, val]);
515		return this;
516	},
517
518	clearer: function (ratio) {
519		var alpha = this.values.alpha;
520		this.setValues('alpha', alpha - (alpha * ratio));
521		return this;
522	},
523
524	opaquer: function (ratio) {
525		var alpha = this.values.alpha;
526		this.setValues('alpha', alpha + (alpha * ratio));
527		return this;
528	},
529
530	rotate: function (degrees) {
531		var hsl = this.values.hsl;
532		var hue = (hsl[0] + degrees) % 360;
533		hsl[0] = hue < 0 ? 360 + hue : hue;
534		this.setValues('hsl', hsl);
535		return this;
536	},
537
538	/**
539	 * Ported from sass implementation in C
540	 * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
541	 */
542	mix: function (mixinColor, weight) {
543		var color1 = this;
544		var color2 = mixinColor;
545		var p = weight === undefined ? 0.5 : weight;
546
547		var w = 2 * p - 1;
548		var a = color1.alpha() - color2.alpha();
549
550		var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
551		var w2 = 1 - w1;
552
553		return this
554			.rgb(
555				w1 * color1.red() + w2 * color2.red(),
556				w1 * color1.green() + w2 * color2.green(),
557				w1 * color1.blue() + w2 * color2.blue()
558			)
559			.alpha(color1.alpha() * p + color2.alpha() * (1 - p));
560	},
561
562	toJSON: function () {
563		return this.rgb();
564	},
565
566	clone: function () {
567		// NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
568		// making the final build way to big to embed in Chart.js. So let's do it manually,
569		// assuming that values to clone are 1 dimension arrays containing only numbers,
570		// except 'alpha' which is a number.
571		var result = new Color();
572		var source = this.values;
573		var target = result.values;
574		var value, type;
575
576		for (var prop in source) {
577			if (source.hasOwnProperty(prop)) {
578				value = source[prop];
579				type = ({}).toString.call(value);
580				if (type === '[object Array]') {
581					target[prop] = value.slice(0);
582				} else if (type === '[object Number]') {
583					target[prop] = value;
584				} else {
585					console.error('unexpected color value:', value);
586				}
587			}
588		}
589
590		return result;
591	}
592};
593
594Color.prototype.spaces = {
595	rgb: ['red', 'green', 'blue'],
596	hsl: ['hue', 'saturation', 'lightness'],
597	hsv: ['hue', 'saturation', 'value'],
598	hwb: ['hue', 'whiteness', 'blackness'],
599	cmyk: ['cyan', 'magenta', 'yellow', 'black', 'brown']
600};
601
602Color.prototype.maxes = {
603	rgb: [255, 255, 255],
604	hsl: [360, 100, 100],
605	hsv: [360, 100, 100],
606	hwb: [360, 100, 100],
607	cmyk: [100, 100, 100, 100]
608};
609
610Color.prototype.getValues = function (space) {
611	var values = this.values;
612	var vals = {};
613
614	for (var i = 0; i < space.length; i++) {
615		vals[space.charAt(i)] = values[space][i];
616	}
617
618	if (values.alpha !== 1) {
619		vals.a = values.alpha;
620	}
621
622	// {r: 255, g: 255, b: 255, a: 0.4}
623	return vals;
624};
625
626Color.prototype.setValues = function (space, vals) {
627	var values = this.values;
628	var spaces = this.spaces;
629	var maxes = this.maxes;
630	var alpha = 1;
631	var i;
632
633	this.valid = true;
634
635	if (space === 'alpha') {
636		alpha = vals;
637	} else if (vals.length) {
638		// [10, 10, 10]
639		values[space] = vals.slice(0, space.length);
640		alpha = vals[space.length];
641	} else if (vals[space.charAt(0)] !== undefined) {
642		// {r: 10, g: 10, b: 10}
643		for (i = 0; i < space.length; i++) {
644			values[space][i] = vals[space.charAt(i)];
645		}
646
647		alpha = vals.a;
648	} else if (vals[spaces[space][0]] !== undefined) {
649		// {red: 10, green: 10, blue: 10}
650		var chans = spaces[space];
651
652		for (i = 0; i < space.length; i++) {
653			values[space][i] = vals[chans[i]];
654		}
655
656		alpha = vals.alpha;
657	}
658
659	values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
660
661	if (space === 'alpha') {
662		return false;
663	}
664
665	var capped;
666
667	// cap values of the space prior converting all values
668	for (i = 0; i < space.length; i++) {
669		capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
670		values[space][i] = Math.round(capped);
671	}
672
673	// convert to all the other color spaces
674	for (var sname in spaces) {
675		if (sname !== space) {
676			values[sname] = convert[space][sname](values[space]);
677		}
678	}
679
680	return true;
681};
682
683Color.prototype.setSpace = function (space, args) {
684	var vals = args[0];
685
686	if (vals === undefined) {
687		// color.rgb()
688		return this.getValues(space);
689	}
690
691	// color.rgb(10, 10, 10)
692	if (typeof vals === 'number') {
693		vals = Array.prototype.slice.call(args);
694	}
695
696	this.setValues(space, vals);
697	return this;
698};
699
700Color.prototype.setChannel = function (space, index, val) {
701	var svalues = this.values[space];
702	if (val === undefined) {
703		// color.red()
704		return svalues[index];
705	} else if (val === svalues[index]) {
706		// color.red(color.red())
707		return this;
708	}
709
710	// color.red(100)
711	svalues[index] = val;
712	this.setValues(space, svalues);
713
714	return this;
715};
716
717if (typeof window !== 'undefined') {
718	window.Color = Color;
719}
720
721module.exports = Color;
722
723},{"1":1,"4":4}],3:[function(require,module,exports){
724/* MIT license */
725
726module.exports = {
727  rgb2hsl: rgb2hsl,
728  rgb2hsv: rgb2hsv,
729  rgb2hwb: rgb2hwb,
730  rgb2cmyk: rgb2cmyk,
731  rgb2keyword: rgb2keyword,
732  rgb2xyz: rgb2xyz,
733  rgb2lab: rgb2lab,
734  rgb2lch: rgb2lch,
735
736  hsl2rgb: hsl2rgb,
737  hsl2hsv: hsl2hsv,
738  hsl2hwb: hsl2hwb,
739  hsl2cmyk: hsl2cmyk,
740  hsl2keyword: hsl2keyword,
741
742  hsv2rgb: hsv2rgb,
743  hsv2hsl: hsv2hsl,
744  hsv2hwb: hsv2hwb,
745  hsv2cmyk: hsv2cmyk,
746  hsv2keyword: hsv2keyword,
747
748  hwb2rgb: hwb2rgb,
749  hwb2hsl: hwb2hsl,
750  hwb2hsv: hwb2hsv,
751  hwb2cmyk: hwb2cmyk,
752  hwb2keyword: hwb2keyword,
753
754  cmyk2rgb: cmyk2rgb,
755  cmyk2hsl: cmyk2hsl,
756  cmyk2hsv: cmyk2hsv,
757  cmyk2hwb: cmyk2hwb,
758  cmyk2keyword: cmyk2keyword,
759
760  keyword2rgb: keyword2rgb,
761  keyword2hsl: keyword2hsl,
762  keyword2hsv: keyword2hsv,
763  keyword2hwb: keyword2hwb,
764  keyword2cmyk: keyword2cmyk,
765  keyword2lab: keyword2lab,
766  keyword2xyz: keyword2xyz,
767
768  xyz2rgb: xyz2rgb,
769  xyz2lab: xyz2lab,
770  xyz2lch: xyz2lch,
771
772  lab2xyz: lab2xyz,
773  lab2rgb: lab2rgb,
774  lab2lch: lab2lch,
775
776  lch2lab: lch2lab,
777  lch2xyz: lch2xyz,
778  lch2rgb: lch2rgb
779}
780
781
782function rgb2hsl(rgb) {
783  var r = rgb[0]/255,
784      g = rgb[1]/255,
785      b = rgb[2]/255,
786      min = Math.min(r, g, b),
787      max = Math.max(r, g, b),
788      delta = max - min,
789      h, s, l;
790
791  if (max == min)
792    h = 0;
793  else if (r == max)
794    h = (g - b) / delta;
795  else if (g == max)
796    h = 2 + (b - r) / delta;
797  else if (b == max)
798    h = 4 + (r - g)/ delta;
799
800  h = Math.min(h * 60, 360);
801
802  if (h < 0)
803    h += 360;
804
805  l = (min + max) / 2;
806
807  if (max == min)
808    s = 0;
809  else if (l <= 0.5)
810    s = delta / (max + min);
811  else
812    s = delta / (2 - max - min);
813
814  return [h, s * 100, l * 100];
815}
816
817function rgb2hsv(rgb) {
818  var r = rgb[0],
819      g = rgb[1],
820      b = rgb[2],
821      min = Math.min(r, g, b),
822      max = Math.max(r, g, b),
823      delta = max - min,
824      h, s, v;
825
826  if (max == 0)
827    s = 0;
828  else
829    s = (delta/max * 1000)/10;
830
831  if (max == min)
832    h = 0;
833  else if (r == max)
834    h = (g - b) / delta;
835  else if (g == max)
836    h = 2 + (b - r) / delta;
837  else if (b == max)
838    h = 4 + (r - g) / delta;
839
840  h = Math.min(h * 60, 360);
841
842  if (h < 0)
843    h += 360;
844
845  v = ((max / 255) * 1000) / 10;
846
847  return [h, s, v];
848}
849
850function rgb2hwb(rgb) {
851  var r = rgb[0],
852      g = rgb[1],
853      b = rgb[2],
854      h = rgb2hsl(rgb)[0],
855      w = 1/255 * Math.min(r, Math.min(g, b)),
856      b = 1 - 1/255 * Math.max(r, Math.max(g, b));
857
858  return [h, w * 100, b * 100];
859}
860
861function rgb2cmyk(rgb) {
862  var r = rgb[0] / 255,
863      g = rgb[1] / 255,
864      b = rgb[2] / 255,
865      c, m, y, k;
866
867  k = Math.min(1 - r, 1 - g, 1 - b);
868  c = (1 - r - k) / (1 - k) || 0;
869  m = (1 - g - k) / (1 - k) || 0;
870  y = (1 - b - k) / (1 - k) || 0;
871  return [c * 100, m * 100, y * 100, k * 100];
872}
873
874function rgb2keyword(rgb) {
875  return reverseKeywords[JSON.stringify(rgb)];
876}
877
878function rgb2xyz(rgb) {
879  var r = rgb[0] / 255,
880      g = rgb[1] / 255,
881      b = rgb[2] / 255;
882
883  // assume sRGB
884  r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
885  g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
886  b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
887
888  var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
889  var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
890  var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
891
892  return [x * 100, y *100, z * 100];
893}
894
895function rgb2lab(rgb) {
896  var xyz = rgb2xyz(rgb),
897        x = xyz[0],
898        y = xyz[1],
899        z = xyz[2],
900        l, a, b;
901
902  x /= 95.047;
903  y /= 100;
904  z /= 108.883;
905
906  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
907  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
908  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
909
910  l = (116 * y) - 16;
911  a = 500 * (x - y);
912  b = 200 * (y - z);
913
914  return [l, a, b];
915}
916
917function rgb2lch(args) {
918  return lab2lch(rgb2lab(args));
919}
920
921function hsl2rgb(hsl) {
922  var h = hsl[0] / 360,
923      s = hsl[1] / 100,
924      l = hsl[2] / 100,
925      t1, t2, t3, rgb, val;
926
927  if (s == 0) {
928    val = l * 255;
929    return [val, val, val];
930  }
931
932  if (l < 0.5)
933    t2 = l * (1 + s);
934  else
935    t2 = l + s - l * s;
936  t1 = 2 * l - t2;
937
938  rgb = [0, 0, 0];
939  for (var i = 0; i < 3; i++) {
940    t3 = h + 1 / 3 * - (i - 1);
941    t3 < 0 && t3++;
942    t3 > 1 && t3--;
943
944    if (6 * t3 < 1)
945      val = t1 + (t2 - t1) * 6 * t3;
946    else if (2 * t3 < 1)
947      val = t2;
948    else if (3 * t3 < 2)
949      val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
950    else
951      val = t1;
952
953    rgb[i] = val * 255;
954  }
955
956  return rgb;
957}
958
959function hsl2hsv(hsl) {
960  var h = hsl[0],
961      s = hsl[1] / 100,
962      l = hsl[2] / 100,
963      sv, v;
964
965  if(l === 0) {
966      // no need to do calc on black
967      // also avoids divide by 0 error
968      return [0, 0, 0];
969  }
970
971  l *= 2;
972  s *= (l <= 1) ? l : 2 - l;
973  v = (l + s) / 2;
974  sv = (2 * s) / (l + s);
975  return [h, sv * 100, v * 100];
976}
977
978function hsl2hwb(args) {
979  return rgb2hwb(hsl2rgb(args));
980}
981
982function hsl2cmyk(args) {
983  return rgb2cmyk(hsl2rgb(args));
984}
985
986function hsl2keyword(args) {
987  return rgb2keyword(hsl2rgb(args));
988}
989
990
991function hsv2rgb(hsv) {
992  var h = hsv[0] / 60,
993      s = hsv[1] / 100,
994      v = hsv[2] / 100,
995      hi = Math.floor(h) % 6;
996
997  var f = h - Math.floor(h),
998      p = 255 * v * (1 - s),
999      q = 255 * v * (1 - (s * f)),
1000      t = 255 * v * (1 - (s * (1 - f))),
1001      v = 255 * v;
1002
1003  switch(hi) {
1004    case 0:
1005      return [v, t, p];
1006    case 1:
1007      return [q, v, p];
1008    case 2:
1009      return [p, v, t];
1010    case 3:
1011      return [p, q, v];
1012    case 4:
1013      return [t, p, v];
1014    case 5:
1015      return [v, p, q];
1016  }
1017}
1018
1019function hsv2hsl(hsv) {
1020  var h = hsv[0],
1021      s = hsv[1] / 100,
1022      v = hsv[2] / 100,
1023      sl, l;
1024
1025  l = (2 - s) * v;
1026  sl = s * v;
1027  sl /= (l <= 1) ? l : 2 - l;
1028  sl = sl || 0;
1029  l /= 2;
1030  return [h, sl * 100, l * 100];
1031}
1032
1033function hsv2hwb(args) {
1034  return rgb2hwb(hsv2rgb(args))
1035}
1036
1037function hsv2cmyk(args) {
1038  return rgb2cmyk(hsv2rgb(args));
1039}
1040
1041function hsv2keyword(args) {
1042  return rgb2keyword(hsv2rgb(args));
1043}
1044
1045// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
1046function hwb2rgb(hwb) {
1047  var h = hwb[0] / 360,
1048      wh = hwb[1] / 100,
1049      bl = hwb[2] / 100,
1050      ratio = wh + bl,
1051      i, v, f, n;
1052
1053  // wh + bl cant be > 1
1054  if (ratio > 1) {
1055    wh /= ratio;
1056    bl /= ratio;
1057  }
1058
1059  i = Math.floor(6 * h);
1060  v = 1 - bl;
1061  f = 6 * h - i;
1062  if ((i & 0x01) != 0) {
1063    f = 1 - f;
1064  }
1065  n = wh + f * (v - wh);  // linear interpolation
1066
1067  switch (i) {
1068    default:
1069    case 6:
1070    case 0: r = v; g = n; b = wh; break;
1071    case 1: r = n; g = v; b = wh; break;
1072    case 2: r = wh; g = v; b = n; break;
1073    case 3: r = wh; g = n; b = v; break;
1074    case 4: r = n; g = wh; b = v; break;
1075    case 5: r = v; g = wh; b = n; break;
1076  }
1077
1078  return [r * 255, g * 255, b * 255];
1079}
1080
1081function hwb2hsl(args) {
1082  return rgb2hsl(hwb2rgb(args));
1083}
1084
1085function hwb2hsv(args) {
1086  return rgb2hsv(hwb2rgb(args));
1087}
1088
1089function hwb2cmyk(args) {
1090  return rgb2cmyk(hwb2rgb(args));
1091}
1092
1093function hwb2keyword(args) {
1094  return rgb2keyword(hwb2rgb(args));
1095}
1096
1097function cmyk2rgb(cmyk) {
1098  var c = cmyk[0] / 100,
1099      m = cmyk[1] / 100,
1100      y = cmyk[2] / 100,
1101      k = cmyk[3] / 100,
1102      r, g, b;
1103
1104  r = 1 - Math.min(1, c * (1 - k) + k);
1105  g = 1 - Math.min(1, m * (1 - k) + k);
1106  b = 1 - Math.min(1, y * (1 - k) + k);
1107  return [r * 255, g * 255, b * 255];
1108}
1109
1110function cmyk2hsl(args) {
1111  return rgb2hsl(cmyk2rgb(args));
1112}
1113
1114function cmyk2hsv(args) {
1115  return rgb2hsv(cmyk2rgb(args));
1116}
1117
1118function cmyk2hwb(args) {
1119  return rgb2hwb(cmyk2rgb(args));
1120}
1121
1122function cmyk2keyword(args) {
1123  return rgb2keyword(cmyk2rgb(args));
1124}
1125
1126
1127function xyz2rgb(xyz) {
1128  var x = xyz[0] / 100,
1129      y = xyz[1] / 100,
1130      z = xyz[2] / 100,
1131      r, g, b;
1132
1133  r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
1134  g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
1135  b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
1136
1137  // assume sRGB
1138  r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
1139    : r = (r * 12.92);
1140
1141  g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
1142    : g = (g * 12.92);
1143
1144  b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
1145    : b = (b * 12.92);
1146
1147  r = Math.min(Math.max(0, r), 1);
1148  g = Math.min(Math.max(0, g), 1);
1149  b = Math.min(Math.max(0, b), 1);
1150
1151  return [r * 255, g * 255, b * 255];
1152}
1153
1154function xyz2lab(xyz) {
1155  var x = xyz[0],
1156      y = xyz[1],
1157      z = xyz[2],
1158      l, a, b;
1159
1160  x /= 95.047;
1161  y /= 100;
1162  z /= 108.883;
1163
1164  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
1165  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
1166  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
1167
1168  l = (116 * y) - 16;
1169  a = 500 * (x - y);
1170  b = 200 * (y - z);
1171
1172  return [l, a, b];
1173}
1174
1175function xyz2lch(args) {
1176  return lab2lch(xyz2lab(args));
1177}
1178
1179function lab2xyz(lab) {
1180  var l = lab[0],
1181      a = lab[1],
1182      b = lab[2],
1183      x, y, z, y2;
1184
1185  if (l <= 8) {
1186    y = (l * 100) / 903.3;
1187    y2 = (7.787 * (y / 100)) + (16 / 116);
1188  } else {
1189    y = 100 * Math.pow((l + 16) / 116, 3);
1190    y2 = Math.pow(y / 100, 1/3);
1191  }
1192
1193  x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
1194
1195  z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
1196
1197  return [x, y, z];
1198}
1199
1200function lab2lch(lab) {
1201  var l = lab[0],
1202      a = lab[1],
1203      b = lab[2],
1204      hr, h, c;
1205
1206  hr = Math.atan2(b, a);
1207  h = hr * 360 / 2 / Math.PI;
1208  if (h < 0) {
1209    h += 360;
1210  }
1211  c = Math.sqrt(a * a + b * b);
1212  return [l, c, h];
1213}
1214
1215function lab2rgb(args) {
1216  return xyz2rgb(lab2xyz(args));
1217}
1218
1219function lch2lab(lch) {
1220  var l = lch[0],
1221      c = lch[1],
1222      h = lch[2],
1223      a, b, hr;
1224
1225  hr = h / 360 * 2 * Math.PI;
1226  a = c * Math.cos(hr);
1227  b = c * Math.sin(hr);
1228  return [l, a, b];
1229}
1230
1231function lch2xyz(args) {
1232  return lab2xyz(lch2lab(args));
1233}
1234
1235function lch2rgb(args) {
1236  return lab2rgb(lch2lab(args));
1237}
1238
1239function keyword2rgb(keyword) {
1240  return cssKeywords[keyword];
1241}
1242
1243function keyword2hsl(args) {
1244  return rgb2hsl(keyword2rgb(args));
1245}
1246
1247function keyword2hsv(args) {
1248  return rgb2hsv(keyword2rgb(args));
1249}
1250
1251function keyword2hwb(args) {
1252  return rgb2hwb(keyword2rgb(args));
1253}
1254
1255function keyword2cmyk(args) {
1256  return rgb2cmyk(keyword2rgb(args));
1257}
1258
1259function keyword2lab(args) {
1260  return rgb2lab(keyword2rgb(args));
1261}
1262
1263function keyword2xyz(args) {
1264  return rgb2xyz(keyword2rgb(args));
1265}
1266
1267var cssKeywords = {
1268  aliceblue:  [240,248,255],
1269  antiquewhite: [250,235,215],
1270  aqua: [0,255,255],
1271  aquamarine: [127,255,212],
1272  azure:  [240,255,255],
1273  beige:  [245,245,220],
1274  bisque: [255,228,196],
1275  black:  [0,0,0],
1276  blanchedalmond: [255,235,205],
1277  blue: [0,0,255],
1278  blueviolet: [138,43,226],
1279  brown:  [165,42,42],
1280  burlywood:  [222,184,135],
1281  cadetblue:  [95,158,160],
1282  chartreuse: [127,255,0],
1283  chocolate:  [210,105,30],
1284  coral:  [255,127,80],
1285  cornflowerblue: [100,149,237],
1286  cornsilk: [255,248,220],
1287  crimson:  [220,20,60],
1288  cyan: [0,255,255],
1289  darkblue: [0,0,139],
1290  darkcyan: [0,139,139],
1291  darkgoldenrod:  [184,134,11],
1292  darkgray: [169,169,169],
1293  darkgreen:  [0,100,0],
1294  darkgrey: [169,169,169],
1295  darkkhaki:  [189,183,107],
1296  darkmagenta:  [139,0,139],
1297  darkolivegreen: [85,107,47],
1298  darkorange: [255,140,0],
1299  darkorchid: [153,50,204],
1300  darkred:  [139,0,0],
1301  darksalmon: [233,150,122],
1302  darkseagreen: [143,188,143],
1303  darkslateblue:  [72,61,139],
1304  darkslategray:  [47,79,79],
1305  darkslategrey:  [47,79,79],
1306  darkturquoise:  [0,206,209],
1307  darkviolet: [148,0,211],
1308  deeppink: [255,20,147],
1309  deepskyblue:  [0,191,255],
1310  dimgray:  [105,105,105],
1311  dimgrey:  [105,105,105],
1312  dodgerblue: [30,144,255],
1313  firebrick:  [178,34,34],
1314  floralwhite:  [255,250,240],
1315  forestgreen:  [34,139,34],
1316  fuchsia:  [255,0,255],
1317  gainsboro:  [220,220,220],
1318  ghostwhite: [248,248,255],
1319  gold: [255,215,0],
1320  goldenrod:  [218,165,32],
1321  gray: [128,128,128],
1322  green:  [0,128,0],
1323  greenyellow:  [173,255,47],
1324  grey: [128,128,128],
1325  honeydew: [240,255,240],
1326  hotpink:  [255,105,180],
1327  indianred:  [205,92,92],
1328  indigo: [75,0,130],
1329  ivory:  [255,255,240],
1330  khaki:  [240,230,140],
1331  lavender: [230,230,250],
1332  lavenderblush:  [255,240,245],
1333  lawngreen:  [124,252,0],
1334  lemonchiffon: [255,250,205],
1335  lightblue:  [173,216,230],
1336  lightcoral: [240,128,128],
1337  lightcyan:  [224,255,255],
1338  lightgoldenrodyellow: [250,250,210],
1339  lightgray:  [211,211,211],
1340  lightgreen: [144,238,144],
1341  lightgrey:  [211,211,211],
1342  lightpink:  [255,182,193],
1343  lightsalmon:  [255,160,122],
1344  lightseagreen:  [32,178,170],
1345  lightskyblue: [135,206,250],
1346  lightslategray: [119,136,153],
1347  lightslategrey: [119,136,153],
1348  lightsteelblue: [176,196,222],
1349  lightyellow:  [255,255,224],
1350  lime: [0,255,0],
1351  limegreen:  [50,205,50],
1352  linen:  [250,240,230],
1353  magenta:  [255,0,255],
1354  maroon: [128,0,0],
1355  mediumaquamarine: [102,205,170],
1356  mediumblue: [0,0,205],
1357  mediumorchid: [186,85,211],
1358  mediumpurple: [147,112,219],
1359  mediumseagreen: [60,179,113],
1360  mediumslateblue:  [123,104,238],
1361  mediumspringgreen:  [0,250,154],
1362  mediumturquoise:  [72,209,204],
1363  mediumvioletred:  [199,21,133],
1364  midnightblue: [25,25,112],
1365  mintcream:  [245,255,250],
1366  mistyrose:  [255,228,225],
1367  moccasin: [255,228,181],
1368  navajowhite:  [255,222,173],
1369  navy: [0,0,128],
1370  oldlace:  [253,245,230],
1371  olive:  [128,128,0],
1372  olivedrab:  [107,142,35],
1373  orange: [255,165,0],
1374  orangered:  [255,69,0],
1375  orchid: [218,112,214],
1376  palegoldenrod:  [238,232,170],
1377  palegreen:  [152,251,152],
1378  paleturquoise:  [175,238,238],
1379  palevioletred:  [219,112,147],
1380  papayawhip: [255,239,213],
1381  peachpuff:  [255,218,185],
1382  peru: [205,133,63],
1383  pink: [255,192,203],
1384  plum: [221,160,221],
1385  powderblue: [176,224,230],
1386  purple: [128,0,128],
1387  rebeccapurple: [102, 51, 153],
1388  red:  [255,0,0],
1389  rosybrown:  [188,143,143],
1390  royalblue:  [65,105,225],
1391  saddlebrown:  [139,69,19],
1392  salmon: [250,128,114],
1393  sandybrown: [244,164,96],
1394  seagreen: [46,139,87],
1395  seashell: [255,245,238],
1396  sienna: [160,82,45],
1397  silver: [192,192,192],
1398  skyblue:  [135,206,235],
1399  slateblue:  [106,90,205],
1400  slategray:  [112,128,144],
1401  slategrey:  [112,128,144],
1402  snow: [255,250,250],
1403  springgreen:  [0,255,127],
1404  steelblue:  [70,130,180],
1405  tan:  [210,180,140],
1406  teal: [0,128,128],
1407  thistle:  [216,191,216],
1408  tomato: [255,99,71],
1409  turquoise:  [64,224,208],
1410  violet: [238,130,238],
1411  wheat:  [245,222,179],
1412  white:  [255,255,255],
1413  whitesmoke: [245,245,245],
1414  yellow: [255,255,0],
1415  yellowgreen:  [154,205,50]
1416};
1417
1418var reverseKeywords = {};
1419for (var key in cssKeywords) {
1420  reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
1421}
1422
1423},{}],4:[function(require,module,exports){
1424var conversions = require(3);
1425
1426var convert = function() {
1427   return new Converter();
1428}
1429
1430for (var func in conversions) {
1431  // export Raw versions
1432  convert[func + "Raw"] =  (function(func) {
1433    // accept array or plain args
1434    return function(arg) {
1435      if (typeof arg == "number")
1436        arg = Array.prototype.slice.call(arguments);
1437      return conversions[func](arg);
1438    }
1439  })(func);
1440
1441  var pair = /(\w+)2(\w+)/.exec(func),
1442      from = pair[1],
1443      to = pair[2];
1444
1445  // export rgb2hsl and ["rgb"]["hsl"]
1446  convert[from] = convert[from] || {};
1447
1448  convert[from][to] = convert[func] = (function(func) { 
1449    return function(arg) {
1450      if (typeof arg == "number")
1451        arg = Array.prototype.slice.call(arguments);
1452      
1453      var val = conversions[func](arg);
1454      if (typeof val == "string" || val === undefined)
1455        return val; // keyword
1456
1457      for (var i = 0; i < val.length; i++)
1458        val[i] = Math.round(val[i]);
1459      return val;
1460    }
1461  })(func);
1462}
1463
1464
1465/* Converter does lazy conversion and caching */
1466var Converter = function() {
1467   this.convs = {};
1468};
1469
1470/* Either get the values for a space or
1471  set the values for a space, depending on args */
1472Converter.prototype.routeSpace = function(space, args) {
1473   var values = args[0];
1474   if (values === undefined) {
1475      // color.rgb()
1476      return this.getValues(space);
1477   }
1478   // color.rgb(10, 10, 10)
1479   if (typeof values == "number") {
1480      values = Array.prototype.slice.call(args);        
1481   }
1482
1483   return this.setValues(space, values);
1484};
1485  
1486/* Set the values for a space, invalidating cache */
1487Converter.prototype.setValues = function(space, values) {
1488   this.space = space;
1489   this.convs = {};
1490   this.convs[space] = values;
1491   return this;
1492};
1493
1494/* Get the values for a space. If there's already
1495  a conversion for the space, fetch it, otherwise
1496  compute it */
1497Converter.prototype.getValues = function(space) {
1498   var vals = this.convs[space];
1499   if (!vals) {
1500      var fspace = this.space,
1501          from = this.convs[fspace];
1502      vals = convert[fspace][space](from);
1503
1504      this.convs[space] = vals;
1505   }
1506  return vals;
1507};
1508
1509["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
1510   Converter.prototype[space] = function(vals) {
1511      return this.routeSpace(space, arguments);
1512   }
1513});
1514
1515module.exports = convert;
1516},{"3":3}],5:[function(require,module,exports){
1517'use strict'
1518
1519module.exports = {
1520	"aliceblue": [240, 248, 255],
1521	"antiquewhite": [250, 235, 215],
1522	"aqua": [0, 255, 255],
1523	"aquamarine": [127, 255, 212],
1524	"azure": [240, 255, 255],
1525	"beige": [245, 245, 220],
1526	"bisque": [255, 228, 196],
1527	"black": [0, 0, 0],
1528	"blanchedalmond": [255, 235, 205],
1529	"blue": [0, 0, 255],
1530	"blueviolet": [138, 43, 226],
1531	"brown": [165, 42, 42],
1532	"burlywood": [222, 184, 135],
1533	"cadetblue": [95, 158, 160],
1534	"chartreuse": [127, 255, 0],
1535	"chocolate": [210, 105, 30],
1536	"coral": [255, 127, 80],
1537	"cornflowerblue": [100, 149, 237],
1538	"cornsilk": [255, 248, 220],
1539	"crimson": [220, 20, 60],
1540	"cyan": [0, 255, 255],
1541	"darkblue": [0, 0, 139],
1542	"darkcyan": [0, 139, 139],
1543	"darkgoldenrod": [184, 134, 11],
1544	"darkgray": [169, 169, 169],
1545	"darkgreen": [0, 100, 0],
1546	"darkgrey": [169, 169, 169],
1547	"darkkhaki": [189, 183, 107],
1548	"darkmagenta": [139, 0, 139],
1549	"darkolivegreen": [85, 107, 47],
1550	"darkorange": [255, 140, 0],
1551	"darkorchid": [153, 50, 204],
1552	"darkred": [139, 0, 0],
1553	"darksalmon": [233, 150, 122],
1554	"darkseagreen": [143, 188, 143],
1555	"darkslateblue": [72, 61, 139],
1556	"darkslategray": [47, 79, 79],
1557	"darkslategrey": [47, 79, 79],
vendor: 5,044 bytes, lines 1558-1727
1558	"darkturquoise": [0, 206, 209],
1559	"darkviolet": [148, 0, 211],
1560	"deeppink": [255, 20, 147],
1561	"deepskyblue": [0, 191, 255],
1562	"dimgray": [105, 105, 105],
1563	"dimgrey": [105, 105, 105],
1564	"dodgerblue": [30, 144, 255],
1565	"firebrick": [178, 34, 34],
1566	"floralwhite": [255, 250, 240],
1567	"forestgreen": [34, 139, 34],
1568	"fuchsia": [255, 0, 255],
1569	"gainsboro": [220, 220, 220],
1570	"ghostwhite": [248, 248, 255],
1571	"gold": [255, 215, 0],
1572	"goldenrod": [218, 165, 32],
1573	"gray": [128, 128, 128],
1574	"green": [0, 128, 0],
1575	"greenyellow": [173, 255, 47],
1576	"grey": [128, 128, 128],
1577	"honeydew": [240, 255, 240],
1578	"hotpink": [255, 105, 180],
1579	"indianred": [205, 92, 92],
1580	"indigo": [75, 0, 130],
1581	"ivory": [255, 255, 240],
1582	"khaki": [240, 230, 140],
1583	"lavender": [230, 230, 250],
1584	"lavenderblush": [255, 240, 245],
1585	"lawngreen": [124, 252, 0],
1586	"lemonchiffon": [255, 250, 205],
1587	"lightblue": [173, 216, 230],
1588	"lightcoral": [240, 128, 128],
1589	"lightcyan": [224, 255, 255],
1590	"lightgoldenrodyellow": [250, 250, 210],
1591	"lightgray": [211, 211, 211],
1592	"lightgreen": [144, 238, 144],
1593	"lightgrey": [211, 211, 211],
1594	"lightpink": [255, 182, 193],
1595	"lightsalmon": [255, 160, 122],
1596	"lightseagreen": [32, 178, 170],
1597	"lightskyblue": [135, 206, 250],
1598	"lightslategray": [119, 136, 153],
1599	"lightslategrey": [119, 136, 153],
1600	"lightsteelblue": [176, 196, 222],
1601	"lightyellow": [255, 255, 224],
1602	"lime": [0, 255, 0],
1603	"limegreen": [50, 205, 50],
1604	"linen": [250, 240, 230],
1605	"magenta": [255, 0, 255],
1606	"maroon": [128, 0, 0],
1607	"mediumaquamarine": [102, 205, 170],
1608	"mediumblue": [0, 0, 205],
1609	"mediumorchid": [186, 85, 211],
1610	"mediumpurple": [147, 112, 219],
1611	"mediumseagreen": [60, 179, 113],
1612	"mediumslateblue": [123, 104, 238],
1613	"mediumspringgreen": [0, 250, 154],
1614	"mediumturquoise": [72, 209, 204],
1615	"mediumvioletred": [199, 21, 133],
1616	"midnightblue": [25, 25, 112],
1617	"mintcream": [245, 255, 250],
1618	"mistyrose": [255, 228, 225],
1619	"moccasin": [255, 228, 181],
1620	"navajowhite": [255, 222, 173],
1621	"navy": [0, 0, 128],
1622	"oldlace": [253, 245, 230],
1623	"olive": [128, 128, 0],
1624	"olivedrab": [107, 142, 35],
1625	"orange": [255, 165, 0],
1626	"orangered": [255, 69, 0],
1627	"orchid": [218, 112, 214],
1628	"palegoldenrod": [238, 232, 170],
1629	"palegreen": [152, 251, 152],
1630	"paleturquoise": [175, 238, 238],
1631	"palevioletred": [219, 112, 147],
1632	"papayawhip": [255, 239, 213],
1633	"peachpuff": [255, 218, 185],
1634	"peru": [205, 133, 63],
1635	"pink": [255, 192, 203],
1636	"plum": [221, 160, 221],
1637	"powderblue": [176, 224, 230],
1638	"purple": [128, 0, 128],
1639	"rebeccapurple": [102, 51, 153],
1640	"red": [255, 0, 0],
1641	"rosybrown": [188, 143, 143],
1642	"royalblue": [65, 105, 225],
1643	"saddlebrown": [139, 69, 19],
1644	"salmon": [250, 128, 114],
1645	"sandybrown": [244, 164, 96],
1646	"seagreen": [46, 139, 87],
1647	"seashell": [255, 245, 238],
1648	"sienna": [160, 82, 45],
1649	"silver": [192, 192, 192],
1650	"skyblue": [135, 206, 235],
1651	"slateblue": [106, 90, 205],
1652	"slategray": [112, 128, 144],
1653	"slategrey": [112, 128, 144],
1654	"snow": [255, 250, 250],
1655	"springgreen": [0, 255, 127],
1656	"steelblue": [70, 130, 180],
1657	"tan": [210, 180, 140],
1658	"teal": [0, 128, 128],
1659	"thistle": [216, 191, 216],
1660	"tomato": [255, 99, 71],
1661	"turquoise": [64, 224, 208],
1662	"violet": [238, 130, 238],
1663	"wheat": [245, 222, 179],
1664	"white": [255, 255, 255],
1665	"whitesmoke": [245, 245, 245],
1666	"yellow": [255, 255, 0],
1667	"yellowgreen": [154, 205, 50]
1668};
1669
1670},{}],6:[function(require,module,exports){
1671//! moment.js
1672//! version : 2.20.1
1673//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
1674//! license : MIT
1675//! momentjs.com
1676
1677;(function (global, factory) {
1678    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
1679    typeof define === 'function' && define.amd ? define(factory) :
1680    global.moment = factory()
1681}(this, (function () { 'use strict';
1682
1683var hookCallback;
1684
1685function hooks () {
1686    return hookCallback.apply(null, arguments);
1687}
1688
1689// This is done to register the method called with moment()
1690// without creating circular dependencies.
1691function setHookCallback (callback) {
1692    hookCallback = callback;
1693}
1694
1695function isArray(input) {
1696    return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
1697}
1698
1699function isObject(input) {
1700    // IE8 will treat undefined and null as object if it wasn't for
1701    // input != null
1702    return input != null && Object.prototype.toString.call(input) === '[object Object]';
1703}
1704
1705function isObjectEmpty(obj) {
1706    if (Object.getOwnPropertyNames) {
1707        return (Object.getOwnPropertyNames(obj).length === 0);
1708    } else {
1709        var k;
1710        for (k in obj) {
1711            if (obj.hasOwnProperty(k)) {
1712                return false;
1713            }
1714        }
1715        return true;
1716    }
1717}
1718
1719function isUndefined(input) {
1720    return input === void 0;
1721}
1722
1723function isNumber(input) {
1724    return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
1725}
1726
1727function isDate(input) {
vendor: 22,993 bytes, lines 1728-2568
1728    return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
1729}
1730
1731function map(arr, fn) {
1732    var res = [], i;
1733    for (i = 0; i < arr.length; ++i) {
1734        res.push(fn(arr[i], i));
1735    }
1736    return res;
1737}
1738
1739function hasOwnProp(a, b) {
1740    return Object.prototype.hasOwnProperty.call(a, b);
1741}
1742
1743function extend(a, b) {
1744    for (var i in b) {
1745        if (hasOwnProp(b, i)) {
1746            a[i] = b[i];
1747        }
1748    }
1749
1750    if (hasOwnProp(b, 'toString')) {
1751        a.toString = b.toString;
1752    }
1753
1754    if (hasOwnProp(b, 'valueOf')) {
1755        a.valueOf = b.valueOf;
1756    }
1757
1758    return a;
1759}
1760
1761function createUTC (input, format, locale, strict) {
1762    return createLocalOrUTC(input, format, locale, strict, true).utc();
1763}
1764
1765function defaultParsingFlags() {
1766    // We need to deep clone this object.
1767    return {
1768        empty           : false,
1769        unusedTokens    : [],
1770        unusedInput     : [],
1771        overflow        : -2,
1772        charsLeftOver   : 0,
1773        nullInput       : false,
1774        invalidMonth    : null,
1775        invalidFormat   : false,
1776        userInvalidated : false,
1777        iso             : false,
1778        parsedDateParts : [],
1779        meridiem        : null,
1780        rfc2822         : false,
1781        weekdayMismatch : false
1782    };
1783}
1784
1785function getParsingFlags(m) {
1786    if (m._pf == null) {
1787        m._pf = defaultParsingFlags();
1788    }
1789    return m._pf;
1790}
1791
1792var some;
1793if (Array.prototype.some) {
1794    some = Array.prototype.some;
1795} else {
1796    some = function (fun) {
1797        var t = Object(this);
1798        var len = t.length >>> 0;
1799
1800        for (var i = 0; i < len; i++) {
1801            if (i in t && fun.call(this, t[i], i, t)) {
1802                return true;
1803            }
1804        }
1805
1806        return false;
1807    };
1808}
1809
1810function isValid(m) {
1811    if (m._isValid == null) {
1812        var flags = getParsingFlags(m);
1813        var parsedParts = some.call(flags.parsedDateParts, function (i) {
1814            return i != null;
1815        });
1816        var isNowValid = !isNaN(m._d.getTime()) &&
1817            flags.overflow < 0 &&
1818            !flags.empty &&
1819            !flags.invalidMonth &&
1820            !flags.invalidWeekday &&
1821            !flags.weekdayMismatch &&
1822            !flags.nullInput &&
1823            !flags.invalidFormat &&
1824            !flags.userInvalidated &&
1825            (!flags.meridiem || (flags.meridiem && parsedParts));
1826
1827        if (m._strict) {
1828            isNowValid = isNowValid &&
1829                flags.charsLeftOver === 0 &&
1830                flags.unusedTokens.length === 0 &&
1831                flags.bigHour === undefined;
1832        }
1833
1834        if (Object.isFrozen == null || !Object.isFrozen(m)) {
1835            m._isValid = isNowValid;
1836        }
1837        else {
1838            return isNowValid;
1839        }
1840    }
1841    return m._isValid;
1842}
1843
1844function createInvalid (flags) {
1845    var m = createUTC(NaN);
1846    if (flags != null) {
1847        extend(getParsingFlags(m), flags);
1848    }
1849    else {
1850        getParsingFlags(m).userInvalidated = true;
1851    }
1852
1853    return m;
1854}
1855
1856// Plugins that add properties should also add the key here (null value),
1857// so we can properly clone ourselves.
1858var momentProperties = hooks.momentProperties = [];
1859
1860function copyConfig(to, from) {
1861    var i, prop, val;
1862
1863    if (!isUndefined(from._isAMomentObject)) {
1864        to._isAMomentObject = from._isAMomentObject;
1865    }
1866    if (!isUndefined(from._i)) {
1867        to._i = from._i;
1868    }
1869    if (!isUndefined(from._f)) {
1870        to._f = from._f;
1871    }
1872    if (!isUndefined(from._l)) {
1873        to._l = from._l;
1874    }
1875    if (!isUndefined(from._strict)) {
1876        to._strict = from._strict;
1877    }
1878    if (!isUndefined(from._tzm)) {
1879        to._tzm = from._tzm;
1880    }
1881    if (!isUndefined(from._isUTC)) {
1882        to._isUTC = from._isUTC;
1883    }
1884    if (!isUndefined(from._offset)) {
1885        to._offset = from._offset;
1886    }
1887    if (!isUndefined(from._pf)) {
1888        to._pf = getParsingFlags(from);
1889    }
1890    if (!isUndefined(from._locale)) {
1891        to._locale = from._locale;
1892    }
1893
1894    if (momentProperties.length > 0) {
1895        for (i = 0; i < momentProperties.length; i++) {
1896            prop = momentProperties[i];
1897            val = from[prop];
1898            if (!isUndefined(val)) {
1899                to[prop] = val;
1900            }
1901        }
1902    }
1903
1904    return to;
1905}
1906
1907var updateInProgress = false;
1908
1909// Moment prototype object
1910function Moment(config) {
1911    copyConfig(this, config);
1912    this._d = new Date(config._d != null ? config._d.getTime() : NaN);
1913    if (!this.isValid()) {
1914        this._d = new Date(NaN);
1915    }
1916    // Prevent infinite loop in case updateOffset creates new moment
1917    // objects.
1918    if (updateInProgress === false) {
1919        updateInProgress = true;
1920        hooks.updateOffset(this);
1921        updateInProgress = false;
1922    }
1923}
1924
1925function isMoment (obj) {
1926    return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
1927}
1928
1929function absFloor (number) {
1930    if (number < 0) {
1931        // -0 -> 0
1932        return Math.ceil(number) || 0;
1933    } else {
1934        return Math.floor(number);
1935    }
1936}
1937
1938function toInt(argumentForCoercion) {
1939    var coercedNumber = +argumentForCoercion,
1940        value = 0;
1941
1942    if (coercedNumber !== 0 && isFinite(coercedNumber)) {
1943        value = absFloor(coercedNumber);
1944    }
1945
1946    return value;
1947}
1948
1949// compare two arrays, return the number of differences
1950function compareArrays(array1, array2, dontConvert) {
1951    var len = Math.min(array1.length, array2.length),
1952        lengthDiff = Math.abs(array1.length - array2.length),
1953        diffs = 0,
1954        i;
1955    for (i = 0; i < len; i++) {
1956        if ((dontConvert && array1[i] !== array2[i]) ||
1957            (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
1958            diffs++;
1959        }
1960    }
1961    return diffs + lengthDiff;
1962}
1963
1964function warn(msg) {
1965    if (hooks.suppressDeprecationWarnings === false &&
1966            (typeof console !==  'undefined') && console.warn) {
1967        console.warn('Deprecation warning: ' + msg);
1968    }
1969}
1970
1971function deprecate(msg, fn) {
1972    var firstTime = true;
1973
1974    return extend(function () {
1975        if (hooks.deprecationHandler != null) {
1976            hooks.deprecationHandler(null, msg);
1977        }
1978        if (firstTime) {
1979            var args = [];
1980            var arg;
1981            for (var i = 0; i < arguments.length; i++) {
1982                arg = '';
1983                if (typeof arguments[i] === 'object') {
1984                    arg += '\n[' + i + '] ';
1985                    for (var key in arguments[0]) {
1986                        arg += key + ': ' + arguments[0][key] + ', ';
1987                    }
1988                    arg = arg.slice(0, -2); // Remove trailing comma and space
1989                } else {
1990                    arg = arguments[i];
1991                }
1992                args.push(arg);
1993            }
1994            warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
1995            firstTime = false;
1996        }
1997        return fn.apply(this, arguments);
1998    }, fn);
1999}
2000
2001var deprecations = {};
2002
2003function deprecateSimple(name, msg) {
2004    if (hooks.deprecationHandler != null) {
2005        hooks.deprecationHandler(name, msg);
2006    }
2007    if (!deprecations[name]) {
2008        warn(msg);
2009        deprecations[name] = true;
2010    }
2011}
2012
2013hooks.suppressDeprecationWarnings = false;
2014hooks.deprecationHandler = null;
2015
2016function isFunction(input) {
2017    return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
2018}
2019
2020function set (config) {
2021    var prop, i;
2022    for (i in config) {
2023        prop = config[i];
2024        if (isFunction(prop)) {
2025            this[i] = prop;
2026        } else {
2027            this['_' + i] = prop;
2028        }
2029    }
2030    this._config = config;
2031    // Lenient ordinal parsing accepts just a number in addition to
2032    // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
2033    // TODO: Remove "ordinalParse" fallback in next major release.
2034    this._dayOfMonthOrdinalParseLenient = new RegExp(
2035        (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
2036            '|' + (/\d{1,2}/).source);
2037}
2038
2039function mergeConfigs(parentConfig, childConfig) {
2040    var res = extend({}, parentConfig), prop;
2041    for (prop in childConfig) {
2042        if (hasOwnProp(childConfig, prop)) {
2043            if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
2044                res[prop] = {};
2045                extend(res[prop], parentConfig[prop]);
2046                extend(res[prop], childConfig[prop]);
2047            } else if (childConfig[prop] != null) {
2048                res[prop] = childConfig[prop];
2049            } else {
2050                delete res[prop];
2051            }
2052        }
2053    }
2054    for (prop in parentConfig) {
2055        if (hasOwnProp(parentConfig, prop) &&
2056                !hasOwnProp(childConfig, prop) &&
2057                isObject(parentConfig[prop])) {
2058            // make sure changes to properties don't modify parent config
2059            res[prop] = extend({}, res[prop]);
2060        }
2061    }
2062    return res;
2063}
2064
2065function Locale(config) {
2066    if (config != null) {
2067        this.set(config);
2068    }
2069}
2070
2071var keys;
2072
2073if (Object.keys) {
2074    keys = Object.keys;
2075} else {
2076    keys = function (obj) {
2077        var i, res = [];
2078        for (i in obj) {
2079            if (hasOwnProp(obj, i)) {
2080                res.push(i);
2081            }
2082        }
2083        return res;
2084    };
2085}
2086
2087var defaultCalendar = {
2088    sameDay : '[Today at] LT',
2089    nextDay : '[Tomorrow at] LT',
2090    nextWeek : 'dddd [at] LT',
2091    lastDay : '[Yesterday at] LT',
2092    lastWeek : '[Last] dddd [at] LT',
2093    sameElse : 'L'
2094};
2095
2096function calendar (key, mom, now) {
2097    var output = this._calendar[key] || this._calendar['sameElse'];
2098    return isFunction(output) ? output.call(mom, now) : output;
2099}
2100
2101var defaultLongDateFormat = {
2102    LTS  : 'h:mm:ss A',
2103    LT   : 'h:mm A',
2104    L    : 'MM/DD/YYYY',
2105    LL   : 'MMMM D, YYYY',
2106    LLL  : 'MMMM D, YYYY h:mm A',
2107    LLLL : 'dddd, MMMM D, YYYY h:mm A'
2108};
2109
2110function longDateFormat (key) {
2111    var format = this._longDateFormat[key],
2112        formatUpper = this._longDateFormat[key.toUpperCase()];
2113
2114    if (format || !formatUpper) {
2115        return format;
2116    }
2117
2118    this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
2119        return val.slice(1);
2120    });
2121
2122    return this._longDateFormat[key];
2123}
2124
2125var defaultInvalidDate = 'Invalid date';
2126
2127function invalidDate () {
2128    return this._invalidDate;
2129}
2130
2131var defaultOrdinal = '%d';
2132var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
2133
2134function ordinal (number) {
2135    return this._ordinal.replace('%d', number);
2136}
2137
2138var defaultRelativeTime = {
2139    future : 'in %s',
2140    past   : '%s ago',
2141    s  : 'a few seconds',
2142    ss : '%d seconds',
2143    m  : 'a minute',
2144    mm : '%d minutes',
2145    h  : 'an hour',
2146    hh : '%d hours',
2147    d  : 'a day',
2148    dd : '%d days',
2149    M  : 'a month',
2150    MM : '%d months',
2151    y  : 'a year',
2152    yy : '%d years'
2153};
2154
2155function relativeTime (number, withoutSuffix, string, isFuture) {
2156    var output = this._relativeTime[string];
2157    return (isFunction(output)) ?
2158        output(number, withoutSuffix, string, isFuture) :
2159        output.replace(/%d/i, number);
2160}
2161
2162function pastFuture (diff, output) {
2163    var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
2164    return isFunction(format) ? format(output) : format.replace(/%s/i, output);
2165}
2166
2167var aliases = {};
2168
2169function addUnitAlias (unit, shorthand) {
2170    var lowerCase = unit.toLowerCase();
2171    aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
2172}
2173
2174function normalizeUnits(units) {
2175    return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
2176}
2177
2178function normalizeObjectUnits(inputObject) {
2179    var normalizedInput = {},
2180        normalizedProp,
2181        prop;
2182
2183    for (prop in inputObject) {
2184        if (hasOwnProp(inputObject, prop)) {
2185            normalizedProp = normalizeUnits(prop);
2186            if (normalizedProp) {
2187                normalizedInput[normalizedProp] = inputObject[prop];
2188            }
2189        }
2190    }
2191
2192    return normalizedInput;
2193}
2194
2195var priorities = {};
2196
2197function addUnitPriority(unit, priority) {
2198    priorities[unit] = priority;
2199}
2200
2201function getPrioritizedUnits(unitsObj) {
2202    var units = [];
2203    for (var u in unitsObj) {
2204        units.push({unit: u, priority: priorities[u]});
2205    }
2206    units.sort(function (a, b) {
2207        return a.priority - b.priority;
2208    });
2209    return units;
2210}
2211
2212function zeroFill(number, targetLength, forceSign) {
2213    var absNumber = '' + Math.abs(number),
2214        zerosToFill = targetLength - absNumber.length,
2215        sign = number >= 0;
2216    return (sign ? (forceSign ? '+' : '') : '-') +
2217        Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
2218}
2219
2220var 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;
2221
2222var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
2223
2224var formatFunctions = {};
2225
2226var formatTokenFunctions = {};
2227
2228// token:    'M'
2229// padded:   ['MM', 2]
2230// ordinal:  'Mo'
2231// callback: function () { this.month() + 1 }
2232function addFormatToken (token, padded, ordinal, callback) {
2233    var func = callback;
2234    if (typeof callback === 'string') {
2235        func = function () {
2236            return this[callback]();
2237        };
2238    }
2239    if (token) {
2240        formatTokenFunctions[token] = func;
2241    }
2242    if (padded) {
2243        formatTokenFunctions[padded[0]] = function () {
2244            return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
2245        };
2246    }
2247    if (ordinal) {
2248        formatTokenFunctions[ordinal] = function () {
2249            return this.localeData().ordinal(func.apply(this, arguments), token);
2250        };
2251    }
2252}
2253
2254function removeFormattingTokens(input) {
2255    if (input.match(/\[[\s\S]/)) {
2256        return input.replace(/^\[|\]$/g, '');
2257    }
2258    return input.replace(/\\/g, '');
2259}
2260
2261function makeFormatFunction(format) {
2262    var array = format.match(formattingTokens), i, length;
2263
2264    for (i = 0, length = array.length; i < length; i++) {
2265        if (formatTokenFunctions[array[i]]) {
2266            array[i] = formatTokenFunctions[array[i]];
2267        } else {
2268            array[i] = removeFormattingTokens(array[i]);
2269        }
2270    }
2271
2272    return function (mom) {
2273        var output = '', i;
2274        for (i = 0; i < length; i++) {
2275            output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
2276        }
2277        return output;
2278    };
2279}
2280
2281// format date using native date object
2282function formatMoment(m, format) {
2283    if (!m.isValid()) {
2284        return m.localeData().invalidDate();
2285    }
2286
2287    format = expandFormat(format, m.localeData());
2288    formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
2289
2290    return formatFunctions[format](m);
2291}
2292
2293function expandFormat(format, locale) {
2294    var i = 5;
2295
2296    function replaceLongDateFormatTokens(input) {
2297        return locale.longDateFormat(input) || input;
2298    }
2299
2300    localFormattingTokens.lastIndex = 0;
2301    while (i >= 0 && localFormattingTokens.test(format)) {
2302        format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
2303        localFormattingTokens.lastIndex = 0;
2304        i -= 1;
2305    }
2306
2307    return format;
2308}
2309
2310var match1         = /\d/;            //       0 - 9
2311var match2         = /\d\d/;          //      00 - 99
2312var match3         = /\d{3}/;         //     000 - 999
2313var match4         = /\d{4}/;         //    0000 - 9999
2314var match6         = /[+-]?\d{6}/;    // -999999 - 999999
2315var match1to2      = /\d\d?/;         //       0 - 99
2316var match3to4      = /\d\d\d\d?/;     //     999 - 9999
2317var match5to6      = /\d\d\d\d\d\d?/; //   99999 - 999999
2318var match1to3      = /\d{1,3}/;       //       0 - 999
2319var match1to4      = /\d{1,4}/;       //       0 - 9999
2320var match1to6      = /[+-]?\d{1,6}/;  // -999999 - 999999
2321
2322var matchUnsigned  = /\d+/;           //       0 - inf
2323var matchSigned    = /[+-]?\d+/;      //    -inf - inf
2324
2325var matchOffset    = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
2326var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
2327
2328var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
2329
2330// any word (or two) characters or numbers including two/three word month in arabic.
2331// includes scottish gaelic two word and hyphenated months
2332var 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;
2333
2334
2335var regexes = {};
2336
2337function addRegexToken (token, regex, strictRegex) {
2338    regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
2339        return (isStrict && strictRegex) ? strictRegex : regex;
2340    };
2341}
2342
2343function getParseRegexForToken (token, config) {
2344    if (!hasOwnProp(regexes, token)) {
2345        return new RegExp(unescapeFormat(token));
2346    }
2347
2348    return regexes[token](config._strict, config._locale);
2349}
2350
2351// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
2352function unescapeFormat(s) {
2353    return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
2354        return p1 || p2 || p3 || p4;
2355    }));
2356}
2357
2358function regexEscape(s) {
2359    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
2360}
2361
2362var tokens = {};
2363
2364function addParseToken (token, callback) {
2365    var i, func = callback;
2366    if (typeof token === 'string') {
2367        token = [token];
2368    }
2369    if (isNumber(callback)) {
2370        func = function (input, array) {
2371            array[callback] = toInt(input);
2372        };
2373    }
2374    for (i = 0; i < token.length; i++) {
2375        tokens[token[i]] = func;
2376    }
2377}
2378
2379function addWeekParseToken (token, callback) {
2380    addParseToken(token, function (input, array, config, token) {
2381        config._w = config._w || {};
2382        callback(input, config._w, config, token);
2383    });
2384}
2385
2386function addTimeToArrayFromToken(token, input, config) {
2387    if (input != null && hasOwnProp(tokens, token)) {
2388        tokens[token](input, config._a, config, token);
2389    }
2390}
2391
2392var YEAR = 0;
2393var MONTH = 1;
2394var DATE = 2;
2395var HOUR = 3;
2396var MINUTE = 4;
2397var SECOND = 5;
2398var MILLISECOND = 6;
2399var WEEK = 7;
2400var WEEKDAY = 8;
2401
2402// FORMATTING
2403
2404addFormatToken('Y', 0, 0, function () {
2405    var y = this.year();
2406    return y <= 9999 ? '' + y : '+' + y;
2407});
2408
2409addFormatToken(0, ['YY', 2], 0, function () {
2410    return this.year() % 100;
2411});
2412
2413addFormatToken(0, ['YYYY',   4],       0, 'year');
2414addFormatToken(0, ['YYYYY',  5],       0, 'year');
2415addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
2416
2417// ALIASES
2418
2419addUnitAlias('year', 'y');
2420
2421// PRIORITIES
2422
2423addUnitPriority('year', 1);
2424
2425// PARSING
2426
2427addRegexToken('Y',      matchSigned);
2428addRegexToken('YY',     match1to2, match2);
2429addRegexToken('YYYY',   match1to4, match4);
2430addRegexToken('YYYYY',  match1to6, match6);
2431addRegexToken('YYYYYY', match1to6, match6);
2432
2433addParseToken(['YYYYY', 'YYYYYY'], YEAR);
2434addParseToken('YYYY', function (input, array) {
2435    array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
2436});
2437addParseToken('YY', function (input, array) {
2438    array[YEAR] = hooks.parseTwoDigitYear(input);
2439});
2440addParseToken('Y', function (input, array) {
2441    array[YEAR] = parseInt(input, 10);
2442});
2443
2444// HELPERS
2445
2446function daysInYear(year) {
2447    return isLeapYear(year) ? 366 : 365;
2448}
2449
2450function isLeapYear(year) {
2451    return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
2452}
2453
2454// HOOKS
2455
2456hooks.parseTwoDigitYear = function (input) {
2457    return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
2458};
2459
2460// MOMENTS
2461
2462var getSetYear = makeGetSet('FullYear', true);
2463
2464function getIsLeapYear () {
2465    return isLeapYear(this.year());
2466}
2467
2468function makeGetSet (unit, keepTime) {
2469    return function (value) {
2470        if (value != null) {
2471            set$1(this, unit, value);
2472            hooks.updateOffset(this, keepTime);
2473            return this;
2474        } else {
2475            return get(this, unit);
2476        }
2477    };
2478}
2479
2480function get (mom, unit) {
2481    return mom.isValid() ?
2482        mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
2483}
2484
2485function set$1 (mom, unit, value) {
2486    if (mom.isValid() && !isNaN(value)) {
2487        if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {
2488            mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));
2489        }
2490        else {
2491            mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
2492        }
2493    }
2494}
2495
2496// MOMENTS
2497
2498function stringGet (units) {
2499    units = normalizeUnits(units);
2500    if (isFunction(this[units])) {
2501        return this[units]();
2502    }
2503    return this;
2504}
2505
2506
2507function stringSet (units, value) {
2508    if (typeof units === 'object') {
2509        units = normalizeObjectUnits(units);
2510        var prioritized = getPrioritizedUnits(units);
2511        for (var i = 0; i < prioritized.length; i++) {
2512            this[prioritized[i].unit](units[prioritized[i].unit]);
2513        }
2514    } else {
2515        units = normalizeUnits(units);
2516        if (isFunction(this[units])) {
2517            return this[units](value);
2518        }
2519    }
2520    return this;
2521}
2522
2523function mod(n, x) {
2524    return ((n % x) + x) % x;
2525}
2526
2527var indexOf;
2528
2529if (Array.prototype.indexOf) {
2530    indexOf = Array.prototype.indexOf;
2531} else {
2532    indexOf = function (o) {
2533        // I know
2534        var i;
2535        for (i = 0; i < this.length; ++i) {
2536            if (this[i] === o) {
2537                return i;
2538            }
2539        }
2540        return -1;
2541    };
2542}
2543
2544function daysInMonth(year, month) {
2545    if (isNaN(year) || isNaN(month)) {
2546        return NaN;
2547    }
2548    var modMonth = mod(month, 12);
2549    year += (month - modMonth) / 12;
2550    return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);
2551}
2552
2553// FORMATTING
2554
2555addFormatToken('M', ['MM', 2], 'Mo', function () {
2556    return this.month() + 1;
2557});
2558
2559addFormatToken('MMM', 0, 0, function (format) {
2560    return this.localeData().monthsShort(this, format);
2561});
2562
2563addFormatToken('MMMM', 0, 0, function (format) {
2564    return this.localeData().months(this, format);
2565});
2566
2567// ALIASES
2568
vendor: 15,495 bytes, lines 2569-3076
2569addUnitAlias('month', 'M');
2570
2571// PRIORITY
2572
2573addUnitPriority('month', 8);
2574
2575// PARSING
2576
2577addRegexToken('M',    match1to2);
2578addRegexToken('MM',   match1to2, match2);
2579addRegexToken('MMM',  function (isStrict, locale) {
2580    return locale.monthsShortRegex(isStrict);
2581});
2582addRegexToken('MMMM', function (isStrict, locale) {
2583    return locale.monthsRegex(isStrict);
2584});
2585
2586addParseToken(['M', 'MM'], function (input, array) {
2587    array[MONTH] = toInt(input) - 1;
2588});
2589
2590addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
2591    var month = config._locale.monthsParse(input, token, config._strict);
2592    // if we didn't find a month name, mark the date as invalid.
2593    if (month != null) {
2594        array[MONTH] = month;
2595    } else {
2596        getParsingFlags(config).invalidMonth = input;
2597    }
2598});
2599
2600// LOCALES
2601
2602var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
2603var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
2604function localeMonths (m, format) {
2605    if (!m) {
2606        return isArray(this._months) ? this._months :
2607            this._months['standalone'];
2608    }
2609    return isArray(this._months) ? this._months[m.month()] :
2610        this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
2611}
2612
2613var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
2614function localeMonthsShort (m, format) {
2615    if (!m) {
2616        return isArray(this._monthsShort) ? this._monthsShort :
2617            this._monthsShort['standalone'];
2618    }
2619    return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
2620        this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
2621}
2622
2623function handleStrictParse(monthName, format, strict) {
2624    var i, ii, mom, llc = monthName.toLocaleLowerCase();
2625    if (!this._monthsParse) {
2626        // this is not used
2627        this._monthsParse = [];
2628        this._longMonthsParse = [];
2629        this._shortMonthsParse = [];
2630        for (i = 0; i < 12; ++i) {
2631            mom = createUTC([2000, i]);
2632            this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
2633            this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
2634        }
2635    }
2636
2637    if (strict) {
2638        if (format === 'MMM') {
2639            ii = indexOf.call(this._shortMonthsParse, llc);
2640            return ii !== -1 ? ii : null;
2641        } else {
2642            ii = indexOf.call(this._longMonthsParse, llc);
2643            return ii !== -1 ? ii : null;
2644        }
2645    } else {
2646        if (format === 'MMM') {
2647            ii = indexOf.call(this._shortMonthsParse, llc);
2648            if (ii !== -1) {
2649                return ii;
2650            }
2651            ii = indexOf.call(this._longMonthsParse, llc);
2652            return ii !== -1 ? ii : null;
2653        } else {
2654            ii = indexOf.call(this._longMonthsParse, llc);
2655            if (ii !== -1) {
2656                return ii;
2657            }
2658            ii = indexOf.call(this._shortMonthsParse, llc);
2659            return ii !== -1 ? ii : null;
2660        }
2661    }
2662}
2663
2664function localeMonthsParse (monthName, format, strict) {
2665    var i, mom, regex;
2666
2667    if (this._monthsParseExact) {
2668        return handleStrictParse.call(this, monthName, format, strict);
2669    }
2670
2671    if (!this._monthsParse) {
2672        this._monthsParse = [];
2673        this._longMonthsParse = [];
2674        this._shortMonthsParse = [];
2675    }
2676
2677    // TODO: add sorting
2678    // Sorting makes sure if one month (or abbr) is a prefix of another
2679    // see sorting in computeMonthsParse
2680    for (i = 0; i < 12; i++) {
2681        // make the regex if we don't have it already
2682        mom = createUTC([2000, i]);
2683        if (strict && !this._longMonthsParse[i]) {
2684            this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
2685            this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
2686        }
2687        if (!strict && !this._monthsParse[i]) {
2688            regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
2689            this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
2690        }
2691        // test the regex
2692        if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
2693            return i;
2694        } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
2695            return i;
2696        } else if (!strict && this._monthsParse[i].test(monthName)) {
2697            return i;
2698        }
2699    }
2700}
2701
2702// MOMENTS
2703
2704function setMonth (mom, value) {
2705    var dayOfMonth;
2706
2707    if (!mom.isValid()) {
2708        // No op
2709        return mom;
2710    }
2711
2712    if (typeof value === 'string') {
2713        if (/^\d+$/.test(value)) {
2714            value = toInt(value);
2715        } else {
2716            value = mom.localeData().monthsParse(value);
2717            // TODO: Another silent failure?
2718            if (!isNumber(value)) {
2719                return mom;
2720            }
2721        }
2722    }
2723
2724    dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
2725    mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
2726    return mom;
2727}
2728
2729function getSetMonth (value) {
2730    if (value != null) {
2731        setMonth(this, value);
2732        hooks.updateOffset(this, true);
2733        return this;
2734    } else {
2735        return get(this, 'Month');
2736    }
2737}
2738
2739function getDaysInMonth () {
2740    return daysInMonth(this.year(), this.month());
2741}
2742
2743var defaultMonthsShortRegex = matchWord;
2744function monthsShortRegex (isStrict) {
2745    if (this._monthsParseExact) {
2746        if (!hasOwnProp(this, '_monthsRegex')) {
2747            computeMonthsParse.call(this);
2748        }
2749        if (isStrict) {
2750            return this._monthsShortStrictRegex;
2751        } else {
2752            return this._monthsShortRegex;
2753        }
2754    } else {
2755        if (!hasOwnProp(this, '_monthsShortRegex')) {
2756            this._monthsShortRegex = defaultMonthsShortRegex;
2757        }
2758        return this._monthsShortStrictRegex && isStrict ?
2759            this._monthsShortStrictRegex : this._monthsShortRegex;
2760    }
2761}
2762
2763var defaultMonthsRegex = matchWord;
2764function monthsRegex (isStrict) {
2765    if (this._monthsParseExact) {
2766        if (!hasOwnProp(this, '_monthsRegex')) {
2767            computeMonthsParse.call(this);
2768        }
2769        if (isStrict) {
2770            return this._monthsStrictRegex;
2771        } else {
2772            return this._monthsRegex;
2773        }
2774    } else {
2775        if (!hasOwnProp(this, '_monthsRegex')) {
2776            this._monthsRegex = defaultMonthsRegex;
2777        }
2778        return this._monthsStrictRegex && isStrict ?
2779            this._monthsStrictRegex : this._monthsRegex;
2780    }
2781}
2782
2783function computeMonthsParse () {
2784    function cmpLenRev(a, b) {
2785        return b.length - a.length;
2786    }
2787
2788    var shortPieces = [], longPieces = [], mixedPieces = [],
2789        i, mom;
2790    for (i = 0; i < 12; i++) {
2791        // make the regex if we don't have it already
2792        mom = createUTC([2000, i]);
2793        shortPieces.push(this.monthsShort(mom, ''));
2794        longPieces.push(this.months(mom, ''));
2795        mixedPieces.push(this.months(mom, ''));
2796        mixedPieces.push(this.monthsShort(mom, ''));
2797    }
2798    // Sorting makes sure if one month (or abbr) is a prefix of another it
2799    // will match the longer piece.
2800    shortPieces.sort(cmpLenRev);
2801    longPieces.sort(cmpLenRev);
2802    mixedPieces.sort(cmpLenRev);
2803    for (i = 0; i < 12; i++) {
2804        shortPieces[i] = regexEscape(shortPieces[i]);
2805        longPieces[i] = regexEscape(longPieces[i]);
2806    }
2807    for (i = 0; i < 24; i++) {
2808        mixedPieces[i] = regexEscape(mixedPieces[i]);
2809    }
2810
2811    this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
2812    this._monthsShortRegex = this._monthsRegex;
2813    this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
2814    this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
2815}
2816
2817function createDate (y, m, d, h, M, s, ms) {
2818    // can't just apply() to create a date:
2819    // https://stackoverflow.com/q/181348
2820    var date = new Date(y, m, d, h, M, s, ms);
2821
2822    // the date constructor remaps years 0-99 to 1900-1999
2823    if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
2824        date.setFullYear(y);
2825    }
2826    return date;
2827}
2828
2829function createUTCDate (y) {
2830    var date = new Date(Date.UTC.apply(null, arguments));
2831
2832    // the Date.UTC function remaps years 0-99 to 1900-1999
2833    if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
2834        date.setUTCFullYear(y);
2835    }
2836    return date;
2837}
2838
2839// start-of-first-week - start-of-year
2840function firstWeekOffset(year, dow, doy) {
2841    var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
2842        fwd = 7 + dow - doy,
2843        // first-week day local weekday -- which local weekday is fwd
2844        fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
2845
2846    return -fwdlw + fwd - 1;
2847}
2848
2849// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
2850function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
2851    var localWeekday = (7 + weekday - dow) % 7,
2852        weekOffset = firstWeekOffset(year, dow, doy),
2853        dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
2854        resYear, resDayOfYear;
2855
2856    if (dayOfYear <= 0) {
2857        resYear = year - 1;
2858        resDayOfYear = daysInYear(resYear) + dayOfYear;
2859    } else if (dayOfYear > daysInYear(year)) {
2860        resYear = year + 1;
2861        resDayOfYear = dayOfYear - daysInYear(year);
2862    } else {
2863        resYear = year;
2864        resDayOfYear = dayOfYear;
2865    }
2866
2867    return {
2868        year: resYear,
2869        dayOfYear: resDayOfYear
2870    };
2871}
2872
2873function weekOfYear(mom, dow, doy) {
2874    var weekOffset = firstWeekOffset(mom.year(), dow, doy),
2875        week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
2876        resWeek, resYear;
2877
2878    if (week < 1) {
2879        resYear = mom.year() - 1;
2880        resWeek = week + weeksInYear(resYear, dow, doy);
2881    } else if (week > weeksInYear(mom.year(), dow, doy)) {
2882        resWeek = week - weeksInYear(mom.year(), dow, doy);
2883        resYear = mom.year() + 1;
2884    } else {
2885        resYear = mom.year();
2886        resWeek = week;
2887    }
2888
2889    return {
2890        week: resWeek,
2891        year: resYear
2892    };
2893}
2894
2895function weeksInYear(year, dow, doy) {
2896    var weekOffset = firstWeekOffset(year, dow, doy),
2897        weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
2898    return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
2899}
2900
2901// FORMATTING
2902
2903addFormatToken('w', ['ww', 2], 'wo', 'week');
2904addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
2905
2906// ALIASES
2907
2908addUnitAlias('week', 'w');
2909addUnitAlias('isoWeek', 'W');
2910
2911// PRIORITIES
2912
2913addUnitPriority('week', 5);
2914addUnitPriority('isoWeek', 5);
2915
2916// PARSING
2917
2918addRegexToken('w',  match1to2);
2919addRegexToken('ww', match1to2, match2);
2920addRegexToken('W',  match1to2);
2921addRegexToken('WW', match1to2, match2);
2922
2923addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
2924    week[token.substr(0, 1)] = toInt(input);
2925});
2926
2927// HELPERS
2928
2929// LOCALES
2930
2931function localeWeek (mom) {
2932    return weekOfYear(mom, this._week.dow, this._week.doy).week;
2933}
2934
2935var defaultLocaleWeek = {
2936    dow : 0, // Sunday is the first day of the week.
2937    doy : 6  // The week that contains Jan 1st is the first week of the year.
2938};
2939
2940function localeFirstDayOfWeek () {
2941    return this._week.dow;
2942}
2943
2944
2945function localeFirstDayOfYear () {
2946    return this._week.doy;
2947}
2948
2949// MOMENTS
2950
2951function getSetWeek (input) {
2952    var week = this.localeData().week(this);
2953    return input == null ? week : this.add((input - week) * 7, 'd');
2954}
2955
2956function getSetISOWeek (input) {
2957    var week = weekOfYear(this, 1, 4).week;
2958    return input == null ? week : this.add((input - week) * 7, 'd');
2959}
2960
2961// FORMATTING
2962
2963addFormatToken('d', 0, 'do', 'day');
2964
2965addFormatToken('dd', 0, 0, function (format) {
2966    return this.localeData().weekdaysMin(this, format);
2967});
2968
2969addFormatToken('ddd', 0, 0, function (format) {
2970    return this.localeData().weekdaysShort(this, format);
2971});
2972
2973addFormatToken('dddd', 0, 0, function (format) {
2974    return this.localeData().weekdays(this, format);
2975});
2976
2977addFormatToken('e', 0, 0, 'weekday');
2978addFormatToken('E', 0, 0, 'isoWeekday');
2979
2980// ALIASES
2981
2982addUnitAlias('day', 'd');
2983addUnitAlias('weekday', 'e');
2984addUnitAlias('isoWeekday', 'E');
2985
2986// PRIORITY
2987addUnitPriority('day', 11);
2988addUnitPriority('weekday', 11);
2989addUnitPriority('isoWeekday', 11);
2990
2991// PARSING
2992
2993addRegexToken('d',    match1to2);
2994addRegexToken('e',    match1to2);
2995addRegexToken('E',    match1to2);
2996addRegexToken('dd',   function (isStrict, locale) {
2997    return locale.weekdaysMinRegex(isStrict);
2998});
2999addRegexToken('ddd',   function (isStrict, locale) {
3000    return locale.weekdaysShortRegex(isStrict);
3001});
3002addRegexToken('dddd',   function (isStrict, locale) {
3003    return locale.weekdaysRegex(isStrict);
3004});
3005
3006addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
3007    var weekday = config._locale.weekdaysParse(input, token, config._strict);
3008    // if we didn't get a weekday name, mark the date as invalid
3009    if (weekday != null) {
3010        week.d = weekday;
3011    } else {
3012        getParsingFlags(config).invalidWeekday = input;
3013    }
3014});
3015
3016addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
3017    week[token] = toInt(input);
3018});
3019
3020// HELPERS
3021
3022function parseWeekday(input, locale) {
3023    if (typeof input !== 'string') {
3024        return input;
3025    }
3026
3027    if (!isNaN(input)) {
3028        return parseInt(input, 10);
3029    }
3030
3031    input = locale.weekdaysParse(input);
3032    if (typeof input === 'number') {
3033        return input;
3034    }
3035
3036    return null;
3037}
3038
3039function parseIsoWeekday(input, locale) {
3040    if (typeof input === 'string') {
3041        return locale.weekdaysParse(input) % 7 || 7;
3042    }
3043    return isNaN(input) ? null : input;
3044}
3045
3046// LOCALES
3047
3048var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
3049function localeWeekdays (m, format) {
3050    if (!m) {
3051        return isArray(this._weekdays) ? this._weekdays :
3052            this._weekdays['standalone'];
3053    }
3054    return isArray(this._weekdays) ? this._weekdays[m.day()] :
3055        this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
3056}
3057
3058var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
3059function localeWeekdaysShort (m) {
3060    return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
3061}
3062
3063var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
3064function localeWeekdaysMin (m) {
3065    return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
3066}
3067
3068function handleStrictParse$1(weekdayName, format, strict) {
3069    var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
3070    if (!this._weekdaysParse) {
3071        this._weekdaysParse = [];
3072        this._shortWeekdaysParse = [];
3073        this._minWeekdaysParse = [];
3074
3075        for (i = 0; i < 7; ++i) {
3076            mom = createUTC([2000, 1]).day(i);
vendor: 48,501 bytes, lines 3077-4606
3077            this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
3078            this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
3079            this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
3080        }
3081    }
3082
3083    if (strict) {
3084        if (format === 'dddd') {
3085            ii = indexOf.call(this._weekdaysParse, llc);
3086            return ii !== -1 ? ii : null;
3087        } else if (format === 'ddd') {
3088            ii = indexOf.call(this._shortWeekdaysParse, llc);
3089            return ii !== -1 ? ii : null;
3090        } else {
3091            ii = indexOf.call(this._minWeekdaysParse, llc);
3092            return ii !== -1 ? ii : null;
3093        }
3094    } else {
3095        if (format === 'dddd') {
3096            ii = indexOf.call(this._weekdaysParse, llc);
3097            if (ii !== -1) {
3098                return ii;
3099            }
3100            ii = indexOf.call(this._shortWeekdaysParse, llc);
3101            if (ii !== -1) {
3102                return ii;
3103            }
3104            ii = indexOf.call(this._minWeekdaysParse, llc);
3105            return ii !== -1 ? ii : null;
3106        } else if (format === 'ddd') {
3107            ii = indexOf.call(this._shortWeekdaysParse, llc);
3108            if (ii !== -1) {
3109                return ii;
3110            }
3111            ii = indexOf.call(this._weekdaysParse, llc);
3112            if (ii !== -1) {
3113                return ii;
3114            }
3115            ii = indexOf.call(this._minWeekdaysParse, llc);
3116            return ii !== -1 ? ii : null;
3117        } else {
3118            ii = indexOf.call(this._minWeekdaysParse, llc);
3119            if (ii !== -1) {
3120                return ii;
3121            }
3122            ii = indexOf.call(this._weekdaysParse, llc);
3123            if (ii !== -1) {
3124                return ii;
3125            }
3126            ii = indexOf.call(this._shortWeekdaysParse, llc);
3127            return ii !== -1 ? ii : null;
3128        }
3129    }
3130}
3131
3132function localeWeekdaysParse (weekdayName, format, strict) {
3133    var i, mom, regex;
3134
3135    if (this._weekdaysParseExact) {
3136        return handleStrictParse$1.call(this, weekdayName, format, strict);
3137    }
3138
3139    if (!this._weekdaysParse) {
3140        this._weekdaysParse = [];
3141        this._minWeekdaysParse = [];
3142        this._shortWeekdaysParse = [];
3143        this._fullWeekdaysParse = [];
3144    }
3145
3146    for (i = 0; i < 7; i++) {
3147        // make the regex if we don't have it already
3148
3149        mom = createUTC([2000, 1]).day(i);
3150        if (strict && !this._fullWeekdaysParse[i]) {
3151            this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
3152            this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
3153            this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
3154        }
3155        if (!this._weekdaysParse[i]) {
3156            regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
3157            this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
3158        }
3159        // test the regex
3160        if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
3161            return i;
3162        } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
3163            return i;
3164        } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
3165            return i;
3166        } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
3167            return i;
3168        }
3169    }
3170}
3171
3172// MOMENTS
3173
3174function getSetDayOfWeek (input) {
3175    if (!this.isValid()) {
3176        return input != null ? this : NaN;
3177    }
3178    var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
3179    if (input != null) {
3180        input = parseWeekday(input, this.localeData());
3181        return this.add(input - day, 'd');
3182    } else {
3183        return day;
3184    }
3185}
3186
3187function getSetLocaleDayOfWeek (input) {
3188    if (!this.isValid()) {
3189        return input != null ? this : NaN;
3190    }
3191    var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
3192    return input == null ? weekday : this.add(input - weekday, 'd');
3193}
3194
3195function getSetISODayOfWeek (input) {
3196    if (!this.isValid()) {
3197        return input != null ? this : NaN;
3198    }
3199
3200    // behaves the same as moment#day except
3201    // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
3202    // as a setter, sunday should belong to the previous week.
3203
3204    if (input != null) {
3205        var weekday = parseIsoWeekday(input, this.localeData());
3206        return this.day(this.day() % 7 ? weekday : weekday - 7);
3207    } else {
3208        return this.day() || 7;
3209    }
3210}
3211
3212var defaultWeekdaysRegex = matchWord;
3213function weekdaysRegex (isStrict) {
3214    if (this._weekdaysParseExact) {
3215        if (!hasOwnProp(this, '_weekdaysRegex')) {
3216            computeWeekdaysParse.call(this);
3217        }
3218        if (isStrict) {
3219            return this._weekdaysStrictRegex;
3220        } else {
3221            return this._weekdaysRegex;
3222        }
3223    } else {
3224        if (!hasOwnProp(this, '_weekdaysRegex')) {
3225            this._weekdaysRegex = defaultWeekdaysRegex;
3226        }
3227        return this._weekdaysStrictRegex && isStrict ?
3228            this._weekdaysStrictRegex : this._weekdaysRegex;
3229    }
3230}
3231
3232var defaultWeekdaysShortRegex = matchWord;
3233function weekdaysShortRegex (isStrict) {
3234    if (this._weekdaysParseExact) {
3235        if (!hasOwnProp(this, '_weekdaysRegex')) {
3236            computeWeekdaysParse.call(this);
3237        }
3238        if (isStrict) {
3239            return this._weekdaysShortStrictRegex;
3240        } else {
3241            return this._weekdaysShortRegex;
3242        }
3243    } else {
3244        if (!hasOwnProp(this, '_weekdaysShortRegex')) {
3245            this._weekdaysShortRegex = defaultWeekdaysShortRegex;
3246        }
3247        return this._weekdaysShortStrictRegex && isStrict ?
3248            this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
3249    }
3250}
3251
3252var defaultWeekdaysMinRegex = matchWord;
3253function weekdaysMinRegex (isStrict) {
3254    if (this._weekdaysParseExact) {
3255        if (!hasOwnProp(this, '_weekdaysRegex')) {
3256            computeWeekdaysParse.call(this);
3257        }
3258        if (isStrict) {
3259            return this._weekdaysMinStrictRegex;
3260        } else {
3261            return this._weekdaysMinRegex;
3262        }
3263    } else {
3264        if (!hasOwnProp(this, '_weekdaysMinRegex')) {
3265            this._weekdaysMinRegex = defaultWeekdaysMinRegex;
3266        }
3267        return this._weekdaysMinStrictRegex && isStrict ?
3268            this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
3269    }
3270}
3271
3272
3273function computeWeekdaysParse () {
3274    function cmpLenRev(a, b) {
3275        return b.length - a.length;
3276    }
3277
3278    var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
3279        i, mom, minp, shortp, longp;
3280    for (i = 0; i < 7; i++) {
3281        // make the regex if we don't have it already
3282        mom = createUTC([2000, 1]).day(i);
3283        minp = this.weekdaysMin(mom, '');
3284        shortp = this.weekdaysShort(mom, '');
3285        longp = this.weekdays(mom, '');
3286        minPieces.push(minp);
3287        shortPieces.push(shortp);
3288        longPieces.push(longp);
3289        mixedPieces.push(minp);
3290        mixedPieces.push(shortp);
3291        mixedPieces.push(longp);
3292    }
3293    // Sorting makes sure if one weekday (or abbr) is a prefix of another it
3294    // will match the longer piece.
3295    minPieces.sort(cmpLenRev);
3296    shortPieces.sort(cmpLenRev);
3297    longPieces.sort(cmpLenRev);
3298    mixedPieces.sort(cmpLenRev);
3299    for (i = 0; i < 7; i++) {
3300        shortPieces[i] = regexEscape(shortPieces[i]);
3301        longPieces[i] = regexEscape(longPieces[i]);
3302        mixedPieces[i] = regexEscape(mixedPieces[i]);
3303    }
3304
3305    this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
3306    this._weekdaysShortRegex = this._weekdaysRegex;
3307    this._weekdaysMinRegex = this._weekdaysRegex;
3308
3309    this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
3310    this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
3311    this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
3312}
3313
3314// FORMATTING
3315
3316function hFormat() {
3317    return this.hours() % 12 || 12;
3318}
3319
3320function kFormat() {
3321    return this.hours() || 24;
3322}
3323
3324addFormatToken('H', ['HH', 2], 0, 'hour');
3325addFormatToken('h', ['hh', 2], 0, hFormat);
3326addFormatToken('k', ['kk', 2], 0, kFormat);
3327
3328addFormatToken('hmm', 0, 0, function () {
3329    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
3330});
3331
3332addFormatToken('hmmss', 0, 0, function () {
3333    return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
3334        zeroFill(this.seconds(), 2);
3335});
3336
3337addFormatToken('Hmm', 0, 0, function () {
3338    return '' + this.hours() + zeroFill(this.minutes(), 2);
3339});
3340
3341addFormatToken('Hmmss', 0, 0, function () {
3342    return '' + this.hours() + zeroFill(this.minutes(), 2) +
3343        zeroFill(this.seconds(), 2);
3344});
3345
3346function meridiem (token, lowercase) {
3347    addFormatToken(token, 0, 0, function () {
3348        return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
3349    });
3350}
3351
3352meridiem('a', true);
3353meridiem('A', false);
3354
3355// ALIASES
3356
3357addUnitAlias('hour', 'h');
3358
3359// PRIORITY
3360addUnitPriority('hour', 13);
3361
3362// PARSING
3363
3364function matchMeridiem (isStrict, locale) {
3365    return locale._meridiemParse;
3366}
3367
3368addRegexToken('a',  matchMeridiem);
3369addRegexToken('A',  matchMeridiem);
3370addRegexToken('H',  match1to2);
3371addRegexToken('h',  match1to2);
3372addRegexToken('k',  match1to2);
3373addRegexToken('HH', match1to2, match2);
3374addRegexToken('hh', match1to2, match2);
3375addRegexToken('kk', match1to2, match2);
3376
3377addRegexToken('hmm', match3to4);
3378addRegexToken('hmmss', match5to6);
3379addRegexToken('Hmm', match3to4);
3380addRegexToken('Hmmss', match5to6);
3381
3382addParseToken(['H', 'HH'], HOUR);
3383addParseToken(['k', 'kk'], function (input, array, config) {
3384    var kInput = toInt(input);
3385    array[HOUR] = kInput === 24 ? 0 : kInput;
3386});
3387addParseToken(['a', 'A'], function (input, array, config) {
3388    config._isPm = config._locale.isPM(input);
3389    config._meridiem = input;
3390});
3391addParseToken(['h', 'hh'], function (input, array, config) {
3392    array[HOUR] = toInt(input);
3393    getParsingFlags(config).bigHour = true;
3394});
3395addParseToken('hmm', function (input, array, config) {
3396    var pos = input.length - 2;
3397    array[HOUR] = toInt(input.substr(0, pos));
3398    array[MINUTE] = toInt(input.substr(pos));
3399    getParsingFlags(config).bigHour = true;
3400});
3401addParseToken('hmmss', function (input, array, config) {
3402    var pos1 = input.length - 4;
3403    var pos2 = input.length - 2;
3404    array[HOUR] = toInt(input.substr(0, pos1));
3405    array[MINUTE] = toInt(input.substr(pos1, 2));
3406    array[SECOND] = toInt(input.substr(pos2));
3407    getParsingFlags(config).bigHour = true;
3408});
3409addParseToken('Hmm', function (input, array, config) {
3410    var pos = input.length - 2;
3411    array[HOUR] = toInt(input.substr(0, pos));
3412    array[MINUTE] = toInt(input.substr(pos));
3413});
3414addParseToken('Hmmss', function (input, array, config) {
3415    var pos1 = input.length - 4;
3416    var pos2 = input.length - 2;
3417    array[HOUR] = toInt(input.substr(0, pos1));
3418    array[MINUTE] = toInt(input.substr(pos1, 2));
3419    array[SECOND] = toInt(input.substr(pos2));
3420});
3421
3422// LOCALES
3423
3424function localeIsPM (input) {
3425    // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
3426    // Using charAt should be more compatible.
3427    return ((input + '').toLowerCase().charAt(0) === 'p');
3428}
3429
3430var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
3431function localeMeridiem (hours, minutes, isLower) {
3432    if (hours > 11) {
3433        return isLower ? 'pm' : 'PM';
3434    } else {
3435        return isLower ? 'am' : 'AM';
3436    }
3437}
3438
3439
3440// MOMENTS
3441
3442// Setting the hour should keep the time, because the user explicitly
3443// specified which hour he wants. So trying to maintain the same hour (in
3444// a new timezone) makes sense. Adding/subtracting hours does not follow
3445// this rule.
3446var getSetHour = makeGetSet('Hours', true);
3447
3448// months
3449// week
3450// weekdays
3451// meridiem
3452var baseConfig = {
3453    calendar: defaultCalendar,
3454    longDateFormat: defaultLongDateFormat,
3455    invalidDate: defaultInvalidDate,
3456    ordinal: defaultOrdinal,
3457    dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
3458    relativeTime: defaultRelativeTime,
3459
3460    months: defaultLocaleMonths,
3461    monthsShort: defaultLocaleMonthsShort,
3462
3463    week: defaultLocaleWeek,
3464
3465    weekdays: defaultLocaleWeekdays,
3466    weekdaysMin: defaultLocaleWeekdaysMin,
3467    weekdaysShort: defaultLocaleWeekdaysShort,
3468
3469    meridiemParse: defaultLocaleMeridiemParse
3470};
3471
3472// internal storage for locale config files
3473var locales = {};
3474var localeFamilies = {};
3475var globalLocale;
3476
3477function normalizeLocale(key) {
3478    return key ? key.toLowerCase().replace('_', '-') : key;
3479}
3480
3481// pick the locale from the array
3482// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
3483// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
3484function chooseLocale(names) {
3485    var i = 0, j, next, locale, split;
3486
3487    while (i < names.length) {
3488        split = normalizeLocale(names[i]).split('-');
3489        j = split.length;
3490        next = normalizeLocale(names[i + 1]);
3491        next = next ? next.split('-') : null;
3492        while (j > 0) {
3493            locale = loadLocale(split.slice(0, j).join('-'));
3494            if (locale) {
3495                return locale;
3496            }
3497            if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
3498                //the next array item is better than a shallower substring of this one
3499                break;
3500            }
3501            j--;
3502        }
3503        i++;
3504    }
3505    return null;
3506}
3507
3508function loadLocale(name) {
3509    var oldLocale = null;
3510    // TODO: Find a better way to register and load all the locales in Node
3511    if (!locales[name] && (typeof module !== 'undefined') &&
3512            module && module.exports) {
3513        try {
3514            oldLocale = globalLocale._abbr;
3515            var aliasedRequire = require;
3516            aliasedRequire('./locale/' + name);
3517            getSetGlobalLocale(oldLocale);
3518        } catch (e) {}
3519    }
3520    return locales[name];
3521}
3522
3523// This function will load locale and then set the global locale.  If
3524// no arguments are passed in, it will simply return the current global
3525// locale key.
3526function getSetGlobalLocale (key, values) {
3527    var data;
3528    if (key) {
3529        if (isUndefined(values)) {
3530            data = getLocale(key);
3531        }
3532        else {
3533            data = defineLocale(key, values);
3534        }
3535
3536        if (data) {
3537            // moment.duration._locale = moment._locale = data;
3538            globalLocale = data;
3539        }
3540    }
3541
3542    return globalLocale._abbr;
3543}
3544
3545function defineLocale (name, config) {
3546    if (config !== null) {
3547        var parentConfig = baseConfig;
3548        config.abbr = name;
3549        if (locales[name] != null) {
3550            deprecateSimple('defineLocaleOverride',
3551                    'use moment.updateLocale(localeName, config) to change ' +
3552                    'an existing locale. moment.defineLocale(localeName, ' +
3553                    'config) should only be used for creating a new locale ' +
3554                    'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
3555            parentConfig = locales[name]._config;
3556        } else if (config.parentLocale != null) {
3557            if (locales[config.parentLocale] != null) {
3558                parentConfig = locales[config.parentLocale]._config;
3559            } else {
3560                if (!localeFamilies[config.parentLocale]) {
3561                    localeFamilies[config.parentLocale] = [];
3562                }
3563                localeFamilies[config.parentLocale].push({
3564                    name: name,
3565                    config: config
3566                });
3567                return null;
3568            }
3569        }
3570        locales[name] = new Locale(mergeConfigs(parentConfig, config));
3571
3572        if (localeFamilies[name]) {
3573            localeFamilies[name].forEach(function (x) {
3574                defineLocale(x.name, x.config);
3575            });
3576        }
3577
3578        // backwards compat for now: also set the locale
3579        // make sure we set the locale AFTER all child locales have been
3580        // created, so we won't end up with the child locale set.
3581        getSetGlobalLocale(name);
3582
3583
3584        return locales[name];
3585    } else {
3586        // useful for testing
3587        delete locales[name];
3588        return null;
3589    }
3590}
3591
3592function updateLocale(name, config) {
3593    if (config != null) {
3594        var locale, tmpLocale, parentConfig = baseConfig;
3595        // MERGE
3596        tmpLocale = loadLocale(name);
3597        if (tmpLocale != null) {
3598            parentConfig = tmpLocale._config;
3599        }
3600        config = mergeConfigs(parentConfig, config);
3601        locale = new Locale(config);
3602        locale.parentLocale = locales[name];
3603        locales[name] = locale;
3604
3605        // backwards compat for now: also set the locale
3606        getSetGlobalLocale(name);
3607    } else {
3608        // pass null for config to unupdate, useful for tests
3609        if (locales[name] != null) {
3610            if (locales[name].parentLocale != null) {
3611                locales[name] = locales[name].parentLocale;
3612            } else if (locales[name] != null) {
3613                delete locales[name];
3614            }
3615        }
3616    }
3617    return locales[name];
3618}
3619
3620// returns locale data
3621function getLocale (key) {
3622    var locale;
3623
3624    if (key && key._locale && key._locale._abbr) {
3625        key = key._locale._abbr;
3626    }
3627
3628    if (!key) {
3629        return globalLocale;
3630    }
3631
3632    if (!isArray(key)) {
3633        //short-circuit everything else
3634        locale = loadLocale(key);
3635        if (locale) {
3636            return locale;
3637        }
3638        key = [key];
3639    }
3640
3641    return chooseLocale(key);
3642}
3643
3644function listLocales() {
3645    return keys(locales);
3646}
3647
3648function checkOverflow (m) {
3649    var overflow;
3650    var a = m._a;
3651
3652    if (a && getParsingFlags(m).overflow === -2) {
3653        overflow =
3654            a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :
3655            a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
3656            a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
3657            a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :
3658            a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :
3659            a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
3660            -1;
3661
3662        if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
3663            overflow = DATE;
3664        }
3665        if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
3666            overflow = WEEK;
3667        }
3668        if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
3669            overflow = WEEKDAY;
3670        }
3671
3672        getParsingFlags(m).overflow = overflow;
3673    }
3674
3675    return m;
3676}
3677
3678// Pick the first defined of two or three arguments.
3679function defaults(a, b, c) {
3680    if (a != null) {
3681        return a;
3682    }
3683    if (b != null) {
3684        return b;
3685    }
3686    return c;
3687}
3688
3689function currentDateArray(config) {
3690    // hooks is actually the exported moment object
3691    var nowValue = new Date(hooks.now());
3692    if (config._useUTC) {
3693        return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
3694    }
3695    return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
3696}
3697
3698// convert an array to a date.
3699// the array should mirror the parameters below
3700// note: all values past the year are optional and will default to the lowest possible value.
3701// [year, month, day , hour, minute, second, millisecond]
3702function configFromArray (config) {
3703    var i, date, input = [], currentDate, expectedWeekday, yearToUse;
3704
3705    if (config._d) {
3706        return;
3707    }
3708
3709    currentDate = currentDateArray(config);
3710
3711    //compute day of the year from weeks and weekdays
3712    if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
3713        dayOfYearFromWeekInfo(config);
3714    }
3715
3716    //if the day of the year is set, figure out what it is
3717    if (config._dayOfYear != null) {
3718        yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
3719
3720        if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
3721            getParsingFlags(config)._overflowDayOfYear = true;
3722        }
3723
3724        date = createUTCDate(yearToUse, 0, config._dayOfYear);
3725        config._a[MONTH] = date.getUTCMonth();
3726        config._a[DATE] = date.getUTCDate();
3727    }
3728
3729    // Default to current date.
3730    // * if no year, month, day of month are given, default to today
3731    // * if day of month is given, default month and year
3732    // * if month is given, default only year
3733    // * if year is given, don't default anything
3734    for (i = 0; i < 3 && config._a[i] == null; ++i) {
3735        config._a[i] = input[i] = currentDate[i];
3736    }
3737
3738    // Zero out whatever was not defaulted, including time
3739    for (; i < 7; i++) {
3740        config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
3741    }
3742
3743    // Check for 24:00:00.000
3744    if (config._a[HOUR] === 24 &&
3745            config._a[MINUTE] === 0 &&
3746            config._a[SECOND] === 0 &&
3747            config._a[MILLISECOND] === 0) {
3748        config._nextDay = true;
3749        config._a[HOUR] = 0;
3750    }
3751
3752    config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
3753    expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay();
3754
3755    // Apply timezone offset from input. The actual utcOffset can be changed
3756    // with parseZone.
3757    if (config._tzm != null) {
3758        config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
3759    }
3760
3761    if (config._nextDay) {
3762        config._a[HOUR] = 24;
3763    }
3764
3765    // check for mismatching day of week
3766    if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {
3767        getParsingFlags(config).weekdayMismatch = true;
3768    }
3769}
3770
3771function dayOfYearFromWeekInfo(config) {
3772    var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
3773
3774    w = config._w;
3775    if (w.GG != null || w.W != null || w.E != null) {
3776        dow = 1;
3777        doy = 4;
3778
3779        // TODO: We need to take the current isoWeekYear, but that depends on
3780        // how we interpret now (local, utc, fixed offset). So create
3781        // a now version of current config (take local/utc/offset flags, and
3782        // create now).
3783        weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
3784        week = defaults(w.W, 1);
3785        weekday = defaults(w.E, 1);
3786        if (weekday < 1 || weekday > 7) {
3787            weekdayOverflow = true;
3788        }
3789    } else {
3790        dow = config._locale._week.dow;
3791        doy = config._locale._week.doy;
3792
3793        var curWeek = weekOfYear(createLocal(), dow, doy);
3794
3795        weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
3796
3797        // Default to current week.
3798        week = defaults(w.w, curWeek.week);
3799
3800        if (w.d != null) {
3801            // weekday -- low day numbers are considered next week
3802            weekday = w.d;
3803            if (weekday < 0 || weekday > 6) {
3804                weekdayOverflow = true;
3805            }
3806        } else if (w.e != null) {
3807            // local weekday -- counting starts from begining of week
3808            weekday = w.e + dow;
3809            if (w.e < 0 || w.e > 6) {
3810                weekdayOverflow = true;
3811            }
3812        } else {
3813            // default to begining of week
3814            weekday = dow;
3815        }
3816    }
3817    if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
3818        getParsingFlags(config)._overflowWeeks = true;
3819    } else if (weekdayOverflow != null) {
3820        getParsingFlags(config)._overflowWeekday = true;
3821    } else {
3822        temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
3823        config._a[YEAR] = temp.year;
3824        config._dayOfYear = temp.dayOfYear;
3825    }
3826}
3827
3828// iso 8601 regex
3829// 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)
3830var 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)?)?$/;
3831var 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)?)?$/;
3832
3833var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
3834
3835var isoDates = [
3836    ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
3837    ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
3838    ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
3839    ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
3840    ['YYYY-DDD', /\d{4}-\d{3}/],
3841    ['YYYY-MM', /\d{4}-\d\d/, false],
3842    ['YYYYYYMMDD', /[+-]\d{10}/],
3843    ['YYYYMMDD', /\d{8}/],
3844    // YYYYMM is NOT allowed by the standard
3845    ['GGGG[W]WWE', /\d{4}W\d{3}/],
3846    ['GGGG[W]WW', /\d{4}W\d{2}/, false],
3847    ['YYYYDDD', /\d{7}/]
3848];
3849
3850// iso time formats and regexes
3851var isoTimes = [
3852    ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
3853    ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
3854    ['HH:mm:ss', /\d\d:\d\d:\d\d/],
3855    ['HH:mm', /\d\d:\d\d/],
3856    ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
3857    ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
3858    ['HHmmss', /\d\d\d\d\d\d/],
3859    ['HHmm', /\d\d\d\d/],
3860    ['HH', /\d\d/]
3861];
3862
3863var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
3864
3865// date from iso format
3866function configFromISO(config) {
3867    var i, l,
3868        string = config._i,
3869        match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
3870        allowTime, dateFormat, timeFormat, tzFormat;
3871
3872    if (match) {
3873        getParsingFlags(config).iso = true;
3874
3875        for (i = 0, l = isoDates.length; i < l; i++) {
3876            if (isoDates[i][1].exec(match[1])) {
3877                dateFormat = isoDates[i][0];
3878                allowTime = isoDates[i][2] !== false;
3879                break;
3880            }
3881        }
3882        if (dateFormat == null) {
3883            config._isValid = false;
3884            return;
3885        }
3886        if (match[3]) {
3887            for (i = 0, l = isoTimes.length; i < l; i++) {
3888                if (isoTimes[i][1].exec(match[3])) {
3889                    // match[2] should be 'T' or space
3890                    timeFormat = (match[2] || ' ') + isoTimes[i][0];
3891                    break;
3892                }
3893            }
3894            if (timeFormat == null) {
3895                config._isValid = false;
3896                return;
3897            }
3898        }
3899        if (!allowTime && timeFormat != null) {
3900            config._isValid = false;
3901            return;
3902        }
3903        if (match[4]) {
3904            if (tzRegex.exec(match[4])) {
3905                tzFormat = 'Z';
3906            } else {
3907                config._isValid = false;
3908                return;
3909            }
3910        }
3911        config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
3912        configFromStringAndFormat(config);
3913    } else {
3914        config._isValid = false;
3915    }
3916}
3917
3918// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
3919var 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}))$/;
3920
3921function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {
3922    var result = [
3923        untruncateYear(yearStr),
3924        defaultLocaleMonthsShort.indexOf(monthStr),
3925        parseInt(dayStr, 10),
3926        parseInt(hourStr, 10),
3927        parseInt(minuteStr, 10)
3928    ];
3929
3930    if (secondStr) {
3931        result.push(parseInt(secondStr, 10));
3932    }
3933
3934    return result;
3935}
3936
3937function untruncateYear(yearStr) {
3938    var year = parseInt(yearStr, 10);
3939    if (year <= 49) {
3940        return 2000 + year;
3941    } else if (year <= 999) {
3942        return 1900 + year;
3943    }
3944    return year;
3945}
3946
3947function preprocessRFC2822(s) {
3948    // Remove comments and folding whitespace and replace multiple-spaces with a single space
3949    return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').trim();
3950}
3951
3952function checkWeekday(weekdayStr, parsedInput, config) {
3953    if (weekdayStr) {
3954        // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
3955        var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
3956            weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();
3957        if (weekdayProvided !== weekdayActual) {
3958            getParsingFlags(config).weekdayMismatch = true;
3959            config._isValid = false;
3960            return false;
3961        }
3962    }
3963    return true;
3964}
3965
3966var obsOffsets = {
3967    UT: 0,
3968    GMT: 0,
3969    EDT: -4 * 60,
3970    EST: -5 * 60,
3971    CDT: -5 * 60,
3972    CST: -6 * 60,
3973    MDT: -6 * 60,
3974    MST: -7 * 60,
3975    PDT: -7 * 60,
3976    PST: -8 * 60
3977};
3978
3979function calculateOffset(obsOffset, militaryOffset, numOffset) {
3980    if (obsOffset) {
3981        return obsOffsets[obsOffset];
3982    } else if (militaryOffset) {
3983        // the only allowed military tz is Z
3984        return 0;
3985    } else {
3986        var hm = parseInt(numOffset, 10);
3987        var m = hm % 100, h = (hm - m) / 100;
3988        return h * 60 + m;
3989    }
3990}
3991
3992// date and time from ref 2822 format
3993function configFromRFC2822(config) {
3994    var match = rfc2822.exec(preprocessRFC2822(config._i));
3995    if (match) {
3996        var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);
3997        if (!checkWeekday(match[1], parsedArray, config)) {
3998            return;
3999        }
4000
4001        config._a = parsedArray;
4002        config._tzm = calculateOffset(match[8], match[9], match[10]);
4003
4004        config._d = createUTCDate.apply(null, config._a);
4005        config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
4006
4007        getParsingFlags(config).rfc2822 = true;
4008    } else {
4009        config._isValid = false;
4010    }
4011}
4012
4013// date from iso format or fallback
4014function configFromString(config) {
4015    var matched = aspNetJsonRegex.exec(config._i);
4016
4017    if (matched !== null) {
4018        config._d = new Date(+matched[1]);
4019        return;
4020    }
4021
4022    configFromISO(config);
4023    if (config._isValid === false) {
4024        delete config._isValid;
4025    } else {
4026        return;
4027    }
4028
4029    configFromRFC2822(config);
4030    if (config._isValid === false) {
4031        delete config._isValid;
4032    } else {
4033        return;
4034    }
4035
4036    // Final attempt, use Input Fallback
4037    hooks.createFromInputFallback(config);
4038}
4039
4040hooks.createFromInputFallback = deprecate(
4041    'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
4042    'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
4043    'discouraged and will be removed in an upcoming major release. Please refer to ' +
4044    'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
4045    function (config) {
4046        config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
4047    }
4048);
4049
4050// constant that refers to the ISO standard
4051hooks.ISO_8601 = function () {};
4052
4053// constant that refers to the RFC 2822 form
4054hooks.RFC_2822 = function () {};
4055
4056// date from string and format string
4057function configFromStringAndFormat(config) {
4058    // TODO: Move this to another part of the creation flow to prevent circular deps
4059    if (config._f === hooks.ISO_8601) {
4060        configFromISO(config);
4061        return;
4062    }
4063    if (config._f === hooks.RFC_2822) {
4064        configFromRFC2822(config);
4065        return;
4066    }
4067    config._a = [];
4068    getParsingFlags(config).empty = true;
4069
4070    // This array is used to make a Date, either with `new Date` or `Date.UTC`
4071    var string = '' + config._i,
4072        i, parsedInput, tokens, token, skipped,
4073        stringLength = string.length,
4074        totalParsedInputLength = 0;
4075
4076    tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
4077
4078    for (i = 0; i < tokens.length; i++) {
4079        token = tokens[i];
4080        parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
4081        // console.log('token', token, 'parsedInput', parsedInput,
4082        //         'regex', getParseRegexForToken(token, config));
4083        if (parsedInput) {
4084            skipped = string.substr(0, string.indexOf(parsedInput));
4085            if (skipped.length > 0) {
4086                getParsingFlags(config).unusedInput.push(skipped);
4087            }
4088            string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
4089            totalParsedInputLength += parsedInput.length;
4090        }
4091        // don't parse if it's not a known token
4092        if (formatTokenFunctions[token]) {
4093            if (parsedInput) {
4094                getParsingFlags(config).empty = false;
4095            }
4096            else {
4097                getParsingFlags(config).unusedTokens.push(token);
4098            }
4099            addTimeToArrayFromToken(token, parsedInput, config);
4100        }
4101        else if (config._strict && !parsedInput) {
4102            getParsingFlags(config).unusedTokens.push(token);
4103        }
4104    }
4105
4106    // add remaining unparsed input length to the string
4107    getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
4108    if (string.length > 0) {
4109        getParsingFlags(config).unusedInput.push(string);
4110    }
4111
4112    // clear _12h flag if hour is <= 12
4113    if (config._a[HOUR] <= 12 &&
4114        getParsingFlags(config).bigHour === true &&
4115        config._a[HOUR] > 0) {
4116        getParsingFlags(config).bigHour = undefined;
4117    }
4118
4119    getParsingFlags(config).parsedDateParts = config._a.slice(0);
4120    getParsingFlags(config).meridiem = config._meridiem;
4121    // handle meridiem
4122    config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
4123
4124    configFromArray(config);
4125    checkOverflow(config);
4126}
4127
4128
4129function meridiemFixWrap (locale, hour, meridiem) {
4130    var isPm;
4131
4132    if (meridiem == null) {
4133        // nothing to do
4134        return hour;
4135    }
4136    if (locale.meridiemHour != null) {
4137        return locale.meridiemHour(hour, meridiem);
4138    } else if (locale.isPM != null) {
4139        // Fallback
4140        isPm = locale.isPM(meridiem);
4141        if (isPm && hour < 12) {
4142            hour += 12;
4143        }
4144        if (!isPm && hour === 12) {
4145            hour = 0;
4146        }
4147        return hour;
4148    } else {
4149        // this is not supposed to happen
4150        return hour;
4151    }
4152}
4153
4154// date from string and array of format strings
4155function configFromStringAndArray(config) {
4156    var tempConfig,
4157        bestMoment,
4158
4159        scoreToBeat,
4160        i,
4161        currentScore;
4162
4163    if (config._f.length === 0) {
4164        getParsingFlags(config).invalidFormat = true;
4165        config._d = new Date(NaN);
4166        return;
4167    }
4168
4169    for (i = 0; i < config._f.length; i++) {
4170        currentScore = 0;
4171        tempConfig = copyConfig({}, config);
4172        if (config._useUTC != null) {
4173            tempConfig._useUTC = config._useUTC;
4174        }
4175        tempConfig._f = config._f[i];
4176        configFromStringAndFormat(tempConfig);
4177
4178        if (!isValid(tempConfig)) {
4179            continue;
4180        }
4181
4182        // if there is any input that was not parsed add a penalty for that format
4183        currentScore += getParsingFlags(tempConfig).charsLeftOver;
4184
4185        //or tokens
4186        currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
4187
4188        getParsingFlags(tempConfig).score = currentScore;
4189
4190        if (scoreToBeat == null || currentScore < scoreToBeat) {
4191            scoreToBeat = currentScore;
4192            bestMoment = tempConfig;
4193        }
4194    }
4195
4196    extend(config, bestMoment || tempConfig);
4197}
4198
4199function configFromObject(config) {
4200    if (config._d) {
4201        return;
4202    }
4203
4204    var i = normalizeObjectUnits(config._i);
4205    config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
4206        return obj && parseInt(obj, 10);
4207    });
4208
4209    configFromArray(config);
4210}
4211
4212function createFromConfig (config) {
4213    var res = new Moment(checkOverflow(prepareConfig(config)));
4214    if (res._nextDay) {
4215        // Adding is smart enough around DST
4216        res.add(1, 'd');
4217        res._nextDay = undefined;
4218    }
4219
4220    return res;
4221}
4222
4223function prepareConfig (config) {
4224    var input = config._i,
4225        format = config._f;
4226
4227    config._locale = config._locale || getLocale(config._l);
4228
4229    if (input === null || (format === undefined && input === '')) {
4230        return createInvalid({nullInput: true});
4231    }
4232
4233    if (typeof input === 'string') {
4234        config._i = input = config._locale.preparse(input);
4235    }
4236
4237    if (isMoment(input)) {
4238        return new Moment(checkOverflow(input));
4239    } else if (isDate(input)) {
4240        config._d = input;
4241    } else if (isArray(format)) {
4242        configFromStringAndArray(config);
4243    } else if (format) {
4244        configFromStringAndFormat(config);
4245    }  else {
4246        configFromInput(config);
4247    }
4248
4249    if (!isValid(config)) {
4250        config._d = null;
4251    }
4252
4253    return config;
4254}
4255
4256function configFromInput(config) {
4257    var input = config._i;
4258    if (isUndefined(input)) {
4259        config._d = new Date(hooks.now());
4260    } else if (isDate(input)) {
4261        config._d = new Date(input.valueOf());
4262    } else if (typeof input === 'string') {
4263        configFromString(config);
4264    } else if (isArray(input)) {
4265        config._a = map(input.slice(0), function (obj) {
4266            return parseInt(obj, 10);
4267        });
4268        configFromArray(config);
4269    } else if (isObject(input)) {
4270        configFromObject(config);
4271    } else if (isNumber(input)) {
4272        // from milliseconds
4273        config._d = new Date(input);
4274    } else {
4275        hooks.createFromInputFallback(config);
4276    }
4277}
4278
4279function createLocalOrUTC (input, format, locale, strict, isUTC) {
4280    var c = {};
4281
4282    if (locale === true || locale === false) {
4283        strict = locale;
4284        locale = undefined;
4285    }
4286
4287    if ((isObject(input) && isObjectEmpty(input)) ||
4288            (isArray(input) && input.length === 0)) {
4289        input = undefined;
4290    }
4291    // object construction must be done this way.
4292    // https://github.com/moment/moment/issues/1423
4293    c._isAMomentObject = true;
4294    c._useUTC = c._isUTC = isUTC;
4295    c._l = locale;
4296    c._i = input;
4297    c._f = format;
4298    c._strict = strict;
4299
4300    return createFromConfig(c);
4301}
4302
4303function createLocal (input, format, locale, strict) {
4304    return createLocalOrUTC(input, format, locale, strict, false);
4305}
4306
4307var prototypeMin = deprecate(
4308    'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
4309    function () {
4310        var other = createLocal.apply(null, arguments);
4311        if (this.isValid() && other.isValid()) {
4312            return other < this ? this : other;
4313        } else {
4314            return createInvalid();
4315        }
4316    }
4317);
4318
4319var prototypeMax = deprecate(
4320    'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
4321    function () {
4322        var other = createLocal.apply(null, arguments);
4323        if (this.isValid() && other.isValid()) {
4324            return other > this ? this : other;
4325        } else {
4326            return createInvalid();
4327        }
4328    }
4329);
4330
4331// Pick a moment m from moments so that m[fn](other) is true for all
4332// other. This relies on the function fn to be transitive.
4333//
4334// moments should either be an array of moment objects or an array, whose
4335// first element is an array of moment objects.
4336function pickBy(fn, moments) {
4337    var res, i;
4338    if (moments.length === 1 && isArray(moments[0])) {
4339        moments = moments[0];
4340    }
4341    if (!moments.length) {
4342        return createLocal();
4343    }
4344    res = moments[0];
4345    for (i = 1; i < moments.length; ++i) {
4346        if (!moments[i].isValid() || moments[i][fn](res)) {
4347            res = moments[i];
4348        }
4349    }
4350    return res;
4351}
4352
4353// TODO: Use [].sort instead?
4354function min () {
4355    var args = [].slice.call(arguments, 0);
4356
4357    return pickBy('isBefore', args);
4358}
4359
4360function max () {
4361    var args = [].slice.call(arguments, 0);
4362
4363    return pickBy('isAfter', args);
4364}
4365
4366var now = function () {
4367    return Date.now ? Date.now() : +(new Date());
4368};
4369
4370var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
4371
4372function isDurationValid(m) {
4373    for (var key in m) {
4374        if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
4375            return false;
4376        }
4377    }
4378
4379    var unitHasDecimal = false;
4380    for (var i = 0; i < ordering.length; ++i) {
4381        if (m[ordering[i]]) {
4382            if (unitHasDecimal) {
4383                return false; // only allow non-integers for smallest unit
4384            }
4385            if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
4386                unitHasDecimal = true;
4387            }
4388        }
4389    }
4390
4391    return true;
4392}
4393
4394function isValid$1() {
4395    return this._isValid;
4396}
4397
4398function createInvalid$1() {
4399    return createDuration(NaN);
4400}
4401
4402function Duration (duration) {
4403    var normalizedInput = normalizeObjectUnits(duration),
4404        years = normalizedInput.year || 0,
4405        quarters = normalizedInput.quarter || 0,
4406        months = normalizedInput.month || 0,
4407        weeks = normalizedInput.week || 0,
4408        days = normalizedInput.day || 0,
4409        hours = normalizedInput.hour || 0,
4410        minutes = normalizedInput.minute || 0,
4411        seconds = normalizedInput.second || 0,
4412        milliseconds = normalizedInput.millisecond || 0;
4413
4414    this._isValid = isDurationValid(normalizedInput);
4415
4416    // representation for dateAddRemove
4417    this._milliseconds = +milliseconds +
4418        seconds * 1e3 + // 1000
4419        minutes * 6e4 + // 1000 * 60
4420        hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
4421    // Because of dateAddRemove treats 24 hours as different from a
4422    // day when working around DST, we need to store them separately
4423    this._days = +days +
4424        weeks * 7;
4425    // It is impossible to translate months into days without knowing
4426    // which months you are are talking about, so we have to store
4427    // it separately.
4428    this._months = +months +
4429        quarters * 3 +
4430        years * 12;
4431
4432    this._data = {};
4433
4434    this._locale = getLocale();
4435
4436    this._bubble();
4437}
4438
4439function isDuration (obj) {
4440    return obj instanceof Duration;
4441}
4442
4443function absRound (number) {
4444    if (number < 0) {
4445        return Math.round(-1 * number) * -1;
4446    } else {
4447        return Math.round(number);
4448    }
4449}
4450
4451// FORMATTING
4452
4453function offset (token, separator) {
4454    addFormatToken(token, 0, 0, function () {
4455        var offset = this.utcOffset();
4456        var sign = '+';
4457        if (offset < 0) {
4458            offset = -offset;
4459            sign = '-';
4460        }
4461        return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
4462    });
4463}
4464
4465offset('Z', ':');
4466offset('ZZ', '');
4467
4468// PARSING
4469
4470addRegexToken('Z',  matchShortOffset);
4471addRegexToken('ZZ', matchShortOffset);
4472addParseToken(['Z', 'ZZ'], function (input, array, config) {
4473    config._useUTC = true;
4474    config._tzm = offsetFromString(matchShortOffset, input);
4475});
4476
4477// HELPERS
4478
4479// timezone chunker
4480// '+10:00' > ['10',  '00']
4481// '-1530'  > ['-15', '30']
4482var chunkOffset = /([\+\-]|\d\d)/gi;
4483
4484function offsetFromString(matcher, string) {
4485    var matches = (string || '').match(matcher);
4486
4487    if (matches === null) {
4488        return null;
4489    }
4490
4491    var chunk   = matches[matches.length - 1] || [];
4492    var parts   = (chunk + '').match(chunkOffset) || ['-', 0, 0];
4493    var minutes = +(parts[1] * 60) + toInt(parts[2]);
4494
4495    return minutes === 0 ?
4496      0 :
4497      parts[0] === '+' ? minutes : -minutes;
4498}
4499
4500// Return a moment from input, that is local/utc/zone equivalent to model.
4501function cloneWithOffset(input, model) {
4502    var res, diff;
4503    if (model._isUTC) {
4504        res = model.clone();
4505        diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
4506        // Use low-level api, because this fn is low-level api.
4507        res._d.setTime(res._d.valueOf() + diff);
4508        hooks.updateOffset(res, false);
4509        return res;
4510    } else {
4511        return createLocal(input).local();
4512    }
4513}
4514
4515function getDateOffset (m) {
4516    // On Firefox.24 Date#getTimezoneOffset returns a floating point.
4517    // https://github.com/moment/moment/pull/1871
4518    return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
4519}
4520
4521// HOOKS
4522
4523// This function will be called whenever a moment is mutated.
4524// It is intended to keep the offset in sync with the timezone.
4525hooks.updateOffset = function () {};
4526
4527// MOMENTS
4528
4529// keepLocalTime = true means only change the timezone, without
4530// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
4531// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
4532// +0200, so we adjust the time as needed, to be valid.
4533//
4534// Keeping the time actually adds/subtracts (one hour)
4535// from the actual represented time. That is why we call updateOffset
4536// a second time. In case it wants us to change the offset again
4537// _changeInProgress == true case, then we have to adjust, because
4538// there is no such time in the given timezone.
4539function getSetOffset (input, keepLocalTime, keepMinutes) {
4540    var offset = this._offset || 0,
4541        localAdjust;
4542    if (!this.isValid()) {
4543        return input != null ? this : NaN;
4544    }
4545    if (input != null) {
4546        if (typeof input === 'string') {
4547            input = offsetFromString(matchShortOffset, input);
4548            if (input === null) {
4549                return this;
4550            }
4551        } else if (Math.abs(input) < 16 && !keepMinutes) {
4552            input = input * 60;
4553        }
4554        if (!this._isUTC && keepLocalTime) {
4555            localAdjust = getDateOffset(this);
4556        }
4557        this._offset = input;
4558        this._isUTC = true;
4559        if (localAdjust != null) {
4560            this.add(localAdjust, 'm');
4561        }
4562        if (offset !== input) {
4563            if (!keepLocalTime || this._changeInProgress) {
4564                addSubtract(this, createDuration(input - offset, 'm'), 1, false);
4565            } else if (!this._changeInProgress) {
4566                this._changeInProgress = true;
4567                hooks.updateOffset(this, true);
4568                this._changeInProgress = null;
4569            }
4570        }
4571        return this;
4572    } else {
4573        return this._isUTC ? offset : getDateOffset(this);
4574    }
4575}
4576
4577function getSetZone (input, keepLocalTime) {
4578    if (input != null) {
4579        if (typeof input !== 'string') {
4580            input = -input;
4581        }
4582
4583        this.utcOffset(input, keepLocalTime);
4584
4585        return this;
4586    } else {
4587        return -this.utcOffset();
4588    }
4589}
4590
4591function setOffsetToUTC (keepLocalTime) {
4592    return this.utcOffset(0, keepLocalTime);
4593}
4594
4595function setOffsetToLocal (keepLocalTime) {
4596    if (this._isUTC) {
4597        this.utcOffset(0, keepLocalTime);
4598        this._isUTC = false;
4599
4600        if (keepLocalTime) {
4601            this.subtract(getDateOffset(this), 'm');
4602        }
4603    }
4604    return this;
4605}
4606
vendor: 17,969 bytes, lines 4607-5186
4607function setOffsetToParsedOffset () {
4608    if (this._tzm != null) {
4609        this.utcOffset(this._tzm, false, true);
4610    } else if (typeof this._i === 'string') {
4611        var tZone = offsetFromString(matchOffset, this._i);
4612        if (tZone != null) {
4613            this.utcOffset(tZone);
4614        }
4615        else {
4616            this.utcOffset(0, true);
4617        }
4618    }
4619    return this;
4620}
4621
4622function hasAlignedHourOffset (input) {
4623    if (!this.isValid()) {
4624        return false;
4625    }
4626    input = input ? createLocal(input).utcOffset() : 0;
4627
4628    return (this.utcOffset() - input) % 60 === 0;
4629}
4630
4631function isDaylightSavingTime () {
4632    return (
4633        this.utcOffset() > this.clone().month(0).utcOffset() ||
4634        this.utcOffset() > this.clone().month(5).utcOffset()
4635    );
4636}
4637
4638function isDaylightSavingTimeShifted () {
4639    if (!isUndefined(this._isDSTShifted)) {
4640        return this._isDSTShifted;
4641    }
4642
4643    var c = {};
4644
4645    copyConfig(c, this);
4646    c = prepareConfig(c);
4647
4648    if (c._a) {
4649        var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
4650        this._isDSTShifted = this.isValid() &&
4651            compareArrays(c._a, other.toArray()) > 0;
4652    } else {
4653        this._isDSTShifted = false;
4654    }
4655
4656    return this._isDSTShifted;
4657}
4658
4659function isLocal () {
4660    return this.isValid() ? !this._isUTC : false;
4661}
4662
4663function isUtcOffset () {
4664    return this.isValid() ? this._isUTC : false;
4665}
4666
4667function isUtc () {
4668    return this.isValid() ? this._isUTC && this._offset === 0 : false;
4669}
4670
4671// ASP.NET json date format regex
4672var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
4673
4674// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
4675// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
4676// and further modified to allow for strings containing both week and day
4677var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
4678
4679function createDuration (input, key) {
4680    var duration = input,
4681        // matching against regexp is expensive, do it on demand
4682        match = null,
4683        sign,
4684        ret,
4685        diffRes;
4686
4687    if (isDuration(input)) {
4688        duration = {
4689            ms : input._milliseconds,
4690            d  : input._days,
4691            M  : input._months
4692        };
4693    } else if (isNumber(input)) {
4694        duration = {};
4695        if (key) {
4696            duration[key] = input;
4697        } else {
4698            duration.milliseconds = input;
4699        }
4700    } else if (!!(match = aspNetRegex.exec(input))) {
4701        sign = (match[1] === '-') ? -1 : 1;
4702        duration = {
4703            y  : 0,
4704            d  : toInt(match[DATE])                         * sign,
4705            h  : toInt(match[HOUR])                         * sign,
4706            m  : toInt(match[MINUTE])                       * sign,
4707            s  : toInt(match[SECOND])                       * sign,
4708            ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
4709        };
4710    } else if (!!(match = isoRegex.exec(input))) {
4711        sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1;
4712        duration = {
4713            y : parseIso(match[2], sign),
4714            M : parseIso(match[3], sign),
4715            w : parseIso(match[4], sign),
4716            d : parseIso(match[5], sign),
4717            h : parseIso(match[6], sign),
4718            m : parseIso(match[7], sign),
4719            s : parseIso(match[8], sign)
4720        };
4721    } else if (duration == null) {// checks for null or undefined
4722        duration = {};
4723    } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
4724        diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
4725
4726        duration = {};
4727        duration.ms = diffRes.milliseconds;
4728        duration.M = diffRes.months;
4729    }
4730
4731    ret = new Duration(duration);
4732
4733    if (isDuration(input) && hasOwnProp(input, '_locale')) {
4734        ret._locale = input._locale;
4735    }
4736
4737    return ret;
4738}
4739
4740createDuration.fn = Duration.prototype;
4741createDuration.invalid = createInvalid$1;
4742
4743function parseIso (inp, sign) {
4744    // We'd normally use ~~inp for this, but unfortunately it also
4745    // converts floats to ints.
4746    // inp may be undefined, so careful calling replace on it.
4747    var res = inp && parseFloat(inp.replace(',', '.'));
4748    // apply sign while we're at it
4749    return (isNaN(res) ? 0 : res) * sign;
4750}
4751
4752function positiveMomentsDifference(base, other) {
4753    var res = {milliseconds: 0, months: 0};
4754
4755    res.months = other.month() - base.month() +
4756        (other.year() - base.year()) * 12;
4757    if (base.clone().add(res.months, 'M').isAfter(other)) {
4758        --res.months;
4759    }
4760
4761    res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
4762
4763    return res;
4764}
4765
4766function momentsDifference(base, other) {
4767    var res;
4768    if (!(base.isValid() && other.isValid())) {
4769        return {milliseconds: 0, months: 0};
4770    }
4771
4772    other = cloneWithOffset(other, base);
4773    if (base.isBefore(other)) {
4774        res = positiveMomentsDifference(base, other);
4775    } else {
4776        res = positiveMomentsDifference(other, base);
4777        res.milliseconds = -res.milliseconds;
4778        res.months = -res.months;
4779    }
4780
4781    return res;
4782}
4783
4784// TODO: remove 'name' arg after deprecation is removed
4785function createAdder(direction, name) {
4786    return function (val, period) {
4787        var dur, tmp;
4788        //invert the arguments, but complain about it
4789        if (period !== null && !isNaN(+period)) {
4790            deprecateSimple(name, 'moment().' + name  + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
4791            'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
4792            tmp = val; val = period; period = tmp;
4793        }
4794
4795        val = typeof val === 'string' ? +val : val;
4796        dur = createDuration(val, period);
4797        addSubtract(this, dur, direction);
4798        return this;
4799    };
4800}
4801
4802function addSubtract (mom, duration, isAdding, updateOffset) {
4803    var milliseconds = duration._milliseconds,
4804        days = absRound(duration._days),
4805        months = absRound(duration._months);
4806
4807    if (!mom.isValid()) {
4808        // No op
4809        return;
4810    }
4811
4812    updateOffset = updateOffset == null ? true : updateOffset;
4813
4814    if (months) {
4815        setMonth(mom, get(mom, 'Month') + months * isAdding);
4816    }
4817    if (days) {
4818        set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
4819    }
4820    if (milliseconds) {
4821        mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
4822    }
4823    if (updateOffset) {
4824        hooks.updateOffset(mom, days || months);
4825    }
4826}
4827
4828var add      = createAdder(1, 'add');
4829var subtract = createAdder(-1, 'subtract');
4830
4831function getCalendarFormat(myMoment, now) {
4832    var diff = myMoment.diff(now, 'days', true);
4833    return diff < -6 ? 'sameElse' :
4834            diff < -1 ? 'lastWeek' :
4835            diff < 0 ? 'lastDay' :
4836            diff < 1 ? 'sameDay' :
4837            diff < 2 ? 'nextDay' :
4838            diff < 7 ? 'nextWeek' : 'sameElse';
4839}
4840
4841function calendar$1 (time, formats) {
4842    // We want to compare the start of today, vs this.
4843    // Getting start-of-today depends on whether we're local/utc/offset or not.
4844    var now = time || createLocal(),
4845        sod = cloneWithOffset(now, this).startOf('day'),
4846        format = hooks.calendarFormat(this, sod) || 'sameElse';
4847
4848    var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
4849
4850    return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
4851}
4852
4853function clone () {
4854    return new Moment(this);
4855}
4856
4857function isAfter (input, units) {
4858    var localInput = isMoment(input) ? input : createLocal(input);
4859    if (!(this.isValid() && localInput.isValid())) {
4860        return false;
4861    }
4862    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
4863    if (units === 'millisecond') {
4864        return this.valueOf() > localInput.valueOf();
4865    } else {
4866        return localInput.valueOf() < this.clone().startOf(units).valueOf();
4867    }
4868}
4869
4870function isBefore (input, units) {
4871    var localInput = isMoment(input) ? input : createLocal(input);
4872    if (!(this.isValid() && localInput.isValid())) {
4873        return false;
4874    }
4875    units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
4876    if (units === 'millisecond') {
4877        return this.valueOf() < localInput.valueOf();
4878    } else {
4879        return this.clone().endOf(units).valueOf() < localInput.valueOf();
4880    }
4881}
4882
4883function isBetween (from, to, units, inclusivity) {
4884    inclusivity = inclusivity || '()';
4885    return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
4886        (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
4887}
4888
4889function isSame (input, units) {
4890    var localInput = isMoment(input) ? input : createLocal(input),
4891        inputMs;
4892    if (!(this.isValid() && localInput.isValid())) {
4893        return false;
4894    }
4895    units = normalizeUnits(units || 'millisecond');
4896    if (units === 'millisecond') {
4897        return this.valueOf() === localInput.valueOf();
4898    } else {
4899        inputMs = localInput.valueOf();
4900        return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
4901    }
4902}
4903
4904function isSameOrAfter (input, units) {
4905    return this.isSame(input, units) || this.isAfter(input,units);
4906}
4907
4908function isSameOrBefore (input, units) {
4909    return this.isSame(input, units) || this.isBefore(input,units);
4910}
4911
4912function diff (input, units, asFloat) {
4913    var that,
4914        zoneDelta,
4915        delta, output;
4916
4917    if (!this.isValid()) {
4918        return NaN;
4919    }
4920
4921    that = cloneWithOffset(input, this);
4922
4923    if (!that.isValid()) {
4924        return NaN;
4925    }
4926
4927    zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
4928
4929    units = normalizeUnits(units);
4930
4931    switch (units) {
4932        case 'year': output = monthDiff(this, that) / 12; break;
4933        case 'month': output = monthDiff(this, that); break;
4934        case 'quarter': output = monthDiff(this, that) / 3; break;
4935        case 'second': output = (this - that) / 1e3; break; // 1000
4936        case 'minute': output = (this - that) / 6e4; break; // 1000 * 60
4937        case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 60
4938        case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst
4939        case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst
4940        default: output = this - that;
4941    }
4942
4943    return asFloat ? output : absFloor(output);
4944}
4945
4946function monthDiff (a, b) {
4947    // difference in months
4948    var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
4949        // b is in (anchor - 1 month, anchor + 1 month)
4950        anchor = a.clone().add(wholeMonthDiff, 'months'),
4951        anchor2, adjust;
4952
4953    if (b - anchor < 0) {
4954        anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
4955        // linear across the month
4956        adjust = (b - anchor) / (anchor - anchor2);
4957    } else {
4958        anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
4959        // linear across the month
4960        adjust = (b - anchor) / (anchor2 - anchor);
4961    }
4962
4963    //check for negative zero, return zero if negative zero
4964    return -(wholeMonthDiff + adjust) || 0;
4965}
4966
4967hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
4968hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
4969
4970function toString () {
4971    return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
4972}
4973
4974function toISOString(keepOffset) {
4975    if (!this.isValid()) {
4976        return null;
4977    }
4978    var utc = keepOffset !== true;
4979    var m = utc ? this.clone().utc() : this;
4980    if (m.year() < 0 || m.year() > 9999) {
4981        return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');
4982    }
4983    if (isFunction(Date.prototype.toISOString)) {
4984        // native implementation is ~50x faster, use it when we can
4985        if (utc) {
4986            return this.toDate().toISOString();
4987        } else {
4988            return new Date(this._d.valueOf()).toISOString().replace('Z', formatMoment(m, 'Z'));
4989        }
4990    }
4991    return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');
4992}
4993
4994/**
4995 * Return a human readable representation of a moment that can
4996 * also be evaluated to get a new moment which is the same
4997 *
4998 * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
4999 */
5000function inspect () {
5001    if (!this.isValid()) {
5002        return 'moment.invalid(/* ' + this._i + ' */)';
5003    }
5004    var func = 'moment';
5005    var zone = '';
5006    if (!this.isLocal()) {
5007        func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
5008        zone = 'Z';
5009    }
5010    var prefix = '[' + func + '("]';
5011    var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
5012    var datetime = '-MM-DD[T]HH:mm:ss.SSS';
5013    var suffix = zone + '[")]';
5014
5015    return this.format(prefix + year + datetime + suffix);
5016}
5017
5018function format (inputString) {
5019    if (!inputString) {
5020        inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
5021    }
5022    var output = formatMoment(this, inputString);
5023    return this.localeData().postformat(output);
5024}
5025
5026function from (time, withoutSuffix) {
5027    if (this.isValid() &&
5028            ((isMoment(time) && time.isValid()) ||
5029             createLocal(time).isValid())) {
5030        return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
5031    } else {
5032        return this.localeData().invalidDate();
5033    }
5034}
5035
5036function fromNow (withoutSuffix) {
5037    return this.from(createLocal(), withoutSuffix);
5038}
5039
5040function to (time, withoutSuffix) {
5041    if (this.isValid() &&
5042            ((isMoment(time) && time.isValid()) ||
5043             createLocal(time).isValid())) {
5044        return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
5045    } else {
5046        return this.localeData().invalidDate();
5047    }
5048}
5049
5050function toNow (withoutSuffix) {
5051    return this.to(createLocal(), withoutSuffix);
5052}
5053
5054// If passed a locale key, it will set the locale for this
5055// instance.  Otherwise, it will return the locale configuration
5056// variables for this instance.
5057function locale (key) {
5058    var newLocaleData;
5059
5060    if (key === undefined) {
5061        return this._locale._abbr;
5062    } else {
5063        newLocaleData = getLocale(key);
5064        if (newLocaleData != null) {
5065            this._locale = newLocaleData;
5066        }
5067        return this;
5068    }
5069}
5070
5071var lang = deprecate(
5072    'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
5073    function (key) {
5074        if (key === undefined) {
5075            return this.localeData();
5076        } else {
5077            return this.locale(key);
5078        }
5079    }
5080);
5081
5082function localeData () {
5083    return this._locale;
5084}
5085
5086function startOf (units) {
5087    units = normalizeUnits(units);
5088    // the following switch intentionally omits break keywords
5089    // to utilize falling through the cases.
5090    switch (units) {
5091        case 'year':
5092            this.month(0);
5093            /* falls through */
5094        case 'quarter':
5095        case 'month':
5096            this.date(1);
5097            /* falls through */
5098        case 'week':
5099        case 'isoWeek':
5100        case 'day':
5101        case 'date':
5102            this.hours(0);
5103            /* falls through */
5104        case 'hour':
5105            this.minutes(0);
5106            /* falls through */
5107        case 'minute':
5108            this.seconds(0);
5109            /* falls through */
5110        case 'second':
5111            this.milliseconds(0);
5112    }
5113
5114    // weeks are a special case
5115    if (units === 'week') {
5116        this.weekday(0);
5117    }
5118    if (units === 'isoWeek') {
5119        this.isoWeekday(1);
5120    }
5121
5122    // quarters are also special
5123    if (units === 'quarter') {
5124        this.month(Math.floor(this.month() / 3) * 3);
5125    }
5126
5127    return this;
5128}
5129
5130function endOf (units) {
5131    units = normalizeUnits(units);
5132    if (units === undefined || units === 'millisecond') {
5133        return this;
5134    }
5135
5136    // 'date' is an alias for 'day', so it should be considered as such.
5137    if (units === 'date') {
5138        units = 'day';
5139    }
5140
5141    return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
5142}
5143
5144function valueOf () {
5145    return this._d.valueOf() - ((this._offset || 0) * 60000);
5146}
5147
5148function unix () {
5149    return Math.floor(this.valueOf() / 1000);
5150}
5151
5152function toDate () {
5153    return new Date(this.valueOf());
5154}
5155
5156function toArray () {
5157    var m = this;
5158    return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
5159}
5160
5161function toObject () {
5162    var m = this;
5163    return {
5164        years: m.year(),
5165        months: m.month(),
5166        date: m.date(),
5167        hours: m.hours(),
5168        minutes: m.minutes(),
5169        seconds: m.seconds(),
5170        milliseconds: m.milliseconds()
5171    };
5172}
5173
5174function toJSON () {
5175    // new Date(NaN).toJSON() === null
5176    return this.isValid() ? this.toISOString() : null;
5177}
5178
5179function isValid$2 () {
5180    return isValid(this);
5181}
5182
5183function parsingFlags () {
5184    return extend({}, getParsingFlags(this));
5185}
5186
vendor: 12,433 bytes, lines 5187-5658
5187function invalidAt () {
5188    return getParsingFlags(this).overflow;
5189}
5190
5191function creationData() {
5192    return {
5193        input: this._i,
5194        format: this._f,
5195        locale: this._locale,
5196        isUTC: this._isUTC,
5197        strict: this._strict
5198    };
5199}
5200
5201// FORMATTING
5202
5203addFormatToken(0, ['gg', 2], 0, function () {
5204    return this.weekYear() % 100;
5205});
5206
5207addFormatToken(0, ['GG', 2], 0, function () {
5208    return this.isoWeekYear() % 100;
5209});
5210
5211function addWeekYearFormatToken (token, getter) {
5212    addFormatToken(0, [token, token.length], 0, getter);
5213}
5214
5215addWeekYearFormatToken('gggg',     'weekYear');
5216addWeekYearFormatToken('ggggg',    'weekYear');
5217addWeekYearFormatToken('GGGG',  'isoWeekYear');
5218addWeekYearFormatToken('GGGGG', 'isoWeekYear');
5219
5220// ALIASES
5221
5222addUnitAlias('weekYear', 'gg');
5223addUnitAlias('isoWeekYear', 'GG');
5224
5225// PRIORITY
5226
5227addUnitPriority('weekYear', 1);
5228addUnitPriority('isoWeekYear', 1);
5229
5230
5231// PARSING
5232
5233addRegexToken('G',      matchSigned);
5234addRegexToken('g',      matchSigned);
5235addRegexToken('GG',     match1to2, match2);
5236addRegexToken('gg',     match1to2, match2);
5237addRegexToken('GGGG',   match1to4, match4);
5238addRegexToken('gggg',   match1to4, match4);
5239addRegexToken('GGGGG',  match1to6, match6);
5240addRegexToken('ggggg',  match1to6, match6);
5241
5242addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
5243    week[token.substr(0, 2)] = toInt(input);
5244});
5245
5246addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
5247    week[token] = hooks.parseTwoDigitYear(input);
5248});
5249
5250// MOMENTS
5251
5252function getSetWeekYear (input) {
5253    return getSetWeekYearHelper.call(this,
5254            input,
5255            this.week(),
5256            this.weekday(),
5257            this.localeData()._week.dow,
5258            this.localeData()._week.doy);
5259}
5260
5261function getSetISOWeekYear (input) {
5262    return getSetWeekYearHelper.call(this,
5263            input, this.isoWeek(), this.isoWeekday(), 1, 4);
5264}
5265
5266function getISOWeeksInYear () {
5267    return weeksInYear(this.year(), 1, 4);
5268}
5269
5270function getWeeksInYear () {
5271    var weekInfo = this.localeData()._week;
5272    return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
5273}
5274
5275function getSetWeekYearHelper(input, week, weekday, dow, doy) {
5276    var weeksTarget;
5277    if (input == null) {
5278        return weekOfYear(this, dow, doy).year;
5279    } else {
5280        weeksTarget = weeksInYear(input, dow, doy);
5281        if (week > weeksTarget) {
5282            week = weeksTarget;
5283        }
5284        return setWeekAll.call(this, input, week, weekday, dow, doy);
5285    }
5286}
5287
5288function setWeekAll(weekYear, week, weekday, dow, doy) {
5289    var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
5290        date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
5291
5292    this.year(date.getUTCFullYear());
5293    this.month(date.getUTCMonth());
5294    this.date(date.getUTCDate());
5295    return this;
5296}
5297
5298// FORMATTING
5299
5300addFormatToken('Q', 0, 'Qo', 'quarter');
5301
5302// ALIASES
5303
5304addUnitAlias('quarter', 'Q');
5305
5306// PRIORITY
5307
5308addUnitPriority('quarter', 7);
5309
5310// PARSING
5311
5312addRegexToken('Q', match1);
5313addParseToken('Q', function (input, array) {
5314    array[MONTH] = (toInt(input) - 1) * 3;
5315});
5316
5317// MOMENTS
5318
5319function getSetQuarter (input) {
5320    return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
5321}
5322
5323// FORMATTING
5324
5325addFormatToken('D', ['DD', 2], 'Do', 'date');
5326
5327// ALIASES
5328
5329addUnitAlias('date', 'D');
5330
5331// PRIOROITY
5332addUnitPriority('date', 9);
5333
5334// PARSING
5335
5336addRegexToken('D',  match1to2);
5337addRegexToken('DD', match1to2, match2);
5338addRegexToken('Do', function (isStrict, locale) {
5339    // TODO: Remove "ordinalParse" fallback in next major release.
5340    return isStrict ?
5341      (locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
5342      locale._dayOfMonthOrdinalParseLenient;
5343});
5344
5345addParseToken(['D', 'DD'], DATE);
5346addParseToken('Do', function (input, array) {
5347    array[DATE] = toInt(input.match(match1to2)[0]);
5348});
5349
5350// MOMENTS
5351
5352var getSetDayOfMonth = makeGetSet('Date', true);
5353
5354// FORMATTING
5355
5356addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
5357
5358// ALIASES
5359
5360addUnitAlias('dayOfYear', 'DDD');
5361
5362// PRIORITY
5363addUnitPriority('dayOfYear', 4);
5364
5365// PARSING
5366
5367addRegexToken('DDD',  match1to3);
5368addRegexToken('DDDD', match3);
5369addParseToken(['DDD', 'DDDD'], function (input, array, config) {
5370    config._dayOfYear = toInt(input);
5371});
5372
5373// HELPERS
5374
5375// MOMENTS
5376
5377function getSetDayOfYear (input) {
5378    var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
5379    return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
5380}
5381
5382// FORMATTING
5383
5384addFormatToken('m', ['mm', 2], 0, 'minute');
5385
5386// ALIASES
5387
5388addUnitAlias('minute', 'm');
5389
5390// PRIORITY
5391
5392addUnitPriority('minute', 14);
5393
5394// PARSING
5395
5396addRegexToken('m',  match1to2);
5397addRegexToken('mm', match1to2, match2);
5398addParseToken(['m', 'mm'], MINUTE);
5399
5400// MOMENTS
5401
5402var getSetMinute = makeGetSet('Minutes', false);
5403
5404// FORMATTING
5405
5406addFormatToken('s', ['ss', 2], 0, 'second');
5407
5408// ALIASES
5409
5410addUnitAlias('second', 's');
5411
5412// PRIORITY
5413
5414addUnitPriority('second', 15);
5415
5416// PARSING
5417
5418addRegexToken('s',  match1to2);
5419addRegexToken('ss', match1to2, match2);
5420addParseToken(['s', 'ss'], SECOND);
5421
5422// MOMENTS
5423
5424var getSetSecond = makeGetSet('Seconds', false);
5425
5426// FORMATTING
5427
5428addFormatToken('S', 0, 0, function () {
5429    return ~~(this.millisecond() / 100);
5430});
5431
5432addFormatToken(0, ['SS', 2], 0, function () {
5433    return ~~(this.millisecond() / 10);
5434});
5435
5436addFormatToken(0, ['SSS', 3], 0, 'millisecond');
5437addFormatToken(0, ['SSSS', 4], 0, function () {
5438    return this.millisecond() * 10;
5439});
5440addFormatToken(0, ['SSSSS', 5], 0, function () {
5441    return this.millisecond() * 100;
5442});
5443addFormatToken(0, ['SSSSSS', 6], 0, function () {
5444    return this.millisecond() * 1000;
5445});
5446addFormatToken(0, ['SSSSSSS', 7], 0, function () {
5447    return this.millisecond() * 10000;
5448});
5449addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
5450    return this.millisecond() * 100000;
5451});
5452addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
5453    return this.millisecond() * 1000000;
5454});
5455
5456
5457// ALIASES
5458
5459addUnitAlias('millisecond', 'ms');
5460
5461// PRIORITY
5462
5463addUnitPriority('millisecond', 16);
5464
5465// PARSING
5466
5467addRegexToken('S',    match1to3, match1);
5468addRegexToken('SS',   match1to3, match2);
5469addRegexToken('SSS',  match1to3, match3);
5470
5471var token;
5472for (token = 'SSSS'; token.length <= 9; token += 'S') {
5473    addRegexToken(token, matchUnsigned);
5474}
5475
5476function parseMs(input, array) {
5477    array[MILLISECOND] = toInt(('0.' + input) * 1000);
5478}
5479
5480for (token = 'S'; token.length <= 9; token += 'S') {
5481    addParseToken(token, parseMs);
5482}
5483// MOMENTS
5484
5485var getSetMillisecond = makeGetSet('Milliseconds', false);
5486
5487// FORMATTING
5488
5489addFormatToken('z',  0, 0, 'zoneAbbr');
5490addFormatToken('zz', 0, 0, 'zoneName');
5491
5492// MOMENTS
5493
5494function getZoneAbbr () {
5495    return this._isUTC ? 'UTC' : '';
5496}
5497
5498function getZoneName () {
5499    return this._isUTC ? 'Coordinated Universal Time' : '';
5500}
5501
5502var proto = Moment.prototype;
5503
5504proto.add               = add;
5505proto.calendar          = calendar$1;
5506proto.clone             = clone;
5507proto.diff              = diff;
5508proto.endOf             = endOf;
5509proto.format            = format;
5510proto.from              = from;
5511proto.fromNow           = fromNow;
5512proto.to                = to;
5513proto.toNow             = toNow;
5514proto.get               = stringGet;
5515proto.invalidAt         = invalidAt;
5516proto.isAfter           = isAfter;
5517proto.isBefore          = isBefore;
5518proto.isBetween         = isBetween;
5519proto.isSame            = isSame;
5520proto.isSameOrAfter     = isSameOrAfter;
5521proto.isSameOrBefore    = isSameOrBefore;
5522proto.isValid           = isValid$2;
5523proto.lang              = lang;
5524proto.locale            = locale;
5525proto.localeData        = localeData;
5526proto.max               = prototypeMax;
5527proto.min               = prototypeMin;
5528proto.parsingFlags      = parsingFlags;
5529proto.set               = stringSet;
5530proto.startOf           = startOf;
5531proto.subtract          = subtract;
5532proto.toArray           = toArray;
5533proto.toObject          = toObject;
5534proto.toDate            = toDate;
5535proto.toISOString       = toISOString;
5536proto.inspect           = inspect;
5537proto.toJSON            = toJSON;
5538proto.toString          = toString;
5539proto.unix              = unix;
5540proto.valueOf           = valueOf;
5541proto.creationData      = creationData;
5542
5543// Year
5544proto.year       = getSetYear;
5545proto.isLeapYear = getIsLeapYear;
5546
5547// Week Year
5548proto.weekYear    = getSetWeekYear;
5549proto.isoWeekYear = getSetISOWeekYear;
5550
5551// Quarter
5552proto.quarter = proto.quarters = getSetQuarter;
5553
5554// Month
5555proto.month       = getSetMonth;
5556proto.daysInMonth = getDaysInMonth;
5557
5558// Week
5559proto.week           = proto.weeks        = getSetWeek;
5560proto.isoWeek        = proto.isoWeeks     = getSetISOWeek;
5561proto.weeksInYear    = getWeeksInYear;
5562proto.isoWeeksInYear = getISOWeeksInYear;
5563
5564// Day
5565proto.date       = getSetDayOfMonth;
5566proto.day        = proto.days             = getSetDayOfWeek;
5567proto.weekday    = getSetLocaleDayOfWeek;
5568proto.isoWeekday = getSetISODayOfWeek;
5569proto.dayOfYear  = getSetDayOfYear;
5570
5571// Hour
5572proto.hour = proto.hours = getSetHour;
5573
5574// Minute
5575proto.minute = proto.minutes = getSetMinute;
5576
5577// Second
5578proto.second = proto.seconds = getSetSecond;
5579
5580// Millisecond
5581proto.millisecond = proto.milliseconds = getSetMillisecond;
5582
5583// Offset
5584proto.utcOffset            = getSetOffset;
5585proto.utc                  = setOffsetToUTC;
5586proto.local                = setOffsetToLocal;
5587proto.parseZone            = setOffsetToParsedOffset;
5588proto.hasAlignedHourOffset = hasAlignedHourOffset;
5589proto.isDST                = isDaylightSavingTime;
5590proto.isLocal              = isLocal;
5591proto.isUtcOffset          = isUtcOffset;
5592proto.isUtc                = isUtc;
5593proto.isUTC                = isUtc;
5594
5595// Timezone
5596proto.zoneAbbr = getZoneAbbr;
5597proto.zoneName = getZoneName;
5598
5599// Deprecations
5600proto.dates  = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
5601proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
5602proto.years  = deprecate('years accessor is deprecated. Use year instead', getSetYear);
5603proto.zone   = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
5604proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
5605
5606function createUnix (input) {
5607    return createLocal(input * 1000);
5608}
5609
5610function createInZone () {
5611    return createLocal.apply(null, arguments).parseZone();
5612}
5613
5614function preParsePostFormat (string) {
5615    return string;
5616}
5617
5618var proto$1 = Locale.prototype;
5619
5620proto$1.calendar        = calendar;
5621proto$1.longDateFormat  = longDateFormat;
5622proto$1.invalidDate     = invalidDate;
5623proto$1.ordinal         = ordinal;
5624proto$1.preparse        = preParsePostFormat;
5625proto$1.postformat      = preParsePostFormat;
5626proto$1.relativeTime    = relativeTime;
5627proto$1.pastFuture      = pastFuture;
5628proto$1.set             = set;
5629
5630// Month
5631proto$1.months            =        localeMonths;
5632proto$1.monthsShort       =        localeMonthsShort;
5633proto$1.monthsParse       =        localeMonthsParse;
5634proto$1.monthsRegex       = monthsRegex;
5635proto$1.monthsShortRegex  = monthsShortRegex;
5636
5637// Week
5638proto$1.week = localeWeek;
5639proto$1.firstDayOfYear = localeFirstDayOfYear;
5640proto$1.firstDayOfWeek = localeFirstDayOfWeek;
5641
5642// Day of Week
5643proto$1.weekdays       =        localeWeekdays;
5644proto$1.weekdaysMin    =        localeWeekdaysMin;
5645proto$1.weekdaysShort  =        localeWeekdaysShort;
5646proto$1.weekdaysParse  =        localeWeekdaysParse;
5647
5648proto$1.weekdaysRegex       =        weekdaysRegex;
5649proto$1.weekdaysShortRegex  =        weekdaysShortRegex;
5650proto$1.weekdaysMinRegex    =        weekdaysMinRegex;
5651
5652// Hours
5653proto$1.isPM = localeIsPM;
5654proto$1.meridiem = localeMeridiem;
5655
5656function get$1 (format, index, field, setter) {
5657    var locale = getLocale();
5658    var utc = createUTC().set(setter, index);
vendor: 8,224 bytes, lines 5659-5951
5659    return locale[field](utc, format);
5660}
5661
5662function listMonthsImpl (format, index, field) {
5663    if (isNumber(format)) {
5664        index = format;
5665        format = undefined;
5666    }
5667
5668    format = format || '';
5669
5670    if (index != null) {
5671        return get$1(format, index, field, 'month');
5672    }
5673
5674    var i;
5675    var out = [];
5676    for (i = 0; i < 12; i++) {
5677        out[i] = get$1(format, i, field, 'month');
5678    }
5679    return out;
5680}
5681
5682// ()
5683// (5)
5684// (fmt, 5)
5685// (fmt)
5686// (true)
5687// (true, 5)
5688// (true, fmt, 5)
5689// (true, fmt)
5690function listWeekdaysImpl (localeSorted, format, index, field) {
5691    if (typeof localeSorted === 'boolean') {
5692        if (isNumber(format)) {
5693            index = format;
5694            format = undefined;
5695        }
5696
5697        format = format || '';
5698    } else {
5699        format = localeSorted;
5700        index = format;
5701        localeSorted = false;
5702
5703        if (isNumber(format)) {
5704            index = format;
5705            format = undefined;
5706        }
5707
5708        format = format || '';
5709    }
5710
5711    var locale = getLocale(),
5712        shift = localeSorted ? locale._week.dow : 0;
5713
5714    if (index != null) {
5715        return get$1(format, (index + shift) % 7, field, 'day');
5716    }
5717
5718    var i;
5719    var out = [];
5720    for (i = 0; i < 7; i++) {
5721        out[i] = get$1(format, (i + shift) % 7, field, 'day');
5722    }
5723    return out;
5724}
5725
5726function listMonths (format, index) {
5727    return listMonthsImpl(format, index, 'months');
5728}
5729
5730function listMonthsShort (format, index) {
5731    return listMonthsImpl(format, index, 'monthsShort');
5732}
5733
5734function listWeekdays (localeSorted, format, index) {
5735    return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
5736}
5737
5738function listWeekdaysShort (localeSorted, format, index) {
5739    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
5740}
5741
5742function listWeekdaysMin (localeSorted, format, index) {
5743    return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
5744}
5745
5746getSetGlobalLocale('en', {
5747    dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
5748    ordinal : function (number) {
5749        var b = number % 10,
5750            output = (toInt(number % 100 / 10) === 1) ? 'th' :
5751            (b === 1) ? 'st' :
5752            (b === 2) ? 'nd' :
5753            (b === 3) ? 'rd' : 'th';
5754        return number + output;
5755    }
5756});
5757
5758// Side effect imports
5759hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
5760hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
5761
5762var mathAbs = Math.abs;
5763
5764function abs () {
5765    var data           = this._data;
5766
5767    this._milliseconds = mathAbs(this._milliseconds);
5768    this._days         = mathAbs(this._days);
5769    this._months       = mathAbs(this._months);
5770
5771    data.milliseconds  = mathAbs(data.milliseconds);
5772    data.seconds       = mathAbs(data.seconds);
5773    data.minutes       = mathAbs(data.minutes);
5774    data.hours         = mathAbs(data.hours);
5775    data.months        = mathAbs(data.months);
5776    data.years         = mathAbs(data.years);
5777
5778    return this;
5779}
5780
5781function addSubtract$1 (duration, input, value, direction) {
5782    var other = createDuration(input, value);
5783
5784    duration._milliseconds += direction * other._milliseconds;
5785    duration._days         += direction * other._days;
5786    duration._months       += direction * other._months;
5787
5788    return duration._bubble();
5789}
5790
5791// supports only 2.0-style add(1, 's') or add(duration)
5792function add$1 (input, value) {
5793    return addSubtract$1(this, input, value, 1);
5794}
5795
5796// supports only 2.0-style subtract(1, 's') or subtract(duration)
5797function subtract$1 (input, value) {
5798    return addSubtract$1(this, input, value, -1);
5799}
5800
5801function absCeil (number) {
5802    if (number < 0) {
5803        return Math.floor(number);
5804    } else {
5805        return Math.ceil(number);
5806    }
5807}
5808
5809function bubble () {
5810    var milliseconds = this._milliseconds;
5811    var days         = this._days;
5812    var months       = this._months;
5813    var data         = this._data;
5814    var seconds, minutes, hours, years, monthsFromDays;
5815
5816    // if we have a mix of positive and negative values, bubble down first
5817    // check: https://github.com/moment/moment/issues/2166
5818    if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
5819            (milliseconds <= 0 && days <= 0 && months <= 0))) {
5820        milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
5821        days = 0;
5822        months = 0;
5823    }
5824
5825    // The following code bubbles up values, see the tests for
5826    // examples of what that means.
5827    data.milliseconds = milliseconds % 1000;
5828
5829    seconds           = absFloor(milliseconds / 1000);
5830    data.seconds      = seconds % 60;
5831
5832    minutes           = absFloor(seconds / 60);
5833    data.minutes      = minutes % 60;
5834
5835    hours             = absFloor(minutes / 60);
5836    data.hours        = hours % 24;
5837
5838    days += absFloor(hours / 24);
5839
5840    // convert days to months
5841    monthsFromDays = absFloor(daysToMonths(days));
5842    months += monthsFromDays;
5843    days -= absCeil(monthsToDays(monthsFromDays));
5844
5845    // 12 months -> 1 year
5846    years = absFloor(months / 12);
5847    months %= 12;
5848
5849    data.days   = days;
5850    data.months = months;
5851    data.years  = years;
5852
5853    return this;
5854}
5855
5856function daysToMonths (days) {
5857    // 400 years have 146097 days (taking into account leap year rules)
5858    // 400 years have 12 months === 4800
5859    return days * 4800 / 146097;
5860}
5861
5862function monthsToDays (months) {
5863    // the reverse of daysToMonths
5864    return months * 146097 / 4800;
5865}
5866
5867function as (units) {
5868    if (!this.isValid()) {
5869        return NaN;
5870    }
5871    var days;
5872    var months;
5873    var milliseconds = this._milliseconds;
5874
5875    units = normalizeUnits(units);
5876
5877    if (units === 'month' || units === 'year') {
5878        days   = this._days   + milliseconds / 864e5;
5879        months = this._months + daysToMonths(days);
5880        return units === 'month' ? months : months / 12;
5881    } else {
5882        // handle milliseconds separately because of floating point math errors (issue #1867)
5883        days = this._days + Math.round(monthsToDays(this._months));
5884        switch (units) {
5885            case 'week'   : return days / 7     + milliseconds / 6048e5;
5886            case 'day'    : return days         + milliseconds / 864e5;
5887            case 'hour'   : return days * 24    + milliseconds / 36e5;
5888            case 'minute' : return days * 1440  + milliseconds / 6e4;
5889            case 'second' : return days * 86400 + milliseconds / 1000;
5890            // Math.floor prevents floating point math errors here
5891            case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
5892            default: throw new Error('Unknown unit ' + units);
5893        }
5894    }
5895}
5896
5897// TODO: Use this.as('ms')?
5898function valueOf$1 () {
5899    if (!this.isValid()) {
5900        return NaN;
5901    }
5902    return (
5903        this._milliseconds +
5904        this._days * 864e5 +
5905        (this._months % 12) * 2592e6 +
5906        toInt(this._months / 12) * 31536e6
5907    );
5908}
5909
5910function makeAs (alias) {
5911    return function () {
5912        return this.as(alias);
5913    };
5914}
5915
5916var asMilliseconds = makeAs('ms');
5917var asSeconds      = makeAs('s');
5918var asMinutes      = makeAs('m');
5919var asHours        = makeAs('h');
5920var asDays         = makeAs('d');
5921var asWeeks        = makeAs('w');
5922var asMonths       = makeAs('M');
5923var asYears        = makeAs('y');
5924
5925function clone$1 () {
5926    return createDuration(this);
5927}
5928
5929function get$2 (units) {
5930    units = normalizeUnits(units);
5931    return this.isValid() ? this[units + 's']() : NaN;
5932}
5933
5934function makeGetter(name) {
5935    return function () {
5936        return this.isValid() ? this._data[name] : NaN;
5937    };
5938}
5939
5940var milliseconds = makeGetter('milliseconds');
5941var seconds      = makeGetter('seconds');
5942var minutes      = makeGetter('minutes');
5943var hours        = makeGetter('hours');
5944var days         = makeGetter('days');
5945var months       = makeGetter('months');
5946var years        = makeGetter('years');
5947
5948function weeks () {
5949    return absFloor(this.days() / 7);
5950}
5951
vendor: 6,445 bytes, lines 5952-6147
5952var round = Math.round;
5953var thresholds = {
5954    ss: 44,         // a few seconds to seconds
5955    s : 45,         // seconds to minute
5956    m : 45,         // minutes to hour
5957    h : 22,         // hours to day
5958    d : 26,         // days to month
5959    M : 11          // months to year
5960};
5961
5962// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
5963function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
5964    return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
5965}
5966
5967function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
5968    var duration = createDuration(posNegDuration).abs();
5969    var seconds  = round(duration.as('s'));
5970    var minutes  = round(duration.as('m'));
5971    var hours    = round(duration.as('h'));
5972    var days     = round(duration.as('d'));
5973    var months   = round(duration.as('M'));
5974    var years    = round(duration.as('y'));
5975
5976    var a = seconds <= thresholds.ss && ['s', seconds]  ||
5977            seconds < thresholds.s   && ['ss', seconds] ||
5978            minutes <= 1             && ['m']           ||
5979            minutes < thresholds.m   && ['mm', minutes] ||
5980            hours   <= 1             && ['h']           ||
5981            hours   < thresholds.h   && ['hh', hours]   ||
5982            days    <= 1             && ['d']           ||
5983            days    < thresholds.d   && ['dd', days]    ||
5984            months  <= 1             && ['M']           ||
5985            months  < thresholds.M   && ['MM', months]  ||
5986            years   <= 1             && ['y']           || ['yy', years];
5987
5988    a[2] = withoutSuffix;
5989    a[3] = +posNegDuration > 0;
5990    a[4] = locale;
5991    return substituteTimeAgo.apply(null, a);
5992}
5993
5994// This function allows you to set the rounding function for relative time strings
5995function getSetRelativeTimeRounding (roundingFunction) {
5996    if (roundingFunction === undefined) {
5997        return round;
5998    }
5999    if (typeof(roundingFunction) === 'function') {
6000        round = roundingFunction;
6001        return true;
6002    }
6003    return false;
6004}
6005
6006// This function allows you to set a threshold for relative time strings
6007function getSetRelativeTimeThreshold (threshold, limit) {
6008    if (thresholds[threshold] === undefined) {
6009        return false;
6010    }
6011    if (limit === undefined) {
6012        return thresholds[threshold];
6013    }
6014    thresholds[threshold] = limit;
6015    if (threshold === 's') {
6016        thresholds.ss = limit - 1;
6017    }
6018    return true;
6019}
6020
6021function humanize (withSuffix) {
6022    if (!this.isValid()) {
6023        return this.localeData().invalidDate();
6024    }
6025
6026    var locale = this.localeData();
6027    var output = relativeTime$1(this, !withSuffix, locale);
6028
6029    if (withSuffix) {
6030        output = locale.pastFuture(+this, output);
6031    }
6032
6033    return locale.postformat(output);
6034}
6035
6036var abs$1 = Math.abs;
6037
6038function sign(x) {
6039    return ((x > 0) - (x < 0)) || +x;
6040}
6041
6042function toISOString$1() {
6043    // for ISO strings we do not use the normal bubbling rules:
6044    //  * milliseconds bubble up until they become hours
6045    //  * days do not bubble at all
6046    //  * months bubble up until they become years
6047    // This is because there is no context-free conversion between hours and days
6048    // (think of clock changes)
6049    // and also not between days and months (28-31 days per month)
6050    if (!this.isValid()) {
6051        return this.localeData().invalidDate();
6052    }
6053
6054    var seconds = abs$1(this._milliseconds) / 1000;
6055    var days         = abs$1(this._days);
6056    var months       = abs$1(this._months);
6057    var minutes, hours, years;
6058
6059    // 3600 seconds -> 60 minutes -> 1 hour
6060    minutes           = absFloor(seconds / 60);
6061    hours             = absFloor(minutes / 60);
6062    seconds %= 60;
6063    minutes %= 60;
6064
6065    // 12 months -> 1 year
6066    years  = absFloor(months / 12);
6067    months %= 12;
6068
6069
6070    // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
6071    var Y = years;
6072    var M = months;
6073    var D = days;
6074    var h = hours;
6075    var m = minutes;
6076    var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
6077    var total = this.asSeconds();
6078
6079    if (!total) {
6080        // this is the same as C#'s (Noda) and python (isodate)...
6081        // but not other JS (goog.date)
6082        return 'P0D';
6083    }
6084
6085    var totalSign = total < 0 ? '-' : '';
6086    var ymSign = sign(this._months) !== sign(total) ? '-' : '';
6087    var daysSign = sign(this._days) !== sign(total) ? '-' : '';
6088    var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
6089
6090    return totalSign + 'P' +
6091        (Y ? ymSign + Y + 'Y' : '') +
6092        (M ? ymSign + M + 'M' : '') +
6093        (D ? daysSign + D + 'D' : '') +
6094        ((h || m || s) ? 'T' : '') +
6095        (h ? hmsSign + h + 'H' : '') +
6096        (m ? hmsSign + m + 'M' : '') +
6097        (s ? hmsSign + s + 'S' : '');
6098}
6099
6100var proto$2 = Duration.prototype;
6101
6102proto$2.isValid        = isValid$1;
6103proto$2.abs            = abs;
6104proto$2.add            = add$1;
6105proto$2.subtract       = subtract$1;
6106proto$2.as             = as;
6107proto$2.asMilliseconds = asMilliseconds;
6108proto$2.asSeconds      = asSeconds;
6109proto$2.asMinutes      = asMinutes;
6110proto$2.asHours        = asHours;
6111proto$2.asDays         = asDays;
6112proto$2.asWeeks        = asWeeks;
6113proto$2.asMonths       = asMonths;
6114proto$2.asYears        = asYears;
6115proto$2.valueOf        = valueOf$1;
6116proto$2._bubble        = bubble;
6117proto$2.clone          = clone$1;
6118proto$2.get            = get$2;
6119proto$2.milliseconds   = milliseconds;
6120proto$2.seconds        = seconds;
6121proto$2.minutes        = minutes;
6122proto$2.hours          = hours;
6123proto$2.days           = days;
6124proto$2.weeks          = weeks;
6125proto$2.months         = months;
6126proto$2.years          = years;
6127proto$2.humanize       = humanize;
6128proto$2.toISOString    = toISOString$1;
6129proto$2.toString       = toISOString$1;
6130proto$2.toJSON         = toISOString$1;
6131proto$2.locale         = locale;
6132proto$2.localeData     = localeData;
6133
6134// Deprecations
6135proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
6136proto$2.lang = lang;
6137
6138// Side effect imports
6139
6140// FORMATTING
6141
6142addFormatToken('X', 0, 0, 'unix');
6143addFormatToken('x', 0, 0, 'valueOf');
6144
6145// PARSING
6146
6147addRegexToken('x', matchSigned);
6148addRegexToken('X', matchTimestamp);
6149addParseToken('X', function (input, array, config) {
6150    config._d = new Date(parseFloat(input, 10) * 1000);
6151});
6152addParseToken('x', function (input, array, config) {
6153    config._d = new Date(toInt(input));
6154});
6155
6156// Side effect imports
6157
6158
6159hooks.version = '2.20.1';
6160
6161setHookCallback(createLocal);
6162
6163hooks.fn                    = proto;
6164hooks.min                   = min;
6165hooks.max                   = max;
6166hooks.now                   = now;
6167hooks.utc                   = createUTC;
6168hooks.unix                  = createUnix;
6169hooks.months                = listMonths;
6170hooks.isDate                = isDate;
6171hooks.locale                = getSetGlobalLocale;
6172hooks.invalid               = createInvalid;
6173hooks.duration              = createDuration;
6174hooks.isMoment              = isMoment;
6175hooks.weekdays              = listWeekdays;
6176hooks.parseZone             = createInZone;
6177hooks.localeData            = getLocale;
6178hooks.isDuration            = isDuration;
6179hooks.monthsShort           = listMonthsShort;
6180hooks.weekdaysMin           = listWeekdaysMin;
6181hooks.defineLocale          = defineLocale;
6182hooks.updateLocale          = updateLocale;
6183hooks.locales               = listLocales;
6184hooks.weekdaysShort         = listWeekdaysShort;
6185hooks.normalizeUnits        = normalizeUnits;
6186hooks.relativeTimeRounding  = getSetRelativeTimeRounding;
6187hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
6188hooks.calendarFormat        = getCalendarFormat;
6189hooks.prototype             = proto;
6190
6191// currently HTML5 input type only supports 24-hour formats
6192hooks.HTML5_FMT = {
6193    DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',             // <input type="datetime-local" />
6194    DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',  // <input type="datetime-local" step="1" />
6195    DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',   // <input type="datetime-local" step="0.001" />
6196    DATE: 'YYYY-MM-DD',                             // <input type="date" />
6197    TIME: 'HH:mm',                                  // <input type="time" />
6198    TIME_SECONDS: 'HH:mm:ss',                       // <input type="time" step="1" />
6199    TIME_MS: 'HH:mm:ss.SSS',                        // <input type="time" step="0.001" />
6200    WEEK: 'YYYY-[W]WW',                             // <input type="week" />
6201    MONTH: 'YYYY-MM'                                // <input type="month" />
6202};
6203
6204return hooks;
6205
6206})));
6207
6208},{}],7:[function(require,module,exports){
6209/**
6210 * @namespace Chart
6211 */
6212var Chart = require(29)();
6213
6214Chart.helpers = require(45);
6215
6216// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
6217require(27)(Chart);
6218
6219Chart.defaults = require(25);
6220Chart.Element = require(26);
6221Chart.elements = require(40);
6222Chart.Interaction = require(28);
6223Chart.layouts = require(30);
6224Chart.platform = require(48);
6225Chart.plugins = require(31);
6226Chart.Ticks = require(34);
6227
6228require(22)(Chart);
6229require(23)(Chart);
6230require(24)(Chart);
6231require(33)(Chart);
6232require(32)(Chart);
6233require(35)(Chart);
6234
6235require(55)(Chart);
6236require(53)(Chart);
6237require(54)(Chart);
6238require(56)(Chart);
6239require(57)(Chart);
6240require(58)(Chart);
6241
6242// Controllers must be loaded after elements
6243// See Chart.core.datasetController.dataElementType
6244require(15)(Chart);
6245require(16)(Chart);
6246require(17)(Chart);
6247require(18)(Chart);
6248require(19)(Chart);
6249require(20)(Chart);
6250require(21)(Chart);
6251
6252require(8)(Chart);
6253require(9)(Chart);
6254require(10)(Chart);
6255require(11)(Chart);
6256require(12)(Chart);
6257require(13)(Chart);
6258require(14)(Chart);
6259
6260// Loading built-it plugins
6261var plugins = require(49);
6262for (var k in plugins) {
6263	if (plugins.hasOwnProperty(k)) {
6264		Chart.plugins.register(plugins[k]);
6265	}
6266}
6267
6268Chart.platform.initialize();
6269
6270module.exports = Chart;
6271if (typeof window !== 'undefined') {
6272	window.Chart = Chart;
6273}
6274
6275// DEPRECATIONS
6276
6277/**
6278 * Provided for backward compatibility, not available anymore
6279 * @namespace Chart.Legend
6280 * @deprecated since version 2.1.5
6281 * @todo remove at version 3
6282 * @private
6283 */
6284Chart.Legend = plugins.legend._element;
6285
6286/**
6287 * Provided for backward compatibility, not available anymore
6288 * @namespace Chart.Title
6289 * @deprecated since version 2.1.5
6290 * @todo remove at version 3
6291 * @private
6292 */
6293Chart.Title = plugins.title._element;
6294
6295/**
6296 * Provided for backward compatibility, use Chart.plugins instead
6297 * @namespace Chart.pluginService
6298 * @deprecated since version 2.1.5
6299 * @todo remove at version 3
6300 * @private
6301 */
6302Chart.pluginService = Chart.plugins;
6303
6304/**
6305 * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
6306 * effect, instead simply create/register plugins via plain JavaScript objects.
6307 * @interface Chart.PluginBase
6308 * @deprecated since version 2.5.0
6309 * @todo remove at version 3
6310 * @private
6311 */
6312Chart.PluginBase = Chart.Element.extend({});
6313
6314/**
6315 * Provided for backward compatibility, use Chart.helpers.canvas instead.
6316 * @namespace Chart.canvasHelpers
6317 * @deprecated since version 2.6.0
6318 * @todo remove at version 3
6319 * @private
6320 */
6321Chart.canvasHelpers = Chart.helpers.canvas;
6322
6323/**
6324 * Provided for backward compatibility, use Chart.layouts instead.
6325 * @namespace Chart.layoutService
6326 * @deprecated since version 2.8.0
6327 * @todo remove at version 3
6328 * @private
6329 */
6330Chart.layoutService = Chart.layouts;
6331
6332},{"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){
6333'use strict';
6334
6335module.exports = function(Chart) {
6336
6337	Chart.Bar = function(context, config) {
6338		config.type = 'bar';
6339
6340		return new Chart(context, config);
6341	};
6342
6343};
6344
6345},{}],9:[function(require,module,exports){
6346'use strict';
6347
6348module.exports = function(Chart) {
6349
6350	Chart.Bubble = function(context, config) {
6351		config.type = 'bubble';
6352		return new Chart(context, config);
6353	};
6354
6355};
6356
6357},{}],10:[function(require,module,exports){
6358'use strict';
6359
6360module.exports = function(Chart) {
6361
6362	Chart.Doughnut = function(context, config) {
6363		config.type = 'doughnut';
6364
6365		return new Chart(context, config);
6366	};
6367
6368};
6369
6370},{}],11:[function(require,module,exports){
6371'use strict';
6372
6373module.exports = function(Chart) {
6374
6375	Chart.Line = function(context, config) {
6376		config.type = 'line';
6377
6378		return new Chart(context, config);
6379	};
6380
6381};
6382
6383},{}],12:[function(require,module,exports){
6384'use strict';
6385
6386module.exports = function(Chart) {
6387
6388	Chart.PolarArea = function(context, config) {
6389		config.type = 'polarArea';
6390
6391		return new Chart(context, config);
6392	};
6393
6394};
6395
6396},{}],13:[function(require,module,exports){
6397'use strict';
6398
6399module.exports = function(Chart) {
6400
6401	Chart.Radar = function(context, config) {
6402		config.type = 'radar';
6403
6404		return new Chart(context, config);
6405	};
6406
6407};
6408
6409},{}],14:[function(require,module,exports){
6410'use strict';
6411
6412module.exports = function(Chart) {
6413	Chart.Scatter = function(context, config) {
6414		config.type = 'scatter';
6415		return new Chart(context, config);
6416	};
6417};
6418
6419},{}],15:[function(require,module,exports){
6420'use strict';
6421
6422var defaults = require(25);
6423var elements = require(40);
6424var helpers = require(45);
6425
6426defaults._set('bar', {
6427	hover: {
6428		mode: 'label'
6429	},
6430
6431	scales: {
6432		xAxes: [{
6433			type: 'category',
6434
6435			// Specific to Bar Controller
6436			categoryPercentage: 0.8,
6437			barPercentage: 0.9,
6438
6439			// offset settings
6440			offset: true,
6441
6442			// grid line settings
6443			gridLines: {
6444				offsetGridLines: true
6445			}
6446		}],
6447
6448		yAxes: [{
6449			type: 'linear'
6450		}]
6451	}
6452});
6453
6454defaults._set('horizontalBar', {
6455	hover: {
6456		mode: 'index',
6457		axis: 'y'
6458	},
6459
6460	scales: {
6461		xAxes: [{
6462			type: 'linear',
6463			position: 'bottom'
6464		}],
6465
6466		yAxes: [{
6467			position: 'left',
6468			type: 'category',
6469
6470			// Specific to Horizontal Bar Controller
6471			categoryPercentage: 0.8,
6472			barPercentage: 0.9,
6473
6474			// offset settings
6475			offset: true,
6476
6477			// grid line settings
6478			gridLines: {
6479				offsetGridLines: true
6480			}
6481		}]
6482	},
6483
6484	elements: {
6485		rectangle: {
6486			borderSkipped: 'left'
6487		}
6488	},
6489
6490	tooltips: {
6491		callbacks: {
6492			title: function(item, data) {
6493				// Pick first xLabel for now
6494				var title = '';
6495
6496				if (item.length > 0) {
6497					if (item[0].yLabel) {
6498						title = item[0].yLabel;
6499					} else if (data.labels.length > 0 && item[0].index < data.labels.length) {
6500						title = data.labels[item[0].index];
6501					}
6502				}
6503
6504				return title;
6505			},
6506
6507			label: function(item, data) {
6508				var datasetLabel = data.datasets[item.datasetIndex].label || '';
6509				return datasetLabel + ': ' + item.xLabel;
6510			}
6511		},
6512		mode: 'index',
6513		axis: 'y'
6514	}
6515});
6516
6517/**
6518 * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
6519 * @private
6520 */
6521function computeMinSampleSize(scale, pixels) {
6522	var min = scale.isHorizontal() ? scale.width : scale.height;
6523	var ticks = scale.getTicks();
6524	var prev, curr, i, ilen;
6525
6526	for (i = 1, ilen = pixels.length; i < ilen; ++i) {
6527		min = Math.min(min, pixels[i] - pixels[i - 1]);
6528	}
6529
6530	for (i = 0, ilen = ticks.length; i < ilen; ++i) {
6531		curr = scale.getPixelForTick(i);
6532		min = i > 0 ? Math.min(min, curr - prev) : min;
6533		prev = curr;
6534	}
6535
6536	return min;
6537}
6538
6539/**
6540 * Computes an "ideal" category based on the absolute bar thickness or, if undefined or null,
6541 * uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This
6542 * mode currently always generates bars equally sized (until we introduce scriptable options?).
6543 * @private
6544 */
6545function computeFitCategoryTraits(index, ruler, options) {
6546	var thickness = options.barThickness;
6547	var count = ruler.stackCount;
6548	var curr = ruler.pixels[index];
6549	var size, ratio;
6550
6551	if (helpers.isNullOrUndef(thickness)) {
6552		size = ruler.min * options.categoryPercentage;
6553		ratio = options.barPercentage;
6554	} else {
6555		// When bar thickness is enforced, category and bar percentages are ignored.
6556		// Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
6557		// and deprecate barPercentage since this value is ignored when thickness is absolute.
6558		size = thickness * count;
6559		ratio = 1;
6560	}
6561
6562	return {
6563		chunk: size / count,
6564		ratio: ratio,
6565		start: curr - (size / 2)
6566	};
6567}
6568
6569/**
6570 * Computes an "optimal" category that globally arranges bars side by side (no gap when
6571 * percentage options are 1), based on the previous and following categories. This mode
6572 * generates bars with different widths when data are not evenly spaced.
6573 * @private
6574 */
6575function computeFlexCategoryTraits(index, ruler, options) {
6576	var pixels = ruler.pixels;
6577	var curr = pixels[index];
6578	var prev = index > 0 ? pixels[index - 1] : null;
6579	var next = index < pixels.length - 1 ? pixels[index + 1] : null;
6580	var percent = options.categoryPercentage;
6581	var start, size;
6582
6583	if (prev === null) {
6584		// first data: its size is double based on the next point or,
6585		// if it's also the last data, we use the scale end extremity.
6586		prev = curr - (next === null ? ruler.end - curr : next - curr);
6587	}
6588
6589	if (next === null) {
6590		// last data: its size is also double based on the previous point.
6591		next = curr + curr - prev;
6592	}
6593
6594	start = curr - ((curr - prev) / 2) * percent;
6595	size = ((next - prev) / 2) * percent;
6596
6597	return {
6598		chunk: size / ruler.stackCount,
6599		ratio: options.barPercentage,
6600		start: start
6601	};
6602}
6603
6604module.exports = function(Chart) {
6605
6606	Chart.controllers.bar = Chart.DatasetController.extend({
6607
6608		dataElementType: elements.Rectangle,
6609
6610		initialize: function() {
6611			var me = this;
6612			var meta;
6613
6614			Chart.DatasetController.prototype.initialize.apply(me, arguments);
6615
6616			meta = me.getMeta();
6617			meta.stack = me.getDataset().stack;
6618			meta.bar = true;
6619		},
6620
6621		update: function(reset) {
6622			var me = this;
6623			var rects = me.getMeta().data;
6624			var i, ilen;
6625
6626			me._ruler = me.getRuler();
6627
6628			for (i = 0, ilen = rects.length; i < ilen; ++i) {
6629				me.updateElement(rects[i], i, reset);
6630			}
6631		},
6632
6633		updateElement: function(rectangle, index, reset) {
6634			var me = this;
6635			var chart = me.chart;
6636			var meta = me.getMeta();
6637			var dataset = me.getDataset();
6638			var custom = rectangle.custom || {};
6639			var rectangleOptions = chart.options.elements.rectangle;
6640
6641			rectangle._xScale = me.getScaleForId(meta.xAxisID);
6642			rectangle._yScale = me.getScaleForId(meta.yAxisID);
6643			rectangle._datasetIndex = me.index;
6644			rectangle._index = index;
6645
6646			rectangle._model = {
6647				datasetLabel: dataset.label,
6648				label: chart.data.labels[index],
6649				borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
6650				backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
6651				borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
6652				borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
6653			};
6654
6655			me.updateElementGeometry(rectangle, index, reset);
6656
6657			rectangle.pivot();
6658		},
6659
6660		/**
6661		 * @private
6662		 */
6663		updateElementGeometry: function(rectangle, index, reset) {
6664			var me = this;
6665			var model = rectangle._model;
6666			var vscale = me.getValueScale();
6667			var base = vscale.getBasePixel();
6668			var horizontal = vscale.isHorizontal();
6669			var ruler = me._ruler || me.getRuler();
6670			var vpixels = me.calculateBarValuePixels(me.index, index);
6671			var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
6672
6673			model.horizontal = horizontal;
6674			model.base = reset ? base : vpixels.base;
6675			model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
6676			model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
6677			model.height = horizontal ? ipixels.size : undefined;
6678			model.width = horizontal ? undefined : ipixels.size;
6679		},
6680
6681		/**
6682		 * @private
6683		 */
6684		getValueScaleId: function() {
6685			return this.getMeta().yAxisID;
6686		},
6687
6688		/**
6689		 * @private
6690		 */
6691		getIndexScaleId: function() {
6692			return this.getMeta().xAxisID;
6693		},
6694
6695		/**
6696		 * @private
6697		 */
6698		getValueScale: function() {
6699			return this.getScaleForId(this.getValueScaleId());
6700		},
6701
6702		/**
6703		 * @private
6704		 */
6705		getIndexScale: function() {
6706			return this.getScaleForId(this.getIndexScaleId());
6707		},
6708
6709		/**
6710		 * Returns the stacks based on groups and bar visibility.
6711		 * @param {Number} [last] - The dataset index
6712		 * @returns {Array} The stack list
6713		 * @private
6714		 */
6715		_getStacks: function(last) {
6716			var me = this;
6717			var chart = me.chart;
6718			var scale = me.getIndexScale();
6719			var stacked = scale.options.stacked;
6720			var ilen = last === undefined ? chart.data.datasets.length : last + 1;
6721			var stacks = [];
6722			var i, meta;
6723
6724			for (i = 0; i < ilen; ++i) {
6725				meta = chart.getDatasetMeta(i);
6726				if (meta.bar && chart.isDatasetVisible(i) &&
6727					(stacked === false ||
6728					(stacked === true && stacks.indexOf(meta.stack) === -1) ||
6729					(stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
6730					stacks.push(meta.stack);
6731				}
6732			}
6733
6734			return stacks;
6735		},
6736
6737		/**
6738		 * Returns the effective number of stacks based on groups and bar visibility.
6739		 * @private
6740		 */
6741		getStackCount: function() {
6742			return this._getStacks().length;
6743		},
6744
6745		/**
6746		 * Returns the stack index for the given dataset based on groups and bar visibility.
6747		 * @param {Number} [datasetIndex] - The dataset index
6748		 * @param {String} [name] - The stack name to find
6749		 * @returns {Number} The stack index
6750		 * @private
6751		 */
6752		getStackIndex: function(datasetIndex, name) {
6753			var stacks = this._getStacks(datasetIndex);
6754			var index = (name !== undefined)
6755				? stacks.indexOf(name)
6756				: -1; // indexOf returns -1 if element is not present
6757
6758			return (index === -1)
6759				? stacks.length - 1
6760				: index;
6761		},
6762
6763		/**
6764		 * @private
6765		 */
6766		getRuler: function() {
6767			var me = this;
6768			var scale = me.getIndexScale();
6769			var stackCount = me.getStackCount();
6770			var datasetIndex = me.index;
6771			var isHorizontal = scale.isHorizontal();
6772			var start = isHorizontal ? scale.left : scale.top;
6773			var end = start + (isHorizontal ? scale.width : scale.height);
6774			var pixels = [];
6775			var i, ilen, min;
6776
6777			for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
6778				pixels.push(scale.getPixelForValue(null, i, datasetIndex));
6779			}
6780
6781			min = helpers.isNullOrUndef(scale.options.barThickness)
6782				? computeMinSampleSize(scale, pixels)
6783				: -1;
6784
6785			return {
6786				min: min,
6787				pixels: pixels,
6788				start: start,
6789				end: end,
6790				stackCount: stackCount,
6791				scale: scale
6792			};
6793		},
6794
6795		/**
6796		 * Note: pixel values are not clamped to the scale area.
6797		 * @private
6798		 */
6799		calculateBarValuePixels: function(datasetIndex, index) {
6800			var me = this;
6801			var chart = me.chart;
6802			var meta = me.getMeta();
6803			var scale = me.getValueScale();
6804			var datasets = chart.data.datasets;
6805			var value = scale.getRightValue(datasets[datasetIndex].data[index]);
6806			var stacked = scale.options.stacked;
6807			var stack = meta.stack;
6808			var start = 0;
6809			var i, imeta, ivalue, base, head, size;
6810
6811			if (stacked || (stacked === undefined && stack !== undefined)) {
6812				for (i = 0; i < datasetIndex; ++i) {
6813					imeta = chart.getDatasetMeta(i);
6814
6815					if (imeta.bar &&
6816						imeta.stack === stack &&
6817						imeta.controller.getValueScaleId() === scale.id &&
6818						chart.isDatasetVisible(i)) {
6819
6820						ivalue = scale.getRightValue(datasets[i].data[index]);
6821						if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
6822							start += ivalue;
6823						}
6824					}
6825				}
6826			}
6827
6828			base = scale.getPixelForValue(start);
6829			head = scale.getPixelForValue(start + value);
6830			size = (head - base) / 2;
6831
6832			return {
6833				size: size,
6834				base: base,
6835				head: head,
6836				center: head + size / 2
6837			};
6838		},
6839
6840		/**
6841		 * @private
6842		 */
6843		calculateBarIndexPixels: function(datasetIndex, index, ruler) {
6844			var me = this;
6845			var options = ruler.scale.options;
6846			var range = options.barThickness === 'flex'
6847				? computeFlexCategoryTraits(index, ruler, options)
6848				: computeFitCategoryTraits(index, ruler, options);
6849
6850			var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
6851			var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
6852			var size = Math.min(
6853				helpers.valueOrDefault(options.maxBarThickness, Infinity),
6854				range.chunk * range.ratio);
6855
6856			return {
6857				base: center - size / 2,
6858				head: center + size / 2,
6859				center: center,
6860				size: size
6861			};
6862		},
6863
6864		draw: function() {
6865			var me = this;
6866			var chart = me.chart;
6867			var scale = me.getValueScale();
6868			var rects = me.getMeta().data;
6869			var dataset = me.getDataset();
6870			var ilen = rects.length;
6871			var i = 0;
6872
6873			helpers.canvas.clipArea(chart.ctx, chart.chartArea);
6874
6875			for (; i < ilen; ++i) {
6876				if (!isNaN(scale.getRightValue(dataset.data[i]))) {
6877					rects[i].draw();
6878				}
6879			}
6880
6881			helpers.canvas.unclipArea(chart.ctx);
6882		},
6883
6884		setHoverStyle: function(rectangle) {
6885			var dataset = this.chart.data.datasets[rectangle._datasetIndex];
6886			var index = rectangle._index;
6887			var custom = rectangle.custom || {};
6888			var model = rectangle._model;
6889
vendor: 4,408 bytes, lines 6890-7031
6890			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
6891			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor));
6892			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
6893		},
6894
6895		removeHoverStyle: function(rectangle) {
6896			var dataset = this.chart.data.datasets[rectangle._datasetIndex];
6897			var index = rectangle._index;
6898			var custom = rectangle.custom || {};
6899			var model = rectangle._model;
6900			var rectangleElementOptions = this.chart.options.elements.rectangle;
6901
6902			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor);
6903			model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor);
6904			model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth);
6905		}
6906	});
6907
6908	Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
6909		/**
6910		 * @private
6911		 */
6912		getValueScaleId: function() {
6913			return this.getMeta().xAxisID;
6914		},
6915
6916		/**
6917		 * @private
6918		 */
6919		getIndexScaleId: function() {
6920			return this.getMeta().yAxisID;
6921		}
6922	});
6923};
6924
6925},{"25":25,"40":40,"45":45}],16:[function(require,module,exports){
6926'use strict';
6927
6928var defaults = require(25);
6929var elements = require(40);
6930var helpers = require(45);
6931
6932defaults._set('bubble', {
6933	hover: {
6934		mode: 'single'
6935	},
6936
6937	scales: {
6938		xAxes: [{
6939			type: 'linear', // bubble should probably use a linear scale by default
6940			position: 'bottom',
6941			id: 'x-axis-0' // need an ID so datasets can reference the scale
6942		}],
6943		yAxes: [{
6944			type: 'linear',
6945			position: 'left',
6946			id: 'y-axis-0'
6947		}]
6948	},
6949
6950	tooltips: {
6951		callbacks: {
6952			title: function() {
6953				// Title doesn't make sense for scatter since we format the data as a point
6954				return '';
6955			},
6956			label: function(item, data) {
6957				var datasetLabel = data.datasets[item.datasetIndex].label || '';
6958				var dataPoint = data.datasets[item.datasetIndex].data[item.index];
6959				return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')';
6960			}
6961		}
6962	}
6963});
6964
6965
6966module.exports = function(Chart) {
6967
6968	Chart.controllers.bubble = Chart.DatasetController.extend({
6969		/**
6970		 * @protected
6971		 */
6972		dataElementType: elements.Point,
6973
6974		/**
6975		 * @protected
6976		 */
6977		update: function(reset) {
6978			var me = this;
6979			var meta = me.getMeta();
6980			var points = meta.data;
6981
6982			// Update Points
6983			helpers.each(points, function(point, index) {
6984				me.updateElement(point, index, reset);
6985			});
6986		},
6987
6988		/**
6989		 * @protected
6990		 */
6991		updateElement: function(point, index, reset) {
6992			var me = this;
6993			var meta = me.getMeta();
6994			var custom = point.custom || {};
6995			var xScale = me.getScaleForId(meta.xAxisID);
6996			var yScale = me.getScaleForId(meta.yAxisID);
6997			var options = me._resolveElementOptions(point, index);
6998			var data = me.getDataset().data[index];
6999			var dsIndex = me.index;
7000
7001			var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
7002			var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
7003
7004			point._xScale = xScale;
7005			point._yScale = yScale;
7006			point._options = options;
7007			point._datasetIndex = dsIndex;
7008			point._index = index;
7009			point._model = {
7010				backgroundColor: options.backgroundColor,
7011				borderColor: options.borderColor,
7012				borderWidth: options.borderWidth,
7013				hitRadius: options.hitRadius,
7014				pointStyle: options.pointStyle,
7015				radius: reset ? 0 : options.radius,
7016				skip: custom.skip || isNaN(x) || isNaN(y),
7017				x: x,
7018				y: y,
7019			};
7020
7021			point.pivot();
7022		},
7023
7024		/**
7025		 * @protected
7026		 */
7027		setHoverStyle: function(point) {
7028			var model = point._model;
7029			var options = point._options;
7030
7031			model.backgroundColor = helpers.valueOrDefault(options.hoverBackgroun
7031dColor, helpers.getHoverColor(options.backgroundColor));
7032			model.borderColor = helpers.valueOrDefault(options.hoverBorderColor, helpers.getHoverColor(options.borderColor));
7033			model.borderWidth = helpers.valueOrDefault(options.hoverBorderWidth, options.borderWidth);
7034			model.radius = options.radius + options.hoverRadius;
7035		},
7036
7037		/**
7038		 * @protected
7039		 */
7040		removeHoverStyle: function(point) {
7041			var model = point._model;
7042			var options = point._options;
7043
7044			model.backgroundColor = options.backgroundColor;
7045			model.borderColor = options.borderColor;
7046			model.borderWidth = options.borderWidth;
7047			model.radius = options.radius;
7048		},
7049
7050		/**
7051		 * @private
7052		 */
7053		_resolveElementOptions: function(point, index) {
7054			var me = this;
7055			var chart = me.chart;
7056			var datasets = chart.data.datasets;
7057			var dataset = datasets[me.index];
7058			var custom = point.custom || {};
7059			var options = chart.options.elements.point;
7060			var resolve = helpers.options.resolve;
7061			var data = dataset.data[index];
7062			var values = {};
7063			var i, ilen, key;
7064
7065			// Scriptable options
7066			var context = {
7067				chart: chart,
7068				dataIndex: index,
7069				dataset: dataset,
7070				datasetIndex: me.index
7071			};
7072
7073			var keys = [
7074				'backgroundColor',
7075				'borderColor',
7076				'borderWidth',
7077				'hoverBackgroundColor',
7078				'hoverBorderColor',
7079				'hoverBorderWidth',
7080				'hoverRadius',
7081				'hitRadius',
7082				'pointStyle'
7083			];
7084
7085			for (i = 0, ilen = keys.length; i < ilen; ++i) {
7086				key = keys[i];
7087				values[key] = resolve([
7088					custom[key],
7089					dataset[key],
7090					options[key]
7091				], context, index);
7092			}
7093
7094			// Custom radius resolution
7095			values.radius = resolve([
7096				custom.radius,
7097				data ? data.r : undefined,
7098				dataset.radius,
7099				options.radius
7100			], context, index);
7101
7102			return values;
7103		}
7104	});
7105};
7106
7107},{"25":25,"40":40,"45":45}],17:[function(require,module,exports){
7108'use strict';
7109
7110var defaults = require(25);
7111var elements = require(40);
7112var helpers = require(45);
7113
7114defaults._set('doughnut', {
7115	animation: {
7116		// Boolean - Whether we animate the rotation of the Doughnut
7117		animateRotate: true,
7118		// Boolean - Whether we animate scaling the Doughnut from the centre
7119		animateScale: false
7120	},
7121	hover: {
7122		mode: 'single'
7123	},
7124	legendCallback: function(chart) {
7125		var text = [];
7126		text.push('<ul class="' + chart.id + '-legend">');
7127
7128		var data = chart.data;
7129		var datasets = data.datasets;
7130		var labels = data.labels;
7131
7132		if (datasets.length) {
7133			for (var i = 0; i < datasets[0].data.length; ++i) {
7134				text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
7135				if (labels[i]) {
7136					text.push(labels[i]);
7137				}
7138				text.push('</li>');
7139			}
7140		}
7141
7142		text.push('</ul>');
7143		return text.join('');
7144	},
7145	legend: {
7146		labels: {
7147			generateLabels: function(chart) {
7148				var data = chart.data;
7149				if (data.labels.length && data.datasets.length) {
7150					return data.labels.map(function(label, i) {
7151						var meta = chart.getDatasetMeta(0);
7152						var ds = data.datasets[0];
7153						var arc = meta.data[i];
7154						var custom = arc && arc.custom || {};
7155						var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
7156						var arcOpts = chart.options.elements.arc;
7157						var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
7158						var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
7159						var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
7160
7161						return {
7162							text: label,
7163							fillStyle: fill,
7164							strokeStyle: stroke,
7165							lineWidth: bw,
7166							hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
7167
7168							// Extra data used for toggling the correct item
7169							index: i
7170						};
7171					});
7172				}
7173				return [];
7174			}
7175		},
7176
7177		onClick: function(e, legendItem) {
7178			var index = legendItem.index;
7179			var chart = this.chart;
7180			var i, ilen, meta;
7181
7182			for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
7183				meta = chart.getDatasetMeta(i);
7184				// toggle visibility of index if exists
7185				if (meta.data[index]) {
7186					meta.data[index].hidden = !meta.data[index].hidden;
7187				}
7188			}
7189
7190			chart.update();
7191		}
7192	},
7193
7194	// The percentage of the chart that we cut out of the middle.
7195	cutoutPercentage: 50,
7196
7197	// The rotation of the chart, where the first data arc begins.
7198	rotation: Math.PI * -0.5,
7199
7200	// The total circumference of the chart.
7201	circumference: Math.PI * 2.0,
7202
7203	// Need to override these to give a nice default
7204	tooltips: {
7205		callbacks: {
7206			title: function() {
7207				return '';
7208			},
7209			label: function(tooltipItem, data) {
7210				var dataLabel = data.labels[tooltipItem.index];
7211				var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
7212
7213				if (helpers.isArray(dataLabel)) {
7214					// show value on first line of multiline label
7215					// need to clone because we are changing the value
7216					dataLabel = dataLabel.slice();
7217					dataLabel[0] += value;
7218				} else {
7219					dataLabel += value;
7220				}
7221
7222				return dataLabel;
7223			}
7224		}
7225	}
7226});
7227
7228defaults._set('pie', helpers.clone(defaults.doughnut));
7229defaults._set('pie', {
7230	cutoutPercentage: 0
7231});
7232
7233module.exports = function(Chart) {
7234
7235	Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
7236
7237		dataElementType: elements.Arc,
7238
7239		linkScales: helpers.noop,
7240
7241		// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
7242		getRingIndex: function(datasetIndex) {
7243			var ringIndex = 0;
7244
7245			for (var j = 0; j < datasetIndex; ++j) {
7246				if (this.chart.isDatasetVisible(j)) {
7247					++ringIndex;
7248				}
7249			}
7250
7251			return ringIndex;
7252		},
7253
7254		update: function(reset) {
7255			var me = this;
7256			var chart = me.chart;
7257			var chartArea = chart.chartArea;
7258			var opts = chart.options;
7259			var arcOpts = opts.elements.arc;
7260			var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth;
7261			var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth;
7262			var minSize = Math.min(availableWidth, availableHeight);
7263			var offset = {x: 0, y: 0};
7264			var meta = me.getMeta();
7265			var cutoutPercentage = opts.cutoutPercentage;
7266			var circumference = opts.circumference;
7267
7268			// If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
7269			if (circumference < Math.PI * 2.0) {
7270				var startAngle = opts.rotation % (Math.PI * 2.0);
7271				startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
7272				var endAngle = startAngle + circumference;
7273				var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
7274				var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
7275				var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
7276				var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
7277				var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
7278				var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
7279				var cutout = cutoutPercentage / 100.0;
7280				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))};
7281				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))};
7282				var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
7283				minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
7284				offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
7285			}
7286
7287			chart.borderWidth = me.getMaxBorderWidth(meta.data);
7288			chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
7289			chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
7290			chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
7291			chart.offsetX = offset.x * chart.outerRadius;
7292			chart.offsetY = offset.y * chart.outerRadius;
7293
7294			meta.total = me.calculateTotal();
7295
7296			me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
7297			me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);
7298
7299			helpers.each(meta.data, function(arc, index) {
7300				me.updateElement(arc, index, reset);
7301			});
7302		},
7303
7304		updateElement: function(arc, index, reset) {
7305			var me = this;
7306			var chart = me.chart;
7307			var chartArea = chart.chartArea;
7308			var opts = chart.options;
7309			var animationOpts = opts.animation;
7310			var centerX = (chartArea.left + chartArea.right) / 2;
7311			var centerY = (chartArea.top + chartArea.bottom) / 2;
7312			var startAngle = opts.rotation; // non reset case handled later
7313			var endAngle = opts.rotation; // non reset case handled later
7314			var dataset = me.getDataset();
7315			var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
7316			var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
7317			var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
7318			var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
7319
7320			helpers.extend(arc, {
7321				// Utility
7322				_datasetIndex: me.index,
7323				_index: index,
7324
7325				// Desired view properties
7326				_model: {
7327					x: centerX + chart.offsetX,
7328					y: centerY + chart.offsetY,
7329					startAngle: startAngle,
7330					endAngle: endAngle,
7331					circumference: circumference,
7332					outerRadius: outerRadius,
7333					innerRadius: innerRadius,
7334					label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
7335				}
7336			});
7337
7338			var model = arc._model;
7339			// Resets the visual styles
7340			this.removeHoverStyle(arc);
7341
7342			// Set correct angles if not resetting
7343			if (!reset || !animationOpts.animateRotate) {
7344				if (index === 0) {
7345					model.startAngle = opts.rotation;
7346				} else {
7347					model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
7348				}
7349
7350				model.endAngle = model.startAngle + model.circumference;
7351			}
7352
7353			arc.pivot();
7354		},
7355
7356		removeHoverStyle: function(arc) {
7357			Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
7358		},
7359
7360		calculateTotal: function() {
7361			var dataset = this.getDataset();
7362			var meta = this.getMeta();
7363			var total = 0;
7364			var value;
7365
7366			helpers.each(meta.data, function(element, index) {
7367				value = dataset.data[index];
7368				if (!isNaN(value) && !element.hidden) {
7369					total += Math.abs(value);
7370				}
7371			});
7372
7373			/* if (total === 0) {
7374				total = NaN;
7375			}*/
7376
7377			return total;
7378		},
7379
7380		calculateCircumference: function(value) {
7381			var total = this.getMeta().total;
7382			if (total > 0 && !isNaN(value)) {
7383				return (Math.PI * 2.0) * (Math.abs(value) / total);
7384			}
7385			return 0;
7386		},
7387
7388		// gets the max border or hover width to properly scale pie charts
7389		getMaxBorderWidth: function(arcs) {
7390			var max = 0;
7391			var index = this.index;
7392			var length = arcs.length;
7393			var borderWidth;
7394			var hoverWidth;
7395
7396			for (var i = 0; i < length; i++) {
7397				borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0;
7398				hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;
7399
7400				max = borderWidth > max ? borderWidth : max;
7401				max = hoverWidth > max ? hoverWidth : max;
7402			}
7403			return max;
7404		}
7405	});
7406};
7407
7408},{"25":25,"40":40,"45":45}],18:[function(require,module,exports){
7409'use strict';
7410
7411var defaults = require(25);
7412var elements = require(40);
7413var helpers = require(45);
7414
7415defaults._set('line', {
7416	showLines: true,
7417	spanGaps: false,
7418
7419	hover: {
7420		mode: 'label'
7421	},
7422
7423	scales: {
7424		xAxes: [{
7425			type: 'category',
7426			id: 'x-axis-0'
7427		}],
7428		yAxes: [{
7429			type: 'linear',
7430			id: 'y-axis-0'
7431		}]
7432	}
7433});
7434
7435module.exports = function(Chart) {
7436
7437	function lineEnabled(dataset, options) {
7438		return helpers.valueOrDefault(dataset.showLine, options.showLines);
7439	}
7440
7441	Chart.controllers.line = Chart.DatasetController.extend({
7442
7443		datasetElementType: elements.Line,
7444
7445		dataElementType: elements.Point,
7446
7447		update: function(reset) {
7448			var me = this;
7449			var meta = me.getMeta();
7450			var line = meta.dataset;
7451			var points = meta.data || [];
7452			var options = me.chart.options;
7453			var lineElementOptions = options.elements.line;
7454			var scale = me.getScaleForId(meta.yAxisID);
7455			var i, ilen, custom;
7456			var dataset = me.getDataset();
7457			var showLine = lineEnabled(dataset, options);
7458
7459			// Update Line
7460			if (showLine) {
7461				custom = line.custom || {};
7462
7463				// Compatibility: If the properties are defined with only the old name, use those values
7464				if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
7465					dataset.lineTension = dataset.tension;
7466				}
7467
7468				// Utility
7469				line._scale = scale;
7470				line._datasetIndex = me.index;
7471				// Data
7472				line._children = points;
7473				// Model
7474				line._model = {
7475					// Appearance
7476					// The default behavior of lines is to break at null values, according
7477					// to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
7478					// This option gives lines the ability to span gaps
7479					spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps,
7480					tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
7481					backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
7482					borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
7483					borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
7484					borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
7485					borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
7486					borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
7487					borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
7488					fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
7489					steppedLine: custom.steppedLine ? custom.steppedLine : helpers.valueOrDefault(dataset.steppedLine, lineElementOptions.stepped),
7490					cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.valueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode),
7491				};
7492
7493				line.pivot();
7494			}
7495
7496			// Update Points
7497			for (i = 0, ilen = points.length; i < ilen; ++i) {
7498				me.updateElement(points[i], i, reset);
7499			}
7500
7501			if (showLine && line._model.tension !== 0) {
7502				me.updateBezierControlPoints();
7503			}
7504
7505			// Now pivot the point for animation
7506			for (i = 0, ilen = points.length; i < ilen; ++i) {
7507				points[i].pivot();
7508			}
7509		},
7510
7511		getPointBackgroundColor: function(point, index) {
7512			var backgroundColor = this.chart.options.elements.point.backgroundColor;
7513			var dataset = this.getDataset();
7514			var custom = point.custom || {};
7515
7516			if (custom.backgroundColor) {
7517				backgroundColor = custom.backgroundColor;
7518			}
7518 else if (dataset.pointBackgroundColor) {
7519				backgroundColor = helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
7520			} else if (dataset.backgroundColor) {
7521				backgroundColor = dataset.backgroundColor;
7522			}
7523
7524			return backgroundColor;
7525		},
7526
7527		getPointBorderColor: function(point, index) {
7528			var borderColor = this.chart.options.elements.point.borderColor;
7529			var dataset = this.getDataset();
7530			var custom = point.custom || {};
7531
7532			if (custom.borderColor) {
7533				borderColor = custom.borderColor;
7534			} else if (dataset.pointBorderColor) {
7535				borderColor = helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
7536			} else if (dataset.borderColor) {
7537				borderColor = dataset.borderColor;
7538			}
7539
7540			return borderColor;
7541		},
7542
7543		getPointBorderWidth: function(point, index) {
7544			var borderWidth = this.chart.options.elements.point.borderWidth;
7545			var dataset = this.getDataset();
7546			var custom = point.custom || {};
7547
7548			if (!isNaN(custom.borderWidth)) {
7549				borderWidth = custom.borderWidth;
7550			} else if (!isNaN(dataset.pointBorderWidth) || helpers.isArray(dataset.pointBorderWidth)) {
7551				borderWidth = helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
7552			} else if (!isNaN(dataset.borderWidth)) {
7553				borderWidth = dataset.borderWidth;
7554			}
7555
7556			return borderWidth;
7557		},
7558
7559		updateElement: function(point, index, reset) {
7560			var me = this;
7561			var meta = me.getMeta();
7562			var custom = point.custom || {};
7563			var dataset = me.getDataset();
7564			var datasetIndex = me.index;
7565			var value = dataset.data[index];
7566			var yScale = me.getScaleForId(meta.yAxisID);
7567			var xScale = me.getScaleForId(meta.xAxisID);
7568			var pointOptions = me.chart.options.elements.point;
7569			var x, y;
7570
7571			// Compatibility: If the properties are defined with only the old name, use those values
7572			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
7573				dataset.pointRadius = dataset.radius;
7574			}
7575			if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
7576				dataset.pointHitRadius = dataset.hitRadius;
7577			}
7578
7579			x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
7580			y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
7581
7582			// Utility
7583			point._xScale = xScale;
7584			point._yScale = yScale;
7585			point._datasetIndex = datasetIndex;
7586			point._index = index;
7587
7588			// Desired view properties
7589			point._model = {
7590				x: x,
7591				y: y,
7592				skip: custom.skip || isNaN(x) || isNaN(y),
7593				// Appearance
7594				radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
7595				pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
7596				backgroundColor: me.getPointBackgroundColor(point, index),
7597				borderColor: me.getPointBorderColor(point, index),
7598				borderWidth: me.getPointBorderWidth(point, index),
7599				tension: meta.dataset._model ? meta.dataset._model.tension : 0,
7600				steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false,
7601				// Tooltip
7602				hitRadius: custom.hitRadius || helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
7603			};
7604		},
7605
7606		calculatePointY: function(value, index, datasetIndex) {
7607			var me = this;
7608			var chart = me.chart;
7609			var meta = me.getMeta();
7610			var yScale = me.getScaleForId(meta.yAxisID);
7611			var sumPos = 0;
7612			var sumNeg = 0;
7613			var i, ds, dsMeta;
7614
7615			if (yScale.options.stacked) {
7616				for (i = 0; i < datasetIndex; i++) {
7617					ds = chart.data.datasets[i];
7618					dsMeta = chart.getDatasetMeta(i);
7619					if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
7620						var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
7621						if (stackedRightValue < 0) {
7622							sumNeg += stackedRightValue || 0;
7623						} else {
7624							sumPos += stackedRightValue || 0;
7625						}
7626					}
7627				}
7628
7629				var rightValue = Number(yScale.getRightValue(value));
7630				if (rightValue < 0) {
7631					return yScale.getPixelForValue(sumNeg + rightValue);
7632				}
7633				return yScale.getPixelForValue(sumPos + rightValue);
7634			}
7635
7636			return yScale.getPixelForValue(value);
7637		},
7638
7639		updateBezierControlPoints: function() {
7640			var me = this;
7641			var meta = me.getMeta();
7642			var area = me.chart.chartArea;
7643			var points = (meta.data || []);
7644			var i, ilen, point, model, controlPoints;
7645
7646			// Only consider points that are drawn in case the spanGaps option is used
7647			if (meta.dataset._model.spanGaps) {
7648				points = points.filter(function(pt) {
7649					return !pt._model.skip;
7650				});
7651			}
7652
7653			function capControlPoint(pt, min, max) {
7654				return Math.max(Math.min(pt, max), min);
7655			}
7656
7657			if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
7658				helpers.splineCurveMonotone(points);
7659			} else {
7660				for (i = 0, ilen = points.length; i < ilen; ++i) {
7661					point = points[i];
7662					model = point._model;
7663					controlPoints = helpers.splineCurve(
7664						helpers.previousItem(points, i)._model,
7665						model,
7666						helpers.nextItem(points, i)._model,
7667						meta.dataset._model.tension
7668					);
7669					model.controlPointPreviousX = controlPoints.previous.x;
7670					model.controlPointPreviousY = controlPoints.previous.y;
7671					model.controlPointNextX = controlPoints.next.x;
7672					model.controlPointNextY = controlPoints.next.y;
7673				}
7674			}
7675
7676			if (me.chart.options.elements.line.capBezierPoints) {
7677				for (i = 0, ilen = points.length; i < ilen; ++i) {
7678					model = points[i]._model;
7679					model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
7680					model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
7681					model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
7682					model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
7683				}
7684			}
7685		},
7686
7687		draw: function() {
7688			var me = this;
7689			var chart = me.chart;
7690			var meta = me.getMeta();
7691			var points = meta.data || [];
7692			var area = chart.chartArea;
7693			var ilen = points.length;
7694			var i = 0;
7695
7696			helpers.canvas.clipArea(chart.ctx, area);
7697
7698			if (lineEnabled(me.getDataset(), chart.options)) {
7699				meta.dataset.draw();
7700			}
7701
7702			helpers.canvas.unclipArea(chart.ctx);
7703
7704			// Draw the points
7705			for (; i < ilen; ++i) {
7706				points[i].draw(area);
7707			}
7708		},
7709
7710		setHoverStyle: function(point) {
7711			// Point
7712			var dataset = this.chart.data.datasets[point._datasetIndex];
7713			var index = point._index;
7714			var custom = point.custom || {};
7715			var model = point._model;
7716
7717			model.radius = custom.hoverRadius || helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
7718			model.backgroundColor = custom.hoverBackgroundColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
7719			model.borderColor = custom.hoverBorderColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
7720			model.borderWidth = custom.hoverBorderWidth || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
7721		},
7722
7723		removeHoverStyle: function(point) {
7724			var me = this;
7725			var dataset = me.chart.data.datasets[point._datasetIndex];
7726			var index = point._index;
7727			var custom = point.custom || {};
7728			var model = point._model;
7729
7730			// Compatibility: If the properties are defined with only the old name, use those values
7731			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
7732				dataset.pointRadius = dataset.radius;
7733			}
7734
7735			model.radius = custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius);
7736			model.backgroundColor = me.getPointBackgroundColor(point, index);
7737			model.borderColor = me.getPointBorderColor(point, index);
7738			model.borderWidth = me.getPointBorderWidth(point, index);
7739		}
7740	});
7741};
7742
7743},{"25":25,"40":40,"45":45}],19:[function(require,module,exports){
7744'use strict';
7745
7746var defaults = require(25);
7747var elements = require(40);
7748var helpers = require(45);
7749
7750defaults._set('polarArea', {
7751	scale: {
7752		type: 'radialLinear',
7753		angleLines: {
7754			display: false
7755		},
7756		gridLines: {
7757			circular: true
7758		},
7759		pointLabels: {
7760			display: false
7761		},
7762		ticks: {
7763			beginAtZero: true
7764		}
7765	},
7766
7767	// Boolean - Whether to animate the rotation of the chart
7768	animation: {
7769		animateRotate: true,
7770		animateScale: true
7771	},
7772
7773	startAngle: -0.5 * Math.PI,
7774	legendCallback: function(chart) {
7775		var text = [];
7776		text.push('<ul class="' + chart.id + '-legend">');
7777
7778		var data = chart.data;
7779		var datasets = data.datasets;
7780		var labels = data.labels;
7781
7782		if (datasets.length) {
7783			for (var i = 0; i < datasets[0].data.length; ++i) {
7784				text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
7785				if (labels[i]) {
7786					text.push(labels[i]);
7787				}
7788				text.push('</li>');
7789			}
7790		}
7791
7792		text.push('</ul>');
7793		return text.join('');
7794	},
7795	legend: {
7796		labels: {
7797			generateLabels: function(chart) {
7798				var data = chart.data;
7799				if (data.labels.length && data.datasets.length) {
7800					return data.labels.map(function(label, i) {
7801						var meta = chart.getDatasetMeta(0);
7802						var ds = data.datasets[0];
7803						var arc = meta.data[i];
7804						var custom = arc.custom || {};
7805						var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
7806						var arcOpts = chart.options.elements.arc;
7807						var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
7808						var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
7809						var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
7810
7811						return {
7812							text: label,
7813							fillStyle: fill,
7814							strokeStyle: stroke,
7815							lineWidth: bw,
7816							hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
7817
7818							// Extra data used for toggling the correct item
7819							index: i
7820						};
7821					});
7822				}
7823				return [];
7824			}
7825		},
7826
7827		onClick: function(e, legendItem) {
7828			var index = legendItem.index;
7829			var chart = this.chart;
7830			var i, ilen, meta;
7831
7832			for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
7833				meta = chart.getDatasetMeta(i);
7834				meta.data[index].hidden = !meta.data[index].hidden;
7835			}
7836
7837			chart.update();
7838		}
7839	},
7840
7841	// Need to override these to give a nice default
7842	tooltips: {
7843		callbacks: {
7844			title: function() {
7845				return '';
7846			},
7847			label: function(item, data) {
7848				return data.labels[item.index] + ': ' + item.yLabel;
7849			}
7850		}
7851	}
7852});
7853
7854module.exports = function(Chart) {
7855
7856	Chart.controllers.polarArea = Chart.DatasetController.extend({
7857
7858		dataElementType: elements.Arc,
7859
7860		linkScales: helpers.noop,
7861
7862		update: function(reset) {
7863			var me = this;
7864			var chart = me.chart;
7865			var chartArea = chart.chartArea;
7866			var meta = me.getMeta();
7867			var opts = chart.options;
7868			var arcOpts = opts.elements.arc;
7869			var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
7870			chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
7871			chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
7872			chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
7873
7874			me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
7875			me.innerRadius = me.outerRadius - chart.radiusLength;
7876
7877			meta.count = me.countVisibleElements();
7878
7879			helpers.each(meta.data, function(arc, index) {
7880				me.updateElement(arc, index, reset);
7881			});
7882		},
7883
7884		updateElement: function(arc, index, reset) {
7885			var me = this;
7886			var chart = me.chart;
7887			var dataset = me.getDataset();
7888			var opts = chart.options;
7889			var animationOpts = opts.animation;
7890			var scale = chart.scale;
7891			var labels = chart.data.labels;
7892
7893			var circumference = me.calculateCircumference(dataset.data[index]);
7894			var centerX = scale.xCenter;
7895			var centerY = scale.yCenter;
7896
7897			// If there is NaN data before us, we need to calculate the starting angle correctly.
7898			// We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
7899			var visibleCount = 0;
7900			var meta = me.getMeta();
7901			for (var i = 0; i < index; ++i) {
7902				if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
7903					++visibleCount;
7904				}
7905			}
7906
7907			// var negHalfPI = -0.5 * Math.PI;
7908			var datasetStartAngle = opts.startAngle;
7909			var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
7910			var startAngle = datasetStartAngle + (circumference * visibleCount);
7911			var endAngle = startAngle + (arc.hidden ? 0 : circumference);
7912
7913			var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
7914
7915			helpers.extend(arc, {
7916				// Utility
7917				_datasetIndex: me.index,
7918				_index: index,
7919				_scale: scale,
7920
7921				// Desired view properties
7922				_model: {
7923					x: centerX,
7924					y: centerY,
7925					innerRadius: 0,
7926					outerRadius: reset ? resetRadius : distance,
7927					startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
7928					endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
7929					label: helpers.valueAtIndexOrDefault(labels, index, labels[index])
7930				}
7931			});
7932
7933			// Apply border and fill style
7934			me.removeHoverStyle(arc);
7935
7936			arc.pivot();
7937		},
7938
7939		removeHoverStyle: function(arc) {
7940			Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
7941		},
7942
7943		countVisibleElements: function() {
7944			var dataset = this.getDataset();
7945			var meta = this.getMeta();
7946			var count = 0;
7947
7948			helpers.each(meta.data, function(element, index) {
7949				if (!isNaN(dataset.data[index]) && !element.hidden) {
7950					count++;
7951				}
7952			});
7953
7954			return count;
7955		},
7956
7957		calculateCircumference: function(value) {
7958			var count = this.getMeta().count;
7959			if (count > 0 && !isNaN(value)) {
7960				return (2 * Math.PI) / count;
7961			}
7962			return 0;
7963		}
7964	});
7965};
7966
7967},{"25":25,"40":40,"45":45}],20:[function(require,module,exports){
7968'use strict';
7969
7970var defaults = require(25);
7971var elements = require(40);
7972var helpers = require(45);
7973
7974defaults._set('radar', {
7975	scale: {
7976		type: 'radialLinear'
7977	},
7978	elements: {
7979		line: {
7980			tension: 0 // no bezier in radar
7981		}
7982	}
7983});
7984
7985module.exports = function(Chart) {
7986
7987	Chart.controllers.radar = Chart.DatasetController.extend({
7988
7989		datasetElementType: elements.Line,
7990
7991		dataElementType: elements.Point,
7992
7993		linkScales: helpers.noop,
7994
7995		update: function(reset) {
7996			var me = this;
7997			var meta = me.getMeta();
7998			var line = meta.dataset;
7999			var points = meta.data;
8000			var custom = line.custom || {};
8001			var dataset = me.getDataset();
8002			var lineElementOptions = me.chart.options.elements.line;
8003			var scale = me.chart.scale;
8004
8005			// Compatibility: If the properties are defined with only the old name, use those values
8006			if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
8007				dataset.lineTension = dataset.tension;
8008			}
8009
8010			helpers.extend(meta.dataset, {
8011				// Utility
8012				_datasetIndex: me.index,
8013				_scale: scale,
8014				// Data
8015				_children: points,
8016				_loop: true,
8017				// Model
8018				_model: {
8019					// Appearance
8020					tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
8021					backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
8022					borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
8023					borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
8024					fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
8025					borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
8026					borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
8027					borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
8028					borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
8029				}
8030			});
8031
8032			meta.dataset.pivot();
8033
8034			// Update Points
8035			helpers.each(points, function(point, index) {
8036				me.updateElement(point, index, reset);
8037			}, me);
8038
8039			// Update bezier control points
8040			me.updateBezierControlPoints();
8041		},
8042		updateElement: function(point, index, reset) {
8043			var me = this;
8044			var custom = point.custom || {};
8045			var dataset = me.getDataset();
8046			var scale = me.chart.scale;
8047			var pointElementOptions = me.chart.options.elements.point;
8048			var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
8049
8050			// Compatibility: If the properties are defined with only the old name, use those values
8051			if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
8052				dataset.pointRadius = dataset.radius;
8053			}
8054			if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
8055				dataset.pointHitRadius = dataset.hitRadius;
8056			}
8057
8058			helpers.extend(point, {
8059				// Utility
8060				_datasetIndex: me.index,
8061				_index: index,
8062				_scale: scale,
8063
8064				// Desired view properties
8065				_model: {
8066					x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
8067					y: reset ? scale.yCenter : pointPosition.y,
8068
8069					// Appearance
8070					tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
8071					radius: custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
8072					backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroun
8072dColor, index, pointElementOptions.backgroundColor),
8073					borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
8074					borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
8075					pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),
8076
8077					// Tooltip
8078					hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius)
8079				}
8080			});
8081
8082			point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
8083		},
8084		updateBezierControlPoints: function() {
8085			var chartArea = this.chart.chartArea;
8086			var meta = this.getMeta();
8087
8088			helpers.each(meta.data, function(point, index) {
8089				var model = point._model;
8090				var controlPoints = helpers.splineCurve(
8091					helpers.previousItem(meta.data, index, true)._model,
8092					model,
8093					helpers.nextItem(meta.data, index, true)._model,
8094					model.tension
8095				);
8096
8097				// Prevent the bezier going outside of the bounds of the graph
8098				model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left);
8099				model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top);
8100
8101				model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left);
8102				model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top);
8103
8104				// Now pivot the point for animation
8105				point.pivot();
8106			});
8107		},
8108
8109		setHoverStyle: function(point) {
8110			// Point
8111			var dataset = this.chart.data.datasets[point._datasetIndex];
8112			var custom = point.custom || {};
8113			var index = point._index;
8114			var model = point._model;
8115
8116			model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
8117			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
8118			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
8119			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
8120		},
8121
8122		removeHoverStyle: function(point) {
8123			var dataset = this.chart.data.datasets[point._datasetIndex];
8124			var custom = point.custom || {};
8125			var index = point._index;
8126			var model = point._model;
8127			var pointElementOptions = this.chart.options.elements.point;
8128
8129			model.radius = custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius);
8130			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroun
8130dColor, index, pointElementOptions.backgroundColor);
8131			model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor);
8132			model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth);
8133		}
8134	});
8135};
8136
8137},{"25":25,"40":40,"45":45}],21:[function(require,module,exports){
8138'use strict';
8139
8140var defaults = require(25);
8141
8142defaults._set('scatter', {
8143	hover: {
8144		mode: 'single'
8145	},
8146
8147	scales: {
8148		xAxes: [{
8149			id: 'x-axis-1',    // need an ID so datasets can reference the scale
8150			type: 'linear',    // scatter should not use a category axis
8151			position: 'bottom'
8152		}],
8153		yAxes: [{
8154			id: 'y-axis-1',
8155			type: 'linear',
8156			position: 'left'
8157		}]
8158	},
8159
8160	showLines: false,
8161
8162	tooltips: {
8163		callbacks: {
8164			title: function() {
8165				return '';     // doesn't make sense for scatter since data are formatted as a point
8166			},
8167			label: function(item) {
8168				return '(' + item.xLabel + ', ' + item.yLabel + ')';
8169			}
8170		}
8171	}
8172});
8173
8174module.exports = function(Chart) {
8175
8176	// Scatter charts use line controllers
8177	Chart.controllers.scatter = Chart.controllers.line;
8178
8179};
8180
8181},{"25":25}],22:[function(require,module,exports){
8182/* global window: false */
8183'use strict';
8184
8185var defaults = require(25);
8186var Element = require(26);
8187var helpers = require(45);
8188
8189defaults._set('global', {
8190	animation: {
8191		duration: 1000,
8192		easing: 'easeOutQuart',
8193		onProgress: helpers.noop,
8194		onComplete: helpers.noop
8195	}
8196});
8197
8198module.exports = function(Chart) {
8199
8200	Chart.Animation = Element.extend({
8201		chart: null, // the animation associated chart instance
8202		currentStep: 0, // the current animation step
8203		numSteps: 60, // default number of steps
8204		easing: '', // the easing to use for this animation
8205		render: null, // render function used by the animation service
8206
8207		onAnimationProgress: null, // user specified callback to fire on each step of the animation
8208		onAnimationComplete: null, // user specified callback to fire when the animation finishes
8209	});
8210
8211	Chart.animationService = {
8212		frameDuration: 17,
8213		animations: [],
8214		dropFrames: 0,
8215		request: null,
8216
8217		/**
8218		 * @param {Chart} chart - The chart to animate.
8219		 * @param {Chart.Animation} animation - The animation that we will animate.
8220		 * @param {Number} duration - The animation duration in ms.
8221		 * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
8222		 */
8223		addAnimation: function(chart, animation, duration, lazy) {
8224			var animations = this.animations;
8225			var i, ilen;
8226
8227			animation.chart = chart;
8228
8229			if (!lazy) {
8230				chart.animating = true;
8231			}
8232
8233			for (i = 0, ilen = animations.length; i < ilen; ++i) {
8234				if (animations[i].chart === chart) {
8235					animations[i] = animation;
8236					return;
8237				}
8238			}
8239
8240			animations.push(animation);
8241
8242			// If there are no animations queued, manually kickstart a digest, for lack of a better word
8243			if (animations.length === 1) {
8244				this.requestAnimationFrame();
8245			}
8246		},
8247
8248		cancelAnimation: function(chart) {
8249			var index = helpers.findIndex(this.animations, function(animation) {
8250				return animation.chart === chart;
8251			});
8252
8253			if (index !== -1) {
8254				this.animations.splice(index, 1);
8255				chart.animating = false;
8256			}
8257		},
8258
8259		requestAnimationFrame: function() {
8260			var me = this;
8261			if (me.request === null) {
8262				// Skip animation frame requests until the active one is executed.
8263				// This can happen when processing mouse events, e.g. 'mousemove'
8264				// and 'mouseout' events will trigger multiple renders.
8265				me.request = helpers.requestAnimFrame.call(window, function() {
8266					me.request = null;
8267					me.startDigest();
8268				});
8269			}
8270		},
8271
8272		/**
8273		 * @private
8274		 */
8275		startDigest: function() {
8276			var me = this;
8277			var startTime = Date.now();
8278			var framesToDrop = 0;
8279
8280			if (me.dropFrames > 1) {
8281				framesToDrop = Math.floor(me.dropFrames);
8282				me.dropFrames = me.dropFrames % 1;
8283			}
8284
8285			me.advance(1 + framesToDrop);
8286
8287			var endTime = Date.now();
8288
8289			me.dropFrames += (endTime - startTime) / me.frameDuration;
8290
8291			// Do we have more stuff to animate?
8292			if (me.animations.length > 0) {
8293				me.requestAnimationFrame();
8294			}
8295		},
8296
8297		/**
8298		 * @private
8299		 */
8300		advance: function(count) {
8301			var animations = this.animations;
8302			var animation, chart;
8303			var i = 0;
8304
8305			while (i < animations.length) {
8306				animation = animations[i];
8307				chart = animation.chart;
8308
8309				animation.currentStep = (animation.currentStep || 0) + count;
8310				animation.currentStep = Math.min(animation.currentStep, animation.numSteps);
8311
8312				helpers.callback(animation.render, [chart, animation], chart);
8313				helpers.callback(animation.onAnimationProgress, [animation], chart);
8314
8315				if (animation.currentStep >= animation.numSteps) {
8316					helpers.callback(animation.onAnimationComplete, [animation], chart);
8317					chart.animating = false;
8318					animations.splice(i, 1);
8319				} else {
8320					++i;
8321				}
8322			}
8323		}
8324	};
8325
8326	/**
8327	 * Provided for backward compatibility, use Chart.Animation instead
8328	 * @prop Chart.Animation#animationObject
8329	 * @deprecated since version 2.6.0
8330	 * @todo remove at version 3
8331	 */
8332	Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
8333		get: function() {
8334			return this;
8335		}
8336	});
8337
8338	/**
8339	 * Provided for backward compatibility, use Chart.Animation#chart instead
8340	 * @prop Chart.Animation#chartInstance
8341	 * @deprecated since version 2.6.0
8342	 * @todo remove at version 3
8343	 */
8344	Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
8345		get: function() {
8346			return this.chart;
8347		},
8348		set: function(value) {
8349			this.chart = value;
8350		}
8351	});
8352
8353};
8354
8355},{"25":25,"26":26,"45":45}],23:[function(require,module,exports){
8356'use strict';
8357
8358var defaults = require(25);
8359var helpers = require(45);
8360var Interaction = require(28);
8361var layouts = require(30);
8362var platform = require(48);
8363var plugins = require(31);
8364
8365module.exports = function(Chart) {
8366
8367	// Create a dictionary of chart types, to allow for extension of existing types
8368	Chart.types = {};
8369
8370	// Store a reference to each instance - allowing us to globally resize chart instances on window resize.
8371	// Destroy method on the chart will remove the instance of the chart from this reference.
8372	Chart.instances = {};
8373
8374	// Controllers available for dataset visualization eg. bar, line, slice, etc.
8375	Chart.controllers = {};
8376
8377	/**
8378	 * Initializes the given config with global and chart default values.
8379	 */
8380	function initConfig(config) {
8381		config = config || {};
8382
8383		// Do NOT use configMerge() for the data object because this method merges arrays
vendor: 12,882 bytes, lines 8384-8846
8384		// and so would change references to labels and datasets, preventing data updates.
8385		var data = config.data = config.data || {};
8386		data.datasets = data.datasets || [];
8387		data.labels = data.labels || [];
8388
8389		config.options = helpers.configMerge(
8390			defaults.global,
8391			defaults[config.type],
8392			config.options || {});
8393
8394		return config;
8395	}
8396
8397	/**
8398	 * Updates the config of the chart
8399	 * @param chart {Chart} chart to update the options for
8400	 */
8401	function updateConfig(chart) {
8402		var newOptions = chart.options;
8403
8404		helpers.each(chart.scales, function(scale) {
8405			layouts.removeBox(chart, scale);
8406		});
8407
8408		newOptions = helpers.configMerge(
8409			Chart.defaults.global,
8410			Chart.defaults[chart.config.type],
8411			newOptions);
8412
8413		chart.options = chart.config.options = newOptions;
8414		chart.ensureScalesHaveIDs();
8415		chart.buildOrUpdateScales();
8416		// Tooltip
8417		chart.tooltip._options = newOptions.tooltips;
8418		chart.tooltip.initialize();
8419	}
8420
8421	function positionIsHorizontal(position) {
8422		return position === 'top' || position === 'bottom';
8423	}
8424
8425	helpers.extend(Chart.prototype, /** @lends Chart */ {
8426		/**
8427		 * @private
8428		 */
8429		construct: function(item, config) {
8430			var me = this;
8431
8432			config = initConfig(config);
8433
8434			var context = platform.acquireContext(item, config);
8435			var canvas = context && context.canvas;
8436			var height = canvas && canvas.height;
8437			var width = canvas && canvas.width;
8438
8439			me.id = helpers.uid();
8440			me.ctx = context;
8441			me.canvas = canvas;
8442			me.config = config;
8443			me.width = width;
8444			me.height = height;
8445			me.aspectRatio = height ? width / height : null;
8446			me.options = config.options;
8447			me._bufferedRender = false;
8448
8449			/**
8450			 * Provided for backward compatibility, Chart and Chart.Controller have been merged,
8451			 * the "instance" still need to be defined since it might be called from plugins.
8452			 * @prop Chart#chart
8453			 * @deprecated since version 2.6.0
8454			 * @todo remove at version 3
8455			 * @private
8456			 */
8457			me.chart = me;
8458			me.controller = me; // chart.chart.controller #inception
8459
8460			// Add the chart instance to the global namespace
8461			Chart.instances[me.id] = me;
8462
8463			// Define alias to the config data: `chart.data === chart.config.data`
8464			Object.defineProperty(me, 'data', {
8465				get: function() {
8466					return me.config.data;
8467				},
8468				set: function(value) {
8469					me.config.data = value;
8470				}
8471			});
8472
8473			if (!context || !canvas) {
8474				// The given item is not a compatible context2d element, let's return before finalizing
8475				// the chart initialization but after setting basic chart / controller properties that
8476				// can help to figure out that the chart is not valid (e.g chart.canvas !== null);
8477				// https://github.com/chartjs/Chart.js/issues/2807
8478				console.error("Failed to create chart: can't acquire context from the given item");
8479				return;
8480			}
8481
8482			me.initialize();
8483			me.update();
8484		},
8485
8486		/**
8487		 * @private
8488		 */
8489		initialize: function() {
8490			var me = this;
8491
8492			// Before init plugin notification
8493			plugins.notify(me, 'beforeInit');
8494
8495			helpers.retinaScale(me, me.options.devicePixelRatio);
8496
8497			me.bindEvents();
8498
8499			if (me.options.responsive) {
8500				// Initial resize before chart draws (must be silent to preserve initial animations).
8501				me.resize(true);
8502			}
8503
8504			// Make sure scales have IDs and are built before we build any controllers.
8505			me.ensureScalesHaveIDs();
8506			me.buildOrUpdateScales();
8507			me.initToolTip();
8508
8509			// After init plugin notification
8510			plugins.notify(me, 'afterInit');
8511
8512			return me;
8513		},
8514
8515		clear: function() {
8516			helpers.canvas.clear(this);
8517			return this;
8518		},
8519
8520		stop: function() {
8521			// Stops any current animation loop occurring
8522			Chart.animationService.cancelAnimation(this);
8523			return this;
8524		},
8525
8526		resize: function(silent) {
8527			var me = this;
8528			var options = me.options;
8529			var canvas = me.canvas;
8530			var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;
8531
8532			// the canvas render width and height will be casted to integers so make sure that
8533			// the canvas display style uses the same integer values to avoid blurring effect.
8534
8535			// Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collased
8536			var newWidth = Math.max(0, Math.floor(helpers.getMaximumWidth(canvas)));
8537			var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas)));
8538
8539			if (me.width === newWidth && me.height === newHeight) {
8540				return;
8541			}
8542
8543			canvas.width = me.width = newWidth;
8544			canvas.height = me.height = newHeight;
8545			canvas.style.width = newWidth + 'px';
8546			canvas.style.height = newHeight + 'px';
8547
8548			helpers.retinaScale(me, options.devicePixelRatio);
8549
8550			if (!silent) {
8551				// Notify any plugins about the resize
8552				var newSize = {width: newWidth, height: newHeight};
8553				plugins.notify(me, 'resize', [newSize]);
8554
8555				// Notify of resize
8556				if (me.options.onResize) {
8557					me.options.onResize(me, newSize);
8558				}
8559
8560				me.stop();
8561				me.update(me.options.responsiveAnimationDuration);
8562			}
8563		},
8564
8565		ensureScalesHaveIDs: function() {
8566			var options = this.options;
8567			var scalesOptions = options.scales || {};
8568			var scaleOptions = options.scale;
8569
8570			helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) {
8571				xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
8572			});
8573
8574			helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) {
8575				yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
8576			});
8577
8578			if (scaleOptions) {
8579				scaleOptions.id = scaleOptions.id || 'scale';
8580			}
8581		},
8582
8583		/**
8584		 * Builds a map of scale ID to scale object for future lookup.
8585		 */
8586		buildOrUpdateScales: function() {
8587			var me = this;
8588			var options = me.options;
8589			var scales = me.scales || {};
8590			var items = [];
8591			var updated = Object.keys(scales).reduce(function(obj, id) {
8592				obj[id] = false;
8593				return obj;
8594			}, {});
8595
8596			if (options.scales) {
8597				items = items.concat(
8598					(options.scales.xAxes || []).map(function(xAxisOptions) {
8599						return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
8600					}),
8601					(options.scales.yAxes || []).map(function(yAxisOptions) {
8602						return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
8603					})
8604				);
8605			}
8606
8607			if (options.scale) {
8608				items.push({
8609					options: options.scale,
8610					dtype: 'radialLinear',
8611					isDefault: true,
8612					dposition: 'chartArea'
8613				});
8614			}
8615
8616			helpers.each(items, function(item) {
8617				var scaleOptions = item.options;
8618				var id = scaleOptions.id;
8619				var scaleType = helpers.valueOrDefault(scaleOptions.type, item.dtype);
8620
8621				if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
8622					scaleOptions.position = item.dposition;
8623				}
8624
8625				updated[id] = true;
8626				var scale = null;
8627				if (id in scales && scales[id].type === scaleType) {
8628					scale = scales[id];
8629					scale.options = scaleOptions;
8630					scale.ctx = me.ctx;
8631					scale.chart = me;
8632				} else {
8633					var scaleClass = Chart.scaleService.getScaleConstructor(scaleType);
8634					if (!scaleClass) {
8635						return;
8636					}
8637					scale = new scaleClass({
8638						id: id,
8639						type: scaleType,
8640						options: scaleOptions,
8641						ctx: me.ctx,
8642						chart: me
8643					});
8644					scales[scale.id] = scale;
8645				}
8646
8647				scale.mergeTicksOptions();
8648
8649				// TODO(SB): I think we should be able to remove this custom case (options.scale)
8650				// and consider it as a regular scale part of the "scales"" map only! This would
8651				// make the logic easier and remove some useless? custom code.
8652				if (item.isDefault) {
8653					me.scale = scale;
8654				}
8655			});
8656			// clear up discarded scales
8657			helpers.each(updated, function(hasUpdated, id) {
8658				if (!hasUpdated) {
8659					delete scales[id];
8660				}
8661			});
8662
8663			me.scales = scales;
8664
8665			Chart.scaleService.addScalesToLayout(this);
8666		},
8667
8668		buildOrUpdateControllers: function() {
8669			var me = this;
8670			var types = [];
8671			var newControllers = [];
8672
8673			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
8674				var meta = me.getDatasetMeta(datasetIndex);
8675				var type = dataset.type || me.config.type;
8676
8677				if (meta.type && meta.type !== type) {
8678					me.destroyDatasetMeta(datasetIndex);
8679					meta = me.getDatasetMeta(datasetIndex);
8680				}
8681				meta.type = type;
8682
8683				types.push(meta.type);
8684
8685				if (meta.controller) {
8686					meta.controller.updateIndex(datasetIndex);
8687					meta.controller.linkScales();
8688				} else {
8689					var ControllerClass = Chart.controllers[meta.type];
8690					if (ControllerClass === undefined) {
8691						throw new Error('"' + meta.type + '" is not a chart type.');
8692					}
8693
8694					meta.controller = new ControllerClass(me, datasetIndex);
8695					newControllers.push(meta.controller);
8696				}
8697			}, me);
8698
8699			return newControllers;
8700		},
8701
8702		/**
8703		 * Reset the elements of all datasets
8704		 * @private
8705		 */
8706		resetElements: function() {
8707			var me = this;
8708			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
8709				me.getDatasetMeta(datasetIndex).controller.reset();
8710			}, me);
8711		},
8712
8713		/**
8714		* Resets the chart back to it's state before the initial animation
8715		*/
8716		reset: function() {
8717			this.resetElements();
8718			this.tooltip.initialize();
8719		},
8720
8721		update: function(config) {
8722			var me = this;
8723
8724			if (!config || typeof config !== 'object') {
8725				// backwards compatibility
8726				config = {
8727					duration: config,
8728					lazy: arguments[1]
8729				};
8730			}
8731
8732			updateConfig(me);
8733
8734			// plugins options references might have change, let's invalidate the cache
8735			// https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
8736			plugins._invalidate(me);
8737
8738			if (plugins.notify(me, 'beforeUpdate') === false) {
8739				return;
8740			}
8741
8742			// In case the entire data object changed
8743			me.tooltip._data = me.data;
8744
8745			// Make sure dataset controllers are updated and new controllers are reset
8746			var newControllers = me.buildOrUpdateControllers();
8747
8748			// Make sure all dataset controllers have correct meta data counts
8749			helpers.each(me.data.datasets, function(dataset, datasetIndex) {
8750				me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
8751			}, me);
8752
8753			me.updateLayout();
8754
8755			// Can only reset the new controllers after the scales have been updated
8756			if (me.options.animation && me.options.animation.duration) {
8757				helpers.each(newControllers, function(controller) {
8758					controller.reset();
8759				});
8760			}
8761
8762			me.updateDatasets();
8763
8764			// Need to reset tooltip in case it is displayed with elements that are removed
8765			// after update.
8766			me.tooltip.initialize();
8767
8768			// Last active contains items that were previously in the tooltip.
8769			// When we reset the tooltip, we need to clear it
8770			me.lastActive = [];
8771
8772			// Do this before render so that any plugins that need final scale updates can use it
8773			plugins.notify(me, 'afterUpdate');
8774
8775			if (me._bufferedRender) {
8776				me._bufferedRequest = {
8777					duration: config.duration,
8778					easing: config.easing,
8779					lazy: config.lazy
8780				};
8781			} else {
8782				me.render(config);
8783			}
8784		},
8785
8786		/**
8787		 * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
8788		 * hook, in which case, plugins will not be called on `afterLayout`.
8789		 * @private
8790		 */
8791		updateLayout: function() {
8792			var me = this;
8793
8794			if (plugins.notify(me, 'beforeLayout') === false) {
8795				return;
8796			}
8797
8798			layouts.update(this, this.width, this.height);
8799
8800			/**
8801			 * Provided for backward compatibility, use `afterLayout` instead.
8802			 * @method IPlugin#afterScaleUpdate
8803			 * @deprecated since version 2.5.0
8804			 * @todo remove at version 3
8805			 * @private
8806			 */
8807			plugins.notify(me, 'afterScaleUpdate');
8808			plugins.notify(me, 'afterLayout');
8809		},
8810
8811		/**
8812		 * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
8813		 * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
8814		 * @private
8815		 */
8816		updateDatasets: function() {
8817			var me = this;
8818
8819			if (plugins.notify(me, 'beforeDatasetsUpdate') === false) {
8820				return;
8821			}
8822
8823			for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
8824				me.updateDataset(i);
8825			}
8826
8827			plugins.notify(me, 'afterDatasetsUpdate');
8828		},
8829
8830		/**
8831		 * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
8832		 * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
8833		 * @private
8834		 */
8835		updateDataset: function(index) {
8836			var me = this;
8837			var meta = me.getDatasetMeta(index);
8838			var args = {
8839				meta: meta,
8840				index: index
8841			};
8842
8843			if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
8844				return;
8845			}
8846
8847			meta.controller.update();
8848
8849			plugins.notify(me, 'afterDatasetUpdate', [args]);
8850		},
8851
8852		render: function(config) {
8853			var me = this;
8854
8855			if (!config || typeof config !== 'object') {
8856				// backwards compatibility
8857				config = {
8858					duration: config,
8859					lazy: arguments[1]
8860				};
8861			}
8862
8863			var duration = config.duration;
8864			var lazy = config.lazy;
8865
8866			if (plugins.notify(me, 'beforeRender') === false) {
8867				return;
8868			}
8869
8870			var animationOptions = me.options.animation;
8871			var onComplete = function(animation) {
8872				plugins.notify(me, 'afterRender');
8873				helpers.callback(animationOptions && animationOptions.onComplete, [animation], me);
8874			};
8875
8876			if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
8877				var animation = new Chart.Animation({
8878					numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
8879					easing: config.easing || animationOptions.easing,
8880
8881					render: function(chart, animationObject) {
8882						var easingFunction = helpers.easing.effects[animationObject.easing];
8883						var currentStep = animationObject.currentStep;
8884						var stepDecimal = currentStep / animationObject.numSteps;
8885
8886						chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
8887					},
8888
8889					onAnimationProgress: animationOptions.onProgress,
8890					onAnimationComplete: onComplete
8891				});
8892
8893				Chart.animationService.addAnimation(me, animation, duration, lazy);
8894			} else {
8895				me.draw();
8896
8897				// See https://github.com/chartjs/Chart.js/issues/3781
8898				onComplete(new Chart.Animation({numSteps: 0, chart: me}));
8899			}
8900
8901			return me;
8902		},
8903
8904		draw: function(easingValue) {
8905			var me = this;
8906
8907			me.clear();
8908
8909			if (helpers.isNullOrUndef(easingValue)) {
8910				easingValue = 1;
8911			}
8912
8913			me.transition(easingValue);
8914
8915			if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
8916				return;
8917			}
8918
8919			// Draw all the scales
8920			helpers.each(me.boxes, function(box) {
8921				box.draw(me.chartArea);
8922			}, me);
8923
8924			if (me.scale) {
8925				me.scale.draw();
8926			}
8927
8928			me.drawDatasets(easingValue);
8929			me._drawTooltip(easingValue);
8930
8931			plugins.notify(me, 'afterDraw', [easingValue]);
8932		},
8933
8934		/**
8935		 * @private
8936		 */
8937		transition: function(easingValue) {
8938			var me = this;
8939
8940			for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {
8941				if (me.isDatasetVisible(i)) {
8942					me.getDatasetMeta(i).controller.transition(easingValue);
8943				}
8944			}
8945
8946			me.tooltip.transition(easingValue);
8947		},
8948
8949		/**
8950		 * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
8951		 * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
8952		 * @private
8953		 */
8954		drawDatasets: function(easingValue) {
8955			var me = this;
8956
8957			if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
8958				return;
8959			}
8960
8961			// Draw datasets reversed to support proper line stacking
8962			for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) {
8963				if (me.isDatasetVisible(i)) {
8964					me.drawDataset(i, easingValue);
8965				}
8966			}
8967
8968			plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
8969		},
8970
8971		/**
8972		 * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
8973		 * hook, in which case, plugins will not be called on `afterDatasetDraw`.
8974		 * @private
8975		 */
8976		drawDataset: function(index, easingValue) {
8977			var me = this;
8978			var meta = me.getDatasetMeta(index);
8979			var args = {
8980				meta: meta,
8981				index: index,
8982				easingValue: easingValue
8983			};
8984
8985			if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
8986				return;
8987			}
8988
8989			meta.controller.draw(easingValue);
8990
8991			plugins.notify(me, 'afterDatasetDraw', [args]);
8992		},
8993
8994		/**
8995		 * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`
8996		 * hook, in which case, plugins will not be called on `afterTooltipDraw`.
8997		 * @private
8998		 */
8999		_drawTooltip: function(easingValue) {
9000			var me = this;
9001			var tooltip = me.tooltip;
9002			var args = {
9003				tooltip: tooltip,
9004				easingValue: easingValue
9005			};
9006
9007			if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
9008				return;
9009			}
9010
9011			tooltip.draw();
9012
9013			plugins.notify(me, 'afterTooltipDraw', [args]);
9014		},
9015
9016		// Get the single element that was clicked on
vendor: 12,764 bytes, lines 9017-9508
9017		// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
9018		getElementAtEvent: function(e) {
9019			return Interaction.modes.single(this, e);
9020		},
9021
9022		getElementsAtEvent: function(e) {
9023			return Interaction.modes.label(this, e, {intersect: true});
9024		},
9025
9026		getElementsAtXAxis: function(e) {
9027			return Interaction.modes['x-axis'](this, e, {intersect: true});
9028		},
9029
9030		getElementsAtEventForMode: function(e, mode, options) {
9031			var method = Interaction.modes[mode];
9032			if (typeof method === 'function') {
9033				return method(this, e, options);
9034			}
9035
9036			return [];
9037		},
9038
9039		getDatasetAtEvent: function(e) {
9040			return Interaction.modes.dataset(this, e, {intersect: true});
9041		},
9042
9043		getDatasetMeta: function(datasetIndex) {
9044			var me = this;
9045			var dataset = me.data.datasets[datasetIndex];
9046			if (!dataset._meta) {
9047				dataset._meta = {};
9048			}
9049
9050			var meta = dataset._meta[me.id];
9051			if (!meta) {
9052				meta = dataset._meta[me.id] = {
9053					type: null,
9054					data: [],
9055					dataset: null,
9056					controller: null,
9057					hidden: null,			// See isDatasetVisible() comment
9058					xAxisID: null,
9059					yAxisID: null
9060				};
9061			}
9062
9063			return meta;
9064		},
9065
9066		getVisibleDatasetCount: function() {
9067			var count = 0;
9068			for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
9069				if (this.isDatasetVisible(i)) {
9070					count++;
9071				}
9072			}
9073			return count;
9074		},
9075
9076		isDatasetVisible: function(datasetIndex) {
9077			var meta = this.getDatasetMeta(datasetIndex);
9078
9079			// meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
9080			// the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
9081			return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
9082		},
9083
9084		generateLegend: function() {
9085			return this.options.legendCallback(this);
9086		},
9087
9088		/**
9089		 * @private
9090		 */
9091		destroyDatasetMeta: function(datasetIndex) {
9092			var id = this.id;
9093			var dataset = this.data.datasets[datasetIndex];
9094			var meta = dataset._meta && dataset._meta[id];
9095
9096			if (meta) {
9097				meta.controller.destroy();
9098				delete dataset._meta[id];
9099			}
9100		},
9101
9102		destroy: function() {
9103			var me = this;
9104			var canvas = me.canvas;
9105			var i, ilen;
9106
9107			me.stop();
9108
9109			// dataset controllers need to cleanup associated data
9110			for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
9111				me.destroyDatasetMeta(i);
9112			}
9113
9114			if (canvas) {
9115				me.unbindEvents();
9116				helpers.canvas.clear(me);
9117				platform.releaseContext(me.ctx);
9118				me.canvas = null;
9119				me.ctx = null;
9120			}
9121
9122			plugins.notify(me, 'destroy');
9123
9124			delete Chart.instances[me.id];
9125		},
9126
9127		toBase64Image: function() {
9128			return this.canvas.toDataURL.apply(this.canvas, arguments);
9129		},
9130
9131		initToolTip: function() {
9132			var me = this;
9133			me.tooltip = new Chart.Tooltip({
9134				_chart: me,
9135				_chartInstance: me, // deprecated, backward compatibility
9136				_data: me.data,
9137				_options: me.options.tooltips
9138			}, me);
9139		},
9140
9141		/**
9142		 * @private
9143		 */
9144		bindEvents: function() {
9145			var me = this;
9146			var listeners = me._listeners = {};
9147			var listener = function() {
9148				me.eventHandler.apply(me, arguments);
9149			};
9150
9151			helpers.each(me.options.events, function(type) {
9152				platform.addEventListener(me, type, listener);
9153				listeners[type] = listener;
9154			});
9155
9156			// Elements used to detect size change should not be injected for non responsive charts.
9157			// See https://github.com/chartjs/Chart.js/issues/2210
9158			if (me.options.responsive) {
9159				listener = function() {
9160					me.resize();
9161				};
9162
9163				platform.addEventListener(me, 'resize', listener);
9164				listeners.resize = listener;
9165			}
9166		},
9167
9168		/**
9169		 * @private
9170		 */
9171		unbindEvents: function() {
9172			var me = this;
9173			var listeners = me._listeners;
9174			if (!listeners) {
9175				return;
9176			}
9177
9178			delete me._listeners;
9179			helpers.each(listeners, function(listener, type) {
9180				platform.removeEventListener(me, type, listener);
9181			});
9182		},
9183
9184		updateHoverStyle: function(elements, mode, enabled) {
9185			var method = enabled ? 'setHoverStyle' : 'removeHoverStyle';
9186			var element, i, ilen;
9187
9188			for (i = 0, ilen = elements.length; i < ilen; ++i) {
9189				element = elements[i];
9190				if (element) {
9191					this.getDatasetMeta(element._datasetIndex).controller[method](element);
9192				}
9193			}
9194		},
9195
9196		/**
9197		 * @private
9198		 */
9199		eventHandler: function(e) {
9200			var me = this;
9201			var tooltip = me.tooltip;
9202
9203			if (plugins.notify(me, 'beforeEvent', [e]) === false) {
9204				return;
9205			}
9206
9207			// Buffer any update calls so that renders do not occur
9208			me._bufferedRender = true;
9209			me._bufferedRequest = null;
9210
9211			var changed = me.handleEvent(e);
9212			// for smooth tooltip animations issue #4989
9213			// the tooltip should be the source of change
9214			// Animation check workaround:
9215			// tooltip._start will be null when tooltip isn't animating
9216			if (tooltip) {
9217				changed = tooltip._start
9218					? tooltip.handleEvent(e)
9219					: changed | tooltip.handleEvent(e);
9220			}
9221
9222			plugins.notify(me, 'afterEvent', [e]);
9223
9224			var bufferedRequest = me._bufferedRequest;
9225			if (bufferedRequest) {
9226				// If we have an update that was triggered, we need to do a normal render
9227				me.render(bufferedRequest);
9228			} else if (changed && !me.animating) {
9229				// If entering, leaving, or changing elements, animate the change via pivot
9230				me.stop();
9231
9232				// We only need to render at this point. Updating will cause scales to be
9233				// recomputed generating flicker & using more memory than necessary.
9234				me.render(me.options.hover.animationDuration, true);
9235			}
9236
9237			me._bufferedRender = false;
9238			me._bufferedRequest = null;
9239
9240			return me;
9241		},
9242
9243		/**
9244		 * Handle an event
9245		 * @private
9246		 * @param {IEvent} event the event to handle
9247		 * @return {Boolean} true if the chart needs to re-render
9248		 */
9249		handleEvent: function(e) {
9250			var me = this;
9251			var options = me.options || {};
9252			var hoverOptions = options.hover;
9253			var changed = false;
9254
9255			me.lastActive = me.lastActive || [];
9256
9257			// Find Active Elements for hover and tooltips
9258			if (e.type === 'mouseout') {
9259				me.active = [];
9260			} else {
9261				me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
9262			}
9263
9264			// Invoke onHover hook
9265			// Need to call with native event here to not break backwards compatibility
9266			helpers.callback(options.onHover || options.hover.onHover, [e.native, me.active], me);
9267
9268			if (e.type === 'mouseup' || e.type === 'click') {
9269				if (options.onClick) {
9270					// Use e.native here for backwards compatibility
9271					options.onClick.call(me, e.native, me.active);
9272				}
9273			}
9274
9275			// Remove styling for last active (even if it may still be active)
9276			if (me.lastActive.length) {
9277				me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
9278			}
9279
9280			// Built in hover styling
9281			if (me.active.length && hoverOptions.mode) {
9282				me.updateHoverStyle(me.active, hoverOptions.mode, true);
9283			}
9284
9285			changed = !helpers.arrayEquals(me.active, me.lastActive);
9286
9287			// Remember Last Actives
9288			me.lastActive = me.active;
9289
9290			return changed;
9291		}
9292	});
9293
9294	/**
9295	 * Provided for backward compatibility, use Chart instead.
9296	 * @class Chart.Controller
9297	 * @deprecated since version 2.6.0
9298	 * @todo remove at version 3
9299	 * @private
9300	 */
9301	Chart.Controller = Chart;
9302};
9303
9304},{"25":25,"28":28,"30":30,"31":31,"45":45,"48":48}],24:[function(require,module,exports){
9305'use strict';
9306
9307var helpers = require(45);
9308
9309module.exports = function(Chart) {
9310
9311	var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
9312
9313	/**
9314	 * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
9315	 * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
9316	 * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
9317	 */
9318	function listenArrayEvents(array, listener) {
9319		if (array._chartjs) {
9320			array._chartjs.listeners.push(listener);
9321			return;
9322		}
9323
9324		Object.defineProperty(array, '_chartjs', {
9325			configurable: true,
9326			enumerable: false,
9327			value: {
9328				listeners: [listener]
9329			}
9330		});
9331
9332		arrayEvents.forEach(function(key) {
9333			var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
9334			var base = array[key];
9335
9336			Object.defineProperty(array, key, {
9337				configurable: true,
9338				enumerable: false,
9339				value: function() {
9340					var args = Array.prototype.slice.call(arguments);
9341					var res = base.apply(this, args);
9342
9343					helpers.each(array._chartjs.listeners, function(object) {
9344						if (typeof object[method] === 'function') {
9345							object[method].apply(object, args);
9346						}
9347					});
9348
9349					return res;
9350				}
9351			});
9352		});
9353	}
9354
9355	/**
9356	 * Removes the given array event listener and cleanup extra attached properties (such as
9357	 * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
9358	 */
9359	function unlistenArrayEvents(array, listener) {
9360		var stub = array._chartjs;
9361		if (!stub) {
9362			return;
9363		}
9364
9365		var listeners = stub.listeners;
9366		var index = listeners.indexOf(listener);
9367		if (index !== -1) {
9368			listeners.splice(index, 1);
9369		}
9370
9371		if (listeners.length > 0) {
9372			return;
9373		}
9374
9375		arrayEvents.forEach(function(key) {
9376			delete array[key];
9377		});
9378
9379		delete array._chartjs;
9380	}
9381
9382	// Base class for all dataset controllers (line, bar, etc)
9383	Chart.DatasetController = function(chart, datasetIndex) {
9384		this.initialize(chart, datasetIndex);
9385	};
9386
9387	helpers.extend(Chart.DatasetController.prototype, {
9388
9389		/**
9390		 * Element type used to generate a meta dataset (e.g. Chart.element.Line).
9391		 * @type {Chart.core.element}
9392		 */
9393		datasetElementType: null,
9394
9395		/**
9396		 * Element type used to generate a meta data (e.g. Chart.element.Point).
9397		 * @type {Chart.core.element}
9398		 */
9399		dataElementType: null,
9400
9401		initialize: function(chart, datasetIndex) {
9402			var me = this;
9403			me.chart = chart;
9404			me.index = datasetIndex;
9405			me.linkScales();
9406			me.addElements();
9407		},
9408
9409		updateIndex: function(datasetIndex) {
9410			this.index = datasetIndex;
9411		},
9412
9413		linkScales: function() {
9414			var me = this;
9415			var meta = me.getMeta();
9416			var dataset = me.getDataset();
9417
9418			if (meta.xAxisID === null || !(meta.xAxisID in me.chart.scales)) {
9419				meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
9420			}
9421			if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) {
9422				meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
9423			}
9424		},
9425
9426		getDataset: function() {
9427			return this.chart.data.datasets[this.index];
9428		},
9429
9430		getMeta: function() {
9431			return this.chart.getDatasetMeta(this.index);
9432		},
9433
9434		getScaleForId: function(scaleID) {
9435			return this.chart.scales[scaleID];
9436		},
9437
9438		reset: function() {
9439			this.update(true);
9440		},
9441
9442		/**
9443		 * @private
9444		 */
9445		destroy: function() {
9446			if (this._data) {
9447				unlistenArrayEvents(this._data, this);
9448			}
9449		},
9450
9451		createMetaDataset: function() {
9452			var me = this;
9453			var type = me.datasetElementType;
9454			return type && new type({
9455				_chart: me.chart,
9456				_datasetIndex: me.index
9457			});
9458		},
9459
9460		createMetaData: function(index) {
9461			var me = this;
9462			var type = me.dataElementType;
9463			return type && new type({
9464				_chart: me.chart,
9465				_datasetIndex: me.index,
9466				_index: index
9467			});
9468		},
9469
9470		addElements: function() {
9471			var me = this;
9472			var meta = me.getMeta();
9473			var data = me.getDataset().data || [];
9474			var metaData = meta.data;
9475			var i, ilen;
9476
9477			for (i = 0, ilen = data.length; i < ilen; ++i) {
9478				metaData[i] = metaData[i] || me.createMetaData(i);
9479			}
9480
9481			meta.dataset = meta.dataset || me.createMetaDataset();
9482		},
9483
9484		addElementAndReset: function(index) {
9485			var element = this.createMetaData(index);
9486			this.getMeta().data.splice(index, 0, element);
9487			this.updateElement(element, index, true);
9488		},
9489
9490		buildOrUpdateElements: function() {
9491			var me = this;
9492			var dataset = me.getDataset();
9493			var data = dataset.data || (dataset.data = []);
9494
9495			// In order to correctly handle data addition/deletion animation (an thus simulate
9496			// real-time charts), we need to monitor these data modifications and synchronize
9497			// the internal meta data accordingly.
9498			if (me._data !== data) {
9499				if (me._data) {
9500					// This case happens when the user replaced the data array instance.
9501					unlistenArrayEvents(me._data, me);
9502				}
9503
9504				listenArrayEvents(data, me);
9505				me._data = data;
9506			}
9507
9508			// Re-sync meta data in case the user replaced the data array or if we missed
9509			// any updates and so make sure that we handle number of datapoints changing.
9510			me.resyncElements();
9511		},
9512
9513		update: helpers.noop,
9514
9515		transition: function(easingValue) {
9516			var meta = this.getMeta();
9517			var elements = meta.data || [];
9518			var ilen = elements.length;
9519			var i = 0;
9520
9521			for (; i < ilen; ++i) {
9522				elements[i].transition(easingValue);
9523			}
9524
9525			if (meta.dataset) {
9526				meta.dataset.transition(easingValue);
9527			}
9528		},
9529
9530		draw: function() {
9531			var meta = this.getMeta();
9532			var elements = meta.data || [];
9533			var ilen = elements.length;
9534			var i = 0;
9535
9536			if (meta.dataset) {
9537				meta.dataset.draw();
9538			}
9539
9540			for (; i < ilen; ++i) {
9541				elements[i].draw();
9542			}
9543		},
9544
9545		removeHoverStyle: function(element, elementOpts) {
9546			var dataset = this.chart.data.datasets[element._datasetIndex];
9547			var index = element._index;
9548			var custom = element.custom || {};
9549			var valueOrDefault = helpers.valueAtIndexOrDefault;
9550			var model = element._model;
9551
9552			model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
9553			model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
9554			model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
9555		},
9556
9557		setHoverStyle: function(element) {
9558			var dataset = this.chart.data.datasets[element._datasetIndex];
9559			var index = element._index;
9560			var custom = element.custom || {};
9561			var valueOrDefault = helpers.valueAtIndexOrDefault;
9562			var getHoverColor = helpers.getHoverColor;
9563			var model = element._model;
9564
9565			model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
9566			model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
9567			model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
9568		},
9569
9570		/**
9571		 * @private
9572		 */
9573		resyncElements: function() {
9574			var me = this;
9575			var meta = me.getMeta();
9576			var data = me.getDataset().data;
9577			var numMeta = meta.data.length;
9578			var numData = data.length;
9579
9580			if (numData < numMeta) {
9581				meta.data.splice(numData, numMeta - numData);
9582			} else if (numData > numMeta) {
9583				me.insertElements(numMeta, numData - numMeta);
9584			}
9585		},
9586
9587		/**
9588		 * @private
9589		 */
9590		insertElements: function(start, count) {
9591			for (var i = 0; i < count; ++i) {
9592				this.addElementAndReset(start + i);
9593			}
9594		},
9595
9596		/**
9597		 * @private
9598		 */
9599		onDataPush: function() {
9600			this.insertElements(this.getDataset().data.length - 1, arguments.length);
9601		},
9602
9603		/**
9604		 * @private
9605		 */
9606		onDataPop: function() {
9607			this.getMeta().data.pop();
9608		},
9609
9610		/**
9611		 * @private
9612		 */
9613		onDataShift: function() {
9614			this.getMeta().data.shift();
9615		},
9616
9617		/**
9618		 * @private
9619		 */
9620		onDataSplice: function(start, count) {
9621			this.getMeta().data.splice(start, count);
9622			this.insertElements(start, arguments.length - 2);
9623		},
9624
9625		/**
9626		 * @private
9627		 */
9628		onDataUnshift: function() {
9629			this.insertElements(0, arguments.length);
9630		}
9631	});
9632
9633	Chart.DatasetController.extend = helpers.inherits;
9634};
9635
9636},{"45":45}],25:[function(require,module,exports){
9637'use strict';
9638
9639var helpers = require(45);
9640
9641module.exports = {
9642	/**
9643	 * @private
9644	 */
9645	_set: function(scope, values) {
9646		return helpers.merge(this[scope] || (this[scope] = {}), values);
9647	}
9648};
9649
9650},{"45":45}],26:[function(require,module,exports){
9651'use strict';
9652
9653var color = require(2);
9654var helpers = require(45);
9655
9656function interpolate(start, view, model, ease) {
9657	var keys = Object.keys(model);
9658	var i, ilen, key, actual, origin, target, type, c0, c1;
9659
9660	for (i = 0, ilen = keys.length; i < ilen; ++i) {
9661		key = keys[i];
9662
9663		target = model[key];
9664
9665		// if a value is added to the model after pivot() has been called, the view
9666		// doesn't contain it, so let's initialize the view to the target value.
9667		if (!view.hasOwnProperty(key)) {
9668			view[key] = target;
9669		}
9670
9671		actual = view[key];
9672
vendor: 28,653 bytes, lines 9673-10577
9673		if (actual === target || key[0] === '_') {
9674			continue;
9675		}
9676
9677		if (!start.hasOwnProperty(key)) {
9678			start[key] = actual;
9679		}
9680
9681		origin = start[key];
9682
9683		type = typeof target;
9684
9685		if (type === typeof origin) {
9686			if (type === 'string') {
9687				c0 = color(origin);
9688				if (c0.valid) {
9689					c1 = color(target);
9690					if (c1.valid) {
9691						view[key] = c1.mix(c0, ease).rgbString();
9692						continue;
9693					}
9694				}
9695			} else if (type === 'number' && isFinite(origin) && isFinite(target)) {
9696				view[key] = origin + (target - origin) * ease;
9697				continue;
9698			}
9699		}
9700
9701		view[key] = target;
9702	}
9703}
9704
9705var Element = function(configuration) {
9706	helpers.extend(this, configuration);
9707	this.initialize.apply(this, arguments);
9708};
9709
9710helpers.extend(Element.prototype, {
9711
9712	initialize: function() {
9713		this.hidden = false;
9714	},
9715
9716	pivot: function() {
9717		var me = this;
9718		if (!me._view) {
9719			me._view = helpers.clone(me._model);
9720		}
9721		me._start = {};
9722		return me;
9723	},
9724
9725	transition: function(ease) {
9726		var me = this;
9727		var model = me._model;
9728		var start = me._start;
9729		var view = me._view;
9730
9731		// No animation -> No Transition
9732		if (!model || ease === 1) {
9733			me._view = model;
9734			me._start = null;
9735			return me;
9736		}
9737
9738		if (!view) {
9739			view = me._view = {};
9740		}
9741
9742		if (!start) {
9743			start = me._start = {};
9744		}
9745
9746		interpolate(start, view, model, ease);
9747
9748		return me;
9749	},
9750
9751	tooltipPosition: function() {
9752		return {
9753			x: this._model.x,
9754			y: this._model.y
9755		};
9756	},
9757
9758	hasValue: function() {
9759		return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
9760	}
9761});
9762
9763Element.extend = helpers.inherits;
9764
9765module.exports = Element;
9766
9767},{"2":2,"45":45}],27:[function(require,module,exports){
9768/* global window: false */
9769/* global document: false */
9770'use strict';
9771
9772var color = require(2);
9773var defaults = require(25);
9774var helpers = require(45);
9775
9776module.exports = function(Chart) {
9777
9778	// -- Basic js utility methods
9779
9780	helpers.configMerge = function(/* objects ... */) {
9781		return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
9782			merger: function(key, target, source, options) {
9783				var tval = target[key] || {};
9784				var sval = source[key];
9785
9786				if (key === 'scales') {
9787					// scale config merging is complex. Add our own function here for that
9788					target[key] = helpers.scaleMerge(tval, sval);
9789				} else if (key === 'scale') {
9790					// used in polar area & radar charts since there is only one scale
9791					target[key] = helpers.merge(tval, [Chart.scaleService.getScaleDefaults(sval.type), sval]);
9792				} else {
9793					helpers._merger(key, target, source, options);
9794				}
9795			}
9796		});
9797	};
9798
9799	helpers.scaleMerge = function(/* objects ... */) {
9800		return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
9801			merger: function(key, target, source, options) {
9802				if (key === 'xAxes' || key === 'yAxes') {
9803					var slen = source[key].length;
9804					var i, type, scale;
9805
9806					if (!target[key]) {
9807						target[key] = [];
9808					}
9809
9810					for (i = 0; i < slen; ++i) {
9811						scale = source[key][i];
9812						type = helpers.valueOrDefault(scale.type, key === 'xAxes' ? 'category' : 'linear');
9813
9814						if (i >= target[key].length) {
9815							target[key].push({});
9816						}
9817
9818						if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) {
9819							// new/untyped scale or type changed: let's apply the new defaults
9820							// then merge source scale to correctly overwrite the defaults.
9821							helpers.merge(target[key][i], [Chart.scaleService.getScaleDefaults(type), scale]);
9822						} else {
9823							// scales type are the same
9824							helpers.merge(target[key][i], scale);
9825						}
9826					}
9827				} else {
9828					helpers._merger(key, target, source, options);
9829				}
9830			}
9831		});
9832	};
9833
9834	helpers.where = function(collection, filterCallback) {
9835		if (helpers.isArray(collection) && Array.prototype.filter) {
9836			return collection.filter(filterCallback);
9837		}
9838		var filtered = [];
9839
9840		helpers.each(collection, function(item) {
9841			if (filterCallback(item)) {
9842				filtered.push(item);
9843			}
9844		});
9845
9846		return filtered;
9847	};
9848	helpers.findIndex = Array.prototype.findIndex ?
9849		function(array, callback, scope) {
9850			return array.findIndex(callback, scope);
9851		} :
9852		function(array, callback, scope) {
9853			scope = scope === undefined ? array : scope;
9854			for (var i = 0, ilen = array.length; i < ilen; ++i) {
9855				if (callback.call(scope, array[i], i, array)) {
9856					return i;
9857				}
9858			}
9859			return -1;
9860		};
9861	helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
9862		// Default to start of the array
9863		if (helpers.isNullOrUndef(startIndex)) {
9864			startIndex = -1;
9865		}
9866		for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
9867			var currentItem = arrayToSearch[i];
9868			if (filterCallback(currentItem)) {
9869				return currentItem;
9870			}
9871		}
9872	};
9873	helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
9874		// Default to end of the array
9875		if (helpers.isNullOrUndef(startIndex)) {
9876			startIndex = arrayToSearch.length;
9877		}
9878		for (var i = startIndex - 1; i >= 0; i--) {
9879			var currentItem = arrayToSearch[i];
9880			if (filterCallback(currentItem)) {
9881				return currentItem;
9882			}
9883		}
9884	};
9885
9886	// -- Math methods
9887	helpers.isNumber = function(n) {
9888		return !isNaN(parseFloat(n)) && isFinite(n);
9889	};
9890	helpers.almostEquals = function(x, y, epsilon) {
9891		return Math.abs(x - y) < epsilon;
9892	};
9893	helpers.almostWhole = function(x, epsilon) {
9894		var rounded = Math.round(x);
9895		return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
9896	};
9897	helpers.max = function(array) {
9898		return array.reduce(function(max, value) {
9899			if (!isNaN(value)) {
9900				return Math.max(max, value);
9901			}
9902			return max;
9903		}, Number.NEGATIVE_INFINITY);
9904	};
9905	helpers.min = function(array) {
9906		return array.reduce(function(min, value) {
9907			if (!isNaN(value)) {
9908				return Math.min(min, value);
9909			}
9910			return min;
9911		}, Number.POSITIVE_INFINITY);
9912	};
9913	helpers.sign = Math.sign ?
9914		function(x) {
9915			return Math.sign(x);
9916		} :
9917		function(x) {
9918			x = +x; // convert to a number
9919			if (x === 0 || isNaN(x)) {
9920				return x;
9921			}
9922			return x > 0 ? 1 : -1;
9923		};
9924	helpers.log10 = Math.log10 ?
9925		function(x) {
9926			return Math.log10(x);
9927		} :
9928		function(x) {
9929			var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
9930			// Check for whole powers of 10,
9931			// which due to floating point rounding error should be corrected.
9932			var powerOf10 = Math.round(exponent);
9933			var isPowerOf10 = x === Math.pow(10, powerOf10);
9934
9935			return isPowerOf10 ? powerOf10 : exponent;
9936		};
9937	helpers.toRadians = function(degrees) {
9938		return degrees * (Math.PI / 180);
9939	};
9940	helpers.toDegrees = function(radians) {
9941		return radians * (180 / Math.PI);
9942	};
9943	// Gets the angle from vertical upright to the point about a centre.
9944	helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
9945		var distanceFromXCenter = anglePoint.x - centrePoint.x;
9946		var distanceFromYCenter = anglePoint.y - centrePoint.y;
9947		var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
9948
9949		var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
9950
9951		if (angle < (-0.5 * Math.PI)) {
9952			angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
9953		}
9954
9955		return {
9956			angle: angle,
9957			distance: radialDistanceFromCenter
9958		};
9959	};
9960	helpers.distanceBetweenPoints = function(pt1, pt2) {
9961		return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
9962	};
9963	helpers.aliasPixel = function(pixelWidth) {
9964		return (pixelWidth % 2 === 0) ? 0 : 0.5;
9965	};
9966	helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
9967		// Props to Rob Spencer at scaled innovation for his post on splining between points
9968		// http://scaledinnovation.com/analytics/splines/aboutSplines.html
9969
9970		// This function must also respect "skipped" points
9971
9972		var previous = firstPoint.skip ? middlePoint : firstPoint;
9973		var current = middlePoint;
9974		var next = afterPoint.skip ? middlePoint : afterPoint;
9975
9976		var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
9977		var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
9978
9979		var s01 = d01 / (d01 + d12);
9980		var s12 = d12 / (d01 + d12);
9981
9982		// If all points are the same, s01 & s02 will be inf
9983		s01 = isNaN(s01) ? 0 : s01;
9984		s12 = isNaN(s12) ? 0 : s12;
9985
9986		var fa = t * s01; // scaling factor for triangle Ta
9987		var fb = t * s12;
9988
9989		return {
9990			previous: {
9991				x: current.x - fa * (next.x - previous.x),
9992				y: current.y - fa * (next.y - previous.y)
9993			},
9994			next: {
9995				x: current.x + fb * (next.x - previous.x),
9996				y: current.y + fb * (next.y - previous.y)
9997			}
9998		};
9999	};
10000	helpers.EPSILON = Number.EPSILON || 1e-14;
10001	helpers.splineCurveMonotone = function(points) {
10002		// This function calculates Bézier control points in a similar way than |splineCurve|,
10003		// but preserves monotonicity of the provided data and ensures no local extremums are added
10004		// between the dataset discrete points due to the interpolation.
10005		// See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
10006
10007		var pointsWithTangents = (points || []).map(function(point) {
10008			return {
10009				model: point._model,
10010				deltaK: 0,
10011				mK: 0
10012			};
10013		});
10014
10015		// Calculate slopes (deltaK) and initialize tangents (mK)
10016		var pointsLen = pointsWithTangents.length;
10017		var i, pointBefore, pointCurrent, pointAfter;
10018		for (i = 0; i < pointsLen; ++i) {
10019			pointCurrent = pointsWithTangents[i];
10020			if (pointCurrent.model.skip) {
10021				continue;
10022			}
10023
10024			pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
10025			pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
10026			if (pointAfter && !pointAfter.model.skip) {
10027				var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
10028
10029				// In the case of two points that appear at the same x pixel, slopeDeltaX is 0
10030				pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
10031			}
10032
10033			if (!pointBefore || pointBefore.model.skip) {
10034				pointCurrent.mK = pointCurrent.deltaK;
10035			} else if (!pointAfter || pointAfter.model.skip) {
10036				pointCurrent.mK = pointBefore.deltaK;
10037			} else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
10038				pointCurrent.mK = 0;
10039			} else {
10040				pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
10041			}
10042		}
10043
10044		// Adjust tangents to ensure monotonic properties
10045		var alphaK, betaK, tauK, squaredMagnitude;
10046		for (i = 0; i < pointsLen - 1; ++i) {
10047			pointCurrent = pointsWithTangents[i];
10048			pointAfter = pointsWithTangents[i + 1];
10049			if (pointCurrent.model.skip || pointAfter.model.skip) {
10050				continue;
10051			}
10052
10053			if (helpers.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
10054				pointCurrent.mK = pointAfter.mK = 0;
10055				continue;
10056			}
10057
10058			alphaK = pointCurrent.mK / pointCurrent.deltaK;
10059			betaK = pointAfter.mK / pointCurrent.deltaK;
10060			squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
10061			if (squaredMagnitude <= 9) {
10062				continue;
10063			}
10064
10065			tauK = 3 / Math.sqrt(squaredMagnitude);
10066			pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
10067			pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
10068		}
10069
10070		// Compute control points
10071		var deltaX;
10072		for (i = 0; i < pointsLen; ++i) {
10073			pointCurrent = pointsWithTangents[i];
10074			if (pointCurrent.model.skip) {
10075				continue;
10076			}
10077
10078			pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
10079			pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
10080			if (pointBefore && !pointBefore.model.skip) {
10081				deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
10082				pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
10083				pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
10084			}
10085			if (pointAfter && !pointAfter.model.skip) {
10086				deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
10087				pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
10088				pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
10089			}
10090		}
10091	};
10092	helpers.nextItem = function(collection, index, loop) {
10093		if (loop) {
10094			return index >= collection.length - 1 ? collection[0] : collection[index + 1];
10095		}
10096		return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
10097	};
10098	helpers.previousItem = function(collection, index, loop) {
10099		if (loop) {
10100			return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
10101		}
10102		return index <= 0 ? collection[0] : collection[index - 1];
10103	};
10104	// Implementation of the nice number algorithm used in determining where axis labels will go
10105	helpers.niceNum = function(range, round) {
10106		var exponent = Math.floor(helpers.log10(range));
10107		var fraction = range / Math.pow(10, exponent);
10108		var niceFraction;
10109
10110		if (round) {
10111			if (fraction < 1.5) {
10112				niceFraction = 1;
10113			} else if (fraction < 3) {
10114				niceFraction = 2;
10115			} else if (fraction < 7) {
10116				niceFraction = 5;
10117			} else {
10118				niceFraction = 10;
10119			}
10120		} else if (fraction <= 1.0) {
10121			niceFraction = 1;
10122		} else if (fraction <= 2) {
10123			niceFraction = 2;
10124		} else if (fraction <= 5) {
10125			niceFraction = 5;
10126		} else {
10127			niceFraction = 10;
10128		}
10129
10130		return niceFraction * Math.pow(10, exponent);
10131	};
10132	// Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
10133	helpers.requestAnimFrame = (function() {
10134		if (typeof window === 'undefined') {
10135			return function(callback) {
10136				callback();
10137			};
10138		}
10139		return window.requestAnimationFrame ||
10140			window.webkitRequestAnimationFrame ||
10141			window.mozRequestAnimationFrame ||
10142			window.oRequestAnimationFrame ||
10143			window.msRequestAnimationFrame ||
10144			function(callback) {
10145				return window.setTimeout(callback, 1000 / 60);
10146			};
10147	}());
10148	// -- DOM methods
10149	helpers.getRelativePosition = function(evt, chart) {
10150		var mouseX, mouseY;
10151		var e = evt.originalEvent || evt;
10152		var canvas = evt.currentTarget || evt.srcElement;
10153		var boundingRect = canvas.getBoundingClientRect();
10154
10155		var touches = e.touches;
10156		if (touches && touches.length > 0) {
10157			mouseX = touches[0].clientX;
10158			mouseY = touches[0].clientY;
10159
10160		} else {
10161			mouseX = e.clientX;
10162			mouseY = e.clientY;
10163		}
10164
10165		// Scale mouse coordinates into canvas coordinates
10166		// by following the pattern laid out by 'jerryj' in the comments of
10167		// http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
10168		var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
10169		var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
10170		var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
10171		var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
10172		var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
10173		var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
10174
10175		// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
10176		// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
10177		mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
10178		mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
10179
10180		return {
10181			x: mouseX,
10182			y: mouseY
10183		};
10184
10185	};
10186
10187	// Private helper function to convert max-width/max-height values that may be percentages into a number
10188	function parseMaxStyle(styleValue, node, parentProperty) {
10189		var valueInPixels;
10190		if (typeof styleValue === 'string') {
10191			valueInPixels = parseInt(styleValue, 10);
10192
10193			if (styleValue.indexOf('%') !== -1) {
10194				// percentage * size in dimension
10195				valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
10196			}
10197		} else {
10198			valueInPixels = styleValue;
10199		}
10200
10201		return valueInPixels;
10202	}
10203
10204	/**
10205	 * Returns if the given value contains an effective constraint.
10206	 * @private
10207	 */
10208	function isConstrainedValue(value) {
10209		return value !== undefined && value !== null && value !== 'none';
10210	}
10211
10212	// Private helper to get a constraint dimension
10213	// @param domNode : the node to check the constraint on
10214	// @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
10215	// @param percentageProperty : property of parent to use when calculating width as a percentage
10216	// @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
10217	function getConstraintDimension(domNode, maxStyle, percentageProperty) {
10218		var view = document.defaultView;
10219		var parentNode = domNode.parentNode;
10220		var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
10221		var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
10222		var hasCNode = isConstrainedValue(constrainedNode);
10223		var hasCContainer = isConstrainedValue(constrainedContainer);
10224		var infinity = Number.POSITIVE_INFINITY;
10225
10226		if (hasCNode || hasCContainer) {
10227			return Math.min(
10228				hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
10229				hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
10230		}
10231
10232		return 'none';
10233	}
10234	// returns Number or undefined if no constraint
10235	helpers.getConstraintWidth = function(domNode) {
10236		return getConstraintDimension(domNode, 'max-width', 'clientWidth');
10237	};
10238	// returns Number or undefined if no constraint
10239	helpers.getConstraintHeight = function(domNode) {
10240		return getConstraintDimension(domNode, 'max-height', 'clientHeight');
10241	};
10242	helpers.getMaximumWidth = function(domNode) {
10243		var container = domNode.parentNode;
10244		if (!container) {
10245			return domNode.clientWidth;
10246		}
10247
10248		var paddingLeft = parseInt(helpers.getStyle(container, 'padding-left'), 10);
10249		var paddingRight = parseInt(helpers.getStyle(container, 'padding-right'), 10);
10250		var w = container.clientWidth - paddingLeft - paddingRight;
10251		var cw = helpers.getConstraintWidth(domNode);
10252		return isNaN(cw) ? w : Math.min(w, cw);
10253	};
10254	helpers.getMaximumHeight = function(domNode) {
10255		var container = domNode.parentNode;
10256		if (!container) {
10257			return domNode.clientHeight;
10258		}
10259
10260		var paddingTop = parseInt(helpers.getStyle(container, 'padding-top'), 10);
10261		var paddingBottom = parseInt(helpers.getStyle(container, 'padding-bottom'), 10);
10262		var h = container.clientHeight - paddingTop - paddingBottom;
10263		var ch = helpers.getConstraintHeight(domNode);
10264		return isNaN(ch) ? h : Math.min(h, ch);
10265	};
10266	helpers.getStyle = function(el, property) {
10267		return el.currentStyle ?
10268			el.currentStyle[property] :
10269			document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
10270	};
10271	helpers.retinaScale = function(chart, forceRatio) {
10272		var pixelRatio = chart.currentDevicePixelRatio = forceRatio || window.devicePixelRatio || 1;
10273		if (pixelRatio === 1) {
10274			return;
10275		}
10276
10277		var canvas = chart.canvas;
10278		var height = chart.height;
10279		var width = chart.width;
10280
10281		canvas.height = height * pixelRatio;
10282		canvas.width = width * pixelRatio;
10283		chart.ctx.scale(pixelRatio, pixelRatio);
10284
10285		// If no style has been set on the canvas, the render size is used as display size,
10286		// making the chart visually bigger, so let's enforce it to the "correct" values.
10287		// See https://github.com/chartjs/Chart.js/issues/3575
10288		if (!canvas.style.height && !canvas.style.width) {
10289			canvas.style.height = height + 'px';
10290			canvas.style.width = width + 'px';
10291		}
10292	};
10293	// -- Canvas methods
10294	helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
10295		return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
10296	};
10297	helpers.longestText = function(ctx, font, arrayOfThings, cache) {
10298		cache = cache || {};
10299		var data = cache.data = cache.data || {};
10300		var gc = cache.garbageCollect = cache.garbageCollect || [];
10301
10302		if (cache.font !== font) {
10303			data = cache.data = {};
10304			gc = cache.garbageCollect = [];
10305			cache.font = font;
10306		}
10307
10308		ctx.font = font;
10309		var longest = 0;
10310		helpers.each(arrayOfThings, function(thing) {
10311			// Undefined strings and arrays should not be measured
10312			if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
10313				longest = helpers.measureText(ctx, data, gc, longest, thing);
10314			} else if (helpers.isArray(thing)) {
10315				// if it is an array lets measure each element
10316				// to do maybe simplify this function a bit so we can do this more recursively?
10317				helpers.each(thing, function(nestedThing) {
10318					// Undefined strings and arrays should not be measured
10319					if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
10320						longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
10321					}
10322				});
10323			}
10324		});
10325
10326		var gcLen = gc.length / 2;
10327		if (gcLen > arrayOfThings.length) {
10328			for (var i = 0; i < gcLen; i++) {
10329				delete data[gc[i]];
10330			}
10331			gc.splice(0, gcLen);
10332		}
10333		return longest;
10334	};
10335	helpers.measureText = function(ctx, data, gc, longest, string) {
10336		var textWidth = data[string];
10337		if (!textWidth) {
10338			textWidth = data[string] = ctx.measureText(string).width;
10339			gc.push(string);
10340		}
10341		if (textWidth > longest) {
10342			longest = textWidth;
10343		}
10344		return longest;
10345	};
10346	helpers.numberOfLabelLines = function(arrayOfThings) {
10347		var numberOfLines = 1;
10348		helpers.each(arrayOfThings, function(thing) {
10349			if (helpers.isArray(thing)) {
10350				if (thing.length > numberOfLines) {
10351					numberOfLines = thing.length;
10352				}
10353			}
10354		});
10355		return numberOfLines;
10356	};
10357
10358	helpers.color = !color ?
10359		function(value) {
10360			console.error('Color.js not found!');
10361			return value;
10362		} :
10363		function(value) {
10364			/* global CanvasGradient */
10365			if (value instanceof CanvasGradient) {
10366				value = defaults.global.defaultColor;
10367			}
10368
10369			return color(value);
10370		};
10371
10372	helpers.getHoverColor = function(colorValue) {
10373		/* global CanvasPattern */
10374		return (colorValue instanceof CanvasPattern) ?
10375			colorValue :
10376			helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
10377	};
10378};
10379
10380},{"2":2,"25":25,"45":45}],28:[function(require,module,exports){
10381'use strict';
10382
10383var helpers = require(45);
10384
10385/**
10386 * Helper function to get relative position for an event
10387 * @param {Event|IEvent} event - The event to get the position for
10388 * @param {Chart} chart - The chart
10389 * @returns {Point} the event position
10390 */
10391function getRelativePosition(e, chart) {
10392	if (e.native) {
10393		return {
10394			x: e.x,
10395			y: e.y
10396		};
10397	}
10398
10399	return helpers.getRelativePosition(e, chart);
10400}
10401
10402/**
10403 * Helper function to traverse all of the visible elements in the chart
10404 * @param chart {chart} the chart
10405 * @param handler {Function} the callback to execute for each visible item
10406 */
10407function parseVisibleItems(chart, handler) {
10408	var datasets = chart.data.datasets;
10409	var meta, i, j, ilen, jlen;
10410
10411	for (i = 0, ilen = datasets.length; i < ilen; ++i) {
10412		if (!chart.isDatasetVisible(i)) {
10413			continue;
10414		}
10415
10416		meta = chart.getDatasetMeta(i);
10417		for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
10418			var element = meta.data[j];
10419			if (!element._view.skip) {
10420				handler(element);
10421			}
10422		}
10423	}
10424}
10425
10426/**
10427 * Helper function to get the items that intersect the event position
10428 * @param items {ChartElement[]} elements to filter
10429 * @param position {Point} the point to be nearest to
10430 * @return {ChartElement[]} the nearest items
10431 */
10432function getIntersectItems(chart, position) {
10433	var elements = [];
10434
10435	parseVisibleItems(chart, function(element) {
10436		if (element.inRange(position.x, position.y)) {
10437			elements.push(element);
10438		}
10439	});
10440
10441	return elements;
10442}
10443
10444/**
10445 * Helper function to get the items nearest to the event position considering all visible items in teh chart
10446 * @param chart {Chart} the chart to look at elements from
10447 * @param position {Point} the point to be nearest to
10448 * @param intersect {Boolean} if true, only consider items that intersect the position
10449 * @param distanceMetric {Function} function to provide the distance between points
10450 * @return {ChartElement[]} the nearest items
10451 */
10452function getNearestItems(chart, position, intersect, distanceMetric) {
10453	var minDistance = Number.POSITIVE_INFINITY;
10454	var nearestItems = [];
10455
10456	parseVisibleItems(chart, function(element) {
10457		if (intersect && !element.inRange(position.x, position.y)) {
10458			return;
10459		}
10460
10461		var center = element.getCenterPoint();
10462		var distance = distanceMetric(position, center);
10463
10464		if (distance < minDistance) {
10465			nearestItems = [element];
10466			minDistance = distance;
10467		} else if (distance === minDistance) {
10468			// Can have multiple items at the same distance in which case we sort by size
10469			nearestItems.push(element);
10470		}
10471	});
10472
10473	return nearestItems;
10474}
10475
10476/**
10477 * Get a distance metric function for two points based on the
10478 * axis mode setting
10479 * @param {String} axis the axis mode. x|y|xy
10480 */
10481function getDistanceMetricForAxis(axis) {
10482	var useX = axis.indexOf('x') !== -1;
10483	var useY = axis.indexOf('y') !== -1;
10484
10485	return function(pt1, pt2) {
10486		var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
10487		var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
10488		return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
10489	};
10490}
10491
10492function indexMode(chart, e, options) {
10493	var position = getRelativePosition(e, chart);
10494	// Default axis for index mode is 'x' to match old behaviour
10495	options.axis = options.axis || 'x';
10496	var distanceMetric = getDistanceMetricForAxis(options.axis);
10497	var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
10498	var elements = [];
10499
10500	if (!items.length) {
10501		return [];
10502	}
10503
10504	chart.data.datasets.forEach(function(dataset, datasetIndex) {
10505		if (chart.isDatasetVisible(datasetIndex)) {
10506			var meta = chart.getDatasetMeta(datasetIndex);
10507			var element = meta.data[items[0]._index];
10508
10509			// don't count items that are skipped (null data)
10510			if (element && !element._view.skip) {
10511				elements.push(element);
10512			}
10513		}
10514	});
10515
10516	return elements;
10517}
10518
10519/**
10520 * @interface IInteractionOptions
10521 */
10522/**
10523 * If true, only consider items that intersect the point
10524 * @name IInterfaceOptions#boolean
10525 * @type Boolean
10526 */
10527
10528/**
10529 * Contains interaction related functions
10530 * @namespace Chart.Interaction
10531 */
10532module.exports = {
10533	// Helper function for different modes
10534	modes: {
10535		single: function(chart, e) {
10536			var position = getRelativePosition(e, chart);
10537			var elements = [];
10538
10539			parseVisibleItems(chart, function(element) {
10540				if (element.inRange(position.x, position.y)) {
10541					elements.push(element);
10542					return elements;
10543				}
10544			});
10545
10546			return elements.slice(0, 1);
10547		},
10548
10549		/**
10550		 * @function Chart.Interaction.modes.label
10551		 * @deprecated since version 2.4.0
10552		 * @todo remove at version 3
10553		 * @private
10554		 */
10555		label: indexMode,
10556
10557		/**
10558		 * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
10559		 * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
10560		 * @function Chart.Interaction.modes.index
10561		 * @since v2.4.0
10562		 * @param chart {chart} the chart we are returning items from
10563		 * @param e {Event} the event we are find things at
10564		 * @param options {IInteractionOptions} options to use during interaction
10565		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10566		 */
10567		index: indexMode,
10568
10569		/**
10570		 * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
10571		 * If the options.intersect is false, we find the nearest item and return the items in that dataset
10572		 * @function Chart.Interaction.modes.dataset
10573		 * @param chart {chart} the chart we are returning items from
10574		 * @param e {Event} the event we are find things at
10575		 * @param options {IInteractionOptions} options to use during interaction
10576		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10577		 */
10578		dataset: function(chart, e, options) {
10579			var position = getRelativePosition(e, chart);
10580			options.axis = options.axis || 'xy';
10581			var distanceMetric = getDistanceMetricForAxis(options.axis);
10582			var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
10583
10584			if (items.length > 0) {
10585				items = chart.getDatasetMeta(items[0]._datasetIndex).data;
10586			}
10587
10588			return items;
10589		},
10590
10591		/**
10592		 * @function Chart.Interaction.modes.x-axis
10593		 * @deprecated since version 2.4.0. Use index mode and intersect == true
10594		 * @todo remove at version 3
10595		 * @private
10596		 */
10597		'x-axis': function(chart, e) {
10598			return indexMode(chart, e, {intersect: false});
10599		},
10600
10601		/**
10602		 * Point mode returns all elements that hit test based on the event position
10603		 * of the event
10604		 * @function Chart.Interaction.modes.intersect
10605		 * @param chart {chart} the chart we are returning items from
10606		 * @param e {Event} the event we are find things at
10607		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10608		 */
10609		point: function(chart, e) {
10610			var position = getRelativePosition(e, chart);
10611			return getIntersectItems(chart, position);
10612		},
10613
10614		/**
10615		 * nearest mode returns the element closest to the point
10616		 * @function Chart.Interaction.modes.intersect
10617		 * @param chart {chart} the chart we are returning items from
10618		 * @param e {Event} the event we are find things at
10619		 * @param options {IInteractionOptions} options to use
10620		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10621		 */
10622		nearest: function(chart, e, options) {
10623			var position = getRelativePosition(e, chart);
10624			options.axis = options.axis || 'xy';
10625			var distanceMetric = getDistanceMetricForAxis(options.axis);
10626			var nearestItems = getNearestItems(chart, position, options.intersect, distanceMetric);
10627
10628			// We have multiple items at the same distance from the event. Now sort by smallest
10629			if (nearestItems.length > 1) {
10630				nearestItems.sort(function(a, b) {
10631					var sizeA = a.getArea();
10632					var sizeB = b.getArea();
10633					var ret = sizeA - sizeB;
10634
10635					if (ret === 0) {
10636						// if equal sort by dataset index
10637						ret = a._datasetIndex - b._datasetIndex;
10638					}
10639
10640					return ret;
10641				});
10642			}
10643
10644			// Return only 1 item
10645			return nearestItems.slice(0, 1);
10646		},
10647
10648		/**
10649		 * x mode returns the elements that hit-test at the current x coordinate
10650		 * @function Chart.Interaction.modes.x
10651		 * @param chart {chart} the chart we are returning items from
10652		 * @param e {Event} the event we are find things at
10653		 * @param options {IInteractionOptions} options to use
10654		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10655		 */
10656		x: function(chart, e, options) {
10657			var position = getRelativePosition(e, chart);
10658			var items = [];
10659			var intersectsItem = false;
10660
10661			parseVisibleItems(chart, function(element) {
10662				if (element.inXRange(position.x)) {
10663					items.push(element);
10664				}
10665
10666				if (element.inRange(position.x, position.y)) {
10667					intersectsItem = true;
10668				}
10669			});
10670
10671			// If we want to trigger on an intersect and we don't have any items
10672			// that intersect the position, return nothing
10673			if (options.intersect && !intersectsItem) {
10674				items = [];
10675			}
10676			return items;
10677		},
10678
10679		/**
10680		 * y mode returns the elements that hit-test at the current y coordinate
10681		 * @function Chart.Interaction.modes.y
10682		 * @param chart {chart} the chart we are returning items from
10683		 * @param e {Event} the event we are find things at
10684		 * @param options {IInteractionOptions} options to use
10685		 * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10686		 */
10687		y: function(chart, e, options) {
10688			var position = getRelativePosition(e, chart);
10689			var items = [];
10690			var intersectsItem = false;
10691
10692			parseVisibleItems(chart, function(element) {
10693				if (element.inYRange(position.y)) {
10694					items.push(element);
10695				}
10696
10697				if (element.inRange(position.x, position.y)) {
10698					intersectsItem = true;
10699				}
10700			});
10701
10702			// If we want to trigger on an intersect and we don't have any items
10703			// that intersect the position, return nothing
10704			if (options.intersect && !intersectsItem) {
10705				items = [];
10706			}
10707			return items;
10708		}
10709	}
10710};
10711
10712},{"45":45}],29:[function(require,module,exports){
10713'use strict';
10714
10715var defaults = require(25);
10716
10717defaults._set('global', {
10718	responsive: true,
10719	responsiveAnimationDuration: 0,
10720	maintainAspectRatio: true,
10721	events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
10722	hover: {
10723		onHover: null,
10724		mode: 'nearest',
10725		intersect: true,
10726		animationDuration: 400
10727	},
10728	onClick: null,
10729	defaultColor: 'rgba(0,0,0,0.1)',
10730	defaultFontColor: '#666',
10731	defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
10732	defaultFontSize: 12,
10733	defaultFontStyle: 'normal',
10734	showLines: true,
10735
10736	// Element defaults defined in element extensions
10737	elements: {},
10738
10739	// Layout options such as padding
10740	layout: {
10741		padding: {
10742			top: 0,
10743			right: 0,
10744			bottom: 0,
10745			left: 0
10746		}
10747	}
10748});
10749
10750module.exports = function() {
10751
10752	// Occupy the global variable of Chart, and create a simple base class
10753	var Chart = function(item, config) {
10754		this.construct(item, config);
10755		return this;
10756	};
10757
10758	Chart.Chart = Chart;
10759
10760	return Chart;
10761};
10762
10763},{"25":25}],30:[function(require,module,exports){
10764'use strict';
10765
10766var helpers = require(45);
10767
10768function filterByPosition(array, position) {
10769	return helpers.where(array, function(v) {
10770		return v.position === position;
10771	});
10772}
10773
10774function sortByWeight(array, reverse) {
10775	array.forEach(function(v, i) {
10776		v._tmpIndex_ = i;
10777		return v;
10778	});
10779	array.sort(function(a, b) {
10780		var v0 = reverse ? b : a;
10781		var v1 = reverse ? a : b;
10782		return v0.weight === v1.weight ?
10783			v0._tmpIndex_ - v1._tmpIndex_ :
10784			v0.weight - v1.weight;
10785	});
10786	array.forEach(function(v) {
10787		delete v._tmpIndex_;
10788	});
10789}
10790
10791/**
10792 * @interface ILayoutItem
10793 * @prop {String} position - The position of the item in the chart layout. Possible values are
10794 * 'left', 'top', 'right', 'bottom', and 'chartArea'
10795 * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
10796 * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
10797 * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
10798 * @prop {Function} update - Takes two parameters: width and height. Returns size of item
10799 * @prop {Function} getPadding -  Returns an object with padding on the edges
10800 * @prop {Number} width - Width of item. Must be valid after update()
10801 * @prop {Number} height - Height of item. Must be valid after update()
10802 * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
10803 * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
10804 * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
10805 * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
10806 */
10807
10808// The layout service is very self explanatory.  It's responsible for the layout within a chart.
10809// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
10810// It is this service's responsibility of carrying out that layout.
10811module.exports = {
10812	defaults: {},
10813
10814	/**
10815	 * Register a box to a chart.
10816	 * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
10817	 * @param {Chart} chart - the chart to use
10818	 * @param {ILayoutItem} item - the item to add to be layed out
10819	 */
10820	addBox: function(chart, item) {
10821		if (!chart.boxes) {
10822			chart.boxes = [];
10823		}
10824
10825		// initialize item with default values
10826		item.fullWidth = item.fullWidth || false;
10827		item.position = item.position || 'top';
10828		item.weight = item.weight || 0;
10829
10830		chart.boxes.push(item);
10831	},
10832
10833	/**
10834	 * Remove a layoutItem from a chart
10835	 * @param {Chart} chart - the chart to remove the box from
10836	 * @param {Object} layoutItem - the item to remove from the layout
10837	 */
10838	removeBox: function(chart, layoutItem) {
10839		var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
10840		if (index !== -1) {
10841			chart.boxes.splice(index, 1);
10842		}
10843	},
10844
10845	/**
10846	 * Sets (or updates) options on the given `item`.
10847	 * @param {Chart} chart - the chart in which the item lives (or will be added to)
10848	 * @param {Object} item - the item to configure with the given options
10849	 * @param {Object} options - the new item options.
10850	 */
10851	configure: function(chart, item, options) {
10852		var props = ['fullWidth', 'position', 'weight'];
10853		var ilen = props.length;
10854		var i = 0;
10855		var prop;
10856
10857		for (; i < ilen; ++i) {
10858			prop = props[i];
10859			if (options.hasOwnProperty(prop)) {
10860				item[prop] = options[prop];
10861			}
10862		}
10863	},
10864
10865	/**
10866	 * Fits boxes of the given chart into the given size by having each box measure itself
10867	 * then running a fitting algorithm
10868	 * @param {Chart} chart - the chart
10869	 * @param {Number} width - the width to fit into
10870	 * @param {Number} height - the height to fit into
10871	 */
10872	update: function(chart, width, height) {
10873		if (!chart) {
10874			return;
10875		}
10876
10877		var layoutOptions = chart.options.layout || {};
10878		var padding = helpers.options.toPadding(layoutOptions.padding);
10879		var leftPadding = padding.left;
10880		var rightPadding = padding.right;
10881		var topPadding = padding.top;
10882		var bottomPadding = padding.bottom;
10883
10884		var leftBoxes = filterByPosition(chart.boxes, 'left');
10885		var rightBoxes = filterByPosition(chart.boxes, 'right');
10886		var topBoxes = filterByPosition(chart.boxes, 'top');
10887		var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
10888		var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');
10889
10890		// Sort boxes by weight. A higher weight is further away from the chart area
10891		sortByWeight(leftBoxes, true);
10892		sortByWeight(rightBoxes, false);
10893		sortByWeight(topBoxes, true);
10894		sortByWeight(bottomBoxes, false);
10895
10896		// Essentially we now have any number of boxes on each of the 4 sides.
10897		// Our canvas looks like the following.
10898		// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
10899		// B1 is the bottom axis
10900		// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
10901		// These locations are single-box locations only, when trying to register a chartArea location that is already taken,
10902		// an error will be thrown.
10903		//
10904		// |----------------------------------------------------|
10905		// |                  T1 (Full Width)                   |
10906		// |----------------------------------------------------|
10907		// |    |    |                 T2                  |    |
10908		// |    |----|-------------------------------------|----|
10909		// |    |    | C1 |                           | C2 |    |
10910		// |    |    |----|                           |----|    |
10911		// |    |    |                                     |    |
10912		// | L1 | L2 |           ChartArea (C0)            | R1 |
10913		// |    |    |                                     |    |
10914		// |    |    |----|                           |----|    |
10915		// |    |    | C3 |                           | C4 |    |
10916		// |    |----|-------------------------------------|----|
10917		// |    |    |                 B1                  |    |
10918		// |----------------------------------------------------|
10919		// |                  B2 (Full Width)                   |
10920		// |----------------------------------------------------|
10921		//
10922		// What we do to find the best sizing, we do the following
10923		// 1. Determine the minimum size of the chart area.
10924		// 2. Split the remaining width equally between each vertical axis
10925		// 3. Split the remaining height equally between each horizontal axis
10926		// 4. Give each layout the maximum size it can be. The layout will return it's minimum size
10927		// 5. Adjust the sizes of each axis based on it's minimum reported size.
10928		// 6. Refit each axis
10929		// 7. Position each axis in the final location
10930		// 8. Tell the chart the final location of the chart area
10931		// 9. Tell any axes that overlay the chart area the positions of the chart area
10932
10933		// Step 1
10934		var chartWidth = width - leftPadding - rightPadding;
10935		var chartHeight = height - topPadding - bottomPadding;
10936		var chartAreaWidth = chartWidth / 2; // min 50%
10937		var chartAreaHeight = chartHeight / 2; // min 50%
10938
10939		// Step 2
10940		var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
10941
10942		// Step 3
10943		var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
10944
10945		// Step 4
10946		var maxChartAreaWidth = chartWidth;
10947		var maxChartAreaHeight = chartHeight;
10948		var minBoxSizes = [];
10949
10950		function getMinimumBoxSize(box) {
10951			var minSize;
10952			var isHorizontal = box.isHorizontal();
10953
10954			if (isHorizontal) {
10955				minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
10956				maxChartAreaHeight -= minSize.height;
10957			} else {
10958				minSize = box.update(verticalBoxWidth, maxChartAreaHeight);
10959				maxChartAreaWidth -= minSize.width;
10960			}
10961
10962			minBoxSizes.push({
10963				horizontal: isHorizontal,
10964				minSize: minSize,
10965				box: box,
10966			});
10967		}
10968
10969		helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
10970
10971		// If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
10972		var maxHorizontalLeftPadding = 0;
10973		var maxHorizontalRightPadding = 0;
10974		var maxVerticalTopPadding = 0;
10975		var maxVerticalBottomPadding = 0;
10976
10977		helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
10978			if (horizontalBox.getPadding) {
10979				var boxPadding = horizontalBox.getPadding();
10980				maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
10981				maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
10982			}
10983		});
10984
10985		helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
10986			if (verticalBox.getPadding) {
10987				var boxPadding = verticalBox.getPadding();
10988				maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
10989				maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
10990			}
10991		});
10992
10993		// At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
10994		// be if the axes are drawn at their minimum sizes.
10995		// Steps 5 & 6
10996		var totalLeftBoxesWidth = leftPadding;
10997		var totalRightBoxesWidth = rightPadding;
10998		var totalTopBoxesHeight = topPadding;
10999		var totalBottomBoxesHeight = bottomPadding;
11000
11001		// Function to fit a box
11002		function fitBox(box) {
11003			var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBox) {
11004				return minBox.box === box;
11005			});
11006
11007			if (minBoxSize) {
11008				if (box.isHorizontal()) {
11009					var scaleMargin = {
11010						left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
11011						right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
11012						top: 0,
11013						bottom: 0
11014					};
11015
11016					// Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
11017					// on the margin. Sometimes they need to increase in size slightly
11018					box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
11019				} else {
11020					box.update(minBoxSize.minSize.width, maxChartAreaHeight);
11021				}
11022			}
11023		}
11024
11025		// Update, and calculate the left and right margins for the horizontal boxes
11026		helpers.each(leftBoxes.concat(rightBoxes), fitBox);
11027
11028		helpers.each(leftBoxes, function(box) {
11029			totalLeftBoxesWidth += box.width;
11030		});
11031
11032		helpers.each(rightBoxes, function(box) {
11033			totalRightBoxesWidth += box.width;
11034		});
11035
11036		// Set the Left and Right margins for the horizontal boxes
11037		helpers.each(topBoxes.concat(bottomBoxes), fitBox);
11038
11039		// Figure out how much margin is on the top and bottom of the vertical boxes
11040		helpers.each(topBoxes, function(box) {
11041			totalTopBoxesHeight += box.height;
11042		});
11043
11044		helpers.each(bottomBoxes, function(box) {
11045			totalBottomBoxesHeight += box.height;
11046		});
11047
11048		function finalFitVerticalBox(box) {
11049			var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) {
11050				return minSize.box === box;
11051			});
11052
11053			var scaleMargin = {
11054				left: 0,
11055				right: 0,
11056				top: totalTopBoxesHeight,
11057				bottom: totalBottomBoxesHeight
11058			};
11059
11060			if (minBoxSize) {
11061				box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
11062			}
11063		}
11064
11065		// Let the left layout know the final margin
11066		helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
11067
11068		// Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
11069		totalLeftBoxesWidth = leftPadding;
11070		totalRightBoxesWidth = rightPadding;
11071		totalTopBoxesHeight = topPadding;
11072		totalBottomBoxesHeight = bottomPadding;
11073
11074		helpers.each(leftBoxes, function(box) {
11075			totalLeftBoxesWidth += box.width;
11076		});
11077
11078		helpers.each(rightBoxes, function(box) {
11079			totalRightBoxesWidth += box.width;
11080		});
11081
11082		helpers.each(topBoxes, function(box) {
11083			totalTopBoxesHeight += box.height;
11084		});
11085		helpers.each(bottomBoxes, function(box) {
11086			totalBottomBoxesHeight += box.height;
11087		});
11088
11089		// We may be adding some padding to account for rotated x axis labels
11090		var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
11091		totalLeftBoxesWidth += leftPaddingAddition;
11092		totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);
11093
11094		var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
11095		totalTopBoxesHeight += topPaddingAddition;
11096		totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);
11097
11098		// Figure out if our chart area changed. This would occur if the dataset layout label rotation
11099		// changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
11100		// without calling `fit` again
11101		var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
11102		var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
11103
11104		if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
11105			helpers.each(leftBoxes, function(box) {
11106				box.height = newMaxChartAreaHeight;
11107			});
11108
11109			helpers.each(rightBoxes, function(box) {
11110				box.height = newMaxChartAreaHeight;
11111			});
11112
11113			helpers.each(topBoxes, function(box) {
11114				if (!box.fullWidth) {
11115					box.width = newMaxChartAreaWidth;
11116				}
11117			});
11118
11119			helpers.each(bottomBoxes, function(box) {
11120				if (!box.fullWidth) {
11121					box.width = newMaxChartAreaWidth;
11122				}
11123			});
11124
11125			maxChartAreaHeight = newMaxChartAreaHeight;
11126			maxChartAreaWidth = newMaxChartAreaWidth;
11127		}
11128
11129		// Step 7 - Position the boxes
11130		var left = leftPadding + leftPaddingAddition;
11131		var top = topPadding + topPaddingAddition;
11132
11133		function placeBox(box) {
11134			if (box.isHorizontal()) {
11135				box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
11136				box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
11137				box.top = top;
11138				box.bottom = top + box.height;
11139
11140				// Move to next point
11141				top = box.bottom;
11142
11143			} else {
11144
11145				box.left = left;
11146				box.right = left + box.width;
11147				box.top = totalTopBoxesHeight;
11148				box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
11149
11150				// Move to next point
11151				left = box.right;
11152			}
11153		}
11154
11155		helpers.each(leftBoxes.concat(topBoxes), placeBox);
11156
11157		// Account for chart width and height
11158		left += maxChartAreaWidth;
11159		top += maxChartAreaHeight;
11160
11161		helpers.each(rightBoxes, placeBox);
11162		helpers.each(bottomBoxes, placeBox);
11163
11164		// Step 8
11165		chart.chartArea = {
11166			left: totalLeftBoxesWidth,
11167			top: totalTopBoxesHeight,
11168			right: totalLeftBoxesWidth + maxChartAreaWidth,
11169			bottom: totalTopBoxesHeight + maxChartAreaHeight
11170		};
11171
11172		// Step 9
11173		helpers.each(chartAreaBoxes, function(box) {
11174			box.left = chart.chartArea.left;
11175			box.top = chart.chartArea.top;
11176			box.right = chart.chartArea.right;
11177			box.bottom = chart.chartArea.bottom;
11178
11179			box.update(maxChartAreaWidth, maxChartAreaHeight);
11180		});
11181	}
11182};
11183
11184},{"45":45}],31:[function(require,module,exports){
11185'use strict';
11186
11187var defaults = require(25);
11188var helpers = require(45);
11189
11190defaults._set('global', {
11191	plugins: {}
11192});
11193
11194/**
11195 * The plugin service singleton
11196 * @namespace Chart.plugins
11197 * @since 2.1.0
11198 */
11199module.exports = {
11200	/**
11201	 * Globally registered plugins.
11202	 * @private
11203	 */
11204	_plugins: [],
11205
11206	/**
11207	 * This identifier is used to invalidate the descriptors cache attached to each chart
11208	 * when a global plugin is registered or unregistered. In this case, the cache ID is
11209	 * incremented and descriptors are regenerated during following API calls.
11210	 * @private
11211	 */
11212	_cacheId: 0,
11213
11214	/**
11215	 * Registers the given plugin(s) if not already registered.
11216	 * @param {Array|Object} plugins plugin instance(s).
11217	 */
11218	register: function(plugins) {
11219		var p = this._plugins;
11220		([]).concat(plugins).forEach(function(plugin) {
11221			if (p.indexOf(plugin) === -1) {
11222				p.push(plugin);
11223			}
11224		});
11225
11226		this._cacheId++;
11227	},
11228
11229	/**
11230	 * Unregisters the given plugin(s) only if registered.
11231	 * @param {Array|Object} plugins plugin instance(s).
11232	 */
11233	unregister: function(plugins) {
11234		var p = this._plugins;
11235		([]).concat(plugins).forEach(function(plugin) {
11236			var idx = p.indexOf(plugin);
11237			if (idx !== -1) {
11238				p.splice(idx, 1);
11239			}
11240		});
11241
11242		this._cacheId++;
11243	},
11244
11245	/**
11246	 * Remove all registered plugins.
11247	 * @since 2.1.5
11248	 */
11249	clear: function() {
11250		this._plugins = [];
11251		this._cacheId++;
11252	},
11253
11254	/**
11255	 * Returns the number of registered plugins?
11256	 * @returns {Number}
11257	 * @since 2.1.5
11258	 */
11259	count: function() {
11260		return this._plugins.length;
11261	},
11262
11263	/**
11264	 * Returns all registered plugin instances.
11265	 * @returns {Array} array of plugin objects.
11266	 * @since 2.1.5
11267	 */
11268	getAll: function() {
11269		return this._plugins;
11270	},
11271
11272	/**
11273	 * Calls enabled plugins for `chart` on the specified hook and with the given args.
11274	 * This method immediately returns as soon as a plugin explicitly returns false. The
11275	 * returned value can be used, for instance, to interrupt the current action.
11276	 * @param {Object} chart - The chart instance for which plugins should be called.
11277	 * @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
11278	 * @param {Array} [args] - Extra arguments to apply to the hook call.
11279	 * @returns {Boolean} false if any of the plugins return false, else returns true.
11280	 */
11281	notify: function(chart, hook, args) {
11282		var descriptors = this.descriptors(chart);
11283		var ilen = descriptors.length;
11284		var i, descriptor, plugin, params, method;
11285
11286		for (i = 0; i < ilen; ++i) {
11287			descriptor = descriptors[i];
11288			plugin = descriptor.plugin;
11289			method = plugin[hook];
11290			if (typeof method === 'function') {
11291				params = [chart].concat(args || []);
11292				params.push(descriptor.options);
11293				if (method.apply(plugin, params) === false) {
11294					return false;
11295				}
11296			}
11297		}
11298
11299		return true;
11300	},
11301
11302	/**
11303	 * Returns descriptors of enabled plugins for the given chart.
11304	 * @returns {Array} [{ plugin, options }]
11305	 * @private
11306	 */
11307	descriptors: function(chart) {
11308		var cache = chart.$plugins || (chart.$plugins = {});
11309		if (cache.id === this._cacheId) {
11310			return cache.descriptors;
11311		}
11312
11313		var plugins = [];
11314		var descriptors = [];
11315		var config = (chart && chart.config) || {};
11316		var options = (config.options && config.options.plugins) || {};
11317
vendor: 9,640 bytes, lines 11318-11546
11318		this._plugins.concat(config.plugins || []).forEach(function(plugin) {
11319			var idx = plugins.indexOf(plugin);
11320			if (idx !== -1) {
11321				return;
11322			}
11323
11324			var id = plugin.id;
11325			var opts = options[id];
11326			if (opts === false) {
11327				return;
11328			}
11329
11330			if (opts === true) {
11331				opts = helpers.clone(defaults.global.plugins[id]);
11332			}
11333
11334			plugins.push(plugin);
11335			descriptors.push({
11336				plugin: plugin,
11337				options: opts || {}
11338			});
11339		});
11340
11341		cache.descriptors = descriptors;
11342		cache.id = this._cacheId;
11343		return descriptors;
11344	},
11345
11346	/**
11347	 * Invalidates cache for the given chart: descriptors hold a reference on plugin option,
11348	 * but in some cases, this reference can be changed by the user when updating options.
11349	 * https://github.com/chartjs/Chart.js/issues/5111#issuecomment-355934167
11350	 * @private
11351	 */
11352	_invalidate: function(chart) {
11353		delete chart.$plugins;
11354	}
11355};
11356
11357/**
11358 * Plugin extension hooks.
11359 * @interface IPlugin
11360 * @since 2.1.0
11361 */
11362/**
11363 * @method IPlugin#beforeInit
11364 * @desc Called before initializing `chart`.
11365 * @param {Chart.Controller} chart - The chart instance.
11366 * @param {Object} options - The plugin options.
11367 */
11368/**
11369 * @method IPlugin#afterInit
11370 * @desc Called after `chart` has been initialized and before the first update.
11371 * @param {Chart.Controller} chart - The chart instance.
11372 * @param {Object} options - The plugin options.
11373 */
11374/**
11375 * @method IPlugin#beforeUpdate
11376 * @desc Called before updating `chart`. If any plugin returns `false`, the update
11377 * is cancelled (and thus subsequent render(s)) until another `update` is triggered.
11378 * @param {Chart.Controller} chart - The chart instance.
11379 * @param {Object} options - The plugin options.
11380 * @returns {Boolean} `false` to cancel the chart update.
11381 */
11382/**
11383 * @method IPlugin#afterUpdate
11384 * @desc Called after `chart` has been updated and before rendering. Note that this
11385 * hook will not be called if the chart update has been previously cancelled.
11386 * @param {Chart.Controller} chart - The chart instance.
11387 * @param {Object} options - The plugin options.
11388 */
11389/**
11390 * @method IPlugin#beforeDatasetsUpdate
11391 * @desc Called before updating the `chart` datasets. If any plugin returns `false`,
11392 * the datasets update is cancelled until another `update` is triggered.
11393 * @param {Chart.Controller} chart - The chart instance.
11394 * @param {Object} options - The plugin options.
11395 * @returns {Boolean} false to cancel the datasets update.
11396 * @since version 2.1.5
11397*/
11398/**
11399 * @method IPlugin#afterDatasetsUpdate
11400 * @desc Called after the `chart` datasets have been updated. Note that this hook
11401 * will not be called if the datasets update has been previously cancelled.
11402 * @param {Chart.Controller} chart - The chart instance.
11403 * @param {Object} options - The plugin options.
11404 * @since version 2.1.5
11405 */
11406/**
11407 * @method IPlugin#beforeDatasetUpdate
11408 * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin
11409 * returns `false`, the datasets update is cancelled until another `update` is triggered.
11410 * @param {Chart} chart - The chart instance.
11411 * @param {Object} args - The call arguments.
11412 * @param {Number} args.index - The dataset index.
11413 * @param {Object} args.meta - The dataset metadata.
11414 * @param {Object} options - The plugin options.
11415 * @returns {Boolean} `false` to cancel the chart datasets drawing.
11416 */
11417/**
11418 * @method IPlugin#afterDatasetUpdate
11419 * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note
11420 * that this hook will not be called if the datasets update has been previously cancelled.
11421 * @param {Chart} chart - The chart instance.
11422 * @param {Object} args - The call arguments.
11423 * @param {Number} args.index - The dataset index.
11424 * @param {Object} args.meta - The dataset metadata.
11425 * @param {Object} options - The plugin options.
11426 */
11427/**
11428 * @method IPlugin#beforeLayout
11429 * @desc Called before laying out `chart`. If any plugin returns `false`,
11430 * the layout update is cancelled until another `update` is triggered.
11431 * @param {Chart.Controller} chart - The chart instance.
11432 * @param {Object} options - The plugin options.
11433 * @returns {Boolean} `false` to cancel the chart layout.
11434 */
11435/**
11436 * @method IPlugin#afterLayout
11437 * @desc Called after the `chart` has been layed out. Note that this hook will not
11438 * be called if the layout update has been previously cancelled.
11439 * @param {Chart.Controller} chart - The chart instance.
11440 * @param {Object} options - The plugin options.
11441 */
11442/**
11443 * @method IPlugin#beforeRender
11444 * @desc Called before rendering `chart`. If any plugin returns `false`,
11445 * the rendering is cancelled until another `render` is triggered.
11446 * @param {Chart.Controller} chart - The chart instance.
11447 * @param {Object} options - The plugin options.
11448 * @returns {Boolean} `false` to cancel the chart rendering.
11449 */
11450/**
11451 * @method IPlugin#afterRender
11452 * @desc Called after the `chart` has been fully rendered (and animation completed). Note
11453 * that this hook will not be called if the rendering has been previously cancelled.
11454 * @param {Chart.Controller} chart - The chart instance.
11455 * @param {Object} options - The plugin options.
11456 */
11457/**
11458 * @method IPlugin#beforeDraw
11459 * @desc Called before drawing `chart` at every animation frame specified by the given
11460 * easing value. If any plugin returns `false`, the frame drawing is cancelled until
11461 * another `render` is triggered.
11462 * @param {Chart.Controller} chart - The chart instance.
11463 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11464 * @param {Object} options - The plugin options.
11465 * @returns {Boolean} `false` to cancel the chart drawing.
11466 */
11467/**
11468 * @method IPlugin#afterDraw
11469 * @desc Called after the `chart` has been drawn for the specific easing value. Note
11470 * that this hook will not be called if the drawing has been previously cancelled.
11471 * @param {Chart.Controller} chart - The chart instance.
11472 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11473 * @param {Object} options - The plugin options.
11474 */
11475/**
11476 * @method IPlugin#beforeDatasetsDraw
11477 * @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
11478 * the datasets drawing is cancelled until another `render` is triggered.
11479 * @param {Chart.Controller} chart - The chart instance.
11480 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11481 * @param {Object} options - The plugin options.
11482 * @returns {Boolean} `false` to cancel the chart datasets drawing.
11483 */
11484/**
11485 * @method IPlugin#afterDatasetsDraw
11486 * @desc Called after the `chart` datasets have been drawn. Note that this hook
11487 * will not be called if the datasets drawing has been previously cancelled.
11488 * @param {Chart.Controller} chart - The chart instance.
11489 * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11490 * @param {Object} options - The plugin options.
11491 */
11492/**
11493 * @method IPlugin#beforeDatasetDraw
11494 * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets
11495 * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing
11496 * is cancelled until another `render` is triggered.
11497 * @param {Chart} chart - The chart instance.
11498 * @param {Object} args - The call arguments.
11499 * @param {Number} args.index - The dataset index.
11500 * @param {Object} args.meta - The dataset metadata.
11501 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11502 * @param {Object} options - The plugin options.
11503 * @returns {Boolean} `false` to cancel the chart datasets drawing.
11504 */
11505/**
11506 * @method IPlugin#afterDatasetDraw
11507 * @desc Called after the `chart` datasets at the given `args.index` have been drawn
11508 * (datasets are drawn in the reverse order). Note that this hook will not be called
11509 * if the datasets drawing has been previously cancelled.
11510 * @param {Chart} chart - The chart instance.
11511 * @param {Object} args - The call arguments.
11512 * @param {Number} args.index - The dataset index.
11513 * @param {Object} args.meta - The dataset metadata.
11514 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11515 * @param {Object} options - The plugin options.
11516 */
11517/**
11518 * @method IPlugin#beforeTooltipDraw
11519 * @desc Called before drawing the `tooltip`. If any plugin returns `false`,
11520 * the tooltip drawing is cancelled until another `render` is triggered.
11521 * @param {Chart} chart - The chart instance.
11522 * @param {Object} args - The call arguments.
11523 * @param {Object} args.tooltip - The tooltip.
11524 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11525 * @param {Object} options - The plugin options.
11526 * @returns {Boolean} `false` to cancel the chart tooltip drawing.
11527 */
11528/**
11529 * @method IPlugin#afterTooltipDraw
11530 * @desc Called after drawing the `tooltip`. Note that this hook will not
11531 * be called if the tooltip drawing has been previously cancelled.
11532 * @param {Chart} chart - The chart instance.
11533 * @param {Object} args - The call arguments.
11534 * @param {Object} args.tooltip - The tooltip.
11535 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11536 * @param {Object} options - The plugin options.
11537 */
11538/**
11539 * @method IPlugin#beforeEvent
11540 * @desc Called before processing the specified `event`. If any plugin returns `false`,
11541 * the event will be discarded.
11542 * @param {Chart.Controller} chart - The chart instance.
11543 * @param {IEvent} event - The event object.
11544 * @param {Object} options - The plugin options.
11545 */
11546/**
11547 * @method IPlugin#afterEvent
11548 * @desc Called after the `event` has been consumed. Note that this hook
11549 * will not be called if the `event` has been previously discarded.
11550 * @param {Chart.Controller} chart - The chart instance.
11551 * @param {IEvent} event - The event object.
11552 * @param {Object} options - The plugin options.
11553 */
11554/**
11555 * @method IPlugin#resize
11556 * @desc Called after the chart as been resized.
11557 * @param {Chart.Controller} chart - The chart instance.
11558 * @param {Number} size - The new canvas display size (eq. canvas.style width & height).
11559 * @param {Object} options - The plugin options.
11560 */
11561/**
11562 * @method IPlugin#destroy
11563 * @desc Called after the chart as been destroyed.
11564 * @param {Chart.Controller} chart - The chart instance.
11565 * @param {Object} options - The plugin options.
11566 */
11567
11568},{"25":25,"45":45}],32:[function(require,module,exports){
11569'use strict';
11570
11571var defaults = require(25);
11572var Element = require(26);
11573var helpers = require(45);
11574var Ticks = require(34);
11575
11576defaults._set('scale', {
11577	display: true,
11578	position: 'left',
11579	offset: false,
11580
11581	// grid line settings
11582	gridLines: {
11583		display: true,
11584		color: 'rgba(0, 0, 0, 0.1)',
11585		lineWidth: 1,
11586		drawBorder: true,
11587		drawOnChartArea: true,
11588		drawTicks: true,
11589		tickMarkLength: 10,
11590		zeroLineWidth: 1,
11591		zeroLineColor: 'rgba(0,0,0,0.25)',
11592		zeroLineBorderDash: [],
11593		zeroLineBorderDashOffset: 0.0,
11594		offsetGridLines: false,
11595		borderDash: [],
11596		borderDashOffset: 0.0
11597	},
11598
11599	// scale label
11600	scaleLabel: {
11601		// display property
11602		display: false,
11603
11604		// actual label
11605		labelString: '',
11606
11607		// line height
11608		lineHeight: 1.2,
11609
11610		// top/bottom padding
11611		padding: {
11612			top: 4,
11613			bottom: 4
11614		}
11615	},
11616
11617	// label settings
11618	ticks: {
11619		beginAtZero: false,
11620		minRotation: 0,
11621		maxRotation: 50,
11622		mirror: false,
11623		padding: 0,
11624		reverse: false,
11625		display: true,
11626		autoSkip: true,
11627		autoSkipPadding: 0,
11628		labelOffset: 0,
11629		// We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
11630		callback: Ticks.formatters.values,
11631		minor: {},
11632		major: {}
11633	}
11634});
11635
11636function labelsFromTicks(ticks) {
11637	var labels = [];
11638	var i, ilen;
11639
11640	for (i = 0, ilen = ticks.length; i < ilen; ++i) {
11641		labels.push(ticks[i].label);
11642	}
11643
11644	return labels;
11645}
11646
11647function getLineValue(scale, index, offsetGridLines) {
11648	var lineValue = scale.getPixelForTick(index);
11649
11650	if (offsetGridLines) {
11651		if (index === 0) {
11652			lineValue -= (scale.getPixelForTick(1) - lineValue) / 2;
11653		} else {
11654			lineValue -= (lineValue - scale.getPixelForTick(index - 1)) / 2;
11655		}
11656	}
11657	return lineValue;
11658}
11659
11660module.exports = function(Chart) {
11661
11662	function computeTextSize(context, tick, font) {
11663		return helpers.isArray(tick) ?
11664			helpers.longestText(context, font, tick) :
11665			context.measureText(tick).width;
11666	}
11667
11668	function parseFontOptions(options) {
11669		var valueOrDefault = helpers.valueOrDefault;
11670		var globalDefaults = defaults.global;
11671		var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
11672		var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
11673		var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);
11674
11675		return {
11676			size: size,
11677			style: style,
11678			family: family,
11679			font: helpers.fontString(size, style, family)
11680		};
11681	}
11682
11683	function parseLineHeight(options) {
11684		return helpers.options.toLineHeight(
11685			helpers.valueOrDefault(options.lineHeight, 1.2),
11686			helpers.valueOrDefault(options.fontSize, defaults.global.defaultFontSize));
11687	}
11688
11689	Chart.Scale = Element.extend({
11690		/**
11691		 * Get the padding needed for the scale
11692		 * @method getPadding
11693		 * @private
11694		 * @returns {Padding} the necessary padding
11695		 */
11696		getPadding: function() {
11697			var me = this;
11698			return {
11699				left: me.paddingLeft || 0,
11700				top: me.paddingTop || 0,
11701				right: me.paddingRight || 0,
11702				bottom: me.paddingBottom || 0
11703			};
11704		},
11705
11706		/**
11707		 * Returns the scale tick objects ({label, major})
11708		 * @since 2.7
11709		 */
11710		getTicks: function() {
11711			return this._ticks;
11712		},
11713
11714		// These methods are ordered by lifecyle. Utilities then follow.
11715		// Any function defined here is inherited by all scale types.
11716		// Any function can be extended by the scale type
11717
11718		mergeTicksOptions: function() {
11719			var ticks = this.options.ticks;
11720			if (ticks.minor === false) {
11721				ticks.minor = {
11722					display: false
11723				};
11724			}
11725			if (ticks.major === false) {
11726				ticks.major = {
11727					display: false
11728				};
11729			}
11730			for (var key in ticks) {
11731				if (key !== 'major' && key !== 'minor') {
11732					if (typeof ticks.minor[key] === 'undefined') {
11733						ticks.minor[key] = ticks[key];
11734					}
11735					if (typeof ticks.major[key] === 'undefined') {
11736						ticks.major[key] = ticks[key];
11737					}
11738				}
11739			}
11740		},
11741		beforeUpdate: function() {
11742			helpers.callback(this.options.beforeUpdate, [this]);
11743		},
11744		update: function(maxWidth, maxHeight, margins) {
11745			var me = this;
11746			var i, ilen, labels, label, ticks, tick;
11747
11748			// Update Lifecycle - Probably don't want to ever extend or over
11748write this function ;)
11749			me.beforeUpdate();
11750
11751			// Absorb the master measurements
11752			me.maxWidth = maxWidth;
11753			me.maxHeight = maxHeight;
11754			me.margins = helpers.extend({
11755				left: 0,
11756				right: 0,
11757				top: 0,
11758				bottom: 0
11759			}, margins);
11760			me.longestTextCache = me.longestTextCache || {};
11761
11762			// Dimensions
11763			me.beforeSetDimensions();
11764			me.setDimensions();
11765			me.afterSetDimensions();
11766
11767			// Data min/max
11768			me.beforeDataLimits();
11769			me.determineDataLimits();
11770			me.afterDataLimits();
11771
11772			// Ticks - `this.ticks` is now DEPRECATED!
11773			// Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
11774			// and must not be accessed directly from outside this class. `this.ticks` being
11775			// around for long time and not marked as private, we can't change its structure
11776			// without unexpected breaking changes. If you need to access the scale ticks,
11777			// use scale.getTicks() instead.
11778
11779			me.beforeBuildTicks();
11780
11781			// New implementations should return an array of objects but for BACKWARD COMPAT,
11782			// we still support no return (`this.ticks` internally set by calling this method).
11783			ticks = me.buildTicks() || [];
11784
11785			me.afterBuildTicks();
11786
11787			me.beforeTickToLabelConversion();
11788
11789			// New implementations should return the formatted tick labels but for BACKWARD
11790			// COMPAT, we still support no return (`this.ticks` internally changed by calling
11791			// this method and supposed to contain only string values).
11792			labels = me.convertTicksToLabels(ticks) || me.ticks;
11793
11794			me.afterTickToLabelConversion();
11795
11796			me.ticks = labels;   // BACKWARD COMPATIBILITY
11797
11798			// IMPORTANT: from this point, we consider that `this.ticks` will NEVER change!
11799
11800			// BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
11801			for (i = 0, ilen = labels.length; i < ilen; ++i) {
11802				label = labels[i];
11803				tick = ticks[i];
11804				if (!tick) {
11805					ticks.push(tick = {
11806						label: label,
11807						major: false
11808					});
11809				} else {
11810					tick.label = label;
11811				}
11812			}
11813
11814			me._ticks = ticks;
11815
11816			// Tick Rotation
11817			me.beforeCalculateTickRotation();
11818			me.calculateTickRotation();
11819			me.afterCalculateTickRotation();
11820			// Fit
11821			me.beforeFit();
11822			me.fit();
11823			me.afterFit();
11824			//
11825			me.afterUpdate();
11826
11827			return me.minSize;
11828
11829		},
11830		afterUpdate: function() {
11831			helpers.callback(this.options.afterUpdate, [this]);
11832		},
11833
11834		//
11835
11836		beforeSetDimensions: function() {
11837			helpers.callback(this.options.beforeSetDimensions, [this]);
11838		},
11839		setDimensions: function() {
11840			var me = this;
11841			// Set the unconstrained dimension before label rotation
11842			if (me.isHorizontal()) {
11843				// Reset position before calculating rotation
11844				me.width = me.maxWidth;
11845				me.left = 0;
11846				me.right = me.width;
11847			} else {
11848				me.height = me.maxHeight;
11849
11850				// Reset position before calculating rotation
11851				me.top = 0;
11852				me.bottom = me.height;
11853			}
11854
11855			// Reset padding
11856			me.paddingLeft = 0;
11857			me.paddingTop = 0;
11858			me.paddingRight = 0;
11859			me.paddingBottom = 0;
11860		},
11861		afterSetDimensions: function() {
11862			helpers.callback(this.options.afterSetDimensions, [this]);
11863		},
11864
11865		// Data limits
11866		beforeDataLimits: function() {
11867			helpers.callback(this.options.beforeDataLimits, [this]);
11868		},
11869		determineDataLimits: helpers.noop,
11870		afterDataLimits: function() {
11871			helpers.callback(this.options.afterDataLimits, [this]);
11872		},
11873
11874		//
11875		beforeBuildTicks: function() {
11876			helpers.callback(this.options.beforeBuildTicks, [this]);
11877		},
11878		buildTicks: helpers.noop,
11879		afterBuildTicks: function() {
11880			helpers.callback(this.options.afterBuildTicks, [this]);
11881		},
11882
11883		beforeTickToLabelConversion: function() {
11884			helpers.callback(this.options.beforeTickToLabelConversion, [this]);
11885		},
11886		convertTicksToLabels: function() {
11887			var me = this;
11888			// Convert ticks to strings
11889			var tickOpts = me.options.ticks;
11890			me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
11891		},
11892		afterTickToLabelConversion: function() {
11893			helpers.callback(this.options.afterTickToLabelConversion, [this]);
11894		},
11895
11896		//
11897
11898		beforeCalculateTickRotation: function() {
11899			helpers.callback(this.options.beforeCalculateTickRotation, [this]);
11900		},
11901		calculateTickRotation: function() {
11902			var me = this;
11903			var context = me.ctx;
11904			var tickOpts = me.options.ticks;
11905			var labels = labelsFromTicks(me._ticks);
11906
11907			// Get the width of each grid by calculating the difference
11908			// between x offsets between 0 and 1.
11909			var tickFont = parseFontOptions(tickOpts);
11910			context.font = tickFont.font;
11911
11912			var labelRotation = tickOpts.minRotation || 0;
11913
11914			if (labels.length && me.options.display && me.isHorizontal()) {
11915				var originalLabelWidth = helpers.longestText(context, tickFont.font, labels, me.longestTextCache);
11916				var labelWidth = originalLabelWidth;
11917				var cosRotation, sinRotation;
11918
11919				// Allow 3 pixels x2 padding either side for label readability
11920				var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
11921
11922				// Max label rotation can be set or default to 90 - also act as a loop counter
11923				while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
11924					var angleRadians = helpers.toRadians(labelRotation);
11925					cosRotation = Math.cos(angleRadians);
11926					sinRotation = Math.sin(angleRadians);
11927
11928					if (sinRotation * originalLabelWidth > me.maxHeight) {
11929						// go back one step
11930						labelRotation--;
11931						break;
11932					}
11933
11934					labelRotation++;
11935					labelWidth = cosRotation * originalLabelWidth;
11936				}
11937			}
11938
11939			me.labelRotation = labelRotation;
11940		},
11941		afterCalculateTickRotation: function() {
11942			helpers.callback(this.options.afterCalculateTickRotation, [this]);
11943		},
11944
11945		//
11946
11947		beforeFit: function() {
11948			helpers.callback(this.options.beforeFit, [this]);
11949		},
11950		fit: function() {
11951			var me = this;
11952			// Reset
11953			var minSize = me.minSize = {
11954				width: 0,
11955				height: 0
11956			};
11957
11958			var labels = labelsFromTicks(me._ticks);
11959
11960			var opts = me.options;
11961			var tickOpts = opts.ticks;
11962			var scaleLabelOpts = opts.scaleLabel;
11963			var gridLineOpts = opts.gridLines;
11964			var display = opts.display;
11965			var isHorizontal = me.isHorizontal();
11966
11967			var tickFont = parseFontOptions(tickOpts);
11968			var tickMarkLength = opts.gridLines.tickMarkLength;
11969
11970			// Width
11971			if (isHorizontal) {
11972				// subtract the margins to line up with the chartArea if we are a full width scale
11973				minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
11974			} else {
11975				minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
11976			}
11977
11978			// height
11979			if (isHorizontal) {
11980				minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
11981			} else {
11982				minSize.height = me.maxHeight; // fill all the height
11983			}
11984
11985			// Are we showing a title for the scale?
11986			if (scaleLabelOpts.display && display) {
11987				var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);
11988				var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding);
11989				var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height;
11990
11991				if (isHorizontal) {
11992					minSize.height += deltaHeight;
11993				} else {
11994					minSize.width += deltaHeight;
11995				}
11996			}
11997
11998			// Don't bother fitting the ticks if we are not showing them
11999			if (tickOpts.display && display) {
12000				var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, labels, me.longestTextCache);
12001				var tallestLabelHeightInLines = helpers.numberOfLabelLines(labels);
12002				var lineSpace = tickFont.size * 0.5;
12003				var tickPadding = me.options.ticks.padding;
12004
12005				if (isHorizontal) {
12006					// A horizontal axis is more constrained by the height.
12007					me.longestLabelWidth = largestTextWidth;
12008
12009					var angleRadians = helpers.toRadians(me.labelRotation);
12010					var cosRotation = Math.cos(angleRadians);
12011					var sinRotation = Math.sin(angleRadians);
12012
12013					// TODO - improve this calculation
12014					var labelHeight = (sinRotation * largestTextWidth)
12015						+ (tickFont.size * tallestLabelHeightInLines)
12016						+ (lineSpace * (tallestLabelHeightInLines - 1))
12017						+ lineSpace; // padding
12018
12019					minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
12020
12021					me.ctx.font = tickFont.font;
12022					var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font);
12023					var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font);
12024
12025					// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
12026					// which means that the right padding is dominated by the font height
12027					if (me.labelRotation !== 0) {
12028						me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
12029						me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3;
12030					} else {
12031						me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
12032						me.paddingRight = lastLabelWidth / 2 + 3;
12033					}
12034				} else {
12035					// A vertical axis is more constrained by the width. Labels are the
12036					// dominant factor here, so get that length first and account for padding
12037					if (tickOpts.mirror) {
12038						largestTextWidth = 0;
12039					} else {
12040						// use lineSpace for consistency with horizontal axis
12041						// tickPadding is not implemented for horizontal
12042						largestTextWidth += tickPadding + lineSpace;
12043					}
12044
12045					minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
12046
12047					me.paddingTop = tickFont.size / 2;
12048					me.paddingBottom = tickFont.size / 2;
12049				}
12050			}
12051
12052			me.handleMargins();
12053
12054			me.width = minSize.width;
12055			me.height = minSize.height;
12056		},
12057
12058		/**
12059		 * Handle margins and padding interactions
12060		 * @private
12061		 */
12062		handleMargins: function() {
12063			var me = this;
12064			if (me.margins) {
12065				me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
12066				me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
12067				me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
12068				me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
12069			}
12070		},
12071
12072		afterFit: function() {
12073			helpers.callback(this.options.afterFit, [this]);
12074		},
12075
12076		// Shared Methods
12077		isHorizontal: function() {
12078			return this.options.position === 'top' || this.options.position === 'bottom';
12079		},
12080		isFullWidth: function() {
12081			return (this.options.fullWidth);
12082		},
12083
12084		// 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
12085		getRightValue: function(rawValue) {
12086			// Null and undefined values first
12087			if (helpers.isNullOrUndef(rawValue)) {
12088				return NaN;
12089			}
12090			// isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
12091			if (typeof rawValue === 'number' && !isFinite(rawValue)) {
12092				return NaN;
12093			}
12094			// If it is in fact an object, dive in one more level
12095			if (rawValue) {
12096				if (this.isHorizontal()) {
12097					if (rawValue.x !== undefined) {
12098						return this.getRightValue(rawValue.x);
12099					}
12100				} else if (rawValue.y !== undefined) {
12101					return this.getRightValue(rawValue.y);
12102				}
12103			}
12104
12105			// Value is good, return it
12106			return rawValue;
12107		},
12108
12109		/**
12110		 * Used to get the value to display in the tooltip for the data at the given index
12111		 * @param index
12112		 * @param datasetIndex
12113		 */
12114		getLabelForIndex: helpers.noop,
12115
12116		/**
12117		 * Returns the location of the given data point. Value can either be an index or a numerical value
12118		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12119		 * @param value
12120		 * @param index
12121		 * @param datasetIndex
12122		 */
12123		getPixelForValue: helpers.noop,
12124
12125		/**
12126		 * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
12127		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12128		 * @param pixel
12129		 */
12130		getValueForPixel: helpers.noop,
12131
12132		/**
12133		 * Returns the location of the tick at the given index
12134		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12135		 */
12136		getPixelForTick: function(index) {
12137			var me = this;
12138			var offset = me.options.offset;
12139			if (me.isHorizontal()) {
12140				var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
12141				var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
12142				var pixel = (tickWidth * index) + me.paddingLeft;
12143
12144				if (offset) {
12145					pixel += tickWidth / 2;
12146				}
12147
12148				var finalVal = me.left + Math.round(pixel);
12149				finalVal += me.isFullWidth() ? me.margins.left : 0;
12150				return finalVal;
12151			}
12152			var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
12153			return me.top + (index * (innerHeight / (me._ticks.length - 1)));
12154		},
12155
12156		/**
12157		 * Utility for getting the pixel location of a percentage of scale
12158		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12159		 */
12160		getPixelForDecimal: function(decimal) {
12161			var me = this;
12162			if (me.isHorizontal()) {
12163				var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
12164				var valueOffset = (innerWidth * decimal) + me.paddingLeft;
12165
12166				var finalVal = me.left + Math.round(valueOffset);
12167				finalVal += me.isFullWidth() ? me.margins.left : 0;
12168				return finalVal;
12169			}
12170			return me.top + (decimal * me.height);
12171		},
12172
12173		/**
12174		 * Returns the pixel for the minimum chart value
12175		 * The coordinate (0, 0) is at the upper-left corner of the canvas
12176		 */
12177		getBasePixel: function() {
12178			return this.getPixelForValue(this.getBaseValue());
12179		},
12180
12181		getBaseValue: function() {
12182			var me = this;
12183			var min = me.min;
12184			var max = me.max;
12185
12186			return me.beginAtZero ? 0 :
12187				min < 0 && max < 0 ? max :
12188				min > 0 && max > 0 ? min :
12189				0;
12190		},
12191
12192		/**
12193		 * Returns a subset of ticks to be plotted to avoid overlapping labels.
12194		 * @private
12195		 */
12196		_autoSkip: function(ticks) {
12197			var skipRatio;
12198			var me = this;
12199			var isHorizontal = me.isHorizontal();
12200			var optionTicks = me.options.ticks.minor;
12201			var tickCount = ticks.length;
12202			var labelRotationRadians = helpers.toRadians(me.labelRotation);
12203			var cosRotation = Math.cos(labelRotationRadians);
12204			var longestRotatedLabel = me.longestLabelWidth * cosRotation;
12205			var result = [];
12206			var i, tick, shouldSkip;
12207
12208			// figure out the maximum number of gridlines to show
12209			var maxTicks;
12210			if (optionTicks.maxTicksLimit) {
12211				maxTicks = optionTicks.maxTicksLimit;
12212			}
12213
12214			if (isHorizontal) {
12215				skipRatio = false;
12216
12217				if ((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount > (me.width - (me.paddingLeft + me.paddingRight))) {
12218					skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount) / (me.width - (me.paddingLeft + me.paddingRight)));
12219				}
12220
12221				// if they defined a max number of optionTicks,
12222				// increase skipRatio until that number is met
12223				if (maxTicks && tickCount > maxTicks) {
12224					skipRatio = Math.max(skipRatio, Math.floor(tickCount / maxTicks));
12225				}
12226			}
12227
12228			for (i = 0; i < tickCount; i++) {
12229				tick = ticks[i];
12230
12231				// Since we always show the last tick,we need may need to hide the last shown one before
12232				shouldSkip = (skipRatio > 1 && i % skipRatio > 0) || (i % skipRatio === 0 && i + skipRatio >= tickCount);
12233				if (shouldSkip && i !== tickCount - 1) {
12234					// leave tick in place but make sure it's not displayed (#4635)
12235					delete tick.label;
12236				}
12237				result.push(tick);
12238			}
12239			return result;
12240		},
12241
12242		// Actually draw the scale on the canvas
12243		// @param {rectangle} chartArea : the area of the chart to draw full grid lines on
12244		draw: function(chartArea) {
12245			var me = this;
12246			var options = me.options;
12247			if (!options.display) {
12248				return;
12249			}
12250
12251			var context = me.ctx;
12252			var globalDefaults = defaults.global;
12253			var optionTicks = options.ticks.minor;
12254			var optionMajorTicks = options.ticks.major || optionTicks;
12255			var gridLines = options.gridLines;
12256			var scaleLabel = options.scaleLabel;
12257
12258			var isRotated = me.labelRotation !== 0;
12259			var isHorizontal = me.isHorizontal();
12260
12261			var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
12262			var tickFontColor = helpers.valueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
12263			var tickFont = parseFontOptions(optionTicks);
12264			var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor);
12265			var majorTickFont = parseFontOptions(optionMajorTicks);
12266
12267			var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
12268
12269			var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
12270			var scaleLabelFont = parseFontOptions(scaleLabel);
12271			var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
12272			var labelRotationRadians = helpers.toRadians(me.labelRotation);
12273
12274			var itemsToDraw = [];
12275
12276			var axisWidth = me.options.gridLines.lineWidth;
12277			var xTickStart = options.position === 'right' ? me.right : me.right - axisWidth - tl;
12278			var xTickEnd = options.position === 'right' ? me.right + tl : me.right;
12279			var yTickStart = options.position === 'bottom' ? me.top + axisWidth : me.bottom - tl - axisWidth;
12280			var yTickEnd = options.position === 'bottom' ? me.top + axisWidth + tl : me.bottom + axisWidth;
12281
12282			helpers.each(ticks, function(tick, index) {
12283				// autoskipper skipped this tick (#4635)
12284				if (helpers.isNullOrUndef(tick.label)) {
12285					return;
12286				}
12287
12288				var label = tick.label;
12289				var lineWidth, lineColor, borderDash, borderDashOffset;
12290				if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
12291					// Draw the first index specially
12292					lineWidth = gridLines.zeroLineWidth;
12293					lineColor = gridLines.zeroLineColor;
12294					borderDash = gridLines.zeroLineBorderDash;
12295					borderDashOffset = gridLines.zeroLineBorderDashOffset;
12296				} else {
12297					lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, index);
12298					lineColor = helpers.valueAtIndexOrDefault(gridLines.color, index);
12299					borderDash = helpers.valueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
12300					borderDashOffset = helpers.valueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
12301				}
12302
12303				// Common properties
12304				var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
12305				var textAlign = 'middle';
12306				var textBaseline = 'middle';
12307				var tickPadding = optionTicks.padding;
12308
12309				if (isHorizontal) {
12310					var labelYOffset = tl + tickPadding;
12311
12312					if (options.position === 'bottom') {
12313						// bottom
12314						textBaseline = !isRotated ? 'top' : 'middle';
12315						textAlign = !isRotated ? 'center' : 'right';
12316						labelY = me.top + labelYOffset;
12317					} else {
12318						// top
12319						textBaseline = !isRotated ? 'bottom' : 'middle';
12320						textAlign = !isRotated ? 'center' : 'left';
12321						labelY = me.bottom - labelYOffset;
12322					}
12323
12324					var xLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
12325					if (xLineValue < me.left) {
12326						lineColor = 'rgba(0,0,0,0)';
12327					}
12328					xLineValue += helpers.aliasPixel(lineWidth);
12329
12330					labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
12331
12332					tx1 = tx2 = x1 = x2 = xLineValue;
12333					ty1 = yTickStart;
12334					ty2 = yTickEnd;
12335					y1 = chartArea.top;
12336					y2 = chartArea.bottom + axisWidth;
12337				} else {
12338					var isLeft = options.position === 'left';
12339					var labelXOffset;
12340
12341					if (optionTicks.mirror) {
12342						textAlign = isLeft ? 'left' : 'right';
12343						labelXOffset = tickPadding;
12344					} else {
12345						textAlign = isLeft ? 'right' : 'left';
12346						labelXOffset = tl + tickPadding;
12347					}
12348
12349					labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
12350
12351					var yLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
12352					if (yLineValue < me.top) {
12353						lineColor = 'rgba(0,0,0,0)';
12354					}
12355					yLineValue += helpers.aliasPixel(lineWidth);
12356
12357					labelY = me.getPixelForTick(index) + optionTicks.labelOffset;
12358
12359					tx1 = xTickStart;
12360					tx2 = xTickEnd;
12361					x1 = chartArea.left;
12362					x2 = chartArea.right + axisWidth;
12363					ty1 = ty2 = y1 = y2 = yLineValue;
12364				}
12365
12366				itemsToDraw.push({
12367					tx1: tx1,
12368					ty1: ty1,
12369					tx2: tx2,
12370					ty2: ty2,
12371					x1: x1,
12372					y1: y1,
12373					x2: x2,
12374					y2: y2,
12375					labelX: labelX,
12376					labelY: labelY,
12377					glWidth: lineWidth,
12378					glColor: lineColor,
12379					glBorderDash: borderDash,
12380					glBorderDashOffset: borderDashOffset,
12381					rotation: -1 * labelRotationRadians,
12382					label: label,
12383					major: tick.major,
12384					textBaseline: textBaseline,
12385					textAlign: textAlign
12386				});
12387			});
12388
12389			// Draw all of the tick labels, tick marks, and grid lines at the correct places
12390			helpers.each(itemsToDraw, function(itemToDraw) {
12391				if (gridLines.display) {
12392					context.save();
12393					context.lineWidth = itemToDraw.glWidth;
12394					context.strokeStyle = itemToDraw.glColor;
12395					if (context.setLineDash) {
12396						context.setLineDash(itemToDraw.glBorderDash);
12397						context.lineDashOffset = itemToDraw.glBorderDashOffset;
12398					}
12399
12400					context.beginPath();
12401
12402					if (gridLines.drawTicks) {
12403						context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
12404						context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
12405					}
12406
12407					if (gridLines.drawOnChartArea) {
12408						context.moveTo(itemToDraw.x1, itemToDraw.y1);
12409						context.lineTo(itemToDraw.x2, itemToDraw.y2);
12410					}
12411
12412					context.stroke();
12413					context.restore();
12414				}
12415
12416				if (optionTicks.display) {
12417					// Make sure we draw text in the correct color and font
12418					context.save();
12419					context.translate(itemToDraw.labelX, itemToDraw.labelY);
12420					context.rotate(itemToDraw.rotation);
12421					context.font = itemToDraw.major ? majorTickFont.font : tickFont.font;
12422					context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
12423					context.textBaseline = itemToDraw.textBaseline;
12424					context.textAlign = itemToDraw.textAlign;
12425
12426					var label = itemToDraw.label;
12427					if (helpers.isArray(label)) {
12428						var lineCount = label.length;
12429						var lineHeight = tickFont.size * 1.5;
12430						var y = me.isHorizontal() ? 0 : -lineHeight * (lineCount - 1) / 2;
12431
12432						for (var i = 0; i < lineCount; ++i) {
12433							// We just make sure the multiline element is a string here..
12434							context.fillText('' + label[i], 0, y);
12435							// apply same lineSpacing as calculated @ L#320
12436							y += lineHeight;
12437						}
12438					} else {
12439						context.fillText(label, 0, 0);
12440					}
12441					context.restore();
12442				}
12443			});
12444
12445			if (scaleLabel.display) {
12446				// Draw the scale label
12447				var scaleLabelX;
12448				var scaleLabelY;
12449				var rotation = 0;
12450				var halfLineHeight = parseLineHeight(scaleLabel) / 2;
12451
12452				if (isHorizontal) {
12453					scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
12454					scaleLabelY = options.position === 'bottom'
12455						? me.bottom - halfLineHeight - scaleLabelPadding.bottom
12456						: me.top + halfLineHeight + scaleLabelPadding.top;
12457				} else {
12458					var isLeft = options.position === 'left';
12459					scaleLabelX = isLeft
12460						? me.left + halfLineHeight + scaleLabelPadding.top
12461						: me.right - halfLineHeight - scaleLabelPadding.top;
12462					scaleLabelY = me.top + ((me.bottom - me.top) / 2);
12463					rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
12464				}
12465
12466				context.save();
12467				context.translate(scaleLabelX, scaleLabelY);
12468				context.rotate(rotation);
12469				context.textAlign = 'center';
12470				context.textBaseline = 'middle';
12471				context.fillStyle = scaleLabelFontColor; // render in correct colour
12472				context.font = scaleLabelFont.font;
12473				context.fillText(scaleLabel.labelString, 0, 0);
12474				context.restore();
12475			}
12476
12477			if (gridLines.drawBorder) {
12478				// Draw the line at the edge of the axis
12479				context.lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0);
12480				context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0);
12481				var x1 = me.left;
12482				var x2 = me.right + axisWidth;
12483				var y1 = me.top;
12484				var y2 = me.bottom + axisWidth;
12485
12486				var aliasPixel = helpers.aliasPixel(context.lineWidth);
12487				if (isHorizontal) {
12488					y1 = y2 = options.position === 'top' ? me.bottom : me.top;
12489					y1 += aliasPixel;
12490					y2 += aliasPixel;
12491				} else {
12492					x1 = x2 = options.position === 'left' ? me.right : me.left;
12493					x1 += aliasPixel;
12494					x2 += aliasPixel;
12495				}
12496
12497				context.beginPath();
12498				context.moveTo(x1, y1);
12499				context.lineTo(x2, y2);
12500				context.stroke();
12501			}
12502		}
12503	});
12504};
12505
12506},{"25":25,"26":26,"34":34,"45":45}],33:[function(require,module,exports){
12507'use strict';
12508
12509var defaults = require(25);
12510var helpers = require(45);
12511var layouts = require(30);
12512
12513module.exports = function(Chart) {
12514
12515	Chart.scaleService = {
12516		// Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
12517		// use the new chart options to grab the correct scale
12518		constructors: {},
12519		// Use a registration function so that we can move to an ES6 map when we no longer need to support
12520		// old browsers
12521
12522		// Scale config defaults
12523		defaults: {},
12524		registerScaleType: function(type, scaleConstructor, scaleDefaults) {
12525			this.constructors[type] = scaleConstructor;
12526			this.defaults[type] = helpers.clone(scaleDefaults);
12527		},
12528		getScaleConstructor: function(type) {
12529			return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
12530		},
12531		getScaleDefaults: function(type) {
12532			// Return the scale defaults merged with the global settings so that we always use the latest ones
12533			return this.defaults.hasOwnProperty(type) ? helpers.merge({}, [defaults.scale, this.defaults[type]]) : {};
12534		},
12535		updateScaleDefaults: function(type, additions) {
12536			var me = this;
12537			if (me.defaults.hasOwnProperty(type)) {
12538				me.defaults[type] = helpers.extend(me.defaults[type], additions);
12539			}
12540		},
12541		addScalesToLayout: function(chart) {
12542			// Adds each scale to the chart.boxes array to be sized accordingly
12543			helpers.each(chart.scales, function(scale) {
12544				// Set ILayoutItem parameters for backwards compatibility
12545				scale.fullWidth = scale.options.fullWidth;
12546				scale.position = scale.options.position;
12547				scale.weight = scale.options.weight;
12548				layouts.addBox(chart, scale);
12549			});
12550		}
12551	};
12552};
12553
12554},{"25":25,"30":30,"45":45}],34:[function(require,module,exports){
12555'use strict';
12556
12557var helpers = require(45);
12558
12559/**
12560 * Namespace to hold static tick generation functions
12561 * @namespace Chart.Ticks
12562 */
12563module.exports = {
12564	/**
12565	 * Namespace to hold formatters for different types of ticks
12566	 * @namespace Chart.Ticks.formatters
12567	 */
12568	formatters: {
12569		/**
12570		 * Formatter for value labels
12571		 * @method Chart.Ticks.formatters.values
12572		 * @param value the value to display
12573		 * @return {String|Array} the label to display
12574		 */
12575		values: function(value) {
12576			return helpers.isArray(value) ? value : '' + value;
12577		},
12578
12579		/**
12580		 * Formatter for linear numeric ticks
12581		 * @method Chart.Ticks.formatters.linear
12582		 * @param tickValue {Number} the value to be formatted
12583		 * @param index {Number} the position of the tickValue parameter in the ticks array
12584		 * @param ticks {Array<Number>} the list of ticks being converted
12585		 * @return {String} string representation of the tickValue parameter
12586		 */
12587		linear: function(tickValue, index, ticks) {
12588			// If we have lots of ticks, don't use the ones
12589			var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
12590
12591			// If we have a number like 2.5 as the delta, figure out how many decimal places we need
12592			if (Math.abs(delta) > 1) {
12593				if (tickValue !== Math.floor(tickValue)) {
12594					// not an integer
12595					delta = tickValue - Math.floor(tickValue);
12596				}
12597			}
12598
12599			var logDelta = helpers.log10(Math.abs(delta));
12600			var tickString = '';
12601
12602			if (tickValue !== 0) {
12603				var numDecimal = -1 * Math.floor(logDelta);
12604				numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
12605				tickString = tickValue.toFixed(numDecimal);
12606			} else {
12607				tickString = '0'; // never show decimal places for 0
12608			}
12609
12610			return tickString;
12611		},
12612
12613		logarithmic: function(tickValue, index, ticks) {
12614			var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue))));
12615
12616			if (tickValue === 0) {
12617				return '0';
12618			} else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
12619				return tickValue.toExponential();
12620			}
12621			return '';
12622		}
12623	}
12624};
12625
12626},{"45":45}],35:[function(require,module,exports){
12627'use strict';
12628
12629var defaults = require(25);
12630var Element = require(26);
12631var helpers = require(45);
12632
12633defaults._set('global', {
12634	tooltips: {
12635		enabled: true,
12636		custom: null,
12637		mode: 'nearest',
12638		position: 'average',
12639		intersect: true,
12640		backgroundColor: 'rgba(0,0,0,0.8)',
12641		titleFontStyle: 'bold',
12642		titleSpacing: 2,
12643		titleMarginBottom: 6,
12644		titleFontColor: '#fff',
12645		titleAlign: 'left',
12646		bodySpacing: 2,
12647		bodyFontColor: '#fff',
12648		bodyAlign: 'left',
12649		footerFontStyle: 'bold',
12650		footerSpacing: 2,
12651		footerMarginTop: 6,
12652		footerFontColor: '#fff',
12653		footerAlign: 'left',
12654		yPadding: 6,
12655		xPadding: 6,
12656		caretPadding: 2,
12657		caretSize: 5,
12658		cornerRadius: 6,
vendor: 11,404 bytes, lines 12659-13033
12659		multiKeyBackground: '#fff',
12660		displayColors: true,
12661		borderColor: 'rgba(0,0,0,0)',
12662		borderWidth: 0,
12663		callbacks: {
12664			// Args are: (tooltipItems, data)
12665			beforeTitle: helpers.noop,
12666			title: function(tooltipItems, data) {
12667				// Pick first xLabel for now
12668				var title = '';
12669				var labels = data.labels;
12670				var labelCount = labels ? labels.length : 0;
12671
12672				if (tooltipItems.length > 0) {
12673					var item = tooltipItems[0];
12674
12675					if (item.xLabel) {
12676						title = item.xLabel;
12677					} else if (labelCount > 0 && item.index < labelCount) {
12678						title = labels[item.index];
12679					}
12680				}
12681
12682				return title;
12683			},
12684			afterTitle: helpers.noop,
12685
12686			// Args are: (tooltipItems, data)
12687			beforeBody: helpers.noop,
12688
12689			// Args are: (tooltipItem, data)
12690			beforeLabel: helpers.noop,
12691			label: function(tooltipItem, data) {
12692				var label = data.datasets[tooltipItem.datasetIndex].label || '';
12693
12694				if (label) {
12695					label += ': ';
12696				}
12697				label += tooltipItem.yLabel;
12698				return label;
12699			},
12700			labelColor: function(tooltipItem, chart) {
12701				var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
12702				var activeElement = meta.data[tooltipItem.index];
12703				var view = activeElement._view;
12704				return {
12705					borderColor: view.borderColor,
12706					backgroundColor: view.backgroundColor
12707				};
12708			},
12709			labelTextColor: function() {
12710				return this._options.bodyFontColor;
12711			},
12712			afterLabel: helpers.noop,
12713
12714			// Args are: (tooltipItems, data)
12715			afterBody: helpers.noop,
12716
12717			// Args are: (tooltipItems, data)
12718			beforeFooter: helpers.noop,
12719			footer: helpers.noop,
12720			afterFooter: helpers.noop
12721		}
12722	}
12723});
12724
12725module.exports = function(Chart) {
12726
12727	/**
12728 	 * Helper method to merge the opacity into a color
12729 	 */
12730	function mergeOpacity(colorString, opacity) {
12731		var color = helpers.color(colorString);
12732		return color.alpha(opacity * color.alpha()).rgbaString();
12733	}
12734
12735	// Helper to push or concat based on if the 2nd parameter is an array or not
12736	function pushOrConcat(base, toPush) {
12737		if (toPush) {
12738			if (helpers.isArray(toPush)) {
12739				// base = base.concat(toPush);
12740				Array.prototype.push.apply(base, toPush);
12741			} else {
12742				base.push(toPush);
12743			}
12744		}
12745
12746		return base;
12747	}
12748
12749	// Private helper to create a tooltip item model
12750	// @param element : the chart element (point, arc, bar) to create the tooltip item for
12751	// @return : new tooltip item
12752	function createTooltipItem(element) {
12753		var xScale = element._xScale;
12754		var yScale = element._yScale || element._scale; // handle radar || polarArea charts
12755		var index = element._index;
12756		var datasetIndex = element._datasetIndex;
12757
12758		return {
12759			xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
12760			yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
12761			index: index,
12762			datasetIndex: datasetIndex,
12763			x: element._model.x,
12764			y: element._model.y
12765		};
12766	}
12767
12768	/**
12769	 * Helper to get the reset model for the tooltip
12770	 * @param tooltipOpts {Object} the tooltip options
12771	 */
12772	function getBaseModel(tooltipOpts) {
12773		var globalDefaults = defaults.global;
12774		var valueOrDefault = helpers.valueOrDefault;
12775
12776		return {
12777			// Positioning
12778			xPadding: tooltipOpts.xPadding,
12779			yPadding: tooltipOpts.yPadding,
12780			xAlign: tooltipOpts.xAlign,
12781			yAlign: tooltipOpts.yAlign,
12782
12783			// Body
12784			bodyFontColor: tooltipOpts.bodyFontColor,
12785			_bodyFontFamily: valueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
12786			_bodyFontStyle: valueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
12787			_bodyAlign: tooltipOpts.bodyAlign,
12788			bodyFontSize: valueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
12789			bodySpacing: tooltipOpts.bodySpacing,
12790
12791			// Title
12792			titleFontColor: tooltipOpts.titleFontColor,
12793			_titleFontFamily: valueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
12794			_titleFontStyle: valueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
12795			titleFontSize: valueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
12796			_titleAlign: tooltipOpts.titleAlign,
12797			titleSpacing: tooltipOpts.titleSpacing,
12798			titleMarginBottom: tooltipOpts.titleMarginBottom,
12799
12800			// Footer
12801			footerFontColor: tooltipOpts.footerFontColor,
12802			_footerFontFamily: valueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
12803			_footerFontStyle: valueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
12804			footerFontSize: valueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
12805			_footerAlign: tooltipOpts.footerAlign,
12806			footerSpacing: tooltipOpts.footerSpacing,
12807			footerMarginTop: tooltipOpts.footerMarginTop,
12808
12809			// Appearance
12810			caretSize: tooltipOpts.caretSize,
12811			cornerRadius: tooltipOpts.cornerRadius,
12812			backgroundColor: tooltipOpts.backgroundColor,
12813			opacity: 0,
12814			legendColorBackground: tooltipOpts.multiKeyBackground,
12815			displayColors: tooltipOpts.displayColors,
12816			borderColor: tooltipOpts.borderColor,
12817			borderWidth: tooltipOpts.borderWidth
12818		};
12819	}
12820
12821	/**
12822	 * Get the size of the tooltip
12823	 */
12824	function getTooltipSize(tooltip, model) {
12825		var ctx = tooltip._chart.ctx;
12826
12827		var height = model.yPadding * 2; // Tooltip Padding
12828		var width = 0;
12829
12830		// Count of all lines in the body
12831		var body = model.body;
12832		var combinedBodyLength = body.reduce(function(count, bodyItem) {
12833			return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
12834		}, 0);
12835		combinedBodyLength += model.beforeBody.length + model.afterBody.length;
12836
12837		var titleLineCount = model.title.length;
12838		var footerLineCount = model.footer.length;
12839		var titleFontSize = model.titleFontSize;
12840		var bodyFontSize = model.bodyFontSize;
12841		var footerFontSize = model.footerFontSize;
12842
12843		height += titleLineCount * titleFontSize; // Title Lines
12844		height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
12845		height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
12846		height += combinedBodyLength * bodyFontSize; // Body Lines
12847		height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
12848		height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
12849		height += footerLineCount * (footerFontSize); // Footer Lines
12850		height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
12851
12852		// Title width
12853		var widthPadding = 0;
12854		var maxLineWidth = function(line) {
12855			width = Math.max(width, ctx.measureText(line).width + widthPadding);
12856		};
12857
12858		ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
12859		helpers.each(model.title, maxLineWidth);
12860
12861		// Body width
12862		ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
12863		helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
12864
12865		// Body lines may include some extra width due to the color box
12866		widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
12867		helpers.each(body, function(bodyItem) {
12868			helpers.each(bodyItem.before, maxLineWidth);
12869			helpers.each(bodyItem.lines, maxLineWidth);
12870			helpers.each(bodyItem.after, maxLineWidth);
12871		});
12872
12873		// Reset back to 0
12874		widthPadding = 0;
12875
12876		// Footer width
12877		ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
12878		helpers.each(model.footer, maxLineWidth);
12879
12880		// Add padding
12881		width += 2 * model.xPadding;
12882
12883		return {
12884			width: width,
12885			height: height
12886		};
12887	}
12888
12889	/**
12890	 * Helper to get the alignment of a tooltip given the size
12891	 */
12892	function determineAlignment(tooltip, size) {
12893		var model = tooltip._model;
12894		var chart = tooltip._chart;
12895		var chartArea = tooltip._chart.chartArea;
12896		var xAlign = 'center';
12897		var yAlign = 'center';
12898
12899		if (model.y < size.height) {
12900			yAlign = 'top';
12901		} else if (model.y > (chart.height - size.height)) {
12902			yAlign = 'bottom';
12903		}
12904
12905		var lf, rf; // functions to determine left, right alignment
12906		var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
12907		var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
12908		var midX = (chartArea.left + chartArea.right) / 2;
12909		var midY = (chartArea.top + chartArea.bottom) / 2;
12910
12911		if (yAlign === 'center') {
12912			lf = function(x) {
12913				return x <= midX;
12914			};
12915			rf = function(x) {
12916				return x > midX;
12917			};
12918		} else {
12919			lf = function(x) {
12920				return x <= (size.width / 2);
12921			};
12922			rf = function(x) {
12923				return x >= (chart.width - (size.width / 2));
12924			};
12925		}
12926
12927		olf = function(x) {
12928			return x + size.width + model.caretSize + model.caretPadding > chart.width;
12929		};
12930		orf = function(x) {
12931			return x - size.width - model.caretSize - model.caretPadding < 0;
12932		};
12933		yf = function(y) {
12934			return y <= midY ? 'top' : 'bottom';
12935		};
12936
12937		if (lf(model.x)) {
12938			xAlign = 'left';
12939
12940			// Is tooltip too wide and goes over the right side of the chart.?
12941			if (olf(model.x)) {
12942				xAlign = 'center';
12943				yAlign = yf(model.y);
12944			}
12945		} else if (rf(model.x)) {
12946			xAlign = 'right';
12947
12948			// Is tooltip too wide and goes outside left edge of canvas?
12949			if (orf(model.x)) {
12950				xAlign = 'center';
12951				yAlign = yf(model.y);
12952			}
12953		}
12954
12955		var opts = tooltip._options;
12956		return {
12957			xAlign: opts.xAlign ? opts.xAlign : xAlign,
12958			yAlign: opts.yAlign ? opts.yAlign : yAlign
12959		};
12960	}
12961
12962	/**
12963	 * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
12964	 */
12965	function getBackgroundPoint(vm, size, alignment, chart) {
12966		// Background Position
12967		var x = vm.x;
12968		var y = vm.y;
12969
12970		var caretSize = vm.caretSize;
12971		var caretPadding = vm.caretPadding;
12972		var cornerRadius = vm.cornerRadius;
12973		var xAlign = alignment.xAlign;
12974		var yAlign = alignment.yAlign;
12975		var paddingAndSize = caretSize + caretPadding;
12976		var radiusAndPadding = cornerRadius + caretPadding;
12977
12978		if (xAlign === 'right') {
12979			x -= size.width;
12980		} else if (xAlign === 'center') {
12981			x -= (size.width / 2);
12982			if (x + size.width > chart.width) {
12983				x = chart.width - size.width;
12984			}
12985			if (x < 0) {
12986				x = 0;
12987			}
12988		}
12989
12990		if (yAlign === 'top') {
12991			y += paddingAndSize;
12992		} else if (yAlign === 'bottom') {
12993			y -= size.height + paddingAndSize;
12994		} else {
12995			y -= (size.height / 2);
12996		}
12997
12998		if (yAlign === 'center') {
12999			if (xAlign === 'left') {
13000				x += paddingAndSize;
13001			} else if (xAlign === 'right') {
13002				x -= paddingAndSize;
13003			}
13004		} else if (xAlign === 'left') {
13005			x -= radiusAndPadding;
13006		} else if (xAlign === 'right') {
13007			x += radiusAndPadding;
13008		}
13009
13010		return {
13011			x: x,
13012			y: y
13013		};
13014	}
13015
13016	Chart.Tooltip = Element.extend({
13017		initialize: function() {
13018			this._model = getBaseModel(this._options);
13019			this._lastActive = [];
13020		},
13021
13022		// Get the title
13023		// Args are: (tooltipItem, data)
13024		getTitle: function() {
13025			var me = this;
13026			var opts = me._options;
13027			var callbacks = opts.callbacks;
13028
13029			var beforeTitle = callbacks.beforeTitle.apply(me, arguments);
13030			var title = callbacks.title.apply(me, arguments);
13031			var afterTitle = callbacks.afterTitle.apply(me, arguments);
13032
13033			var lines = [];
13034			lines = pushOrConcat(lines, beforeTitle);
13035			lines = pushOrConcat(lines, title);
13036			lines = pushOrConcat(lines, afterTitle);
13037
13038			return lines;
13039		},
13040
13041		// Args are: (tooltipItem, data)
13042		getBeforeBody: function() {
13043			var lines = this._options.callbacks.beforeBody.apply(this, arguments);
13044			return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
13045		},
13046
13047		// Args are: (tooltipItem, data)
13048		getBody: function(tooltipItems, data) {
13049			var me = this;
13050			var callbacks = me._options.callbacks;
13051			var bodyItems = [];
13052
13053			helpers.each(tooltipItems, function(tooltipItem) {
13054				var bodyItem = {
13055					before: [],
13056					lines: [],
13057					after: []
13058				};
13059				pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
13060				pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
13061				pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));
13062
13063				bodyItems.push(bodyItem);
13064			});
13065
13066			return bodyItems;
13067		},
13068
13069		// Args are: (tooltipItem, data)
13070		getAfterBody: function() {
13071			var lines = this._options.callbacks.afterBody.apply(this, arguments);
13072			return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
13073		},
13074
13075		// Get the footer and beforeFooter and afterFooter lines
13076		// Args are: (tooltipItem, data)
13077		getFooter: function() {
13078			var me = this;
13079			var callbacks = me._options.callbacks;
13080
13081			var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
13082			var footer = callbacks.footer.apply(me, arguments);
13083			var afterFooter = callbacks.afterFooter.apply(me, arguments);
13084
13085			var lines = [];
13086			lines = pushOrConcat(lines, beforeFooter);
13087			lines = pushOrConcat(lines, footer);
13088			lines = pushOrConcat(lines, afterFooter);
13089
13090			return lines;
13091		},
13092
13093		update: function(changed) {
13094			var me = this;
13095			var opts = me._options;
13096
13097			// Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
13098			// 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
13099			// which breaks any animations.
13100			var existingModel = me._model;
13101			var model = me._model = getBaseModel(opts);
13102			var active = me._active;
13103
13104			var data = me._data;
13105
13106			// In the case where active.length === 0 we need to keep these at existing values for good animations
13107			var alignment = {
13108				xAlign: existingModel.xAlign,
13109				yAlign: existingModel.yAlign
13110			};
13111			var backgroundPoint = {
13112				x: existingModel.x,
13113				y: existingModel.y
13114			};
13115			var tooltipSize = {
13116				width: existingModel.width,
13117				height: existingModel.height
13118			};
13119			var tooltipPosition = {
13120				x: existingModel.caretX,
13121				y: existingModel.caretY
13122			};
13123
13124			var i, len;
13125
13126			if (active.length) {
13127				model.opacity = 1;
13128
13129				var labelColors = [];
13130				var labelTextColors = [];
13131				tooltipPosition = Chart.Tooltip.positioners[opts.position].call(me, active, me._eventPosition);
13132
13133				var tooltipItems = [];
13134				for (i = 0, len = active.length; i < len; ++i) {
13135					tooltipItems.push(createTooltipItem(active[i]));
13136				}
13137
13138				// If the user provided a filter function, use it to modify the tooltip items
13139				if (opts.filter) {
13140					tooltipItems = tooltipItems.filter(function(a) {
13141						return opts.filter(a, data);
13142					});
13143				}
13144
13145				// If the user provided a sorting function, use it to modify the tooltip items
13146				if (opts.itemSort) {
13147					tooltipItems = tooltipItems.sort(function(a, b) {
13148						return opts.itemSort(a, b, data);
13149					});
13150				}
13151
13152				// Determine colors for boxes
13153				helpers.each(tooltipItems, function(tooltipItem) {
13154					labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
13155					labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart));
13156				});
13157
13158
13159				// Build the Text Lines
13160				model.title = me.getTitle(tooltipItems, data);
13161				model.beforeBody = me.getBeforeBody(tooltipItems, data);
13162				model.body = me.getBody(tooltipItems, data);
13163				model.afterBody = me.getAfterBody(tooltipItems, data);
13164				model.footer = me.getFooter(tooltipItems, data);
13165
13166				// Initial positioning and colors
13167				model.x = Math.round(tooltipPosition.x);
13168				model.y = Math.round(tooltipPosition.y);
13169				model.caretPadding = opts.caretPadding;
13170				model.labelColors = labelColors;
13171				model.labelTextColors = labelTextColors;
13172
13173				// data points
13174				model.dataPoints = tooltipItems;
13175
13176				// We need to determine alignment of the tooltip
13177				tooltipSize = getTooltipSize(this, model);
13178				alignment = determineAlignment(this, tooltipSize);
13179				// Final Size and Position
13180				backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart);
13181			} else {
13182				model.opacity = 0;
13183			}
13184
13185			model.xAlign = alignment.xAlign;
13186			model.yAlign = alignment.yAlign;
13187			model.x = backgroundPoint.x;
13188			model.y = backgroundPoint.y;
13189			model.width = tooltipSize.width;
13190			model.height = tooltipSize.height;
13191
13192			// Point where the caret on the tooltip points to
13193			model.caretX = tooltipPosition.x;
13194			model.caretY = tooltipPosition.y;
13195
13196			me._model = model;
13197
13198			if (changed && opts.custom) {
13199				opts.custom.call(me, model);
13200			}
13201
13202			return me;
13203		},
13204		drawCaret: function(tooltipPoint, size) {
13205			var ctx = this._chart.ctx;
13206			var vm = this._view;
13207			var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
13208
13209			ctx.lineTo(caretPosition.x1, caretPosition.y1);
13210			ctx.lineTo(caretPosition.x2, caretPosition.y2);
13211			ctx.lineTo(caretPosition.x3, caretPosition.y3);
13212		},
13213		getCaretPosition: function(tooltipPoint, size, vm) {
13214			var x1, x2, x3, y1, y2, y3;
13215			var caretSize = vm.caretSize;
13216			var cornerRadius = vm.cornerRadius;
13217			var xAlign = vm.xAlign;
13218			var yAlign = vm.yAlign;
13219			var ptX = tooltipPoint.x;
13220			var ptY = tooltipPoint.y;
13221			var width = size.width;
13222			var height = size.height;
13223
13224			if (yAlign === 'center') {
13225				y2 = ptY + (height / 2);
13226
13227				if (xAlign === 'left') {
13228					x1 = ptX;
13229					x2 = x1 - caretSize;
13230					x3 = x1;
13231
13232					y1 = y2 + caretSize;
13233					y3 = y2 - caretSize;
13234				} else {
13235					x1 = ptX + width;
13236					x2 = x1 + caretSize;
13237					x3 = x1;
13238
13239					y1 = y2 - caretSize;
13240					y3 = y2 + caretSize;
13241				}
13242			} else {
13243				if (xAlign === 'left') {
13244					x2 = ptX + cornerRadius + (caretSize);
13245					x1 = x2 - caretSize;
13246					x3 = x2 + caretSize;
13247				} else if (xAlign === 'right') {
13248					x2 = ptX + width - cornerRadius - caretSize;
13249					x1 = x2 - caretSize;
13250					x3 = x2 + caretSize;
13251				} else {
13252					x2 = vm.caretX;
13253					x1 = x2 - caretSize;
13254					x3 = x2 + caretSize;
13255				}
13256				if (yAlign === 'top') {
13257					y1 = ptY;
13258					y2 = y1 - caretSize;
13259					y3 = y1;
13260				} else {
13261					y1 = ptY + height;
13262					y2 = y1 + caretSize;
13263					y3 = y1;
13264					// invert drawing order
13265					var tmp = x3;
13266					x3 = x1;
13267					x1 = tmp;
13268				}
13269			}
13270			return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
13271		},
13272		drawTitle: function(pt, vm, ctx, opacity) {
13273			var title = vm.title;
13274
13275			if (title.length) {
13276				ctx.textAlign = vm._titleAlign;
13277				ctx.textBaseline = 'top';
13278
13279				var titleFontSize = vm.titleFontSize;
13280				var titleSpacing = vm.titleSpacing;
13281
13282				ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
13283				ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
13284
13285				var i, len;
13286				for (i = 0, len = title.length; i < len; ++i) {
13287					ctx.fillText(title[i], pt.x, pt.y);
13288					pt.y += titleFontSize + titleSpacing; // Line Height and spacing
13289
13290					if (i + 1 === title.length) {
13291						pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
13292					}
13293				}
13294			}
13295		},
13296		drawBody: function(pt, vm, ctx, opacity) {
13297			var bodyFontSize = vm.bodyFontSize;
13298			var bodySpacing = vm.bodySpacing;
13299			var body = vm.body;
13300
13301			ctx.textAlign = vm._bodyAlign;
13302			ctx.textBaseline = 'top';
13303			ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
13304
13305			// Before Body
13306			var xLinePadding = 0;
13307			var fillLineOfText = function(line) {
13308				ctx.fillText(line, pt.x + xLinePadding, pt.y);
13309				pt.y += bodyFontSize + bodySpacing;
13310			};
13311
13312			// Before body lines
13313			ctx.fillStyle = mergeOpacity(vm.bodyFontColor, opacity);
13314			helpers.each(vm.beforeBody, fillLineOfText);
13315
13316			var drawColorBoxes = vm.displayColors;
13317			xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
13318
13319			// Draw body lines now
13320			helpers.each(body, function(bodyItem, i) {
13321				var textColor = mergeOpacity(vm.labelTextColors[i], opacity);
13322				ctx.fillStyle = textColor;
13323				helpers.each(bodyItem.before, fillLineOfText);
13324
13325				helpers.each(bodyItem.lines, function(line) {
13326					// Draw Legend-like boxes if needed
13327					if (drawColorBoxes) {
13328						// Fill a white rect so that colours merge nicely if the opacity is < 1
13329						ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
13330						ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
13331
13332						// Border
13333						ctx.lineWidth = 1;
13334						ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
13335						ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
13336
13337						// Inner square
13338						ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
13339						ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
13340						ctx.fillStyle = textColor;
13341					}
13342
13343					fillLineOfText(line);
13344				});
13345
13346				helpers.each(bodyItem.after, fillLineOfText);
13347			});
13348
13349			// Reset back to 0 for after body
13350			xLinePadding = 0;
13351
13352			// After body lines
13353			helpers.each(vm.afterBody, fillLineOfText);
13354			pt.y -= bodySpacing; // Remove last body spacing
13355		},
13356		drawFooter: function(pt, vm, ctx, opacity) {
13357			var footer = vm.footer;
13358
13359			if (footer.length) {
13360				pt.y += vm.footerMarginTop;
13361
13362				ctx.textAlign = vm._footerAlign;
13363				ctx.textBaseline = 'top';
13364
13365				ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
13366				ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
13367
13368				helpers.each(footer, function(line) {
13369					ctx.fillText(line, pt.x, pt.y);
13370					pt.y += vm.footerFontSize + vm.footerSpacing;
13371				});
13372			}
13373		},
13374		drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
13375			ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
13376			ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
13377			ctx.lineWidth = vm.borderWidth;
13378			var xAlign = vm.xAlign;
13379			var yAlign = vm.yAlign;
13380			var x = pt.x;
13381			var y = pt.y;
13382			var width = tooltipSize.width;
13383			var height = tooltipSize.height;
13384			var radius = vm.cornerRadius;
13385
13386			ctx.beginPath();
13387			ctx.moveTo(x + radius, y);
13388			if (yAlign === 'top') {
13389				this.drawCaret(pt, tooltipSize);
13390			}
13391			ctx.lineTo(x + width - radius, y);
13392			ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
13393			if (yAlign === 'center' && xAlign === 'right') {
13394				this.drawCaret(pt, tooltipSize);
13395			}
13396			ctx.lineTo(x + width, y + height - radius);
13397			ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
13398			if (yAlign === 'bottom') {
13399				this.drawCaret(pt, tooltipSize);
13400			}
13401			ctx.lineTo(x + radius, y + height);
13402			ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
13403			if (yAlign === 'center' && xAlign === 'left') {
13404				this.drawCaret(pt, tooltipSize);
13405			}
13406			ctx.lineTo(x, y + radius);
13407			ctx.quadraticCurveTo(x, y, x + radius, y);
13408			ctx.closePath();
13409
13410			ctx.fill();
13411
13412			if (vm.borderWidth > 0) {
13413				ctx.stroke();
13414			}
13415		},
13416		draw: function() {
13417			var ctx = this._chart.ctx;
13418			var vm = this._view;
13419
13420			if (vm.opacity === 0) {
13421				return;
13422			}
13423
13424			var tooltipSize = {
13425				width: vm.width,
13426				height: vm.height
13427			};
13428			var pt = {
13429				x: vm.x,
13430				y: vm.y
13431			};
13432
13433			// IE11/Edge does not like very small opacities, so snap to 0
13434			var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
13435
13436			// Truthy/falsey value for empty tooltip
13437			var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
13438
13439			if (this._options.enabled && hasTooltipContent) {
13440				// Draw Background
13441				this.drawBackground(pt, vm, ctx, tooltipSize, opacity);
13442
13443				// Draw Title, Body, and Footer
13444				pt.x += vm.xPadding;
13445				pt.y += vm.yPadding;
13446
13447				// Titles
13448				this.drawTitle(pt, vm, ctx, opacity);
13449
13450				// Body
13451				this.drawBody(pt, vm, ctx, opacity);
13452
13453				// Footer
13454				this.drawFooter(pt, vm, ctx, opacity);
13455			}
13456		},
13457
13458		/**
13459		 * Handle an event
13460		 * @private
13461		 * @param {IEvent} event - The event to handle
13462		 * @returns {Boolean} true if the tooltip changed
13463		 */
13464		handleEvent: function(e) {
13465			var me = this;
13466			var options = me._options;
13467			var changed = false;
13468
13469			me._lastActive = me._lastActive || [];
13470
13471			// Find Active Elements for tooltips
13472			if (e.type === 'mouseout') {
13473				me._active = [];
13474			} else {
13475				me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
13476			}
13477
13478			// Remember Last Actives
13479			changed = !helpers.arrayEquals(me._active, me._lastActive);
13480
13481			// Only handle target event on tooltip change
13482			if (changed) {
13483				me._lastActive = me._active;
13484
13485				if (options.enabled || options.custom) {
13486					me._eventPosition = {
13487						x: e.x,
13488						y: e.y
13489					};
13490
13491					me.update(true);
13492					me.pivot();
13493				}
13494			}
13495
13496			return changed;
13497		}
13498	});
13499
13500	/**
13501	 * @namespace Chart.Tooltip.positioners
13502	 */
13503	Chart.Tooltip.positioners = {
13504		/**
13505		 * Average mode places the tooltip at the average position of the elements shown
13506		 * @function Chart.Tooltip.positioners.average
13507		 * @param elements {ChartElement[]} the elements being displayed in the tooltip
13508		 * @returns {Point} tooltip position
13509		 */
13510		average: function(elements) {
13511			if (!elements.length) {
13512				return false;
13513			}
13514
13515			var i, len;
13516			var x = 0;
13517			var y = 0;
13518			var count = 0;
13519
13520			for (i = 0, len = elements.length; i < len; ++i) {
13521				var el = elements[i];
13522				if (el && el.hasValue()) {
13523					var pos = el.tooltipPosition();
13524					x += pos.x;
13525					y += pos.y;
13526					++count;
13527				}
13528			}
13529
13530			return {
13531				x: Math.round(x / count),
13532				y: Math.round(y / count)
13533			};
13534		},
13535
13536		/**
13537		 * Gets the tooltip position nearest of the item nearest to the event position
13538		 * @function Chart.Tooltip.positioners.nearest
13539		 * @param elements {Chart.Element[]} the tooltip elements
13540		 * @param eventPosition {Point} the position of the event in canvas coordinates
13541		 * @returns {Point} the tooltip position
13542		 */
13543		nearest: function(elements, eventPosition) {
13544			var x = eventPosition.x;
13545			var y = eventPosition.y;
13546			var minDistance = Number.POSITIVE_INFINITY;
13547			var i, len, nearestElement;
13548
13549			for (i = 0, len = elements.length; i < len; ++i) {
13550				var el = elements[i];
13551				if (el && el.hasValue()) {
13552					var center = el.getCenterPoint();
13553					var d = helpers.distanceBetweenPoints(eventPosition, center);
13554
13555					if (d < minDistance) {
13556						minDistance = d;
13557						nearestElement = el;
13558					}
13559				}
13560			}
13561
13562			if (nearestElement) {
13563				var tp = nearestElement.tooltipPosition();
13564				x = tp.x;
13565				y = tp.y;
13566			}
13567
13568			return {
13569				x: x,
13570				y: y
13571			};
13572		}
13573	};
13574};
13575
13576},{"25":25,"26":26,"45":45}],36:[function(require,module,exports){
13577'use strict';
13578
13579var defaults = require(25);
13580var Element = require(26);
13581var helpers = require(45);
13582
13583defaults._set('global', {
13584	elements: {
13585		arc: {
13586			backgroundColor: defaults.global.defaultColor,
13587			borderColor: '#fff',
13588			borderWidth: 2
13589		}
13590	}
13591});
13592
13593module.exports = Element.extend({
13594	inLabelRange: function(mouseX) {
13595		var vm = this._view;
13596
13597		if (vm) {
13598			return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
13599		}
13600		return false;
13601	},
13602
13603	inRange: function(chartX, chartY) {
13604		var vm = this._view;
13605
13606		if (vm) {
13607			var pointRelativePosition = helpers.getAngleFromPoint(vm, {x: chartX, y: chartY});
13608			var	angle = pointRelativePosition.angle;
13609			var distance = pointRelativePosition.distance;
13610
13611			// Sanitise angle range
13612			var startAngle = vm.startAngle;
13613			var endAngle = vm.endAngle;
13614			while (endAngle < startAngle) {
13615				endAngle += 2.0 * Math.PI;
13616			}
13617			while (angle > endAngle) {
13618				angle -= 2.0 * Math.PI;
13619			}
13620			while (angle < startAngle) {
13621				angle += 2.0 * Math.PI;
13622			}
13623
13624			// Check if within the range of the open/close angle
13625			var betweenAngles = (angle >= startAngle && angle <= endAngle);
13626			var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
13627
13628			return (betweenAngles && withinRadius);
13629		}
13630		return false;
13631	},
13632
13633	getCenterPoint: function() {
13634		var vm = this._view;
13635		var halfAngle = (vm.startAngle + vm.endAngle) / 2;
13636		var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
13637		return {
13638			x: vm.x + Math.cos(halfAngle) * halfRadius,
13639			y: vm.y + Math.sin(halfAngle) * halfRadius
13640		};
13641	},
13642
13643	getArea: function() {
13644		var vm = this._view;
13645		return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
13646	},
13647
13648	tooltipPosition: function() {
13649		var vm = this._view;
13650		var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
13651		var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
13652
13653		return {
13654			x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
13655			y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
13656		};
13657	},
13658
13659	draw: function() {
13660		var ctx = this._chart.ctx;
13661		var vm = this._view;
13662		var sA = vm.startAngle;
13663		var eA = vm.endAngle;
13664
13665		ctx.beginPath();
13666
13667		ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
13668		ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
13669
13670		ctx.closePath();
13671		ctx.strokeStyle = vm.borderColor;
13672		ctx.lineWidth = vm.borderWidth;
13673
13674		ctx.fillStyle = vm.backgroundColor;
13675
13676		ctx.fill();
13677		ctx.lineJoin = 'bevel';
13678
13679		if (vm.borderWidth) {
13680			ctx.stroke();
13681		}
13682	}
13683});
13684
13685},{"25":25,"26":26,"45":45}],37:[function(require,module,exports){
13686'use strict';
13687
13688var defaults = require(25);
13689var Element = require(26);
13690var helpers = require(45);
13691
13692var globalDefaults = defaults.global;
13693
13694defaults._set('global', {
13695	elements: {
13696		line: {
13697			tension: 0.4,
13698			backgroundColor: globalDefaults.defaultColor,
13699			borderWidth: 3,
13700			borderColor: globalDefaults.defaultColor,
13701			borderCapStyle: 'butt',
13702			borderDash: [],
13703			borderDashOffset: 0.0,
13704			borderJoinStyle: 'miter',
13705			capBezierPoints: true,
13706			fill: true, // do we fill in the area between the line and its base axis
13707		}
13708	}
13709});
13710
13711module.exports = Element.extend({
13712	draw: function() {
13713		var me = this;
13714		var vm = me._view;
13715		var ctx = me._chart.ctx;
13716		var spanGaps = vm.spanGaps;
13717		var points = me._children.slice(); // clone array
13718		var globalOptionLineElements = globalDefaults.elements.line;
13719		var lastDrawnIndex = -1;
13720		var index, current, previous, currentVM;
13721
13722		// If we are looping, adding the first point again
13723		if (me._loop && points.length) {
13724			points.push(points[0]);
13725		}
13726
13727		ctx.save();
13728
13729		// Stroke Line Options
13730		ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
13731
13732		// IE 9 and 10 do not support line dash
13733		if (ctx.setLineDash) {
13734			ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
13735		}
13736
13737		ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
13738		ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
13739		ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
13740		ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
13741
13742		// Stroke Line
13743		ctx.beginPath();
13744		lastDrawnIndex = -1;
13745
13746		for (index = 0; index < points.length; ++index) {
13747			current = points[index];
13748			previous = helpers.previousItem(points, index);
13749			currentVM = current._view;
13750
13751			// First point moves to it's starting position no matter what
13752			if (index === 0) {
13753				if (!currentVM.skip) {
13754					ctx.moveTo(currentVM.x, currentVM.y);
13755					lastDrawnIndex = index;
13756				}
13757			} else {
13758				previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
13759
13760				if (!currentVM.skip) {
13761					if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
13762						// There was a gap and this is the first point after the gap
13763						ctx.moveTo(currentVM.x, currentVM.y);
13764					} else {
13765						// Line to next point
13766						helpers.canvas.lineTo(ctx, previous._view, current._view);
13767					}
13768					lastDrawnIndex = index;
13769				}
13770			}
13771		}
13772
13773		ctx.stroke();
13774		ctx.restore();
13775	}
13776});
13777
13778},{"25":25,"26":26,"45":45}],38:[function(require,module,exports){
13779'use strict';
13780
13781var defaults = require(25);
13782var Element = require(26);
13783var helpers = require(45);
13784
13785var defaultColor = defaults.global.defaultColor;
13786
13787defaults._set('global', {
13788	elements: {
13789		point: {
13790			radius: 3,
13791			pointStyle: 'circle',
13792			backgroundColor: defaultColor,
13793			borderColor: defaultColor,
13794			borderWidth: 1,
13795			// Hover
13796			hitRadius: 1,
13797			hoverRadius: 4,
13798			hoverBorderWidth: 1
13799		}
13800	}
13801});
13802
13803function xRange(mouseX) {
13804	var vm = this._view;
13805	return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false;
13806}
13807
13808function yRange(mouseY) {
13809	var vm = this._view;
13810	return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false;
13811}
13812
13813module.exports = Element.extend({
13814	inRange: function(mouseX, mouseY) {
13815		var vm = this._view;
13816		return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
13817	},
13818
13819	inLabelRange: xRange,
13820	inXRange: xRange,
13821	inYRange: yRange,
13822
13823	getCenterPoint: function() {
13824		var vm = this._view;
13825		return {
13826			x: vm.x,
13827			y: vm.y
13828		};
13829	},
13830
13831	getArea: function() {
13832		return Math.PI * Math.pow(this._view.radius, 2);
13833	},
13834
13835	tooltipPosition: function() {
13836		var vm = this._view;
13837		return {
13838			x: vm.x,
13839			y: vm.y,
13840			padding: vm.radius + vm.borderWidth
13841		};
13842	},
13843
13844	draw: function(chartArea) {
13845		var vm = this._view;
13846		var model = this._model;
13847		var ctx = this._chart.ctx;
13848		var pointStyle = vm.pointStyle;
13849		var radius = vm.radius;
13850		var x = vm.x;
13851		var y = vm.y;
13852		var color = helpers.color;
13853		var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
13854		var ratio = 0;
13855
13856		if (vm.skip) {
13857			return;
13858		}
13859
13860		ctx.strokeStyle = vm.borderColor || defaultColor;
13861		ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth);
13862		ctx.fillStyle = vm.backgroundColor || defaultColor;
13863
13864		// Cliping for Points.
13865		// going out from inner charArea?
13866		if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right * errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom * errMargin < model.y))) {
13867			// Point fade out
13868			if (model.x < chartArea.left) {
13869				ratio = (x - model.x) / (chartArea.left - model.x);
13870			} else if (chartArea.right * errMargin < model.x) {
13871				ratio = (model.x - x) / (model.x - chartArea.right);
13872			} else if (model.y < chartArea.top) {
13873				ratio = (y - model.y) / (chartArea.top - model.y);
13874			} else if (chartArea.bottom * errMargin < model.y) {
13875				ratio = (model.y - y) / (model.y - chartArea.bottom);
13876			}
13877			ratio = Math.round(ratio * 100) / 100;
13878			ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
13879			ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
13880		}
13881
13882		helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y);
13883	}
13884});
13885
13886},{"25":25,"26":26,"45":45}],39:[function(require,module,exports){
13887'use strict';
13888
13889var defaults = require(25);
13890var Element = require(26);
13891
13892defaults._set('global', {
13893	elements: {
13894		rectangle: {
13895			backgroundColor: defaults.global.defaultColor,
13896			borderColor: defaults.global.defaultColor,
13897			borderSkipped: 'bottom',
13898			borderWidth: 0
13899		}
13900	}
13901});
13902
13903function isVertical(bar) {
13904	return bar._view.width !== undefined;
13905}
13906
13907/**
13908 * Helper function to get the bounds of the bar regardless of the orientation
13909 * @param bar {Chart.Element.Rectangle} the bar
13910 * @return {Bounds} bounds of the bar
13911 * @private
13912 */
13913function getBarBounds(bar) {
13914	var vm = bar._view;
13915	var x1, x2, y1, y2;
13916
13917	if (isVertical(bar)) {
13918		// vertical
13919		var halfWidth = vm.width / 2;
13920		x1 = vm.x - halfWidth;
13921		x2 = vm.x + halfWidth;
13922		y1 = Math.min(vm.y, vm.base);
13923		y2 = Math.max(vm.y, vm.base);
13924	} else {
13925		// horizontal bar
13926		var halfHeight = vm.height / 2;
13927		x1 = Math.min(vm.x, vm.base);
13928		x2 = Math.max(vm.x, vm.base);
13929		y1 = vm.y - halfHeight;
13930		y2 = vm.y + halfHeight;
13931	}
13932
13933	return {
13934		left: x1,
13935		top: y1,
13936		right: x2,
13937		bottom: y2
13938	};
13939}
13940
13941module.exports = Element.extend({
13942	draw: function() {
13943		var ctx = this._chart.ctx;
13944		var vm = this._view;
13945		var left, right, top, bottom, signX, signY, borderSkipped;
13946		var borderWidth = vm.borderWidth;
13947
13948		if (!vm.horizontal) {
13949			// bar
13950			left = vm.x - vm.width / 2;
13951			right = vm.x + vm.width / 2;
13952			top = vm.y;
13953			bottom = vm.base;
13954			signX = 1;
13955			signY = bottom > top ? 1 : -1;
13956			borderSkipped = vm.borderSkipped || 'bottom';
13957		} else {
13958			// horizontal bar
13959			left = vm.base;
13960			right = vm.x;
13961			top = vm.y - vm.height / 2;
13962			bottom = vm.y + vm.height / 2;
13963			signX = right > left ? 1 : -1;
13964			signY = 1;
13965			borderSkipped = vm.borderSkipped || 'left';
13966		}
13967
13968		// Canvas doesn't allow us to stroke inside the width so we can
13969		// adjust the sizes to fit if we're setting a stroke on the line
13970		if (borderWidth) {
13971			// borderWidth shold be less than bar width and bar height.
13972			var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
13973			borderWidth = borderWidth > barSize ? barSize : borderWidth;
13974			var halfStroke = borderWidth / 2;
13975			// Adjust borderWidth when bar top position is near vm.base(zero).
13976			var borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
13977			var borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
13978			var borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
13979			var borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
13980			// not become a vertical line?
13981			if (borderLeft !== borderRight) {
13982				top = borderTop;
13983				bottom = borderBottom;
13984			}
13985			// not become a horizontal line?
13986			if (borderTop !== borderBottom) {
13987				left = borderLeft;
13988				right = borderRight;
13989			}
13990		}
13991
13992		ctx.beginPath();
13993		ctx.fillStyle = vm.backgroundColor;
13994		ctx.strokeStyle = vm.borderColor;
13995		ctx.lineWidth = borderWidth;
13996
13997		// Corner points, from bottom-left to bottom-right clockwise
13998		// | 1 2 |
13999		// | 0 3 |
14000		var corners = [
14001			[left, bottom],
14002			[left, top],
14003			[right, top],
14004			[right, bottom]
14005		];
14006
14007		// Find first (starting) corner with fallback to 'bottom'
14008		var borders = ['bottom', 'left', 'top', 'right'];
14009		var startCorner = borders.indexOf(borderSkipped, 0);
14010		if (startCorner === -1) {
14011			startCorner = 0;
14012		}
14013
14014		function cornerAt(index) {
14015			return corners[(startCorner + index) % 4];
14016		}
14017
14018		// Draw rectangle from 'startCorner'
14019		var corner = cornerAt(0);
14020		ctx.moveTo(corner[0], corner[1]);
14021
14022		for (var i = 1; i < 4; i++) {
14023			corner = cornerAt(i);
14024			ctx.lineTo(corner[0], corner[1]);
14025		}
14026
14027		ctx.fill();
14028		if (borderWidth) {
14029			ctx.stroke();
14030		}
14031	},
14032
14033	height: function() {
14034		var vm = this._view;
14035		return vm.base - vm.y;
14036	},
14037
14038	inRange: function(mouseX, mouseY) {
14039		var inRange = false;
14040
14041		if (this._view) {
14042			var bounds = getBarBounds(this);
14043			inRange = mouseX >
14043= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
14044		}
14045
14046		return inRange;
14047	},
14048
14049	inLabelRange: function(mouseX, mouseY) {
14050		var me = this;
14051		if (!me._view) {
14052			return false;
14053		}
14054
14055		var inRange = false;
14056		var bounds = getBarBounds(me);
14057
14058		if (isVertical(me)) {
14059			inRange = mouseX >= bounds.left && mouseX <= bounds.right;
14060		} else {
14061			inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
14062		}
14063
14064		return inRange;
14065	},
14066
14067	inXRange: function(mouseX) {
14068		var bounds = getBarBounds(this);
14069		return mouseX >= bounds.left && mouseX <= bounds.right;
14070	},
14071
14072	inYRange: function(mouseY) {
14073		var bounds = getBarBounds(this);
14074		return mouseY >= bounds.top && mouseY <= bounds.bottom;
14075	},
14076
14077	getCenterPoint: function() {
14078		var vm = this._view;
14079		var x, y;
14080		if (isVertical(this)) {
14081			x = vm.x;
14082			y = (vm.y + vm.base) / 2;
14083		} else {
14084			x = (vm.x + vm.base) / 2;
14085			y = vm.y;
14086		}
14087
14088		return {x: x, y: y};
14089	},
14090
14091	getArea: function() {
14092		var vm = this._view;
14093		return vm.width * Math.abs(vm.y - vm.base);
14094	},
14095
14096	tooltipPosition: function() {
14097		var vm = this._view;
14098		return {
14099			x: vm.x,
14100			y: vm.y
14101		};
14102	}
14103});
14104
14105},{"25":25,"26":26}],40:[function(require,module,exports){
14106'use strict';
14107
14108module.exports = {};
14109module.exports.Arc = require(36);
14110module.exports.Line = require(37);
14111module.exports.Point = require(38);
14112module.exports.Rectangle = require(39);
14113
14114},{"36":36,"37":37,"38":38,"39":39}],41:[function(require,module,exports){
14115'use strict';
14116
14117var helpers = require(42);
14118
14119/**
14120 * @namespace Chart.helpers.canvas
14121 */
14122var exports = module.exports = {
14123	/**
14124	 * Clears the entire canvas associated to the given `chart`.
14125	 * @param {Chart} chart - The chart for which to clear the canvas.
14126	 */
14127	clear: function(chart) {
14128		chart.ctx.clearRect(0, 0, chart.width, chart.height);
14129	},
14130
14131	/**
14132	 * Creates a "path" for a rectangle with rounded corners at position (x, y) with a
14133	 * given size (width, height) and the same `radius` for all corners.
14134	 * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
14135	 * @param {Number} x - The x axis of the coordinate for the rectangle starting point.
14136	 * @param {Number} y - The y axis of the coordinate for the rectangle starting point.
14137	 * @param {Number} width - The rectangle's width.
14138	 * @param {Number} height - The rectangle's height.
14139	 * @param {Number} radius - The rounded amount (in pixels) for the four corners.
14140	 * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?
14141	 */
14142	roundedRect: function(ctx, x, y, width, height, radius) {
14143		if (radius) {
14144			var rx = Math.min(radius, width / 2);
14145			var ry = Math.min(radius, height / 2);
14146
14147			ctx.moveTo(x + rx, y);
14148			ctx.lineTo(x + width - rx, y);
14149			ctx.quadraticCurveTo(x + width, y, x + width, y + ry);
14150			ctx.lineTo(x + width, y + height - ry);
14151			ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height);
14152			ctx.lineTo(x + rx, y + height);
14153			ctx.quadraticCurveTo(x, y + height, x, y + height - ry);
14154			ctx.lineTo(x, y + ry);
14155			ctx.quadraticCurveTo(x, y, x + rx, y);
14156		} else {
14157			ctx.rect(x, y, width, height);
14158		}
14159	},
14160
14161	drawPoint: function(ctx, style, radius, x, y) {
14162		var type, edgeLength, xOffset, yOffset, height, size;
14163
14164		if (style && typeof style === 'object') {
14165			type = style.toString();
14166			if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
14167				ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
14168				return;
14169			}
14170		}
14171
14172		if (isNaN(radius) || radius <= 0) {
14173			return;
14174		}
14175
14176		switch (style) {
14177		// Default includes circle
14178		default:
14179			ctx.beginPath();
14180			ctx.arc(x, y, radius, 0, Math.PI * 2);
14181			ctx.closePath();
14182			ctx.fill();
14183			break;
14184		case 'triangle':
14185			ctx.beginPath();
14186			edgeLength = 3 * radius / Math.sqrt(3);
14187			height = edgeLength * Math.sqrt(3) / 2;
14188			ctx.moveTo(x - edgeLength / 2, y + height / 3);
14189			ctx.lineTo(x + edgeLength / 2, y + height / 3);
14190			ctx.lineTo(x, y - 2 * height / 3);
14191			ctx.closePath();
14192			ctx.fill();
14193			break;
14194		case 'rect':
14195			size = 1 / Math.SQRT2 * radius;
14196			ctx.beginPath();
14197			ctx.fillRect(x - size, y - size, 2 * size, 2 * size);
14198			ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
14199			break;
14200		case 'rectRounded':
14201			var offset = radius / Math.SQRT2;
14202			var leftX = x - offset;
14203			var topY = y - offset;
14204			var sideSize = Math.SQRT2 * radius;
14205			ctx.beginPath();
14206			this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2);
14207			ctx.closePath();
14208			ctx.fill();
14209			break;
14210		case 'rectRot':
14211			size = 1 / Math.SQRT2 * radius;
14212			ctx.beginPath();
14213			ctx.moveTo(x - size, y);
14214			ctx.lineTo(x, y + size);
14215			ctx.lineTo(x + size, y);
14216			ctx.lineTo(x, y - size);
14217			ctx.closePath();
14218			ctx.fill();
14219			break;
14220		case 'cross':
14221			ctx.beginPath();
14222			ctx.moveTo(x, y + radius);
14223			ctx.lineTo(x, y - radius);
14224			ctx.moveTo(x - radius, y);
14225			ctx.lineTo(x + radius, y);
14226			ctx.closePath();
14227			break;
14228		case 'crossRot':
14229			ctx.beginPath();
14230			xOffset = Math.cos(Math.PI / 4) * radius;
14231			yOffset = Math.sin(Math.PI / 4) * radius;
14232			ctx.moveTo(x - xOffset, y - yOffset);
14233			ctx.lineTo(x + xOffset, y + yOffset);
14234			ctx.moveTo(x - xOffset, y + yOffset);
14235			ctx.lineTo(x + xOffset, y - yOffset);
14236			ctx.closePath();
14237			break;
14238		case 'star':
14239			ctx.beginPath();
14240			ctx.moveTo(x, y + radius);
14241			ctx.lineTo(x, y - radius);
14242			ctx.moveTo(x - radius, y);
14243			ctx.lineTo(x + radius, y);
14244			xOffset = Math.cos(Math.PI / 4) * radius;
14245			yOffset = Math.sin(Math.PI / 4) * radius;
14246			ctx.moveTo(x - xOffset, y - yOffset);
14247			ctx.lineTo(x + xOffset, y + yOffset);
14248			ctx.moveTo(x - xOffset, y + yOffset);
14249			ctx.lineTo(x + xOffset, y - yOffset);
14250			ctx.closePath();
14251			break;
14252		case 'line':
14253			ctx.beginPath();
14254			ctx.moveTo(x - radius, y);
14255			ctx.lineTo(x + radius, y);
14256			ctx.closePath();
14257			break;
14258		case 'dash':
14259			ctx.beginPath();
14260			ctx.moveTo(x, y);
14261			ctx.lineTo(x + radius, y);
14262			ctx.closePath();
14263			break;
14264		}
14265
14266		ctx.stroke();
14267	},
14268
14269	clipArea: function(ctx, area) {
14270		ctx.save();
14271		ctx.beginPath();
14272		ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
14273		ctx.clip();
14274	},
14275
14276	unclipArea: function(ctx) {
14277		ctx.restore();
14278	},
14279
14280	lineTo: function(ctx, previous, target, flip) {
14281		if (target.steppedLine) {
14282			if ((target.steppedLine === 'after' && !flip) || (target.steppedLine !== 'after' && flip)) {
14283				ctx.lineTo(previous.x, target.y);
14284			} else {
14285				ctx.lineTo(target.x, previous.y);
14286			}
14287			ctx.lineTo(target.x, target.y);
14288			return;
14289		}
14290
14291		if (!target.tension) {
14292			ctx.lineTo(target.x, target.y);
14293			return;
14294		}
14295
14296		ctx.bezierCurveTo(
14297			flip ? previous.controlPointPreviousX : previous.controlPointNextX,
14298			flip ? previous.controlPointPreviousY : previous.controlPointNextY,
14299			flip ? target.controlPointNextX : target.controlPointPreviousX,
14300			flip ? target.controlPointNextY : target.controlPointPreviousY,
14301			target.x,
14302			target.y);
14303	}
14304};
14305
14306// DEPRECATIONS
14307
14308/**
14309 * Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
14310 * @namespace Chart.helpers.clear
14311 * @deprecated since version 2.7.0
14312 * @todo remove at version 3
14313 * @private
14314 */
14315helpers.clear = exports.clear;
14316
14317/**
14318 * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
14319 * @namespace Chart.helpers.drawRoundedRectangle
14320 * @deprecated since version 2.7.0
14321 * @todo remove at version 3
14322 * @private
14323 */
14324helpers.drawRoundedRectangle = function(ctx) {
14325	ctx.beginPath();
14326	exports.roundedRect.apply(exports, arguments);
14327	ctx.closePath();
14328};
14329
14330},{"42":42}],42:[function(require,module,exports){
14331'use strict';
14332
14333/**
14334 * @namespace Chart.helpers
14335 */
14336var helpers = {
14337	/**
14338	 * An empty function that can be used, for example, for optional callback.
14339	 */
14340	noop: function() {},
14341
14342	/**
14343	 * Returns a unique id, sequentially generated from a global variable.
14344	 * @returns {Number}
14345	 * @function
14346	 */
14347	uid: (function() {
14348		var id = 0;
14349		return function() {
14350			return id++;
14351		};
14352	}()),
14353
14354	/**
14355	 * Returns true if `value` is neither null nor undefined, else returns false.
14356	 * @param {*} value - The value to test.
14357	 * @returns {Boolean}
14358	 * @since 2.7.0
14359	 */
14360	isNullOrUndef: function(value) {
14361		return value === null || typeof value === 'undefined';
14362	},
14363
14364	/**
14365	 * Returns true if `value` is an array, else returns false.
14366	 * @param {*} value - The value to test.
14367	 * @returns {Boolean}
14368	 * @function
14369	 */
14370	isArray: Array.isArray ? Array.isArray : function(value) {
14371		return Object.prototype.toString.call(value) === '[object Array]';
14372	},
14373
14374	/**
14375	 * Returns true if `value` is an object (excluding null), else returns false.
14376	 * @param {*} value - The value to test.
14377	 * @returns {Boolean}
14378	 * @since 2.7.0
14379	 */
14380	isObject: function(value) {
14381		return value !== null && Object.prototype.toString.call(value) === '[object Object]';
14382	},
14383
14384	/**
14385	 * Returns `value` if defined, else returns `defaultValue`.
14386	 * @param {*} value - The value to return if defined.
14387	 * @param {*} defaultValue - The value to return if `value` is undefined.
14388	 * @returns {*}
14389	 */
14390	valueOrDefault: function(value, defaultValue) {
14391		return typeof value === 'undefined' ? defaultValue : value;
14392	},
14393
14394	/**
14395	 * Returns value at the given `index` in array if defined, else returns `defaultValue`.
14396	 * @param {Array} value - The array to lookup for value at `index`.
14397	 * @param {Number} index - The index in `value` to lookup for value.
14398	 * @param {*} defaultValue - The value to return if `value[index]` is undefined.
14399	 * @returns {*}
14400	 */
14401	valueAtIndexOrDefault: function(value, index, defaultValue) {
14402		return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
14403	},
14404
14405	/**
14406	 * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
14407	 * value returned by `fn`. If `fn` is not a function, this method returns undefined.
14408	 * @param {Function} fn - The function to call.
14409	 * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
14410	 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
14411	 * @returns {*}
14412	 */
14413	callback: function(fn, args, thisArg) {
14414		if (fn && typeof fn.call === 'function') {
14415			return fn.apply(thisArg, args);
14416		}
14417	},
14418
14419	/**
14420	 * Note(SB) for performance sake, this method should only be used when loopable type
14421	 * is unknown or in none intensive code (not called often and small loopable). Else
14422	 * it's preferable to use a regular for() loop and save extra function calls.
14423	 * @param {Object|Array} loopable - The object or array to be iterated.
14424	 * @param {Function} fn - The function to call for each item.
14425	 * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
14426	 * @param {Boolean} [reverse] - If true, iterates backward on the loopable.
14427	 */
14428	each: function(loopable, fn, thisArg, reverse) {
14429		var i, len, keys;
14430		if (helpers.isArray(loopable)) {
14431			len = loopable.length;
14432			if (reverse) {
14433				for (i = len - 1; i >= 0; i--) {
14434					fn.call(thisArg, loopable[i], i);
14435				}
14436			} else {
14437				for (i = 0; i < len; i++) {
14438					fn.call(thisArg, loopable[i], i);
14439				}
14440			}
14441		} else if (helpers.isObject(loopable)) {
14442			keys = Object.keys(loopable);
14443			len = keys.length;
14444			for (i = 0; i < len; i++) {
14445				fn.call(thisArg, loopable[keys[i]], keys[i]);
14446			}
14447		}
14448	},
14449
14450	/**
14451	 * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
14452	 * @see http://stackoverflow.com/a/14853974
14453	 * @param {Array} a0 - The array to compare
14454	 * @param {Array} a1 - The array to compare
14455	 * @returns {Boolean}
14456	 */
14457	arrayEquals: function(a0, a1) {
14458		var i, ilen, v0, v1;
14459
14460		if (!a0 || !a1 || a0.length !== a1.length) {
14461			return false;
14462		}
14463
14464		for (i = 0, ilen = a0.length; i < ilen; ++i) {
14465			v0 = a0[i];
14466			v1 = a1[i];
14467
14468			if (v0 instanceof Array && v1 instanceof Array) {
14469				if (!helpers.arrayEquals(v0, v1)) {
14470					return false;
14471				}
14472			} else if (v0 !== v1) {
14473				// NOTE: two different object instances will never be equal: {x:20} != {x:20}
14474				return false;
14475			}
14476		}
14477
14478		return true;
14479	},
14480
14481	/**
14482	 * Returns a deep copy of `source` without keeping references on objects and arrays.
14483	 * @param {*} source - The value to clone.
vendor: 10,304 bytes, lines 14484-14915
14484	 * @returns {*}
14485	 */
14486	clone: function(source) {
14487		if (helpers.isArray(source)) {
14488			return source.map(helpers.clone);
14489		}
14490
14491		if (helpers.isObject(source)) {
14492			var target = {};
14493			var keys = Object.keys(source);
14494			var klen = keys.length;
14495			var k = 0;
14496
14497			for (; k < klen; ++k) {
14498				target[keys[k]] = helpers.clone(source[keys[k]]);
14499			}
14500
14501			return target;
14502		}
14503
14504		return source;
14505	},
14506
14507	/**
14508	 * The default merger when Chart.helpers.merge is called without merger option.
14509	 * Note(SB): this method is also used by configMerge and scaleMerge as fallback.
14510	 * @private
14511	 */
14512	_merger: function(key, target, source, options) {
14513		var tval = target[key];
14514		var sval = source[key];
14515
14516		if (helpers.isObject(tval) && helpers.isObject(sval)) {
14517			helpers.merge(tval, sval, options);
14518		} else {
14519			target[key] = helpers.clone(sval);
14520		}
14521	},
14522
14523	/**
14524	 * Merges source[key] in target[key] only if target[key] is undefined.
14525	 * @private
14526	 */
14527	_mergerIf: function(key, target, source) {
14528		var tval = target[key];
14529		var sval = source[key];
14530
14531		if (helpers.isObject(tval) && helpers.isObject(sval)) {
14532			helpers.mergeIf(tval, sval);
14533		} else if (!target.hasOwnProperty(key)) {
14534			target[key] = helpers.clone(sval);
14535		}
14536	},
14537
14538	/**
14539	 * Recursively deep copies `source` properties into `target` with the given `options`.
14540	 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
14541	 * @param {Object} target - The target object in which all sources are merged into.
14542	 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
14543	 * @param {Object} [options] - Merging options:
14544	 * @param {Function} [options.merger] - The merge method (key, target, source, options)
14545	 * @returns {Object} The `target` object.
14546	 */
14547	merge: function(target, source, options) {
14548		var sources = helpers.isArray(source) ? source : [source];
14549		var ilen = sources.length;
14550		var merge, i, keys, klen, k;
14551
14552		if (!helpers.isObject(target)) {
14553			return target;
14554		}
14555
14556		options = options || {};
14557		merge = options.merger || helpers._merger;
14558
14559		for (i = 0; i < ilen; ++i) {
14560			source = sources[i];
14561			if (!helpers.isObject(source)) {
14562				continue;
14563			}
14564
14565			keys = Object.keys(source);
14566			for (k = 0, klen = keys.length; k < klen; ++k) {
14567				merge(keys[k], target, source, options);
14568			}
14569		}
14570
14571		return target;
14572	},
14573
14574	/**
14575	 * Recursively deep copies `source` properties into `target` *only* if not defined in target.
14576	 * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
14577	 * @param {Object} target - The target object in which all sources are merged into.
14578	 * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
14579	 * @returns {Object} The `target` object.
14580	 */
14581	mergeIf: function(target, source) {
14582		return helpers.merge(target, source, {merger: helpers._mergerIf});
14583	},
14584
14585	/**
14586	 * Applies the contents of two or more objects together into the first object.
14587	 * @param {Object} target - The target object in which all objects are merged into.
14588	 * @param {Object} arg1 - Object containing additional properties to merge in target.
14589	 * @param {Object} argN - Additional objects containing properties to merge in target.
14590	 * @returns {Object} The `target` object.
14591	 */
14592	extend: function(target) {
14593		var setFn = function(value, key) {
14594			target[key] = value;
14595		};
14596		for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
14597			helpers.each(arguments[i], setFn);
14598		}
14599		return target;
14600	},
14601
14602	/**
14603	 * Basic javascript inheritance based on the model created in Backbone.js
14604	 */
14605	inherits: function(extensions) {
14606		var me = this;
14607		var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
14608			return me.apply(this, arguments);
14609		};
14610
14611		var Surrogate = function() {
14612			this.constructor = ChartElement;
14613		};
14614
14615		Surrogate.prototype = me.prototype;
14616		ChartElement.prototype = new Surrogate();
14617		ChartElement.extend = helpers.inherits;
14618
14619		if (extensions) {
14620			helpers.extend(ChartElement.prototype, extensions);
14621		}
14622
14623		ChartElement.__super__ = me.prototype;
14624		return ChartElement;
14625	}
14626};
14627
14628module.exports = helpers;
14629
14630// DEPRECATIONS
14631
14632/**
14633 * Provided for backward compatibility, use Chart.helpers.callback instead.
14634 * @function Chart.helpers.callCallback
14635 * @deprecated since version 2.6.0
14636 * @todo remove at version 3
14637 * @private
14638 */
14639helpers.callCallback = helpers.callback;
14640
14641/**
14642 * Provided for backward compatibility, use Array.prototype.indexOf instead.
14643 * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
14644 * @function Chart.helpers.indexOf
14645 * @deprecated since version 2.7.0
14646 * @todo remove at version 3
14647 * @private
14648 */
14649helpers.indexOf = function(array, item, fromIndex) {
14650	return Array.prototype.indexOf.call(array, item, fromIndex);
14651};
14652
14653/**
14654 * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
14655 * @function Chart.helpers.getValueOrDefault
14656 * @deprecated since version 2.7.0
14657 * @todo remove at version 3
14658 * @private
14659 */
14660helpers.getValueOrDefault = helpers.valueOrDefault;
14661
14662/**
14663 * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
14664 * @function Chart.helpers.getValueAtIndexOrDefault
14665 * @deprecated since version 2.7.0
14666 * @todo remove at version 3
14667 * @private
14668 */
14669helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
14670
14671},{}],43:[function(require,module,exports){
14672'use strict';
14673
14674var helpers = require(42);
14675
14676/**
14677 * Easing functions adapted from Robert Penner's easing equations.
14678 * @namespace Chart.helpers.easingEffects
14679 * @see http://www.robertpenner.com/easing/
14680 */
14681var effects = {
14682	linear: function(t) {
14683		return t;
14684	},
14685
14686	easeInQuad: function(t) {
14687		return t * t;
14688	},
14689
14690	easeOutQuad: function(t) {
14691		return -t * (t - 2);
14692	},
14693
14694	easeInOutQuad: function(t) {
14695		if ((t /= 0.5) < 1) {
14696			return 0.5 * t * t;
14697		}
14698		return -0.5 * ((--t) * (t - 2) - 1);
14699	},
14700
14701	easeInCubic: function(t) {
14702		return t * t * t;
14703	},
14704
14705	easeOutCubic: function(t) {
14706		return (t = t - 1) * t * t + 1;
14707	},
14708
14709	easeInOutCubic: function(t) {
14710		if ((t /= 0.5) < 1) {
14711			return 0.5 * t * t * t;
14712		}
14713		return 0.5 * ((t -= 2) * t * t + 2);
14714	},
14715
14716	easeInQuart: function(t) {
14717		return t * t * t * t;
14718	},
14719
14720	easeOutQuart: function(t) {
14721		return -((t = t - 1) * t * t * t - 1);
14722	},
14723
14724	easeInOutQuart: function(t) {
14725		if ((t /= 0.5) < 1) {
14726			return 0.5 * t * t * t * t;
14727		}
14728		return -0.5 * ((t -= 2) * t * t * t - 2);
14729	},
14730
14731	easeInQuint: function(t) {
14732		return t * t * t * t * t;
14733	},
14734
14735	easeOutQuint: function(t) {
14736		return (t = t - 1) * t * t * t * t + 1;
14737	},
14738
14739	easeInOutQuint: function(t) {
14740		if ((t /= 0.5) < 1) {
14741			return 0.5 * t * t * t * t * t;
14742		}
14743		return 0.5 * ((t -= 2) * t * t * t * t + 2);
14744	},
14745
14746	easeInSine: function(t) {
14747		return -Math.cos(t * (Math.PI / 2)) + 1;
14748	},
14749
14750	easeOutSine: function(t) {
14751		return Math.sin(t * (Math.PI / 2));
14752	},
14753
14754	easeInOutSine: function(t) {
14755		return -0.5 * (Math.cos(Math.PI * t) - 1);
14756	},
14757
14758	easeInExpo: function(t) {
14759		return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
14760	},
14761
14762	easeOutExpo: function(t) {
14763		return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
14764	},
14765
14766	easeInOutExpo: function(t) {
14767		if (t === 0) {
14768			return 0;
14769		}
14770		if (t === 1) {
14771			return 1;
14772		}
14773		if ((t /= 0.5) < 1) {
14774			return 0.5 * Math.pow(2, 10 * (t - 1));
14775		}
14776		return 0.5 * (-Math.pow(2, -10 * --t) + 2);
14777	},
14778
14779	easeInCirc: function(t) {
14780		if (t >= 1) {
14781			return t;
14782		}
14783		return -(Math.sqrt(1 - t * t) - 1);
14784	},
14785
14786	easeOutCirc: function(t) {
14787		return Math.sqrt(1 - (t = t - 1) * t);
14788	},
14789
14790	easeInOutCirc: function(t) {
14791		if ((t /= 0.5) < 1) {
14792			return -0.5 * (Math.sqrt(1 - t * t) - 1);
14793		}
14794		return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
14795	},
14796
14797	easeInElastic: function(t) {
14798		var s = 1.70158;
14799		var p = 0;
14800		var a = 1;
14801		if (t === 0) {
14802			return 0;
14803		}
14804		if (t === 1) {
14805			return 1;
14806		}
14807		if (!p) {
14808			p = 0.3;
14809		}
14810		if (a < 1) {
14811			a = 1;
14812			s = p / 4;
14813		} else {
14814			s = p / (2 * Math.PI) * Math.asin(1 / a);
14815		}
14816		return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
14817	},
14818
14819	easeOutElastic: function(t) {
14820		var s = 1.70158;
14821		var p = 0;
14822		var a = 1;
14823		if (t === 0) {
14824			return 0;
14825		}
14826		if (t === 1) {
14827			return 1;
14828		}
14829		if (!p) {
14830			p = 0.3;
14831		}
14832		if (a < 1) {
14833			a = 1;
14834			s = p / 4;
14835		} else {
14836			s = p / (2 * Math.PI) * Math.asin(1 / a);
14837		}
14838		return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
14839	},
14840
14841	easeInOutElastic: function(t) {
14842		var s = 1.70158;
14843		var p = 0;
14844		var a = 1;
14845		if (t === 0) {
14846			return 0;
14847		}
14848		if ((t /= 0.5) === 2) {
14849			return 1;
14850		}
14851		if (!p) {
14852			p = 0.45;
14853		}
14854		if (a < 1) {
14855			a = 1;
14856			s = p / 4;
14857		} else {
14858			s = p / (2 * Math.PI) * Math.asin(1 / a);
14859		}
14860		if (t < 1) {
14861			return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
14862		}
14863		return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
14864	},
14865	easeInBack: function(t) {
14866		var s = 1.70158;
14867		return t * t * ((s + 1) * t - s);
14868	},
14869
14870	easeOutBack: function(t) {
14871		var s = 1.70158;
14872		return (t = t - 1) * t * ((s + 1) * t + s) + 1;
14873	},
14874
14875	easeInOutBack: function(t) {
14876		var s = 1.70158;
14877		if ((t /= 0.5) < 1) {
14878			return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
14879		}
14880		return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
14881	},
14882
14883	easeInBounce: function(t) {
14884		return 1 - effects.easeOutBounce(1 - t);
14885	},
14886
14887	easeOutBounce: function(t) {
14888		if (t < (1 / 2.75)) {
14889			return 7.5625 * t * t;
14890		}
14891		if (t < (2 / 2.75)) {
14892			return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
14893		}
14894		if (t < (2.5 / 2.75)) {
14895			return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
14896		}
14897		return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
14898	},
14899
14900	easeInOutBounce: function(t) {
14901		if (t < 0.5) {
14902			return effects.easeInBounce(t * 2) * 0.5;
14903		}
14904		return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
14905	}
14906};
14907
14908module.exports = {
14909	effects: effects
14910};
14911
14912// DEPRECATIONS
14913
14914/**
14915 * Provided for backward compatibility, use Chart.helpers.easing.effects instead.
14916 * @function Chart.helpers.easingEffects
14917 * @deprecated since version 2.7.0
14918 * @todo remove at version 3
14919 * @private
14920 */
14921helpers.easingEffects = effects;
14922
14923},{"42":42}],44:[function(require,module,exports){
14924'use strict';
14925
14926var helpers = require(42);
14927
14928/**
14929 * @alias Chart.helpers.options
14930 * @namespace
14931 */
14932module.exports = {
14933	/**
14934	 * Converts the given line height `value` in pixels for a specific font `size`.
14935	 * @param {Number|String} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
14936	 * @param {Number} size - The font size (in pixels) used to resolve relative `value`.
14937	 * @returns {Number} The effective line height in pixels (size * 1.2 if value is invalid).
14938	 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
14939	 * @since 2.7.0
14940	 */
14941	toLineHeight: function(value, size) {
14942		var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
14943		if (!matches || matches[1] === 'normal') {
14944			return size * 1.2;
14945		}
14946
14947		value = +matches[2];
14948
14949		switch (matches[3]) {
14950		case 'px':
14951			return value;
14952		case '%':
14953			value /= 100;
14954			break;
14955		default:
14956			break;
14957		}
14958
14959		return size * value;
14960	},
14961
14962	/**
14963	 * Converts the given value into a padding object with pre-computed width/height.
14964	 * @param {Number|Object} value - If a number, set the value to all TRBL component,
14965	 *  else, if and object, use defined properties and sets undefined ones to 0.
14966	 * @returns {Object} The padding values (top, right, bottom, left, width, height)
14967	 * @since 2.7.0
14968	 */
14969	toPadding: function(value) {
14970		var t, r, b, l;
14971
14972		if (helpers.isObject(value)) {
14973			t = +value.top || 0;
14974			r = +value.right || 0;
14975			b = +value.bottom || 0;
14976			l = +value.left || 0;
14977		} else {
14978			t = r = b = l = +value || 0;
14979		}
14980
14981		return {
14982			top: t,
14983			right: r,
14984			bottom: b,
14985			left: l,
14986			height: t + b,
14987			width: l + r
14988		};
14989	},
14990
14991	/**
14992	 * Evaluates the given `inputs` sequentially and returns the first defined value.
14993	 * @param {Array[]} inputs - An array of values, falling back to the last value.
14994	 * @param {Object} [context] - If defined and the current value is a function, the value
14995	 * is called with `context` as first argument and the result becomes the new input.
14996	 * @param {Number} [index] - If defined and the current value is an array, the value
14997	 * at `index` become the new input.
14998	 * @since 2.7.0
14999	 */
15000	resolve: function(inputs, context, index) {
15001		var i, ilen, value;
15002
15003		for (i = 0, ilen = inputs.length; i < ilen; ++i) {
15004			value = inputs[i];
15005			if (value === undefined) {
15006				continue;
15007			}
15008			if (context !== undefined && typeof value === 'function') {
15009				value = value(context);
15010			}
15011			if (index !== undefined && helpers.isArray(value)) {
15012				value = value[index];
15013			}
15014			if (value !== undefined) {
15015				return value;
15016			}
15017		}
15018	}
15019};
15020
15021},{"42":42}],45:[function(require,module,exports){
15022'use strict';
15023
15024module.exports = require(42);
15025module.exports.easing = require(43);
15026module.exports.canvas = require(41);
15027module.exports.options = require(44);
15028
15029},{"41":41,"42":42,"43":43,"44":44}],46:[function(require,module,exports){
15030/**
15031 * Platform fallback implementation (minimal).
15032 * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939
15033 */
15034
15035module.exports = {
15036	acquireContext: function(item) {
15037		if (item && item.canvas) {
15038			// Support for any object associated to a canvas (including a context2d)
15039			item = item.canvas;
15040		}
15041
15042		return item && item.getContext('2d') || null;
15043	}
15044};
15045
15046},{}],47:[function(require,module,exports){
15047/**
15048 * Chart.Platform implementation for targeting a web browser
15049 */
15050
15051'use strict';
15052
15053var helpers = require(45);
15054
15055var EXPANDO_KEY = '$chartjs';
15056var CSS_PREFIX = 'chartjs-';
15057var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';
15058var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';
15059var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];
15060
15061/**
15062 * DOM event types -> Chart.js event types.
15063 * Note: only events with different types are mapped.
15064 * @see https://developer.mozilla.org/en-US/docs/Web/Events
15065 */
15066var EVENT_TYPES = {
15067	touchstart: 'mousedown',
15068	touchmove: 'mousemove',
15069	touchend: 'mouseup',
15070	pointerenter: 'mouseenter',
15071	pointerdown: 'mousedown',
15072	pointermove: 'mousemove',
15073	pointerup: 'mouseup',
15074	pointerleave: 'mouseout',
15075	pointerout: 'mouseout'
15076};
15077
15078/**
15079 * The "used" size is the final value of a dimension property after all calculations have
15080 * been performed. This method uses the computed style of `element` but returns undefined
15081 * if the computed style is not expressed in pixels. That can happen in some cases where
15082 * `element` has a size relative to its parent and this last one is not yet displayed,
15083 * for example because of `display: none` on a parent node.
15084 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
15085 * @returns {Number} Size in pixels or undefined if unknown.
15086 */
15087function readUsedSize(element, property) {
15088	var value = helpers.getStyle(element, property);
15089	var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
15090	return matches ? Number(matches[1]) : undefined;
15091}
15092
15093/**
15094 * Initializes the canvas style and render size without modifying the canvas display size,
15095 * since responsiveness is handled by the controller.resize() method. The config is used
15096 * to determine the aspect ratio to apply in case no explicit height has been specified.
15097 */
15098function initCanvas(canvas, config) {
15099	var style = canvas.style;
15100
15101	// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
15102	// returns null or '' if no explicit value has been set to the canvas attribute.
15103	var renderHeight = canvas.getAttribute('height');
15104	var renderWidth = canvas.getAttribute('width');
15105
15106	// Chart.js modifies some canvas values that we want to restore on de
vendor: 4,734 bytes, lines 15106-15280
15106stroy
15107	canvas[EXPANDO_KEY] = {
15108		initial: {
15109			height: renderHeight,
15110			width: renderWidth,
15111			style: {
15112				display: style.display,
15113				height: style.height,
15114				width: style.width
15115			}
15116		}
15117	};
15118
15119	// Force canvas to display as block to avoid extra space caused by inline
15120	// elements, which would interfere with the responsive resize process.
15121	// https://github.com/chartjs/Chart.js/issues/2538
15122	style.display = style.display || 'block';
15123
15124	if (renderWidth === null || renderWidth === '') {
15125		var displayWidth = readUsedSize(canvas, 'width');
15126		if (displayWidth !== undefined) {
15127			canvas.width = displayWidth;
15128		}
15129	}
15130
15131	if (renderHeight === null || renderHeight === '') {
15132		if (canvas.style.height === '') {
15133			// If no explicit render height and style height, let's apply the aspect ratio,
15134			// which one can be specified by the user but also by charts as default option
15135			// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
15136			canvas.height = canvas.width / (config.options.aspectRatio || 2);
15137		} else {
15138			var displayHeight = readUsedSize(canvas, 'height');
15139			if (displayWidth !== undefined) {
15140				canvas.height = displayHeight;
15141			}
15142		}
15143	}
15144
15145	return canvas;
15146}
15147
15148/**
15149 * Detects support for options object argument in addEventListener.
15150 * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
15151 * @private
15152 */
15153var supportsEventListenerOptions = (function() {
15154	var supports = false;
15155	try {
15156		var options = Object.defineProperty({}, 'passive', {
15157			get: function() {
15158				supports = true;
15159			}
15160		});
15161		window.addEventListener('e', null, options);
15162	} catch (e) {
15163		// continue regardless of error
15164	}
15165	return supports;
15166}());
15167
15168// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
15169// https://github.com/chartjs/Chart.js/issues/4287
15170var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;
15171
15172function addEventListener(node, type, listener) {
15173	node.addEventListener(type, listener, eventListenerOptions);
15174}
15175
15176function removeEventListener(node, type, listener) {
15177	node.removeEventListener(type, listener, eventListenerOptions);
15178}
15179
15180function createEvent(type, chart, x, y, nativeEvent) {
15181	return {
15182		type: type,
15183		chart: chart,
15184		native: nativeEvent || null,
15185		x: x !== undefined ? x : null,
15186		y: y !== undefined ? y : null,
15187	};
15188}
15189
15190function fromNativeEvent(event, chart) {
15191	var type = EVENT_TYPES[event.type] || event.type;
15192	var pos = helpers.getRelativePosition(event, chart);
15193	return createEvent(type, chart, pos.x, pos.y, event);
15194}
15195
15196function throttled(fn, thisArg) {
15197	var ticking = false;
15198	var args = [];
15199
15200	return function() {
15201		args = Array.prototype.slice.call(arguments);
15202		thisArg = thisArg || this;
15203
15204		if (!ticking) {
15205			ticking = true;
15206			helpers.requestAnimFrame.call(window, function() {
15207				ticking = false;
15208				fn.apply(thisArg, args);
15209			});
15210		}
15211	};
15212}
15213
15214// Implementation based on https://github.com/marcj/css-element-queries
15215function createResizer(handler) {
15216	var resizer = document.createElement('div');
15217	var cls = CSS_PREFIX + 'size-monitor';
15218	var maxSize = 1000000;
15219	var style =
15220		'position:absolute;' +
15221		'left:0;' +
15222		'top:0;' +
15223		'right:0;' +
15224		'bottom:0;' +
15225		'overflow:hidden;' +
15226		'pointer-events:none;' +
15227		'visibility:hidden;' +
15228		'z-index:-1;';
15229
15230	resizer.style.cssText = style;
15231	resizer.className = cls;
15232	resizer.innerHTML =
15233		'<div class="' + cls + '-expand" style="' + style + '">' +
15234			'<div style="' +
15235				'position:absolute;' +
15236				'width:' + maxSize + 'px;' +
15237				'height:' + maxSize + 'px;' +
15238				'left:0;' +
15239				'top:0">' +
15240			'</div>' +
15241		'</div>' +
15242		'<div class="' + cls + '-shrink" style="' + style + '">' +
15243			'<div style="' +
15244				'position:absolute;' +
15245				'width:200%;' +
15246				'height:200%;' +
15247				'left:0; ' +
15248				'top:0">' +
15249			'</div>' +
15250		'</div>';
15251
15252	var expand = resizer.childNodes[0];
15253	var shrink = resizer.childNodes[1];
15254
15255	resizer._reset = function() {
15256		expand.scrollLeft = maxSize;
15257		expand.scrollTop = maxSize;
15258		shrink.scrollLeft = maxSize;
15259		shrink.scrollTop = maxSize;
15260	};
15261	var onScroll = function() {
15262		resizer._reset();
15263		handler();
15264	};
15265
15266	addEventListener(expand, 'scroll', onScroll.bind(expand, 'expand'));
15267	addEventListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));
15268
15269	return resizer;
15270}
15271
15272// https://davidwalsh.name/detect-node-insertion
15273function watchForRender(node, handler) {
15274	var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
15275	var proxy = expando.renderProxy = function(e) {
15276		if (e.animationName === CSS_RENDER_ANIMATION) {
15277			handler();
15278		}
15279	};
15280
15281	helpers.each(ANIMATION_START_EVENTS, function(type) {
15282		addEventListener(node, type, proxy);
15283	});
15284
15285	// #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class
15286	// is removed then added back immediately (same animation frame?). Accessing the
15287	// `offsetParent` property will force a reflow and re-evaluate the CSS animation.
15288	// https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics
15289	// https://github.com/chartjs/Chart.js/issues/4737
15290	expando.reflow = !!node.offsetParent;
15291
15292	node.classList.add(CSS_RENDER_MONITOR);
15293}
15294
15295function unwatchForRender(node) {
15296	var expando = node[EXPANDO_KEY] || {};
15297	var proxy = expando.renderProxy;
15298
15299	if (proxy) {
15300		helpers.each(ANIMATION_START_EVENTS, function(type) {
15301			removeEventListener(node, type, proxy);
15302		});
15303
15304		delete expando.renderProxy;
15305	}
15306
15307	node.classList.remove(CSS_RENDER_MONITOR);
15308}
15309
15310function addResizeListener(node, listener, chart) {
15311	var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
15312
15313	// Let's keep track of this added resizer and thus avoid DOM query when removing it.
15314	var resizer = expando.resizer = createResizer(throttled(function() {
15315		if (expando.resizer) {
15316			return listener(createEvent('resize', chart));
15317		}
15318	}));
15319
15320	// The resizer needs to be attached to the node parent, so we first need to be
15321	// sure that `node` is attached to the DOM before injecting the resizer element.
15322	watchForRender(node, function() {
15323		if (expando.resizer) {
15324			var container = node.parentNode;
15325			if (container && container !== resizer.parentNode) {
15326				container.insertBefore(resizer, container.firstChild);
15327			}
15328
15329			// The container size might have changed, let's reset the resizer state.
15330			resizer._reset();
15331		}
15332	});
15333}
15334
15335function removeResizeListener(node) {
15336	var expando = node[EXPANDO_KEY] || {};
15337	var resizer = expando.resizer;
15338
15339	delete expando.resizer;
15340	unwatchForRender(node);
15341
15342	if (resizer && resizer.parentNode) {
15343		resizer.parentNode.removeChild(resizer);
15344	}
15345}
15346
15347function injectCSS(platform, css) {
15348	// http://stackoverflow.com/q/3922139
15349	var style = platform._style || document.createElement('style');
15350	if (!platform._style) {
15351		platform._style = style;
15352		css = '/* Chart.js */\n' + css;
15353		style.setAttribute('type', 'text/css');
15354		document.getElementsByTagName('head')[0].appendChild(style);
15355	}
15356
15357	style.appendChild(document.createTextNode(css));
15358}
15359
15360module.exports = {
15361	/**
15362	 * This property holds whether this platform is enabled for the current environment.
15363	 * Currently used by platform.js to select the proper implementation.
15364	 * @private
15365	 */
15366	_enabled: typeof window !== 'undefined' && typeof document !== 'undefined',
15367
15368	initialize: function() {
15369		var keyframes = 'from{opacity:0.99}to{opacity:1}';
15370
15371		injectCSS(this,
15372			// DOM rendering detection
15373			// https://davidwalsh.name/detect-node-insertion
15374			'@-webkit-keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
15375			'@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
15376			'.' + CSS_RENDER_MONITOR + '{' +
15377				'-webkit-animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
15378				'animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
15379			'}'
15380		);
15381	},
15382
15383	acquireContext: function(item, config) {
15384		if (typeof item === 'string') {
15385			item = document.getElementById(item);
15386		} else if (item.length) {
15387			// Support for array based queries (such as jQuery)
15388			item = item[0];
15389		}
15390
15391		if (item && item.canvas) {
15392			// Support for any object associated to a canvas (including a context2d)
15393			item = item.canvas;
15394		}
15395
15396		// To prevent canvas fingerprinting, some add-ons undefine the getContext
15397		// method, for example: https://github.com/kkapsner/CanvasBlocker
15398		// https://github.com/chartjs/Chart.js/issues/2807
15399		var context = item && item.getContext && item.getContext('2d');
15400
15401		// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
15402		// inside an iframe or when running in a protected environment. We could guess the
15403		// types from their toString() value but let's keep things flexible and assume it's
15404		// a sufficient condition if the item has a context2D which has item as `canvas`.
15405		// https://github.com/chartjs/Chart.js/issues/3887
15406		// https://github.com/chartjs/Chart.js/issues/4102
15407		// https://github.com/chartjs/Chart.js/issues/4152
15408		if (context && context.canvas === item) {
15409			initCanvas(item, config);
15410			return context;
15411		}
15412
15413		return null;
15414	},
15415
15416	releaseContext: function(context) {
15417		var canvas = context.canvas;
15418		if (!canvas[EXPANDO_KEY]) {
15419			return;
15420		}
15421
15422		var initial = canvas[EXPANDO_KEY].initial;
15423		['height', 'width'].forEach(function(prop) {
15424			var value = initial[prop];
15425			if (helpers.isNullOrUndef(value)) {
15426				canvas.removeAttribute(prop);
15427			} else {
15428				canvas.setAttribute(prop, value);
15429			}
15430		});
15431
15432		helpers.each(initial.style || {}, function(value, key) {
15433			canvas.style[key] = value;
15434		});
15435
15436		// The canvas render size might have been changed (and thus the state stack discarded),
15437		// we can't use save() and restore() to restore the initial state. So make sure that at
15438		// least the canvas context is reset to the default state by setting the canvas width.
15439		// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
15440		canvas.width = canvas.width;
15441
15442		delete canvas[EXPANDO_KEY];
15443	},
15444
15445	addEventListener: function(chart, type, listener) {
15446		var canvas = chart.canvas;
15447		if (type === 'resize') {
15448			// Note: the resize event is not supported on all browsers.
15449			addResizeListener(canvas, listener, chart);
15450			return;
15451		}
15452
15453		var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {});
15454		var proxies = expando.proxies || (expando.proxies = {});
15455		var proxy = proxies[chart.id + '_' + type] = function(event) {
15456			listener(fromNativeEvent(event, chart));
15457		};
15458
15459		addEventListener(canvas, type, proxy);
15460	},
15461
15462	removeEventListener: function(chart, type, listener) {
15463		var canvas = chart.canvas;
15464		if (type === 'resize') {
15465			// Note: the resize event is not supported on all browsers.
15466			removeResizeListener(canvas, listener);
15467			return;
15468		}
15469
15470		var expando = listener[EXPANDO_KEY] || {};
15471		var proxies = expando.proxies || {};
15472		var proxy = proxies[chart.id + '_' + type];
15473		if (!proxy) {
15474			return;
15475		}
15476
15477		removeEventListener(canvas, type, proxy);
15478	}
15479};
15480
15481// DEPRECATIONS
15482
15483/**
15484 * Provided for backward compatibility, use EventTarget.addEventListener instead.
15485 * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
15486 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
15487 * @function Chart.helpers.addEvent
15488 * @deprecated since version 2.7.0
15489 * @todo remove at version 3
15490 * @private
15491 */
15492helpers.addEvent = addEventListener;
15493
15494/**
15495 * Provided for backward compatibility, use EventTarget.removeEventListener instead.
15496 * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
15497 * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
15498 * @function Chart.helpers.removeEvent
15499 * @deprecated since version 2.7.0
15500 * @todo remove at version 3
15501 * @private
15502 */
15503helpers.removeEvent = removeEventListener;
15504
15505},{"45":45}],48:[function(require,module,exports){
15506'use strict';
15507
15508var helpers = require(45);
15509var basic = require(46);
15510var dom = require(47);
15511
15512// @TODO Make possible to select another platform at build time.
15513var implementation = dom._enabled ? dom : basic;
15514
15515/**
15516 * @namespace Chart.platform
15517 * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
15518 * @since 2.4.0
15519 */
15520module.exports = helpers.extend({
15521	/**
15522	 * @since 2.7.0
15523	 */
15524	initialize: function() {},
15525
15526	/**
15527	 * Called at chart construction time, returns a context2d instance implementing
15528	 * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
15529	 * @param {*} item - The native item from which to acquire context (platform specific)
15530	 * @param {Object} options - The chart options
15531	 * @returns {CanvasRenderingContext2D} context2d instance
15532	 */
15533	acquireContext: function() {},
15534
15535	/**
15536	 * Called at chart destruction time, releases any resources associated to the context
15537	 * previously returned by the acquireContext() method.
15538	 * @param {CanvasRenderingContext2D} context - The context2d instance
15539	 * @returns {Boolean} true if the method succeeded, else false
15540	 */
15541	releaseContext: function() {},
15542
15543	/**
15544	 * Registers the specified listener on the given chart.
15545	 * @param {Chart} chart - Chart from which to listen for event
15546	 * @param {String} type - The ({@link IEvent}) type to listen for
15547	 * @param {Function} listener - Receives a notification (an object that implements
15548	 * the {@link IEvent} interface) when an event of the specified type occurs.
15549	 */
15550	addEventListener: function() {},
15551
15552	/**
15553	 * Removes the specified listener previously registered with addEventListener.
15554	 * @param {Chart} chart -Chart from which to remove the listener
15555	 * @param {String} type - The ({@link IEvent}) type to remove
15556	 * @param {Function} listener - The listener function to remove from the event target.
15557	 */
15558	removeEventListener: function() {}
15559
15560}, implementation);
15561
15562/**
15563 * @interface IPlatform
15564 * Allows abstracting platform dependencies away from the chart
15565 * @borrows Chart.platform.acquireContext as acquireContext
15566 * @borrows Chart.platform.releaseContext as releaseContext
15567 * @borrows Chart.platform.addEventListener as addEventListener
15568 * @borrows Chart.platform.removeEventListener as removeEventListener
15569 */
15570
15571/**
15572 * @interface IEvent
15573 * @prop {String} type - The event type name, possible values are:
15574 * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
15575 * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
15576 * @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
15577 * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
15578 * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
15579 */
15580
15581},{"45":45,"46":46,"47":47}],49:[function(require,module,exports){
15582'use strict';
15583
15584module.exports = {};
15585module.exports.filler = require(50);
15586module.exports.legend = require(51);
15587module.exports.title = require(52);
15588
15589},{"50":50,"51":51,"52":52}],50:[function(require,module,exports){
15590/**
15591 * Plugin based on discussion from the following Chart.js issues:
15592 * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569
15593 * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897
15594 */
15595
15596'use strict';
15597
15598var defaults = require(25);
15599var elements = require(40);
15600var helpers = require(45);
15601
15602defaults._set('global', {
15603	plugins: {
15604		filler: {
15605			propagate: true
15606		}
15607	}
15608});
15609
15610var mappers = {
15611	dataset: function(source) {
15612		var index = source.fill;
15613		var chart = source.chart;
15614		var meta = chart.getDatasetMeta(index);
15615		var visible = meta && chart.isDatasetVisible(index);
15616		var points = (visible && meta.dataset._children) || [];
15617		var length = points.length || 0;
15618
15619		return !length ? null : function(point, i) {
15620			return (i < length && points[i]._view) || null;
15621		};
15622	},
15623
15624	boundary: function(source) {
15625		var boundary = source.boundary;
15626		var x = boundary ? boundary.x : null;
15627		var y = boundary ? boundary.y : null;
15628
15629		return function(point) {
15630			return {
15631				x: x === null ? point.x : x,
15632				y: y === null ? point.y : y,
15633			};
15634		};
15635	}
15636};
15637
15638// @todo if (fill[0] === '#')
15639function decodeFill(el, index, count) {
15640	var model = el._model || {};
15641	var fill = model.fill;
15642	var target;
15643
15644	if (fill === undefined) {
15645		fill = !!model.backgroundColor;
15646	}
15647
15648	if (fill === false || fill === null) {
15649		return false;
15650	}
15651
15652	if (fill === true) {
15653		return 'origin';
15654	}
15655
15656	target = parseFloat(fill, 10);
15657	if (isFinite(target) && Math.floor(target) === target) {
15658		if (fill[0] === '-' || fill[0] === '+') {
15659			target = index + target;
15660		}
15661
15662		if (target === index || target < 0 || target >= count) {
15663			return false;
15664		}
15665
15666		return target;
15667	}
15668
15669	switch (fill) {
15670	// compatibility
15671	case 'bottom':
15672		return 'start';
15673	case 'top':
15674		return 'end';
15675	case 'zero':
15676		return 'origin';
15677	// supported boundaries
15678	case 'origin':
15679	case 'start':
15680	case 'end':
15681		return fill;
15682	// invalid fill values
15683	default:
15684		return false;
15685	}
15686}
15687
15688function computeBoundary(source) {
15689	var model = source.el._model || {};
15690	var scale = source.el._scale || {};
15691	var fill = source.fill;
15692	var target = null;
15693	var horizontal;
15694
15695	if (isFinite(fill)) {
15696		return null;
15697	}
15698
15699	// Backward compatibility: until v3, we still need to support boundary values set on
15700	// the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
15701	// controllers might still use it (e.g. the Smith chart).
15702
15703	if (fill === 'start') {
15704		target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom;
15705	} else if (fill === 'end') {
15706		target = model.scaleTop === undefined ? scale.top : model.scaleTop;
15707	} else if (model.scaleZero !== undefined) {
15708		target = model.scaleZero;
15709	} else if (scale.getBasePosition) {
15710		target = scale.getBasePosition();
15711	} else if (scale.getBasePixel) {
15712		target = scale.getBasePixel();
15713	}
15714
15715	if (target !== undefined && target !== null) {
15716		if (target.x !== undefined && target.y !== undefined) {
15717			return target;
15718		}
15719
15720		if (typeof target === 'number' && isFinite(target)) {
15721			horizontal = scale.isHorizontal();
15722			return {
15723				x: horizontal ? target : null,
15724				y: horizontal ? null : target
15725			};
15726		}
15727	}
15728
15729	return null;
15730}
15731
15732function resolveTarget(sources, index, propagate) {
15733	var source = sources[index];
15734	var fill = source.fill;
15735	var visited = [index];
15736	var target;
15737
15738	if (!propagate) {
15739		return fill;
15740	}
15741
15742	while (fill !== false && visited.indexOf(fill) === -1) {
15743		if (!isFinite(fill)) {
15744			return fill;
15745		}
15746
15747		target = sources[fill];
15748		if (!target) {
15749			return false;
15750		}
15751
15752		if (target.visible) {
15753			return fill;
15754		}
15755
15756		visited.push(fill);
15757		fill = target.fill;
15758	}
15759
15760	return false;
15761}
15762
15763function createMapper(source) {
15764	var fill = source.fill;
15765	var type = 'dataset';
15766
15767	if (fill === false) {
15768		return null;
15769	}
15770
15771	if (!isFinite(fill)) {
15772		type = 'boundary';
15773	}
15774
15775	return mappers[type](source);
15776}
15777
15778function isDrawable(point) {
15779	return point && !point.skip;
15780}
15781
15782function drawArea(ctx, curve0, curve1, len0, len1) {
15783	var i;
15784
15785	if (!len0 || !len1) {
15786		return;
15787	}
15788
15789	// building first area curve (normal)
15790	ctx.moveTo(curve0[0].x, curve0[0].y);
15791	for (i = 1; i < len0; ++i) {
15792		helpers.canvas.lineTo(ctx, curve0[i - 1], curve0[i]);
15793	}
15794
15795	// joining the two area curves
15796	ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);
15797
15798	// building opposite area curve (reverse)
15799	for (i = len1 - 1; i > 0; --i) {
15800		helpers.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true);
15801	}
15802}
15803
15804function doFill(ctx, points, mapper, view, color, loop) {
15805	var count = points.length;
15806	var span = view.spanGaps;
15807	var curve0 = [];
15808	var curve1 = [];
15809	var len0 = 0;
15810	var len1 = 0;
15811	var i, ilen, index, p0, p1, d0, d1;
15812
15813	ctx.beginPath();
15814
15815	for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
15816		index = i % count;
15817		p0 = points[index]._view;
15818		p1 = mapper(p0, index, view);
15819		d0 = isDrawable(p0);
15820		d1 = isDrawable(p1);
15821
15822		if (d0 && d1) {
15823			len0 = curve0.push(p0);
15824			len1 = curve1.push(p1);
15825		} else if (len0 && len1) {
15826			if (!span) {
15827				drawArea(ctx, curve0, curve1, len0, len1);
15828				len0 = len1 = 0;
15829				curve0 = [];
15830				curve1 = [];
15831			} else {
15832				if (d0) {
15833					curve0.push(p0);
15834				}
15835				if (d1) {
15836					curve1.push(p1);
15837				}
15838			}
15839		}
15840	}
15841
15842	drawArea(ctx, curve0, curve1, len0, len1);
15843
15844	ctx.closePath();
15845	ctx.fillStyle = color;
15846	ctx.fill();
15847}
15848
15849module.exports = {
15850	id: 'filler',
15851
15852	afterDatasetsUpdate: function(chart, options) {
15853		var count = (chart.data.datasets || []).length;
15854		var propagate = options.propagate;
15855		var sources = [];
15856		var meta, i, el, source;
15857
15858		for (i = 0; i < count; ++i) {
15859			meta = chart.getDatasetMeta(i);
15860			el = meta.dataset;
15861			source = null;
15862
15863			if (el && el._model && el instanceof elements.Line) {
15864				source = {
15865					visible: chart.isDatasetVisible(i),
15866					fill: decodeFill(el, i, count),
15867					chart: chart,
15868					el: el
15869				};
15870			}
15871
15872			meta.$filler = source;
15873			sources.push(source);
15874		}
15875
15876		for (i = 0; i < count; ++i) {
15877			source = sources[i];
15878			if (!source) {
15879				continue;
15880			}
15881
15882			source.fill = resolveTarget(sources, i, propagate);
15883			source.boundary = computeBoundary(source);
15884			source.mapper = createMapper(source);
15885		}
15886	},
15887
15888	beforeDatasetDraw: function(chart, args) {
15889		var meta = args.meta.$filler;
15890		if (!meta) {
15891			return;
15892		}
15893
15894		var ctx = chart.ctx;
15895		var el = meta.el;
15896		var view = el._view;
15897		var points = el._children || [];
15898		var mapper = meta.mapper;
15899		var color = view.backgroundColor || defaults.global.defaultColor;
15900
15901		if (mapper && color && points.length) {
15902			helpers.canvas.clipArea(ctx, chart.chartArea);
15903			doFill(ctx, points, mapper, view, color, el._loop);
15904			helpers.canvas.unclipArea(ctx);
15905		}
15906	}
15907};
15908
15909},{"25":25,"40":40,"45":45}],51:[function(require,module,exports){
15910'use strict';
15911
15912var defaults = require(25);
15913var Element = require(26);
15914var helpers = require(45);
15915var layouts = require(30);
15916
15917var noop = helpers.noop;
15918
15919defaults._set('global', {
15920	legend: {
15921		display: true,
15922		position: 'top',
15923		fullWidth: true,
15924		reverse: false,
15925		weight: 1000,
15926
15927		// a callback that will handle
15928		onClick: function(e, legendItem) {
15929			var index = legendItem.datasetIndex;
15930			var ci = this.chart;
15931			var meta = ci.getDatasetMeta(index);
15932
15933			// See controller.isDatasetVisible comment
15934			meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
15935
15936			// We hid a dataset ... rerender the chart
15937			ci.update();
15938		},
15939
15940		onHover: null,
15941
15942		labels: {
15943			boxWidth: 40,
15944			padding: 10,
15945			// Generates labels shown in the legend
15946			// Valid properties to return:
15947			// text : text to display
15948			// fillStyle : fill of coloured box
15949			// strokeStyle: stroke of coloured box
15950			// hidden : if this legend item refers to a hidden item
15951			// lineCap : cap style for line
15952			// lineDash
15953			// lineDashOffset :
15954			// lineJoin :
15955			// lineWidth :
15956			generateLabels: function(chart) {
15957				var data = chart.data;
15958				return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
15959					return {
15960						text: dataset.label,
15961						fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
15962						hidden: !chart.isDatasetVisible(i),
15963						lineCap: dataset.borderCapStyle,
15964						lineDash: dataset.borderDash,
15965						lineDashOffset: dataset.borderDashOffset,
15966						lineJoin: dataset.borderJoinStyle,
15967						lineWidth: dataset.borderWidth,
15968						strokeStyle: dataset.borderColor,
15969						pointStyle: dataset.pointStyle,
15970
15971						// Below is extra data used for toggling the datasets
15972						datasetIndex: i
15973					};
15974				}, this) : [];
15975			}
15976		}
15977	},
15978
15979	legendCallback: function(chart) {
15980		var text = [];
15981		text.push('<ul class="' + chart.id + '-legend">');
15982		for (var i = 0; i < chart.data.datasets.length; i++) {
15983			text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
15984			if (chart.data.datasets[i].label) {
15985				text.push(chart.data.datasets[i].label);
15986			}
15987			text.push('</li>');
15988		}
15989		text.push('</ul>');
15990		return text.join('');
15991	}
15992});
15993
15994/**
15995 * Helper function to get the box width based on the usePointStyle option
15996 * @param labelopts {Object} the label options on the legend
15997 * @param fontSize {Number} the label font size
15998 * @return {Number} width of the color box area
15999 */
16000function getBoxWidth(labelOpts, fontSize) {
16001	return labelOpts.usePointStyle ?
16002		fontSize * Math.SQRT2 :
16003		labelOpts.boxWidth;
16004}
16005
16006/**
16007 * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
16008 */
16009var Legend = Element.extend({
16010
16011	initialize: function(config) {
16012		helpers.extend(this, config);
16013
16014		// Contains hit boxes for each dataset (in dataset order)
16015		this.legendHitBoxes = [];
16016
16017		// Are we in doughnut mode which has a different data type
16018		this.doughnutMode = false;
16019	},
16020
16021	// These methods are ordered by lifecycle. Utilities then follow.
16022	// Any function defined here is inherited by all legend types.
16023	// Any function can be extended by the legend type
16024
16025	beforeUpdate: noop,
16026	update: function(maxWidth, maxHeight, margins) {
16027		var me = this;
16028
16029		// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
16030		me.beforeUpdate();
16031
16032		// Absorb the master measurements
16033		me.maxWidth = maxWidth;
16034		me.maxHeight = maxHeight;
16035		me.margins = margins;
16036
16037		// Dimensions
16038		me.beforeSetDimensions();
16039		me.setDimensions();
16040		me.afterSetDimensions();
16041		// Labels
16042		me.beforeBuildLabels();
16043		me.buildLabels();
16044		me.afterBuildLabels();
16045
16046		// Fit
16047		me.beforeFit();
16048		me.fit();
16049		me.afterFit();
16050		//
16051		me.afterUpdate();
16052
16053		return me.minSize;
16054	},
16055	afterUpdate: noop,
16056
16057	//
16058
16059	beforeSetDimensions: noop,
16060	setDimensions: function() {
16061		var me = this;
16062		// Set the unconstrained dimension before label rotation
16063		if (me.isHorizontal()) {
16064			// Reset position before calculating rotation
16065			me.width = me.maxWidth;
16066			me.left = 0;
16067			me.right = me.width;
16068		} else {
16069			me.height = me.maxHeight;
16070
16071			// Reset position before calculating rotation
16072			me.top = 0;
16073			me.bottom = me.height;
16074		}
16075
16076		// Reset padding
16077		me.paddingLeft = 0;
16078		me.paddingTop = 0;
16079		me.paddingRight = 0;
16080		me.paddingBottom = 0;
16081
16082		// Reset minSize
16083		me.minSize = {
16084			width: 0,
16085			height: 0
16086		};
16087	},
16088	afterSetDimensions: noop,
16089
16090	//
16091
16092	beforeBuildLabels: noop,
16093	buildLabels: function() {
16094		var me = this;
16095		var labelOpts = me.options.labels || {};
16096		var legendItems = helpers.callback(labelOpts.generateLabels, [me.chart], me) || [];
16097
16098		if (labelOpts.filter) {
16099			legendItems = legendItems.filter(function(item) {
16100				return labelOpts.filter(item, me.chart.data);
16101			});
16102		}
16103
16104		if (me.options.reverse) {
16105			legendItems.reverse();
16106		}
16107
16108		me.legendItems = legendItems;
16109	},
16110	afterBuildLabels: noop,
16111
16112	//
16113
16114	beforeFit: noop,
16115	fit: function() {
16116		var me = this;
16117		var opts = me.options;
16118		var labelOpts = opts.labels;
16119		var display = opts.display;
16120
16121		var ctx = me.ctx;
16122
16123		var globalDefault = defaults.global;
16124		var valueOrDefault = helpers.valueOrDefault;
16125		var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
16126		var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
16127		var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
16128		var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
16129
16130		// Reset hit boxes
16131		var hitboxes = me.legendHitBoxes = [];
16132
16133		var minSize = me.minSize;
16134		var isHorizontal = me.isHorizontal();
16135
16136		if (isHorizontal) {
16137			minSize.width = me.maxWidth; // fill all the width
16138			minSize.height = display ? 10 : 0;
16139		} else {
16140			minSize.width = display ? 10 : 0;
16141			minSize.height = me.maxHeight; // fill all the height
16142		}
16143
16144		// Increase sizes here
16145		if (display) {
16146			ctx.font = labelFont;
16147
16148			if (isHorizontal) {
16149				// Labels
16150
16151				// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
16152				var lineWidths = me.lineWidths = [0];
16153				var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0;
16154
16155				ctx.textAlign = 'left';
16156				ctx.textBaseline = 'top';
16157
16158				helpers.each(me.legendItems, function(legendItem, i) {
16159					var boxWidth = getBoxWidth(labelOpts, fontSize);
16160					var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
16161
16162					if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) {
16163						totalHeight += fontSize + (labelOpts.padding);
16164						lineWidths[lineWidths.length] = me.left;
16165					}
16166
16167					// Store the hitbox width and height here. Final position will be updated in `draw`
16168					hitboxes[i] = {
16169						left: 0,
16170						top: 0,
16171						width: width,
16172						height: fontSize
16173					};
16174
16175					lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
16176				});
16177
16178				minSize.height += totalHeight;
16179
16180			} else {
16181				var vPadding = labelOpts.padding;
16182				var columnWidths = me.columnWidths = [];
16183				var totalWidth = labelOpts.padding;
16184				var currentColWidth = 0;
16185				var currentColHeight = 0;
16186				var itemHeight = fontSize + vPadding;
16187
16188				helpers.each(me.legendItems, function(legendItem, i) {
16189					var boxWidth = getBoxWidth(labelOpts, fontSize);
16190					var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
16191
16192					// If too tall, go to new column
16193					if (currentColHeight + itemHeight > minSize.height) {
16194						totalWidth += currentColWidth + labelOpts.padding;
16195						columnWidths.push(currentColWidth); // previous column width
16196
16197						currentColWidth = 0;
16198						currentColHeight = 0;
16199					}
16200
16201					// Get max width
16202					currentColWidth = Math.max(currentColWidth, itemWidth);
16203					currentColHeight += itemHeight;
16204
16205					// Store the hitbox width and height here. Final position will be updated in `draw`
16206					hitboxes[i] = {
16207						left: 0,
16208						top: 0,
16209						width: itemWidth,
16210						height: fontSize
16211					};
16212				});
16213
16214				totalWidth += currentColWidth;
16215				columnWidths.push(currentColWidth);
16216				minSize.width += totalWidth;
16217			}
16218		}
16219
16220		me.width = minSize.width;
16221		me.height = minSize.height;
16222	},
16223	afterFit: noop,
16224
16225	// Shared Methods
16226	isHorizontal: function() {
16227		return this.options.position === 'top' || this.options.position === 'bottom';
16228	},
16229
16230	// Actually draw the legend on the canvas
16231	draw: function() {
16232		var me = this;
16233		var opts = me.options;
16234		var labelOpts = opts.labels;
16235		var globalDefault = defaults.global;
16236		var lineDefault = globalDefault.elements.line;
16237		var legendWidth = me.width;
16238		var lineWidths = me.lineWidths;
16239
16240		if (opts.display) {
16241			var ctx = me.ctx;
16242			var valueOrDefault = helpers.valueOrDefault;
16243			var fontColor = valueOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor);
16244			var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
16245			var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
16246			var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
16247			var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
16248			var cursor;
16249
16250			// Canvas setup
16251			ctx.textAlign = 'left';
16252			ctx.textBaseline = 'middle';
16253			ctx.lineWidth = 0.5;
16254			ctx.strokeStyle = fontColor; // for strikethrough effect
16255			ctx.fillStyle = fontColor; // render in correct colour
16256			ctx.font = labelFont;
16257
16258			var boxWidth = getBoxWidth(labelOpts, fontSize);
16259			var hitboxes = me.legendHitBoxes;
16260
16261			// current position
16262			var drawLegendBox = function(x, y, legendItem) {
16263				if (isNaN(boxWidth) || boxWidth <= 0) {
16264					return;
16265				}
16266
16267				// Set the ctx for the box
16268				ctx.save();
16269
16270				ctx.fillStyle = valueOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
16271				ctx.lineCap = valueOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
16272				ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
16273				ctx.lineJoin = valueOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
16274				ctx.lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
16275				ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
16276				var isLineWidthZero = (valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);
16277
16278				if (ctx.setLineDash) {
16279					// IE 9 and 10 do not support line dash
16280					ctx.setLineDash(valueOrDefault(legendItem.lineDash, lineDefault.borderDash));
16281				}
16282
16283				if (opts.labels && opts.labels.usePointStyle) {
16284					// Recalculate x and y for drawPoint() because its expecting
16285					// x and y to be center of figure (instead of top left)
16286					var radius = fontSize * Math.SQRT2 / 2;
16287					var offSet = radius / Math.SQRT2;
16288					var centerX = x + offSet;
16289					var centerY = y + offSet;
16290
16291					// Draw pointStyle as legend symbol
16292					helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
16293				} else {
16294					// Draw box as legend symbol
16295					if (!isLineWidthZero) {
16296						ctx.strokeRect(x, y, boxWidth, fontSize);
16297					}
16298					ctx.fillRect(x, y, boxWidth, fontSize);
16299				}
16300
16301				ctx.restore();
16302			};
16303			var fillText = function(x, y, legendItem, textWidth) {
16304				var halfFontSize = fontSize / 2;
16305				var xLeft = boxWidth + halfFontSize + x;
16306				var yMiddle = y + halfFontSize;
16307
16308				ctx.fillText(legendItem.text, xLeft, yMiddle);
16309
16310				if (legendItem.hidden) {
16311					// Strikethrough the text if hidden
16312					ctx.beginPath();
16313					ctx.lineWidth = 2;
16314					ctx.moveTo(xLeft, yMiddle);
16315					ctx.lineTo(xLeft + textWidth, yMiddle);
16316					ctx.stroke();
16317				}
16318			};
16319
16320			// Horizontal
16321			var isHorizontal = me.isHorizontal();
16322			if (isHorizontal) {
16323				cursor = {
16324					x: me.left + ((legendWidth - lineWidths[0]) / 2),
16325					y: me.top + labelOpts.padding,
16326					line: 0
16327				};
16328			} else {
16329				cursor = {
16330					x: me.left + labelOpts.padding,
16331					y: me.top + labelOpts.padding,
16332					line: 0
16333				};
16334			}
16335
16336			var itemHeight = fontSize + labelOpts.padding;
16337			helpers.each(me.legendItems, function(legendItem, i) {
16338				var textWidth = ctx.measureText(legendItem.text).width;
16339				var width = boxWidth + (fontSize / 2) + textWidth;
16340				var x = cursor.x;
16341				var y = cursor.y;
16342
16343				if (isHorizontal) {
16344					if (x + width >= legendWidth) {
16345						y = cursor.y += itemHeight;
16346						cursor.line++;
16347						x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
16348					}
16349				} else if (y + itemHeight > me.bottom) {
16350					x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
16351					y = cursor.y = me.top + labelOpts.padding;
16352					cursor.line++;
16353				}
16354
16355				drawLegendBox(x, y, legendItem);
16356
16357				hitboxes[i].left = x;
16358				hitboxes[i].top = y;
16359
16360				// Fill the actual label
16361				fillText(x, y, legendItem, textWidth);
16362
16363				if (isHorizontal) {
16364					cursor.x += width + (labelOpts.padding);
16365				} else {
16366					cursor.y += itemHeight;
16367				}
16368
16369			});
16370		}
16371	},
16372
16373	/**
16374	 * Handle an event
16375	 * @private
16376	 * @param {IEvent} event - The event to handle
16377	 * @return {Boolean} true if a change occured
16378	 */
16379	handleEvent: function(e) {
16380		var me = this;
16381		var opts = me.options;
16382		var type = e.type === 'mouseup' ? 'click' : e.type;
16383		var changed = false;
16384
16385		if (type === 'mousemove') {
16386			if (!opts.onHover) {
16387				return;
16388			}
16389		} else if (type === 'click') {
16390			if (!opts.onClick) {
16391				return;
16392			}
16393		} else {
16394			return;
16395		}
16396
16397		// Chart event already has relative position in it
16398		var x = e.x;
16399		var y = e.y;
16400
16401		if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
16402			// See if we are touching one of the dataset boxes
16403			var lh = me.legendHitBoxes;
16404			for (var i = 0; i < lh.length; ++i) {
16405				var hitBox = lh[i];
16406
16407				if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
16408					// Touching an element
16409					if (type === 'click') {
16410						// use e.native for backwards compatibility
16411						opts.onClick.call(me, e.native, me.legendItems[i]);
16412						changed = true;
16413						break;
16414					} else if (type === 'mousemove') {
16415						// use e.native for backwards compatibility
16416						opts.onHover.call(me, e.native, me.legendItems[i]);
16417						changed = true;
16418						break;
16419					}
16420				}
16421			}
16422		}
16423
16424		return changed;
16425	}
16426});
16427
16428function createNewLegendAndAttach(chart, legendOpts) {
16429	var legend = new Legend({
16430		ctx: chart.ctx,
16431		options: legendOpts,
16432		chart: chart
16433	});
16434
16435	layouts.configure(chart, legend, legendOpts);
16436	layouts.addBox(chart, legend);
16437	chart.legend = legend;
16438}
16439
16440module.exports = {
16441	id: 'legend',
16442
16443	/**
16444	 * Backward compatibility: since 2.1.5, the legend is registered as a plugin, making
16445	 * Chart.Legend obsolete. To avoid a breaking change, we export the Legend as part of
16446	 * the plugin, which one will be re-exposed in the chart.js file.
16447	 * https://github.com/chartjs/Chart.js/pull/2640
16448	 * @private
16449	 */
16450	_element: Legend,
16451
vendor: 5,367 bytes, lines 16452-16664
16452	beforeInit: function(chart) {
16453		var legendOpts = chart.options.legend;
16454
16455		if (legendOpts) {
16456			createNewLegendAndAttach(chart, legendOpts);
16457		}
16458	},
16459
16460	beforeUpdate: function(chart) {
16461		var legendOpts = chart.options.legend;
16462		var legend = chart.legend;
16463
16464		if (legendOpts) {
16465			helpers.mergeIf(legendOpts, defaults.global.legend);
16466
16467			if (legend) {
16468				layouts.configure(chart, legend, legendOpts);
16469				legend.options = legendOpts;
16470			} else {
16471				createNewLegendAndAttach(chart, legendOpts);
16472			}
16473		} else if (legend) {
16474			layouts.removeBox(chart, legend);
16475			delete chart.legend;
16476		}
16477	},
16478
16479	afterEvent: function(chart, e) {
16480		var legend = chart.legend;
16481		if (legend) {
16482			legend.handleEvent(e);
16483		}
16484	}
16485};
16486
16487},{"25":25,"26":26,"30":30,"45":45}],52:[function(require,module,exports){
16488'use strict';
16489
16490var defaults = require(25);
16491var Element = require(26);
16492var helpers = require(45);
16493var layouts = require(30);
16494
16495var noop = helpers.noop;
16496
16497defaults._set('global', {
16498	title: {
16499		display: false,
16500		fontStyle: 'bold',
16501		fullWidth: true,
16502		lineHeight: 1.2,
16503		padding: 10,
16504		position: 'top',
16505		text: '',
16506		weight: 2000         // by default greater than legend (1000) to be above
16507	}
16508});
16509
16510/**
16511 * IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!
16512 */
16513var Title = Element.extend({
16514	initialize: function(config) {
16515		var me = this;
16516		helpers.extend(me, config);
16517
16518		// Contains hit boxes for each dataset (in dataset order)
16519		me.legendHitBoxes = [];
16520	},
16521
16522	// These methods are ordered by lifecycle. Utilities then follow.
16523
16524	beforeUpdate: noop,
16525	update: function(maxWidth, maxHeight, margins) {
16526		var me = this;
16527
16528		// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
16529		me.beforeUpdate();
16530
16531		// Absorb the master measurements
16532		me.maxWidth = maxWidth;
16533		me.maxHeight = maxHeight;
16534		me.margins = margins;
16535
16536		// Dimensions
16537		me.beforeSetDimensions();
16538		me.setDimensions();
16539		me.afterSetDimensions();
16540		// Labels
16541		me.beforeBuildLabels();
16542		me.buildLabels();
16543		me.afterBuildLabels();
16544
16545		// Fit
16546		me.beforeFit();
16547		me.fit();
16548		me.afterFit();
16549		//
16550		me.afterUpdate();
16551
16552		return me.minSize;
16553
16554	},
16555	afterUpdate: noop,
16556
16557	//
16558
16559	beforeSetDimensions: noop,
16560	setDimensions: function() {
16561		var me = this;
16562		// Set the unconstrained dimension before label rotation
16563		if (me.isHorizontal()) {
16564			// Reset position before calculating rotation
16565			me.width = me.maxWidth;
16566			me.left = 0;
16567			me.right = me.width;
16568		} else {
16569			me.height = me.maxHeight;
16570
16571			// Reset position before calculating rotation
16572			me.top = 0;
16573			me.bottom = me.height;
16574		}
16575
16576		// Reset padding
16577		me.paddingLeft = 0;
16578		me.paddingTop = 0;
16579		me.paddingRight = 0;
16580		me.paddingBottom = 0;
16581
16582		// Reset minSize
16583		me.minSize = {
16584			width: 0,
16585			height: 0
16586		};
16587	},
16588	afterSetDimensions: noop,
16589
16590	//
16591
16592	beforeBuildLabels: noop,
16593	buildLabels: noop,
16594	afterBuildLabels: noop,
16595
16596	//
16597
16598	beforeFit: noop,
16599	fit: function() {
16600		var me = this;
16601		var valueOrDefault = helpers.valueOrDefault;
16602		var opts = me.options;
16603		var display = opts.display;
16604		var fontSize = valueOrDefault(opts.fontSize, defaults.global.defaultFontSize);
16605		var minSize = me.minSize;
16606		var lineCount = helpers.isArray(opts.text) ? opts.text.length : 1;
16607		var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
16608		var textSize = display ? (lineCount * lineHeight) + (opts.padding * 2) : 0;
16609
16610		if (me.isHorizontal()) {
16611			minSize.width = me.maxWidth; // fill all the width
16612			minSize.height = textSize;
16613		} else {
16614			minSize.width = textSize;
16615			minSize.height = me.maxHeight; // fill all the height
16616		}
16617
16618		me.width = minSize.width;
16619		me.height = minSize.height;
16620
16621	},
16622	afterFit: noop,
16623
16624	// Shared Methods
16625	isHorizontal: function() {
16626		var pos = this.options.position;
16627		return pos === 'top' || pos === 'bottom';
16628	},
16629
16630	// Actually draw the title block on the canvas
16631	draw: function() {
16632		var me = this;
16633		var ctx = me.ctx;
16634		var valueOrDefault = helpers.valueOrDefault;
16635		var opts = me.options;
16636		var globalDefaults = defaults.global;
16637
16638		if (opts.display) {
16639			var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize);
16640			var fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle);
16641			var fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily);
16642			var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily);
16643			var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
16644			var offset = lineHeight / 2 + opts.padding;
16645			var rotation = 0;
16646			var top = me.top;
16647			var left = me.left;
16648			var bottom = me.bottom;
16649			var right = me.right;
16650			var maxWidth, titleX, titleY;
16651
16652			ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
16653			ctx.font = titleFont;
16654
16655			// Horizontal
16656			if (me.isHorizontal()) {
16657				titleX = left + ((right - left) / 2); // midpoint of the width
16658				titleY = top + offset;
16659				maxWidth = right - left;
16660			} else {
16661				titleX = opts.position === 'left' ? left + offset : right - offset;
16662				titleY = top + ((bottom - top) / 2);
16663				maxWidth = bottom - top;
16664				rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
16665			}
16666
16667			ctx.save();
16668			ctx.translate(titleX, titleY);
16669			ctx.rotate(rotation);
16670			ctx.textAlign = 'center';
16671			ctx.textBaseline = 'middle';
16672
16673			var text = opts.text;
16674			if (helpers.isArray(text)) {
16675				var y = 0;
16676				for (var i = 0; i < text.length; ++i) {
16677					ctx.fillText(text[i], 0, y, maxWidth);
16678					y += lineHeight;
16679				}
16680			} else {
16681				ctx.fillText(text, 0, 0, maxWidth);
16682			}
16683
16684			ctx.restore();
16685		}
16686	}
16687});
16688
16689function createNewTitleBlockAndAttach(chart, titleOpts) {
16690	var title = new Title({
16691		ctx: chart.ctx,
16692		options: titleOpts,
16693		chart: chart
16694	});
16695
16696	layouts.configure(chart, title, titleOpts);
16697	layouts.addBox(chart, title);
16698	chart.titleBlock = title;
16699}
16700
16701module.exports = {
16702	id: 'title',
16703
16704	/**
16705	 * Backward compatibility: since 2.1.5, the title is registered as a plugin, making
16706	 * Chart.Title obsolete. To avoid a breaking change, we export the Title as part of
16707	 * the plugin, which one will be re-exposed in the chart.js file.
16708	 * https://github.com/chartjs/Chart.js/pull/2640
16709	 * @private
16710	 */
16711	_element: Title,
16712
16713	beforeInit: function(chart) {
16714		var titleOpts = chart.options.title;
16715
16716		if (titleOpts) {
16717			createNewTitleBlockAndAttach(chart, titleOpts);
16718		}
16719	},
16720
16721	beforeUpdate: function(chart) {
16722		var titleOpts = chart.options.title;
16723		var titleBlock = chart.titleBlock;
16724
16725		if (titleOpts) {
16726			helpers.mergeIf(titleOpts, defaults.global.title);
16727
16728			if (titleBlock) {
16729				layouts.configure(chart, titleBlock, titleOpts);
16730				titleBlock.options = titleOpts;
16731			} else {
16732				createNewTitleBlockAndAttach(chart, titleOpts);
16733			}
16734		} else if (titleBlock) {
16735			layouts.removeBox(chart, titleBlock);
16736			delete chart.titleBlock;
16737		}
16738	}
16739};
16740
16741},{"25":25,"26":26,"30":30,"45":45}],53:[function(require,module,exports){
16742'use strict';
16743
16744module.exports = function(Chart) {
16745
16746	// Default config for a category scale
16747	var defaultConfig = {
16748		position: 'bottom'
16749	};
16750
16751	var DatasetScale = Chart.Scale.extend({
16752		/**
16753		* Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
16754		* else fall back to data.labels
16755		* @private
16756		*/
16757		getLabels: function() {
16758			var data = this.chart.data;
16759			return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
16760		},
16761
16762		determineDataLimits: function() {
16763			var me = this;
16764			var labels = me.getLabels();
16765			me.minIndex = 0;
16766			me.maxIndex = labels.length - 1;
16767			var findIndex;
16768
16769			if (me.options.ticks.min !== undefined) {
16770				// user specified min value
16771				findIndex = labels.indexOf(me.options.ticks.min);
16772				me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
16773			}
16774
16775			if (me.options.ticks.max !== undefined) {
16776				// user specified max value
16777				findIndex = labels.indexOf(me.options.ticks.max);
16778				me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
16779			}
16780
16781			me.min = labels[me.minIndex];
16782			me.max = labels[me.maxIndex];
16783		},
16784
16785		buildTicks: function() {
16786			var me = this;
16787			var labels = me.getLabels();
16788			// If we are viewing some subset of labels, slice the original array
16789			me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
16790		},
16791
16792		getLabelForIndex: function(index, datasetIndex) {
16793			var me = this;
16794			var data = me.chart.data;
16795			var isHorizontal = me.isHorizontal();
16796
16797			if (data.yLabels && !isHorizontal) {
16798				return me.getRightValue(data.datasets[datasetIndex].data[index]);
16799			}
16800			return me.ticks[index - me.minIndex];
16801		},
16802
16803		// Used to get data value locations.  Value can either be an index or a numerical value
16804		getPixelForValue: function(value, index) {
16805			var me = this;
16806			var offset = me.options.offset;
16807			// 1 is added because we need the length but we have the indexes
16808			var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1);
16809
16810			// If value is a data object, then index is the index in the data array,
16811			// not the index of the scale. We need to change that.
16812			var valueCategory;
16813			if (value !== undefined && value !== null) {
16814				valueCategory = me.isHorizontal() ? value.x : value.y;
16815			}
16816			if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
16817				var labels = me.getLabels();
16818				value = valueCategory || value;
16819				var idx = labels.indexOf(value);
16820				index = idx !== -1 ? idx : index;
16821			}
16822
16823			if (me.isHorizontal()) {
16824				var valueWidth = me.width / offsetAmt;
16825				var widthOffset = (valueWidth * (index - me.minIndex));
16826
16827				if (offset) {
16828					widthOffset += (valueWidth / 2);
16829				}
16830
16831				return me.left + Math.round(widthOffset);
16832			}
16833			var valueHeight = me.height / offsetAmt;
16834			var heightOffset = (valueHeight * (index - me.minIndex));
16835
16836			if (offset) {
16837				heightOffset += (valueHeight / 2);
16838			}
16839
16840			return me.top + Math.round(heightOffset);
16841		},
16842		getPixelForTick: function(index) {
16843			return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
16844		},
16845		getValueForPixel: function(pixel) {
16846			var me = this;
16847			var offset = me.options.offset;
16848			var value;
16849			var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
16850			var horz = me.isHorizontal();
16851			var valueDimension = (horz ? me.width : me.height) / offsetAmt;
16852
16853			pixel -= horz ? me.left : me.top;
16854
16855			if (offset) {
16856				pixel -= (valueDimension / 2);
16857			}
16858
16859			if (pixel <= 0) {
16860				value = 0;
16861			} else {
16862				value = Math.round(pixel / valueDimension);
16863			}
16864
16865			return value + me.minIndex;
16866		},
16867		getBasePixel: function() {
16868			return this.bottom;
16869		}
16870	});
16871
16872	Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig);
16873
16874};
16875
16876},{}],54:[function(require,module,exports){
16877'use strict';
16878
16879var defaults = require(25);
16880var helpers = require(45);
16881var Ticks = require(34);
16882
16883module.exports = function(Chart) {
16884
16885	var defaultConfig = {
16886		position: 'left',
16887		ticks: {
16888			callback: Ticks.formatters.linear
16889		}
16890	};
16891
16892	var LinearScale = Chart.LinearScaleBase.extend({
16893
16894		determineDataLimits: function() {
16895			var me = this;
16896			var opts = me.options;
16897			var chart = me.chart;
16898			var data = chart.data;
16899			var datasets = data.datasets;
16900			var isHorizontal = me.isHorizontal();
16901			var DEFAULT_MIN = 0;
16902			var DEFAULT_MAX = 1;
16903
16904			function IDMatches(meta) {
16905				return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
16906			}
16907
16908			// First Calculate the range
16909			me.min = null;
16910			me.max = null;
16911
16912			var hasStacks = opts.stacked;
16913			if (hasStacks === undefined) {
16914				helpers.each(datasets, function(dataset, datasetIndex) {
16915					if (hasStacks) {
16916						return;
16917					}
16918
16919					var meta = chart.getDatasetMeta(datasetIndex);
16920					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
16921						meta.stack !== undefined) {
16922						hasStacks = true;
16923					}
16924				});
16925			}
16926
16927			if (opts.stacked || hasStacks) {
16928				var valuesPerStack = {};
16929
16930				helpers.each(datasets, function(dataset, datasetIndex) {
16931					var meta = chart.getDatasetMeta(datasetIndex);
16932					var key = [
16933						meta.type,
16934						// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
16935						((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
16936						meta.stack
16937					].join('.');
16938
16939					if (valuesPerStack[key] === undefined) {
16940						valuesPerStack[key] = {
16941							positiveValues: [],
16942							negativeValues: []
16943						};
16944					}
16945
16946					// Store these per type
16947					var positiveValues = valuesPerStack[key].positiveValues;
16948					var negativeValues = valuesPerStack[key].negativeValues;
16949
16950					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
16951						helpers.each(dataset.data, function(rawValue, index) {
16952							var value = +me.getRightValue(rawValue);
16953							if (isNaN(value) || meta.data[index].hidden) {
16954								return;
16955							}
16956
16957							positiveValues[index] = positiveValues[index] || 0;
16958							negativeValues[index] = negativeValues[index] || 0;
16959
16960							if (opts.relativePoints) {
16961								positiveValues[index] = 100;
16962							} else if (value < 0) {
16963								negativeValues[index] += value;
16964							} else {
16965								positiveValues[index] += value;
16966							}
16967						});
16968					}
16969				});
16970
16971				helpers.each(valuesPerStack, function(valuesForType) {
16972					var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
16973					var minVal = helpers.min(values);
16974					var maxVal = helpers.max(values);
16975					me.min = me.min === null ? minVal : Math.min(me.min, minVal);
16976					me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
16977				});
16978
16979			} else {
16980				helpers.each(datasets, function(dataset, datasetIndex) {
16981					var meta = chart.getDatasetMeta(datasetIndex);
16982					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
16983						helpers.each(dataset.data, function(rawValue, index) {
16984							var value = +me.getRightValue(rawValue);
16985							if (isNaN(value) || meta.data[index].hidden) {
16986								return;
16987							}
16988
16989							if (me.min === null) {
16990								me.min = value;
16991							} else if (value < me.min) {
16992								me.min = value;
16993							}
16994
16995							if (me.max === null) {
16996								me.max = value;
16997							} else if (value > me.max) {
16998								me.max = value;
16999							}
17000						});
17001					}
17002				});
17003			}
17004
17005			me.min = isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
17006			me.max = isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;
17007
17008			// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
17009			this.handleTickRangeOptions();
17010		},
17011		getTickLimit: function() {
17012			var maxTicks;
17013			var me = this;
17014			var tickOpts = me.options.ticks;
17015
17016			if (me.isHorizontal()) {
17017				maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
17018			} else {
17019				// The factor of 2 used to scale the font size has been experimentally determined.
17020				var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize);
17021				maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
17022			}
17023
17024			return maxTicks;
17025		},
17026		// Called after the ticks are built. We need
17027		handleDirectionalChanges: function() {
17028			if (!this.isHorizontal()) {
17029				// We are in a vertical orientation. The top value is the highest. So reverse the array
17030				this.ticks.reverse();
17031			}
17032		},
17033		getLabelForIndex: function(index, datasetIndex) {
17034			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
17035		},
17036		// Utils
17037		getPixelForValue: function(value) {
17038			// This must be called after fit has been run so that
17039			// this.left, this.top, this.right, and this.bottom have been defined
17040			var me = this;
17041			var start = me.start;
17042
17043			var rightValue = +me.getRightValue(value);
17044			var pixel;
17045			var range = me.end - start;
17046
17047			if (me.isHorizontal()) {
17048				pixel = me.left + (me.width / range * (rightValue - start));
17049			} else {
17050				pixel = me.bottom - (me.height / range * (rightValue - start));
17051			}
17052			return pixel;
17053		},
17054		getValueForPixel: function(pixel) {
17055			var me = this;
17056			var isHorizontal = me.isHorizontal();
17057			var innerDimension = isHorizontal ? me.width : me.height;
17058			var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
17059			return me.start + ((me.end - me.start) * offset);
17060		},
17061		getPixelForTick: function(index) {
17062			return this.getPixelForValue(this.ticksAsNumbers[index]);
17063		}
17064	});
17065	Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig);
17066
17067};
17068
17069},{"25":25,"34":34,"45":45}],55:[function(require,module,exports){
17070'use strict';
17071
17072var helpers = require(45);
17073
17074/**
17075 * Generate a set of linear ticks
17076 * @param generationOptions the options used to generate the ticks
17077 * @param dataRange the range of the data
17078 * @returns {Array<Number>} array of tick values
17079 */
17080function generateTicks(generationOptions, dataRange) {
17081	var ticks = [];
17082	// To get a "nice" value for the tick spacing, we will use the appropriately named
17083	// "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
17084	// for details.
17085
17086	var spacing;
17087	if (generationOptions.stepSize && generationOptions.stepSize > 0) {
17088		spacing = generationOptions.stepSize;
17089	} else {
17090		var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
17091		spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
17092	}
17093	var niceMin = Math.floor(dataRange.min / spacing) * spacing;
17094	var niceMax = Math.ceil(dataRange.max / spacing) * spacing;
17095
17096	// If min, max and stepSize is set and they make an evenly spaced scale use it.
17097	if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
17098		// If very close to our whole number, use it.
17099		if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
17100			niceMin = generationOptions.min;
17101			niceMax = generationOptions.max;
17102		}
17103	}
17104
17105	var numSpaces = (niceMax - niceMin) / spacing;
17106	// If very close to our rounded value, use it.
17107	if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
17108		numSpaces = Math.round(numSpaces);
17109	} else {
17110		numSpaces = Math.ceil(numSpaces);
17111	}
17112
17113	var precision = 1;
17114	if (spacing < 1) {
17115		precision = Math.pow(10, spacing.toString().length - 2);
17116		niceMin = Math.round(niceMin * precision) / precision;
17117		niceMax = Math.round(niceMax * precision) / precision;
17118	}
17119	ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
17120	for (var j = 1; j < numSpaces; ++j) {
17121		ticks.push(Math.round((niceMin + j * spacing) * precision) / precision);
17122	}
17123	ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
17124
17125	return ticks;
17126}
17127
17128
17129module.exports = function(Chart) {
17130
17131	var noop = helpers.noop;
17132
17133	Chart.LinearScaleBase = Chart.Scale.extend({
17134		getRightValue: function(value) {
17135			if (typeof value === 'string') {
17136				return +value;
17137			}
17138			return Chart.Scale.prototype.getRightValue.call(this, value);
17139		},
17140
17141		handleTickRangeOptions: function() {
17142			var me = this;
17143			var opts = me.options;
17144			var tickOpts = opts.ticks;
17145
17146			// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
17147			// do nothing since that would make the chart weird. If the user really wants a weird chart
17148			// axis, they can manually override it
17149			if (tickOpts.beginAtZero) {
17150				var minSign = helpers.sign(me.min);
17151				var maxSign = helpers.sign(me.max);
17152
17153				if (minSign < 0 && maxSign < 0) {
17154					// move the top up to 0
17155					me.max = 0;
17156				} else if (minSign > 0 && maxSign > 0) {
17157					// move the bottom down to 0
17158					me.min = 0;
17159				}
17160			}
17161
17162			var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined;
17163			var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined;
17164
17165			if (tickOpts.min !== undefined) {
17166				me.min = tickOpts.min;
17167			} else if (tickOpts.suggestedMin !== undefined) {
17168				if (me.min === null) {
17169					me.min = tickOpts.suggestedMin;
17170				} else {
17171					me.min = Math.min(me.min, tickOpts.suggestedMin);
17172				}
17173			}
17174
17175			if (tickOpts.max !== undefined) {
17176				me.max = tickOpts.max;
17177			} else if (tickOpts.suggestedMax !== undefined) {
17178				if (me.max === null) {
17179					me.max = tickOpts.suggestedMax;
17180				} else {
17181					me.max = Math.max(me.max, tickOpts.suggestedMax);
17182				}
17183			}
17184
17185			if (setMin !== setMax) {
17186				// We set the min or the max but not both.
17187				// So ensure that our range is good
17188				// Inverted or 0 length range can happen when
17189				// ticks.min is set, and no datasets are visible
17190				if (me.min >= me.max) {
17191					if (setMin) {
17192						me.max = me.min + 1;
17193					} else {
17194						me.min = me.max - 1;
17195					}
17196				}
17197			}
17198
17199			if (me.min === me.max) {
17200				me.max++;
17201
17202				if (!tickOpts.beginAtZero) {
17203					me.min--;
17204				}
17205			}
17206		},
17207		getTickLimit: noop,
17208		handleDirectionalChanges: noop,
17209
17210		buildTicks: function() {
17211			var me = this;
17212			var opts = me.options;
17213			var tickOpts = opts.ticks;
17214
17215			// Figure out what the max number of ticks we can support it is based on the size of
17216			// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
17217			// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
17218			// the graph. Make sure we always have at least 2 ticks
17219			var maxTicks = me.getTickLimit();
17220			maxTicks = Math.max(2, maxTicks);
17221
17222			var numericGeneratorOptions = {
17223				maxTicks: maxTicks,
17224				min: tickOpts.min,
17225				max: tickOpts.max,
17226				stepSize: helpers.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
17227			};
17228			var ticks = me.ticks = generateTicks(numericGeneratorOptions, me);
17229
17230			me.handleDirectionalChanges();
17231
17232			// At this point, we need to update our max and min given the tick values since we have expanded the
17233			// range of the scale
17234			me.max = helpers.max(ticks);
17235			me.min = helpers.min(ticks);
17236
17237			if (tickOpts.reverse) {
17238				ticks.reverse();
17239
17240				me.start = me.max;
17241				me.end = me.min;
17242			} else {
17243				me.start = me.min;
17244				me.end = me.max;
17245			}
17246		},
17247		convertTicksToLabels: function() {
17248			var me = this;
17249			me.ticksAsNumbers = me.ticks.slice();
17250			me.zeroLineIndex = me.ticks.indexOf(0);
17251
17252			Chart.Scale.prototype.convertTicksToLabels.call(me);
17253		}
17254	});
17255};
17256
17257},{"45":45}],56:[function(require,module,exports){
17258'use strict';
17259
17260var helpers = require(45);
17261var Ticks = require(34);
17262
17263/**
17264 * Generate a set of logarithmic ticks
17265 * @param generationOptions the options used to generate the ticks
17266 * @param dataRange the range of the data
17267 * @returns {Array<Number>} array of tick values
17268 */
17269function generateTicks(generationOptions, dataRange) {
17270	var ticks = [];
17271	var valueOrDefault = helpers.valueOrDefault;
17272
17273	// Figure out what the max number of ticks we can support it is based on the size of
17274	// the axis area. For now, we say that the minimum tick spacing in pixels must be 50
17275	// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
17276	// the graph
17277	var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
17278
17279	var endExp = Math.floor(helpers.log10(dataRange.max));
17280	var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
17281	var exp, significand;
17282
17283	if (tickVal === 0) {
17284		exp = Math.floor(helpers.log10(dataRange.minNotZero));
17285		significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
17286
17287		ticks.push(tickVal);
17288		tickVal = significand * Math.pow(10, exp);
17289	} else {
17290		exp = Math.floor(helpers.log10(tickVal));
17291		significand = Math.floor(tickVal / Math.pow(10, exp));
17292	}
17293	var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
17294
17295	do {
17296		ticks.push(tickVal);
17297
17298		++significand;
17299		if (significand === 10) {
17300			significand = 1;
17301			++exp;
17302			precision = exp >= 0 ? 1 : precision;
17303		}
17304
17305		tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
17306	} while (exp < endExp || (exp === endExp && significand < endSignificand));
17307
17308	var lastTick = valueOrDefault(generationOptions.max, tickVal);
17309	ticks.push(lastTick);
17310
17311	return ticks;
17312}
17313
17314
17315module.exports = function(Chart) {
17316
17317	var defaultConfig = {
17318		position: 'left',
17319
17320		// label settings
17321		ticks: {
17322			callback: Ticks.formatters.logarithmic
17323		}
17324	};
17325
17326	var LogarithmicScale = Chart.Scale.extend({
17327		determineDataLimits: function() {
17328			var me = this;
17329			var opts = me.options;
17330			var chart = me.chart;
17331			var data = chart.data;
17332			var datasets = data.datasets;
17333			var isHorizontal = me.isHorizontal();
17334			function IDMatches(meta) {
17335				return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
17336			}
17337
17338			// Calculate Range
17339			me.min = null;
17340			me.max = null;
17341			me.minNotZero = null;
17342
17343			var hasStacks = opts.stacked;
17344			if (hasStacks === undefined) {
17345				helpers.each(datasets, function(dataset, datasetIndex) {
17346					if (hasStacks) {
17347						return;
17348					}
17349
17350					var meta = chart.getDatasetMeta(datasetIndex);
17351					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
17352						meta.stack !== undefined) {
17353						hasStacks = true;
17354					}
17355				});
17356			}
17357
17358			if (opts.stacked || hasStacks) {
17359				var valuesPerStack = {};
17360
17361				helpers.each(datasets, function(dataset, datasetIndex) {
17362					var meta = chart.getDatasetMeta(datasetIndex);
17363					var key = [
17364						meta.type,
17365						// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
17366						((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
17367						meta.stack
17368					].join('.');
17369
17370					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
17371						if (valuesPerStack[key] === undefined) {
17372							valuesPerStack[key] = [];
17373						}
17374
17375						helpers.each(dataset.data, function(rawValue, index) {
17376							var values = valuesPerStack[key];
17377							var value = +me.getRightValue(rawValue);
17378							// invalid, hidden and negative values are ignored
17379							if (isNaN(value) || meta.data[index].hidden || value < 0) {
17380								return;
17381							}
17382							values[index] = values[index] || 0;
17383							values[index] += value;
17384						});
17385					}
17386				});
17387
17388				helpers.each(valuesPerStack, function(valuesForType) {
17389					if (valuesForType.length > 0) {
17390						var minVal = helpers.min(valuesForType);
17391						var maxVal = helpers.max(valuesForType);
17392						me.min = me.min === null ? minVal : Math.min(me.min, minVal);
17393						me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
17394					}
17395				});
17396
17397			} else {
17398				helpers.each(datasets, function(dataset, datasetIndex) {
17399					var meta = chart.getDatasetMeta(datasetIndex);
17400					if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
17401						helpers.each(dataset.data, function(rawValue, index) {
17402							var value = +me.getRightValue(rawValue);
17403							// invalid, hidden and negative values are ignored
17404							if (isNaN(value) || meta.data[index].hidden || value < 0) {
17405								return;
17406							}
17407
17408							if (me.min === null) {
17409								me.min = value;
17410							} else if (value < me.min) {
17411								me.min = value;
17412							}
17413
17414							if (me.max === null) {
17415								me.max = value;
17416							} else if (value > me.max) {
17417								me.max = value;
17418							}
17419
17420							if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
17421								me.minNotZero = value;
17422							}
17423						});
17424					}
17425				});
17426			}
17427
17428			// Common base implementation to handle ticks.min, ticks.max
17429			this.handleTickRangeOptions();
17430		},
17431		handleTickRangeOptions: function() {
17432			var me = this;
17433			var opts = me.options;
17434			var tickOpts = opts.ticks;
17435			var valueOrDefault = helpers.valueOrDefault;
17436			var DEFAULT_MIN = 1;
17437			var DEFAULT_MAX = 10;
17438
17439			me.min = valueOrDefault(tickOpts.min, me.min);
17440			me.max = valueOrDefault(tickOpts.max, me.max);
17441
17442			if (me.min === me.max) {
17443				if (me.min !== 0 && me.min !== null) {
17444					me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
17445					me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
17446				} else {
17447					me.min = DEFAULT_MIN;
17448					me.max = DEFAULT_MAX;
17449				}
17450			}
17451			if (me.min === null) {
17452				me.min = Math.pow(10, Math.floor(helpers.log10(me.max)) - 1);
17453			}
17454			if (me.max === null) {
17455				me.max = me.min !== 0
17456					? Math.pow(10, Math.floor(helpers.log10(me.min)) + 1)
17457					: DEFAULT_MAX;
17458			}
17459			if (me.minNotZero === null) {
17460				if (me.min > 0) {
17461					me.minNotZero = me.min;
17462				} else if (me.max < 1) {
17463					me.minNotZero = Math.pow(10, Math.floor(helpers.log10(me.max)));
17464				} else {
17465					me.minNotZero = DEFAULT_MIN;
17466				}
17467			}
17468		},
17469		buildTicks: function() {
17470			var me = this;
17471			var opts = me.options;
17472			var tickOpts = opts.ticks;
17473			var reverse = !me.isHorizontal();
17474
17475			var generationOptions = {
17476				min: tickOpts.min,
17477				max: tickOpts.max
17478			};
17479			var ticks = me.ticks = generateTicks(generationOptions, me);
17480
17481			// At this point, we need to update our max and min given the tick values since we have expanded the
17482			// range of the scale
17483			me.max = helpers.max(ticks);
17484			me.min = helpers.min(ticks);
17485
17486			if (tickOpts.reverse) {
17487				reverse = !reverse;
17488				me.start = me.max;
17489				me.end = me.min;
17490			} else {
17491				me.start = me.min;
17492				me.end = me.max;
17493			}
17494			if (reverse) {
17495				ticks.reverse();
17496			}
17497		},
17498		convertTicksToLabels: function() {
17499			this.tickValues = this.ticks.slice();
17500
17501			Chart.Scale.prototype.convertTicksToLabels.call(this);
17502		},
17503		// Get the correct tooltip label
17504		getLabelForIndex: function(index, datasetIndex) {
17505			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
17506		},
17507		getPixelForTick: function(index) {
17508			return this.getPixelForValue(this.tickValues[index]);
17509		},
17510		/**
17511		 * Returns the value of the first tick.
17512		 * @param {Number} value - The minimum not zero value.
17513		 * @return {Number} The first tick value.
17514		 * @private
17515		 */
17516		_getFirstTickValue: function(value) {
17517			var exp = Math.floor(helpers.log10(value));
17518			var significand = Math.floor(value / Math.pow(10, exp));
17519
17520			return significand * Math.pow(10, exp);
17521		},
17522		getPixelForValue: function(value) {
17523			var me = this;
17524			var reverse = me.options.ticks.reverse;
17525			var log10 = helpers.log10;
17526			var firstTickValue = me._getFirstTickValue(me.minNotZero);
17527			var offset = 0;
17528			var innerDimension, pixel, start, end, sign;
17529
17530			value = +me.getRightValue(value);
17531			if (reverse) {
17532				start = me.end;
17533				end = me.start;
17534				sign = -1;
17535			} else {
17536				start = me.start;
17537				end = me.end;
17538				sign = 1;
17539			}
17540			if (me.isHorizontal()) {
17541				innerDimension = me.width;
17542				pixel = reverse ? me.right : me.left;
17543			} else {
17544				innerDimension = me.height;
17545				sign *= -1; // invert, since the upper-left corner of the canvas is at pixel (0, 0)
17546				pixel = reverse ? me.top : me.bottom;
17547			}
17548			if (value !== start) {
17549				if (start === 0) { // include zero tick
17550					offset = helpers.getValueOrDefault(
17551						me.options.ticks.fontSize,
17552						Chart.defaults.global.defaultFontSize
17553					);
17554					innerDimension -= offset;
17555					start = firstTickValue;
17556				}
17557				if (value !== 0) {
17558					offset += innerDimension / (log10(end) - log10(start)) * (log10(value) - log10(start));
17559				}
17560				pixel += sign * offset;
17561			}
17562			return pixel;
17563		},
17564		getValueForPixel: function(pixel) {
17565			var me = this;
17566			var reverse = me.options.ticks.reverse;
17567			var log10 = helpers.log10;
17568			var firstTickValue = me._getFirstTickValue(me.minNotZero);
17569			var innerDimension, start, end, value;
17570
17571			if (reverse) {
17572				start = me.end;
17573				end = me.start;
17574			} else {
17575				start = me.start;
17576				end = me.end;
17577			}
17578			if (me.isHorizontal()) {
17579				innerDimension = me.width;
17580				value = reverse ? me.right - pixel : pixel - me.left;
17581			} else {
17582				innerDimension = me.height;
17583				value = reverse ? pixel - me.top : me.bottom - pixel;
17584			}
17585			if (value !== start) {
17586				if (start === 0) { // include zero tick
17587					var offset = helpers.getValueOrDefault(
17588						me.options.ticks.fontSize,
17589						Chart.defaults.global.defaultFontSize
17590					);
17591					value -= offset;
17592					innerDimension -= offset;
17593					start = firstTickValue;
17594				}
17595				value *= log10(end) - log10(start);
17596				value /= innerDimension;
17597				value = Math.pow(10, log10(start) + value);
17598			}
17599			return value;
17600		}
17601	});
17602	Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig);
17603
17604};
17605
17606},{"34":34,"45":45}],57:[function(require,module,exports){
17607'use strict';
17608
17609var defaults = require(25);
17610var helpers = require(45);
17611var Ticks = require(34);
17612
17613module.exports = function(Chart) {
17614
17615	var globalDefaults = defaults.global;
17616
17617	var defaultConfig = {
17618		display: true,
17619
17620		// Boolean - Whether to animate scaling the chart from the centre
17621		animate: true,
17622		position: 'chartArea',
17623
17624		angleLines: {
17625			display: true,
17626			color: 'rgba(0, 0, 0, 0.1)',
17627			lineWidth: 1
17628		},
17629
17630		gridLines: {
17631			circular: false
17632		},
17633
17634		// label settings
17635		ticks: {
17636			// Boolean - Show a backdrop to the scale label
17637			showLabelBackdrop: true,
17638
17639			// String - The colour of the label backdrop
17640			backdropColor: 'rgba(255,255,255,0.75)',
17641
17642			// Number - The backdrop padding above & below the label in pixels
17643			backdropPaddingY: 2,
17644
17645			// Number - The backdrop padding to the side of the label in pixels
17646			backdropPaddingX: 2,
17647
17648			callback: Ticks.formatters.linear
17649		},
17650
17651		pointLabels: {
17652			// Boolean - if true, show point labels
17653			display: true,
17654
17655			// Number - Point label font size in pixels
17656			fontSize: 10,
17657
17658			// Function - Used to convert point labels
17659			callback: function(label) {
17660				return label;
17661			}
17662		}
17663	};
17664
17665	function getValueCount(scale) {
17666		var opts = scale.options;
17667		return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
17668	}
17669
17670	function getPointLabelFontOptions(scale) {
17671		var pointLabelOptions = scale.options.pointLabels;
17672		var fontSize = helpers.valueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
17673		var fontStyle = helpers.valueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
17674		var fontFamily = helpers.valueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
17675		var font = helpers.fontString(fontSize, fontStyle, fontFamily);
17676
17677		return {
17678			size: fontSize,
17679			style: fontStyle,
17680			family: fontFamily,
17681			font: font
17682		};
17683	}
17684
17685	function measureLabelSize(ctx, fontSize, label) {
17686		if (helpers.isArray(label)) {
17687			return {
17688				w: helpers.longestText(ctx, ctx.font, label),
17689				h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
17690			};
17691		}
17692
17693		return {
17694			w: ctx.measureText(label).width,
17695			h: fontSize
17696		};
17697	}
17698
17699	function determineLimits(angle, pos, size, min, max) {
17700		if (angle === min || angle === max) {
17701			return {
17702				start: pos - (size / 2),
17703				end: pos + (size / 2)
17704			};
17705		} else if (angle < min || angle > max) {
17706			return {
17707				start: pos - size - 5,
17708				end: pos
17709			};
17710		}
17711
17712		return {
17713			start: pos,
17714			end: pos + size + 5
17715		};
17716	}
17717
17718	/**
17719	 * Helper function to fit a radial linear scale with point labels
17720	 */
17721	function fitWithPointLabels(scale) {
17722		/*
17723		 * Right, this is really confusing and there is a lot of maths going on here
17724		 * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
17725		 *
17726		 * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
17727		 *
17728		 * Solution:
17729		 *
17730		 * We assume the radius of the polygon is half the size of the canvas at first
17731		 * at each index we check if the text overlaps.
17732		 *
17733		 * Where it does, we store that angle and that index.
17734		 *
17735		 * After finding the largest index and angle we calculate how much we need to remove
17736		 * from the shape radius to move the point inwards by that x.
17737		 *
17738		 * We average the left and right distances to get the maximum shape radius that can fit in the box
17739		 * along with labels.
17740		 *
17741		 * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
17742		 * on each side, removing that from the size, halving it and adding the left x protrusion width.
17743		 *
17744		 * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
17745		 * and position it in the most space efficient manner
17746		 *
17747		 * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
17748		 */
17749
17750		var plFont = getPointLabelFontOptions(scale);
17751
17752		// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
17753		// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
17754		var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
17755		var furthestLimits = {
17756			r: scale.width,
17757			l: 0,
17758			t: scale.height,
17759			b: 0
17760		};
17761		var furthestAngles = {};
17762		var i, textSize, pointPosition;
17763
17764		scale.ctx.font = plFont.font;
17765		scale._pointLabelSizes = [];
17766
17767		var valueCount = getValueCount(scale);
17768		for (i = 0; i < valueCount; i++) {
17769			pointPosition = scale.getPointPosition(i, largestPossibleRadius);
17770			textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
17771			scale._pointLabelSizes[i] = textSize;
17772
17773			// Add quarter circle to make degree 0 mean top of circle
17774			var angleRadians = scale.getIndexAngle(i);
17775			var angle = helpers.toDegrees(angleRadians) % 360;
17776			var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
17777			var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
17778
17779			if (hLimits.start < furthestLimits.l) {
17780				furthestLimits.l = hLimits.start;
17781				furthestAngles.l = angleRadians;
17782			}
17783
17784			if (hLimits.end > furthestLimits.r) {
17785				furthestLimits.r = hLimits.end;
17786				furthestAngles.r = angleRadians;
17787			}
17788
17789			if (vLimits.start < furthestLimits.t) {
17790				furthestLimits.t = vLimits.start;
17791				furthestAngles.t = angleRadians;
17792			}
17793
17794			if (vLimits.end > furthestLimits.b) {
17795				furthestLimits.b = vLimits.end;
17796				furthestAngles.b = angleRadians;
17797			}
17798		}
17799
17800		scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
17801	}
17802
17803	/**
17804	 * Helper function to fit a radial linear scale with no point labels
17805	 */
17806	function fit(scale) {
17807		var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
17808		scale.drawingArea = Math.round(largestPossibleRadius);
17809		scale.setCenterPoint(0, 0, 0, 0);
17810	}
17811
17812	function getTextAlignForAngle(angle) {
17813		if (angle === 0 || angle === 180) {
17814			return 'center';
17815		} else if (angle < 180) {
17816			return 'left';
17817		}
17818
17819		return 'right';
17820	}
17821
17822	function fillText(ctx, text, position, fontSize) {
17823		if (helpers.isArray(text)) {
17824			var y = position.y;
17825			var spacing = 1.5 * fontSize;
17826
17827			for (var i = 0; i < text.length; ++i) {
17828				ctx.fillText(text[i], position.x, y);
17829				y += spacing;
17830			}
17831		} else {
17832			ctx.fillText(text, position.x, position.y);
17833		}
17834	}
17835
17836	function adjustPointPositionForLabelHeight(angle, textSize, position) {
17837		if (angle === 90 || angle === 270) {
17838			position.y -= (textSize.h / 2);
17839		} else if (angle > 270 || angle < 90) {
17840			position.y -= textSize.h;
17841		}
17842	}
17843
17844	function drawPointLabels(scale) {
17845		var ctx = scale.ctx;
17846		var opts = scale.options;
17847		var angleLineOpts = opts.angleLines;
17848		var pointLabelOpts = opts.pointLabels;
17849
17850		ctx.lineWidth = angleLineOpts.lineWidth;
17851		ctx.strokeStyle = angleLineOpts.color;
17852
17853		var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
17854
17855		// Point Label Font
17856		var plFont = getPointLabelFontOptions(scale);
17857
17858		ctx.textBaseline = 'top';
17859
17860		for (var i = getValueCount(scale) - 1; i >= 0; i--) {
17861			if (angleLineOpts.display) {
17862				var outerPosition = scale.getPointPosition(i, outerDistance);
17863				ctx.beginPath();
17864				ctx.moveTo(scale.xCenter, scale.yCenter);
17865				ctx.lineTo(outerPosition.x, outerPosition.y);
17866				ctx.stroke();
17867				ctx.closePath();
17868			}
17869
17870			if (pointLabelOpts.display) {
17871				// Extra 3px out for some label spacing
17872				var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);
17873
17874				// Keep this in loop since we may support array properties here
17875				var pointLabelFontColor = helpers.valueAtIndexOrDefault(pointLabelOpts.fontColor, i, globalDefaults.defaultFontColor);
17876				ctx.font = plFont.font;
17877				ctx.fillStyle = pointLabelFontColor;
17878
17879				var angleRadians = scale.getIndexAngle(i);
17880				var angle = helpers.toDegrees(angleRadians);
17881				ctx.textAlign = getTextAlignForAngle(angle);
17882				adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
17883				fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
17884			}
17885		}
17886	}
17887
17888	function drawRadiusLine(scale, gridLineOpts, radius, index) {
17889		var ctx = scale.ctx;
17890		ctx.strokeStyle = helpers.valueAtIndexOrDefault(gridLineOpts.color, index - 1);
17891		ctx.lineWidth = helpers.valueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
17892
17893		if (scale.options.gridLines.circular) {
17894			// Draw circular arcs between the points
17895			ctx.beginPath();
17896			ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
17897			ctx.closePath();
17898			ctx.stroke();
17899		} else {
17900			// Draw straight lines connecting each index
17901			var valueCount = getValueCount(scale);
17902
17903			if (valueCount === 0) {
17904				return;
17905			}
17906
17907			ctx.beginPath();
17908			var pointPosition = scale.getPointPosition(0, radius);
17909			ctx.moveTo(pointPosition.x, pointPosition.y);
17910
17911			for (var i = 1; i < valueCount; i++) {
17912				pointPosition = scale.getPointPosition(i, radius);
17913				ctx.lineTo(pointPosition.x, pointPosition.y);
17914			}
17915
17916			ctx.closePath();
17917			ctx.stroke();
17918		}
17919	}
17920
17921	function numberOrZero(param) {
17922		return helpers.isNumber(param) ? param : 0;
17923	}
17924
17925	var LinearRadialScale = Chart.LinearScaleBase.extend({
17926		setDimensions: function() {
17927			var me = this;
17928			var opts = me.options;
17929			var tickOpts = opts.ticks;
17930			// Set the unconstrained dimension before label rotation
17931			me.width = me.maxWidth;
17932			me.height = me.maxHeight;
17933			me.xCenter = Math.round(me.width / 2);
17934			me.yCenter = Math.round(me.height / 2);
17935
17936			var minSize = helpers.min([me.height, me.width]);
17937			var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
17938			me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
17939		},
17940		determineDataLimits: function() {
17941			var me = this;
17942			var chart = me.chart;
17943			var min = Number.POSITIVE_INFINITY;
17944			var max = Number.NEGATIVE_INFINITY;
17945
17946			helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
17947				if (chart.isDatasetVisible(datasetIndex)) {
17948					var meta = chart.getDatasetMeta(datasetIndex);
17949
17950					helpers.each(dataset.data, function(rawValue, index) {
17951						var value = +me.getRightValue(rawValue);
17952						if (isNaN(value) || meta.data[index].hidden) {
17953							return;
17954						}
17955
17956						min = Math.min(value, min);
17957						max = Math.max(value, max);
17958					});
17959				}
17960			});
17961
17962			me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
17963			me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
17964
17965			// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
17966			me.handleTickRangeOptions();
17967		},
17968		getTickLimit: function() {
17969			var tickOpts = this.options.ticks;
17970			var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
17971			return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
17972		},
17973		convertTicksToLabels: function() {
17974			var me = this;
17975
17976			Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);
17977
17978			// Point labels
17979			me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
17980		},
17981		getLabelForIndex: function(index, datasetIndex) {
17982			return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
17983		},
17984		fit: function() {
17985			if (this.options.pointLabels.display) {
17986				fitWithPointLabels(this);
17987			} else {
17988				fit(this);
17989			}
17990		},
17991		/**
17992		 * Set radius reductions and determine new radius and center point
17993		 * @private
17994		 */
17995		setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
17996			var me = this;
17997			var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
17998			var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
17999			var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
18000			var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);
18001
18002			radiusReductionLeft = numberOrZero(radiusReductionLeft);
18003			radiusReductionRight = numberOrZero(radiusReductionRight);
18004			radiusReductionTop = numberOrZero(radiusReductionTop);
18005			radiusReductionBottom = numberOrZero(radiusReductionBottom);
18006
18007			me.drawingArea = Math.min(
18008				Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
18009				Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
18010			me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
18011		},
18012		setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
18013			var me = this;
18014			var maxRight = me.width - rightMovement - me.drawingArea;
18015			var maxLeft = leftMovement + me.drawingArea;
18016			var maxTop = topMovement + me.drawingArea;
18017			var maxBottom = me.height - bottomMovement - me.drawingArea;
18018
18019			me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
18020			me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
18021		},
18022
18023		getIndexAngle: function(index) {
18024			var angleMultiplier = (Math.PI * 2) / getValueCount(this);
18025			var startAngle = this.chart.options && this.chart.options.startAngle ?
18026				this.chart.options.startAngle :
18027				0;
18028
18029			var startAngleRadians = startAngle * Math.PI * 2 / 360;
18030
18031			// Start from the top instead of right, so remove a quarter of the circle
18032			return index * angleMultiplier + startAngleRadians;
18033		},
18034		getDistanceFromCenterForValue: function(value) {
18035			var me = this;
18036
18037			if (value === null) {
18038				return 0; // null always in center
18039			}
18040
18041			// Take into account half font size + the yPadding of the top value
18042			var scalingFactor = me.drawingArea / (me.max - me.min);
18043			if (me.options.ticks.reverse) {
18044				return (me.max - value) * scalingFactor;
18045			}
18046			return (value - me.min) * scalingFactor;
18047		},
18048		getPointPosition: function(index, distanceFromCenter) {
18049			var me = this;
18050			var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
18051			return {
18052				x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
18053				y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
18054			};
18055		},
18056		getPointPositionForValue: function(index, value) {
18057			return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
18058		},
18059
18060		getBasePosition: function() {
18061			var me = this;
18062			var min = me.min;
18063			var max = me.max;
18064
18065			return me.getPointPositionForValue(0,
18066				me.beginAtZero ? 0 :
18067				min < 0 && max < 0 ? max :
18068				min > 0 && max > 0 ? min :
18069				0);
18070		},
18071
18072		draw: function() {
18073			var me = this;
18074			var opts = me.options;
18075			var gridLineOpts = opts.gridLines;
18076			var tickOpts = opts.ticks;
18077			var valueOrDefault = helpers.valueOrDefault;
18078
18079			if (opts.display) {
18080				var ctx = me.ctx;
18081				var startAngle = this.getIndexAngle(0);
18082
18083				// Tick Font
18084				var tickFontSize = valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
18085				var tickFontStyle = valueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
18086				var tickFontFamily = valueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
18087				var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
18088
18089				helpers.each(me.ticks, function(label, index) {
18090					// Don't draw a centre value (if it is minimum)
18091					if (index > 0 || tickOpts.reverse) {
18092						var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
18093
18094						// Draw circular lines around the scale
18095						if (gridLineOpts.display && index !== 0) {
18096							drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
18097						}
18098
18099						if (tickOpts.display) {
18100							var tickFontColor = valueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
18101							ctx.font = tickLabelFont;
18102
18103							ctx.save();
18104							ctx.translate(me.xCenter, me.yCenter);
18105							ctx.rotate(startAngle);
18106
18107							if (tickOpts.showLabelBackdrop) {
18108								var labelWidth = ctx.measureText(label).width;
18109								ctx.fillStyle = tickOpts.backdropColor;
18110								ctx.fillRect(
18111									-labelWidth / 2 - tickOpts.backdropPaddingX,
18112									-yCenterOffset - tickFontSize / 2 - tickOpts.backdropPaddingY,
18113									labelWidth + tickOpts.backdropPaddingX * 2,
18114									tickFontSize + tickOpts.backdropPaddingY * 2
18115								);
18116							}
18117
18118							ctx.textAlign = 'center';
18119							ctx.textBaseline = 'middle';
18120							ctx.fillStyle = tickFontColor;
18121							ctx.fillText(label, 0, -yCenterOffset);
18122							ctx.restore();
18123						}
18124					}
18125				});
18126
18127				if (opts.angleLines.display || opts.pointLabels.display) {
18128					drawPointLabels(me);
18129				}
18130			}
18131		}
18132	});
18133	Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig);
18134
18135};
18136
18137},{"25":25,"34":34,"45":45}],58:[function(require,module,exports){
18138/* global window: false */
18139'use strict';
18140
18141var moment = require(6);
18142moment = typeof moment === 'function' ? moment : window.moment;
18143
18144var defaults = require(25);
18145var helpers = require(45);
18146
18147// Integer constants are from the ES6 spec.
18148var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
18149var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
18150
18151var INTERVALS = {
18152	millisecond: {
18153		common: true,
18154		size: 1,
18155		steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
18156	},
18157	second: {
18158		common: true,
18159		size: 1000,
18160		steps: [1, 2, 5, 10, 30]
18161	},
18162	minute: {
18163		common: true,
18164		size: 60000,
18165		steps: [1, 2, 5, 10, 30]
18166	},
18167	hour: {
18168		common: true,
18169		size: 3600000,
18170		steps: [1, 2, 3, 6, 12]
18171	},
18172	day: {
18173		common: true,
18174		size: 86400000,
18175		steps: [1, 2, 5]
18176	},
18177	week: {
18178		common: false,
18179		size: 604800000,
18180		steps: [1, 2, 3, 4]
18181	},
18182	month: {
18183		common: true,
18184		size: 2.628e9,
18185		steps: [1, 2, 3]
18186	},
18187	quarter: {
18188		common: false,
18189		size: 7.884e9,
18190		steps: [1, 2, 3, 4]
18191	},
18192	year: {
18193		common: true,
18194		size: 3.154e10
18195	}
18196};
18197
18198var UNITS = Object.keys(INTERVALS);
18199
18200function sorter(a, b) {
18201	return a - b;
18202}
18203
18204function arrayUnique(items) {
18205	var hash = {};
18206	var out = [];
18207	var i, ilen, item;
18208
18209	for (i = 0, ilen = items.length; i < ilen; ++i) {
18210		item = items[i];
18211		if (!hash[item]) {
18212			hash[item] = true;
18213			out.push(item);
18214		}
18215	}
18216
18217	return out;
18218}
18219
18220/**
18221 * Returns an array of {time, pos} objects used to interpolate a specific `time` or position
18222 * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is
18223 * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other
18224 * extremity (left + width or top + height). Note that it would be more optimized to directly
18225 * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need
18226 * to create the lookup table. The table ALWAYS contains at least two items: min and max.
18227 *
18228 * @param {Number[]} timestamps - timestamps sorted from lowest to highest.
18229 * @param {String} distribution - If 'linear', timestamps will be spread linearly along the min
18230 * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}.
18231 * If 'series', timestamps will be positioned at the same distance from each other. In this
18232 * case, only timestamps that break the time linearity are registered, meaning that in the
18233 * best case, all timestamps are linear, the table contains only min and max.
18234 */
18235function buildLookupTable(timestamps, min, max, distribution) {
18236	if (distribution === 'linear' || !timestamps.length) {
18237		return [
18238			{time: min, pos: 0},
18239			{time: max, pos: 1}
18240		];
18241	}
18242
18243	var table = [];
18244	var items = [min];
18245	var i, ilen, prev, curr, next;
18246
18247	for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
18248		curr = timestamps[i];
18249		if (curr > min && curr < max) {
18250			items.push(curr);
18251		}
18252	}
18253
18254	items.push(max);
18255
18256	for (i = 0, ilen = items.length; i < ilen; ++i) {
18257		next = items[i + 1];
18258		prev = items[i - 1];
18259		curr = items[i];
18260
18261		// only add points that breaks the scale linearity
18262		if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) {
18263			table.push({time: curr, pos: i / (ilen - 1)});
18264		}
18265	}
18266
18267	return table;
18268}
18269
18270// @see adapted from http://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/
18271function lookup(table, key, value) {
18272	var lo = 0;
18273	var hi = table.length - 1;
18274	var mid, i0, i1;
18275
18276	while (lo >= 0 && lo <= hi) {
18277		mid = (lo + hi) >> 1;
18278		i0 = table[mid - 1] || null;
18279		i1 = table[mid];
18280
18281		if (!i0) {
18282			// given value is outside table (before first item)
18283			return {lo: null, hi: i1};
18284		} else if (i1[key] < value) {
18285			lo = mid + 1;
18286		} else if (i0[key] > value) {
18287			hi = mid - 1;
18288		} else {
18289			return {lo: i0, hi: i1};
18290		}
18291	}
18292
18293	// given value is outside table (after last item)
18294	return {lo: i1, hi: null};
18295}
18296
18297/**
18298 * Linearly interpolates the given source `value` using the table items `skey` values and
18299 * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos')
18300 * returns the position for a timestamp equal to 42. If value is out of bounds, values at
18301 * index [0, 1] or [n - 1, n] are used for the interpolation.
18302 */
18303function interpolate(table, skey, sval, tkey) {
18304	var range = lookup(table, skey, sval);
18305
18306	// Note: the lookup table ALWAYS contains at least 2 items (min and max)
18307	var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo;
18308	var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi;
18309
18310	var span = next[skey] - prev[skey];
18311	var ratio = span ? (sval - prev[skey]) / span : 0;
18312	var offset = (next[tkey] - prev[tkey]) * ratio;
18313
18314	return prev[tkey] + offset;
18315}
18316
18317/**
18318 * Convert the given value to a moment object using the given time options.
18319 * @see http://momentjs.com/docs/#/parsing/
18320 */
18321function momentify(value, options) {
18322	var parser = options.parser;
18323	var format = options.parser || options.format;
18324
18325	if (typeof parser === 'function') {
18326		return parser(value);
18327	}
18328
18329	if (typeof value === 'string' && typeof format === 'string') {
18330		return moment(value, format);
18331	}
18332
18333	if (!(value instanceof moment)) {
18334		value = moment(value);
18335	}
18336
18337	if (value.isValid()) {
18338		return value;
18339	}
18340
18341	// Labels are in an incompatible moment format and no `parser` has been provided.
18342	// The user might still use the deprecated `format` option to convert his inputs.
18343	if (typeof format === 'function') {
18344		return format(value);
18345	}
18346
18347	return value;
18348}
18349
18350function parse(input, scale) {
18351	if (helpers.isNullOrUndef(input)) {
18352		return null;
18353	}
18354
18355	var options = scale.options.time;
18356	var value = momentify(scale.getRightValue(input), options);
18357	if (!value.isValid()) {
18358		return null;
18359	}
18360
18361	if (options.round) {
18362		value.startOf(options.round);
18363	}
18364
18365	return value.valueOf();
18366}
18367
18368/**
18369 * Returns the number of unit to skip to be able to display up to `capacity` number of ticks
18370 * in `unit` for the given `min` / `max` range and respecting the interval steps constraints.
18371 */
18372function determineStepSize(min, max, unit, capacity) {
18373	var range = max - min;
18374	var interval = INTERVALS[unit];
18375	var milliseconds = interval.size;
18376	var steps = interval.steps;
18377	var i, ilen, factor;
18378
18379	if (!steps) {
18380		return Math.ceil(range / (capacity * milliseconds));
18381	}
18382
18383	for (i = 0, ilen = steps.length; i < ilen; ++i) {
18384		factor = steps[i];
18385		if (Math.ceil(range / (milliseconds * factor)) <= capacity) {
18386			break;
18387		}
18388	}
18389
18390	return factor;
18391}
18392
18393/**
18394 * Figures out what unit results in an appropriate number of auto-generated ticks
18395 */
18396function determineUnitForAutoTicks(minUnit, min, max, capacity) {
18397	var ilen = UNITS.length;
18398	var i, interval, factor;
18399
18400	for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
18401		interval = INTERVALS[UNITS[i]];
18402		factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER;
18403
18404		if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
18405			return UNITS[i];
18406		}
18407	}
18408
18409	return UNITS[ilen - 1];
18410}
18411
18412/**
18413 * Figures out what unit to format a set of ticks with
18414 */
18415function determineUnitForFormatting(ticks, minUnit, min, max) {
18416	var duration = moment.duration(moment(max).diff(moment(min)));
18417	var ilen = UNITS.length;
18418	var i, unit;
18419
18420	for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) {
18421		unit = UNITS[i];
18422		if (INTERVALS[unit].common && duration.as(unit) >= ticks.length) {
18423			return unit;
18424		}
18425	}
18426
18427	return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
18428}
18429
18430function determineMajorUnit(unit) {
18431	for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
18432		if (INTERVALS[UNITS[i]].common) {
18433			return UNITS[i];
18434		}
18435	}
18436}
18437
18438/**
18439 * Generates a maximum of `capacity` timestamps between min and max, rounded to the
18440 * `minor` unit, aligned on the `major` unit and using the given scale time `options`.
18441 * Important: this method can return ticks outside the min and max range, it's the
18442 * responsibility of the calling code to clamp values if needed.
18443 */
18444function generate(min, max, capacity, options) {
18445	var timeOpts = options.time;
18446	var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
18447	var major = determineMajorUnit(minor);
18448	var stepSize = helpers.valueOrDefault(timeOpts.stepSize, timeOpts.unitStepSize);
18449	var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
18450	var majorTicksEnabled = options.ticks.major.enabled;
18451	var interval = INTERVALS[minor];
18452	var first = moment(min);
18453	var last = moment(max);
18454	var ticks = [];
18455	var time;
18456
18457	if (!stepSize) {
18458		stepSize = determineStepSize(min, max, minor, capacity);
18459	}
18460
18461	// For 'week' unit, handle the first day of week option
18462	if (weekday) {
18463		first = first.isoWeekday(weekday);
18464		last = last.isoWeekday(weekday);
18465	}
18466
18467	// Align first/last ticks on unit
18468	first = first.startOf(weekday ? 'day' : minor);
18469	last = last.startOf(weekday ? 'day' : minor);
18470
18471	// Make sure that the last tick include max
18472	if (last < max) {
18473		last.add(1, minor);
18474	}
18475
18476	time = moment(first);
18477
18478	if (majorTicksEnabled && major && !weekday && !timeOpts.round) {
18479		// Align the first tick on the previous `minor` unit aligned on the `major` unit:
18480		// we first aligned time on the previous `major` unit then add the number of full
18481		// stepSize there is between first and the previous major time.
18482		time.startOf(major);
18483		time.add(~~((first - time) / (interval.size * stepSize)) * stepSize, minor);
18484	}
18485
18486	for (; time < last; time.add(stepSize, minor)) {
18487		ticks.push(+time);
18488	}
18489
18490	ticks.push(+time);
18491
18492	return ticks;
18493}
18494
18495/**
18496 * Returns the right and left offsets from edges in the form of {left, right}.
18497 * Offsets are added when the `offset` option is true.
18498 */
18499function computeOffsets(table, ticks, min, max, options) {
18500	var left = 0;
18501	var right = 0;
18502	var upper, lower;
18503
18504	if (options.offset && ticks.length) {
18505		if (!options.time.min) {
18506			upper = ticks.length > 1 ? ticks[1] : max;
18507			lower = ticks[0];
18508			left = (
18509				interpolate(table, 'time', upper, 'pos') -
18510				interpolate(table, 'time', lower, 'pos')
18511			) / 2;
18512		}
18513		if (!options.time.max) {
18514			upper = ticks[ticks.length - 1];
18515			lower = ticks.length > 1 ? ticks[ticks.length - 2] : min;
18516			right = (
18517				interpolate(table, 'time', upper, 'pos') -
18518				interpolate(table, 'time', lower, 'pos')
18519			) / 2;
18520		}
18521	}
18522
18523	return {left: left, right: right};
18524}
18525
18526function ticksFromTimestamps(values, majorUnit) {
18527	var ticks = [];
18528	var i, ilen, value, major;
18529
18530	for (i = 0, ilen = values.length; i < ilen; ++i) {
18531		value = values[i];
18532		major = majorUnit ? value === +moment(value).startOf(majorUnit) : false;
18533
18534		ticks.push({
18535			value: value,
18536			major: major
18537		});
18538	}
18539
18540	return ticks;
18541}
18542
18543function determineLabelFormat(data, timeOpts) {
18544	var i, momentDate, hasTime;
18545	var ilen = data.length;
18546
18547	// find the label with the most parts (milliseconds, minutes, etc.)
18548	// format all labels with the same level of detail as the most specific label
18549	for (i = 0; i < ilen; i++) {
18550		momentDate = momentify(data[i], timeOpts);
18551		if (momentDate.millisecond() !== 0) {
18552			return 'MMM D, YYYY h:mm:ss.SSS a';
18553		}
18554		if (momentDate.second() !== 0 || momentDate.minute() !== 0 || momentDate.hour() !== 0) {
18555			hasTime = true;
18556		}
18557	}
18558	if (hasTime) {
18559		return 'MMM D, YYYY h:mm:ss a';
18560	}
18561	return 'MMM D, YYYY';
18562}
18563
18564module.exports = function(Chart) {
18565
18566	var defaultConfig = {
18567		position: 'bottom',
18568
18569		/**
18570		 * Data distribution along the scale:
18571		 * - 'linear': data are spread according to their time (distances can vary),
18572		 * - 'series': data are spread at the same distance from each other.
18573		 * @see https://github.com/chartjs/Chart.js/pull/4507
18574		 * @since 2.7.0
18575		 */
18576		distribution: 'linear',
18577
18578		/**
18579		 * Scale boundary strategy (bypassed by min/max time options)
18580		 * - `data`: make sure data are fully visible, ticks outside are removed
18581		 * - `ticks`: make sure ticks are fully visible, data outside are truncated
18582		 * @see https://github.com/chartjs/Chart.js/pull/4556
18583		 * @since 2.7.0
18584		 */
18585		bounds: 'data',
18586
18587		time: {
18588			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
18589			format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
18590			unit: false, // false == automatic or override with week, month, year, etc.
18591			round: false, // none, or override with week, month, year, etc.
18592			displayFormat: false, // DEPRECATED
18593			isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
18594			minUnit: 'millisecond',
18595
18596			// defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
18597			displayFormats: {
18598				millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
18599				second: 'h:mm:ss a', // 11:20:01 AM
18600				minute: 'h:mm a', // 11:20 AM
18601				hour: 'hA', // 5PM
18602				day: 'MMM D', // Sep 4
18603				week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
18604				month: 'MMM YYYY', // Sept 2015
18605				quarter: '[Q]Q - YYYY', // Q3
18606				year: 'YYYY' // 2015
18607			},
18608		},
18609		ticks: {
18610			autoSkip: false,
18611
18612			/**
18613			 * Ticks generation input values:
18614			 * - 'auto': generates "optimal" ticks based on scale size and time options.
18615			 * - 'data': generates ticks from data (including labels from data {t|x|y} objects).
18616			 * - 'labels': generates ticks from user given `data.labels` values ONLY.
18617			 * @see https://github.com/chartjs/Chart.js/pull/4507
18618			 * @since 2.7.0
18619			 */
18620			source: 'auto',
18621
18622			major: {
18623				enabled: false
18624			}
18625		}
18626	};
18627
18628	var TimeScale = Chart.Scale.extend({
18629		initialize: function() {
18630			if (!moment) {
18631				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');
18632			}
18633
18634			this.mergeTicksOptions();
18635
18636			Chart.Scale.prototype.initialize.call(this);
18637		},
18638
18639		update: function() {
18640			var me = this;
18641			var options = me.options;
18642
18643			// DEPRECATIONS: output a message only one time per update
18644			if (options.time && options.time.format) {
18645				console.warn('options.time.format is deprecated and replaced by options.time.parser.');
18646			}
18647
18648			return Chart.Scale.prototype.update.apply(me, arguments);
18649		},
18650
18651		/**
18652		 * Allows data to be referenced via 't' attribute
18653		 */
18654		getRightValue: function(rawValue) {
18655			if (rawValue && rawValue.t !== undefined) {
18656				rawValue = rawValue.t;
18657			}
18658			return Chart.Scale.prototype.getRightValue.call(this, rawValue);
18659		},
18660
18661		determineDataLimits: function() {
18662			var me = this;
18663			var chart = me.chart;
18664			var timeOpts = me.options.time;
18665			var unit = timeOpts.unit || 'day';
18666			var min = MAX_INTEGER;
18667			var max = MIN_INTEGER;
18668			var timestamps = [];
18669			var datasets = [];
18670			var labels = [];
18671			var i, j, ilen, jlen, data, timestamp;
18672
18673			// Convert labels to timestamps
18674			for (i = 0, ilen = chart.data.labels.length; i < ilen; ++i) {
18675				labels.push(parse(chart.data.labels[i], me));
18676			}
18677
18678			// Convert data to timestamps
18679			for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
18680				if (chart.isDatasetVisible(i)) {
18681					data = chart.data.datasets[i].data;
18682
18683					// Let's consider that all data have the same format.
18684					if (helpers.isObject(data[0])) {
18685						datasets[i] = [];
18686
18687						for (j = 0, jlen = data.length; j < jlen; ++j) {
18688							timestamp = parse(data[j], me);
18689							timestamps.push(timestamp);
18690							datasets[i][j] = timestamp;
18691						}
18692					} else {
18693						timestamps.push.apply(timestamps, labels);
18694						datasets[i] = labels.slice(0);
18695					}
18696				} else {
18697					datasets[i] = [];
18698				}
18699			}
18700
18701			if (labels.length) {
18702				// Sort labels **after** data have been converted
18703				labels = arrayUnique(labels).sort(sorter);
18704				min = Math.min(min, labels[0]);
18705				max = Math.max(max, labels[labels.length - 1]);
18706			}
18707
18708			if (timestamps.length) {
18709				timestamps = arrayUnique(timestamps).sort(sorter);
18710				min = Math.min(min, timestamps[0]);
18711				max = Math.max(max, timestamps[timestamps.length - 1]);
18712			}
18713
18714			min = parse(timeOpts.min, me) || min;
18715			max = parse(timeOpts.max, me) || max;
18716
18717			// In case there is no valid min/max, set limits based on unit time option
18718			min = min === MAX_INTEGER ? +moment().startOf(unit) : min;
18719			max = max === MIN_INTEGER ? +moment().endOf(unit) + 1 : max;
18720
18721			// Make sure that max is strictly higher than min (required by the lookup table)
18722			me.min = Math.min(min, max);
18723			me.max = Math.max(min + 1, max);
18724
18725			// PRIVATE
18726			me._horizontal = me.isHorizontal();
18727			me._table = [];
18728			me._timestamps = {
18729				data: timestamps,
18730				datasets: datasets,
18731				labels: labels
18732			};
18733		},
18734
18735		buildTicks: function() {
18736			var me = this;
18737			var min = me.min;
18738			var max = me.max;
18739			var options = me.options;
18740			var timeOpts = options.time;
18741			var timestamps = [];
18742			var ticks = [];
18743			var i, ilen, timestamp;
18744
18745			switch (options.ticks.source) {
18746			case 'data':
18747				timestamps = me._timestamps.data;
18748				break;
18749			case 'labels':
18750				timestamps = me._timestamps.labels;
18751				break;
18752			case 'auto':
18753			default:
18754				timestamps = generate(min, max, me.getLabelCapacity(min), options);
18755			}
18756
18757			if (options.bounds === 'ticks' && timestamps.length) {
18758				min = timestamps[0];
18759				max = timestamps[timestamps.length - 1];
18760			}
18761
18762			// Enforce limits with user min/max options
18763			min = parse(timeOpts.min, me) || min;
18764			max = parse(timeOpts.max, me) || max;
18765
18766			// Remove ticks outside the min/max range
18767			for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
18768				timestamp = timestamps[i];
18769				if (timestamp >= min && timestamp <= max) {
18770					ticks.push(timestamp);
18771				}
18772			}
18773
18774			me.min = min;
18775			me.max = max;
18776
18777			// PRIVATE
18778			me._unit = timeOpts.unit || determineUnitForFormatting(ticks, timeOpts.minUnit, me.min, me.max);
18779			me._majorUnit = determineMajorUnit(me._unit);
18780			me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution);
18781			me._offsets = computeOffsets(me._table, ticks, min, max, options);
18782			me._labelFormat = determineLabelFormat(me._timestamps.data, timeOpts);
18783
18784			return ticksFromTimestamps(ticks, me._majorUnit);
18785		},
18786
18787		getLabelForIndex: function(index, datasetIndex) {
18788			var me = this;
18789			var data = me.chart.data;
18790			var timeOpts = me.options.time;
18791			var label = data.labels && index < data.labels.length ? data.labels[index] : '';
18792			var value = data.datasets[datasetIndex].data[index];
18793
18794			if (helpers.isObject(value)) {
18795				label = me.getRightValue(value);
18796			}
18797			if (timeOpts.tooltipFormat) {
18798				return momentify(label, timeOpts).format(timeOpts.tooltipFormat);
18799			}
18800			if (typeof label === 'string') {
18801				return label;
18802			}
18803
18804			return momentify(label, timeOpts).format(me._labelFormat);
18805		},
18806
18807		/**
18808		 * Function to format an individual tick mark
18809		 * @private
18810		 */
18811		tickFormatFunction: function(tick, index, ticks, formatOverride) {
18812			var me = this;
18813			var options = me.options;
18814			var time = tick.valueOf();
18815			var formats = options.time.displayFormats;
18816			var minorFormat = formats[me._unit];
18817			var majorUnit = me._majorUnit;
18818			var majorFormat = formats[majorUnit];
18819			var majorTime = tick.clone().startOf(majorUnit).valueOf();
18820			var majorTickOpts = options.ticks.major;
18821			var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime;
18822			var label = tick.format(formatOverride ? formatOverride : major ? majorFormat : minorFormat);
18823			var tickOpts = major ? majorTickOpts : options.ticks.minor;
18824			var formatter = helpers.valueOrDefault(tickOpts.callback, tickOpts.userCallback);
18825
18826			return formatter ? formatter(label, index, ticks) : label;
18827		},
18828
18829		convertTicksToLabels: function(ticks) {
18830			var labels = [];
18831			var i, ilen;
18832
18833			for (i = 0, ilen = ticks.length; i < ilen; ++i) {
18834				labels.push(this.tickFormatFunction(moment(ticks[i].value), i, ticks));
18835			}
18836
18837			return labels;
18838		},
18839
18840		/**
18841		 * @private
18842		 */
18843		getPixelForOffset: function(time) {
18844			var me = this;
18845			var size = me._horizontal ? me.width : me.height;
18846			var start = me._horizontal ? me.left : me.top;
18847			var pos = interpolate(me._table, 'time', time, 'pos');
18848
18849			return start + size * (me._offsets.left + pos) / (me._offsets.left + 1 + me._offsets.right);
18850		},
18851
18852		getPixelForValue: function(value, index, datasetIndex) {
18853			var me = this;
18854			var time = null;
18855
18856			if (index !== undefined && datasetIndex !== undefined) {
18857				time = me._timestamps.datasets[datasetIndex][index];
18858			}
18859
18860			if (time === null) {
18861				time = parse(value, me);
18862			}
18863
18864			if (time !== null) {
18865				return me.getPixelForOffset(time);
18866			}
18867		},
18868
18869		getPixelForTick: function(index) {
18870			var ticks = this.getTicks();
18871			return index >= 0 && index < ticks.length ?
18872				this.getPixelForOffset(ticks[index].value) :
18873				null;
18874		},
18875
18876		getValueForPixel: function(pixel) {
18877			var me = this;
18878			var size = me._horizontal ? me.width : me.height;
18879			var start = me._horizontal ? me.left : me.top;
18880			var pos = (size ? (pixel - start) / size : 0) * (me._offsets.left + 1 + me._offsets.left) - me._offsets.right;
18881			var time = interpolate(me._table, 'pos', pos, 'time');
18882
18883			return moment(time);
18884		},
18885
18886		/**
18887		 * Crude approximation of what the label width might be
18888		 * @private
18889		 */
18890		getLabelWidth: function(label) {
18891			var me = this;
18892			var ticksOpts = me.options.ticks;
18893			var tickLabelWidth = me.ctx.measureText(label).width;
18894			var angle = helpers.toRadians(ticksOpts.maxRotation);
18895			var cosRotation = Math.cos(angle);
18896			var sinRotation = Math.sin(angle);
18897			var tickFontSize = helpers.valueOrDefault(ticksOpts.fontSize, defaults.global.defaultFontSize);
18898
18899			return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
18900		},
18901
18902		/**
18903		 * @private
18904		 */
18905		getLabelCapacity: function(exampleTime) {
18906			var me = this;
18907
18908			var formatOverride = me.options.time.displayFormats.millisecond;	// Pick the longest format for guestimation
18909
18910			var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, [], formatOverride);
18911			var tickLabelWidth = me.getLabelWidth(exampleLabel);
18912			var innerWidth = me.isHorizontal() ? me.width : me.height;
18913
18914			var capacity = Math.floor(innerWidth / tickLabelWidth);
18915			return capacity > 0 ? capacity : 1;
18916		}
18917	});
18918
18919	Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig);
18920};
18921
18922},{"25":25,"45":45,"6":6}]},{},[7])(7)
18923});

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.