Product Feed PRO for WooCommerce - Version 11.0.0

Version Description

Removed unused variables from some functions and did an extra array check

Download this release

Release Info

Developer jorisverwater
Plugin Icon 128x128 Product Feed PRO for WooCommerce
Version 11.0.0
Comparing to
See all releases

Code changes from version 10.9.9 to 11.0.0

js/Chart.bundle.js DELETED
@@ -1,17220 +0,0 @@
1
- /*!
2
- * Chart.js
3
- * http://chartjs.org/
4
- * Version: 2.6.0
5
- *
6
- * Copyright 2017 Nick Downie
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 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})({1:[function(require,module,exports){
11
- /* MIT license */
12
- var colorNames = require(5);
13
-
14
- module.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
-
33
- function getRgba(string) {
34
- if (!string) {
35
- return;
36
- }
37
- var abbr = /^#([a-fA-F0-9]{3})$/,
38
- hex = /^#([a-fA-F0-9]{6})$/,
39
- rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
40
- per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
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
-
93
- function 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
-
109
- function 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
-
125
- function getRgb(string) {
126
- var rgba = getRgba(string);
127
- return rgba && rgba.slice(0, 3);
128
- }
129
-
130
- function getHsl(string) {
131
- var hsla = getHsla(string);
132
- return hsla && hsla.slice(0, 3);
133
- }
134
-
135
- function 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
149
- function hexString(rgb) {
150
- return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
151
- + hexDouble(rgb[2]);
152
- }
153
-
154
- function rgbString(rgba, alpha) {
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
-
161
- function 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
-
169
- function 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
-
180
- function 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
-
187
- function 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
-
194
- function 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)
204
- function 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
-
212
- function keyword(rgb) {
213
- return reverseNames[rgb.slice(0, 3)];
214
- }
215
-
216
- // helpers
217
- function scale(num, min, max) {
218
- return Math.min(Math.max(min, num), max);
219
- }
220
-
221
- function 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
228
- var reverseNames = {};
229
- for (var name in colorNames) {
230
- reverseNames[colorNames[name]] = name;
231
- }
232
-
233
- },{"5":5}],2:[function(require,module,exports){
234
- /* MIT license */
235
- var convert = require(4);
236
- var string = require(1);
237
-
238
- var 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
-
283
- Color.prototype = {
284
- isValid: function () {
285
- return this.valid;
286
- },
287
- rgb: function () {
288
- return this.setSpace('rgb', arguments);
289
- },
290
- hsl: function () {
291
- return this.setSpace('hsl', arguments);
292
- },
293
- hsv: function () {
294
- return this.setSpace('hsv', arguments);
295
- },
296
- hwb: function () {
297
- return this.setSpace('hwb', arguments);
298
- },
299
- cmyk: function () {
300
- return this.setSpace('cmyk', arguments);
301
- },
302
-
303
- rgbArray: function () {
304
- return this.values.rgb;
305
- },
306
- hslArray: function () {
307
- return this.values.hsl;
308
- },
309
- hsvArray: function () {
310
- return this.values.hsv;
311
- },
312
- hwbArray: function () {
313
- var values = this.values;
314
- if (values.alpha !== 1) {
315
- return values.hwb.concat([values.alpha]);
316
- }
317
- return values.hwb;
318
- },
319
- cmykArray: function () {
320
- return this.values.cmyk;
321
- },
322
- rgbaArray: function () {
323
- var values = this.values;
324
- return values.rgb.concat([values.alpha]);
325
- },
326
- hslaArray: function () {
327
- var values = this.values;
328
- return values.hsl.concat([values.alpha]);
329
- },
330
- alpha: function (val) {
331
- if (val === undefined) {
332
- return this.values.alpha;
333
- }
334
- this.setValues('alpha', val);
335
- return this;
336
- },
337
-
338
- red: function (val) {
339
- return this.setChannel('rgb', 0, val);
340
- },
341
- green: function (val) {
342
- return this.setChannel('rgb', 1, val);
343
- },
344
- blue: function (val) {
345
- return this.setChannel('rgb', 2, val);
346
- },
347
- hue: function (val) {
348
- if (val) {
349
- val %= 360;
350
- val = val < 0 ? 360 + val : val;
351
- }
352
- return this.setChannel('hsl', 0, val);
353
- },
354
- saturation: function (val) {
355
- return this.setChannel('hsl', 1, val);
356
- },
357
- lightness: function (val) {
358
- return this.setChannel('hsl', 2, val);
359
- },
360
- saturationv: function (val) {
361
- return this.setChannel('hsv', 1, val);
362
- },
363
- whiteness: function (val) {
364
- return this.setChannel('hwb', 1, val);
365
- },
366
- blackness: function (val) {
367
- return this.setChannel('hwb', 2, val);
368
- },
369
- value: function (val) {
370
- return this.setChannel('hsv', 2, val);
371
- },
372
- cyan: function (val) {
373
- return this.setChannel('cmyk', 0, val);
374
- },
375
- magenta: function (val) {
376
- return this.setChannel('cmyk', 1, val);
377
- },
378
- yellow: function (val) {
379
- return this.setChannel('cmyk', 2, val);
380
- },
381
- black: function (val) {
382
- return this.setChannel('cmyk', 3, val);
383
- },
384
-
385
- hexString: function () {
386
- return string.hexString(this.values.rgb);
387
- },
388
- rgbString: function () {
389
- return string.rgbString(this.values.rgb, this.values.alpha);
390
- },
391
- rgbaString: function () {
392
- return string.rgbaString(this.values.rgb, this.values.alpha);
393
- },
394
- percentString: function () {
395
- return string.percentString(this.values.rgb, this.values.alpha);
396
- },
397
- hslString: function () {
398
- return string.hslString(this.values.hsl, this.values.alpha);
399
- },
400
- hslaString: function () {
401
- return string.hslaString(this.values.hsl, this.values.alpha);
402
- },
403
- hwbString: function () {
404
- return string.hwbString(this.values.hwb, this.values.alpha);
405
- },
406
- keyword: function () {
407
- return string.keyword(this.values.rgb, this.values.alpha);
408
- },
409
-
410
- rgbNumber: function () {
411
- var rgb = this.values.rgb;
412
- return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
413
- },
414
-
415
- luminosity: function () {
416
- // http://www.w3.org/TR/WCAG20/#relativeluminancedef
417
- var rgb = this.values.rgb;
418
- var lum = [];
419
- for (var i = 0; i < rgb.length; i++) {
420
- var chan = rgb[i] / 255;
421
- lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
422
- }
423
- return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
424
- },
425
-
426
- contrast: function (color2) {
427
- // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
428
- var lum1 = this.luminosity();
429
- var lum2 = color2.luminosity();
430
- if (lum1 > lum2) {
431
- return (lum1 + 0.05) / (lum2 + 0.05);
432
- }
433
- return (lum2 + 0.05) / (lum1 + 0.05);
434
- },
435
-
436
- level: function (color2) {
437
- var contrastRatio = this.contrast(color2);
438
- if (contrastRatio >= 7.1) {
439
- return 'AAA';
440
- }
441
-
442
- return (contrastRatio >= 4.5) ? 'AA' : '';
443
- },
444
-
445
- dark: function () {
446
- // YIQ equation from http://24ways.org/2010/calculating-color-contrast
447
- var rgb = this.values.rgb;
448
- var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
449
- return yiq < 128;
450
- },
451
-
452
- light: function () {
453
- return !this.dark();
454
- },
455
-
456
- negate: function () {
457
- var rgb = [];
458
- for (var i = 0; i < 3; i++) {
459
- rgb[i] = 255 - this.values.rgb[i];
460
- }
461
- this.setValues('rgb', rgb);
462
- return this;
463
- },
464
-
465
- lighten: function (ratio) {
466
- var hsl = this.values.hsl;
467
- hsl[2] += hsl[2] * ratio;
468
- this.setValues('hsl', hsl);
469
- return this;
470
- },
471
-
472
- darken: function (ratio) {
473
- var hsl = this.values.hsl;
474
- hsl[2] -= hsl[2] * ratio;
475
- this.setValues('hsl', hsl);
476
- return this;
477
- },
478
-
479
- saturate: function (ratio) {
480
- var hsl = this.values.hsl;
481
- hsl[1] += hsl[1] * ratio;
482
- this.setValues('hsl', hsl);
483
- return this;
484
- },
485
-
486
- desaturate: function (ratio) {
487
- var hsl = this.values.hsl;
488
- hsl[1] -= hsl[1] * ratio;
489
- this.setValues('hsl', hsl);
490
- return this;
491
- },
492
-
493
- whiten: function (ratio) {
494
- var hwb = this.values.hwb;
495
- hwb[1] += hwb[1] * ratio;
496
- this.setValues('hwb', hwb);
497
- return this;
498
- },
499
-
500
- blacken: function (ratio) {
501
- var hwb = this.values.hwb;
502
- hwb[2] += hwb[2] * ratio;
503
- this.setValues('hwb', hwb);
504
- return this;
505
- },
506
-
507
- greyscale: function () {
508
- var rgb = this.values.rgb;
509
- // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
510
- var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
511
- this.setValues('rgb', [val, val, val]);
512
- return this;
513
- },
514
-
515
- clearer: function (ratio) {
516
- var alpha = this.values.alpha;
517
- this.setValues('alpha', alpha - (alpha * ratio));
518
- return this;
519
- },
520
-
521
- opaquer: function (ratio) {
522
- var alpha = this.values.alpha;
523
- this.setValues('alpha', alpha + (alpha * ratio));
524
- return this;
525
- },
526
-
527
- rotate: function (degrees) {
528
- var hsl = this.values.hsl;
529
- var hue = (hsl[0] + degrees) % 360;
530
- hsl[0] = hue < 0 ? 360 + hue : hue;
531
- this.setValues('hsl', hsl);
532
- return this;
533
- },
534
-
535
- /**
536
- * Ported from sass implementation in C
537
- * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
538
- */
539
- mix: function (mixinColor, weight) {
540
- var color1 = this;
541
- var color2 = mixinColor;
542
- var p = weight === undefined ? 0.5 : weight;
543
-
544
- var w = 2 * p - 1;
545
- var a = color1.alpha() - color2.alpha();
546
-
547
- var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
548
- var w2 = 1 - w1;
549
-
550
- return this
551
- .rgb(
552
- w1 * color1.red() + w2 * color2.red(),
553
- w1 * color1.green() + w2 * color2.green(),
554
- w1 * color1.blue() + w2 * color2.blue()
555
- )
556
- .alpha(color1.alpha() * p + color2.alpha() * (1 - p));
557
- },
558
-
559
- toJSON: function () {
560
- return this.rgb();
561
- },
562
-
563
- clone: function () {
564
- // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
565
- // making the final build way to big to embed in Chart.js. So let's do it manually,
566
- // assuming that values to clone are 1 dimension arrays containing only numbers,
567
- // except 'alpha' which is a number.
568
- var result = new Color();
569
- var source = this.values;
570
- var target = result.values;
571
- var value, type;
572
-
573
- for (var prop in source) {
574
- if (source.hasOwnProperty(prop)) {
575
- value = source[prop];
576
- type = ({}).toString.call(value);
577
- if (type === '[object Array]') {
578
- target[prop] = value.slice(0);
579
- } else if (type === '[object Number]') {
580
- target[prop] = value;
581
- } else {
582
- console.error('unexpected color value:', value);
583
- }
584
- }
585
- }
586
-
587
- return result;
588
- }
589
- };
590
-
591
- Color.prototype.spaces = {
592
- rgb: ['red', 'green', 'blue'],
593
- hsl: ['hue', 'saturation', 'lightness'],
594
- hsv: ['hue', 'saturation', 'value'],
595
- hwb: ['hue', 'whiteness', 'blackness'],
596
- cmyk: ['cyan', 'magenta', 'yellow', 'black']
597
- };
598
-
599
- Color.prototype.maxes = {
600
- rgb: [255, 255, 255],
601
- hsl: [360, 100, 100],
602
- hsv: [360, 100, 100],
603
- hwb: [360, 100, 100],
604
- cmyk: [100, 100, 100, 100]
605
- };
606
-
607
- Color.prototype.getValues = function (space) {
608
- var values = this.values;
609
- var vals = {};
610
-
611
- for (var i = 0; i < space.length; i++) {
612
- vals[space.charAt(i)] = values[space][i];
613
- }
614
-
615
- if (values.alpha !== 1) {
616
- vals.a = values.alpha;
617
- }
618
-
619
- // {r: 255, g: 255, b: 255, a: 0.4}
620
- return vals;
621
- };
622
-
623
- Color.prototype.setValues = function (space, vals) {
624
- var values = this.values;
625
- var spaces = this.spaces;
626
- var maxes = this.maxes;
627
- var alpha = 1;
628
- var i;
629
-
630
- this.valid = true;
631
-
632
- if (space === 'alpha') {
633
- alpha = vals;
634
- } else if (vals.length) {
635
- // [10, 10, 10]
636
- values[space] = vals.slice(0, space.length);
637
- alpha = vals[space.length];
638
- } else if (vals[space.charAt(0)] !== undefined) {
639
- // {r: 10, g: 10, b: 10}
640
- for (i = 0; i < space.length; i++) {
641
- values[space][i] = vals[space.charAt(i)];
642
- }
643
-
644
- alpha = vals.a;
645
- } else if (vals[spaces[space][0]] !== undefined) {
646
- // {red: 10, green: 10, blue: 10}
647
- var chans = spaces[space];
648
-
649
- for (i = 0; i < space.length; i++) {
650
- values[space][i] = vals[chans[i]];
651
- }
652
-
653
- alpha = vals.alpha;
654
- }
655
-
656
- values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
657
-
658
- if (space === 'alpha') {
659
- return false;
660
- }
661
-
662
- var capped;
663
-
664
- // cap values of the space prior converting all values
665
- for (i = 0; i < space.length; i++) {
666
- capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
667
- values[space][i] = Math.round(capped);
668
- }
669
-
670
- // convert to all the other color spaces
671
- for (var sname in spaces) {
672
- if (sname !== space) {
673
- values[sname] = convert[space][sname](values[space]);
674
- }
675
- }
676
-
677
- return true;
678
- };
679
-
680
- Color.prototype.setSpace = function (space, args) {
681
- var vals = args[0];
682
-
683
- if (vals === undefined) {
684
- // color.rgb()
685
- return this.getValues(space);
686
- }
687
-
688
- // color.rgb(10, 10, 10)
689
- if (typeof vals === 'number') {
690
- vals = Array.prototype.slice.call(args);
691
- }
692
-
693
- this.setValues(space, vals);
694
- return this;
695
- };
696
-
697
- Color.prototype.setChannel = function (space, index, val) {
698
- var svalues = this.values[space];
699
- if (val === undefined) {
700
- // color.red()
701
- return svalues[index];
702
- } else if (val === svalues[index]) {
703
- // color.red(color.red())
704
- return this;
705
- }
706
-
707
- // color.red(100)
708
- svalues[index] = val;
709
- this.setValues(space, svalues);
710
-
711
- return this;
712
- };
713
-
714
- if (typeof window !== 'undefined') {
715
- window.Color = Color;
716
- }
717
-
718
- module.exports = Color;
719
-
720
- },{"1":1,"4":4}],3:[function(require,module,exports){
721
- /* MIT license */
722
-
723
- module.exports = {
724
- rgb2hsl: rgb2hsl,
725
- rgb2hsv: rgb2hsv,
726
- rgb2hwb: rgb2hwb,
727
- rgb2cmyk: rgb2cmyk,
728
- rgb2keyword: rgb2keyword,
729
- rgb2xyz: rgb2xyz,
730
- rgb2lab: rgb2lab,
731
- rgb2lch: rgb2lch,
732
-
733
- hsl2rgb: hsl2rgb,
734
- hsl2hsv: hsl2hsv,
735
- hsl2hwb: hsl2hwb,
736
- hsl2cmyk: hsl2cmyk,
737
- hsl2keyword: hsl2keyword,
738
-
739
- hsv2rgb: hsv2rgb,
740
- hsv2hsl: hsv2hsl,
741
- hsv2hwb: hsv2hwb,
742
- hsv2cmyk: hsv2cmyk,
743
- hsv2keyword: hsv2keyword,
744
-
745
- hwb2rgb: hwb2rgb,
746
- hwb2hsl: hwb2hsl,
747
- hwb2hsv: hwb2hsv,
748
- hwb2cmyk: hwb2cmyk,
749
- hwb2keyword: hwb2keyword,
750
-
751
- cmyk2rgb: cmyk2rgb,
752
- cmyk2hsl: cmyk2hsl,
753
- cmyk2hsv: cmyk2hsv,
754
- cmyk2hwb: cmyk2hwb,
755
- cmyk2keyword: cmyk2keyword,
756
-
757
- keyword2rgb: keyword2rgb,
758
- keyword2hsl: keyword2hsl,
759
- keyword2hsv: keyword2hsv,
760
- keyword2hwb: keyword2hwb,
761
- keyword2cmyk: keyword2cmyk,
762
- keyword2lab: keyword2lab,
763
- keyword2xyz: keyword2xyz,
764
-
765
- xyz2rgb: xyz2rgb,
766
- xyz2lab: xyz2lab,
767
- xyz2lch: xyz2lch,
768
-
769
- lab2xyz: lab2xyz,
770
- lab2rgb: lab2rgb,
771
- lab2lch: lab2lch,
772
-
773
- lch2lab: lch2lab,
774
- lch2xyz: lch2xyz,
775
- lch2rgb: lch2rgb
776
- }
777
-
778
-
779
- function rgb2hsl(rgb) {
780
- var r = rgb[0]/255,
781
- g = rgb[1]/255,
782
- b = rgb[2]/255,
783
- min = Math.min(r, g, b),
784
- max = Math.max(r, g, b),
785
- delta = max - min,
786
- h, s, l;
787
-
788
- if (max == min)
789
- h = 0;
790
- else if (r == max)
791
- h = (g - b) / delta;
792
- else if (g == max)
793
- h = 2 + (b - r) / delta;
794
- else if (b == max)
795
- h = 4 + (r - g)/ delta;
796
-
797
- h = Math.min(h * 60, 360);
798
-
799
- if (h < 0)
800
- h += 360;
801
-
802
- l = (min + max) / 2;
803
-
804
- if (max == min)
805
- s = 0;
806
- else if (l <= 0.5)
807
- s = delta / (max + min);
808
- else
809
- s = delta / (2 - max - min);
810
-
811
- return [h, s * 100, l * 100];
812
- }
813
-
814
- function rgb2hsv(rgb) {
815
- var r = rgb[0],
816
- g = rgb[1],
817
- b = rgb[2],
818
- min = Math.min(r, g, b),
819
- max = Math.max(r, g, b),
820
- delta = max - min,
821
- h, s, v;
822
-
823
- if (max == 0)
824
- s = 0;
825
- else
826
- s = (delta/max * 1000)/10;
827
-
828
- if (max == min)
829
- h = 0;
830
- else if (r == max)
831
- h = (g - b) / delta;
832
- else if (g == max)
833
- h = 2 + (b - r) / delta;
834
- else if (b == max)
835
- h = 4 + (r - g) / delta;
836
-
837
- h = Math.min(h * 60, 360);
838
-
839
- if (h < 0)
840
- h += 360;
841
-
842
- v = ((max / 255) * 1000) / 10;
843
-
844
- return [h, s, v];
845
- }
846
-
847
- function rgb2hwb(rgb) {
848
- var r = rgb[0],
849
- g = rgb[1],
850
- b = rgb[2],
851
- h = rgb2hsl(rgb)[0],
852
- w = 1/255 * Math.min(r, Math.min(g, b)),
853
- b = 1 - 1/255 * Math.max(r, Math.max(g, b));
854
-
855
- return [h, w * 100, b * 100];
856
- }
857
-
858
- function rgb2cmyk(rgb) {
859
- var r = rgb[0] / 255,
860
- g = rgb[1] / 255,
861
- b = rgb[2] / 255,
862
- c, m, y, k;
863
-
864
- k = Math.min(1 - r, 1 - g, 1 - b);
865
- c = (1 - r - k) / (1 - k) || 0;
866
- m = (1 - g - k) / (1 - k) || 0;
867
- y = (1 - b - k) / (1 - k) || 0;
868
- return [c * 100, m * 100, y * 100, k * 100];
869
- }
870
-
871
- function rgb2keyword(rgb) {
872
- return reverseKeywords[JSON.stringify(rgb)];
873
- }
874
-
875
- function rgb2xyz(rgb) {
876
- var r = rgb[0] / 255,
877
- g = rgb[1] / 255,
878
- b = rgb[2] / 255;
879
-
880
- // assume sRGB
881
- r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
882
- g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
883
- b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
884
-
885
- var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
886
- var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
887
- var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
888
-
889
- return [x * 100, y *100, z * 100];
890
- }
891
-
892
- function rgb2lab(rgb) {
893
- var xyz = rgb2xyz(rgb),
894
- x = xyz[0],
895
- y = xyz[1],
896
- z = xyz[2],
897
- l, a, b;
898
-
899
- x /= 95.047;
900
- y /= 100;
901
- z /= 108.883;
902
-
903
- x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
904
- y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
905
- z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
906
-
907
- l = (116 * y) - 16;
908
- a = 500 * (x - y);
909
- b = 200 * (y - z);
910
-
911
- return [l, a, b];
912
- }
913
-
914
- function rgb2lch(args) {
915
- return lab2lch(rgb2lab(args));
916
- }
917
-
918
- function hsl2rgb(hsl) {
919
- var h = hsl[0] / 360,
920
- s = hsl[1] / 100,
921
- l = hsl[2] / 100,
922
- t1, t2, t3, rgb, val;
923
-
924
- if (s == 0) {
925
- val = l * 255;
926
- return [val, val, val];
927
- }
928
-
929
- if (l < 0.5)
930
- t2 = l * (1 + s);
931
- else
932
- t2 = l + s - l * s;
933
- t1 = 2 * l - t2;
934
-
935
- rgb = [0, 0, 0];
936
- for (var i = 0; i < 3; i++) {
937
- t3 = h + 1 / 3 * - (i - 1);
938
- t3 < 0 && t3++;
939
- t3 > 1 && t3--;
940
-
941
- if (6 * t3 < 1)
942
- val = t1 + (t2 - t1) * 6 * t3;
943
- else if (2 * t3 < 1)
944
- val = t2;
945
- else if (3 * t3 < 2)
946
- val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
947
- else
948
- val = t1;
949
-
950
- rgb[i] = val * 255;
951
- }
952
-
953
- return rgb;
954
- }
955
-
956
- function hsl2hsv(hsl) {
957
- var h = hsl[0],
958
- s = hsl[1] / 100,
959
- l = hsl[2] / 100,
960
- sv, v;
961
-
962
- if(l === 0) {
963
- // no need to do calc on black
964
- // also avoids divide by 0 error
965
- return [0, 0, 0];
966
- }
967
-
968
- l *= 2;
969
- s *= (l <= 1) ? l : 2 - l;
970
- v = (l + s) / 2;
971
- sv = (2 * s) / (l + s);
972
- return [h, sv * 100, v * 100];
973
- }
974
-
975
- function hsl2hwb(args) {
976
- return rgb2hwb(hsl2rgb(args));
977
- }
978
-
979
- function hsl2cmyk(args) {
980
- return rgb2cmyk(hsl2rgb(args));
981
- }
982
-
983
- function hsl2keyword(args) {
984
- return rgb2keyword(hsl2rgb(args));
985
- }
986
-
987
-
988
- function hsv2rgb(hsv) {
989
- var h = hsv[0] / 60,
990
- s = hsv[1] / 100,
991
- v = hsv[2] / 100,
992
- hi = Math.floor(h) % 6;
993
-
994
- var f = h - Math.floor(h),
995
- p = 255 * v * (1 - s),
996
- q = 255 * v * (1 - (s * f)),
997
- t = 255 * v * (1 - (s * (1 - f))),
998
- v = 255 * v;
999
-
1000
- switch(hi) {
1001
- case 0:
1002
- return [v, t, p];
1003
- case 1:
1004
- return [q, v, p];
1005
- case 2:
1006
- return [p, v, t];
1007
- case 3:
1008
- return [p, q, v];
1009
- case 4:
1010
- return [t, p, v];
1011
- case 5:
1012
- return [v, p, q];
1013
- }
1014
- }
1015
-
1016
- function hsv2hsl(hsv) {
1017
- var h = hsv[0],
1018
- s = hsv[1] / 100,
1019
- v = hsv[2] / 100,
1020
- sl, l;
1021
-
1022
- l = (2 - s) * v;
1023
- sl = s * v;
1024
- sl /= (l <= 1) ? l : 2 - l;
1025
- sl = sl || 0;
1026
- l /= 2;
1027
- return [h, sl * 100, l * 100];
1028
- }
1029
-
1030
- function hsv2hwb(args) {
1031
- return rgb2hwb(hsv2rgb(args))
1032
- }
1033
-
1034
- function hsv2cmyk(args) {
1035
- return rgb2cmyk(hsv2rgb(args));
1036
- }
1037
-
1038
- function hsv2keyword(args) {
1039
- return rgb2keyword(hsv2rgb(args));
1040
- }
1041
-
1042
- // http://dev.w3.org/csswg/css-color/#hwb-to-rgb
1043
- function hwb2rgb(hwb) {
1044
- var h = hwb[0] / 360,
1045
- wh = hwb[1] / 100,
1046
- bl = hwb[2] / 100,
1047
- ratio = wh + bl,
1048
- i, v, f, n;
1049
-
1050
- // wh + bl cant be > 1
1051
- if (ratio > 1) {
1052
- wh /= ratio;
1053
- bl /= ratio;
1054
- }
1055
-
1056
- i = Math.floor(6 * h);
1057
- v = 1 - bl;
1058
- f = 6 * h - i;
1059
- if ((i & 0x01) != 0) {
1060
- f = 1 - f;
1061
- }
1062
- n = wh + f * (v - wh); // linear interpolation
1063
-
1064
- switch (i) {
1065
- default:
1066
- case 6:
1067
- case 0: r = v; g = n; b = wh; break;
1068
- case 1: r = n; g = v; b = wh; break;
1069
- case 2: r = wh; g = v; b = n; break;
1070
- case 3: r = wh; g = n; b = v; break;
1071
- case 4: r = n; g = wh; b = v; break;
1072
- case 5: r = v; g = wh; b = n; break;
1073
- }
1074
-
1075
- return [r * 255, g * 255, b * 255];
1076
- }
1077
-
1078
- function hwb2hsl(args) {
1079
- return rgb2hsl(hwb2rgb(args));
1080
- }
1081
-
1082
- function hwb2hsv(args) {
1083
- return rgb2hsv(hwb2rgb(args));
1084
- }
1085
-
1086
- function hwb2cmyk(args) {
1087
- return rgb2cmyk(hwb2rgb(args));
1088
- }
1089
-
1090
- function hwb2keyword(args) {
1091
- return rgb2keyword(hwb2rgb(args));
1092
- }
1093
-
1094
- function cmyk2rgb(cmyk) {
1095
- var c = cmyk[0] / 100,
1096
- m = cmyk[1] / 100,
1097
- y = cmyk[2] / 100,
1098
- k = cmyk[3] / 100,
1099
- r, g, b;
1100
-
1101
- r = 1 - Math.min(1, c * (1 - k) + k);
1102
- g = 1 - Math.min(1, m * (1 - k) + k);
1103
- b = 1 - Math.min(1, y * (1 - k) + k);
1104
- return [r * 255, g * 255, b * 255];
1105
- }
1106
-
1107
- function cmyk2hsl(args) {
1108
- return rgb2hsl(cmyk2rgb(args));
1109
- }
1110
-
1111
- function cmyk2hsv(args) {
1112
- return rgb2hsv(cmyk2rgb(args));
1113
- }
1114
-
1115
- function cmyk2hwb(args) {
1116
- return rgb2hwb(cmyk2rgb(args));
1117
- }
1118
-
1119
- function cmyk2keyword(args) {
1120
- return rgb2keyword(cmyk2rgb(args));
1121
- }
1122
-
1123
-
1124
- function xyz2rgb(xyz) {
1125
- var x = xyz[0] / 100,
1126
- y = xyz[1] / 100,
1127
- z = xyz[2] / 100,
1128
- r, g, b;
1129
-
1130
- r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
1131
- g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
1132
- b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
1133
-
1134
- // assume sRGB
1135
- r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
1136
- : r = (r * 12.92);
1137
-
1138
- g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
1139
- : g = (g * 12.92);
1140
-
1141
- b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
1142
- : b = (b * 12.92);
1143
-
1144
- r = Math.min(Math.max(0, r), 1);
1145
- g = Math.min(Math.max(0, g), 1);
1146
- b = Math.min(Math.max(0, b), 1);
1147
-
1148
- return [r * 255, g * 255, b * 255];
1149
- }
1150
-
1151
- function xyz2lab(xyz) {
1152
- var x = xyz[0],
1153
- y = xyz[1],
1154
- z = xyz[2],
1155
- l, a, b;
1156
-
1157
- x /= 95.047;
1158
- y /= 100;
1159
- z /= 108.883;
1160
-
1161
- x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
1162
- y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
1163
- z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
1164
-
1165
- l = (116 * y) - 16;
1166
- a = 500 * (x - y);
1167
- b = 200 * (y - z);
1168
-
1169
- return [l, a, b];
1170
- }
1171
-
1172
- function xyz2lch(args) {
1173
- return lab2lch(xyz2lab(args));
1174
- }
1175
-
1176
- function lab2xyz(lab) {
1177
- var l = lab[0],
1178
- a = lab[1],
1179
- b = lab[2],
1180
- x, y, z, y2;
1181
-
1182
- if (l <= 8) {
1183
- y = (l * 100) / 903.3;
1184
- y2 = (7.787 * (y / 100)) + (16 / 116);
1185
- } else {
1186
- y = 100 * Math.pow((l + 16) / 116, 3);
1187
- y2 = Math.pow(y / 100, 1/3);
1188
- }
1189
-
1190
- x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
1191
-
1192
- z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
1193
-
1194
- return [x, y, z];
1195
- }
1196
-
1197
- function lab2lch(lab) {
1198
- var l = lab[0],
1199
- a = lab[1],
1200
- b = lab[2],
1201
- hr, h, c;
1202
-
1203
- hr = Math.atan2(b, a);
1204
- h = hr * 360 / 2 / Math.PI;
1205
- if (h < 0) {
1206
- h += 360;
1207
- }
1208
- c = Math.sqrt(a * a + b * b);
1209
- return [l, c, h];
1210
- }
1211
-
1212
- function lab2rgb(args) {
1213
- return xyz2rgb(lab2xyz(args));
1214
- }
1215
-
1216
- function lch2lab(lch) {
1217
- var l = lch[0],
1218
- c = lch[1],
1219
- h = lch[2],
1220
- a, b, hr;
1221
-
1222
- hr = h / 360 * 2 * Math.PI;
1223
- a = c * Math.cos(hr);
1224
- b = c * Math.sin(hr);
1225
- return [l, a, b];
1226
- }
1227
-
1228
- function lch2xyz(args) {
1229
- return lab2xyz(lch2lab(args));
1230
- }
1231
-
1232
- function lch2rgb(args) {
1233
- return lab2rgb(lch2lab(args));
1234
- }
1235
-
1236
- function keyword2rgb(keyword) {
1237
- return cssKeywords[keyword];
1238
- }
1239
-
1240
- function keyword2hsl(args) {
1241
- return rgb2hsl(keyword2rgb(args));
1242
- }
1243
-
1244
- function keyword2hsv(args) {
1245
- return rgb2hsv(keyword2rgb(args));
1246
- }
1247
-
1248
- function keyword2hwb(args) {
1249
- return rgb2hwb(keyword2rgb(args));
1250
- }
1251
-
1252
- function keyword2cmyk(args) {
1253
- return rgb2cmyk(keyword2rgb(args));
1254
- }
1255
-
1256
- function keyword2lab(args) {
1257
- return rgb2lab(keyword2rgb(args));
1258
- }
1259
-
1260
- function keyword2xyz(args) {
1261
- return rgb2xyz(keyword2rgb(args));
1262
- }
1263
-
1264
- var cssKeywords = {
1265
- aliceblue: [240,248,255],
1266
- antiquewhite: [250,235,215],
1267
- aqua: [0,255,255],
1268
- aquamarine: [127,255,212],
1269
- azure: [240,255,255],
1270
- beige: [245,245,220],
1271
- bisque: [255,228,196],
1272
- black: [0,0,0],
1273
- blanchedalmond: [255,235,205],
1274
- blue: [0,0,255],
1275
- blueviolet: [138,43,226],
1276
- brown: [165,42,42],
1277
- burlywood: [222,184,135],
1278
- cadetblue: [95,158,160],
1279
- chartreuse: [127,255,0],
1280
- chocolate: [210,105,30],
1281
- coral: [255,127,80],
1282
- cornflowerblue: [100,149,237],
1283
- cornsilk: [255,248,220],
1284
- crimson: [220,20,60],
1285
- cyan: [0,255,255],
1286
- darkblue: [0,0,139],
1287
- darkcyan: [0,139,139],
1288
- darkgoldenrod: [184,134,11],
1289
- darkgray: [169,169,169],
1290
- darkgreen: [0,100,0],
1291
- darkgrey: [169,169,169],
1292
- darkkhaki: [189,183,107],
1293
- darkmagenta: [139,0,139],
1294
- darkolivegreen: [85,107,47],
1295
- darkorange: [255,140,0],
1296
- darkorchid: [153,50,204],
1297
- darkred: [139,0,0],
1298
- darksalmon: [233,150,122],
1299
- darkseagreen: [143,188,143],
1300
- darkslateblue: [72,61,139],
1301
- darkslategray: [47,79,79],
1302
- darkslategrey: [47,79,79],
1303
- darkturquoise: [0,206,209],
1304
- darkviolet: [148,0,211],
1305
- deeppink: [255,20,147],
1306
- deepskyblue: [0,191,255],
1307
- dimgray: [105,105,105],
1308
- dimgrey: [105,105,105],
1309
- dodgerblue: [30,144,255],
1310
- firebrick: [178,34,34],
1311
- floralwhite: [255,250,240],
1312
- forestgreen: [34,139,34],
1313
- fuchsia: [255,0,255],
1314
- gainsboro: [220,220,220],
1315
- ghostwhite: [248,248,255],
1316
- gold: [255,215,0],
1317
- goldenrod: [218,165,32],
1318
- gray: [128,128,128],
1319
- green: [0,128,0],
1320
- greenyellow: [173,255,47],
1321
- grey: [128,128,128],
1322
- honeydew: [240,255,240],
1323
- hotpink: [255,105,180],
1324
- indianred: [205,92,92],
1325
- indigo: [75,0,130],
1326
- ivory: [255,255,240],
1327
- khaki: [240,230,140],
1328
- lavender: [230,230,250],
1329
- lavenderblush: [255,240,245],
1330
- lawngreen: [124,252,0],
1331
- lemonchiffon: [255,250,205],
1332
- lightblue: [173,216,230],
1333
- lightcoral: [240,128,128],
1334
- lightcyan: [224,255,255],
1335
- lightgoldenrodyellow: [250,250,210],
1336
- lightgray: [211,211,211],
1337
- lightgreen: [144,238,144],
1338
- lightgrey: [211,211,211],
1339
- lightpink: [255,182,193],
1340
- lightsalmon: [255,160,122],
1341
- lightseagreen: [32,178,170],
1342
- lightskyblue: [135,206,250],
1343
- lightslategray: [119,136,153],
1344
- lightslategrey: [119,136,153],
1345
- lightsteelblue: [176,196,222],
1346
- lightyellow: [255,255,224],
1347
- lime: [0,255,0],
1348
- limegreen: [50,205,50],
1349
- linen: [250,240,230],
1350
- magenta: [255,0,255],
1351
- maroon: [128,0,0],
1352
- mediumaquamarine: [102,205,170],
1353
- mediumblue: [0,0,205],
1354
- mediumorchid: [186,85,211],
1355
- mediumpurple: [147,112,219],
1356
- mediumseagreen: [60,179,113],
1357
- mediumslateblue: [123,104,238],
1358
- mediumspringgreen: [0,250,154],
1359
- mediumturquoise: [72,209,204],
1360
- mediumvioletred: [199,21,133],
1361
- midnightblue: [25,25,112],
1362
- mintcream: [245,255,250],
1363
- mistyrose: [255,228,225],
1364
- moccasin: [255,228,181],
1365
- navajowhite: [255,222,173],
1366
- navy: [0,0,128],
1367
- oldlace: [253,245,230],
1368
- olive: [128,128,0],
1369
- olivedrab: [107,142,35],
1370
- orange: [255,165,0],
1371
- orangered: [255,69,0],
1372
- orchid: [218,112,214],
1373
- palegoldenrod: [238,232,170],
1374
- palegreen: [152,251,152],
1375
- paleturquoise: [175,238,238],
1376
- palevioletred: [219,112,147],
1377
- papayawhip: [255,239,213],
1378
- peachpuff: [255,218,185],
1379
- peru: [205,133,63],
1380
- pink: [255,192,203],
1381
- plum: [221,160,221],
1382
- powderblue: [176,224,230],
1383
- purple: [128,0,128],
1384
- rebeccapurple: [102, 51, 153],
1385
- red: [255,0,0],
1386
- rosybrown: [188,143,143],
1387
- royalblue: [65,105,225],
1388
- saddlebrown: [139,69,19],
1389
- salmon: [250,128,114],
1390
- sandybrown: [244,164,96],
1391
- seagreen: [46,139,87],
1392
- seashell: [255,245,238],
1393
- sienna: [160,82,45],
1394
- silver: [192,192,192],
1395
- skyblue: [135,206,235],
1396
- slateblue: [106,90,205],
1397
- slategray: [112,128,144],
1398
- slategrey: [112,128,144],
1399
- snow: [255,250,250],
1400
- springgreen: [0,255,127],
1401
- steelblue: [70,130,180],
1402
- tan: [210,180,140],
1403
- teal: [0,128,128],
1404
- thistle: [216,191,216],
1405
- tomato: [255,99,71],
1406
- turquoise: [64,224,208],
1407
- violet: [238,130,238],
1408
- wheat: [245,222,179],
1409
- white: [255,255,255],
1410
- whitesmoke: [245,245,245],
1411
- yellow: [255,255,0],
1412
- yellowgreen: [154,205,50]
1413
- };
1414
-
1415
- var reverseKeywords = {};
1416
- for (var key in cssKeywords) {
1417
- reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
1418
- }
1419
-
1420
- },{}],4:[function(require,module,exports){
1421
- var conversions = require(3);
1422
-
1423
- var convert = function() {
1424
- return new Converter();
1425
- }
1426
-
1427
- for (var func in conversions) {
1428
- // export Raw versions
1429
- convert[func + "Raw"] = (function(func) {
1430
- // accept array or plain args
1431
- return function(arg) {
1432
- if (typeof arg == "number")
1433
- arg = Array.prototype.slice.call(arguments);
1434
- return conversions[func](arg);
1435
- }
1436
- })(func);
1437
-
1438
- var pair = /(\w+)2(\w+)/.exec(func),
1439
- from = pair[1],
1440
- to = pair[2];
1441
-
1442
- // export rgb2hsl and ["rgb"]["hsl"]
1443
- convert[from] = convert[from] || {};
1444
-
1445
- convert[from][to] = convert[func] = (function(func) {
1446
- return function(arg) {
1447
- if (typeof arg == "number")
1448
- arg = Array.prototype.slice.call(arguments);
1449
-
1450
- var val = conversions[func](arg);
1451
- if (typeof val == "string" || val === undefined)
1452
- return val; // keyword
1453
-
1454
- for (var i = 0; i < val.length; i++)
1455
- val[i] = Math.round(val[i]);
1456
- return val;
1457
- }
1458
- })(func);
1459
- }
1460
-
1461
-
1462
- /* Converter does lazy conversion and caching */
1463
- var Converter = function() {
1464
- this.convs = {};
1465
- };
1466
-
1467
- /* Either get the values for a space or
1468
- set the values for a space, depending on args */
1469
- Converter.prototype.routeSpace = function(space, args) {
1470
- var values = args[0];
1471
- if (values === undefined) {
1472
- // color.rgb()
1473
- return this.getValues(space);
1474
- }
1475
- // color.rgb(10, 10, 10)
1476
- if (typeof values == "number") {
1477
- values = Array.prototype.slice.call(args);
1478
- }
1479
-
1480
- return this.setValues(space, values);
1481
- };
1482
-
1483
- /* Set the values for a space, invalidating cache */
1484
- Converter.prototype.setValues = function(space, values) {
1485
- this.space = space;
1486
- this.convs = {};
1487
- this.convs[space] = values;
1488
- return this;
1489
- };
1490
-
1491
- /* Get the values for a space. If there's already
1492
- a conversion for the space, fetch it, otherwise
1493
- compute it */
1494
- Converter.prototype.getValues = function(space) {
1495
- var vals = this.convs[space];
1496
- if (!vals) {
1497
- var fspace = this.space,
1498
- from = this.convs[fspace];
1499
- vals = convert[fspace][space](from);
1500
-
1501
- this.convs[space] = vals;
1502
- }
1503
- return vals;
1504
- };
1505
-
1506
- ["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
1507
- Converter.prototype[space] = function(vals) {
1508
- return this.routeSpace(space, arguments);
1509
- }
1510
- });
1511
-
1512
- module.exports = convert;
1513
- },{"3":3}],5:[function(require,module,exports){
1514
- module.exports = {
1515
- "aliceblue": [240, 248, 255],
1516
- "antiquewhite": [250, 235, 215],
1517
- "aqua": [0, 255, 255],
1518
- "aquamarine": [127, 255, 212],
1519
- "azure": [240, 255, 255],
1520
- "beige": [245, 245, 220],
1521
- "bisque": [255, 228, 196],
1522
- "black": [0, 0, 0],
1523
- "blanchedalmond": [255, 235, 205],
1524
- "blue": [0, 0, 255],
1525
- "blueviolet": [138, 43, 226],
1526
- "brown": [165, 42, 42],
1527
- "burlywood": [222, 184, 135],
1528
- "cadetblue": [95, 158, 160],
1529
- "chartreuse": [127, 255, 0],
1530
- "chocolate": [210, 105, 30],
1531
- "coral": [255, 127, 80],
1532
- "cornflowerblue": [100, 149, 237],
1533
- "cornsilk": [255, 248, 220],
1534
- "crimson": [220, 20, 60],
1535
- "cyan": [0, 255, 255],
1536
- "darkblue": [0, 0, 139],
1537
- "darkcyan": [0, 139, 139],
1538
- "darkgoldenrod": [184, 134, 11],
1539
- "darkgray": [169, 169, 169],
1540
- "darkgreen": [0, 100, 0],
1541
- "darkgrey": [169, 169, 169],
1542
- "darkkhaki": [189, 183, 107],
1543
- "darkmagenta": [139, 0, 139],
1544
- "darkolivegreen": [85, 107, 47],
1545
- "darkorange": [255, 140, 0],
1546
- "darkorchid": [153, 50, 204],
1547
- "darkred": [139, 0, 0],
1548
- "darksalmon": [233, 150, 122],
1549
- "darkseagreen": [143, 188, 143],
1550
- "darkslateblue": [72, 61, 139],
1551
- "darkslategray": [47, 79, 79],
1552
- "darkslategrey": [47, 79, 79],
1553
- "darkturquoise": [0, 206, 209],
1554
- "darkviolet": [148, 0, 211],
1555
- "deeppink": [255, 20, 147],
1556
- "deepskyblue": [0, 191, 255],
1557
- "dimgray": [105, 105, 105],
1558
- "dimgrey": [105, 105, 105],
1559
- "dodgerblue": [30, 144, 255],
1560
- "firebrick": [178, 34, 34],
1561
- "floralwhite": [255, 250, 240],
1562
- "forestgreen": [34, 139, 34],
1563
- "fuchsia": [255, 0, 255],
1564
- "gainsboro": [220, 220, 220],
1565
- "ghostwhite": [248, 248, 255],
1566
- "gold": [255, 215, 0],
1567
- "goldenrod": [218, 165, 32],
1568
- "gray": [128, 128, 128],
1569
- "green": [0, 128, 0],
1570
- "greenyellow": [173, 255, 47],
1571
- "grey": [128, 128, 128],
1572
- "honeydew": [240, 255, 240],
1573
- "hotpink": [255, 105, 180],
1574
- "indianred": [205, 92, 92],
1575
- "indigo": [75, 0, 130],
1576
- "ivory": [255, 255, 240],
1577
- "khaki": [240, 230, 140],
1578
- "lavender": [230, 230, 250],
1579
- "lavenderblush": [255, 240, 245],
1580
- "lawngreen": [124, 252, 0],
1581
- "lemonchiffon": [255, 250, 205],
1582
- "lightblue": [173, 216, 230],
1583
- "lightcoral": [240, 128, 128],
1584
- "lightcyan": [224, 255, 255],
1585
- "lightgoldenrodyellow": [250, 250, 210],
1586
- "lightgray": [211, 211, 211],
1587
- "lightgreen": [144, 238, 144],
1588
- "lightgrey": [211, 211, 211],
1589
- "lightpink": [255, 182, 193],
1590
- "lightsalmon": [255, 160, 122],
1591
- "lightseagreen": [32, 178, 170],
1592
- "lightskyblue": [135, 206, 250],
1593
- "lightslategray": [119, 136, 153],
1594
- "lightslategrey": [119, 136, 153],
1595
- "lightsteelblue": [176, 196, 222],
1596
- "lightyellow": [255, 255, 224],
1597
- "lime": [0, 255, 0],
1598
- "limegreen": [50, 205, 50],
1599
- "linen": [250, 240, 230],
1600
- "magenta": [255, 0, 255],
1601
- "maroon": [128, 0, 0],
1602
- "mediumaquamarine": [102, 205, 170],
1603
- "mediumblue": [0, 0, 205],
1604
- "mediumorchid": [186, 85, 211],
1605
- "mediumpurple": [147, 112, 219],
1606
- "mediumseagreen": [60, 179, 113],
1607
- "mediumslateblue": [123, 104, 238],
1608
- "mediumspringgreen": [0, 250, 154],
1609
- "mediumturquoise": [72, 209, 204],
1610
- "mediumvioletred": [199, 21, 133],
1611
- "midnightblue": [25, 25, 112],
1612
- "mintcream": [245, 255, 250],
1613
- "mistyrose": [255, 228, 225],
1614
- "moccasin": [255, 228, 181],
1615
- "navajowhite": [255, 222, 173],
1616
- "navy": [0, 0, 128],
1617
- "oldlace": [253, 245, 230],
1618
- "olive": [128, 128, 0],
1619
- "olivedrab": [107, 142, 35],
1620
- "orange": [255, 165, 0],
1621
- "orangered": [255, 69, 0],
1622
- "orchid": [218, 112, 214],
1623
- "palegoldenrod": [238, 232, 170],
1624
- "palegreen": [152, 251, 152],
1625
- "paleturquoise": [175, 238, 238],
1626
- "palevioletred": [219, 112, 147],
1627
- "papayawhip": [255, 239, 213],
1628
- "peachpuff": [255, 218, 185],
1629
- "peru": [205, 133, 63],
1630
- "pink": [255, 192, 203],
1631
- "plum": [221, 160, 221],
1632
- "powderblue": [176, 224, 230],
1633
- "purple": [128, 0, 128],
1634
- "rebeccapurple": [102, 51, 153],
1635
- "red": [255, 0, 0],
1636
- "rosybrown": [188, 143, 143],
1637
- "royalblue": [65, 105, 225],
1638
- "saddlebrown": [139, 69, 19],
1639
- "salmon": [250, 128, 114],
1640
- "sandybrown": [244, 164, 96],
1641
- "seagreen": [46, 139, 87],
1642
- "seashell": [255, 245, 238],
1643
- "sienna": [160, 82, 45],
1644
- "silver": [192, 192, 192],
1645
- "skyblue": [135, 206, 235],
1646
- "slateblue": [106, 90, 205],
1647
- "slategray": [112, 128, 144],
1648
- "slategrey": [112, 128, 144],
1649
- "snow": [255, 250, 250],
1650
- "springgreen": [0, 255, 127],
1651
- "steelblue": [70, 130, 180],
1652
- "tan": [210, 180, 140],
1653
- "teal": [0, 128, 128],
1654
- "thistle": [216, 191, 216],
1655
- "tomato": [255, 99, 71],
1656
- "turquoise": [64, 224, 208],
1657
- "violet": [238, 130, 238],
1658
- "wheat": [245, 222, 179],
1659
- "white": [255, 255, 255],
1660
- "whitesmoke": [245, 245, 245],
1661
- "yellow": [255, 255, 0],
1662
- "yellowgreen": [154, 205, 50]
1663
- };
1664
- },{}],6:[function(require,module,exports){
1665
- //! moment.js
1666
- //! version : 2.18.1
1667
- //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
1668
- //! license : MIT
1669
- //! momentjs.com
1670
-
1671
- ;(function (global, factory) {
1672
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
1673
- typeof define === 'function' && define.amd ? define(factory) :
1674
- global.moment = factory()
1675
- }(this, (function () { 'use strict';
1676
-
1677
- var hookCallback;
1678
-
1679
- function hooks () {
1680
- return hookCallback.apply(null, arguments);
1681
- }
1682
-
1683
- // This is done to register the method called with moment()
1684
- // without creating circular dependencies.
1685
- function setHookCallback (callback) {
1686
- hookCallback = callback;
1687
- }
1688
-
1689
- function isArray(input) {
1690
- return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
1691
- }
1692
-
1693
- function isObject(input) {
1694
- // IE8 will treat undefined and null as object if it wasn't for
1695
- // input != null
1696
- return input != null && Object.prototype.toString.call(input) === '[object Object]';
1697
- }
1698
-
1699
- function isObjectEmpty(obj) {
1700
- var k;
1701
- for (k in obj) {
1702
- // even if its not own property I'd still call it non-empty
1703
- return false;
1704
- }
1705
- return true;
1706
- }
1707
-
1708
- function isUndefined(input) {
1709
- return input === void 0;
1710
- }
1711
-
1712
- function isNumber(input) {
1713
- return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';
1714
- }
1715
-
1716
- function isDate(input) {
1717
- return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
1718
- }
1719
-
1720
- function map(arr, fn) {
1721
- var res = [], i;
1722
- for (i = 0; i < arr.length; ++i) {
1723
- res.push(fn(arr[i], i));
1724
- }
1725
- return res;
1726
- }
1727
-
1728
- function hasOwnProp(a, b) {
1729
- return Object.prototype.hasOwnProperty.call(a, b);
1730
- }
1731
-
1732
- function extend(a, b) {
1733
- for (var i in b) {
1734
- if (hasOwnProp(b, i)) {
1735
- a[i] = b[i];
1736
- }
1737
- }
1738
-
1739
- if (hasOwnProp(b, 'toString')) {
1740
- a.toString = b.toString;
1741
- }
1742
-
1743
- if (hasOwnProp(b, 'valueOf')) {
1744
- a.valueOf = b.valueOf;
1745
- }
1746
-
1747
- return a;
1748
- }
1749
-
1750
- function createUTC (input, format, locale, strict) {
1751
- return createLocalOrUTC(input, format, locale, strict, true).utc();
1752
- }
1753
-
1754
- function defaultParsingFlags() {
1755
- // We need to deep clone this object.
1756
- return {
1757
- empty : false,
1758
- unusedTokens : [],
1759
- unusedInput : [],
1760
- overflow : -2,
1761
- charsLeftOver : 0,
1762
- nullInput : false,
1763
- invalidMonth : null,
1764
- invalidFormat : false,
1765
- userInvalidated : false,
1766
- iso : false,
1767
- parsedDateParts : [],
1768
- meridiem : null,
1769
- rfc2822 : false,
1770
- weekdayMismatch : false
1771
- };
1772
- }
1773
-
1774
- function getParsingFlags(m) {
1775
- if (m._pf == null) {
1776
- m._pf = defaultParsingFlags();
1777
- }
1778
- return m._pf;
1779
- }
1780
-
1781
- var some;
1782
- if (Array.prototype.some) {
1783
- some = Array.prototype.some;
1784
- } else {
1785
- some = function (fun) {
1786
- var t = Object(this);
1787
- var len = t.length >>> 0;
1788
-
1789
- for (var i = 0; i < len; i++) {
1790
- if (i in t && fun.call(this, t[i], i, t)) {
1791
- return true;
1792
- }
1793
- }
1794
-
1795
- return false;
1796
- };
1797
- }
1798
-
1799
- var some$1 = some;
1800
-
1801
- function isValid(m) {
1802
- if (m._isValid == null) {
1803
- var flags = getParsingFlags(m);
1804
- var parsedParts = some$1.call(flags.parsedDateParts, function (i) {
1805
- return i != null;
1806
- });
1807
- var isNowValid = !isNaN(m._d.getTime()) &&
1808
- flags.overflow < 0 &&
1809
- !flags.empty &&
1810
- !flags.invalidMonth &&
1811
- !flags.invalidWeekday &&
1812
- !flags.nullInput &&
1813
- !flags.invalidFormat &&
1814
- !flags.userInvalidated &&
1815
- (!flags.meridiem || (flags.meridiem && parsedParts));
1816
-
1817
- if (m._strict) {
1818
- isNowValid = isNowValid &&
1819
- flags.charsLeftOver === 0 &&
1820
- flags.unusedTokens.length === 0 &&
1821
- flags.bigHour === undefined;
1822
- }
1823
-
1824
- if (Object.isFrozen == null || !Object.isFrozen(m)) {
1825
- m._isValid = isNowValid;
1826
- }
1827
- else {
1828
- return isNowValid;
1829
- }
1830
- }
1831
- return m._isValid;
1832
- }
1833
-
1834
- function createInvalid (flags) {
1835
- var m = createUTC(NaN);
1836
- if (flags != null) {
1837
- extend(getParsingFlags(m), flags);
1838
- }
1839
- else {
1840
- getParsingFlags(m).userInvalidated = true;
1841
- }
1842
-
1843
- return m;
1844
- }
1845
-
1846
- // Plugins that add properties should also add the key here (null value),
1847
- // so we can properly clone ourselves.
1848
- var momentProperties = hooks.momentProperties = [];
1849
-
1850
- function copyConfig(to, from) {
1851
- var i, prop, val;
1852
-
1853
- if (!isUndefined(from._isAMomentObject)) {
1854
- to._isAMomentObject = from._isAMomentObject;
1855
- }
1856
- if (!isUndefined(from._i)) {
1857
- to._i = from._i;
1858
- }
1859
- if (!isUndefined(from._f)) {
1860
- to._f = from._f;
1861
- }
1862
- if (!isUndefined(from._l)) {
1863
- to._l = from._l;
1864
- }
1865
- if (!isUndefined(from._strict)) {
1866
- to._strict = from._strict;
1867
- }
1868
- if (!isUndefined(from._tzm)) {
1869
- to._tzm = from._tzm;
1870
- }
1871
- if (!isUndefined(from._isUTC)) {
1872
- to._isUTC = from._isUTC;
1873
- }
1874
- if (!isUndefined(from._offset)) {
1875
- to._offset = from._offset;
1876
- }
1877
- if (!isUndefined(from._pf)) {
1878
- to._pf = getParsingFlags(from);
1879
- }
1880
- if (!isUndefined(from._locale)) {
1881
- to._locale = from._locale;
1882
- }
1883
-
1884
- if (momentProperties.length > 0) {
1885
- for (i = 0; i < momentProperties.length; i++) {
1886
- prop = momentProperties[i];
1887
- val = from[prop];
1888
- if (!isUndefined(val)) {
1889
- to[prop] = val;
1890
- }
1891
- }
1892
- }
1893
-
1894
- return to;
1895
- }
1896
-
1897
- var updateInProgress = false;
1898
-
1899
- // Moment prototype object
1900
- function Moment(config) {
1901
- copyConfig(this, config);
1902
- this._d = new Date(config._d != null ? config._d.getTime() : NaN);
1903
- if (!this.isValid()) {
1904
- this._d = new Date(NaN);
1905
- }
1906
- // Prevent infinite loop in case updateOffset creates new moment
1907
- // objects.
1908
- if (updateInProgress === false) {
1909
- updateInProgress = true;
1910
- hooks.updateOffset(this);
1911
- updateInProgress = false;
1912
- }
1913
- }
1914
-
1915
- function isMoment (obj) {
1916
- return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
1917
- }
1918
-
1919
- function absFloor (number) {
1920
- if (number < 0) {
1921
- // -0 -> 0
1922
- return Math.ceil(number) || 0;
1923
- } else {
1924
- return Math.floor(number);
1925
- }
1926
- }
1927
-
1928
- function toInt(argumentForCoercion) {
1929
- var coercedNumber = +argumentForCoercion,
1930
- value = 0;
1931
-
1932
- if (coercedNumber !== 0 && isFinite(coercedNumber)) {
1933
- value = absFloor(coercedNumber);
1934
- }
1935
-
1936
- return value;
1937
- }
1938
-
1939
- // compare two arrays, return the number of differences
1940
- function compareArrays(array1, array2, dontConvert) {
1941
- var len = Math.min(array1.length, array2.length),
1942
- lengthDiff = Math.abs(array1.length - array2.length),
1943
- diffs = 0,
1944
- i;
1945
- for (i = 0; i < len; i++) {
1946
- if ((dontConvert && array1[i] !== array2[i]) ||
1947
- (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
1948
- diffs++;
1949
- }
1950
- }
1951
- return diffs + lengthDiff;
1952
- }
1953
-
1954
- function warn(msg) {
1955
- if (hooks.suppressDeprecationWarnings === false &&
1956
- (typeof console !== 'undefined') && console.warn) {
1957
- console.warn('Deprecation warning: ' + msg);
1958
- }
1959
- }
1960
-
1961
- function deprecate(msg, fn) {
1962
- var firstTime = true;
1963
-
1964
- return extend(function () {
1965
- if (hooks.deprecationHandler != null) {
1966
- hooks.deprecationHandler(null, msg);
1967
- }
1968
- if (firstTime) {
1969
- var args = [];
1970
- var arg;
1971
- for (var i = 0; i < arguments.length; i++) {
1972
- arg = '';
1973
- if (typeof arguments[i] === 'object') {
1974
- arg += '\n[' + i + '] ';
1975
- for (var key in arguments[0]) {
1976
- arg += key + ': ' + arguments[0][key] + ', ';
1977
- }
1978
- arg = arg.slice(0, -2); // Remove trailing comma and space
1979
- } else {
1980
- arg = arguments[i];
1981
- }
1982
- args.push(arg);
1983
- }
1984
- warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);
1985
- firstTime = false;
1986
- }
1987
- return fn.apply(this, arguments);
1988
- }, fn);
1989
- }
1990
-
1991
- var deprecations = {};
1992
-
1993
- function deprecateSimple(name, msg) {
1994
- if (hooks.deprecationHandler != null) {
1995
- hooks.deprecationHandler(name, msg);
1996
- }
1997
- if (!deprecations[name]) {
1998
- warn(msg);
1999
- deprecations[name] = true;
2000
- }
2001
- }
2002
-
2003
- hooks.suppressDeprecationWarnings = false;
2004
- hooks.deprecationHandler = null;
2005
-
2006
- function isFunction(input) {
2007
- return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
2008
- }
2009
-
2010
- function set (config) {
2011
- var prop, i;
2012
- for (i in config) {
2013
- prop = config[i];
2014
- if (isFunction(prop)) {
2015
- this[i] = prop;
2016
- } else {
2017
- this['_' + i] = prop;
2018
- }
2019
- }
2020
- this._config = config;
2021
- // Lenient ordinal parsing accepts just a number in addition to
2022
- // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
2023
- // TODO: Remove "ordinalParse" fallback in next major release.
2024
- this._dayOfMonthOrdinalParseLenient = new RegExp(
2025
- (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
2026
- '|' + (/\d{1,2}/).source);
2027
- }
2028
-
2029
- function mergeConfigs(parentConfig, childConfig) {
2030
- var res = extend({}, parentConfig), prop;
2031
- for (prop in childConfig) {
2032
- if (hasOwnProp(childConfig, prop)) {
2033
- if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
2034
- res[prop] = {};
2035
- extend(res[prop], parentConfig[prop]);
2036
- extend(res[prop], childConfig[prop]);
2037
- } else if (childConfig[prop] != null) {
2038
- res[prop] = childConfig[prop];
2039
- } else {
2040
- delete res[prop];
2041
- }
2042
- }
2043
- }
2044
- for (prop in parentConfig) {
2045
- if (hasOwnProp(parentConfig, prop) &&
2046
- !hasOwnProp(childConfig, prop) &&
2047
- isObject(parentConfig[prop])) {
2048
- // make sure changes to properties don't modify parent config
2049
- res[prop] = extend({}, res[prop]);
2050
- }
2051
- }
2052
- return res;
2053
- }
2054
-
2055
- function Locale(config) {
2056
- if (config != null) {
2057
- this.set(config);
2058
- }
2059
- }
2060
-
2061
- var keys;
2062
-
2063
- if (Object.keys) {
2064
- keys = Object.keys;
2065
- } else {
2066
- keys = function (obj) {
2067
- var i, res = [];
2068
- for (i in obj) {
2069
- if (hasOwnProp(obj, i)) {
2070
- res.push(i);
2071
- }
2072
- }
2073
- return res;
2074
- };
2075
- }
2076
-
2077
- var keys$1 = keys;
2078
-
2079
- var defaultCalendar = {
2080
- sameDay : '[Today at] LT',
2081
- nextDay : '[Tomorrow at] LT',
2082
- nextWeek : 'dddd [at] LT',
2083
- lastDay : '[Yesterday at] LT',
2084
- lastWeek : '[Last] dddd [at] LT',
2085
- sameElse : 'L'
2086
- };
2087
-
2088
- function calendar (key, mom, now) {
2089
- var output = this._calendar[key] || this._calendar['sameElse'];
2090
- return isFunction(output) ? output.call(mom, now) : output;
2091
- }
2092
-
2093
- var defaultLongDateFormat = {
2094
- LTS : 'h:mm:ss A',
2095
- LT : 'h:mm A',
2096
- L : 'MM/DD/YYYY',
2097
- LL : 'MMMM D, YYYY',
2098
- LLL : 'MMMM D, YYYY h:mm A',
2099
- LLLL : 'dddd, MMMM D, YYYY h:mm A'
2100
- };
2101
-
2102
- function longDateFormat (key) {
2103
- var format = this._longDateFormat[key],
2104
- formatUpper = this._longDateFormat[key.toUpperCase()];
2105
-
2106
- if (format || !formatUpper) {
2107
- return format;
2108
- }
2109
-
2110
- this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
2111
- return val.slice(1);
2112
- });
2113
-
2114
- return this._longDateFormat[key];
2115
- }
2116
-
2117
- var defaultInvalidDate = 'Invalid date';
2118
-
2119
- function invalidDate () {
2120
- return this._invalidDate;
2121
- }
2122
-
2123
- var defaultOrdinal = '%d';
2124
- var defaultDayOfMonthOrdinalParse = /\d{1,2}/;
2125
-
2126
- function ordinal (number) {
2127
- return this._ordinal.replace('%d', number);
2128
- }
2129
-
2130
- var defaultRelativeTime = {
2131
- future : 'in %s',
2132
- past : '%s ago',
2133
- s : 'a few seconds',
2134
- ss : '%d seconds',
2135
- m : 'a minute',
2136
- mm : '%d minutes',
2137
- h : 'an hour',
2138
- hh : '%d hours',
2139
- d : 'a day',
2140
- dd : '%d days',
2141
- M : 'a month',
2142
- MM : '%d months',
2143
- y : 'a year',
2144
- yy : '%d years'
2145
- };
2146
-
2147
- function relativeTime (number, withoutSuffix, string, isFuture) {
2148
- var output = this._relativeTime[string];
2149
- return (isFunction(output)) ?
2150
- output(number, withoutSuffix, string, isFuture) :
2151
- output.replace(/%d/i, number);
2152
- }
2153
-
2154
- function pastFuture (diff, output) {
2155
- var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
2156
- return isFunction(format) ? format(output) : format.replace(/%s/i, output);
2157
- }
2158
-
2159
- var aliases = {};
2160
-
2161
- function addUnitAlias (unit, shorthand) {
2162
- var lowerCase = unit.toLowerCase();
2163
- aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
2164
- }
2165
-
2166
- function normalizeUnits(units) {
2167
- return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
2168
- }
2169
-
2170
- function normalizeObjectUnits(inputObject) {
2171
- var normalizedInput = {},
2172
- normalizedProp,
2173
- prop;
2174
-
2175
- for (prop in inputObject) {
2176
- if (hasOwnProp(inputObject, prop)) {
2177
- normalizedProp = normalizeUnits(prop);
2178
- if (normalizedProp) {
2179
- normalizedInput[normalizedProp] = inputObject[prop];
2180
- }
2181
- }
2182
- }
2183
-
2184
- return normalizedInput;
2185
- }
2186
-
2187
- var priorities = {};
2188
-
2189
- function addUnitPriority(unit, priority) {
2190
- priorities[unit] = priority;
2191
- }
2192
-
2193
- function getPrioritizedUnits(unitsObj) {
2194
- var units = [];
2195
- for (var u in unitsObj) {
2196
- units.push({unit: u, priority: priorities[u]});
2197
- }
2198
- units.sort(function (a, b) {
2199
- return a.priority - b.priority;
2200
- });
2201
- return units;
2202
- }
2203
-
2204
- function makeGetSet (unit, keepTime) {
2205
- return function (value) {
2206
- if (value != null) {
2207
- set$1(this, unit, value);
2208
- hooks.updateOffset(this, keepTime);
2209
- return this;
2210
- } else {
2211
- return get(this, unit);
2212
- }
2213
- };
2214
- }
2215
-
2216
- function get (mom, unit) {
2217
- return mom.isValid() ?
2218
- mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
2219
- }
2220
-
2221
- function set$1 (mom, unit, value) {
2222
- if (mom.isValid()) {
2223
- mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
2224
- }
2225
- }
2226
-
2227
- // MOMENTS
2228
-
2229
- function stringGet (units) {
2230
- units = normalizeUnits(units);
2231
- if (isFunction(this[units])) {
2232
- return this[units]();
2233
- }
2234
- return this;
2235
- }
2236
-
2237
-
2238
- function stringSet (units, value) {
2239
- if (typeof units === 'object') {
2240
- units = normalizeObjectUnits(units);
2241
- var prioritized = getPrioritizedUnits(units);
2242
- for (var i = 0; i < prioritized.length; i++) {
2243
- this[prioritized[i].unit](units[prioritized[i].unit]);
2244
- }
2245
- } else {
2246
- units = normalizeUnits(units);
2247
- if (isFunction(this[units])) {
2248
- return this[units](value);
2249
- }
2250
- }
2251
- return this;
2252
- }
2253
-
2254
- function zeroFill(number, targetLength, forceSign) {
2255
- var absNumber = '' + Math.abs(number),
2256
- zerosToFill = targetLength - absNumber.length,
2257
- sign = number >= 0;
2258
- return (sign ? (forceSign ? '+' : '') : '-') +
2259
- Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
2260
- }
2261
-
2262
- var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
2263
-
2264
- var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
2265
-
2266
- var formatFunctions = {};
2267
-
2268
- var formatTokenFunctions = {};
2269
-
2270
- // token: 'M'
2271
- // padded: ['MM', 2]
2272
- // ordinal: 'Mo'
2273
- // callback: function () { this.month() + 1 }
2274
- function addFormatToken (token, padded, ordinal, callback) {
2275
- var func = callback;
2276
- if (typeof callback === 'string') {
2277
- func = function () {
2278
- return this[callback]();
2279
- };
2280
- }
2281
- if (token) {
2282
- formatTokenFunctions[token] = func;
2283
- }
2284
- if (padded) {
2285
- formatTokenFunctions[padded[0]] = function () {
2286
- return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
2287
- };
2288
- }
2289
- if (ordinal) {
2290
- formatTokenFunctions[ordinal] = function () {
2291
- return this.localeData().ordinal(func.apply(this, arguments), token);
2292
- };
2293
- }
2294
- }
2295
-
2296
- function removeFormattingTokens(input) {
2297
- if (input.match(/\[[\s\S]/)) {
2298
- return input.replace(/^\[|\]$/g, '');
2299
- }
2300
- return input.replace(/\\/g, '');
2301
- }
2302
-
2303
- function makeFormatFunction(format) {
2304
- var array = format.match(formattingTokens), i, length;
2305
-
2306
- for (i = 0, length = array.length; i < length; i++) {
2307
- if (formatTokenFunctions[array[i]]) {
2308
- array[i] = formatTokenFunctions[array[i]];
2309
- } else {
2310
- array[i] = removeFormattingTokens(array[i]);
2311
- }
2312
- }
2313
-
2314
- return function (mom) {
2315
- var output = '', i;
2316
- for (i = 0; i < length; i++) {
2317
- output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];
2318
- }
2319
- return output;
2320
- };
2321
- }
2322
-
2323
- // format date using native date object
2324
- function formatMoment(m, format) {
2325
- if (!m.isValid()) {
2326
- return m.localeData().invalidDate();
2327
- }
2328
-
2329
- format = expandFormat(format, m.localeData());
2330
- formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
2331
-
2332
- return formatFunctions[format](m);
2333
- }
2334
-
2335
- function expandFormat(format, locale) {
2336
- var i = 5;
2337
-
2338
- function replaceLongDateFormatTokens(input) {
2339
- return locale.longDateFormat(input) || input;
2340
- }
2341
-
2342
- localFormattingTokens.lastIndex = 0;
2343
- while (i >= 0 && localFormattingTokens.test(format)) {
2344
- format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
2345
- localFormattingTokens.lastIndex = 0;
2346
- i -= 1;
2347
- }
2348
-
2349
- return format;
2350
- }
2351
-
2352
- var match1 = /\d/; // 0 - 9
2353
- var match2 = /\d\d/; // 00 - 99
2354
- var match3 = /\d{3}/; // 000 - 999
2355
- var match4 = /\d{4}/; // 0000 - 9999
2356
- var match6 = /[+-]?\d{6}/; // -999999 - 999999
2357
- var match1to2 = /\d\d?/; // 0 - 99
2358
- var match3to4 = /\d\d\d\d?/; // 999 - 9999
2359
- var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
2360
- var match1to3 = /\d{1,3}/; // 0 - 999
2361
- var match1to4 = /\d{1,4}/; // 0 - 9999
2362
- var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
2363
-
2364
- var matchUnsigned = /\d+/; // 0 - inf
2365
- var matchSigned = /[+-]?\d+/; // -inf - inf
2366
-
2367
- var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
2368
- var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
2369
-
2370
- var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
2371
-
2372
- // any word (or two) characters or numbers including two/three word month in arabic.
2373
- // includes scottish gaelic two word and hyphenated months
2374
- var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
2375
-
2376
-
2377
- var regexes = {};
2378
-
2379
- function addRegexToken (token, regex, strictRegex) {
2380
- regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
2381
- return (isStrict && strictRegex) ? strictRegex : regex;
2382
- };
2383
- }
2384
-
2385
- function getParseRegexForToken (token, config) {
2386
- if (!hasOwnProp(regexes, token)) {
2387
- return new RegExp(unescapeFormat(token));
2388
- }
2389
-
2390
- return regexes[token](config._strict, config._locale);
2391
- }
2392
-
2393
- // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
2394
- function unescapeFormat(s) {
2395
- return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
2396
- return p1 || p2 || p3 || p4;
2397
- }));
2398
- }
2399
-
2400
- function regexEscape(s) {
2401
- return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
2402
- }
2403
-
2404
- var tokens = {};
2405
-
2406
- function addParseToken (token, callback) {
2407
- var i, func = callback;
2408
- if (typeof token === 'string') {
2409
- token = [token];
2410
- }
2411
- if (isNumber(callback)) {
2412
- func = function (input, array) {
2413
- array[callback] = toInt(input);
2414
- };
2415
- }
2416
- for (i = 0; i < token.length; i++) {
2417
- tokens[token[i]] = func;
2418
- }
2419
- }
2420
-
2421
- function addWeekParseToken (token, callback) {
2422
- addParseToken(token, function (input, array, config, token) {
2423
- config._w = config._w || {};
2424
- callback(input, config._w, config, token);
2425
- });
2426
- }
2427
-
2428
- function addTimeToArrayFromToken(token, input, config) {
2429
- if (input != null && hasOwnProp(tokens, token)) {
2430
- tokens[token](input, config._a, config, token);
2431
- }
2432
- }
2433
-
2434
- var YEAR = 0;
2435
- var MONTH = 1;
2436
- var DATE = 2;
2437
- var HOUR = 3;
2438
- var MINUTE = 4;
2439
- var SECOND = 5;
2440
- var MILLISECOND = 6;
2441
- var WEEK = 7;
2442
- var WEEKDAY = 8;
2443
-
2444
- var indexOf;
2445
-
2446
- if (Array.prototype.indexOf) {
2447
- indexOf = Array.prototype.indexOf;
2448
- } else {
2449
- indexOf = function (o) {
2450
- // I know
2451
- var i;
2452
- for (i = 0; i < this.length; ++i) {
2453
- if (this[i] === o) {
2454
- return i;
2455
- }
2456
- }
2457
- return -1;
2458
- };
2459
- }
2460
-
2461
- var indexOf$1 = indexOf;
2462
-
2463
- function daysInMonth(year, month) {
2464
- return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
2465
- }
2466
-
2467
- // FORMATTING
2468
-
2469
- addFormatToken('M', ['MM', 2], 'Mo', function () {
2470
- return this.month() + 1;
2471
- });
2472
-
2473
- addFormatToken('MMM', 0, 0, function (format) {
2474
- return this.localeData().monthsShort(this, format);
2475
- });
2476
-
2477
- addFormatToken('MMMM', 0, 0, function (format) {
2478
- return this.localeData().months(this, format);
2479
- });
2480
-
2481
- // ALIASES
2482
-
2483
- addUnitAlias('month', 'M');
2484
-
2485
- // PRIORITY
2486
-
2487
- addUnitPriority('month', 8);
2488
-
2489
- // PARSING
2490
-
2491
- addRegexToken('M', match1to2);
2492
- addRegexToken('MM', match1to2, match2);
2493
- addRegexToken('MMM', function (isStrict, locale) {
2494
- return locale.monthsShortRegex(isStrict);
2495
- });
2496
- addRegexToken('MMMM', function (isStrict, locale) {
2497
- return locale.monthsRegex(isStrict);
2498
- });
2499
-
2500
- addParseToken(['M', 'MM'], function (input, array) {
2501
- array[MONTH] = toInt(input) - 1;
2502
- });
2503
-
2504
- addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
2505
- var month = config._locale.monthsParse(input, token, config._strict);
2506
- // if we didn't find a month name, mark the date as invalid.
2507
- if (month != null) {
2508
- array[MONTH] = month;
2509
- } else {
2510
- getParsingFlags(config).invalidMonth = input;
2511
- }
2512
- });
2513
-
2514
- // LOCALES
2515
-
2516
- var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
2517
- var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
2518
- function localeMonths (m, format) {
2519
- if (!m) {
2520
- return isArray(this._months) ? this._months :
2521
- this._months['standalone'];
2522
- }
2523
- return isArray(this._months) ? this._months[m.month()] :
2524
- this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];
2525
- }
2526
-
2527
- var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
2528
- function localeMonthsShort (m, format) {
2529
- if (!m) {
2530
- return isArray(this._monthsShort) ? this._monthsShort :
2531
- this._monthsShort['standalone'];
2532
- }
2533
- return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
2534
- this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
2535
- }
2536
-
2537
- function handleStrictParse(monthName, format, strict) {
2538
- var i, ii, mom, llc = monthName.toLocaleLowerCase();
2539
- if (!this._monthsParse) {
2540
- // this is not used
2541
- this._monthsParse = [];
2542
- this._longMonthsParse = [];
2543
- this._shortMonthsParse = [];
2544
- for (i = 0; i < 12; ++i) {
2545
- mom = createUTC([2000, i]);
2546
- this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
2547
- this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
2548
- }
2549
- }
2550
-
2551
- if (strict) {
2552
- if (format === 'MMM') {
2553
- ii = indexOf$1.call(this._shortMonthsParse, llc);
2554
- return ii !== -1 ? ii : null;
2555
- } else {
2556
- ii = indexOf$1.call(this._longMonthsParse, llc);
2557
- return ii !== -1 ? ii : null;
2558
- }
2559
- } else {
2560
- if (format === 'MMM') {
2561
- ii = indexOf$1.call(this._shortMonthsParse, llc);
2562
- if (ii !== -1) {
2563
- return ii;
2564
- }
2565
- ii = indexOf$1.call(this._longMonthsParse, llc);
2566
- return ii !== -1 ? ii : null;
2567
- } else {
2568
- ii = indexOf$1.call(this._longMonthsParse, llc);
2569
- if (ii !== -1) {
2570
- return ii;
2571
- }
2572
- ii = indexOf$1.call(this._shortMonthsParse, llc);
2573
- return ii !== -1 ? ii : null;
2574
- }
2575
- }
2576
- }
2577
-
2578
- function localeMonthsParse (monthName, format, strict) {
2579
- var i, mom, regex;
2580
-
2581
- if (this._monthsParseExact) {
2582
- return handleStrictParse.call(this, monthName, format, strict);
2583
- }
2584
-
2585
- if (!this._monthsParse) {
2586
- this._monthsParse = [];
2587
- this._longMonthsParse = [];
2588
- this._shortMonthsParse = [];
2589
- }
2590
-
2591
- // TODO: add sorting
2592
- // Sorting makes sure if one month (or abbr) is a prefix of another
2593
- // see sorting in computeMonthsParse
2594
- for (i = 0; i < 12; i++) {
2595
- // make the regex if we don't have it already
2596
- mom = createUTC([2000, i]);
2597
- if (strict && !this._longMonthsParse[i]) {
2598
- this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
2599
- this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
2600
- }
2601
- if (!strict && !this._monthsParse[i]) {
2602
- regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
2603
- this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
2604
- }
2605
- // test the regex
2606
- if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
2607
- return i;
2608
- } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
2609
- return i;
2610
- } else if (!strict && this._monthsParse[i].test(monthName)) {
2611
- return i;
2612
- }
2613
- }
2614
- }
2615
-
2616
- // MOMENTS
2617
-
2618
- function setMonth (mom, value) {
2619
- var dayOfMonth;
2620
-
2621
- if (!mom.isValid()) {
2622
- // No op
2623
- return mom;
2624
- }
2625
-
2626
- if (typeof value === 'string') {
2627
- if (/^\d+$/.test(value)) {
2628
- value = toInt(value);
2629
- } else {
2630
- value = mom.localeData().monthsParse(value);
2631
- // TODO: Another silent failure?
2632
- if (!isNumber(value)) {
2633
- return mom;
2634
- }
2635
- }
2636
- }
2637
-
2638
- dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
2639
- mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
2640
- return mom;
2641
- }
2642
-
2643
- function getSetMonth (value) {
2644
- if (value != null) {
2645
- setMonth(this, value);
2646
- hooks.updateOffset(this, true);
2647
- return this;
2648
- } else {
2649
- return get(this, 'Month');
2650
- }
2651
- }
2652
-
2653
- function getDaysInMonth () {
2654
- return daysInMonth(this.year(), this.month());
2655
- }
2656
-
2657
- var defaultMonthsShortRegex = matchWord;
2658
- function monthsShortRegex (isStrict) {
2659
- if (this._monthsParseExact) {
2660
- if (!hasOwnProp(this, '_monthsRegex')) {
2661
- computeMonthsParse.call(this);
2662
- }
2663
- if (isStrict) {
2664
- return this._monthsShortStrictRegex;
2665
- } else {
2666
- return this._monthsShortRegex;
2667
- }
2668
- } else {
2669
- if (!hasOwnProp(this, '_monthsShortRegex')) {
2670
- this._monthsShortRegex = defaultMonthsShortRegex;
2671
- }
2672
- return this._monthsShortStrictRegex && isStrict ?
2673
- this._monthsShortStrictRegex : this._monthsShortRegex;
2674
- }
2675
- }
2676
-
2677
- var defaultMonthsRegex = matchWord;
2678
- function monthsRegex (isStrict) {
2679
- if (this._monthsParseExact) {
2680
- if (!hasOwnProp(this, '_monthsRegex')) {
2681
- computeMonthsParse.call(this);
2682
- }
2683
- if (isStrict) {
2684
- return this._monthsStrictRegex;
2685
- } else {
2686
- return this._monthsRegex;
2687
- }
2688
- } else {
2689
- if (!hasOwnProp(this, '_monthsRegex')) {
2690
- this._monthsRegex = defaultMonthsRegex;
2691
- }
2692
- return this._monthsStrictRegex && isStrict ?
2693
- this._monthsStrictRegex : this._monthsRegex;
2694
- }
2695
- }
2696
-
2697
- function computeMonthsParse () {
2698
- function cmpLenRev(a, b) {
2699
- return b.length - a.length;
2700
- }
2701
-
2702
- var shortPieces = [], longPieces = [], mixedPieces = [],
2703
- i, mom;
2704
- for (i = 0; i < 12; i++) {
2705
- // make the regex if we don't have it already
2706
- mom = createUTC([2000, i]);
2707
- shortPieces.push(this.monthsShort(mom, ''));
2708
- longPieces.push(this.months(mom, ''));
2709
- mixedPieces.push(this.months(mom, ''));
2710
- mixedPieces.push(this.monthsShort(mom, ''));
2711
- }
2712
- // Sorting makes sure if one month (or abbr) is a prefix of another it
2713
- // will match the longer piece.
2714
- shortPieces.sort(cmpLenRev);
2715
- longPieces.sort(cmpLenRev);
2716
- mixedPieces.sort(cmpLenRev);
2717
- for (i = 0; i < 12; i++) {
2718
- shortPieces[i] = regexEscape(shortPieces[i]);
2719
- longPieces[i] = regexEscape(longPieces[i]);
2720
- }
2721
- for (i = 0; i < 24; i++) {
2722
- mixedPieces[i] = regexEscape(mixedPieces[i]);
2723
- }
2724
-
2725
- this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
2726
- this._monthsShortRegex = this._monthsRegex;
2727
- this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
2728
- this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
2729
- }
2730
-
2731
- // FORMATTING
2732
-
2733
- addFormatToken('Y', 0, 0, function () {
2734
- var y = this.year();
2735
- return y <= 9999 ? '' + y : '+' + y;
2736
- });
2737
-
2738
- addFormatToken(0, ['YY', 2], 0, function () {
2739
- return this.year() % 100;
2740
- });
2741
-
2742
- addFormatToken(0, ['YYYY', 4], 0, 'year');
2743
- addFormatToken(0, ['YYYYY', 5], 0, 'year');
2744
- addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
2745
-
2746
- // ALIASES
2747
-
2748
- addUnitAlias('year', 'y');
2749
-
2750
- // PRIORITIES
2751
-
2752
- addUnitPriority('year', 1);
2753
-
2754
- // PARSING
2755
-
2756
- addRegexToken('Y', matchSigned);
2757
- addRegexToken('YY', match1to2, match2);
2758
- addRegexToken('YYYY', match1to4, match4);
2759
- addRegexToken('YYYYY', match1to6, match6);
2760
- addRegexToken('YYYYYY', match1to6, match6);
2761
-
2762
- addParseToken(['YYYYY', 'YYYYYY'], YEAR);
2763
- addParseToken('YYYY', function (input, array) {
2764
- array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
2765
- });
2766
- addParseToken('YY', function (input, array) {
2767
- array[YEAR] = hooks.parseTwoDigitYear(input);
2768
- });
2769
- addParseToken('Y', function (input, array) {
2770
- array[YEAR] = parseInt(input, 10);
2771
- });
2772
-
2773
- // HELPERS
2774
-
2775
- function daysInYear(year) {
2776
- return isLeapYear(year) ? 366 : 365;
2777
- }
2778
-
2779
- function isLeapYear(year) {
2780
- return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
2781
- }
2782
-
2783
- // HOOKS
2784
-
2785
- hooks.parseTwoDigitYear = function (input) {
2786
- return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
2787
- };
2788
-
2789
- // MOMENTS
2790
-
2791
- var getSetYear = makeGetSet('FullYear', true);
2792
-
2793
- function getIsLeapYear () {
2794
- return isLeapYear(this.year());
2795
- }
2796
-
2797
- function createDate (y, m, d, h, M, s, ms) {
2798
- // can't just apply() to create a date:
2799
- // https://stackoverflow.com/q/181348
2800
- var date = new Date(y, m, d, h, M, s, ms);
2801
-
2802
- // the date constructor remaps years 0-99 to 1900-1999
2803
- if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
2804
- date.setFullYear(y);
2805
- }
2806
- return date;
2807
- }
2808
-
2809
- function createUTCDate (y) {
2810
- var date = new Date(Date.UTC.apply(null, arguments));
2811
-
2812
- // the Date.UTC function remaps years 0-99 to 1900-1999
2813
- if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
2814
- date.setUTCFullYear(y);
2815
- }
2816
- return date;
2817
- }
2818
-
2819
- // start-of-first-week - start-of-year
2820
- function firstWeekOffset(year, dow, doy) {
2821
- var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
2822
- fwd = 7 + dow - doy,
2823
- // first-week day local weekday -- which local weekday is fwd
2824
- fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
2825
-
2826
- return -fwdlw + fwd - 1;
2827
- }
2828
-
2829
- // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
2830
- function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
2831
- var localWeekday = (7 + weekday - dow) % 7,
2832
- weekOffset = firstWeekOffset(year, dow, doy),
2833
- dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
2834
- resYear, resDayOfYear;
2835
-
2836
- if (dayOfYear <= 0) {
2837
- resYear = year - 1;
2838
- resDayOfYear = daysInYear(resYear) + dayOfYear;
2839
- } else if (dayOfYear > daysInYear(year)) {
2840
- resYear = year + 1;
2841
- resDayOfYear = dayOfYear - daysInYear(year);
2842
- } else {
2843
- resYear = year;
2844
- resDayOfYear = dayOfYear;
2845
- }
2846
-
2847
- return {
2848
- year: resYear,
2849
- dayOfYear: resDayOfYear
2850
- };
2851
- }
2852
-
2853
- function weekOfYear(mom, dow, doy) {
2854
- var weekOffset = firstWeekOffset(mom.year(), dow, doy),
2855
- week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
2856
- resWeek, resYear;
2857
-
2858
- if (week < 1) {
2859
- resYear = mom.year() - 1;
2860
- resWeek = week + weeksInYear(resYear, dow, doy);
2861
- } else if (week > weeksInYear(mom.year(), dow, doy)) {
2862
- resWeek = week - weeksInYear(mom.year(), dow, doy);
2863
- resYear = mom.year() + 1;
2864
- } else {
2865
- resYear = mom.year();
2866
- resWeek = week;
2867
- }
2868
-
2869
- return {
2870
- week: resWeek,
2871
- year: resYear
2872
- };
2873
- }
2874
-
2875
- function weeksInYear(year, dow, doy) {
2876
- var weekOffset = firstWeekOffset(year, dow, doy),
2877
- weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
2878
- return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
2879
- }
2880
-
2881
- // FORMATTING
2882
-
2883
- addFormatToken('w', ['ww', 2], 'wo', 'week');
2884
- addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
2885
-
2886
- // ALIASES
2887
-
2888
- addUnitAlias('week', 'w');
2889
- addUnitAlias('isoWeek', 'W');
2890
-
2891
- // PRIORITIES
2892
-
2893
- addUnitPriority('week', 5);
2894
- addUnitPriority('isoWeek', 5);
2895
-
2896
- // PARSING
2897
-
2898
- addRegexToken('w', match1to2);
2899
- addRegexToken('ww', match1to2, match2);
2900
- addRegexToken('W', match1to2);
2901
- addRegexToken('WW', match1to2, match2);
2902
-
2903
- addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
2904
- week[token.substr(0, 1)] = toInt(input);
2905
- });
2906
-
2907
- // HELPERS
2908
-
2909
- // LOCALES
2910
-
2911
- function localeWeek (mom) {
2912
- return weekOfYear(mom, this._week.dow, this._week.doy).week;
2913
- }
2914
-
2915
- var defaultLocaleWeek = {
2916
- dow : 0, // Sunday is the first day of the week.
2917
- doy : 6 // The week that contains Jan 1st is the first week of the year.
2918
- };
2919
-
2920
- function localeFirstDayOfWeek () {
2921
- return this._week.dow;
2922
- }
2923
-
2924
- function localeFirstDayOfYear () {
2925
- return this._week.doy;
2926
- }
2927
-
2928
- // MOMENTS
2929
-
2930
- function getSetWeek (input) {
2931
- var week = this.localeData().week(this);
2932
- return input == null ? week : this.add((input - week) * 7, 'd');
2933
- }
2934
-
2935
- function getSetISOWeek (input) {
2936
- var week = weekOfYear(this, 1, 4).week;
2937
- return input == null ? week : this.add((input - week) * 7, 'd');
2938
- }
2939
-
2940
- // FORMATTING
2941
-
2942
- addFormatToken('d', 0, 'do', 'day');
2943
-
2944
- addFormatToken('dd', 0, 0, function (format) {
2945
- return this.localeData().weekdaysMin(this, format);
2946
- });
2947
-
2948
- addFormatToken('ddd', 0, 0, function (format) {
2949
- return this.localeData().weekdaysShort(this, format);
2950
- });
2951
-
2952
- addFormatToken('dddd', 0, 0, function (format) {
2953
- return this.localeData().weekdays(this, format);
2954
- });
2955
-
2956
- addFormatToken('e', 0, 0, 'weekday');
2957
- addFormatToken('E', 0, 0, 'isoWeekday');
2958
-
2959
- // ALIASES
2960
-
2961
- addUnitAlias('day', 'd');
2962
- addUnitAlias('weekday', 'e');
2963
- addUnitAlias('isoWeekday', 'E');
2964
-
2965
- // PRIORITY
2966
- addUnitPriority('day', 11);
2967
- addUnitPriority('weekday', 11);
2968
- addUnitPriority('isoWeekday', 11);
2969
-
2970
- // PARSING
2971
-
2972
- addRegexToken('d', match1to2);
2973
- addRegexToken('e', match1to2);
2974
- addRegexToken('E', match1to2);
2975
- addRegexToken('dd', function (isStrict, locale) {
2976
- return locale.weekdaysMinRegex(isStrict);
2977
- });
2978
- addRegexToken('ddd', function (isStrict, locale) {
2979
- return locale.weekdaysShortRegex(isStrict);
2980
- });
2981
- addRegexToken('dddd', function (isStrict, locale) {
2982
- return locale.weekdaysRegex(isStrict);
2983
- });
2984
-
2985
- addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
2986
- var weekday = config._locale.weekdaysParse(input, token, config._strict);
2987
- // if we didn't get a weekday name, mark the date as invalid
2988
- if (weekday != null) {
2989
- week.d = weekday;
2990
- } else {
2991
- getParsingFlags(config).invalidWeekday = input;
2992
- }
2993
- });
2994
-
2995
- addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
2996
- week[token] = toInt(input);
2997
- });
2998
-
2999
- // HELPERS
3000
-
3001
- function parseWeekday(input, locale) {
3002
- if (typeof input !== 'string') {
3003
- return input;
3004
- }
3005
-
3006
- if (!isNaN(input)) {
3007
- return parseInt(input, 10);
3008
- }
3009
-
3010
- input = locale.weekdaysParse(input);
3011
- if (typeof input === 'number') {
3012
- return input;
3013
- }
3014
-
3015
- return null;
3016
- }
3017
-
3018
- function parseIsoWeekday(input, locale) {
3019
- if (typeof input === 'string') {
3020
- return locale.weekdaysParse(input) % 7 || 7;
3021
- }
3022
- return isNaN(input) ? null : input;
3023
- }
3024
-
3025
- // LOCALES
3026
-
3027
- var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
3028
- function localeWeekdays (m, format) {
3029
- if (!m) {
3030
- return isArray(this._weekdays) ? this._weekdays :
3031
- this._weekdays['standalone'];
3032
- }
3033
- return isArray(this._weekdays) ? this._weekdays[m.day()] :
3034
- this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
3035
- }
3036
-
3037
- var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
3038
- function localeWeekdaysShort (m) {
3039
- return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;
3040
- }
3041
-
3042
- var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
3043
- function localeWeekdaysMin (m) {
3044
- return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;
3045
- }
3046
-
3047
- function handleStrictParse$1(weekdayName, format, strict) {
3048
- var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
3049
- if (!this._weekdaysParse) {
3050
- this._weekdaysParse = [];
3051
- this._shortWeekdaysParse = [];
3052
- this._minWeekdaysParse = [];
3053
-
3054
- for (i = 0; i < 7; ++i) {
3055
- mom = createUTC([2000, 1]).day(i);
3056
- this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
3057
- this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
3058
- this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
3059
- }
3060
- }
3061
-
3062
- if (strict) {
3063
- if (format === 'dddd') {
3064
- ii = indexOf$1.call(this._weekdaysParse, llc);
3065
- return ii !== -1 ? ii : null;
3066
- } else if (format === 'ddd') {
3067
- ii = indexOf$1.call(this._shortWeekdaysParse, llc);
3068
- return ii !== -1 ? ii : null;
3069
- } else {
3070
- ii = indexOf$1.call(this._minWeekdaysParse, llc);
3071
- return ii !== -1 ? ii : null;
3072
- }
3073
- } else {
3074
- if (format === 'dddd') {
3075
- ii = indexOf$1.call(this._weekdaysParse, llc);
3076
- if (ii !== -1) {
3077
- return ii;
3078
- }
3079
- ii = indexOf$1.call(this._shortWeekdaysParse, llc);
3080
- if (ii !== -1) {
3081
- return ii;
3082
- }
3083
- ii = indexOf$1.call(this._minWeekdaysParse, llc);
3084
- return ii !== -1 ? ii : null;
3085
- } else if (format === 'ddd') {
3086
- ii = indexOf$1.call(this._shortWeekdaysParse, llc);
3087
- if (ii !== -1) {
3088
- return ii;
3089
- }
3090
- ii = indexOf$1.call(this._weekdaysParse, llc);
3091
- if (ii !== -1) {
3092
- return ii;
3093
- }
3094
- ii = indexOf$1.call(this._minWeekdaysParse, llc);
3095
- return ii !== -1 ? ii : null;
3096
- } else {
3097
- ii = indexOf$1.call(this._minWeekdaysParse, llc);
3098
- if (ii !== -1) {
3099
- return ii;
3100
- }
3101
- ii = indexOf$1.call(this._weekdaysParse, llc);
3102
- if (ii !== -1) {
3103
- return ii;
3104
- }
3105
- ii = indexOf$1.call(this._shortWeekdaysParse, llc);
3106
- return ii !== -1 ? ii : null;
3107
- }
3108
- }
3109
- }
3110
-
3111
- function localeWeekdaysParse (weekdayName, format, strict) {
3112
- var i, mom, regex;
3113
-
3114
- if (this._weekdaysParseExact) {
3115
- return handleStrictParse$1.call(this, weekdayName, format, strict);
3116
- }
3117
-
3118
- if (!this._weekdaysParse) {
3119
- this._weekdaysParse = [];
3120
- this._minWeekdaysParse = [];
3121
- this._shortWeekdaysParse = [];
3122
- this._fullWeekdaysParse = [];
3123
- }
3124
-
3125
- for (i = 0; i < 7; i++) {
3126
- // make the regex if we don't have it already
3127
-
3128
- mom = createUTC([2000, 1]).day(i);
3129
- if (strict && !this._fullWeekdaysParse[i]) {
3130
- this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
3131
- this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
3132
- this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
3133
- }
3134
- if (!this._weekdaysParse[i]) {
3135
- regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
3136
- this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
3137
- }
3138
- // test the regex
3139
- if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
3140
- return i;
3141
- } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
3142
- return i;
3143
- } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
3144
- return i;
3145
- } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
3146
- return i;
3147
- }
3148
- }
3149
- }
3150
-
3151
- // MOMENTS
3152
-
3153
- function getSetDayOfWeek (input) {
3154
- if (!this.isValid()) {
3155
- return input != null ? this : NaN;
3156
- }
3157
- var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
3158
- if (input != null) {
3159
- input = parseWeekday(input, this.localeData());
3160
- return this.add(input - day, 'd');
3161
- } else {
3162
- return day;
3163
- }
3164
- }
3165
-
3166
- function getSetLocaleDayOfWeek (input) {
3167
- if (!this.isValid()) {
3168
- return input != null ? this : NaN;
3169
- }
3170
- var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
3171
- return input == null ? weekday : this.add(input - weekday, 'd');
3172
- }
3173
-
3174
- function getSetISODayOfWeek (input) {
3175
- if (!this.isValid()) {
3176
- return input != null ? this : NaN;
3177
- }
3178
-
3179
- // behaves the same as moment#day except
3180
- // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
3181
- // as a setter, sunday should belong to the previous week.
3182
-
3183
- if (input != null) {
3184
- var weekday = parseIsoWeekday(input, this.localeData());
3185
- return this.day(this.day() % 7 ? weekday : weekday - 7);
3186
- } else {
3187
- return this.day() || 7;
3188
- }
3189
- }
3190
-
3191
- var defaultWeekdaysRegex = matchWord;
3192
- function weekdaysRegex (isStrict) {
3193
- if (this._weekdaysParseExact) {
3194
- if (!hasOwnProp(this, '_weekdaysRegex')) {
3195
- computeWeekdaysParse.call(this);
3196
- }
3197
- if (isStrict) {
3198
- return this._weekdaysStrictRegex;
3199
- } else {
3200
- return this._weekdaysRegex;
3201
- }
3202
- } else {
3203
- if (!hasOwnProp(this, '_weekdaysRegex')) {
3204
- this._weekdaysRegex = defaultWeekdaysRegex;
3205
- }
3206
- return this._weekdaysStrictRegex && isStrict ?
3207
- this._weekdaysStrictRegex : this._weekdaysRegex;
3208
- }
3209
- }
3210
-
3211
- var defaultWeekdaysShortRegex = matchWord;
3212
- function weekdaysShortRegex (isStrict) {
3213
- if (this._weekdaysParseExact) {
3214
- if (!hasOwnProp(this, '_weekdaysRegex')) {
3215
- computeWeekdaysParse.call(this);
3216
- }
3217
- if (isStrict) {
3218
- return this._weekdaysShortStrictRegex;
3219
- } else {
3220
- return this._weekdaysShortRegex;
3221
- }
3222
- } else {
3223
- if (!hasOwnProp(this, '_weekdaysShortRegex')) {
3224
- this._weekdaysShortRegex = defaultWeekdaysShortRegex;
3225
- }
3226
- return this._weekdaysShortStrictRegex && isStrict ?
3227
- this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
3228
- }
3229
- }
3230
-
3231
- var defaultWeekdaysMinRegex = matchWord;
3232
- function weekdaysMinRegex (isStrict) {
3233
- if (this._weekdaysParseExact) {
3234
- if (!hasOwnProp(this, '_weekdaysRegex')) {
3235
- computeWeekdaysParse.call(this);
3236
- }
3237
- if (isStrict) {
3238
- return this._weekdaysMinStrictRegex;
3239
- } else {
3240
- return this._weekdaysMinRegex;
3241
- }
3242
- } else {
3243
- if (!hasOwnProp(this, '_weekdaysMinRegex')) {
3244
- this._weekdaysMinRegex = defaultWeekdaysMinRegex;
3245
- }
3246
- return this._weekdaysMinStrictRegex && isStrict ?
3247
- this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
3248
- }
3249
- }
3250
-
3251
-
3252
- function computeWeekdaysParse () {
3253
- function cmpLenRev(a, b) {
3254
- return b.length - a.length;
3255
- }
3256
-
3257
- var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
3258
- i, mom, minp, shortp, longp;
3259
- for (i = 0; i < 7; i++) {
3260
- // make the regex if we don't have it already
3261
- mom = createUTC([2000, 1]).day(i);
3262
- minp = this.weekdaysMin(mom, '');
3263
- shortp = this.weekdaysShort(mom, '');
3264
- longp = this.weekdays(mom, '');
3265
- minPieces.push(minp);
3266
- shortPieces.push(shortp);
3267
- longPieces.push(longp);
3268
- mixedPieces.push(minp);
3269
- mixedPieces.push(shortp);
3270
- mixedPieces.push(longp);
3271
- }
3272
- // Sorting makes sure if one weekday (or abbr) is a prefix of another it
3273
- // will match the longer piece.
3274
- minPieces.sort(cmpLenRev);
3275
- shortPieces.sort(cmpLenRev);
3276
- longPieces.sort(cmpLenRev);
3277
- mixedPieces.sort(cmpLenRev);
3278
- for (i = 0; i < 7; i++) {
3279
- shortPieces[i] = regexEscape(shortPieces[i]);
3280
- longPieces[i] = regexEscape(longPieces[i]);
3281
- mixedPieces[i] = regexEscape(mixedPieces[i]);
3282
- }
3283
-
3284
- this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
3285
- this._weekdaysShortRegex = this._weekdaysRegex;
3286
- this._weekdaysMinRegex = this._weekdaysRegex;
3287
-
3288
- this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
3289
- this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
3290
- this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
3291
- }
3292
-
3293
- // FORMATTING
3294
-
3295
- function hFormat() {
3296
- return this.hours() % 12 || 12;
3297
- }
3298
-
3299
- function kFormat() {
3300
- return this.hours() || 24;
3301
- }
3302
-
3303
- addFormatToken('H', ['HH', 2], 0, 'hour');
3304
- addFormatToken('h', ['hh', 2], 0, hFormat);
3305
- addFormatToken('k', ['kk', 2], 0, kFormat);
3306
-
3307
- addFormatToken('hmm', 0, 0, function () {
3308
- return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
3309
- });
3310
-
3311
- addFormatToken('hmmss', 0, 0, function () {
3312
- return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
3313
- zeroFill(this.seconds(), 2);
3314
- });
3315
-
3316
- addFormatToken('Hmm', 0, 0, function () {
3317
- return '' + this.hours() + zeroFill(this.minutes(), 2);
3318
- });
3319
-
3320
- addFormatToken('Hmmss', 0, 0, function () {
3321
- return '' + this.hours() + zeroFill(this.minutes(), 2) +
3322
- zeroFill(this.seconds(), 2);
3323
- });
3324
-
3325
- function meridiem (token, lowercase) {
3326
- addFormatToken(token, 0, 0, function () {
3327
- return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
3328
- });
3329
- }
3330
-
3331
- meridiem('a', true);
3332
- meridiem('A', false);
3333
-
3334
- // ALIASES
3335
-
3336
- addUnitAlias('hour', 'h');
3337
-
3338
- // PRIORITY
3339
- addUnitPriority('hour', 13);
3340
-
3341
- // PARSING
3342
-
3343
- function matchMeridiem (isStrict, locale) {
3344
- return locale._meridiemParse;
3345
- }
3346
-
3347
- addRegexToken('a', matchMeridiem);
3348
- addRegexToken('A', matchMeridiem);
3349
- addRegexToken('H', match1to2);
3350
- addRegexToken('h', match1to2);
3351
- addRegexToken('k', match1to2);
3352
- addRegexToken('HH', match1to2, match2);
3353
- addRegexToken('hh', match1to2, match2);
3354
- addRegexToken('kk', match1to2, match2);
3355
-
3356
- addRegexToken('hmm', match3to4);
3357
- addRegexToken('hmmss', match5to6);
3358
- addRegexToken('Hmm', match3to4);
3359
- addRegexToken('Hmmss', match5to6);
3360
-
3361
- addParseToken(['H', 'HH'], HOUR);
3362
- addParseToken(['k', 'kk'], function (input, array, config) {
3363
- var kInput = toInt(input);
3364
- array[HOUR] = kInput === 24 ? 0 : kInput;
3365
- });
3366
- addParseToken(['a', 'A'], function (input, array, config) {
3367
- config._isPm = config._locale.isPM(input);
3368
- config._meridiem = input;
3369
- });
3370
- addParseToken(['h', 'hh'], function (input, array, config) {
3371
- array[HOUR] = toInt(input);
3372
- getParsingFlags(config).bigHour = true;
3373
- });
3374
- addParseToken('hmm', function (input, array, config) {
3375
- var pos = input.length - 2;
3376
- array[HOUR] = toInt(input.substr(0, pos));
3377
- array[MINUTE] = toInt(input.substr(pos));
3378
- getParsingFlags(config).bigHour = true;
3379
- });
3380
- addParseToken('hmmss', function (input, array, config) {
3381
- var pos1 = input.length - 4;
3382
- var pos2 = input.length - 2;
3383
- array[HOUR] = toInt(input.substr(0, pos1));
3384
- array[MINUTE] = toInt(input.substr(pos1, 2));
3385
- array[SECOND] = toInt(input.substr(pos2));
3386
- getParsingFlags(config).bigHour = true;
3387
- });
3388
- addParseToken('Hmm', function (input, array, config) {
3389
- var pos = input.length - 2;
3390
- array[HOUR] = toInt(input.substr(0, pos));
3391
- array[MINUTE] = toInt(input.substr(pos));
3392
- });
3393
- addParseToken('Hmmss', function (input, array, config) {
3394
- var pos1 = input.length - 4;
3395
- var pos2 = input.length - 2;
3396
- array[HOUR] = toInt(input.substr(0, pos1));
3397
- array[MINUTE] = toInt(input.substr(pos1, 2));
3398
- array[SECOND] = toInt(input.substr(pos2));
3399
- });
3400
-
3401
- // LOCALES
3402
-
3403
- function localeIsPM (input) {
3404
- // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
3405
- // Using charAt should be more compatible.
3406
- return ((input + '').toLowerCase().charAt(0) === 'p');
3407
- }
3408
-
3409
- var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
3410
- function localeMeridiem (hours, minutes, isLower) {
3411
- if (hours > 11) {
3412
- return isLower ? 'pm' : 'PM';
3413
- } else {
3414
- return isLower ? 'am' : 'AM';
3415
- }
3416
- }
3417
-
3418
-
3419
- // MOMENTS
3420
-
3421
- // Setting the hour should keep the time, because the user explicitly
3422
- // specified which hour he wants. So trying to maintain the same hour (in
3423
- // a new timezone) makes sense. Adding/subtracting hours does not follow
3424
- // this rule.
3425
- var getSetHour = makeGetSet('Hours', true);
3426
-
3427
- // months
3428
- // week
3429
- // weekdays
3430
- // meridiem
3431
- var baseConfig = {
3432
- calendar: defaultCalendar,
3433
- longDateFormat: defaultLongDateFormat,
3434
- invalidDate: defaultInvalidDate,
3435
- ordinal: defaultOrdinal,
3436
- dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
3437
- relativeTime: defaultRelativeTime,
3438
-
3439
- months: defaultLocaleMonths,
3440
- monthsShort: defaultLocaleMonthsShort,
3441
-
3442
- week: defaultLocaleWeek,
3443
-
3444
- weekdays: defaultLocaleWeekdays,
3445
- weekdaysMin: defaultLocaleWeekdaysMin,
3446
- weekdaysShort: defaultLocaleWeekdaysShort,
3447
-
3448
- meridiemParse: defaultLocaleMeridiemParse
3449
- };
3450
-
3451
- // internal storage for locale config files
3452
- var locales = {};
3453
- var localeFamilies = {};
3454
- var globalLocale;
3455
-
3456
- function normalizeLocale(key) {
3457
- return key ? key.toLowerCase().replace('_', '-') : key;
3458
- }
3459
-
3460
- // pick the locale from the array
3461
- // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
3462
- // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
3463
- function chooseLocale(names) {
3464
- var i = 0, j, next, locale, split;
3465
-
3466
- while (i < names.length) {
3467
- split = normalizeLocale(names[i]).split('-');
3468
- j = split.length;
3469
- next = normalizeLocale(names[i + 1]);
3470
- next = next ? next.split('-') : null;
3471
- while (j > 0) {
3472
- locale = loadLocale(split.slice(0, j).join('-'));
3473
- if (locale) {
3474
- return locale;
3475
- }
3476
- if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
3477
- //the next array item is better than a shallower substring of this one
3478
- break;
3479
- }
3480
- j--;
3481
- }
3482
- i++;
3483
- }
3484
- return null;
3485
- }
3486
-
3487
- function loadLocale(name) {
3488
- var oldLocale = null;
3489
- // TODO: Find a better way to register and load all the locales in Node
3490
- if (!locales[name] && (typeof module !== 'undefined') &&
3491
- module && module.exports) {
3492
- try {
3493
- oldLocale = globalLocale._abbr;
3494
- require('./locale/' + name);
3495
- // because defineLocale currently also sets the global locale, we
3496
- // want to undo that for lazy loaded locales
3497
- getSetGlobalLocale(oldLocale);
3498
- } catch (e) { }
3499
- }
3500
- return locales[name];
3501
- }
3502
-
3503
- // This function will load locale and then set the global locale. If
3504
- // no arguments are passed in, it will simply return the current global
3505
- // locale key.
3506
- function getSetGlobalLocale (key, values) {
3507
- var data;
3508
- if (key) {
3509
- if (isUndefined(values)) {
3510
- data = getLocale(key);
3511
- }
3512
- else {
3513
- data = defineLocale(key, values);
3514
- }
3515
-
3516
- if (data) {
3517
- // moment.duration._locale = moment._locale = data;
3518
- globalLocale = data;
3519
- }
3520
- }
3521
-
3522
- return globalLocale._abbr;
3523
- }
3524
-
3525
- function defineLocale (name, config) {
3526
- if (config !== null) {
3527
- var parentConfig = baseConfig;
3528
- config.abbr = name;
3529
- if (locales[name] != null) {
3530
- deprecateSimple('defineLocaleOverride',
3531
- 'use moment.updateLocale(localeName, config) to change ' +
3532
- 'an existing locale. moment.defineLocale(localeName, ' +
3533
- 'config) should only be used for creating a new locale ' +
3534
- 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
3535
- parentConfig = locales[name]._config;
3536
- } else if (config.parentLocale != null) {
3537
- if (locales[config.parentLocale] != null) {
3538
- parentConfig = locales[config.parentLocale]._config;
3539
- } else {
3540
- if (!localeFamilies[config.parentLocale]) {
3541
- localeFamilies[config.parentLocale] = [];
3542
- }
3543
- localeFamilies[config.parentLocale].push({
3544
- name: name,
3545
- config: config
3546
- });
3547
- return null;
3548
- }
3549
- }
3550
- locales[name] = new Locale(mergeConfigs(parentConfig, config));
3551
-
3552
- if (localeFamilies[name]) {
3553
- localeFamilies[name].forEach(function (x) {
3554
- defineLocale(x.name, x.config);
3555
- });
3556
- }
3557
-
3558
- // backwards compat for now: also set the locale
3559
- // make sure we set the locale AFTER all child locales have been
3560
- // created, so we won't end up with the child locale set.
3561
- getSetGlobalLocale(name);
3562
-
3563
-
3564
- return locales[name];
3565
- } else {
3566
- // useful for testing
3567
- delete locales[name];
3568
- return null;
3569
- }
3570
- }
3571
-
3572
- function updateLocale(name, config) {
3573
- if (config != null) {
3574
- var locale, parentConfig = baseConfig;
3575
- // MERGE
3576
- if (locales[name] != null) {
3577
- parentConfig = locales[name]._config;
3578
- }
3579
- config = mergeConfigs(parentConfig, config);
3580
- locale = new Locale(config);
3581
- locale.parentLocale = locales[name];
3582
- locales[name] = locale;
3583
-
3584
- // backwards compat for now: also set the locale
3585
- getSetGlobalLocale(name);
3586
- } else {
3587
- // pass null for config to unupdate, useful for tests
3588
- if (locales[name] != null) {
3589
- if (locales[name].parentLocale != null) {
3590
- locales[name] = locales[name].parentLocale;
3591
- } else if (locales[name] != null) {
3592
- delete locales[name];
3593
- }
3594
- }
3595
- }
3596
- return locales[name];
3597
- }
3598
-
3599
- // returns locale data
3600
- function getLocale (key) {
3601
- var locale;
3602
-
3603
- if (key && key._locale && key._locale._abbr) {
3604
- key = key._locale._abbr;
3605
- }
3606
-
3607
- if (!key) {
3608
- return globalLocale;
3609
- }
3610
-
3611
- if (!isArray(key)) {
3612
- //short-circuit everything else
3613
- locale = loadLocale(key);
3614
- if (locale) {
3615
- return locale;
3616
- }
3617
- key = [key];
3618
- }
3619
-
3620
- return chooseLocale(key);
3621
- }
3622
-
3623
- function listLocales() {
3624
- return keys$1(locales);
3625
- }
3626
-
3627
- function checkOverflow (m) {
3628
- var overflow;
3629
- var a = m._a;
3630
-
3631
- if (a && getParsingFlags(m).overflow === -2) {
3632
- overflow =
3633
- a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
3634
- a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
3635
- a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
3636
- a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
3637
- a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
3638
- a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
3639
- -1;
3640
-
3641
- if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
3642
- overflow = DATE;
3643
- }
3644
- if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
3645
- overflow = WEEK;
3646
- }
3647
- if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
3648
- overflow = WEEKDAY;
3649
- }
3650
-
3651
- getParsingFlags(m).overflow = overflow;
3652
- }
3653
-
3654
- return m;
3655
- }
3656
-
3657
- // iso 8601 regex
3658
- // 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)
3659
- var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
3660
- var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
3661
-
3662
- var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
3663
-
3664
- var isoDates = [
3665
- ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
3666
- ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
3667
- ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
3668
- ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
3669
- ['YYYY-DDD', /\d{4}-\d{3}/],
3670
- ['YYYY-MM', /\d{4}-\d\d/, false],
3671
- ['YYYYYYMMDD', /[+-]\d{10}/],
3672
- ['YYYYMMDD', /\d{8}/],
3673
- // YYYYMM is NOT allowed by the standard
3674
- ['GGGG[W]WWE', /\d{4}W\d{3}/],
3675
- ['GGGG[W]WW', /\d{4}W\d{2}/, false],
3676
- ['YYYYDDD', /\d{7}/]
3677
- ];
3678
-
3679
- // iso time formats and regexes
3680
- var isoTimes = [
3681
- ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
3682
- ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
3683
- ['HH:mm:ss', /\d\d:\d\d:\d\d/],
3684
- ['HH:mm', /\d\d:\d\d/],
3685
- ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
3686
- ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
3687
- ['HHmmss', /\d\d\d\d\d\d/],
3688
- ['HHmm', /\d\d\d\d/],
3689
- ['HH', /\d\d/]
3690
- ];
3691
-
3692
- var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
3693
-
3694
- // date from iso format
3695
- function configFromISO(config) {
3696
- var i, l,
3697
- string = config._i,
3698
- match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
3699
- allowTime, dateFormat, timeFormat, tzFormat;
3700
-
3701
- if (match) {
3702
- getParsingFlags(config).iso = true;
3703
-
3704
- for (i = 0, l = isoDates.length; i < l; i++) {
3705
- if (isoDates[i][1].exec(match[1])) {
3706
- dateFormat = isoDates[i][0];
3707
- allowTime = isoDates[i][2] !== false;
3708
- break;
3709
- }
3710
- }
3711
- if (dateFormat == null) {
3712
- config._isValid = false;
3713
- return;
3714
- }
3715
- if (match[3]) {
3716
- for (i = 0, l = isoTimes.length; i < l; i++) {
3717
- if (isoTimes[i][1].exec(match[3])) {
3718
- // match[2] should be 'T' or space
3719
- timeFormat = (match[2] || ' ') + isoTimes[i][0];
3720
- break;
3721
- }
3722
- }
3723
- if (timeFormat == null) {
3724
- config._isValid = false;
3725
- return;
3726
- }
3727
- }
3728
- if (!allowTime && timeFormat != null) {
3729
- config._isValid = false;
3730
- return;
3731
- }
3732
- if (match[4]) {
3733
- if (tzRegex.exec(match[4])) {
3734
- tzFormat = 'Z';
3735
- } else {
3736
- config._isValid = false;
3737
- return;
3738
- }
3739
- }
3740
- config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
3741
- configFromStringAndFormat(config);
3742
- } else {
3743
- config._isValid = false;
3744
- }
3745
- }
3746
-
3747
- // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
3748
- var basicRfcRegex = /^((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d?\d\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?:\d\d)?\d\d\s)(\d\d:\d\d)(\:\d\d)?(\s(?:UT|GMT|[ECMP][SD]T|[A-IK-Za-ik-z]|[+-]\d{4}))$/;
3749
-
3750
- // date and time from ref 2822 format
3751
- function configFromRFC2822(config) {
3752
- var string, match, dayFormat,
3753
- dateFormat, timeFormat, tzFormat;
3754
- var timezones = {
3755
- ' GMT': ' +0000',
3756
- ' EDT': ' -0400',
3757
- ' EST': ' -0500',
3758
- ' CDT': ' -0500',
3759
- ' CST': ' -0600',
3760
- ' MDT': ' -0600',
3761
- ' MST': ' -0700',
3762
- ' PDT': ' -0700',
3763
- ' PST': ' -0800'
3764
- };
3765
- var military = 'YXWVUTSRQPONZABCDEFGHIKLM';
3766
- var timezone, timezoneIndex;
3767
-
3768
- string = config._i
3769
- .replace(/\([^\)]*\)|[\n\t]/g, ' ') // Remove comments and folding whitespace
3770
- .replace(/(\s\s+)/g, ' ') // Replace multiple-spaces with a single space
3771
- .replace(/^\s|\s$/g, ''); // Remove leading and trailing spaces
3772
- match = basicRfcRegex.exec(string);
3773
-
3774
- if (match) {
3775
- dayFormat = match[1] ? 'ddd' + ((match[1].length === 5) ? ', ' : ' ') : '';
3776
- dateFormat = 'D MMM ' + ((match[2].length > 10) ? 'YYYY ' : 'YY ');
3777
- timeFormat = 'HH:mm' + (match[4] ? ':ss' : '');
3778
-
3779
- // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
3780
- if (match[1]) { // day of week given
3781
- var momentDate = new Date(match[2]);
3782
- var momentDay = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][momentDate.getDay()];
3783
-
3784
- if (match[1].substr(0,3) !== momentDay) {
3785
- getParsingFlags(config).weekdayMismatch = true;
3786
- config._isValid = false;
3787
- return;
3788
- }
3789
- }
3790
-
3791
- switch (match[5].length) {
3792
- case 2: // military
3793
- if (timezoneIndex === 0) {
3794
- timezone = ' +0000';
3795
- } else {
3796
- timezoneIndex = military.indexOf(match[5][1].toUpperCase()) - 12;
3797
- timezone = ((timezoneIndex < 0) ? ' -' : ' +') +
3798
- (('' + timezoneIndex).replace(/^-?/, '0')).match(/..$/)[0] + '00';
3799
- }
3800
- break;
3801
- case 4: // Zone
3802
- timezone = timezones[match[5]];
3803
- break;
3804
- default: // UT or +/-9999
3805
- timezone = timezones[' GMT'];
3806
- }
3807
- match[5] = timezone;
3808
- config._i = match.splice(1).join('');
3809
- tzFormat = ' ZZ';
3810
- config._f = dayFormat + dateFormat + timeFormat + tzFormat;
3811
- configFromStringAndFormat(config);
3812
- getParsingFlags(config).rfc2822 = true;
3813
- } else {
3814
- config._isValid = false;
3815
- }
3816
- }
3817
-
3818
- // date from iso format or fallback
3819
- function configFromString(config) {
3820
- var matched = aspNetJsonRegex.exec(config._i);
3821
-
3822
- if (matched !== null) {
3823
- config._d = new Date(+matched[1]);
3824
- return;
3825
- }
3826
-
3827
- configFromISO(config);
3828
- if (config._isValid === false) {
3829
- delete config._isValid;
3830
- } else {
3831
- return;
3832
- }
3833
-
3834
- configFromRFC2822(config);
3835
- if (config._isValid === false) {
3836
- delete config._isValid;
3837
- } else {
3838
- return;
3839
- }
3840
-
3841
- // Final attempt, use Input Fallback
3842
- hooks.createFromInputFallback(config);
3843
- }
3844
-
3845
- hooks.createFromInputFallback = deprecate(
3846
- 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
3847
- 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
3848
- 'discouraged and will be removed in an upcoming major release. Please refer to ' +
3849
- 'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
3850
- function (config) {
3851
- config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
3852
- }
3853
- );
3854
-
3855
- // Pick the first defined of two or three arguments.
3856
- function defaults(a, b, c) {
3857
- if (a != null) {
3858
- return a;
3859
- }
3860
- if (b != null) {
3861
- return b;
3862
- }
3863
- return c;
3864
- }
3865
-
3866
- function currentDateArray(config) {
3867
- // hooks is actually the exported moment object
3868
- var nowValue = new Date(hooks.now());
3869
- if (config._useUTC) {
3870
- return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
3871
- }
3872
- return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
3873
- }
3874
-
3875
- // convert an array to a date.
3876
- // the array should mirror the parameters below
3877
- // note: all values past the year are optional and will default to the lowest possible value.
3878
- // [year, month, day , hour, minute, second, millisecond]
3879
- function configFromArray (config) {
3880
- var i, date, input = [], currentDate, yearToUse;
3881
-
3882
- if (config._d) {
3883
- return;
3884
- }
3885
-
3886
- currentDate = currentDateArray(config);
3887
-
3888
- //compute day of the year from weeks and weekdays
3889
- if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
3890
- dayOfYearFromWeekInfo(config);
3891
- }
3892
-
3893
- //if the day of the year is set, figure out what it is
3894
- if (config._dayOfYear != null) {
3895
- yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
3896
-
3897
- if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {
3898
- getParsingFlags(config)._overflowDayOfYear = true;
3899
- }
3900
-
3901
- date = createUTCDate(yearToUse, 0, config._dayOfYear);
3902
- config._a[MONTH] = date.getUTCMonth();
3903
- config._a[DATE] = date.getUTCDate();
3904
- }
3905
-
3906
- // Default to current date.
3907
- // * if no year, month, day of month are given, default to today
3908
- // * if day of month is given, default month and year
3909
- // * if month is given, default only year
3910
- // * if year is given, don't default anything
3911
- for (i = 0; i < 3 && config._a[i] == null; ++i) {
3912
- config._a[i] = input[i] = currentDate[i];
3913
- }
3914
-
3915
- // Zero out whatever was not defaulted, including time
3916
- for (; i < 7; i++) {
3917
- config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
3918
- }
3919
-
3920
- // Check for 24:00:00.000
3921
- if (config._a[HOUR] === 24 &&
3922
- config._a[MINUTE] === 0 &&
3923
- config._a[SECOND] === 0 &&
3924
- config._a[MILLISECOND] === 0) {
3925
- config._nextDay = true;
3926
- config._a[HOUR] = 0;
3927
- }
3928
-
3929
- config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
3930
- // Apply timezone offset from input. The actual utcOffset can be changed
3931
- // with parseZone.
3932
- if (config._tzm != null) {
3933
- config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
3934
- }
3935
-
3936
- if (config._nextDay) {
3937
- config._a[HOUR] = 24;
3938
- }
3939
- }
3940
-
3941
- function dayOfYearFromWeekInfo(config) {
3942
- var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
3943
-
3944
- w = config._w;
3945
- if (w.GG != null || w.W != null || w.E != null) {
3946
- dow = 1;
3947
- doy = 4;
3948
-
3949
- // TODO: We need to take the current isoWeekYear, but that depends on
3950
- // how we interpret now (local, utc, fixed offset). So create
3951
- // a now version of current config (take local/utc/offset flags, and
3952
- // create now).
3953
- weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);
3954
- week = defaults(w.W, 1);
3955
- weekday = defaults(w.E, 1);
3956
- if (weekday < 1 || weekday > 7) {
3957
- weekdayOverflow = true;
3958
- }
3959
- } else {
3960
- dow = config._locale._week.dow;
3961
- doy = config._locale._week.doy;
3962
-
3963
- var curWeek = weekOfYear(createLocal(), dow, doy);
3964
-
3965
- weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);
3966
-
3967
- // Default to current week.
3968
- week = defaults(w.w, curWeek.week);
3969
-
3970
- if (w.d != null) {
3971
- // weekday -- low day numbers are considered next week
3972
- weekday = w.d;
3973
- if (weekday < 0 || weekday > 6) {
3974
- weekdayOverflow = true;
3975
- }
3976
- } else if (w.e != null) {
3977
- // local weekday -- counting starts from begining of week
3978
- weekday = w.e + dow;
3979
- if (w.e < 0 || w.e > 6) {
3980
- weekdayOverflow = true;
3981
- }
3982
- } else {
3983
- // default to begining of week
3984
- weekday = dow;
3985
- }
3986
- }
3987
- if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
3988
- getParsingFlags(config)._overflowWeeks = true;
3989
- } else if (weekdayOverflow != null) {
3990
- getParsingFlags(config)._overflowWeekday = true;
3991
- } else {
3992
- temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
3993
- config._a[YEAR] = temp.year;
3994
- config._dayOfYear = temp.dayOfYear;
3995
- }
3996
- }
3997
-
3998
- // constant that refers to the ISO standard
3999
- hooks.ISO_8601 = function () {};
4000
-
4001
- // constant that refers to the RFC 2822 form
4002
- hooks.RFC_2822 = function () {};
4003
-
4004
- // date from string and format string
4005
- function configFromStringAndFormat(config) {
4006
- // TODO: Move this to another part of the creation flow to prevent circular deps
4007
- if (config._f === hooks.ISO_8601) {
4008
- configFromISO(config);
4009
- return;
4010
- }
4011
- if (config._f === hooks.RFC_2822) {
4012
- configFromRFC2822(config);
4013
- return;
4014
- }
4015
- config._a = [];
4016
- getParsingFlags(config).empty = true;
4017
-
4018
- // This array is used to make a Date, either with `new Date` or `Date.UTC`
4019
- var string = '' + config._i,
4020
- i, parsedInput, tokens, token, skipped,
4021
- stringLength = string.length,
4022
- totalParsedInputLength = 0;
4023
-
4024
- tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
4025
-
4026
- for (i = 0; i < tokens.length; i++) {
4027
- token = tokens[i];
4028
- parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
4029
- // console.log('token', token, 'parsedInput', parsedInput,
4030
- // 'regex', getParseRegexForToken(token, config));
4031
- if (parsedInput) {
4032
- skipped = string.substr(0, string.indexOf(parsedInput));
4033
- if (skipped.length > 0) {
4034
- getParsingFlags(config).unusedInput.push(skipped);
4035
- }
4036
- string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
4037
- totalParsedInputLength += parsedInput.length;
4038
- }
4039
- // don't parse if it's not a known token
4040
- if (formatTokenFunctions[token]) {
4041
- if (parsedInput) {
4042
- getParsingFlags(config).empty = false;
4043
- }
4044
- else {
4045
- getParsingFlags(config).unusedTokens.push(token);
4046
- }
4047
- addTimeToArrayFromToken(token, parsedInput, config);
4048
- }
4049
- else if (config._strict && !parsedInput) {
4050
- getParsingFlags(config).unusedTokens.push(token);
4051
- }
4052
- }
4053
-
4054
- // add remaining unparsed input length to the string
4055
- getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
4056
- if (string.length > 0) {
4057
- getParsingFlags(config).unusedInput.push(string);
4058
- }
4059
-
4060
- // clear _12h flag if hour is <= 12
4061
- if (config._a[HOUR] <= 12 &&
4062
- getParsingFlags(config).bigHour === true &&
4063
- config._a[HOUR] > 0) {
4064
- getParsingFlags(config).bigHour = undefined;
4065
- }
4066
-
4067
- getParsingFlags(config).parsedDateParts = config._a.slice(0);
4068
- getParsingFlags(config).meridiem = config._meridiem;
4069
- // handle meridiem
4070
- config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
4071
-
4072
- configFromArray(config);
4073
- checkOverflow(config);
4074
- }
4075
-
4076
-
4077
- function meridiemFixWrap (locale, hour, meridiem) {
4078
- var isPm;
4079
-
4080
- if (meridiem == null) {
4081
- // nothing to do
4082
- return hour;
4083
- }
4084
- if (locale.meridiemHour != null) {
4085
- return locale.meridiemHour(hour, meridiem);
4086
- } else if (locale.isPM != null) {
4087
- // Fallback
4088
- isPm = locale.isPM(meridiem);
4089
- if (isPm && hour < 12) {
4090
- hour += 12;
4091
- }
4092
- if (!isPm && hour === 12) {
4093
- hour = 0;
4094
- }
4095
- return hour;
4096
- } else {
4097
- // this is not supposed to happen
4098
- return hour;
4099
- }
4100
- }
4101
-
4102
- // date from string and array of format strings
4103
- function configFromStringAndArray(config) {
4104
- var tempConfig,
4105
- bestMoment,
4106
-
4107
- scoreToBeat,
4108
- i,
4109
- currentScore;
4110
-
4111
- if (config._f.length === 0) {
4112
- getParsingFlags(config).invalidFormat = true;
4113
- config._d = new Date(NaN);
4114
- return;
4115
- }
4116
-
4117
- for (i = 0; i < config._f.length; i++) {
4118
- currentScore = 0;
4119
- tempConfig = copyConfig({}, config);
4120
- if (config._useUTC != null) {
4121
- tempConfig._useUTC = config._useUTC;
4122
- }
4123
- tempConfig._f = config._f[i];
4124
- configFromStringAndFormat(tempConfig);
4125
-
4126
- if (!isValid(tempConfig)) {
4127
- continue;
4128
- }
4129
-
4130
- // if there is any input that was not parsed add a penalty for that format
4131
- currentScore += getParsingFlags(tempConfig).charsLeftOver;
4132
-
4133
- //or tokens
4134
- currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
4135
-
4136
- getParsingFlags(tempConfig).score = currentScore;
4137
-
4138
- if (scoreToBeat == null || currentScore < scoreToBeat) {
4139
- scoreToBeat = currentScore;
4140
- bestMoment = tempConfig;
4141
- }
4142
- }
4143
-
4144
- extend(config, bestMoment || tempConfig);
4145
- }
4146
-
4147
- function configFromObject(config) {
4148
- if (config._d) {
4149
- return;
4150
- }
4151
-
4152
- var i = normalizeObjectUnits(config._i);
4153
- config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
4154
- return obj && parseInt(obj, 10);
4155
- });
4156
-
4157
- configFromArray(config);
4158
- }
4159
-
4160
- function createFromConfig (config) {
4161
- var res = new Moment(checkOverflow(prepareConfig(config)));
4162
- if (res._nextDay) {
4163
- // Adding is smart enough around DST
4164
- res.add(1, 'd');
4165
- res._nextDay = undefined;
4166
- }
4167
-
4168
- return res;
4169
- }
4170
-
4171
- function prepareConfig (config) {
4172
- var input = config._i,
4173
- format = config._f;
4174
-
4175
- config._locale = config._locale || getLocale(config._l);
4176
-
4177
- if (input === null || (format === undefined && input === '')) {
4178
- return createInvalid({nullInput: true});
4179
- }
4180
-
4181
- if (typeof input === 'string') {
4182
- config._i = input = config._locale.preparse(input);
4183
- }
4184
-
4185
- if (isMoment(input)) {
4186
- return new Moment(checkOverflow(input));
4187
- } else if (isDate(input)) {
4188
- config._d = input;
4189
- } else if (isArray(format)) {
4190
- configFromStringAndArray(config);
4191
- } else if (format) {
4192
- configFromStringAndFormat(config);
4193
- } else {
4194
- configFromInput(config);
4195
- }
4196
-
4197
- if (!isValid(config)) {
4198
- config._d = null;
4199
- }
4200
-
4201
- return config;
4202
- }
4203
-
4204
- function configFromInput(config) {
4205
- var input = config._i;
4206
- if (isUndefined(input)) {
4207
- config._d = new Date(hooks.now());
4208
- } else if (isDate(input)) {
4209
- config._d = new Date(input.valueOf());
4210
- } else if (typeof input === 'string') {
4211
- configFromString(config);
4212
- } else if (isArray(input)) {
4213
- config._a = map(input.slice(0), function (obj) {
4214
- return parseInt(obj, 10);
4215
- });
4216
- configFromArray(config);
4217
- } else if (isObject(input)) {
4218
- configFromObject(config);
4219
- } else if (isNumber(input)) {
4220
- // from milliseconds
4221
- config._d = new Date(input);
4222
- } else {
4223
- hooks.createFromInputFallback(config);
4224
- }
4225
- }
4226
-
4227
- function createLocalOrUTC (input, format, locale, strict, isUTC) {
4228
- var c = {};
4229
-
4230
- if (locale === true || locale === false) {
4231
- strict = locale;
4232
- locale = undefined;
4233
- }
4234
-
4235
- if ((isObject(input) && isObjectEmpty(input)) ||
4236
- (isArray(input) && input.length === 0)) {
4237
- input = undefined;
4238
- }
4239
- // object construction must be done this way.
4240
- // https://github.com/moment/moment/issues/1423
4241
- c._isAMomentObject = true;
4242
- c._useUTC = c._isUTC = isUTC;
4243
- c._l = locale;
4244
- c._i = input;
4245
- c._f = format;
4246
- c._strict = strict;
4247
-
4248
- return createFromConfig(c);
4249
- }
4250
-
4251
- function createLocal (input, format, locale, strict) {
4252
- return createLocalOrUTC(input, format, locale, strict, false);
4253
- }
4254
-
4255
- var prototypeMin = deprecate(
4256
- 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
4257
- function () {
4258
- var other = createLocal.apply(null, arguments);
4259
- if (this.isValid() && other.isValid()) {
4260
- return other < this ? this : other;
4261
- } else {
4262
- return createInvalid();
4263
- }
4264
- }
4265
- );
4266
-
4267
- var prototypeMax = deprecate(
4268
- 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
4269
- function () {
4270
- var other = createLocal.apply(null, arguments);
4271
- if (this.isValid() && other.isValid()) {
4272
- return other > this ? this : other;
4273
- } else {
4274
- return createInvalid();
4275
- }
4276
- }
4277
- );
4278
-
4279
- // Pick a moment m from moments so that m[fn](other) is true for all
4280
- // other. This relies on the function fn to be transitive.
4281
- //
4282
- // moments should either be an array of moment objects or an array, whose
4283
- // first element is an array of moment objects.
4284
- function pickBy(fn, moments) {
4285
- var res, i;
4286
- if (moments.length === 1 && isArray(moments[0])) {
4287
- moments = moments[0];
4288
- }
4289
- if (!moments.length) {
4290
- return createLocal();
4291
- }
4292
- res = moments[0];
4293
- for (i = 1; i < moments.length; ++i) {
4294
- if (!moments[i].isValid() || moments[i][fn](res)) {
4295
- res = moments[i];
4296
- }
4297
- }
4298
- return res;
4299
- }
4300
-
4301
- // TODO: Use [].sort instead?
4302
- function min () {
4303
- var args = [].slice.call(arguments, 0);
4304
-
4305
- return pickBy('isBefore', args);
4306
- }
4307
-
4308
- function max () {
4309
- var args = [].slice.call(arguments, 0);
4310
-
4311
- return pickBy('isAfter', args);
4312
- }
4313
-
4314
- var now = function () {
4315
- return Date.now ? Date.now() : +(new Date());
4316
- };
4317
-
4318
- var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];
4319
-
4320
- function isDurationValid(m) {
4321
- for (var key in m) {
4322
- if (!(ordering.indexOf(key) !== -1 && (m[key] == null || !isNaN(m[key])))) {
4323
- return false;
4324
- }
4325
- }
4326
-
4327
- var unitHasDecimal = false;
4328
- for (var i = 0; i < ordering.length; ++i) {
4329
- if (m[ordering[i]]) {
4330
- if (unitHasDecimal) {
4331
- return false; // only allow non-integers for smallest unit
4332
- }
4333
- if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
4334
- unitHasDecimal = true;
4335
- }
4336
- }
4337
- }
4338
-
4339
- return true;
4340
- }
4341
-
4342
- function isValid$1() {
4343
- return this._isValid;
4344
- }
4345
-
4346
- function createInvalid$1() {
4347
- return createDuration(NaN);
4348
- }
4349
-
4350
- function Duration (duration) {
4351
- var normalizedInput = normalizeObjectUnits(duration),
4352
- years = normalizedInput.year || 0,
4353
- quarters = normalizedInput.quarter || 0,
4354
- months = normalizedInput.month || 0,
4355
- weeks = normalizedInput.week || 0,
4356
- days = normalizedInput.day || 0,
4357
- hours = normalizedInput.hour || 0,
4358
- minutes = normalizedInput.minute || 0,
4359
- seconds = normalizedInput.second || 0,
4360
- milliseconds = normalizedInput.millisecond || 0;
4361
-
4362
- this._isValid = isDurationValid(normalizedInput);
4363
-
4364
- // representation for dateAddRemove
4365
- this._milliseconds = +milliseconds +
4366
- seconds * 1e3 + // 1000
4367
- minutes * 6e4 + // 1000 * 60
4368
- hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
4369
- // Because of dateAddRemove treats 24 hours as different from a
4370
- // day when working around DST, we need to store them separately
4371
- this._days = +days +
4372
- weeks * 7;
4373
- // It is impossible translate months into days without knowing
4374
- // which months you are are talking about, so we have to store
4375
- // it separately.
4376
- this._months = +months +
4377
- quarters * 3 +
4378
- years * 12;
4379
-
4380
- this._data = {};
4381
-
4382
- this._locale = getLocale();
4383
-
4384
- this._bubble();
4385
- }
4386
-
4387
- function isDuration (obj) {
4388
- return obj instanceof Duration;
4389
- }
4390
-
4391
- function absRound (number) {
4392
- if (number < 0) {
4393
- return Math.round(-1 * number) * -1;
4394
- } else {
4395
- return Math.round(number);
4396
- }
4397
- }
4398
-
4399
- // FORMATTING
4400
-
4401
- function offset (token, separator) {
4402
- addFormatToken(token, 0, 0, function () {
4403
- var offset = this.utcOffset();
4404
- var sign = '+';
4405
- if (offset < 0) {
4406
- offset = -offset;
4407
- sign = '-';
4408
- }
4409
- return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
4410
- });
4411
- }
4412
-
4413
- offset('Z', ':');
4414
- offset('ZZ', '');
4415
-
4416
- // PARSING
4417
-
4418
- addRegexToken('Z', matchShortOffset);
4419
- addRegexToken('ZZ', matchShortOffset);
4420
- addParseToken(['Z', 'ZZ'], function (input, array, config) {
4421
- config._useUTC = true;
4422
- config._tzm = offsetFromString(matchShortOffset, input);
4423
- });
4424
-
4425
- // HELPERS
4426
-
4427
- // timezone chunker
4428
- // '+10:00' > ['10', '00']
4429
- // '-1530' > ['-15', '30']
4430
- var chunkOffset = /([\+\-]|\d\d)/gi;
4431
-
4432
- function offsetFromString(matcher, string) {
4433
- var matches = (string || '').match(matcher);
4434
-
4435
- if (matches === null) {
4436
- return null;
4437
- }
4438
-
4439
- var chunk = matches[matches.length - 1] || [];
4440
- var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
4441
- var minutes = +(parts[1] * 60) + toInt(parts[2]);
4442
-
4443
- return minutes === 0 ?
4444
- 0 :
4445
- parts[0] === '+' ? minutes : -minutes;
4446
- }
4447
-
4448
- // Return a moment from input, that is local/utc/zone equivalent to model.
4449
- function cloneWithOffset(input, model) {
4450
- var res, diff;
4451
- if (model._isUTC) {
4452
- res = model.clone();
4453
- diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();
4454
- // Use low-level api, because this fn is low-level api.
4455
- res._d.setTime(res._d.valueOf() + diff);
4456
- hooks.updateOffset(res, false);
4457
- return res;
4458
- } else {
4459
- return createLocal(input).local();
4460
- }
4461
- }
4462
-
4463
- function getDateOffset (m) {
4464
- // On Firefox.24 Date#getTimezoneOffset returns a floating point.
4465
- // https://github.com/moment/moment/pull/1871
4466
- return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
4467
- }
4468
-
4469
- // HOOKS
4470
-
4471
- // This function will be called whenever a moment is mutated.
4472
- // It is intended to keep the offset in sync with the timezone.
4473
- hooks.updateOffset = function () {};
4474
-
4475
- // MOMENTS
4476
-
4477
- // keepLocalTime = true means only change the timezone, without
4478
- // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
4479
- // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
4480
- // +0200, so we adjust the time as needed, to be valid.
4481
- //
4482
- // Keeping the time actually adds/subtracts (one hour)
4483
- // from the actual represented time. That is why we call updateOffset
4484
- // a second time. In case it wants us to change the offset again
4485
- // _changeInProgress == true case, then we have to adjust, because
4486
- // there is no such time in the given timezone.
4487
- function getSetOffset (input, keepLocalTime, keepMinutes) {
4488
- var offset = this._offset || 0,
4489
- localAdjust;
4490
- if (!this.isValid()) {
4491
- return input != null ? this : NaN;
4492
- }
4493
- if (input != null) {
4494
- if (typeof input === 'string') {
4495
- input = offsetFromString(matchShortOffset, input);
4496
- if (input === null) {
4497
- return this;
4498
- }
4499
- } else if (Math.abs(input) < 16 && !keepMinutes) {
4500
- input = input * 60;
4501
- }
4502
- if (!this._isUTC && keepLocalTime) {
4503
- localAdjust = getDateOffset(this);
4504
- }
4505
- this._offset = input;
4506
- this._isUTC = true;
4507
- if (localAdjust != null) {
4508
- this.add(localAdjust, 'm');
4509
- }
4510
- if (offset !== input) {
4511
- if (!keepLocalTime || this._changeInProgress) {
4512
- addSubtract(this, createDuration(input - offset, 'm'), 1, false);
4513
- } else if (!this._changeInProgress) {
4514
- this._changeInProgress = true;
4515
- hooks.updateOffset(this, true);
4516
- this._changeInProgress = null;
4517
- }
4518
- }
4519
- return this;
4520
- } else {
4521
- return this._isUTC ? offset : getDateOffset(this);
4522
- }
4523
- }
4524
-
4525
- function getSetZone (input, keepLocalTime) {
4526
- if (input != null) {
4527
- if (typeof input !== 'string') {
4528
- input = -input;
4529
- }
4530
-
4531
- this.utcOffset(input, keepLocalTime);
4532
-
4533
- return this;
4534
- } else {
4535
- return -this.utcOffset();
4536
- }
4537
- }
4538
-
4539
- function setOffsetToUTC (keepLocalTime) {
4540
- return this.utcOffset(0, keepLocalTime);
4541
- }
4542
-
4543
- function setOffsetToLocal (keepLocalTime) {
4544
- if (this._isUTC) {
4545
- this.utcOffset(0, keepLocalTime);
4546
- this._isUTC = false;
4547
-
4548
- if (keepLocalTime) {
4549
- this.subtract(getDateOffset(this), 'm');
4550
- }
4551
- }
4552
- return this;
4553
- }
4554
-
4555
- function setOffsetToParsedOffset () {
4556
- if (this._tzm != null) {
4557
- this.utcOffset(this._tzm, false, true);
4558
- } else if (typeof this._i === 'string') {
4559
- var tZone = offsetFromString(matchOffset, this._i);
4560
- if (tZone != null) {
4561
- this.utcOffset(tZone);
4562
- }
4563
- else {
4564
- this.utcOffset(0, true);
4565
- }
4566
- }
4567
- return this;
4568
- }
4569
-
4570
- function hasAlignedHourOffset (input) {
4571
- if (!this.isValid()) {
4572
- return false;
4573
- }
4574
- input = input ? createLocal(input).utcOffset() : 0;
4575
-
4576
- return (this.utcOffset() - input) % 60 === 0;
4577
- }
4578
-
4579
- function isDaylightSavingTime () {
4580
- return (
4581
- this.utcOffset() > this.clone().month(0).utcOffset() ||
4582
- this.utcOffset() > this.clone().month(5).utcOffset()
4583
- );
4584
- }
4585
-
4586
- function isDaylightSavingTimeShifted () {
4587
- if (!isUndefined(this._isDSTShifted)) {
4588
- return this._isDSTShifted;
4589
- }
4590
-
4591
- var c = {};
4592
-
4593
- copyConfig(c, this);
4594
- c = prepareConfig(c);
4595
-
4596
- if (c._a) {
4597
- var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
4598
- this._isDSTShifted = this.isValid() &&
4599
- compareArrays(c._a, other.toArray()) > 0;
4600
- } else {
4601
- this._isDSTShifted = false;
4602
- }
4603
-
4604
- return this._isDSTShifted;
4605
- }
4606
-
4607
- function isLocal () {
4608
- return this.isValid() ? !this._isUTC : false;
4609
- }
4610
-
4611
- function isUtcOffset () {
4612
- return this.isValid() ? this._isUTC : false;
4613
- }
4614
-
4615
- function isUtc () {
4616
- return this.isValid() ? this._isUTC && this._offset === 0 : false;
4617
- }
4618
-
4619
- // ASP.NET json date format regex
4620
- var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;
4621
-
4622
- // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
4623
- // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
4624
- // and further modified to allow for strings containing both week and day
4625
- var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;
4626
-
4627
- function createDuration (input, key) {
4628
- var duration = input,
4629
- // matching against regexp is expensive, do it on demand
4630
- match = null,
4631
- sign,
4632
- ret,
4633
- diffRes;
4634
-
4635
- if (isDuration(input)) {
4636
- duration = {
4637
- ms : input._milliseconds,
4638
- d : input._days,
4639
- M : input._months
4640
- };
4641
- } else if (isNumber(input)) {
4642
- duration = {};
4643
- if (key) {
4644
- duration[key] = input;
4645
- } else {
4646
- duration.milliseconds = input;
4647
- }
4648
- } else if (!!(match = aspNetRegex.exec(input))) {
4649
- sign = (match[1] === '-') ? -1 : 1;
4650
- duration = {
4651
- y : 0,
4652
- d : toInt(match[DATE]) * sign,
4653
- h : toInt(match[HOUR]) * sign,
4654
- m : toInt(match[MINUTE]) * sign,
4655
- s : toInt(match[SECOND]) * sign,
4656
- ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
4657
- };
4658
- } else if (!!(match = isoRegex.exec(input))) {
4659
- sign = (match[1] === '-') ? -1 : 1;
4660
- duration = {
4661
- y : parseIso(match[2], sign),
4662
- M : parseIso(match[3], sign),
4663
- w : parseIso(match[4], sign),
4664
- d : parseIso(match[5], sign),
4665
- h : parseIso(match[6], sign),
4666
- m : parseIso(match[7], sign),
4667
- s : parseIso(match[8], sign)
4668
- };
4669
- } else if (duration == null) {// checks for null or undefined
4670
- duration = {};
4671
- } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
4672
- diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));
4673
-
4674
- duration = {};
4675
- duration.ms = diffRes.milliseconds;
4676
- duration.M = diffRes.months;
4677
- }
4678
-
4679
- ret = new Duration(duration);
4680
-
4681
- if (isDuration(input) && hasOwnProp(input, '_locale')) {
4682
- ret._locale = input._locale;
4683
- }
4684
-
4685
- return ret;
4686
- }
4687
-
4688
- createDuration.fn = Duration.prototype;
4689
- createDuration.invalid = createInvalid$1;
4690
-
4691
- function parseIso (inp, sign) {
4692
- // We'd normally use ~~inp for this, but unfortunately it also
4693
- // converts floats to ints.
4694
- // inp may be undefined, so careful calling replace on it.
4695
- var res = inp && parseFloat(inp.replace(',', '.'));
4696
- // apply sign while we're at it
4697
- return (isNaN(res) ? 0 : res) * sign;
4698
- }
4699
-
4700
- function positiveMomentsDifference(base, other) {
4701
- var res = {milliseconds: 0, months: 0};
4702
-
4703
- res.months = other.month() - base.month() +
4704
- (other.year() - base.year()) * 12;
4705
- if (base.clone().add(res.months, 'M').isAfter(other)) {
4706
- --res.months;
4707
- }
4708
-
4709
- res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
4710
-
4711
- return res;
4712
- }
4713
-
4714
- function momentsDifference(base, other) {
4715
- var res;
4716
- if (!(base.isValid() && other.isValid())) {
4717
- return {milliseconds: 0, months: 0};
4718
- }
4719
-
4720
- other = cloneWithOffset(other, base);
4721
- if (base.isBefore(other)) {
4722
- res = positiveMomentsDifference(base, other);
4723
- } else {
4724
- res = positiveMomentsDifference(other, base);
4725
- res.milliseconds = -res.milliseconds;
4726
- res.months = -res.months;
4727
- }
4728
-
4729
- return res;
4730
- }
4731
-
4732
- // TODO: remove 'name' arg after deprecation is removed
4733
- function createAdder(direction, name) {
4734
- return function (val, period) {
4735
- var dur, tmp;
4736
- //invert the arguments, but complain about it
4737
- if (period !== null && !isNaN(+period)) {
4738
- deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +
4739
- 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');
4740
- tmp = val; val = period; period = tmp;
4741
- }
4742
-
4743
- val = typeof val === 'string' ? +val : val;
4744
- dur = createDuration(val, period);
4745
- addSubtract(this, dur, direction);
4746
- return this;
4747
- };
4748
- }
4749
-
4750
- function addSubtract (mom, duration, isAdding, updateOffset) {
4751
- var milliseconds = duration._milliseconds,
4752
- days = absRound(duration._days),
4753
- months = absRound(duration._months);
4754
-
4755
- if (!mom.isValid()) {
4756
- // No op
4757
- return;
4758
- }
4759
-
4760
- updateOffset = updateOffset == null ? true : updateOffset;
4761
-
4762
- if (milliseconds) {
4763
- mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
4764
- }
4765
- if (days) {
4766
- set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
4767
- }
4768
- if (months) {
4769
- setMonth(mom, get(mom, 'Month') + months * isAdding);
4770
- }
4771
- if (updateOffset) {
4772
- hooks.updateOffset(mom, days || months);
4773
- }
4774
- }
4775
-
4776
- var add = createAdder(1, 'add');
4777
- var subtract = createAdder(-1, 'subtract');
4778
-
4779
- function getCalendarFormat(myMoment, now) {
4780
- var diff = myMoment.diff(now, 'days', true);
4781
- return diff < -6 ? 'sameElse' :
4782
- diff < -1 ? 'lastWeek' :
4783
- diff < 0 ? 'lastDay' :
4784
- diff < 1 ? 'sameDay' :
4785
- diff < 2 ? 'nextDay' :
4786
- diff < 7 ? 'nextWeek' : 'sameElse';
4787
- }
4788
-
4789
- function calendar$1 (time, formats) {
4790
- // We want to compare the start of today, vs this.
4791
- // Getting start-of-today depends on whether we're local/utc/offset or not.
4792
- var now = time || createLocal(),
4793
- sod = cloneWithOffset(now, this).startOf('day'),
4794
- format = hooks.calendarFormat(this, sod) || 'sameElse';
4795
-
4796
- var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);
4797
-
4798
- return this.format(output || this.localeData().calendar(format, this, createLocal(now)));
4799
- }
4800
-
4801
- function clone () {
4802
- return new Moment(this);
4803
- }
4804
-
4805
- function isAfter (input, units) {
4806
- var localInput = isMoment(input) ? input : createLocal(input);
4807
- if (!(this.isValid() && localInput.isValid())) {
4808
- return false;
4809
- }
4810
- units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
4811
- if (units === 'millisecond') {
4812
- return this.valueOf() > localInput.valueOf();
4813
- } else {
4814
- return localInput.valueOf() < this.clone().startOf(units).valueOf();
4815
- }
4816
- }
4817
-
4818
- function isBefore (input, units) {
4819
- var localInput = isMoment(input) ? input : createLocal(input);
4820
- if (!(this.isValid() && localInput.isValid())) {
4821
- return false;
4822
- }
4823
- units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
4824
- if (units === 'millisecond') {
4825
- return this.valueOf() < localInput.valueOf();
4826
- } else {
4827
- return this.clone().endOf(units).valueOf() < localInput.valueOf();
4828
- }
4829
- }
4830
-
4831
- function isBetween (from, to, units, inclusivity) {
4832
- inclusivity = inclusivity || '()';
4833
- return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
4834
- (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
4835
- }
4836
-
4837
- function isSame (input, units) {
4838
- var localInput = isMoment(input) ? input : createLocal(input),
4839
- inputMs;
4840
- if (!(this.isValid() && localInput.isValid())) {
4841
- return false;
4842
- }
4843
- units = normalizeUnits(units || 'millisecond');
4844
- if (units === 'millisecond') {
4845
- return this.valueOf() === localInput.valueOf();
4846
- } else {
4847
- inputMs = localInput.valueOf();
4848
- return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
4849
- }
4850
- }
4851
-
4852
- function isSameOrAfter (input, units) {
4853
- return this.isSame(input, units) || this.isAfter(input,units);
4854
- }
4855
-
4856
- function isSameOrBefore (input, units) {
4857
- return this.isSame(input, units) || this.isBefore(input,units);
4858
- }
4859
-
4860
- function diff (input, units, asFloat) {
4861
- var that,
4862
- zoneDelta,
4863
- delta, output;
4864
-
4865
- if (!this.isValid()) {
4866
- return NaN;
4867
- }
4868
-
4869
- that = cloneWithOffset(input, this);
4870
-
4871
- if (!that.isValid()) {
4872
- return NaN;
4873
- }
4874
-
4875
- zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
4876
-
4877
- units = normalizeUnits(units);
4878
-
4879
- if (units === 'year' || units === 'month' || units === 'quarter') {
4880
- output = monthDiff(this, that);
4881
- if (units === 'quarter') {
4882
- output = output / 3;
4883
- } else if (units === 'year') {
4884
- output = output / 12;
4885
- }
4886
- } else {
4887
- delta = this - that;
4888
- output = units === 'second' ? delta / 1e3 : // 1000
4889
- units === 'minute' ? delta / 6e4 : // 1000 * 60
4890
- units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60
4891
- units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
4892
- units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
4893
- delta;
4894
- }
4895
- return asFloat ? output : absFloor(output);
4896
- }
4897
-
4898
- function monthDiff (a, b) {
4899
- // difference in months
4900
- var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
4901
- // b is in (anchor - 1 month, anchor + 1 month)
4902
- anchor = a.clone().add(wholeMonthDiff, 'months'),
4903
- anchor2, adjust;
4904
-
4905
- if (b - anchor < 0) {
4906
- anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
4907
- // linear across the month
4908
- adjust = (b - anchor) / (anchor - anchor2);
4909
- } else {
4910
- anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
4911
- // linear across the month
4912
- adjust = (b - anchor) / (anchor2 - anchor);
4913
- }
4914
-
4915
- //check for negative zero, return zero if negative zero
4916
- return -(wholeMonthDiff + adjust) || 0;
4917
- }
4918
-
4919
- hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
4920
- hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
4921
-
4922
- function toString () {
4923
- return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
4924
- }
4925
-
4926
- function toISOString() {
4927
- if (!this.isValid()) {
4928
- return null;
4929
- }
4930
- var m = this.clone().utc();
4931
- if (m.year() < 0 || m.year() > 9999) {
4932
- return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
4933
- }
4934
- if (isFunction(Date.prototype.toISOString)) {
4935
- // native implementation is ~50x faster, use it when we can
4936
- return this.toDate().toISOString();
4937
- }
4938
- return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
4939
- }
4940
-
4941
- /**
4942
- * Return a human readable representation of a moment that can
4943
- * also be evaluated to get a new moment which is the same
4944
- *
4945
- * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
4946
- */
4947
- function inspect () {
4948
- if (!this.isValid()) {
4949
- return 'moment.invalid(/* ' + this._i + ' */)';
4950
- }
4951
- var func = 'moment';
4952
- var zone = '';
4953
- if (!this.isLocal()) {
4954
- func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
4955
- zone = 'Z';
4956
- }
4957
- var prefix = '[' + func + '("]';
4958
- var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';
4959
- var datetime = '-MM-DD[T]HH:mm:ss.SSS';
4960
- var suffix = zone + '[")]';
4961
-
4962
- return this.format(prefix + year + datetime + suffix);
4963
- }
4964
-
4965
- function format (inputString) {
4966
- if (!inputString) {
4967
- inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;
4968
- }
4969
- var output = formatMoment(this, inputString);
4970
- return this.localeData().postformat(output);
4971
- }
4972
-
4973
- function from (time, withoutSuffix) {
4974
- if (this.isValid() &&
4975
- ((isMoment(time) && time.isValid()) ||
4976
- createLocal(time).isValid())) {
4977
- return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
4978
- } else {
4979
- return this.localeData().invalidDate();
4980
- }
4981
- }
4982
-
4983
- function fromNow (withoutSuffix) {
4984
- return this.from(createLocal(), withoutSuffix);
4985
- }
4986
-
4987
- function to (time, withoutSuffix) {
4988
- if (this.isValid() &&
4989
- ((isMoment(time) && time.isValid()) ||
4990
- createLocal(time).isValid())) {
4991
- return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
4992
- } else {
4993
- return this.localeData().invalidDate();
4994
- }
4995
- }
4996
-
4997
- function toNow (withoutSuffix) {
4998
- return this.to(createLocal(), withoutSuffix);
4999
- }
5000
-
5001
- // If passed a locale key, it will set the locale for this
5002
- // instance. Otherwise, it will return the locale configuration
5003
- // variables for this instance.
5004
- function locale (key) {
5005
- var newLocaleData;
5006
-
5007
- if (key === undefined) {
5008
- return this._locale._abbr;
5009
- } else {
5010
- newLocaleData = getLocale(key);
5011
- if (newLocaleData != null) {
5012
- this._locale = newLocaleData;
5013
- }
5014
- return this;
5015
- }
5016
- }
5017
-
5018
- var lang = deprecate(
5019
- 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
5020
- function (key) {
5021
- if (key === undefined) {
5022
- return this.localeData();
5023
- } else {
5024
- return this.locale(key);
5025
- }
5026
- }
5027
- );
5028
-
5029
- function localeData () {
5030
- return this._locale;
5031
- }
5032
-
5033
- function startOf (units) {
5034
- units = normalizeUnits(units);
5035
- // the following switch intentionally omits break keywords
5036
- // to utilize falling through the cases.
5037
- switch (units) {
5038
- case 'year':
5039
- this.month(0);
5040
- /* falls through */
5041
- case 'quarter':
5042
- case 'month':
5043
- this.date(1);
5044
- /* falls through */
5045
- case 'week':
5046
- case 'isoWeek':
5047
- case 'day':
5048
- case 'date':
5049
- this.hours(0);
5050
- /* falls through */
5051
- case 'hour':
5052
- this.minutes(0);
5053
- /* falls through */
5054
- case 'minute':
5055
- this.seconds(0);
5056
- /* falls through */
5057
- case 'second':
5058
- this.milliseconds(0);
5059
- }
5060
-
5061
- // weeks are a special case
5062
- if (units === 'week') {
5063
- this.weekday(0);
5064
- }
5065
- if (units === 'isoWeek') {
5066
- this.isoWeekday(1);
5067
- }
5068
-
5069
- // quarters are also special
5070
- if (units === 'quarter') {
5071
- this.month(Math.floor(this.month() / 3) * 3);
5072
- }
5073
-
5074
- return this;
5075
- }
5076
-
5077
- function endOf (units) {
5078
- units = normalizeUnits(units);
5079
- if (units === undefined || units === 'millisecond') {
5080
- return this;
5081
- }
5082
-
5083
- // 'date' is an alias for 'day', so it should be considered as such.
5084
- if (units === 'date') {
5085
- units = 'day';
5086
- }
5087
-
5088
- return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
5089
- }
5090
-
5091
- function valueOf () {
5092
- return this._d.valueOf() - ((this._offset || 0) * 60000);
5093
- }
5094
-
5095
- function unix () {
5096
- return Math.floor(this.valueOf() / 1000);
5097
- }
5098
-
5099
- function toDate () {
5100
- return new Date(this.valueOf());
5101
- }
5102
-
5103
- function toArray () {
5104
- var m = this;
5105
- return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
5106
- }
5107
-
5108
- function toObject () {
5109
- var m = this;
5110
- return {
5111
- years: m.year(),
5112
- months: m.month(),
5113
- date: m.date(),
5114
- hours: m.hours(),
5115
- minutes: m.minutes(),
5116
- seconds: m.seconds(),
5117
- milliseconds: m.milliseconds()
5118
- };
5119
- }
5120
-
5121
- function toJSON () {
5122
- // new Date(NaN).toJSON() === null
5123
- return this.isValid() ? this.toISOString() : null;
5124
- }
5125
-
5126
- function isValid$2 () {
5127
- return isValid(this);
5128
- }
5129
-
5130
- function parsingFlags () {
5131
- return extend({}, getParsingFlags(this));
5132
- }
5133
-
5134
- function invalidAt () {
5135
- return getParsingFlags(this).overflow;
5136
- }
5137
-
5138
- function creationData() {
5139
- return {
5140
- input: this._i,
5141
- format: this._f,
5142
- locale: this._locale,
5143
- isUTC: this._isUTC,
5144
- strict: this._strict
5145
- };
5146
- }
5147
-
5148
- // FORMATTING
5149
-
5150
- addFormatToken(0, ['gg', 2], 0, function () {
5151
- return this.weekYear() % 100;
5152
- });
5153
-
5154
- addFormatToken(0, ['GG', 2], 0, function () {
5155
- return this.isoWeekYear() % 100;
5156
- });
5157
-
5158
- function addWeekYearFormatToken (token, getter) {
5159
- addFormatToken(0, [token, token.length], 0, getter);
5160
- }
5161
-
5162
- addWeekYearFormatToken('gggg', 'weekYear');
5163
- addWeekYearFormatToken('ggggg', 'weekYear');
5164
- addWeekYearFormatToken('GGGG', 'isoWeekYear');
5165
- addWeekYearFormatToken('GGGGG', 'isoWeekYear');
5166
-
5167
- // ALIASES
5168
-
5169
- addUnitAlias('weekYear', 'gg');
5170
- addUnitAlias('isoWeekYear', 'GG');
5171
-
5172
- // PRIORITY
5173
-
5174
- addUnitPriority('weekYear', 1);
5175
- addUnitPriority('isoWeekYear', 1);
5176
-
5177
-
5178
- // PARSING
5179
-
5180
- addRegexToken('G', matchSigned);
5181
- addRegexToken('g', matchSigned);
5182
- addRegexToken('GG', match1to2, match2);
5183
- addRegexToken('gg', match1to2, match2);
5184
- addRegexToken('GGGG', match1to4, match4);
5185
- addRegexToken('gggg', match1to4, match4);
5186
- addRegexToken('GGGGG', match1to6, match6);
5187
- addRegexToken('ggggg', match1to6, match6);
5188
-
5189
- addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
5190
- week[token.substr(0, 2)] = toInt(input);
5191
- });
5192
-
5193
- addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
5194
- week[token] = hooks.parseTwoDigitYear(input);
5195
- });
5196
-
5197
- // MOMENTS
5198
-
5199
- function getSetWeekYear (input) {
5200
- return getSetWeekYearHelper.call(this,
5201
- input,
5202
- this.week(),
5203
- this.weekday(),
5204
- this.localeData()._week.dow,
5205
- this.localeData()._week.doy);
5206
- }
5207
-
5208
- function getSetISOWeekYear (input) {
5209
- return getSetWeekYearHelper.call(this,
5210
- input, this.isoWeek(), this.isoWeekday(), 1, 4);
5211
- }
5212
-
5213
- function getISOWeeksInYear () {
5214
- return weeksInYear(this.year(), 1, 4);
5215
- }
5216
-
5217
- function getWeeksInYear () {
5218
- var weekInfo = this.localeData()._week;
5219
- return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
5220
- }
5221
-
5222
- function getSetWeekYearHelper(input, week, weekday, dow, doy) {
5223
- var weeksTarget;
5224
- if (input == null) {
5225
- return weekOfYear(this, dow, doy).year;
5226
- } else {
5227
- weeksTarget = weeksInYear(input, dow, doy);
5228
- if (week > weeksTarget) {
5229
- week = weeksTarget;
5230
- }
5231
- return setWeekAll.call(this, input, week, weekday, dow, doy);
5232
- }
5233
- }
5234
-
5235
- function setWeekAll(weekYear, week, weekday, dow, doy) {
5236
- var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
5237
- date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
5238
-
5239
- this.year(date.getUTCFullYear());
5240
- this.month(date.getUTCMonth());
5241
- this.date(date.getUTCDate());
5242
- return this;
5243
- }
5244
-
5245
- // FORMATTING
5246
-
5247
- addFormatToken('Q', 0, 'Qo', 'quarter');
5248
-
5249
- // ALIASES
5250
-
5251
- addUnitAlias('quarter', 'Q');
5252
-
5253
- // PRIORITY
5254
-
5255
- addUnitPriority('quarter', 7);
5256
-
5257
- // PARSING
5258
-
5259
- addRegexToken('Q', match1);
5260
- addParseToken('Q', function (input, array) {
5261
- array[MONTH] = (toInt(input) - 1) * 3;
5262
- });
5263
-
5264
- // MOMENTS
5265
-
5266
- function getSetQuarter (input) {
5267
- return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
5268
- }
5269
-
5270
- // FORMATTING
5271
-
5272
- addFormatToken('D', ['DD', 2], 'Do', 'date');
5273
-
5274
- // ALIASES
5275
-
5276
- addUnitAlias('date', 'D');
5277
-
5278
- // PRIOROITY
5279
- addUnitPriority('date', 9);
5280
-
5281
- // PARSING
5282
-
5283
- addRegexToken('D', match1to2);
5284
- addRegexToken('DD', match1to2, match2);
5285
- addRegexToken('Do', function (isStrict, locale) {
5286
- // TODO: Remove "ordinalParse" fallback in next major release.
5287
- return isStrict ?
5288
- (locale._dayOfMonthOrdinalParse || locale._ordinalParse) :
5289
- locale._dayOfMonthOrdinalParseLenient;
5290
- });
5291
-
5292
- addParseToken(['D', 'DD'], DATE);
5293
- addParseToken('Do', function (input, array) {
5294
- array[DATE] = toInt(input.match(match1to2)[0], 10);
5295
- });
5296
-
5297
- // MOMENTS
5298
-
5299
- var getSetDayOfMonth = makeGetSet('Date', true);
5300
-
5301
- // FORMATTING
5302
-
5303
- addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
5304
-
5305
- // ALIASES
5306
-
5307
- addUnitAlias('dayOfYear', 'DDD');
5308
-
5309
- // PRIORITY
5310
- addUnitPriority('dayOfYear', 4);
5311
-
5312
- // PARSING
5313
-
5314
- addRegexToken('DDD', match1to3);
5315
- addRegexToken('DDDD', match3);
5316
- addParseToken(['DDD', 'DDDD'], function (input, array, config) {
5317
- config._dayOfYear = toInt(input);
5318
- });
5319
-
5320
- // HELPERS
5321
-
5322
- // MOMENTS
5323
-
5324
- function getSetDayOfYear (input) {
5325
- var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
5326
- return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
5327
- }
5328
-
5329
- // FORMATTING
5330
-
5331
- addFormatToken('m', ['mm', 2], 0, 'minute');
5332
-
5333
- // ALIASES
5334
-
5335
- addUnitAlias('minute', 'm');
5336
-
5337
- // PRIORITY
5338
-
5339
- addUnitPriority('minute', 14);
5340
-
5341
- // PARSING
5342
-
5343
- addRegexToken('m', match1to2);
5344
- addRegexToken('mm', match1to2, match2);
5345
- addParseToken(['m', 'mm'], MINUTE);
5346
-
5347
- // MOMENTS
5348
-
5349
- var getSetMinute = makeGetSet('Minutes', false);
5350
-
5351
- // FORMATTING
5352
-
5353
- addFormatToken('s', ['ss', 2], 0, 'second');
5354
-
5355
- // ALIASES
5356
-
5357
- addUnitAlias('second', 's');
5358
-
5359
- // PRIORITY
5360
-
5361
- addUnitPriority('second', 15);
5362
-
5363
- // PARSING
5364
-
5365
- addRegexToken('s', match1to2);
5366
- addRegexToken('ss', match1to2, match2);
5367
- addParseToken(['s', 'ss'], SECOND);
5368
-
5369
- // MOMENTS
5370
-
5371
- var getSetSecond = makeGetSet('Seconds', false);
5372
-
5373
- // FORMATTING
5374
-
5375
- addFormatToken('S', 0, 0, function () {
5376
- return ~~(this.millisecond() / 100);
5377
- });
5378
-
5379
- addFormatToken(0, ['SS', 2], 0, function () {
5380
- return ~~(this.millisecond() / 10);
5381
- });
5382
-
5383
- addFormatToken(0, ['SSS', 3], 0, 'millisecond');
5384
- addFormatToken(0, ['SSSS', 4], 0, function () {
5385
- return this.millisecond() * 10;
5386
- });
5387
- addFormatToken(0, ['SSSSS', 5], 0, function () {
5388
- return this.millisecond() * 100;
5389
- });
5390
- addFormatToken(0, ['SSSSSS', 6], 0, function () {
5391
- return this.millisecond() * 1000;
5392
- });
5393
- addFormatToken(0, ['SSSSSSS', 7], 0, function () {
5394
- return this.millisecond() * 10000;
5395
- });
5396
- addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
5397
- return this.millisecond() * 100000;
5398
- });
5399
- addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
5400
- return this.millisecond() * 1000000;
5401
- });
5402
-
5403
-
5404
- // ALIASES
5405
-
5406
- addUnitAlias('millisecond', 'ms');
5407
-
5408
- // PRIORITY
5409
-
5410
- addUnitPriority('millisecond', 16);
5411
-
5412
- // PARSING
5413
-
5414
- addRegexToken('S', match1to3, match1);
5415
- addRegexToken('SS', match1to3, match2);
5416
- addRegexToken('SSS', match1to3, match3);
5417
-
5418
- var token;
5419
- for (token = 'SSSS'; token.length <= 9; token += 'S') {
5420
- addRegexToken(token, matchUnsigned);
5421
- }
5422
-
5423
- function parseMs(input, array) {
5424
- array[MILLISECOND] = toInt(('0.' + input) * 1000);
5425
- }
5426
-
5427
- for (token = 'S'; token.length <= 9; token += 'S') {
5428
- addParseToken(token, parseMs);
5429
- }
5430
- // MOMENTS
5431
-
5432
- var getSetMillisecond = makeGetSet('Milliseconds', false);
5433
-
5434
- // FORMATTING
5435
-
5436
- addFormatToken('z', 0, 0, 'zoneAbbr');
5437
- addFormatToken('zz', 0, 0, 'zoneName');
5438
-
5439
- // MOMENTS
5440
-
5441
- function getZoneAbbr () {
5442
- return this._isUTC ? 'UTC' : '';
5443
- }
5444
-
5445
- function getZoneName () {
5446
- return this._isUTC ? 'Coordinated Universal Time' : '';
5447
- }
5448
-
5449
- var proto = Moment.prototype;
5450
-
5451
- proto.add = add;
5452
- proto.calendar = calendar$1;
5453
- proto.clone = clone;
5454
- proto.diff = diff;
5455
- proto.endOf = endOf;
5456
- proto.format = format;
5457
- proto.from = from;
5458
- proto.fromNow = fromNow;
5459
- proto.to = to;
5460
- proto.toNow = toNow;
5461
- proto.get = stringGet;
5462
- proto.invalidAt = invalidAt;
5463
- proto.isAfter = isAfter;
5464
- proto.isBefore = isBefore;
5465
- proto.isBetween = isBetween;
5466
- proto.isSame = isSame;
5467
- proto.isSameOrAfter = isSameOrAfter;
5468
- proto.isSameOrBefore = isSameOrBefore;
5469
- proto.isValid = isValid$2;
5470
- proto.lang = lang;
5471
- proto.locale = locale;
5472
- proto.localeData = localeData;
5473
- proto.max = prototypeMax;
5474
- proto.min = prototypeMin;
5475
- proto.parsingFlags = parsingFlags;
5476
- proto.set = stringSet;
5477
- proto.startOf = startOf;
5478
- proto.subtract = subtract;
5479
- proto.toArray = toArray;
5480
- proto.toObject = toObject;
5481
- proto.toDate = toDate;
5482
- proto.toISOString = toISOString;
5483
- proto.inspect = inspect;
5484
- proto.toJSON = toJSON;
5485
- proto.toString = toString;
5486
- proto.unix = unix;
5487
- proto.valueOf = valueOf;
5488
- proto.creationData = creationData;
5489
-
5490
- // Year
5491
- proto.year = getSetYear;
5492
- proto.isLeapYear = getIsLeapYear;
5493
-
5494
- // Week Year
5495
- proto.weekYear = getSetWeekYear;
5496
- proto.isoWeekYear = getSetISOWeekYear;
5497
-
5498
- // Quarter
5499
- proto.quarter = proto.quarters = getSetQuarter;
5500
-
5501
- // Month
5502
- proto.month = getSetMonth;
5503
- proto.daysInMonth = getDaysInMonth;
5504
-
5505
- // Week
5506
- proto.week = proto.weeks = getSetWeek;
5507
- proto.isoWeek = proto.isoWeeks = getSetISOWeek;
5508
- proto.weeksInYear = getWeeksInYear;
5509
- proto.isoWeeksInYear = getISOWeeksInYear;
5510
-
5511
- // Day
5512
- proto.date = getSetDayOfMonth;
5513
- proto.day = proto.days = getSetDayOfWeek;
5514
- proto.weekday = getSetLocaleDayOfWeek;
5515
- proto.isoWeekday = getSetISODayOfWeek;
5516
- proto.dayOfYear = getSetDayOfYear;
5517
-
5518
- // Hour
5519
- proto.hour = proto.hours = getSetHour;
5520
-
5521
- // Minute
5522
- proto.minute = proto.minutes = getSetMinute;
5523
-
5524
- // Second
5525
- proto.second = proto.seconds = getSetSecond;
5526
-
5527
- // Millisecond
5528
- proto.millisecond = proto.milliseconds = getSetMillisecond;
5529
-
5530
- // Offset
5531
- proto.utcOffset = getSetOffset;
5532
- proto.utc = setOffsetToUTC;
5533
- proto.local = setOffsetToLocal;
5534
- proto.parseZone = setOffsetToParsedOffset;
5535
- proto.hasAlignedHourOffset = hasAlignedHourOffset;
5536
- proto.isDST = isDaylightSavingTime;
5537
- proto.isLocal = isLocal;
5538
- proto.isUtcOffset = isUtcOffset;
5539
- proto.isUtc = isUtc;
5540
- proto.isUTC = isUtc;
5541
-
5542
- // Timezone
5543
- proto.zoneAbbr = getZoneAbbr;
5544
- proto.zoneName = getZoneName;
5545
-
5546
- // Deprecations
5547
- proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
5548
- proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
5549
- proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
5550
- proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
5551
- proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
5552
-
5553
- function createUnix (input) {
5554
- return createLocal(input * 1000);
5555
- }
5556
-
5557
- function createInZone () {
5558
- return createLocal.apply(null, arguments).parseZone();
5559
- }
5560
-
5561
- function preParsePostFormat (string) {
5562
- return string;
5563
- }
5564
-
5565
- var proto$1 = Locale.prototype;
5566
-
5567
- proto$1.calendar = calendar;
5568
- proto$1.longDateFormat = longDateFormat;
5569
- proto$1.invalidDate = invalidDate;
5570
- proto$1.ordinal = ordinal;
5571
- proto$1.preparse = preParsePostFormat;
5572
- proto$1.postformat = preParsePostFormat;
5573
- proto$1.relativeTime = relativeTime;
5574
- proto$1.pastFuture = pastFuture;
5575
- proto$1.set = set;
5576
-
5577
- // Month
5578
- proto$1.months = localeMonths;
5579
- proto$1.monthsShort = localeMonthsShort;
5580
- proto$1.monthsParse = localeMonthsParse;
5581
- proto$1.monthsRegex = monthsRegex;
5582
- proto$1.monthsShortRegex = monthsShortRegex;
5583
-
5584
- // Week
5585
- proto$1.week = localeWeek;
5586
- proto$1.firstDayOfYear = localeFirstDayOfYear;
5587
- proto$1.firstDayOfWeek = localeFirstDayOfWeek;
5588
-
5589
- // Day of Week
5590
- proto$1.weekdays = localeWeekdays;
5591
- proto$1.weekdaysMin = localeWeekdaysMin;
5592
- proto$1.weekdaysShort = localeWeekdaysShort;
5593
- proto$1.weekdaysParse = localeWeekdaysParse;
5594
-
5595
- proto$1.weekdaysRegex = weekdaysRegex;
5596
- proto$1.weekdaysShortRegex = weekdaysShortRegex;
5597
- proto$1.weekdaysMinRegex = weekdaysMinRegex;
5598
-
5599
- // Hours
5600
- proto$1.isPM = localeIsPM;
5601
- proto$1.meridiem = localeMeridiem;
5602
-
5603
- function get$1 (format, index, field, setter) {
5604
- var locale = getLocale();
5605
- var utc = createUTC().set(setter, index);
5606
- return locale[field](utc, format);
5607
- }
5608
-
5609
- function listMonthsImpl (format, index, field) {
5610
- if (isNumber(format)) {
5611
- index = format;
5612
- format = undefined;
5613
- }
5614
-
5615
- format = format || '';
5616
-
5617
- if (index != null) {
5618
- return get$1(format, index, field, 'month');
5619
- }
5620
-
5621
- var i;
5622
- var out = [];
5623
- for (i = 0; i < 12; i++) {
5624
- out[i] = get$1(format, i, field, 'month');
5625
- }
5626
- return out;
5627
- }
5628
-
5629
- // ()
5630
- // (5)
5631
- // (fmt, 5)
5632
- // (fmt)
5633
- // (true)
5634
- // (true, 5)
5635
- // (true, fmt, 5)
5636
- // (true, fmt)
5637
- function listWeekdaysImpl (localeSorted, format, index, field) {
5638
- if (typeof localeSorted === 'boolean') {
5639
- if (isNumber(format)) {
5640
- index = format;
5641
- format = undefined;
5642
- }
5643
-
5644
- format = format || '';
5645
- } else {
5646
- format = localeSorted;
5647
- index = format;
5648
- localeSorted = false;
5649
-
5650
- if (isNumber(format)) {
5651
- index = format;
5652
- format = undefined;
5653
- }
5654
-
5655
- format = format || '';
5656
- }
5657
-
5658
- var locale = getLocale(),
5659
- shift = localeSorted ? locale._week.dow : 0;
5660
-
5661
- if (index != null) {
5662
- return get$1(format, (index + shift) % 7, field, 'day');
5663
- }
5664
-
5665
- var i;
5666
- var out = [];
5667
- for (i = 0; i < 7; i++) {
5668
- out[i] = get$1(format, (i + shift) % 7, field, 'day');
5669
- }
5670
- return out;
5671
- }
5672
-
5673
- function listMonths (format, index) {
5674
- return listMonthsImpl(format, index, 'months');
5675
- }
5676
-
5677
- function listMonthsShort (format, index) {
5678
- return listMonthsImpl(format, index, 'monthsShort');
5679
- }
5680
-
5681
- function listWeekdays (localeSorted, format, index) {
5682
- return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
5683
- }
5684
-
5685
- function listWeekdaysShort (localeSorted, format, index) {
5686
- return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
5687
- }
5688
-
5689
- function listWeekdaysMin (localeSorted, format, index) {
5690
- return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
5691
- }
5692
-
5693
- getSetGlobalLocale('en', {
5694
- dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
5695
- ordinal : function (number) {
5696
- var b = number % 10,
5697
- output = (toInt(number % 100 / 10) === 1) ? 'th' :
5698
- (b === 1) ? 'st' :
5699
- (b === 2) ? 'nd' :
5700
- (b === 3) ? 'rd' : 'th';
5701
- return number + output;
5702
- }
5703
- });
5704
-
5705
- // Side effect imports
5706
- hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);
5707
- hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);
5708
-
5709
- var mathAbs = Math.abs;
5710
-
5711
- function abs () {
5712
- var data = this._data;
5713
-
5714
- this._milliseconds = mathAbs(this._milliseconds);
5715
- this._days = mathAbs(this._days);
5716
- this._months = mathAbs(this._months);
5717
-
5718
- data.milliseconds = mathAbs(data.milliseconds);
5719
- data.seconds = mathAbs(data.seconds);
5720
- data.minutes = mathAbs(data.minutes);
5721
- data.hours = mathAbs(data.hours);
5722
- data.months = mathAbs(data.months);
5723
- data.years = mathAbs(data.years);
5724
-
5725
- return this;
5726
- }
5727
-
5728
- function addSubtract$1 (duration, input, value, direction) {
5729
- var other = createDuration(input, value);
5730
-
5731
- duration._milliseconds += direction * other._milliseconds;
5732
- duration._days += direction * other._days;
5733
- duration._months += direction * other._months;
5734
-
5735
- return duration._bubble();
5736
- }
5737
-
5738
- // supports only 2.0-style add(1, 's') or add(duration)
5739
- function add$1 (input, value) {
5740
- return addSubtract$1(this, input, value, 1);
5741
- }
5742
-
5743
- // supports only 2.0-style subtract(1, 's') or subtract(duration)
5744
- function subtract$1 (input, value) {
5745
- return addSubtract$1(this, input, value, -1);
5746
- }
5747
-
5748
- function absCeil (number) {
5749
- if (number < 0) {
5750
- return Math.floor(number);
5751
- } else {
5752
- return Math.ceil(number);
5753
- }
5754
- }
5755
-
5756
- function bubble () {
5757
- var milliseconds = this._milliseconds;
5758
- var days = this._days;
5759
- var months = this._months;
5760
- var data = this._data;
5761
- var seconds, minutes, hours, years, monthsFromDays;
5762
-
5763
- // if we have a mix of positive and negative values, bubble down first
5764
- // check: https://github.com/moment/moment/issues/2166
5765
- if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
5766
- (milliseconds <= 0 && days <= 0 && months <= 0))) {
5767
- milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
5768
- days = 0;
5769
- months = 0;
5770
- }
5771
-
5772
- // The following code bubbles up values, see the tests for
5773
- // examples of what that means.
5774
- data.milliseconds = milliseconds % 1000;
5775
-
5776
- seconds = absFloor(milliseconds / 1000);
5777
- data.seconds = seconds % 60;
5778
-
5779
- minutes = absFloor(seconds / 60);
5780
- data.minutes = minutes % 60;
5781
-
5782
- hours = absFloor(minutes / 60);
5783
- data.hours = hours % 24;
5784
-
5785
- days += absFloor(hours / 24);
5786
-
5787
- // convert days to months
5788
- monthsFromDays = absFloor(daysToMonths(days));
5789
- months += monthsFromDays;
5790
- days -= absCeil(monthsToDays(monthsFromDays));
5791
-
5792
- // 12 months -> 1 year
5793
- years = absFloor(months / 12);
5794
- months %= 12;
5795
-
5796
- data.days = days;
5797
- data.months = months;
5798
- data.years = years;
5799
-
5800
- return this;
5801
- }
5802
-
5803
- function daysToMonths (days) {
5804
- // 400 years have 146097 days (taking into account leap year rules)
5805
- // 400 years have 12 months === 4800
5806
- return days * 4800 / 146097;
5807
- }
5808
-
5809
- function monthsToDays (months) {
5810
- // the reverse of daysToMonths
5811
- return months * 146097 / 4800;
5812
- }
5813
-
5814
- function as (units) {
5815
- if (!this.isValid()) {
5816
- return NaN;
5817
- }
5818
- var days;
5819
- var months;
5820
- var milliseconds = this._milliseconds;
5821
-
5822
- units = normalizeUnits(units);
5823
-
5824
- if (units === 'month' || units === 'year') {
5825
- days = this._days + milliseconds / 864e5;
5826
- months = this._months + daysToMonths(days);
5827
- return units === 'month' ? months : months / 12;
5828
- } else {
5829
- // handle milliseconds separately because of floating point math errors (issue #1867)
5830
- days = this._days + Math.round(monthsToDays(this._months));
5831
- switch (units) {
5832
- case 'week' : return days / 7 + milliseconds / 6048e5;
5833
- case 'day' : return days + milliseconds / 864e5;
5834
- case 'hour' : return days * 24 + milliseconds / 36e5;
5835
- case 'minute' : return days * 1440 + milliseconds / 6e4;
5836
- case 'second' : return days * 86400 + milliseconds / 1000;
5837
- // Math.floor prevents floating point math errors here
5838
- case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
5839
- default: throw new Error('Unknown unit ' + units);
5840
- }
5841
- }
5842
- }
5843
-
5844
- // TODO: Use this.as('ms')?
5845
- function valueOf$1 () {
5846
- if (!this.isValid()) {
5847
- return NaN;
5848
- }
5849
- return (
5850
- this._milliseconds +
5851
- this._days * 864e5 +
5852
- (this._months % 12) * 2592e6 +
5853
- toInt(this._months / 12) * 31536e6
5854
- );
5855
- }
5856
-
5857
- function makeAs (alias) {
5858
- return function () {
5859
- return this.as(alias);
5860
- };
5861
- }
5862
-
5863
- var asMilliseconds = makeAs('ms');
5864
- var asSeconds = makeAs('s');
5865
- var asMinutes = makeAs('m');
5866
- var asHours = makeAs('h');
5867
- var asDays = makeAs('d');
5868
- var asWeeks = makeAs('w');
5869
- var asMonths = makeAs('M');
5870
- var asYears = makeAs('y');
5871
-
5872
- function get$2 (units) {
5873
- units = normalizeUnits(units);
5874
- return this.isValid() ? this[units + 's']() : NaN;
5875
- }
5876
-
5877
- function makeGetter(name) {
5878
- return function () {
5879
- return this.isValid() ? this._data[name] : NaN;
5880
- };
5881
- }
5882
-
5883
- var milliseconds = makeGetter('milliseconds');
5884
- var seconds = makeGetter('seconds');
5885
- var minutes = makeGetter('minutes');
5886
- var hours = makeGetter('hours');
5887
- var days = makeGetter('days');
5888
- var months = makeGetter('months');
5889
- var years = makeGetter('years');
5890
-
5891
- function weeks () {
5892
- return absFloor(this.days() / 7);
5893
- }
5894
-
5895
- var round = Math.round;
5896
- var thresholds = {
5897
- ss: 44, // a few seconds to seconds
5898
- s : 45, // seconds to minute
5899
- m : 45, // minutes to hour
5900
- h : 22, // hours to day
5901
- d : 26, // days to month
5902
- M : 11 // months to year
5903
- };
5904
-
5905
- // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
5906
- function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
5907
- return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
5908
- }
5909
-
5910
- function relativeTime$1 (posNegDuration, withoutSuffix, locale) {
5911
- var duration = createDuration(posNegDuration).abs();
5912
- var seconds = round(duration.as('s'));
5913
- var minutes = round(duration.as('m'));
5914
- var hours = round(duration.as('h'));
5915
- var days = round(duration.as('d'));
5916
- var months = round(duration.as('M'));
5917
- var years = round(duration.as('y'));
5918
-
5919
- var a = seconds <= thresholds.ss && ['s', seconds] ||
5920
- seconds < thresholds.s && ['ss', seconds] ||
5921
- minutes <= 1 && ['m'] ||
5922
- minutes < thresholds.m && ['mm', minutes] ||
5923
- hours <= 1 && ['h'] ||
5924
- hours < thresholds.h && ['hh', hours] ||
5925
- days <= 1 && ['d'] ||
5926
- days < thresholds.d && ['dd', days] ||
5927
- months <= 1 && ['M'] ||
5928
- months < thresholds.M && ['MM', months] ||
5929
- years <= 1 && ['y'] || ['yy', years];
5930
-
5931
- a[2] = withoutSuffix;
5932
- a[3] = +posNegDuration > 0;
5933
- a[4] = locale;
5934
- return substituteTimeAgo.apply(null, a);
5935
- }
5936
-
5937
- // This function allows you to set the rounding function for relative time strings
5938
- function getSetRelativeTimeRounding (roundingFunction) {
5939
- if (roundingFunction === undefined) {
5940
- return round;
5941
- }
5942
- if (typeof(roundingFunction) === 'function') {
5943
- round = roundingFunction;
5944
- return true;
5945
- }
5946
- return false;
5947
- }
5948
-
5949
- // This function allows you to set a threshold for relative time strings
5950
- function getSetRelativeTimeThreshold (threshold, limit) {
5951
- if (thresholds[threshold] === undefined) {
5952
- return false;
5953
- }
5954
- if (limit === undefined) {
5955
- return thresholds[threshold];
5956
- }
5957
- thresholds[threshold] = limit;
5958
- if (threshold === 's') {
5959
- thresholds.ss = limit - 1;
5960
- }
5961
- return true;
5962
- }
5963
-
5964
- function humanize (withSuffix) {
5965
- if (!this.isValid()) {
5966
- return this.localeData().invalidDate();
5967
- }
5968
-
5969
- var locale = this.localeData();
5970
- var output = relativeTime$1(this, !withSuffix, locale);
5971
-
5972
- if (withSuffix) {
5973
- output = locale.pastFuture(+this, output);
5974
- }
5975
-
5976
- return locale.postformat(output);
5977
- }
5978
-
5979
- var abs$1 = Math.abs;
5980
-
5981
- function toISOString$1() {
5982
- // for ISO strings we do not use the normal bubbling rules:
5983
- // * milliseconds bubble up until they become hours
5984
- // * days do not bubble at all
5985
- // * months bubble up until they become years
5986
- // This is because there is no context-free conversion between hours and days
5987
- // (think of clock changes)
5988
- // and also not between days and months (28-31 days per month)
5989
- if (!this.isValid()) {
5990
- return this.localeData().invalidDate();
5991
- }
5992
-
5993
- var seconds = abs$1(this._milliseconds) / 1000;
5994
- var days = abs$1(this._days);
5995
- var months = abs$1(this._months);
5996
- var minutes, hours, years;
5997
-
5998
- // 3600 seconds -> 60 minutes -> 1 hour
5999
- minutes = absFloor(seconds / 60);
6000
- hours = absFloor(minutes / 60);
6001
- seconds %= 60;
6002
- minutes %= 60;
6003
-
6004
- // 12 months -> 1 year
6005
- years = absFloor(months / 12);
6006
- months %= 12;
6007
-
6008
-
6009
- // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
6010
- var Y = years;
6011
- var M = months;
6012
- var D = days;
6013
- var h = hours;
6014
- var m = minutes;
6015
- var s = seconds;
6016
- var total = this.asSeconds();
6017
-
6018
- if (!total) {
6019
- // this is the same as C#'s (Noda) and python (isodate)...
6020
- // but not other JS (goog.date)
6021
- return 'P0D';
6022
- }
6023
-
6024
- return (total < 0 ? '-' : '') +
6025
- 'P' +
6026
- (Y ? Y + 'Y' : '') +
6027
- (M ? M + 'M' : '') +
6028
- (D ? D + 'D' : '') +
6029
- ((h || m || s) ? 'T' : '') +
6030
- (h ? h + 'H' : '') +
6031
- (m ? m + 'M' : '') +
6032
- (s ? s + 'S' : '');
6033
- }
6034
-
6035
- var proto$2 = Duration.prototype;
6036
-
6037
- proto$2.isValid = isValid$1;
6038
- proto$2.abs = abs;
6039
- proto$2.add = add$1;
6040
- proto$2.subtract = subtract$1;
6041
- proto$2.as = as;
6042
- proto$2.asMilliseconds = asMilliseconds;
6043
- proto$2.asSeconds = asSeconds;
6044
- proto$2.asMinutes = asMinutes;
6045
- proto$2.asHours = asHours;
6046
- proto$2.asDays = asDays;
6047
- proto$2.asWeeks = asWeeks;
6048
- proto$2.asMonths = asMonths;
6049
- proto$2.asYears = asYears;
6050
- proto$2.valueOf = valueOf$1;
6051
- proto$2._bubble = bubble;
6052
- proto$2.get = get$2;
6053
- proto$2.milliseconds = milliseconds;
6054
- proto$2.seconds = seconds;
6055
- proto$2.minutes = minutes;
6056
- proto$2.hours = hours;
6057
- proto$2.days = days;
6058
- proto$2.weeks = weeks;
6059
- proto$2.months = months;
6060
- proto$2.years = years;
6061
- proto$2.humanize = humanize;
6062
- proto$2.toISOString = toISOString$1;
6063
- proto$2.toString = toISOString$1;
6064
- proto$2.toJSON = toISOString$1;
6065
- proto$2.locale = locale;
6066
- proto$2.localeData = localeData;
6067
-
6068
- // Deprecations
6069
- proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);
6070
- proto$2.lang = lang;
6071
-
6072
- // Side effect imports
6073
-
6074
- // FORMATTING
6075
-
6076
- addFormatToken('X', 0, 0, 'unix');
6077
- addFormatToken('x', 0, 0, 'valueOf');
6078
-
6079
- // PARSING
6080
-
6081
- addRegexToken('x', matchSigned);
6082
- addRegexToken('X', matchTimestamp);
6083
- addParseToken('X', function (input, array, config) {
6084
- config._d = new Date(parseFloat(input, 10) * 1000);
6085
- });
6086
- addParseToken('x', function (input, array, config) {
6087
- config._d = new Date(toInt(input));
6088
- });
6089
-
6090
- // Side effect imports
6091
-
6092
-
6093
- hooks.version = '2.18.1';
6094
-
6095
- setHookCallback(createLocal);
6096
-
6097
- hooks.fn = proto;
6098
- hooks.min = min;
6099
- hooks.max = max;
6100
- hooks.now = now;
6101
- hooks.utc = createUTC;
6102
- hooks.unix = createUnix;
6103
- hooks.months = listMonths;
6104
- hooks.isDate = isDate;
6105
- hooks.locale = getSetGlobalLocale;
6106
- hooks.invalid = createInvalid;
6107
- hooks.duration = createDuration;
6108
- hooks.isMoment = isMoment;
6109
- hooks.weekdays = listWeekdays;
6110
- hooks.parseZone = createInZone;
6111
- hooks.localeData = getLocale;
6112
- hooks.isDuration = isDuration;
6113
- hooks.monthsShort = listMonthsShort;
6114
- hooks.weekdaysMin = listWeekdaysMin;
6115
- hooks.defineLocale = defineLocale;
6116
- hooks.updateLocale = updateLocale;
6117
- hooks.locales = listLocales;
6118
- hooks.weekdaysShort = listWeekdaysShort;
6119
- hooks.normalizeUnits = normalizeUnits;
6120
- hooks.relativeTimeRounding = getSetRelativeTimeRounding;
6121
- hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
6122
- hooks.calendarFormat = getCalendarFormat;
6123
- hooks.prototype = proto;
6124
-
6125
- return hooks;
6126
-
6127
- })));
6128
-
6129
- },{}],7:[function(require,module,exports){
6130
- /**
6131
- * @namespace Chart
6132
- */
6133
- var Chart = require(28)();
6134
-
6135
- require(26)(Chart);
6136
- require(40)(Chart);
6137
- require(22)(Chart);
6138
- require(25)(Chart);
6139
- require(30)(Chart);
6140
- require(21)(Chart);
6141
- require(23)(Chart);
6142
- require(24)(Chart);
6143
- require(29)(Chart);
6144
- require(32)(Chart);
6145
- require(33)(Chart);
6146
- require(31)(Chart);
6147
- require(27)(Chart);
6148
- require(34)(Chart);
6149
-
6150
- require(35)(Chart);
6151
- require(36)(Chart);
6152
- require(37)(Chart);
6153
- require(38)(Chart);
6154
-
6155
- require(46)(Chart);
6156
- require(44)(Chart);
6157
- require(45)(Chart);
6158
- require(47)(Chart);
6159
- require(48)(Chart);
6160
- require(49)(Chart);
6161
-
6162
- // Controllers must be loaded after elements
6163
- // See Chart.core.datasetController.dataElementType
6164
- require(15)(Chart);
6165
- require(16)(Chart);
6166
- require(17)(Chart);
6167
- require(18)(Chart);
6168
- require(19)(Chart);
6169
- require(20)(Chart);
6170
-
6171
- require(8)(Chart);
6172
- require(9)(Chart);
6173
- require(10)(Chart);
6174
- require(11)(Chart);
6175
- require(12)(Chart);
6176
- require(13)(Chart);
6177
- require(14)(Chart);
6178
-
6179
- // Loading built-it plugins
6180
- var plugins = [];
6181
-
6182
- plugins.push(
6183
- require(41)(Chart),
6184
- require(42)(Chart),
6185
- require(43)(Chart)
6186
- );
6187
-
6188
- Chart.plugins.register(plugins);
6189
-
6190
- module.exports = Chart;
6191
- if (typeof window !== 'undefined') {
6192
- window.Chart = Chart;
6193
- }
6194
-
6195
- },{"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,"36":36,"37":37,"38":38,"40":40,"41":41,"42":42,"43":43,"44":44,"45":45,"46":46,"47":47,"48":48,"49":49,"8":8,"9":9}],8:[function(require,module,exports){
6196
- 'use strict';
6197
-
6198
- module.exports = function(Chart) {
6199
-
6200
- Chart.Bar = function(context, config) {
6201
- config.type = 'bar';
6202
-
6203
- return new Chart(context, config);
6204
- };
6205
-
6206
- };
6207
-
6208
- },{}],9:[function(require,module,exports){
6209
- 'use strict';
6210
-
6211
- module.exports = function(Chart) {
6212
-
6213
- Chart.Bubble = function(context, config) {
6214
- config.type = 'bubble';
6215
- return new Chart(context, config);
6216
- };
6217
-
6218
- };
6219
-
6220
- },{}],10:[function(require,module,exports){
6221
- 'use strict';
6222
-
6223
- module.exports = function(Chart) {
6224
-
6225
- Chart.Doughnut = function(context, config) {
6226
- config.type = 'doughnut';
6227
-
6228
- return new Chart(context, config);
6229
- };
6230
-
6231
- };
6232
-
6233
- },{}],11:[function(require,module,exports){
6234
- 'use strict';
6235
-
6236
- module.exports = function(Chart) {
6237
-
6238
- Chart.Line = function(context, config) {
6239
- config.type = 'line';
6240
-
6241
- return new Chart(context, config);
6242
- };
6243
-
6244
- };
6245
-
6246
- },{}],12:[function(require,module,exports){
6247
- 'use strict';
6248
-
6249
- module.exports = function(Chart) {
6250
-
6251
- Chart.PolarArea = function(context, config) {
6252
- config.type = 'polarArea';
6253
-
6254
- return new Chart(context, config);
6255
- };
6256
-
6257
- };
6258
-
6259
- },{}],13:[function(require,module,exports){
6260
- 'use strict';
6261
-
6262
- module.exports = function(Chart) {
6263
-
6264
- Chart.Radar = function(context, config) {
6265
- config.type = 'radar';
6266
-
6267
- return new Chart(context, config);
6268
- };
6269
-
6270
- };
6271
-
6272
- },{}],14:[function(require,module,exports){
6273
- 'use strict';
6274
-
6275
- module.exports = function(Chart) {
6276
-
6277
- var defaultConfig = {
6278
- hover: {
6279
- mode: 'single'
6280
- },
6281
-
6282
- scales: {
6283
- xAxes: [{
6284
- type: 'linear', // scatter should not use a category axis
6285
- position: 'bottom',
6286
- id: 'x-axis-1' // need an ID so datasets can reference the scale
6287
- }],
6288
- yAxes: [{
6289
- type: 'linear',
6290
- position: 'left',
6291
- id: 'y-axis-1'
6292
- }]
6293
- },
6294
-
6295
- tooltips: {
6296
- callbacks: {
6297
- title: function() {
6298
- // Title doesn't make sense for scatter since we format the data as a point
6299
- return '';
6300
- },
6301
- label: function(tooltipItem) {
6302
- return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')';
6303
- }
6304
- }
6305
- }
6306
- };
6307
-
6308
- // Register the default config for this type
6309
- Chart.defaults.scatter = defaultConfig;
6310
-
6311
- // Scatter charts use line controllers
6312
- Chart.controllers.scatter = Chart.controllers.line;
6313
-
6314
- Chart.Scatter = function(context, config) {
6315
- config.type = 'scatter';
6316
- return new Chart(context, config);
6317
- };
6318
-
6319
- };
6320
-
6321
- },{}],15:[function(require,module,exports){
6322
- 'use strict';
6323
-
6324
- module.exports = function(Chart) {
6325
-
6326
- var helpers = Chart.helpers;
6327
-
6328
- Chart.defaults.bar = {
6329
- hover: {
6330
- mode: 'label'
6331
- },
6332
-
6333
- scales: {
6334
- xAxes: [{
6335
- type: 'category',
6336
-
6337
- // Specific to Bar Controller
6338
- categoryPercentage: 0.8,
6339
- barPercentage: 0.9,
6340
-
6341
- // grid line settings
6342
- gridLines: {
6343
- offsetGridLines: true
6344
- }
6345
- }],
6346
- yAxes: [{
6347
- type: 'linear'
6348
- }]
6349
- }
6350
- };
6351
-
6352
- Chart.controllers.bar = Chart.DatasetController.extend({
6353
-
6354
- dataElementType: Chart.elements.Rectangle,
6355
-
6356
- initialize: function() {
6357
- var me = this;
6358
- var meta;
6359
-
6360
- Chart.DatasetController.prototype.initialize.apply(me, arguments);
6361
-
6362
- meta = me.getMeta();
6363
- meta.stack = me.getDataset().stack;
6364
- meta.bar = true;
6365
- },
6366
-
6367
- update: function(reset) {
6368
- var me = this;
6369
- var elements = me.getMeta().data;
6370
- var i, ilen;
6371
-
6372
- me._ruler = me.getRuler();
6373
-
6374
- for (i = 0, ilen = elements.length; i < ilen; ++i) {
6375
- me.updateElement(elements[i], i, reset);
6376
- }
6377
- },
6378
-
6379
- updateElement: function(rectangle, index, reset) {
6380
- var me = this;
6381
- var chart = me.chart;
6382
- var meta = me.getMeta();
6383
- var dataset = me.getDataset();
6384
- var custom = rectangle.custom || {};
6385
- var rectangleOptions = chart.options.elements.rectangle;
6386
-
6387
- rectangle._xScale = me.getScaleForId(meta.xAxisID);
6388
- rectangle._yScale = me.getScaleForId(meta.yAxisID);
6389
- rectangle._datasetIndex = me.index;
6390
- rectangle._index = index;
6391
-
6392
- rectangle._model = {
6393
- datasetLabel: dataset.label,
6394
- label: chart.data.labels[index],
6395
- borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
6396
- backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
6397
- borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
6398
- borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
6399
- };
6400
-
6401
- me.updateElementGeometry(rectangle, index, reset);
6402
-
6403
- rectangle.pivot();
6404
- },
6405
-
6406
- /**
6407
- * @private
6408
- */
6409
- updateElementGeometry: function(rectangle, index, reset) {
6410
- var me = this;
6411
- var model = rectangle._model;
6412
- var vscale = me.getValueScale();
6413
- var base = vscale.getBasePixel();
6414
- var horizontal = vscale.isHorizontal();
6415
- var ruler = me._ruler || me.getRuler();
6416
- var vpixels = me.calculateBarValuePixels(me.index, index);
6417
- var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
6418
-
6419
- model.horizontal = horizontal;
6420
- model.base = reset? base : vpixels.base;
6421
- model.x = horizontal? reset? base : vpixels.head : ipixels.center;
6422
- model.y = horizontal? ipixels.center : reset? base : vpixels.head;
6423
- model.height = horizontal? ipixels.size : undefined;
6424
- model.width = horizontal? undefined : ipixels.size;
6425
- },
6426
-
6427
- /**
6428
- * @private
6429
- */
6430
- getValueScaleId: function() {
6431
- return this.getMeta().yAxisID;
6432
- },
6433
-
6434
- /**
6435
- * @private
6436
- */
6437
- getIndexScaleId: function() {
6438
- return this.getMeta().xAxisID;
6439
- },
6440
-
6441
- /**
6442
- * @private
6443
- */
6444
- getValueScale: function() {
6445
- return this.getScaleForId(this.getValueScaleId());
6446
- },
6447
-
6448
- /**
6449
- * @private
6450
- */
6451
- getIndexScale: function() {
6452
- return this.getScaleForId(this.getIndexScaleId());
6453
- },
6454
-
6455
- /**
6456
- * Returns the effective number of stacks based on groups and bar visibility.
6457
- * @private
6458
- */
6459
- getStackCount: function(last) {
6460
- var me = this;
6461
- var chart = me.chart;
6462
- var scale = me.getIndexScale();
6463
- var stacked = scale.options.stacked;
6464
- var ilen = last === undefined? chart.data.datasets.length : last + 1;
6465
- var stacks = [];
6466
- var i, meta;
6467
-
6468
- for (i = 0; i < ilen; ++i) {
6469
- meta = chart.getDatasetMeta(i);
6470
- if (meta.bar && chart.isDatasetVisible(i) &&
6471
- (stacked === false ||
6472
- (stacked === true && stacks.indexOf(meta.stack) === -1) ||
6473
- (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
6474
- stacks.push(meta.stack);
6475
- }
6476
- }
6477
-
6478
- return stacks.length;
6479
- },
6480
-
6481
- /**
6482
- * Returns the stack index for the given dataset based on groups and bar visibility.
6483
- * @private
6484
- */
6485
- getStackIndex: function(datasetIndex) {
6486
- return this.getStackCount(datasetIndex) - 1;
6487
- },
6488
-
6489
- /**
6490
- * @private
6491
- */
6492
- getRuler: function() {
6493
- var me = this;
6494
- var scale = me.getIndexScale();
6495
- var options = scale.options;
6496
- var stackCount = me.getStackCount();
6497
- var fullSize = scale.isHorizontal()? scale.width : scale.height;
6498
- var tickSize = fullSize / scale.ticks.length;
6499
- var categorySize = tickSize * options.categoryPercentage;
6500
- var fullBarSize = categorySize / stackCount;
6501
- var barSize = fullBarSize * options.barPercentage;
6502
-
6503
- barSize = Math.min(
6504
- helpers.getValueOrDefault(options.barThickness, barSize),
6505
- helpers.getValueOrDefault(options.maxBarThickness, Infinity));
6506
-
6507
- return {
6508
- stackCount: stackCount,
6509
- tickSize: tickSize,
6510
- categorySize: categorySize,
6511
- categorySpacing: tickSize - categorySize,
6512
- fullBarSize: fullBarSize,
6513
- barSize: barSize,
6514
- barSpacing: fullBarSize - barSize,
6515
- scale: scale
6516
- };
6517
- },
6518
-
6519
- /**
6520
- * Note: pixel values are not clamped to the scale area.
6521
- * @private
6522
- */
6523
- calculateBarValuePixels: function(datasetIndex, index) {
6524
- var me = this;
6525
- var chart = me.chart;
6526
- var meta = me.getMeta();
6527
- var scale = me.getValueScale();
6528
- var datasets = chart.data.datasets;
6529
- var value = Number(datasets[datasetIndex].data[index]);
6530
- var stacked = scale.options.stacked;
6531
- var stack = meta.stack;
6532
- var start = 0;
6533
- var i, imeta, ivalue, base, head, size;
6534
-
6535
- if (stacked || (stacked === undefined && stack !== undefined)) {
6536
- for (i = 0; i < datasetIndex; ++i) {
6537
- imeta = chart.getDatasetMeta(i);
6538
-
6539
- if (imeta.bar &&
6540
- imeta.stack === stack &&
6541
- imeta.controller.getValueScaleId() === scale.id &&
6542
- chart.isDatasetVisible(i)) {
6543
-
6544
- ivalue = Number(datasets[i].data[index]);
6545
- if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
6546
- start += ivalue;
6547
- }
6548
- }
6549
- }
6550
- }
6551
-
6552
- base = scale.getPixelForValue(start);
6553
- head = scale.getPixelForValue(start + value);
6554
- size = (head - base) / 2;
6555
-
6556
- return {
6557
- size: size,
6558
- base: base,
6559
- head: head,
6560
- center: head + size / 2
6561
- };
6562
- },
6563
-
6564
- /**
6565
- * @private
6566
- */
6567
- calculateBarIndexPixels: function(datasetIndex, index, ruler) {
6568
- var me = this;
6569
- var scale = ruler.scale;
6570
- var isCombo = me.chart.isCombo;
6571
- var stackIndex = me.getStackIndex(datasetIndex);
6572
- var base = scale.getPixelForValue(null, index, datasetIndex, isCombo);
6573
- var size = ruler.barSize;
6574
-
6575
- base -= isCombo? ruler.tickSize / 2 : 0;
6576
- base += ruler.fullBarSize * stackIndex;
6577
- base += ruler.categorySpacing / 2;
6578
- base += ruler.barSpacing / 2;
6579
-
6580
- return {
6581
- size: size,
6582
- base: base,
6583
- head: base + size,
6584
- center: base + size / 2
6585
- };
6586
- },
6587
-
6588
- draw: function() {
6589
- var me = this;
6590
- var chart = me.chart;
6591
- var elements = me.getMeta().data;
6592
- var dataset = me.getDataset();
6593
- var ilen = elements.length;
6594
- var i = 0;
6595
- var d;
6596
-
6597
- helpers.canvas.clipArea(chart.ctx, chart.chartArea);
6598
-
6599
- for (; i<ilen; ++i) {
6600
- d = dataset.data[i];
6601
- if (d !== null && d !== undefined && !isNaN(d)) {
6602
- elements[i].draw();
6603
- }
6604
- }
6605
-
6606
- helpers.canvas.unclipArea(chart.ctx);
6607
- },
6608
-
6609
- setHoverStyle: function(rectangle) {
6610
- var dataset = this.chart.data.datasets[rectangle._datasetIndex];
6611
- var index = rectangle._index;
6612
- var custom = rectangle.custom || {};
6613
- var model = rectangle._model;
6614
-
6615
- model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
6616
- model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor));
6617
- model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
6618
- },
6619
-
6620
- removeHoverStyle: function(rectangle) {
6621
- var dataset = this.chart.data.datasets[rectangle._datasetIndex];
6622
- var index = rectangle._index;
6623
- var custom = rectangle.custom || {};
6624
- var model = rectangle._model;
6625
- var rectangleElementOptions = this.chart.options.elements.rectangle;
6626
-
6627
- model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor);
6628
- model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor);
6629
- model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth);
6630
- }
6631
- });
6632
-
6633
-
6634
- // including horizontalBar in the bar file, instead of a file of its own
6635
- // it extends bar (like pie extends doughnut)
6636
- Chart.defaults.horizontalBar = {
6637
- hover: {
6638
- mode: 'label'
6639
- },
6640
-
6641
- scales: {
6642
- xAxes: [{
6643
- type: 'linear',
6644
- position: 'bottom'
6645
- }],
6646
- yAxes: [{
6647
- position: 'left',
6648
- type: 'category',
6649
-
6650
- // Specific to Horizontal Bar Controller
6651
- categoryPercentage: 0.8,
6652
- barPercentage: 0.9,
6653
-
6654
- // grid line settings
6655
- gridLines: {
6656
- offsetGridLines: true
6657
- }
6658
- }]
6659
- },
6660
- elements: {
6661
- rectangle: {
6662
- borderSkipped: 'left'
6663
- }
6664
- },
6665
- tooltips: {
6666
- callbacks: {
6667
- title: function(tooltipItems, data) {
6668
- // Pick first xLabel for now
6669
- var title = '';
6670
-
6671
- if (tooltipItems.length > 0) {
6672
- if (tooltipItems[0].yLabel) {
6673
- title = tooltipItems[0].yLabel;
6674
- } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) {
6675
- title = data.labels[tooltipItems[0].index];
6676
- }
6677
- }
6678
-
6679
- return title;
6680
- },
6681
- label: function(tooltipItem, data) {
6682
- var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
6683
- return datasetLabel + ': ' + tooltipItem.xLabel;
6684
- }
6685
- }
6686
- }
6687
- };
6688
-
6689
- Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
6690
- /**
6691
- * @private
6692
- */
6693
- getValueScaleId: function() {
6694
- return this.getMeta().xAxisID;
6695
- },
6696
-
6697
- /**
6698
- * @private
6699
- */
6700
- getIndexScaleId: function() {
6701
- return this.getMeta().yAxisID;
6702
- }
6703
- });
6704
- };
6705
-
6706
- },{}],16:[function(require,module,exports){
6707
- 'use strict';
6708
-
6709
- module.exports = function(Chart) {
6710
-
6711
- var helpers = Chart.helpers;
6712
-
6713
- Chart.defaults.bubble = {
6714
- hover: {
6715
- mode: 'single'
6716
- },
6717
-
6718
- scales: {
6719
- xAxes: [{
6720
- type: 'linear', // bubble should probably use a linear scale by default
6721
- position: 'bottom',
6722
- id: 'x-axis-0' // need an ID so datasets can reference the scale
6723
- }],
6724
- yAxes: [{
6725
- type: 'linear',
6726
- position: 'left',
6727
- id: 'y-axis-0'
6728
- }]
6729
- },
6730
-
6731
- tooltips: {
6732
- callbacks: {
6733
- title: function() {
6734
- // Title doesn't make sense for scatter since we format the data as a point
6735
- return '';
6736
- },
6737
- label: function(tooltipItem, data) {
6738
- var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
6739
- var dataPoint = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
6740
- return datasetLabel + ': (' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ', ' + dataPoint.r + ')';
6741
- }
6742
- }
6743
- }
6744
- };
6745
-
6746
- Chart.controllers.bubble = Chart.DatasetController.extend({
6747
-
6748
- dataElementType: Chart.elements.Point,
6749
-
6750
- update: function(reset) {
6751
- var me = this;
6752
- var meta = me.getMeta();
6753
- var points = meta.data;
6754
-
6755
- // Update Points
6756
- helpers.each(points, function(point, index) {
6757
- me.updateElement(point, index, reset);
6758
- });
6759
- },
6760
-
6761
- updateElement: function(point, index, reset) {
6762
- var me = this;
6763
- var meta = me.getMeta();
6764
- var xScale = me.getScaleForId(meta.xAxisID);
6765
- var yScale = me.getScaleForId(meta.yAxisID);
6766
-
6767
- var custom = point.custom || {};
6768
- var dataset = me.getDataset();
6769
- var data = dataset.data[index];
6770
- var pointElementOptions = me.chart.options.elements.point;
6771
- var dsIndex = me.index;
6772
-
6773
- helpers.extend(point, {
6774
- // Utility
6775
- _xScale: xScale,
6776
- _yScale: yScale,
6777
- _datasetIndex: dsIndex,
6778
- _index: index,
6779
-
6780
- // Desired view properties
6781
- _model: {
6782
- x: reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex, me.chart.isCombo),
6783
- y: reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex),
6784
- // Appearance
6785
- radius: reset ? 0 : custom.radius ? custom.radius : me.getRadius(data),
6786
-
6787
- // Tooltip
6788
- hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius)
6789
- }
6790
- });
6791
-
6792
- // Trick to reset the styles of the point
6793
- Chart.DatasetController.prototype.removeHoverStyle.call(me, point, pointElementOptions);
6794
-
6795
- var model = point._model;
6796
- model.skip = custom.skip ? custom.skip : (isNaN(model.x) || isNaN(model.y));
6797
-
6798
- point.pivot();
6799
- },
6800
-
6801
- getRadius: function(value) {
6802
- return value.r || this.chart.options.elements.point.radius;
6803
- },
6804
-
6805
- setHoverStyle: function(point) {
6806
- var me = this;
6807
- Chart.DatasetController.prototype.setHoverStyle.call(me, point);
6808
-
6809
- // Radius
6810
- var dataset = me.chart.data.datasets[point._datasetIndex];
6811
- var index = point._index;
6812
- var custom = point.custom || {};
6813
- var model = point._model;
6814
- model.radius = custom.hoverRadius ? custom.hoverRadius : (helpers.getValueAtIndexOrDefault(dataset.hoverRadius, index, me.chart.options.elements.point.hoverRadius)) + me.getRadius(dataset.data[index]);
6815
- },
6816
-
6817
- removeHoverStyle: function(point) {
6818
- var me = this;
6819
- Chart.DatasetController.prototype.removeHoverStyle.call(me, point, me.chart.options.elements.point);
6820
-
6821
- var dataVal = me.chart.data.datasets[point._datasetIndex].data[point._index];
6822
- var custom = point.custom || {};
6823
- var model = point._model;
6824
-
6825
- model.radius = custom.radius ? custom.radius : me.getRadius(dataVal);
6826
- }
6827
- });
6828
- };
6829
-
6830
- },{}],17:[function(require,module,exports){
6831
- 'use strict';
6832
-
6833
- module.exports = function(Chart) {
6834
-
6835
- var helpers = Chart.helpers,
6836
- defaults = Chart.defaults;
6837
-
6838
- defaults.doughnut = {
6839
- animation: {
6840
- // Boolean - Whether we animate the rotation of the Doughnut
6841
- animateRotate: true,
6842
- // Boolean - Whether we animate scaling the Doughnut from the centre
6843
- animateScale: false
6844
- },
6845
- aspectRatio: 1,
6846
- hover: {
6847
- mode: 'single'
6848
- },
6849
- legendCallback: function(chart) {
6850
- var text = [];
6851
- text.push('<ul class="' + chart.id + '-legend">');
6852
-
6853
- var data = chart.data;
6854
- var datasets = data.datasets;
6855
- var labels = data.labels;
6856
-
6857
- if (datasets.length) {
6858
- for (var i = 0; i < datasets[0].data.length; ++i) {
6859
- text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
6860
- if (labels[i]) {
6861
- text.push(labels[i]);
6862
- }
6863
- text.push('</li>');
6864
- }
6865
- }
6866
-
6867
- text.push('</ul>');
6868
- return text.join('');
6869
- },
6870
- legend: {
6871
- labels: {
6872
- generateLabels: function(chart) {
6873
- var data = chart.data;
6874
- if (data.labels.length && data.datasets.length) {
6875
- return data.labels.map(function(label, i) {
6876
- var meta = chart.getDatasetMeta(0);
6877
- var ds = data.datasets[0];
6878
- var arc = meta.data[i];
6879
- var custom = arc && arc.custom || {};
6880
- var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
6881
- var arcOpts = chart.options.elements.arc;
6882
- var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
6883
- var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
6884
- var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
6885
-
6886
- return {
6887
- text: label,
6888
- fillStyle: fill,
6889
- strokeStyle: stroke,
6890
- lineWidth: bw,
6891
- hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
6892
-
6893
- // Extra data used for toggling the correct item
6894
- index: i
6895
- };
6896
- });
6897
- }
6898
- return [];
6899
- }
6900
- },
6901
-
6902
- onClick: function(e, legendItem) {
6903
- var index = legendItem.index;
6904
- var chart = this.chart;
6905
- var i, ilen, meta;
6906
-
6907
- for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
6908
- meta = chart.getDatasetMeta(i);
6909
- // toggle visibility of index if exists
6910
- if (meta.data[index]) {
6911
- meta.data[index].hidden = !meta.data[index].hidden;
6912
- }
6913
- }
6914
-
6915
- chart.update();
6916
- }
6917
- },
6918
-
6919
- // The percentage of the chart that we cut out of the middle.
6920
- cutoutPercentage: 50,
6921
-
6922
- // The rotation of the chart, where the first data arc begins.
6923
- rotation: Math.PI * -0.5,
6924
-
6925
- // The total circumference of the chart.
6926
- circumference: Math.PI * 2.0,
6927
-
6928
- // Need to override these to give a nice default
6929
- tooltips: {
6930
- callbacks: {
6931
- title: function() {
6932
- return '';
6933
- },
6934
- label: function(tooltipItem, data) {
6935
- var dataLabel = data.labels[tooltipItem.index];
6936
- var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
6937
-
6938
- if (helpers.isArray(dataLabel)) {
6939
- // show value on first line of multiline label
6940
- // need to clone because we are changing the value
6941
- dataLabel = dataLabel.slice();
6942
- dataLabel[0] += value;
6943
- } else {
6944
- dataLabel += value;
6945
- }
6946
-
6947
- return dataLabel;
6948
- }
6949
- }
6950
- }
6951
- };
6952
-
6953
- defaults.pie = helpers.clone(defaults.doughnut);
6954
- helpers.extend(defaults.pie, {
6955
- cutoutPercentage: 0
6956
- });
6957
-
6958
-
6959
- Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
6960
-
6961
- dataElementType: Chart.elements.Arc,
6962
-
6963
- linkScales: helpers.noop,
6964
-
6965
- // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
6966
- getRingIndex: function(datasetIndex) {
6967
- var ringIndex = 0;
6968
-
6969
- for (var j = 0; j < datasetIndex; ++j) {
6970
- if (this.chart.isDatasetVisible(j)) {
6971
- ++ringIndex;
6972
- }
6973
- }
6974
-
6975
- return ringIndex;
6976
- },
6977
-
6978
- update: function(reset) {
6979
- var me = this;
6980
- var chart = me.chart,
6981
- chartArea = chart.chartArea,
6982
- opts = chart.options,
6983
- arcOpts = opts.elements.arc,
6984
- availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth,
6985
- availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth,
6986
- minSize = Math.min(availableWidth, availableHeight),
6987
- offset = {
6988
- x: 0,
6989
- y: 0
6990
- },
6991
- meta = me.getMeta(),
6992
- cutoutPercentage = opts.cutoutPercentage,
6993
- circumference = opts.circumference;
6994
-
6995
- // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
6996
- if (circumference < Math.PI * 2.0) {
6997
- var startAngle = opts.rotation % (Math.PI * 2.0);
6998
- startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
6999
- var endAngle = startAngle + circumference;
7000
- var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
7001
- var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
7002
- var contains0 = (startAngle <= 0 && 0 <= endAngle) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
7003
- var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
7004
- var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
7005
- var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
7006
- var cutout = cutoutPercentage / 100.0;
7007
- 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))};
7008
- 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))};
7009
- var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
7010
- minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
7011
- offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
7012
- }
7013
-
7014
- chart.borderWidth = me.getMaxBorderWidth(meta.data);
7015
- chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
7016
- chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
7017
- chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
7018
- chart.offsetX = offset.x * chart.outerRadius;
7019
- chart.offsetY = offset.y * chart.outerRadius;
7020
-
7021
- meta.total = me.calculateTotal();
7022
-
7023
- me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
7024
- me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);
7025
-
7026
- helpers.each(meta.data, function(arc, index) {
7027
- me.updateElement(arc, index, reset);
7028
- });
7029
- },
7030
-
7031
- updateElement: function(arc, index, reset) {
7032
- var me = this;
7033
- var chart = me.chart,
7034
- chartArea = chart.chartArea,
7035
- opts = chart.options,
7036
- animationOpts = opts.animation,
7037
- centerX = (chartArea.left + chartArea.right) / 2,
7038
- centerY = (chartArea.top + chartArea.bottom) / 2,
7039
- startAngle = opts.rotation, // non reset case handled later
7040
- endAngle = opts.rotation, // non reset case handled later
7041
- dataset = me.getDataset(),
7042
- circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)),
7043
- innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius,
7044
- outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius,
7045
- valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
7046
-
7047
- helpers.extend(arc, {
7048
- // Utility
7049
- _datasetIndex: me.index,
7050
- _index: index,
7051
-
7052
- // Desired view properties
7053
- _model: {
7054
- x: centerX + chart.offsetX,
7055
- y: centerY + chart.offsetY,
7056
- startAngle: startAngle,
7057
- endAngle: endAngle,
7058
- circumference: circumference,
7059
- outerRadius: outerRadius,
7060
- innerRadius: innerRadius,
7061
- label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
7062
- }
7063
- });
7064
-
7065
- var model = arc._model;
7066
- // Resets the visual styles
7067
- this.removeHoverStyle(arc);
7068
-
7069
- // Set correct angles if not resetting
7070
- if (!reset || !animationOpts.animateRotate) {
7071
- if (index === 0) {
7072
- model.startAngle = opts.rotation;
7073
- } else {
7074
- model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
7075
- }
7076
-
7077
- model.endAngle = model.startAngle + model.circumference;
7078
- }
7079
-
7080
- arc.pivot();
7081
- },
7082
-
7083
- removeHoverStyle: function(arc) {
7084
- Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
7085
- },
7086
-
7087
- calculateTotal: function() {
7088
- var dataset = this.getDataset();
7089
- var meta = this.getMeta();
7090
- var total = 0;
7091
- var value;
7092
-
7093
- helpers.each(meta.data, function(element, index) {
7094
- value = dataset.data[index];
7095
- if (!isNaN(value) && !element.hidden) {
7096
- total += Math.abs(value);
7097
- }
7098
- });
7099
-
7100
- /* if (total === 0) {
7101
- total = NaN;
7102
- }*/
7103
-
7104
- return total;
7105
- },
7106
-
7107
- calculateCircumference: function(value) {
7108
- var total = this.getMeta().total;
7109
- if (total > 0 && !isNaN(value)) {
7110
- return (Math.PI * 2.0) * (value / total);
7111
- }
7112
- return 0;
7113
- },
7114
-
7115
- // gets the max border or hover width to properly scale pie charts
7116
- getMaxBorderWidth: function(elements) {
7117
- var max = 0,
7118
- index = this.index,
7119
- length = elements.length,
7120
- borderWidth,
7121
- hoverWidth;
7122
-
7123
- for (var i = 0; i < length; i++) {
7124
- borderWidth = elements[i]._model ? elements[i]._model.borderWidth : 0;
7125
- hoverWidth = elements[i]._chart ? elements[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;
7126
-
7127
- max = borderWidth > max ? borderWidth : max;
7128
- max = hoverWidth > max ? hoverWidth : max;
7129
- }
7130
- return max;
7131
- }
7132
- });
7133
- };
7134
-
7135
- },{}],18:[function(require,module,exports){
7136
- 'use strict';
7137
-
7138
- module.exports = function(Chart) {
7139
-
7140
- var helpers = Chart.helpers;
7141
-
7142
- Chart.defaults.line = {
7143
- showLines: true,
7144
- spanGaps: false,
7145
-
7146
- hover: {
7147
- mode: 'label'
7148
- },
7149
-
7150
- scales: {
7151
- xAxes: [{
7152
- type: 'category',
7153
- id: 'x-axis-0'
7154
- }],
7155
- yAxes: [{
7156
- type: 'linear',
7157
- id: 'y-axis-0'
7158
- }]
7159
- }
7160
- };
7161
-
7162
- function lineEnabled(dataset, options) {
7163
- return helpers.getValueOrDefault(dataset.showLine, options.showLines);
7164
- }
7165
-
7166
- Chart.controllers.line = Chart.DatasetController.extend({
7167
-
7168
- datasetElementType: Chart.elements.Line,
7169
-
7170
- dataElementType: Chart.elements.Point,
7171
-
7172
- update: function(reset) {
7173
- var me = this;
7174
- var meta = me.getMeta();
7175
- var line = meta.dataset;
7176
- var points = meta.data || [];
7177
- var options = me.chart.options;
7178
- var lineElementOptions = options.elements.line;
7179
- var scale = me.getScaleForId(meta.yAxisID);
7180
- var i, ilen, custom;
7181
- var dataset = me.getDataset();
7182
- var showLine = lineEnabled(dataset, options);
7183
-
7184
- // Update Line
7185
- if (showLine) {
7186
- custom = line.custom || {};
7187
-
7188
- // Compatibility: If the properties are defined with only the old name, use those values
7189
- if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
7190
- dataset.lineTension = dataset.tension;
7191
- }
7192
-
7193
- // Utility
7194
- line._scale = scale;
7195
- line._datasetIndex = me.index;
7196
- // Data
7197
- line._children = points;
7198
- // Model
7199
- line._model = {
7200
- // Appearance
7201
- // The default behavior of lines is to break at null values, according
7202
- // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
7203
- // This option gives lines the ability to span gaps
7204
- spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps,
7205
- tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension),
7206
- backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
7207
- borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
7208
- borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
7209
- borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
7210
- borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
7211
- borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
7212
- borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
7213
- fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
7214
- steppedLine: custom.steppedLine ? custom.steppedLine : helpers.getValueOrDefault(dataset.steppedLine, lineElementOptions.stepped),
7215
- cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.getValueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode),
7216
- };
7217
-
7218
- line.pivot();
7219
- }
7220
-
7221
- // Update Points
7222
- for (i=0, ilen=points.length; i<ilen; ++i) {
7223
- me.updateElement(points[i], i, reset);
7224
- }
7225
-
7226
- if (showLine && line._model.tension !== 0) {
7227
- me.updateBezierControlPoints();
7228
- }
7229
-
7230
- // Now pivot the point for animation
7231
- for (i=0, ilen=points.length; i<ilen; ++i) {
7232
- points[i].pivot();
7233
- }
7234
- },
7235
-
7236
- getPointBackgroundColor: function(point, index) {
7237
- var backgroundColor = this.chart.options.elements.point.backgroundColor;
7238
- var dataset = this.getDataset();
7239
- var custom = point.custom || {};
7240
-
7241
- if (custom.backgroundColor) {
7242
- backgroundColor = custom.backgroundColor;
7243
- } else if (dataset.pointBackgroundColor) {
7244
- backgroundColor = helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
7245
- } else if (dataset.backgroundColor) {
7246
- backgroundColor = dataset.backgroundColor;
7247
- }
7248
-
7249
- return backgroundColor;
7250
- },
7251
-
7252
- getPointBorderColor: function(point, index) {
7253
- var borderColor = this.chart.options.elements.point.borderColor;
7254
- var dataset = this.getDataset();
7255
- var custom = point.custom || {};
7256
-
7257
- if (custom.borderColor) {
7258
- borderColor = custom.borderColor;
7259
- } else if (dataset.pointBorderColor) {
7260
- borderColor = helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
7261
- } else if (dataset.borderColor) {
7262
- borderColor = dataset.borderColor;
7263
- }
7264
-
7265
- return borderColor;
7266
- },
7267
-
7268
- getPointBorderWidth: function(point, index) {
7269
- var borderWidth = this.chart.options.elements.point.borderWidth;
7270
- var dataset = this.getDataset();
7271
- var custom = point.custom || {};
7272
-
7273
- if (!isNaN(custom.borderWidth)) {
7274
- borderWidth = custom.borderWidth;
7275
- } else if (!isNaN(dataset.pointBorderWidth)) {
7276
- borderWidth = helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
7277
- } else if (!isNaN(dataset.borderWidth)) {
7278
- borderWidth = dataset.borderWidth;
7279
- }
7280
-
7281
- return borderWidth;
7282
- },
7283
-
7284
- updateElement: function(point, index, reset) {
7285
- var me = this;
7286
- var meta = me.getMeta();
7287
- var custom = point.custom || {};
7288
- var dataset = me.getDataset();
7289
- var datasetIndex = me.index;
7290
- var value = dataset.data[index];
7291
- var yScale = me.getScaleForId(meta.yAxisID);
7292
- var xScale = me.getScaleForId(meta.xAxisID);
7293
- var pointOptions = me.chart.options.elements.point;
7294
- var x, y;
7295
- var labels = me.chart.data.labels || [];
7296
- var includeOffset = (labels.length === 1 || dataset.data.length === 1) || me.chart.isCombo;
7297
-
7298
- // Compatibility: If the properties are defined with only the old name, use those values
7299
- if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
7300
- dataset.pointRadius = dataset.radius;
7301
- }
7302
- if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
7303
- dataset.pointHitRadius = dataset.hitRadius;
7304
- }
7305
-
7306
- x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex, includeOffset);
7307
- y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
7308
-
7309
- // Utility
7310
- point._xScale = xScale;
7311
- point._yScale = yScale;
7312
- point._datasetIndex = datasetIndex;
7313
- point._index = index;
7314
-
7315
- // Desired view properties
7316
- point._model = {
7317
- x: x,
7318
- y: y,
7319
- skip: custom.skip || isNaN(x) || isNaN(y),
7320
- // Appearance
7321
- radius: custom.radius || helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
7322
- pointStyle: custom.pointStyle || helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
7323
- backgroundColor: me.getPointBackgroundColor(point, index),
7324
- borderColor: me.getPointBorderColor(point, index),
7325
- borderWidth: me.getPointBorderWidth(point, index),
7326
- tension: meta.dataset._model ? meta.dataset._model.tension : 0,
7327
- steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false,
7328
- // Tooltip
7329
- hitRadius: custom.hitRadius || helpers.getValueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
7330
- };
7331
- },
7332
-
7333
- calculatePointY: function(value, index, datasetIndex) {
7334
- var me = this;
7335
- var chart = me.chart;
7336
- var meta = me.getMeta();
7337
- var yScale = me.getScaleForId(meta.yAxisID);
7338
- var sumPos = 0;
7339
- var sumNeg = 0;
7340
- var i, ds, dsMeta;
7341
-
7342
- if (yScale.options.stacked) {
7343
- for (i = 0; i < datasetIndex; i++) {
7344
- ds = chart.data.datasets[i];
7345
- dsMeta = chart.getDatasetMeta(i);
7346
- if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
7347
- var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
7348
- if (stackedRightValue < 0) {
7349
- sumNeg += stackedRightValue || 0;
7350
- } else {
7351
- sumPos += stackedRightValue || 0;
7352
- }
7353
- }
7354
- }
7355
-
7356
- var rightValue = Number(yScale.getRightValue(value));
7357
- if (rightValue < 0) {
7358
- return yScale.getPixelForValue(sumNeg + rightValue);
7359
- }
7360
- return yScale.getPixelForValue(sumPos + rightValue);
7361
- }
7362
-
7363
- return yScale.getPixelForValue(value);
7364
- },
7365
-
7366
- updateBezierControlPoints: function() {
7367
- var me = this;
7368
- var meta = me.getMeta();
7369
- var area = me.chart.chartArea;
7370
- var points = (meta.data || []);
7371
- var i, ilen, point, model, controlPoints;
7372
-
7373
- // Only consider points that are drawn in case the spanGaps option is used
7374
- if (meta.dataset._model.spanGaps) {
7375
- points = points.filter(function(pt) {
7376
- return !pt._model.skip;
7377
- });
7378
- }
7379
-
7380
- function capControlPoint(pt, min, max) {
7381
- return Math.max(Math.min(pt, max), min);
7382
- }
7383
-
7384
- if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
7385
- helpers.splineCurveMonotone(points);
7386
- } else {
7387
- for (i = 0, ilen = points.length; i < ilen; ++i) {
7388
- point = points[i];
7389
- model = point._model;
7390
- controlPoints = helpers.splineCurve(
7391
- helpers.previousItem(points, i)._model,
7392
- model,
7393
- helpers.nextItem(points, i)._model,
7394
- meta.dataset._model.tension
7395
- );
7396
- model.controlPointPreviousX = controlPoints.previous.x;
7397
- model.controlPointPreviousY = controlPoints.previous.y;
7398
- model.controlPointNextX = controlPoints.next.x;
7399
- model.controlPointNextY = controlPoints.next.y;
7400
- }
7401
- }
7402
-
7403
- if (me.chart.options.elements.line.capBezierPoints) {
7404
- for (i = 0, ilen = points.length; i < ilen; ++i) {
7405
- model = points[i]._model;
7406
- model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
7407
- model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
7408
- model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
7409
- model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
7410
- }
7411
- }
7412
- },
7413
-
7414
- draw: function() {
7415
- var me = this;
7416
- var chart = me.chart;
7417
- var meta = me.getMeta();
7418
- var points = meta.data || [];
7419
- var area = chart.chartArea;
7420
- var ilen = points.length;
7421
- var i = 0;
7422
-
7423
- Chart.canvasHelpers.clipArea(chart.ctx, area);
7424
-
7425
- if (lineEnabled(me.getDataset(), chart.options)) {
7426
- meta.dataset.draw();
7427
- }
7428
-
7429
- Chart.canvasHelpers.unclipArea(chart.ctx);
7430
-
7431
- // Draw the points
7432
- for (; i<ilen; ++i) {
7433
- points[i].draw(area);
7434
- }
7435
- },
7436
-
7437
- setHoverStyle: function(point) {
7438
- // Point
7439
- var dataset = this.chart.data.datasets[point._datasetIndex];
7440
- var index = point._index;
7441
- var custom = point.custom || {};
7442
- var model = point._model;
7443
-
7444
- model.radius = custom.hoverRadius || helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
7445
- model.backgroundColor = custom.hoverBackgroundColor || helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
7446
- model.borderColor = custom.hoverBorderColor || helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
7447
- model.borderWidth = custom.hoverBorderWidth || helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
7448
- },
7449
-
7450
- removeHoverStyle: function(point) {
7451
- var me = this;
7452
- var dataset = me.chart.data.datasets[point._datasetIndex];
7453
- var index = point._index;
7454
- var custom = point.custom || {};
7455
- var model = point._model;
7456
-
7457
- // Compatibility: If the properties are defined with only the old name, use those values
7458
- if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
7459
- dataset.pointRadius = dataset.radius;
7460
- }
7461
-
7462
- model.radius = custom.radius || helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius);
7463
- model.backgroundColor = me.getPointBackgroundColor(point, index);
7464
- model.borderColor = me.getPointBorderColor(point, index);
7465
- model.borderWidth = me.getPointBorderWidth(point, index);
7466
- }
7467
- });
7468
- };
7469
-
7470
- },{}],19:[function(require,module,exports){
7471
- 'use strict';
7472
-
7473
- module.exports = function(Chart) {
7474
-
7475
- var helpers = Chart.helpers;
7476
-
7477
- Chart.defaults.polarArea = {
7478
-
7479
- scale: {
7480
- type: 'radialLinear',
7481
- angleLines: {
7482
- display: false
7483
- },
7484
- gridLines: {
7485
- circular: true
7486
- },
7487
- pointLabels: {
7488
- display: false
7489
- },
7490
- ticks: {
7491
- beginAtZero: true
7492
- }
7493
- },
7494
-
7495
- // Boolean - Whether to animate the rotation of the chart
7496
- animation: {
7497
- animateRotate: true,
7498
- animateScale: true
7499
- },
7500
-
7501
- startAngle: -0.5 * Math.PI,
7502
- aspectRatio: 1,
7503
- legendCallback: function(chart) {
7504
- var text = [];
7505
- text.push('<ul class="' + chart.id + '-legend">');
7506
-
7507
- var data = chart.data;
7508
- var datasets = data.datasets;
7509
- var labels = data.labels;
7510
-
7511
- if (datasets.length) {
7512
- for (var i = 0; i < datasets[0].data.length; ++i) {
7513
- text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
7514
- if (labels[i]) {
7515
- text.push(labels[i]);
7516
- }
7517
- text.push('</li>');
7518
- }
7519
- }
7520
-
7521
- text.push('</ul>');
7522
- return text.join('');
7523
- },
7524
- legend: {
7525
- labels: {
7526
- generateLabels: function(chart) {
7527
- var data = chart.data;
7528
- if (data.labels.length && data.datasets.length) {
7529
- return data.labels.map(function(label, i) {
7530
- var meta = chart.getDatasetMeta(0);
7531
- var ds = data.datasets[0];
7532
- var arc = meta.data[i];
7533
- var custom = arc.custom || {};
7534
- var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
7535
- var arcOpts = chart.options.elements.arc;
7536
- var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
7537
- var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
7538
- var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
7539
-
7540
- return {
7541
- text: label,
7542
- fillStyle: fill,
7543
- strokeStyle: stroke,
7544
- lineWidth: bw,
7545
- hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
7546
-
7547
- // Extra data used for toggling the correct item
7548
- index: i
7549
- };
7550
- });
7551
- }
7552
- return [];
7553
- }
7554
- },
7555
-
7556
- onClick: function(e, legendItem) {
7557
- var index = legendItem.index;
7558
- var chart = this.chart;
7559
- var i, ilen, meta;
7560
-
7561
- for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
7562
- meta = chart.getDatasetMeta(i);
7563
- meta.data[index].hidden = !meta.data[index].hidden;
7564
- }
7565
-
7566
- chart.update();
7567
- }
7568
- },
7569
-
7570
- // Need to override these to give a nice default
7571
- tooltips: {
7572
- callbacks: {
7573
- title: function() {
7574
- return '';
7575
- },
7576
- label: function(tooltipItem, data) {
7577
- return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
7578
- }
7579
- }
7580
- }
7581
- };
7582
-
7583
- Chart.controllers.polarArea = Chart.DatasetController.extend({
7584
-
7585
- dataElementType: Chart.elements.Arc,
7586
-
7587
- linkScales: helpers.noop,
7588
-
7589
- update: function(reset) {
7590
- var me = this;
7591
- var chart = me.chart;
7592
- var chartArea = chart.chartArea;
7593
- var meta = me.getMeta();
7594
- var opts = chart.options;
7595
- var arcOpts = opts.elements.arc;
7596
- var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
7597
- chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
7598
- chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
7599
- chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
7600
-
7601
- me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
7602
- me.innerRadius = me.outerRadius - chart.radiusLength;
7603
-
7604
- meta.count = me.countVisibleElements();
7605
-
7606
- helpers.each(meta.data, function(arc, index) {
7607
- me.updateElement(arc, index, reset);
7608
- });
7609
- },
7610
-
7611
- updateElement: function(arc, index, reset) {
7612
- var me = this;
7613
- var chart = me.chart;
7614
- var dataset = me.getDataset();
7615
- var opts = chart.options;
7616
- var animationOpts = opts.animation;
7617
- var scale = chart.scale;
7618
- var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
7619
- var labels = chart.data.labels;
7620
-
7621
- var circumference = me.calculateCircumference(dataset.data[index]);
7622
- var centerX = scale.xCenter;
7623
- var centerY = scale.yCenter;
7624
-
7625
- // If there is NaN data before us, we need to calculate the starting angle correctly.
7626
- // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
7627
- var visibleCount = 0;
7628
- var meta = me.getMeta();
7629
- for (var i = 0; i < index; ++i) {
7630
- if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
7631
- ++visibleCount;
7632
- }
7633
- }
7634
-
7635
- // var negHalfPI = -0.5 * Math.PI;
7636
- var datasetStartAngle = opts.startAngle;
7637
- var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
7638
- var startAngle = datasetStartAngle + (circumference * visibleCount);
7639
- var endAngle = startAngle + (arc.hidden ? 0 : circumference);
7640
-
7641
- var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
7642
-
7643
- helpers.extend(arc, {
7644
- // Utility
7645
- _datasetIndex: me.index,
7646
- _index: index,
7647
- _scale: scale,
7648
-
7649
- // Desired view properties
7650
- _model: {
7651
- x: centerX,
7652
- y: centerY,
7653
- innerRadius: 0,
7654
- outerRadius: reset ? resetRadius : distance,
7655
- startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
7656
- endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
7657
- label: getValueAtIndexOrDefault(labels, index, labels[index])
7658
- }
7659
- });
7660
-
7661
- // Apply border and fill style
7662
- me.removeHoverStyle(arc);
7663
-
7664
- arc.pivot();
7665
- },
7666
-
7667
- removeHoverStyle: function(arc) {
7668
- Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
7669
- },
7670
-
7671
- countVisibleElements: function() {
7672
- var dataset = this.getDataset();
7673
- var meta = this.getMeta();
7674
- var count = 0;
7675
-
7676
- helpers.each(meta.data, function(element, index) {
7677
- if (!isNaN(dataset.data[index]) && !element.hidden) {
7678
- count++;
7679
- }
7680
- });
7681
-
7682
- return count;
7683
- },
7684
-
7685
- calculateCircumference: function(value) {
7686
- var count = this.getMeta().count;
7687
- if (count > 0 && !isNaN(value)) {
7688
- return (2 * Math.PI) / count;
7689
- }
7690
- return 0;
7691
- }
7692
- });
7693
- };
7694
-
7695
- },{}],20:[function(require,module,exports){
7696
- 'use strict';
7697
-
7698
- module.exports = function(Chart) {
7699
-
7700
- var helpers = Chart.helpers;
7701
-
7702
- Chart.defaults.radar = {
7703
- aspectRatio: 1,
7704
- scale: {
7705
- type: 'radialLinear'
7706
- },
7707
- elements: {
7708
- line: {
7709
- tension: 0 // no bezier in radar
7710
- }
7711
- }
7712
- };
7713
-
7714
- Chart.controllers.radar = Chart.DatasetController.extend({
7715
-
7716
- datasetElementType: Chart.elements.Line,
7717
-
7718
- dataElementType: Chart.elements.Point,
7719
-
7720
- linkScales: helpers.noop,
7721
-
7722
- update: function(reset) {
7723
- var me = this;
7724
- var meta = me.getMeta();
7725
- var line = meta.dataset;
7726
- var points = meta.data;
7727
- var custom = line.custom || {};
7728
- var dataset = me.getDataset();
7729
- var lineElementOptions = me.chart.options.elements.line;
7730
- var scale = me.chart.scale;
7731
-
7732
- // Compatibility: If the properties are defined with only the old name, use those values
7733
- if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
7734
- dataset.lineTension = dataset.tension;
7735
- }
7736
-
7737
- helpers.extend(meta.dataset, {
7738
- // Utility
7739
- _datasetIndex: me.index,
7740
- _scale: scale,
7741
- // Data
7742
- _children: points,
7743
- _loop: true,
7744
- // Model
7745
- _model: {
7746
- // Appearance
7747
- tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension),
7748
- backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
7749
- borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
7750
- borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
7751
- fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
7752
- borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
7753
- borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
7754
- borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
7755
- borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
7756
- }
7757
- });
7758
-
7759
- meta.dataset.pivot();
7760
-
7761
- // Update Points
7762
- helpers.each(points, function(point, index) {
7763
- me.updateElement(point, index, reset);
7764
- }, me);
7765
-
7766
- // Update bezier control points
7767
- me.updateBezierControlPoints();
7768
- },
7769
- updateElement: function(point, index, reset) {
7770
- var me = this;
7771
- var custom = point.custom || {};
7772
- var dataset = me.getDataset();
7773
- var scale = me.chart.scale;
7774
- var pointElementOptions = me.chart.options.elements.point;
7775
- var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
7776
-
7777
- // Compatibility: If the properties are defined with only the old name, use those values
7778
- if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
7779
- dataset.pointRadius = dataset.radius;
7780
- }
7781
- if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
7782
- dataset.pointHitRadius = dataset.hitRadius;
7783
- }
7784
-
7785
- helpers.extend(point, {
7786
- // Utility
7787
- _datasetIndex: me.index,
7788
- _index: index,
7789
- _scale: scale,
7790
-
7791
- // Desired view properties
7792
- _model: {
7793
- x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
7794
- y: reset ? scale.yCenter : pointPosition.y,
7795
-
7796
- // Appearance
7797
- tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
7798
- radius: custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
7799
- backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
7800
- borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
7801
- borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
7802
- pointStyle: custom.pointStyle ? custom.pointStyle : helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),
7803
-
7804
- // Tooltip
7805
- hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius)
7806
- }
7807
- });
7808
-
7809
- point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
7810
- },
7811
- updateBezierControlPoints: function() {
7812
- var chartArea = this.chart.chartArea;
7813
- var meta = this.getMeta();
7814
-
7815
- helpers.each(meta.data, function(point, index) {
7816
- var model = point._model;
7817
- var controlPoints = helpers.splineCurve(
7818
- helpers.previousItem(meta.data, index, true)._model,
7819
- model,
7820
- helpers.nextItem(meta.data, index, true)._model,
7821
- model.tension
7822
- );
7823
-
7824
- // Prevent the bezier going outside of the bounds of the graph
7825
- model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left);
7826
- model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top);
7827
-
7828
- model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left);
7829
- model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top);
7830
-
7831
- // Now pivot the point for animation
7832
- point.pivot();
7833
- });
7834
- },
7835
-
7836
- setHoverStyle: function(point) {
7837
- // Point
7838
- var dataset = this.chart.data.datasets[point._datasetIndex];
7839
- var custom = point.custom || {};
7840
- var index = point._index;
7841
- var model = point._model;
7842
-
7843
- model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
7844
- model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
7845
- model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
7846
- model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
7847
- },
7848
-
7849
- removeHoverStyle: function(point) {
7850
- var dataset = this.chart.data.datasets[point._datasetIndex];
7851
- var custom = point.custom || {};
7852
- var index = point._index;
7853
- var model = point._model;
7854
- var pointElementOptions = this.chart.options.elements.point;
7855
-
7856
- model.radius = custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius);
7857
- model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor);
7858
- model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor);
7859
- model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth);
7860
- }
7861
- });
7862
- };
7863
-
7864
- },{}],21:[function(require,module,exports){
7865
- /* global window: false */
7866
- 'use strict';
7867
-
7868
- module.exports = function(Chart) {
7869
-
7870
- var helpers = Chart.helpers;
7871
-
7872
- Chart.defaults.global.animation = {
7873
- duration: 1000,
7874
- easing: 'easeOutQuart',
7875
- onProgress: helpers.noop,
7876
- onComplete: helpers.noop
7877
- };
7878
-
7879
- Chart.Animation = Chart.Element.extend({
7880
- chart: null, // the animation associated chart instance
7881
- currentStep: 0, // the current animation step
7882
- numSteps: 60, // default number of steps
7883
- easing: '', // the easing to use for this animation
7884
- render: null, // render function used by the animation service
7885
-
7886
- onAnimationProgress: null, // user specified callback to fire on each step of the animation
7887
- onAnimationComplete: null, // user specified callback to fire when the animation finishes
7888
- });
7889
-
7890
- Chart.animationService = {
7891
- frameDuration: 17,
7892
- animations: [],
7893
- dropFrames: 0,
7894
- request: null,
7895
-
7896
- /**
7897
- * @param {Chart} chart - The chart to animate.
7898
- * @param {Chart.Animation} animation - The animation that we will animate.
7899
- * @param {Number} duration - The animation duration in ms.
7900
- * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
7901
- */
7902
- addAnimation: function(chart, animation, duration, lazy) {
7903
- var animations = this.animations;
7904
- var i, ilen;
7905
-
7906
- animation.chart = chart;
7907
-
7908
- if (!lazy) {
7909
- chart.animating = true;
7910
- }
7911
-
7912
- for (i=0, ilen=animations.length; i < ilen; ++i) {
7913
- if (animations[i].chart === chart) {
7914
- animations[i] = animation;
7915
- return;
7916
- }
7917
- }
7918
-
7919
- animations.push(animation);
7920
-
7921
- // If there are no animations queued, manually kickstart a digest, for lack of a better word
7922
- if (animations.length === 1) {
7923
- this.requestAnimationFrame();
7924
- }
7925
- },
7926
-
7927
- cancelAnimation: function(chart) {
7928
- var index = helpers.findIndex(this.animations, function(animation) {
7929
- return animation.chart === chart;
7930
- });
7931
-
7932
- if (index !== -1) {
7933
- this.animations.splice(index, 1);
7934
- chart.animating = false;
7935
- }
7936
- },
7937
-
7938
- requestAnimationFrame: function() {
7939
- var me = this;
7940
- if (me.request === null) {
7941
- // Skip animation frame requests until the active one is executed.
7942
- // This can happen when processing mouse events, e.g. 'mousemove'
7943
- // and 'mouseout' events will trigger multiple renders.
7944
- me.request = helpers.requestAnimFrame.call(window, function() {
7945
- me.request = null;
7946
- me.startDigest();
7947
- });
7948
- }
7949
- },
7950
-
7951
- /**
7952
- * @private
7953
- */
7954
- startDigest: function() {
7955
- var me = this;
7956
- var startTime = Date.now();
7957
- var framesToDrop = 0;
7958
-
7959
- if (me.dropFrames > 1) {
7960
- framesToDrop = Math.floor(me.dropFrames);
7961
- me.dropFrames = me.dropFrames % 1;
7962
- }
7963
-
7964
- me.advance(1 + framesToDrop);
7965
-
7966
- var endTime = Date.now();
7967
-
7968
- me.dropFrames += (endTime - startTime) / me.frameDuration;
7969
-
7970
- // Do we have more stuff to animate?
7971
- if (me.animations.length > 0) {
7972
- me.requestAnimationFrame();
7973
- }
7974
- },
7975
-
7976
- /**
7977
- * @private
7978
- */
7979
- advance: function(count) {
7980
- var animations = this.animations;
7981
- var animation, chart;
7982
- var i = 0;
7983
-
7984
- while (i < animations.length) {
7985
- animation = animations[i];
7986
- chart = animation.chart;
7987
-
7988
- animation.currentStep = (animation.currentStep || 0) + count;
7989
- animation.currentStep = Math.min(animation.currentStep, animation.numSteps);
7990
-
7991
- helpers.callback(animation.render, [chart, animation], chart);
7992
- helpers.callback(animation.onAnimationProgress, [animation], chart);
7993
-
7994
- if (animation.currentStep >= animation.numSteps) {
7995
- helpers.callback(animation.onAnimationComplete, [animation], chart);
7996
- chart.animating = false;
7997
- animations.splice(i, 1);
7998
- } else {
7999
- ++i;
8000
- }
8001
- }
8002
- }
8003
- };
8004
-
8005
- /**
8006
- * Provided for backward compatibility, use Chart.Animation instead
8007
- * @prop Chart.Animation#animationObject
8008
- * @deprecated since version 2.6.0
8009
- * @todo remove at version 3
8010
- */
8011
- Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
8012
- get: function() {
8013
- return this;
8014
- }
8015
- });
8016
-
8017
- /**
8018
- * Provided for backward compatibility, use Chart.Animation#chart instead
8019
- * @prop Chart.Animation#chartInstance
8020
- * @deprecated since version 2.6.0
8021
- * @todo remove at version 3
8022
- */
8023
- Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
8024
- get: function() {
8025
- return this.chart;
8026
- },
8027
- set: function(value) {
8028
- this.chart = value;
8029
- }
8030
- });
8031
-
8032
- };
8033
-
8034
- },{}],22:[function(require,module,exports){
8035
- 'use strict';
8036
-
8037
- module.exports = function(Chart) {
8038
- // Global Chart canvas helpers object for drawing items to canvas
8039
- var helpers = Chart.canvasHelpers = {};
8040
-
8041
- helpers.drawPoint = function(ctx, pointStyle, radius, x, y) {
8042
- var type, edgeLength, xOffset, yOffset, height, size;
8043
-
8044
- if (typeof pointStyle === 'object') {
8045
- type = pointStyle.toString();
8046
- if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
8047
- ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2, pointStyle.width, pointStyle.height);
8048
- return;
8049
- }
8050
- }
8051
-
8052
- if (isNaN(radius) || radius <= 0) {
8053
- return;
8054
- }
8055
-
8056
- switch (pointStyle) {
8057
- // Default includes circle
8058
- default:
8059
- ctx.beginPath();
8060
- ctx.arc(x, y, radius, 0, Math.PI * 2);
8061
- ctx.closePath();
8062
- ctx.fill();
8063
- break;
8064
- case 'triangle':
8065
- ctx.beginPath();
8066
- edgeLength = 3 * radius / Math.sqrt(3);
8067
- height = edgeLength * Math.sqrt(3) / 2;
8068
- ctx.moveTo(x - edgeLength / 2, y + height / 3);
8069
- ctx.lineTo(x + edgeLength / 2, y + height / 3);
8070
- ctx.lineTo(x, y - 2 * height / 3);
8071
- ctx.closePath();
8072
- ctx.fill();
8073
- break;
8074
- case 'rect':
8075
- size = 1 / Math.SQRT2 * radius;
8076
- ctx.beginPath();
8077
- ctx.fillRect(x - size, y - size, 2 * size, 2 * size);
8078
- ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
8079
- break;
8080
- case 'rectRounded':
8081
- var offset = radius / Math.SQRT2;
8082
- var leftX = x - offset;
8083
- var topY = y - offset;
8084
- var sideSize = Math.SQRT2 * radius;
8085
- Chart.helpers.drawRoundedRectangle(ctx, leftX, topY, sideSize, sideSize, radius / 2);
8086
- ctx.fill();
8087
- break;
8088
- case 'rectRot':
8089
- size = 1 / Math.SQRT2 * radius;
8090
- ctx.beginPath();
8091
- ctx.moveTo(x - size, y);
8092
- ctx.lineTo(x, y + size);
8093
- ctx.lineTo(x + size, y);
8094
- ctx.lineTo(x, y - size);
8095
- ctx.closePath();
8096
- ctx.fill();
8097
- break;
8098
- case 'cross':
8099
- ctx.beginPath();
8100
- ctx.moveTo(x, y + radius);
8101
- ctx.lineTo(x, y - radius);
8102
- ctx.moveTo(x - radius, y);
8103
- ctx.lineTo(x + radius, y);
8104
- ctx.closePath();
8105
- break;
8106
- case 'crossRot':
8107
- ctx.beginPath();
8108
- xOffset = Math.cos(Math.PI / 4) * radius;
8109
- yOffset = Math.sin(Math.PI / 4) * radius;
8110
- ctx.moveTo(x - xOffset, y - yOffset);
8111
- ctx.lineTo(x + xOffset, y + yOffset);
8112
- ctx.moveTo(x - xOffset, y + yOffset);
8113
- ctx.lineTo(x + xOffset, y - yOffset);
8114
- ctx.closePath();
8115
- break;
8116
- case 'star':
8117
- ctx.beginPath();
8118
- ctx.moveTo(x, y + radius);
8119
- ctx.lineTo(x, y - radius);
8120
- ctx.moveTo(x - radius, y);
8121
- ctx.lineTo(x + radius, y);
8122
- xOffset = Math.cos(Math.PI / 4) * radius;
8123
- yOffset = Math.sin(Math.PI / 4) * radius;
8124
- ctx.moveTo(x - xOffset, y - yOffset);
8125
- ctx.lineTo(x + xOffset, y + yOffset);
8126
- ctx.moveTo(x - xOffset, y + yOffset);
8127
- ctx.lineTo(x + xOffset, y - yOffset);
8128
- ctx.closePath();
8129
- break;
8130
- case 'line':
8131
- ctx.beginPath();
8132
- ctx.moveTo(x - radius, y);
8133
- ctx.lineTo(x + radius, y);
8134
- ctx.closePath();
8135
- break;
8136
- case 'dash':
8137
- ctx.beginPath();
8138
- ctx.moveTo(x, y);
8139
- ctx.lineTo(x + radius, y);
8140
- ctx.closePath();
8141
- break;
8142
- }
8143
-
8144
- ctx.stroke();
8145
- };
8146
-
8147
- helpers.clipArea = function(ctx, clipArea) {
8148
- ctx.save();
8149
- ctx.beginPath();
8150
- ctx.rect(clipArea.left, clipArea.top, clipArea.right - clipArea.left, clipArea.bottom - clipArea.top);
8151
- ctx.clip();
8152
- };
8153
-
8154
- helpers.unclipArea = function(ctx) {
8155
- ctx.restore();
8156
- };
8157
-
8158
- helpers.lineTo = function(ctx, previous, target, flip) {
8159
- if (target.steppedLine) {
8160
- if (target.steppedLine === 'after') {
8161
- ctx.lineTo(previous.x, target.y);
8162
- } else {
8163
- ctx.lineTo(target.x, previous.y);
8164
- }
8165
- ctx.lineTo(target.x, target.y);
8166
- return;
8167
- }
8168
-
8169
- if (!target.tension) {
8170
- ctx.lineTo(target.x, target.y);
8171
- return;
8172
- }
8173
-
8174
- ctx.bezierCurveTo(
8175
- flip? previous.controlPointPreviousX : previous.controlPointNextX,
8176
- flip? previous.controlPointPreviousY : previous.controlPointNextY,
8177
- flip? target.controlPointNextX : target.controlPointPreviousX,
8178
- flip? target.controlPointNextY : target.controlPointPreviousY,
8179
- target.x,
8180
- target.y);
8181
- };
8182
-
8183
- Chart.helpers.canvas = helpers;
8184
- };
8185
-
8186
- },{}],23:[function(require,module,exports){
8187
- 'use strict';
8188
-
8189
- module.exports = function(Chart) {
8190
-
8191
- var helpers = Chart.helpers;
8192
- var plugins = Chart.plugins;
8193
- var platform = Chart.platform;
8194
-
8195
- // Create a dictionary of chart types, to allow for extension of existing types
8196
- Chart.types = {};
8197
-
8198
- // Store a reference to each instance - allowing us to globally resize chart instances on window resize.
8199
- // Destroy method on the chart will remove the instance of the chart from this reference.
8200
- Chart.instances = {};
8201
-
8202
- // Controllers available for dataset visualization eg. bar, line, slice, etc.
8203
- Chart.controllers = {};
8204
-
8205
- /**
8206
- * Initializes the given config with global and chart default values.
8207
- */
8208
- function initConfig(config) {
8209
- config = config || {};
8210
-
8211
- // Do NOT use configMerge() for the data object because this method merges arrays
8212
- // and so would change references to labels and datasets, preventing data updates.
8213
- var data = config.data = config.data || {};
8214
- data.datasets = data.datasets || [];
8215
- data.labels = data.labels || [];
8216
-
8217
- config.options = helpers.configMerge(
8218
- Chart.defaults.global,
8219
- Chart.defaults[config.type],
8220
- config.options || {});
8221
-
8222
- return config;
8223
- }
8224
-
8225
- /**
8226
- * Updates the config of the chart
8227
- * @param chart {Chart} chart to update the options for
8228
- */
8229
- function updateConfig(chart) {
8230
- var newOptions = chart.options;
8231
-
8232
- // Update Scale(s) with options
8233
- if (newOptions.scale) {
8234
- chart.scale.options = newOptions.scale;
8235
- } else if (newOptions.scales) {
8236
- newOptions.scales.xAxes.concat(newOptions.scales.yAxes).forEach(function(scaleOptions) {
8237
- chart.scales[scaleOptions.id].options = scaleOptions;
8238
- });
8239
- }
8240
-
8241
- // Tooltip
8242
- chart.tooltip._options = newOptions.tooltips;
8243
- }
8244
-
8245
- function positionIsHorizontal(position) {
8246
- return position === 'top' || position === 'bottom';
8247
- }
8248
-
8249
- helpers.extend(Chart.prototype, /** @lends Chart */ {
8250
- /**
8251
- * @private
8252
- */
8253
- construct: function(item, config) {
8254
- var me = this;
8255
-
8256
- config = initConfig(config);
8257
-
8258
- var context = platform.acquireContext(item, config);
8259
- var canvas = context && context.canvas;
8260
- var height = canvas && canvas.height;
8261
- var width = canvas && canvas.width;
8262
-
8263
- me.id = helpers.uid();
8264
- me.ctx = context;
8265
- me.canvas = canvas;
8266
- me.config = config;
8267
- me.width = width;
8268
- me.height = height;
8269
- me.aspectRatio = height? width / height : null;
8270
- me.options = config.options;
8271
- me._bufferedRender = false;
8272
-
8273
- /**
8274
- * Provided for backward compatibility, Chart and Chart.Controller have been merged,
8275
- * the "instance" still need to be defined since it might be called from plugins.
8276
- * @prop Chart#chart
8277
- * @deprecated since version 2.6.0
8278
- * @todo remove at version 3
8279
- * @private
8280
- */
8281
- me.chart = me;
8282
- me.controller = me; // chart.chart.controller #inception
8283
-
8284
- // Add the chart instance to the global namespace
8285
- Chart.instances[me.id] = me;
8286
-
8287
- // Define alias to the config data: `chart.data === chart.config.data`
8288
- Object.defineProperty(me, 'data', {
8289
- get: function() {
8290
- return me.config.data;
8291
- },
8292
- set: function(value) {
8293
- me.config.data = value;
8294
- }
8295
- });
8296
-
8297
- if (!context || !canvas) {
8298
- // The given item is not a compatible context2d element, let's return before finalizing
8299
- // the chart initialization but after setting basic chart / controller properties that
8300
- // can help to figure out that the chart is not valid (e.g chart.canvas !== null);
8301
- // https://github.com/chartjs/Chart.js/issues/2807
8302
- console.error("Failed to create chart: can't acquire context from the given item");
8303
- return;
8304
- }
8305
-
8306
- me.initialize();
8307
- me.update();
8308
- },
8309
-
8310
- /**
8311
- * @private
8312
- */
8313
- initialize: function() {
8314
- var me = this;
8315
-
8316
- // Before init plugin notification
8317
- plugins.notify(me, 'beforeInit');
8318
-
8319
- helpers.retinaScale(me);
8320
-
8321
- me.bindEvents();
8322
-
8323
- if (me.options.responsive) {
8324
- // Initial resize before chart draws (must be silent to preserve initial animations).
8325
- me.resize(true);
8326
- }
8327
-
8328
- // Make sure scales have IDs and are built before we build any controllers.
8329
- me.ensureScalesHaveIDs();
8330
- me.buildScales();
8331
- me.initToolTip();
8332
-
8333
- // After init plugin notification
8334
- plugins.notify(me, 'afterInit');
8335
-
8336
- return me;
8337
- },
8338
-
8339
- clear: function() {
8340
- helpers.clear(this);
8341
- return this;
8342
- },
8343
-
8344
- stop: function() {
8345
- // Stops any current animation loop occurring
8346
- Chart.animationService.cancelAnimation(this);
8347
- return this;
8348
- },
8349
-
8350
- resize: function(silent) {
8351
- var me = this;
8352
- var options = me.options;
8353
- var canvas = me.canvas;
8354
- var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;
8355
-
8356
- // the canvas render width and height will be casted to integers so make sure that
8357
- // the canvas display style uses the same integer values to avoid blurring effect.
8358
- var newWidth = Math.floor(helpers.getMaximumWidth(canvas));
8359
- var newHeight = Math.floor(aspectRatio? newWidth / aspectRatio : helpers.getMaximumHeight(canvas));
8360
-
8361
- if (me.width === newWidth && me.height === newHeight) {
8362
- return;
8363
- }
8364
-
8365
- canvas.width = me.width = newWidth;
8366
- canvas.height = me.height = newHeight;
8367
- canvas.style.width = newWidth + 'px';
8368
- canvas.style.height = newHeight + 'px';
8369
-
8370
- helpers.retinaScale(me);
8371
-
8372
- if (!silent) {
8373
- // Notify any plugins about the resize
8374
- var newSize = {width: newWidth, height: newHeight};
8375
- plugins.notify(me, 'resize', [newSize]);
8376
-
8377
- // Notify of resize
8378
- if (me.options.onResize) {
8379
- me.options.onResize(me, newSize);
8380
- }
8381
-
8382
- me.stop();
8383
- me.update(me.options.responsiveAnimationDuration);
8384
- }
8385
- },
8386
-
8387
- ensureScalesHaveIDs: function() {
8388
- var options = this.options;
8389
- var scalesOptions = options.scales || {};
8390
- var scaleOptions = options.scale;
8391
-
8392
- helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) {
8393
- xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
8394
- });
8395
-
8396
- helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) {
8397
- yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
8398
- });
8399
-
8400
- if (scaleOptions) {
8401
- scaleOptions.id = scaleOptions.id || 'scale';
8402
- }
8403
- },
8404
-
8405
- /**
8406
- * Builds a map of scale ID to scale object for future lookup.
8407
- */
8408
- buildScales: function() {
8409
- var me = this;
8410
- var options = me.options;
8411
- var scales = me.scales = {};
8412
- var items = [];
8413
-
8414
- if (options.scales) {
8415
- items = items.concat(
8416
- (options.scales.xAxes || []).map(function(xAxisOptions) {
8417
- return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
8418
- }),
8419
- (options.scales.yAxes || []).map(function(yAxisOptions) {
8420
- return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
8421
- })
8422
- );
8423
- }
8424
-
8425
- if (options.scale) {
8426
- items.push({
8427
- options: options.scale,
8428
- dtype: 'radialLinear',
8429
- isDefault: true,
8430
- dposition: 'chartArea'
8431
- });
8432
- }
8433
-
8434
- helpers.each(items, function(item) {
8435
- var scaleOptions = item.options;
8436
- var scaleType = helpers.getValueOrDefault(scaleOptions.type, item.dtype);
8437
- var scaleClass = Chart.scaleService.getScaleConstructor(scaleType);
8438
- if (!scaleClass) {
8439
- return;
8440
- }
8441
-
8442
- if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
8443
- scaleOptions.position = item.dposition;
8444
- }
8445
-
8446
- var scale = new scaleClass({
8447
- id: scaleOptions.id,
8448
- options: scaleOptions,
8449
- ctx: me.ctx,
8450
- chart: me
8451
- });
8452
-
8453
- scales[scale.id] = scale;
8454
-
8455
- // TODO(SB): I think we should be able to remove this custom case (options.scale)
8456
- // and consider it as a regular scale part of the "scales"" map only! This would
8457
- // make the logic easier and remove some useless? custom code.
8458
- if (item.isDefault) {
8459
- me.scale = scale;
8460
- }
8461
- });
8462
-
8463
- Chart.scaleService.addScalesToLayout(this);
8464
- },
8465
-
8466
- buildOrUpdateControllers: function() {
8467
- var me = this;
8468
- var types = [];
8469
- var newControllers = [];
8470
-
8471
- helpers.each(me.data.datasets, function(dataset, datasetIndex) {
8472
- var meta = me.getDatasetMeta(datasetIndex);
8473
- if (!meta.type) {
8474
- meta.type = dataset.type || me.config.type;
8475
- }
8476
-
8477
- types.push(meta.type);
8478
-
8479
- if (meta.controller) {
8480
- meta.controller.updateIndex(datasetIndex);
8481
- } else {
8482
- var ControllerClass = Chart.controllers[meta.type];
8483
- if (ControllerClass === undefined) {
8484
- throw new Error('"' + meta.type + '" is not a chart type.');
8485
- }
8486
-
8487
- meta.controller = new ControllerClass(me, datasetIndex);
8488
- newControllers.push(meta.controller);
8489
- }
8490
- }, me);
8491
-
8492
- if (types.length > 1) {
8493
- for (var i = 1; i < types.length; i++) {
8494
- if (types[i] !== types[i - 1]) {
8495
- me.isCombo = true;
8496
- break;
8497
- }
8498
- }
8499
- }
8500
-
8501
- return newControllers;
8502
- },
8503
-
8504
- /**
8505
- * Reset the elements of all datasets
8506
- * @private
8507
- */
8508
- resetElements: function() {
8509
- var me = this;
8510
- helpers.each(me.data.datasets, function(dataset, datasetIndex) {
8511
- me.getDatasetMeta(datasetIndex).controller.reset();
8512
- }, me);
8513
- },
8514
-
8515
- /**
8516
- * Resets the chart back to it's state before the initial animation
8517
- */
8518
- reset: function() {
8519
- this.resetElements();
8520
- this.tooltip.initialize();
8521
- },
8522
-
8523
- update: function(animationDuration, lazy) {
8524
- var me = this;
8525
-
8526
- updateConfig(me);
8527
-
8528
- if (plugins.notify(me, 'beforeUpdate') === false) {
8529
- return;
8530
- }
8531
-
8532
- // In case the entire data object changed
8533
- me.tooltip._data = me.data;
8534
-
8535
- // Make sure dataset controllers are updated and new controllers are reset
8536
- var newControllers = me.buildOrUpdateControllers();
8537
-
8538
- // Make sure all dataset controllers have correct meta data counts
8539
- helpers.each(me.data.datasets, function(dataset, datasetIndex) {
8540
- me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
8541
- }, me);
8542
-
8543
- me.updateLayout();
8544
-
8545
- // Can only reset the new controllers after the scales have been updated
8546
- helpers.each(newControllers, function(controller) {
8547
- controller.reset();
8548
- });
8549
-
8550
- me.updateDatasets();
8551
-
8552
- // Do this before render so that any plugins that need final scale updates can use it
8553
- plugins.notify(me, 'afterUpdate');
8554
-
8555
- if (me._bufferedRender) {
8556
- me._bufferedRequest = {
8557
- lazy: lazy,
8558
- duration: animationDuration
8559
- };
8560
- } else {
8561
- me.render(animationDuration, lazy);
8562
- }
8563
- },
8564
-
8565
- /**
8566
- * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
8567
- * hook, in which case, plugins will not be called on `afterLayout`.
8568
- * @private
8569
- */
8570
- updateLayout: function() {
8571
- var me = this;
8572
-
8573
- if (plugins.notify(me, 'beforeLayout') === false) {
8574
- return;
8575
- }
8576
-
8577
- Chart.layoutService.update(this, this.width, this.height);
8578
-
8579
- /**
8580
- * Provided for backward compatibility, use `afterLayout` instead.
8581
- * @method IPlugin#afterScaleUpdate
8582
- * @deprecated since version 2.5.0
8583
- * @todo remove at version 3
8584
- * @private
8585
- */
8586
- plugins.notify(me, 'afterScaleUpdate');
8587
- plugins.notify(me, 'afterLayout');
8588
- },
8589
-
8590
- /**
8591
- * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
8592
- * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
8593
- * @private
8594
- */
8595
- updateDatasets: function() {
8596
- var me = this;
8597
-
8598
- if (plugins.notify(me, 'beforeDatasetsUpdate') === false) {
8599
- return;
8600
- }
8601
-
8602
- for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
8603
- me.updateDataset(i);
8604
- }
8605
-
8606
- plugins.notify(me, 'afterDatasetsUpdate');
8607
- },
8608
-
8609
- /**
8610
- * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
8611
- * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
8612
- * @private
8613
- */
8614
- updateDataset: function(index) {
8615
- var me = this;
8616
- var meta = me.getDatasetMeta(index);
8617
- var args = {
8618
- meta: meta,
8619
- index: index
8620
- };
8621
-
8622
- if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
8623
- return;
8624
- }
8625
-
8626
- meta.controller.update();
8627
-
8628
- plugins.notify(me, 'afterDatasetUpdate', [args]);
8629
- },
8630
-
8631
- render: function(duration, lazy) {
8632
- var me = this;
8633
-
8634
- if (plugins.notify(me, 'beforeRender') === false) {
8635
- return;
8636
- }
8637
-
8638
- var animationOptions = me.options.animation;
8639
- var onComplete = function(animation) {
8640
- plugins.notify(me, 'afterRender');
8641
- helpers.callback(animationOptions && animationOptions.onComplete, [animation], me);
8642
- };
8643
-
8644
- if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
8645
- var animation = new Chart.Animation({
8646
- numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
8647
- easing: animationOptions.easing,
8648
-
8649
- render: function(chart, animationObject) {
8650
- var easingFunction = helpers.easingEffects[animationObject.easing];
8651
- var currentStep = animationObject.currentStep;
8652
- var stepDecimal = currentStep / animationObject.numSteps;
8653
-
8654
- chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
8655
- },
8656
-
8657
- onAnimationProgress: animationOptions.onProgress,
8658
- onAnimationComplete: onComplete
8659
- });
8660
-
8661
- Chart.animationService.addAnimation(me, animation, duration, lazy);
8662
- } else {
8663
- me.draw();
8664
-
8665
- // See https://github.com/chartjs/Chart.js/issues/3781
8666
- onComplete(new Chart.Animation({numSteps: 0, chart: me}));
8667
- }
8668
-
8669
- return me;
8670
- },
8671
-
8672
- draw: function(easingValue) {
8673
- var me = this;
8674
-
8675
- me.clear();
8676
-
8677
- if (easingValue === undefined || easingValue === null) {
8678
- easingValue = 1;
8679
- }
8680
-
8681
- me.transition(easingValue);
8682
-
8683
- if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
8684
- return;
8685
- }
8686
-
8687
- // Draw all the scales
8688
- helpers.each(me.boxes, function(box) {
8689
- box.draw(me.chartArea);
8690
- }, me);
8691
-
8692
- if (me.scale) {
8693
- me.scale.draw();
8694
- }
8695
-
8696
- me.drawDatasets(easingValue);
8697
-
8698
- // Finally draw the tooltip
8699
- me.tooltip.draw();
8700
-
8701
- plugins.notify(me, 'afterDraw', [easingValue]);
8702
- },
8703
-
8704
- /**
8705
- * @private
8706
- */
8707
- transition: function(easingValue) {
8708
- var me = this;
8709
-
8710
- for (var i=0, ilen=(me.data.datasets || []).length; i<ilen; ++i) {
8711
- if (me.isDatasetVisible(i)) {
8712
- me.getDatasetMeta(i).controller.transition(easingValue);
8713
- }
8714
- }
8715
-
8716
- me.tooltip.transition(easingValue);
8717
- },
8718
-
8719
- /**
8720
- * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
8721
- * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
8722
- * @private
8723
- */
8724
- drawDatasets: function(easingValue) {
8725
- var me = this;
8726
-
8727
- if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
8728
- return;
8729
- }
8730
-
8731
- // Draw datasets reversed to support proper line stacking
8732
- for (var i=(me.data.datasets || []).length - 1; i >= 0; --i) {
8733
- if (me.isDatasetVisible(i)) {
8734
- me.drawDataset(i, easingValue);
8735
- }
8736
- }
8737
-
8738
- plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
8739
- },
8740
-
8741
- /**
8742
- * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
8743
- * hook, in which case, plugins will not be called on `afterDatasetDraw`.
8744
- * @private
8745
- */
8746
- drawDataset: function(index, easingValue) {
8747
- var me = this;
8748
- var meta = me.getDatasetMeta(index);
8749
- var args = {
8750
- meta: meta,
8751
- index: index,
8752
- easingValue: easingValue
8753
- };
8754
-
8755
- if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
8756
- return;
8757
- }
8758
-
8759
- meta.controller.draw(easingValue);
8760
-
8761
- plugins.notify(me, 'afterDatasetDraw', [args]);
8762
- },
8763
-
8764
- // Get the single element that was clicked on
8765
- // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
8766
- getElementAtEvent: function(e) {
8767
- return Chart.Interaction.modes.single(this, e);
8768
- },
8769
-
8770
- getElementsAtEvent: function(e) {
8771
- return Chart.Interaction.modes.label(this, e, {intersect: true});
8772
- },
8773
-
8774
- getElementsAtXAxis: function(e) {
8775
- return Chart.Interaction.modes['x-axis'](this, e, {intersect: true});
8776
- },
8777
-
8778
- getElementsAtEventForMode: function(e, mode, options) {
8779
- var method = Chart.Interaction.modes[mode];
8780
- if (typeof method === 'function') {
8781
- return method(this, e, options);
8782
- }
8783
-
8784
- return [];
8785
- },
8786
-
8787
- getDatasetAtEvent: function(e) {
8788
- return Chart.Interaction.modes.dataset(this, e, {intersect: true});
8789
- },
8790
-
8791
- getDatasetMeta: function(datasetIndex) {
8792
- var me = this;
8793
- var dataset = me.data.datasets[datasetIndex];
8794
- if (!dataset._meta) {
8795
- dataset._meta = {};
8796
- }
8797
-
8798
- var meta = dataset._meta[me.id];
8799
- if (!meta) {
8800
- meta = dataset._meta[me.id] = {
8801
- type: null,
8802
- data: [],
8803
- dataset: null,
8804
- controller: null,
8805
- hidden: null, // See isDatasetVisible() comment
8806
- xAxisID: null,
8807
- yAxisID: null
8808
- };
8809
- }
8810
-
8811
- return meta;
8812
- },
8813
-
8814
- getVisibleDatasetCount: function() {
8815
- var count = 0;
8816
- for (var i = 0, ilen = this.data.datasets.length; i<ilen; ++i) {
8817
- if (this.isDatasetVisible(i)) {
8818
- count++;
8819
- }
8820
- }
8821
- return count;
8822
- },
8823
-
8824
- isDatasetVisible: function(datasetIndex) {
8825
- var meta = this.getDatasetMeta(datasetIndex);
8826
-
8827
- // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
8828
- // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
8829
- return typeof meta.hidden === 'boolean'? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
8830
- },
8831
-
8832
- generateLegend: function() {
8833
- return this.options.legendCallback(this);
8834
- },
8835
-
8836
- destroy: function() {
8837
- var me = this;
8838
- var canvas = me.canvas;
8839
- var meta, i, ilen;
8840
-
8841
- me.stop();
8842
-
8843
- // dataset controllers need to cleanup associated data
8844
- for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
8845
- meta = me.getDatasetMeta(i);
8846
- if (meta.controller) {
8847
- meta.controller.destroy();
8848
- meta.controller = null;
8849
- }
8850
- }
8851
-
8852
- if (canvas) {
8853
- me.unbindEvents();
8854
- helpers.clear(me);
8855
- platform.releaseContext(me.ctx);
8856
- me.canvas = null;
8857
- me.ctx = null;
8858
- }
8859
-
8860
- plugins.notify(me, 'destroy');
8861
-
8862
- delete Chart.instances[me.id];
8863
- },
8864
-
8865
- toBase64Image: function() {
8866
- return this.canvas.toDataURL.apply(this.canvas, arguments);
8867
- },
8868
-
8869
- initToolTip: function() {
8870
- var me = this;
8871
- me.tooltip = new Chart.Tooltip({
8872
- _chart: me,
8873
- _chartInstance: me, // deprecated, backward compatibility
8874
- _data: me.data,
8875
- _options: me.options.tooltips
8876
- }, me);
8877
- me.tooltip.initialize();
8878
- },
8879
-
8880
- /**
8881
- * @private
8882
- */
8883
- bindEvents: function() {
8884
- var me = this;
8885
- var listeners = me._listeners = {};
8886
- var listener = function() {
8887
- me.eventHandler.apply(me, arguments);
8888
- };
8889
-
8890
- helpers.each(me.options.events, function(type) {
8891
- platform.addEventListener(me, type, listener);
8892
- listeners[type] = listener;
8893
- });
8894
-
8895
- // Responsiveness is currently based on the use of an iframe, however this method causes
8896
- // performance issues and could be troublesome when used with ad blockers. So make sure
8897
- // that the user is still able to create a chart without iframe when responsive is false.
8898
- // See https://github.com/chartjs/Chart.js/issues/2210
8899
- if (me.options.responsive) {
8900
- listener = function() {
8901
- me.resize();
8902
- };
8903
-
8904
- platform.addEventListener(me, 'resize', listener);
8905
- listeners.resize = listener;
8906
- }
8907
- },
8908
-
8909
- /**
8910
- * @private
8911
- */
8912
- unbindEvents: function() {
8913
- var me = this;
8914
- var listeners = me._listeners;
8915
- if (!listeners) {
8916
- return;
8917
- }
8918
-
8919
- delete me._listeners;
8920
- helpers.each(listeners, function(listener, type) {
8921
- platform.removeEventListener(me, type, listener);
8922
- });
8923
- },
8924
-
8925
- updateHoverStyle: function(elements, mode, enabled) {
8926
- var method = enabled? 'setHoverStyle' : 'removeHoverStyle';
8927
- var element, i, ilen;
8928
-
8929
- for (i=0, ilen=elements.length; i<ilen; ++i) {
8930
- element = elements[i];
8931
- if (element) {
8932
- this.getDatasetMeta(element._datasetIndex).controller[method](element);
8933
- }
8934
- }
8935
- },
8936
-
8937
- /**
8938
- * @private
8939
- */
8940
- eventHandler: function(e) {
8941
- var me = this;
8942
- var tooltip = me.tooltip;
8943
-
8944
- if (plugins.notify(me, 'beforeEvent', [e]) === false) {
8945
- return;
8946
- }
8947
-
8948
- // Buffer any update calls so that renders do not occur
8949
- me._bufferedRender = true;
8950
- me._bufferedRequest = null;
8951
-
8952
- var changed = me.handleEvent(e);
8953
- changed |= tooltip && tooltip.handleEvent(e);
8954
-
8955
- plugins.notify(me, 'afterEvent', [e]);
8956
-
8957
- var bufferedRequest = me._bufferedRequest;
8958
- if (bufferedRequest) {
8959
- // If we have an update that was triggered, we need to do a normal render
8960
- me.render(bufferedRequest.duration, bufferedRequest.lazy);
8961
- } else if (changed && !me.animating) {
8962
- // If entering, leaving, or changing elements, animate the change via pivot
8963
- me.stop();
8964
-
8965
- // We only need to render at this point. Updating will cause scales to be
8966
- // recomputed generating flicker & using more memory than necessary.
8967
- me.render(me.options.hover.animationDuration, true);
8968
- }
8969
-
8970
- me._bufferedRender = false;
8971
- me._bufferedRequest = null;
8972
-
8973
- return me;
8974
- },
8975
-
8976
- /**
8977
- * Handle an event
8978
- * @private
8979
- * @param {IEvent} event the event to handle
8980
- * @return {Boolean} true if the chart needs to re-render
8981
- */
8982
- handleEvent: function(e) {
8983
- var me = this;
8984
- var options = me.options || {};
8985
- var hoverOptions = options.hover;
8986
- var changed = false;
8987
-
8988
- me.lastActive = me.lastActive || [];
8989
-
8990
- // Find Active Elements for hover and tooltips
8991
- if (e.type === 'mouseout') {
8992
- me.active = [];
8993
- } else {
8994
- me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
8995
- }
8996
-
8997
- // On Hover hook
8998
- if (hoverOptions.onHover) {
8999
- // Need to call with native event here to not break backwards compatibility
9000
- hoverOptions.onHover.call(me, e.native, me.active);
9001
- }
9002
-
9003
- if (e.type === 'mouseup' || e.type === 'click') {
9004
- if (options.onClick) {
9005
- // Use e.native here for backwards compatibility
9006
- options.onClick.call(me, e.native, me.active);
9007
- }
9008
- }
9009
-
9010
- // Remove styling for last active (even if it may still be active)
9011
- if (me.lastActive.length) {
9012
- me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
9013
- }
9014
-
9015
- // Built in hover styling
9016
- if (me.active.length && hoverOptions.mode) {
9017
- me.updateHoverStyle(me.active, hoverOptions.mode, true);
9018
- }
9019
-
9020
- changed = !helpers.arrayEquals(me.active, me.lastActive);
9021
-
9022
- // Remember Last Actives
9023
- me.lastActive = me.active;
9024
-
9025
- return changed;
9026
- }
9027
- });
9028
-
9029
- /**
9030
- * Provided for backward compatibility, use Chart instead.
9031
- * @class Chart.Controller
9032
- * @deprecated since version 2.6.0
9033
- * @todo remove at version 3
9034
- * @private
9035
- */
9036
- Chart.Controller = Chart;
9037
- };
9038
-
9039
- },{}],24:[function(require,module,exports){
9040
- 'use strict';
9041
-
9042
- module.exports = function(Chart) {
9043
-
9044
- var helpers = Chart.helpers;
9045
-
9046
- var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
9047
-
9048
- /**
9049
- * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
9050
- * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
9051
- * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
9052
- */
9053
- function listenArrayEvents(array, listener) {
9054
- if (array._chartjs) {
9055
- array._chartjs.listeners.push(listener);
9056
- return;
9057
- }
9058
-
9059
- Object.defineProperty(array, '_chartjs', {
9060
- configurable: true,
9061
- enumerable: false,
9062
- value: {
9063
- listeners: [listener]
9064
- }
9065
- });
9066
-
9067
- arrayEvents.forEach(function(key) {
9068
- var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
9069
- var base = array[key];
9070
-
9071
- Object.defineProperty(array, key, {
9072
- configurable: true,
9073
- enumerable: false,
9074
- value: function() {
9075
- var args = Array.prototype.slice.call(arguments);
9076
- var res = base.apply(this, args);
9077
-
9078
- helpers.each(array._chartjs.listeners, function(object) {
9079
- if (typeof object[method] === 'function') {
9080
- object[method].apply(object, args);
9081
- }
9082
- });
9083
-
9084
- return res;
9085
- }
9086
- });
9087
- });
9088
- }
9089
-
9090
- /**
9091
- * Removes the given array event listener and cleanup extra attached properties (such as
9092
- * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
9093
- */
9094
- function unlistenArrayEvents(array, listener) {
9095
- var stub = array._chartjs;
9096
- if (!stub) {
9097
- return;
9098
- }
9099
-
9100
- var listeners = stub.listeners;
9101
- var index = listeners.indexOf(listener);
9102
- if (index !== -1) {
9103
- listeners.splice(index, 1);
9104
- }
9105
-
9106
- if (listeners.length > 0) {
9107
- return;
9108
- }
9109
-
9110
- arrayEvents.forEach(function(key) {
9111
- delete array[key];
9112
- });
9113
-
9114
- delete array._chartjs;
9115
- }
9116
-
9117
- // Base class for all dataset controllers (line, bar, etc)
9118
- Chart.DatasetController = function(chart, datasetIndex) {
9119
- this.initialize(chart, datasetIndex);
9120
- };
9121
-
9122
- helpers.extend(Chart.DatasetController.prototype, {
9123
-
9124
- /**
9125
- * Element type used to generate a meta dataset (e.g. Chart.element.Line).
9126
- * @type {Chart.core.element}
9127
- */
9128
- datasetElementType: null,
9129
-
9130
- /**
9131
- * Element type used to generate a meta data (e.g. Chart.element.Point).
9132
- * @type {Chart.core.element}
9133
- */
9134
- dataElementType: null,
9135
-
9136
- initialize: function(chart, datasetIndex) {
9137
- var me = this;
9138
- me.chart = chart;
9139
- me.index = datasetIndex;
9140
- me.linkScales();
9141
- me.addElements();
9142
- },
9143
-
9144
- updateIndex: function(datasetIndex) {
9145
- this.index = datasetIndex;
9146
- },
9147
-
9148
- linkScales: function() {
9149
- var me = this;
9150
- var meta = me.getMeta();
9151
- var dataset = me.getDataset();
9152
-
9153
- if (meta.xAxisID === null) {
9154
- meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
9155
- }
9156
- if (meta.yAxisID === null) {
9157
- meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
9158
- }
9159
- },
9160
-
9161
- getDataset: function() {
9162
- return this.chart.data.datasets[this.index];
9163
- },
9164
-
9165
- getMeta: function() {
9166
- return this.chart.getDatasetMeta(this.index);
9167
- },
9168
-
9169
- getScaleForId: function(scaleID) {
9170
- return this.chart.scales[scaleID];
9171
- },
9172
-
9173
- reset: function() {
9174
- this.update(true);
9175
- },
9176
-
9177
- /**
9178
- * @private
9179
- */
9180
- destroy: function() {
9181
- if (this._data) {
9182
- unlistenArrayEvents(this._data, this);
9183
- }
9184
- },
9185
-
9186
- createMetaDataset: function() {
9187
- var me = this;
9188
- var type = me.datasetElementType;
9189
- return type && new type({
9190
- _chart: me.chart,
9191
- _datasetIndex: me.index
9192
- });
9193
- },
9194
-
9195
- createMetaData: function(index) {
9196
- var me = this;
9197
- var type = me.dataElementType;
9198
- return type && new type({
9199
- _chart: me.chart,
9200
- _datasetIndex: me.index,
9201
- _index: index
9202
- });
9203
- },
9204
-
9205
- addElements: function() {
9206
- var me = this;
9207
- var meta = me.getMeta();
9208
- var data = me.getDataset().data || [];
9209
- var metaData = meta.data;
9210
- var i, ilen;
9211
-
9212
- for (i=0, ilen=data.length; i<ilen; ++i) {
9213
- metaData[i] = metaData[i] || me.createMetaData(i);
9214
- }
9215
-
9216
- meta.dataset = meta.dataset || me.createMetaDataset();
9217
- },
9218
-
9219
- addElementAndReset: function(index) {
9220
- var element = this.createMetaData(index);
9221
- this.getMeta().data.splice(index, 0, element);
9222
- this.updateElement(element, index, true);
9223
- },
9224
-
9225
- buildOrUpdateElements: function() {
9226
- var me = this;
9227
- var dataset = me.getDataset();
9228
- var data = dataset.data || (dataset.data = []);
9229
-
9230
- // In order to correctly handle data addition/deletion animation (an thus simulate
9231
- // real-time charts), we need to monitor these data modifications and synchronize
9232
- // the internal meta data accordingly.
9233
- if (me._data !== data) {
9234
- if (me._data) {
9235
- // This case happens when the user replaced the data array instance.
9236
- unlistenArrayEvents(me._data, me);
9237
- }
9238
-
9239
- listenArrayEvents(data, me);
9240
- me._data = data;
9241
- }
9242
-
9243
- // Re-sync meta data in case the user replaced the data array or if we missed
9244
- // any updates and so make sure that we handle number of datapoints changing.
9245
- me.resyncElements();
9246
- },
9247
-
9248
- update: helpers.noop,
9249
-
9250
- transition: function(easingValue) {
9251
- var meta = this.getMeta();
9252
- var elements = meta.data || [];
9253
- var ilen = elements.length;
9254
- var i = 0;
9255
-
9256
- for (; i<ilen; ++i) {
9257
- elements[i].transition(easingValue);
9258
- }
9259
-
9260
- if (meta.dataset) {
9261
- meta.dataset.transition(easingValue);
9262
- }
9263
- },
9264
-
9265
- draw: function() {
9266
- var meta = this.getMeta();
9267
- var elements = meta.data || [];
9268
- var ilen = elements.length;
9269
- var i = 0;
9270
-
9271
- if (meta.dataset) {
9272
- meta.dataset.draw();
9273
- }
9274
-
9275
- for (; i<ilen; ++i) {
9276
- elements[i].draw();
9277
- }
9278
- },
9279
-
9280
- removeHoverStyle: function(element, elementOpts) {
9281
- var dataset = this.chart.data.datasets[element._datasetIndex],
9282
- index = element._index,
9283
- custom = element.custom || {},
9284
- valueOrDefault = helpers.getValueAtIndexOrDefault,
9285
- model = element._model;
9286
-
9287
- model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
9288
- model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
9289
- model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
9290
- },
9291
-
9292
- setHoverStyle: function(element) {
9293
- var dataset = this.chart.data.datasets[element._datasetIndex],
9294
- index = element._index,
9295
- custom = element.custom || {},
9296
- valueOrDefault = helpers.getValueAtIndexOrDefault,
9297
- getHoverColor = helpers.getHoverColor,
9298
- model = element._model;
9299
-
9300
- model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
9301
- model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
9302
- model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
9303
- },
9304
-
9305
- /**
9306
- * @private
9307
- */
9308
- resyncElements: function() {
9309
- var me = this;
9310
- var meta = me.getMeta();
9311
- var data = me.getDataset().data;
9312
- var numMeta = meta.data.length;
9313
- var numData = data.length;
9314
-
9315
- if (numData < numMeta) {
9316
- meta.data.splice(numData, numMeta - numData);
9317
- } else if (numData > numMeta) {
9318
- me.insertElements(numMeta, numData - numMeta);
9319
- }
9320
- },
9321
-
9322
- /**
9323
- * @private
9324
- */
9325
- insertElements: function(start, count) {
9326
- for (var i=0; i<count; ++i) {
9327
- this.addElementAndReset(start + i);
9328
- }
9329
- },
9330
-
9331
- /**
9332
- * @private
9333
- */
9334
- onDataPush: function() {
9335
- this.insertElements(this.getDataset().data.length-1, arguments.length);
9336
- },
9337
-
9338
- /**
9339
- * @private
9340
- */
9341
- onDataPop: function() {
9342
- this.getMeta().data.pop();
9343
- },
9344
-
9345
- /**
9346
- * @private
9347
- */
9348
- onDataShift: function() {
9349
- this.getMeta().data.shift();
9350
- },
9351
-
9352
- /**
9353
- * @private
9354
- */
9355
- onDataSplice: function(start, count) {
9356
- this.getMeta().data.splice(start, count);
9357
- this.insertElements(start, arguments.length - 2);
9358
- },
9359
-
9360
- /**
9361
- * @private
9362
- */
9363
- onDataUnshift: function() {
9364
- this.insertElements(0, arguments.length);
9365
- }
9366
- });
9367
-
9368
- Chart.DatasetController.extend = helpers.inherits;
9369
- };
9370
-
9371
- },{}],25:[function(require,module,exports){
9372
- 'use strict';
9373
-
9374
- var color = require(2);
9375
-
9376
- module.exports = function(Chart) {
9377
-
9378
- var helpers = Chart.helpers;
9379
-
9380
- function interpolate(start, view, model, ease) {
9381
- var keys = Object.keys(model);
9382
- var i, ilen, key, actual, origin, target, type, c0, c1;
9383
-
9384
- for (i=0, ilen=keys.length; i<ilen; ++i) {
9385
- key = keys[i];
9386
-
9387
- target = model[key];
9388
-
9389
- // if a value is added to the model after pivot() has been called, the view
9390
- // doesn't contain it, so let's initialize the view to the target value.
9391
- if (!view.hasOwnProperty(key)) {
9392
- view[key] = target;
9393
- }
9394
-
9395
- actual = view[key];
9396
-
9397
- if (actual === target || key[0] === '_') {
9398
- continue;
9399
- }
9400
-
9401
- if (!start.hasOwnProperty(key)) {
9402
- start[key] = actual;
9403
- }
9404
-
9405
- origin = start[key];
9406
-
9407
- type = typeof(target);
9408
-
9409
- if (type === typeof(origin)) {
9410
- if (type === 'string') {
9411
- c0 = color(origin);
9412
- if (c0.valid) {
9413
- c1 = color(target);
9414
- if (c1.valid) {
9415
- view[key] = c1.mix(c0, ease).rgbString();
9416
- continue;
9417
- }
9418
- }
9419
- } else if (type === 'number' && isFinite(origin) && isFinite(target)) {
9420
- view[key] = origin + (target - origin) * ease;
9421
- continue;
9422
- }
9423
- }
9424
-
9425
- view[key] = target;
9426
- }
9427
- }
9428
-
9429
- Chart.elements = {};
9430
-
9431
- Chart.Element = function(configuration) {
9432
- helpers.extend(this, configuration);
9433
- this.initialize.apply(this, arguments);
9434
- };
9435
-
9436
- helpers.extend(Chart.Element.prototype, {
9437
-
9438
- initialize: function() {
9439
- this.hidden = false;
9440
- },
9441
-
9442
- pivot: function() {
9443
- var me = this;
9444
- if (!me._view) {
9445
- me._view = helpers.clone(me._model);
9446
- }
9447
- me._start = {};
9448
- return me;
9449
- },
9450
-
9451
- transition: function(ease) {
9452
- var me = this;
9453
- var model = me._model;
9454
- var start = me._start;
9455
- var view = me._view;
9456
-
9457
- // No animation -> No Transition
9458
- if (!model || ease === 1) {
9459
- me._view = model;
9460
- me._start = null;
9461
- return me;
9462
- }
9463
-
9464
- if (!view) {
9465
- view = me._view = {};
9466
- }
9467
-
9468
- if (!start) {
9469
- start = me._start = {};
9470
- }
9471
-
9472
- interpolate(start, view, model, ease);
9473
-
9474
- return me;
9475
- },
9476
-
9477
- tooltipPosition: function() {
9478
- return {
9479
- x: this._model.x,
9480
- y: this._model.y
9481
- };
9482
- },
9483
-
9484
- hasValue: function() {
9485
- return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
9486
- }
9487
- });
9488
-
9489
- Chart.Element.extend = helpers.inherits;
9490
- };
9491
-
9492
- },{"2":2}],26:[function(require,module,exports){
9493
- /* global window: false */
9494
- /* global document: false */
9495
- 'use strict';
9496
-
9497
- var color = require(2);
9498
-
9499
- module.exports = function(Chart) {
9500
- // Global Chart helpers object for utility methods and classes
9501
- var helpers = Chart.helpers = {};
9502
-
9503
- // -- Basic js utility methods
9504
- helpers.each = function(loopable, callback, self, reverse) {
9505
- // Check to see if null or undefined firstly.
9506
- var i, len;
9507
- if (helpers.isArray(loopable)) {
9508
- len = loopable.length;
9509
- if (reverse) {
9510
- for (i = len - 1; i >= 0; i--) {
9511
- callback.call(self, loopable[i], i);
9512
- }
9513
- } else {
9514
- for (i = 0; i < len; i++) {
9515
- callback.call(self, loopable[i], i);
9516
- }
9517
- }
9518
- } else if (typeof loopable === 'object') {
9519
- var keys = Object.keys(loopable);
9520
- len = keys.length;
9521
- for (i = 0; i < len; i++) {
9522
- callback.call(self, loopable[keys[i]], keys[i]);
9523
- }
9524
- }
9525
- };
9526
- helpers.clone = function(obj) {
9527
- var objClone = {};
9528
- helpers.each(obj, function(value, key) {
9529
- if (helpers.isArray(value)) {
9530
- objClone[key] = value.slice(0);
9531
- } else if (typeof value === 'object' && value !== null) {
9532
- objClone[key] = helpers.clone(value);
9533
- } else {
9534
- objClone[key] = value;
9535
- }
9536
- });
9537
- return objClone;
9538
- };
9539
- helpers.extend = function(base) {
9540
- var setFn = function(value, key) {
9541
- base[key] = value;
9542
- };
9543
- for (var i = 1, ilen = arguments.length; i < ilen; i++) {
9544
- helpers.each(arguments[i], setFn);
9545
- }
9546
- return base;
9547
- };
9548
- // Need a special merge function to chart configs since they are now grouped
9549
- helpers.configMerge = function(_base) {
9550
- var base = helpers.clone(_base);
9551
- helpers.each(Array.prototype.slice.call(arguments, 1), function(extension) {
9552
- helpers.each(extension, function(value, key) {
9553
- var baseHasProperty = base.hasOwnProperty(key);
9554
- var baseVal = baseHasProperty ? base[key] : {};
9555
-
9556
- if (key === 'scales') {
9557
- // Scale config merging is complex. Add our own function here for that
9558
- base[key] = helpers.scaleMerge(baseVal, value);
9559
- } else if (key === 'scale') {
9560
- // Used in polar area & radar charts since there is only one scale
9561
- base[key] = helpers.configMerge(baseVal, Chart.scaleService.getScaleDefaults(value.type), value);
9562
- } else if (baseHasProperty
9563
- && typeof baseVal === 'object'
9564
- && !helpers.isArray(baseVal)
9565
- && baseVal !== null
9566
- && typeof value === 'object'
9567
- && !helpers.isArray(value)) {
9568
- // If we are overwriting an object with an object, do a merge of the properties.
9569
- base[key] = helpers.configMerge(baseVal, value);
9570
- } else {
9571
- // can just overwrite the value in this case
9572
- base[key] = value;
9573
- }
9574
- });
9575
- });
9576
-
9577
- return base;
9578
- };
9579
- helpers.scaleMerge = function(_base, extension) {
9580
- var base = helpers.clone(_base);
9581
-
9582
- helpers.each(extension, function(value, key) {
9583
- if (key === 'xAxes' || key === 'yAxes') {
9584
- // These properties are arrays of items
9585
- if (base.hasOwnProperty(key)) {
9586
- helpers.each(value, function(valueObj, index) {
9587
- var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear');
9588
- var axisDefaults = Chart.scaleService.getScaleDefaults(axisType);
9589
- if (index >= base[key].length || !base[key][index].type) {
9590
- base[key].push(helpers.configMerge(axisDefaults, valueObj));
9591
- } else if (valueObj.type && valueObj.type !== base[key][index].type) {
9592
- // Type changed. Bring in the new defaults before we bring in valueObj so that valueObj can override the correct scale defaults
9593
- base[key][index] = helpers.configMerge(base[key][index], axisDefaults, valueObj);
9594
- } else {
9595
- // Type is the same
9596
- base[key][index] = helpers.configMerge(base[key][index], valueObj);
9597
- }
9598
- });
9599
- } else {
9600
- base[key] = [];
9601
- helpers.each(value, function(valueObj) {
9602
- var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear');
9603
- base[key].push(helpers.configMerge(Chart.scaleService.getScaleDefaults(axisType), valueObj));
9604
- });
9605
- }
9606
- } else if (base.hasOwnProperty(key) && typeof base[key] === 'object' && base[key] !== null && typeof value === 'object') {
9607
- // If we are overwriting an object with an object, do a merge of the properties.
9608
- base[key] = helpers.configMerge(base[key], value);
9609
-
9610
- } else {
9611
- // can just overwrite the value in this case
9612
- base[key] = value;
9613
- }
9614
- });
9615
-
9616
- return base;
9617
- };
9618
- helpers.getValueAtIndexOrDefault = function(value, index, defaultValue) {
9619
- if (value === undefined || value === null) {
9620
- return defaultValue;
9621
- }
9622
-
9623
- if (helpers.isArray(value)) {
9624
- return index < value.length ? value[index] : defaultValue;
9625
- }
9626
-
9627
- return value;
9628
- };
9629
- helpers.getValueOrDefault = function(value, defaultValue) {
9630
- return value === undefined ? defaultValue : value;
9631
- };
9632
- helpers.indexOf = Array.prototype.indexOf?
9633
- function(array, item) {
9634
- return array.indexOf(item);
9635
- }:
9636
- function(array, item) {
9637
- for (var i = 0, ilen = array.length; i < ilen; ++i) {
9638
- if (array[i] === item) {
9639
- return i;
9640
- }
9641
- }
9642
- return -1;
9643
- };
9644
- helpers.where = function(collection, filterCallback) {
9645
- if (helpers.isArray(collection) && Array.prototype.filter) {
9646
- return collection.filter(filterCallback);
9647
- }
9648
- var filtered = [];
9649
-
9650
- helpers.each(collection, function(item) {
9651
- if (filterCallback(item)) {
9652
- filtered.push(item);
9653
- }
9654
- });
9655
-
9656
- return filtered;
9657
- };
9658
- helpers.findIndex = Array.prototype.findIndex?
9659
- function(array, callback, scope) {
9660
- return array.findIndex(callback, scope);
9661
- } :
9662
- function(array, callback, scope) {
9663
- scope = scope === undefined? array : scope;
9664
- for (var i = 0, ilen = array.length; i < ilen; ++i) {
9665
- if (callback.call(scope, array[i], i, array)) {
9666
- return i;
9667
- }
9668
- }
9669
- return -1;
9670
- };
9671
- helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
9672
- // Default to start of the array
9673
- if (startIndex === undefined || startIndex === null) {
9674
- startIndex = -1;
9675
- }
9676
- for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
9677
- var currentItem = arrayToSearch[i];
9678
- if (filterCallback(currentItem)) {
9679
- return currentItem;
9680
- }
9681
- }
9682
- };
9683
- helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
9684
- // Default to end of the array
9685
- if (startIndex === undefined || startIndex === null) {
9686
- startIndex = arrayToSearch.length;
9687
- }
9688
- for (var i = startIndex - 1; i >= 0; i--) {
9689
- var currentItem = arrayToSearch[i];
9690
- if (filterCallback(currentItem)) {
9691
- return currentItem;
9692
- }
9693
- }
9694
- };
9695
- helpers.inherits = function(extensions) {
9696
- // Basic javascript inheritance based on the model created in Backbone.js
9697
- var me = this;
9698
- var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
9699
- return me.apply(this, arguments);
9700
- };
9701
-
9702
- var Surrogate = function() {
9703
- this.constructor = ChartElement;
9704
- };
9705
- Surrogate.prototype = me.prototype;
9706
- ChartElement.prototype = new Surrogate();
9707
-
9708
- ChartElement.extend = helpers.inherits;
9709
-
9710
- if (extensions) {
9711
- helpers.extend(ChartElement.prototype, extensions);
9712
- }
9713
-
9714
- ChartElement.__super__ = me.prototype;
9715
-
9716
- return ChartElement;
9717
- };
9718
- helpers.noop = function() {};
9719
- helpers.uid = (function() {
9720
- var id = 0;
9721
- return function() {
9722
- return id++;
9723
- };
9724
- }());
9725
- // -- Math methods
9726
- helpers.isNumber = function(n) {
9727
- return !isNaN(parseFloat(n)) && isFinite(n);
9728
- };
9729
- helpers.almostEquals = function(x, y, epsilon) {
9730
- return Math.abs(x - y) < epsilon;
9731
- };
9732
- helpers.almostWhole = function(x, epsilon) {
9733
- var rounded = Math.round(x);
9734
- return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
9735
- };
9736
- helpers.max = function(array) {
9737
- return array.reduce(function(max, value) {
9738
- if (!isNaN(value)) {
9739
- return Math.max(max, value);
9740
- }
9741
- return max;
9742
- }, Number.NEGATIVE_INFINITY);
9743
- };
9744
- helpers.min = function(array) {
9745
- return array.reduce(function(min, value) {
9746
- if (!isNaN(value)) {
9747
- return Math.min(min, value);
9748
- }
9749
- return min;
9750
- }, Number.POSITIVE_INFINITY);
9751
- };
9752
- helpers.sign = Math.sign?
9753
- function(x) {
9754
- return Math.sign(x);
9755
- } :
9756
- function(x) {
9757
- x = +x; // convert to a number
9758
- if (x === 0 || isNaN(x)) {
9759
- return x;
9760
- }
9761
- return x > 0 ? 1 : -1;
9762
- };
9763
- helpers.log10 = Math.log10?
9764
- function(x) {
9765
- return Math.log10(x);
9766
- } :
9767
- function(x) {
9768
- return Math.log(x) / Math.LN10;
9769
- };
9770
- helpers.toRadians = function(degrees) {
9771
- return degrees * (Math.PI / 180);
9772
- };
9773
- helpers.toDegrees = function(radians) {
9774
- return radians * (180 / Math.PI);
9775
- };
9776
- // Gets the angle from vertical upright to the point about a centre.
9777
- helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
9778
- var distanceFromXCenter = anglePoint.x - centrePoint.x,
9779
- distanceFromYCenter = anglePoint.y - centrePoint.y,
9780
- radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
9781
-
9782
- var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
9783
-
9784
- if (angle < (-0.5 * Math.PI)) {
9785
- angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
9786
- }
9787
-
9788
- return {
9789
- angle: angle,
9790
- distance: radialDistanceFromCenter
9791
- };
9792
- };
9793
- helpers.distanceBetweenPoints = function(pt1, pt2) {
9794
- return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
9795
- };
9796
- helpers.aliasPixel = function(pixelWidth) {
9797
- return (pixelWidth % 2 === 0) ? 0 : 0.5;
9798
- };
9799
- helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
9800
- // Props to Rob Spencer at scaled innovation for his post on splining between points
9801
- // http://scaledinnovation.com/analytics/splines/aboutSplines.html
9802
-
9803
- // This function must also respect "skipped" points
9804
-
9805
- var previous = firstPoint.skip ? middlePoint : firstPoint,
9806
- current = middlePoint,
9807
- next = afterPoint.skip ? middlePoint : afterPoint;
9808
-
9809
- var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
9810
- var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
9811
-
9812
- var s01 = d01 / (d01 + d12);
9813
- var s12 = d12 / (d01 + d12);
9814
-
9815
- // If all points are the same, s01 & s02 will be inf
9816
- s01 = isNaN(s01) ? 0 : s01;
9817
- s12 = isNaN(s12) ? 0 : s12;
9818
-
9819
- var fa = t * s01; // scaling factor for triangle Ta
9820
- var fb = t * s12;
9821
-
9822
- return {
9823
- previous: {
9824
- x: current.x - fa * (next.x - previous.x),
9825
- y: current.y - fa * (next.y - previous.y)
9826
- },
9827
- next: {
9828
- x: current.x + fb * (next.x - previous.x),
9829
- y: current.y + fb * (next.y - previous.y)
9830
- }
9831
- };
9832
- };
9833
- helpers.EPSILON = Number.EPSILON || 1e-14;
9834
- helpers.splineCurveMonotone = function(points) {
9835
- // This function calculates Bézier control points in a similar way than |splineCurve|,
9836
- // but preserves monotonicity of the provided data and ensures no local extremums are added
9837
- // between the dataset discrete points due to the interpolation.
9838
- // See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
9839
-
9840
- var pointsWithTangents = (points || []).map(function(point) {
9841
- return {
9842
- model: point._model,
9843
- deltaK: 0,
9844
- mK: 0
9845
- };
9846
- });
9847
-
9848
- // Calculate slopes (deltaK) and initialize tangents (mK)
9849
- var pointsLen = pointsWithTangents.length;
9850
- var i, pointBefore, pointCurrent, pointAfter;
9851
- for (i = 0; i < pointsLen; ++i) {
9852
- pointCurrent = pointsWithTangents[i];
9853
- if (pointCurrent.model.skip) {
9854
- continue;
9855
- }
9856
-
9857
- pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
9858
- pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
9859
- if (pointAfter && !pointAfter.model.skip) {
9860
- var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
9861
-
9862
- // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
9863
- pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
9864
- }
9865
-
9866
- if (!pointBefore || pointBefore.model.skip) {
9867
- pointCurrent.mK = pointCurrent.deltaK;
9868
- } else if (!pointAfter || pointAfter.model.skip) {
9869
- pointCurrent.mK = pointBefore.deltaK;
9870
- } else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
9871
- pointCurrent.mK = 0;
9872
- } else {
9873
- pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
9874
- }
9875
- }
9876
-
9877
- // Adjust tangents to ensure monotonic properties
9878
- var alphaK, betaK, tauK, squaredMagnitude;
9879
- for (i = 0; i < pointsLen - 1; ++i) {
9880
- pointCurrent = pointsWithTangents[i];
9881
- pointAfter = pointsWithTangents[i + 1];
9882
- if (pointCurrent.model.skip || pointAfter.model.skip) {
9883
- continue;
9884
- }
9885
-
9886
- if (helpers.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
9887
- pointCurrent.mK = pointAfter.mK = 0;
9888
- continue;
9889
- }
9890
-
9891
- alphaK = pointCurrent.mK / pointCurrent.deltaK;
9892
- betaK = pointAfter.mK / pointCurrent.deltaK;
9893
- squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
9894
- if (squaredMagnitude <= 9) {
9895
- continue;
9896
- }
9897
-
9898
- tauK = 3 / Math.sqrt(squaredMagnitude);
9899
- pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
9900
- pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
9901
- }
9902
-
9903
- // Compute control points
9904
- var deltaX;
9905
- for (i = 0; i < pointsLen; ++i) {
9906
- pointCurrent = pointsWithTangents[i];
9907
- if (pointCurrent.model.skip) {
9908
- continue;
9909
- }
9910
-
9911
- pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
9912
- pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
9913
- if (pointBefore && !pointBefore.model.skip) {
9914
- deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
9915
- pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
9916
- pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
9917
- }
9918
- if (pointAfter && !pointAfter.model.skip) {
9919
- deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
9920
- pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
9921
- pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
9922
- }
9923
- }
9924
- };
9925
- helpers.nextItem = function(collection, index, loop) {
9926
- if (loop) {
9927
- return index >= collection.length - 1 ? collection[0] : collection[index + 1];
9928
- }
9929
- return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
9930
- };
9931
- helpers.previousItem = function(collection, index, loop) {
9932
- if (loop) {
9933
- return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
9934
- }
9935
- return index <= 0 ? collection[0] : collection[index - 1];
9936
- };
9937
- // Implementation of the nice number algorithm used in determining where axis labels will go
9938
- helpers.niceNum = function(range, round) {
9939
- var exponent = Math.floor(helpers.log10(range));
9940
- var fraction = range / Math.pow(10, exponent);
9941
- var niceFraction;
9942
-
9943
- if (round) {
9944
- if (fraction < 1.5) {
9945
- niceFraction = 1;
9946
- } else if (fraction < 3) {
9947
- niceFraction = 2;
9948
- } else if (fraction < 7) {
9949
- niceFraction = 5;
9950
- } else {
9951
- niceFraction = 10;
9952
- }
9953
- } else if (fraction <= 1.0) {
9954
- niceFraction = 1;
9955
- } else if (fraction <= 2) {
9956
- niceFraction = 2;
9957
- } else if (fraction <= 5) {
9958
- niceFraction = 5;
9959
- } else {
9960
- niceFraction = 10;
9961
- }
9962
-
9963
- return niceFraction * Math.pow(10, exponent);
9964
- };
9965
- // Easing functions adapted from Robert Penner's easing equations
9966
- // http://www.robertpenner.com/easing/
9967
- var easingEffects = helpers.easingEffects = {
9968
- linear: function(t) {
9969
- return t;
9970
- },
9971
- easeInQuad: function(t) {
9972
- return t * t;
9973
- },
9974
- easeOutQuad: function(t) {
9975
- return -1 * t * (t - 2);
9976
- },
9977
- easeInOutQuad: function(t) {
9978
- if ((t /= 1 / 2) < 1) {
9979
- return 1 / 2 * t * t;
9980
- }
9981
- return -1 / 2 * ((--t) * (t - 2) - 1);
9982
- },
9983
- easeInCubic: function(t) {
9984
- return t * t * t;
9985
- },
9986
- easeOutCubic: function(t) {
9987
- return 1 * ((t = t / 1 - 1) * t * t + 1);
9988
- },
9989
- easeInOutCubic: function(t) {
9990
- if ((t /= 1 / 2) < 1) {
9991
- return 1 / 2 * t * t * t;
9992
- }
9993
- return 1 / 2 * ((t -= 2) * t * t + 2);
9994
- },
9995
- easeInQuart: function(t) {
9996
- return t * t * t * t;
9997
- },
9998
- easeOutQuart: function(t) {
9999
- return -1 * ((t = t / 1 - 1) * t * t * t - 1);
10000
- },
10001
- easeInOutQuart: function(t) {
10002
- if ((t /= 1 / 2) < 1) {
10003
- return 1 / 2 * t * t * t * t;
10004
- }
10005
- return -1 / 2 * ((t -= 2) * t * t * t - 2);
10006
- },
10007
- easeInQuint: function(t) {
10008
- return 1 * (t /= 1) * t * t * t * t;
10009
- },
10010
- easeOutQuint: function(t) {
10011
- return 1 * ((t = t / 1 - 1) * t * t * t * t + 1);
10012
- },
10013
- easeInOutQuint: function(t) {
10014
- if ((t /= 1 / 2) < 1) {
10015
- return 1 / 2 * t * t * t * t * t;
10016
- }
10017
- return 1 / 2 * ((t -= 2) * t * t * t * t + 2);
10018
- },
10019
- easeInSine: function(t) {
10020
- return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1;
10021
- },
10022
- easeOutSine: function(t) {
10023
- return 1 * Math.sin(t / 1 * (Math.PI / 2));
10024
- },
10025
- easeInOutSine: function(t) {
10026
- return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1);
10027
- },
10028
- easeInExpo: function(t) {
10029
- return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1));
10030
- },
10031
- easeOutExpo: function(t) {
10032
- return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1);
10033
- },
10034
- easeInOutExpo: function(t) {
10035
- if (t === 0) {
10036
- return 0;
10037
- }
10038
- if (t === 1) {
10039
- return 1;
10040
- }
10041
- if ((t /= 1 / 2) < 1) {
10042
- return 1 / 2 * Math.pow(2, 10 * (t - 1));
10043
- }
10044
- return 1 / 2 * (-Math.pow(2, -10 * --t) + 2);
10045
- },
10046
- easeInCirc: function(t) {
10047
- if (t >= 1) {
10048
- return t;
10049
- }
10050
- return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1);
10051
- },
10052
- easeOutCirc: function(t) {
10053
- return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t);
10054
- },
10055
- easeInOutCirc: function(t) {
10056
- if ((t /= 1 / 2) < 1) {
10057
- return -1 / 2 * (Math.sqrt(1 - t * t) - 1);
10058
- }
10059
- return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1);
10060
- },
10061
- easeInElastic: function(t) {
10062
- var s = 1.70158;
10063
- var p = 0;
10064
- var a = 1;
10065
- if (t === 0) {
10066
- return 0;
10067
- }
10068
- if ((t /= 1) === 1) {
10069
- return 1;
10070
- }
10071
- if (!p) {
10072
- p = 1 * 0.3;
10073
- }
10074
- if (a < Math.abs(1)) {
10075
- a = 1;
10076
- s = p / 4;
10077
- } else {
10078
- s = p / (2 * Math.PI) * Math.asin(1 / a);
10079
- }
10080
- return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
10081
- },
10082
- easeOutElastic: function(t) {
10083
- var s = 1.70158;
10084
- var p = 0;
10085
- var a = 1;
10086
- if (t === 0) {
10087
- return 0;
10088
- }
10089
- if ((t /= 1) === 1) {
10090
- return 1;
10091
- }
10092
- if (!p) {
10093
- p = 1 * 0.3;
10094
- }
10095
- if (a < Math.abs(1)) {
10096
- a = 1;
10097
- s = p / 4;
10098
- } else {
10099
- s = p / (2 * Math.PI) * Math.asin(1 / a);
10100
- }
10101
- return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
10102
- },
10103
- easeInOutElastic: function(t) {
10104
- var s = 1.70158;
10105
- var p = 0;
10106
- var a = 1;
10107
- if (t === 0) {
10108
- return 0;
10109
- }
10110
- if ((t /= 1 / 2) === 2) {
10111
- return 1;
10112
- }
10113
- if (!p) {
10114
- p = 1 * (0.3 * 1.5);
10115
- }
10116
- if (a < Math.abs(1)) {
10117
- a = 1;
10118
- s = p / 4;
10119
- } else {
10120
- s = p / (2 * Math.PI) * Math.asin(1 / a);
10121
- }
10122
- if (t < 1) {
10123
- return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
10124
- }
10125
- return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1;
10126
- },
10127
- easeInBack: function(t) {
10128
- var s = 1.70158;
10129
- return 1 * (t /= 1) * t * ((s + 1) * t - s);
10130
- },
10131
- easeOutBack: function(t) {
10132
- var s = 1.70158;
10133
- return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1);
10134
- },
10135
- easeInOutBack: function(t) {
10136
- var s = 1.70158;
10137
- if ((t /= 1 / 2) < 1) {
10138
- return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s));
10139
- }
10140
- return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
10141
- },
10142
- easeInBounce: function(t) {
10143
- return 1 - easingEffects.easeOutBounce(1 - t);
10144
- },
10145
- easeOutBounce: function(t) {
10146
- if ((t /= 1) < (1 / 2.75)) {
10147
- return 1 * (7.5625 * t * t);
10148
- } else if (t < (2 / 2.75)) {
10149
- return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75);
10150
- } else if (t < (2.5 / 2.75)) {
10151
- return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375);
10152
- }
10153
- return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375);
10154
- },
10155
- easeInOutBounce: function(t) {
10156
- if (t < 1 / 2) {
10157
- return easingEffects.easeInBounce(t * 2) * 0.5;
10158
- }
10159
- return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5;
10160
- }
10161
- };
10162
- // Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
10163
- helpers.requestAnimFrame = (function() {
10164
- if (typeof window === 'undefined') {
10165
- return function(callback) {
10166
- callback();
10167
- };
10168
- }
10169
- return window.requestAnimationFrame ||
10170
- window.webkitRequestAnimationFrame ||
10171
- window.mozRequestAnimationFrame ||
10172
- window.oRequestAnimationFrame ||
10173
- window.msRequestAnimationFrame ||
10174
- function(callback) {
10175
- return window.setTimeout(callback, 1000 / 60);
10176
- };
10177
- }());
10178
- // -- DOM methods
10179
- helpers.getRelativePosition = function(evt, chart) {
10180
- var mouseX, mouseY;
10181
- var e = evt.originalEvent || evt,
10182
- canvas = evt.currentTarget || evt.srcElement,
10183
- boundingRect = canvas.getBoundingClientRect();
10184
-
10185
- var touches = e.touches;
10186
- if (touches && touches.length > 0) {
10187
- mouseX = touches[0].clientX;
10188
- mouseY = touches[0].clientY;
10189
-
10190
- } else {
10191
- mouseX = e.clientX;
10192
- mouseY = e.clientY;
10193
- }
10194
-
10195
- // Scale mouse coordinates into canvas coordinates
10196
- // by following the pattern laid out by 'jerryj' in the comments of
10197
- // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
10198
- var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
10199
- var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
10200
- var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
10201
- var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
10202
- var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
10203
- var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
10204
-
10205
- // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
10206
- // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
10207
- mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
10208
- mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
10209
-
10210
- return {
10211
- x: mouseX,
10212
- y: mouseY
10213
- };
10214
-
10215
- };
10216
- helpers.addEvent = function(node, eventType, method) {
10217
- if (node.addEventListener) {
10218
- node.addEventListener(eventType, method);
10219
- } else if (node.attachEvent) {
10220
- node.attachEvent('on' + eventType, method);
10221
- } else {
10222
- node['on' + eventType] = method;
10223
- }
10224
- };
10225
- helpers.removeEvent = function(node, eventType, handler) {
10226
- if (node.removeEventListener) {
10227
- node.removeEventListener(eventType, handler, false);
10228
- } else if (node.detachEvent) {
10229
- node.detachEvent('on' + eventType, handler);
10230
- } else {
10231
- node['on' + eventType] = helpers.noop;
10232
- }
10233
- };
10234
-
10235
- // Private helper function to convert max-width/max-height values that may be percentages into a number
10236
- function parseMaxStyle(styleValue, node, parentProperty) {
10237
- var valueInPixels;
10238
- if (typeof(styleValue) === 'string') {
10239
- valueInPixels = parseInt(styleValue, 10);
10240
-
10241
- if (styleValue.indexOf('%') !== -1) {
10242
- // percentage * size in dimension
10243
- valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
10244
- }
10245
- } else {
10246
- valueInPixels = styleValue;
10247
- }
10248
-
10249
- return valueInPixels;
10250
- }
10251
-
10252
- /**
10253
- * Returns if the given value contains an effective constraint.
10254
- * @private
10255
- */
10256
- function isConstrainedValue(value) {
10257
- return value !== undefined && value !== null && value !== 'none';
10258
- }
10259
-
10260
- // Private helper to get a constraint dimension
10261
- // @param domNode : the node to check the constraint on
10262
- // @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
10263
- // @param percentageProperty : property of parent to use when calculating width as a percentage
10264
- // @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
10265
- function getConstraintDimension(domNode, maxStyle, percentageProperty) {
10266
- var view = document.defaultView;
10267
- var parentNode = domNode.parentNode;
10268
- var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
10269
- var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
10270
- var hasCNode = isConstrainedValue(constrainedNode);
10271
- var hasCContainer = isConstrainedValue(constrainedContainer);
10272
- var infinity = Number.POSITIVE_INFINITY;
10273
-
10274
- if (hasCNode || hasCContainer) {
10275
- return Math.min(
10276
- hasCNode? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
10277
- hasCContainer? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
10278
- }
10279
-
10280
- return 'none';
10281
- }
10282
- // returns Number or undefined if no constraint
10283
- helpers.getConstraintWidth = function(domNode) {
10284
- return getConstraintDimension(domNode, 'max-width', 'clientWidth');
10285
- };
10286
- // returns Number or undefined if no constraint
10287
- helpers.getConstraintHeight = function(domNode) {
10288
- return getConstraintDimension(domNode, 'max-height', 'clientHeight');
10289
- };
10290
- helpers.getMaximumWidth = function(domNode) {
10291
- var container = domNode.parentNode;
10292
- var paddingLeft = parseInt(helpers.getStyle(container, 'padding-left'), 10);
10293
- var paddingRight = parseInt(helpers.getStyle(container, 'padding-right'), 10);
10294
- var w = container.clientWidth - paddingLeft - paddingRight;
10295
- var cw = helpers.getConstraintWidth(domNode);
10296
- return isNaN(cw)? w : Math.min(w, cw);
10297
- };
10298
- helpers.getMaximumHeight = function(domNode) {
10299
- var container = domNode.parentNode;
10300
- var paddingTop = parseInt(helpers.getStyle(container, 'padding-top'), 10);
10301
- var paddingBottom = parseInt(helpers.getStyle(container, 'padding-bottom'), 10);
10302
- var h = container.clientHeight - paddingTop - paddingBottom;
10303
- var ch = helpers.getConstraintHeight(domNode);
10304
- return isNaN(ch)? h : Math.min(h, ch);
10305
- };
10306
- helpers.getStyle = function(el, property) {
10307
- return el.currentStyle ?
10308
- el.currentStyle[property] :
10309
- document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
10310
- };
10311
- helpers.retinaScale = function(chart) {
10312
- var pixelRatio = chart.currentDevicePixelRatio = window.devicePixelRatio || 1;
10313
- if (pixelRatio === 1) {
10314
- return;
10315
- }
10316
-
10317
- var canvas = chart.canvas;
10318
- var height = chart.height;
10319
- var width = chart.width;
10320
-
10321
- canvas.height = height * pixelRatio;
10322
- canvas.width = width * pixelRatio;
10323
- chart.ctx.scale(pixelRatio, pixelRatio);
10324
-
10325
- // If no style has been set on the canvas, the render size is used as display size,
10326
- // making the chart visually bigger, so let's enforce it to the "correct" values.
10327
- // See https://github.com/chartjs/Chart.js/issues/3575
10328
- canvas.style.height = height + 'px';
10329
- canvas.style.width = width + 'px';
10330
- };
10331
- // -- Canvas methods
10332
- helpers.clear = function(chart) {
10333
- chart.ctx.clearRect(0, 0, chart.width, chart.height);
10334
- };
10335
- helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
10336
- return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
10337
- };
10338
- helpers.longestText = function(ctx, font, arrayOfThings, cache) {
10339
- cache = cache || {};
10340
- var data = cache.data = cache.data || {};
10341
- var gc = cache.garbageCollect = cache.garbageCollect || [];
10342
-
10343
- if (cache.font !== font) {
10344
- data = cache.data = {};
10345
- gc = cache.garbageCollect = [];
10346
- cache.font = font;
10347
- }
10348
-
10349
- ctx.font = font;
10350
- var longest = 0;
10351
- helpers.each(arrayOfThings, function(thing) {
10352
- // Undefined strings and arrays should not be measured
10353
- if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
10354
- longest = helpers.measureText(ctx, data, gc, longest, thing);
10355
- } else if (helpers.isArray(thing)) {
10356
- // if it is an array lets measure each element
10357
- // to do maybe simplify this function a bit so we can do this more recursively?
10358
- helpers.each(thing, function(nestedThing) {
10359
- // Undefined strings and arrays should not be measured
10360
- if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
10361
- longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
10362
- }
10363
- });
10364
- }
10365
- });
10366
-
10367
- var gcLen = gc.length / 2;
10368
- if (gcLen > arrayOfThings.length) {
10369
- for (var i = 0; i < gcLen; i++) {
10370
- delete data[gc[i]];
10371
- }
10372
- gc.splice(0, gcLen);
10373
- }
10374
- return longest;
10375
- };
10376
- helpers.measureText = function(ctx, data, gc, longest, string) {
10377
- var textWidth = data[string];
10378
- if (!textWidth) {
10379
- textWidth = data[string] = ctx.measureText(string).width;
10380
- gc.push(string);
10381
- }
10382
- if (textWidth > longest) {
10383
- longest = textWidth;
10384
- }
10385
- return longest;
10386
- };
10387
- helpers.numberOfLabelLines = function(arrayOfThings) {
10388
- var numberOfLines = 1;
10389
- helpers.each(arrayOfThings, function(thing) {
10390
- if (helpers.isArray(thing)) {
10391
- if (thing.length > numberOfLines) {
10392
- numberOfLines = thing.length;
10393
- }
10394
- }
10395
- });
10396
- return numberOfLines;
10397
- };
10398
- helpers.drawRoundedRectangle = function(ctx, x, y, width, height, radius) {
10399
- ctx.beginPath();
10400
- ctx.moveTo(x + radius, y);
10401
- ctx.lineTo(x + width - radius, y);
10402
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
10403
- ctx.lineTo(x + width, y + height - radius);
10404
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
10405
- ctx.lineTo(x + radius, y + height);
10406
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
10407
- ctx.lineTo(x, y + radius);
10408
- ctx.quadraticCurveTo(x, y, x + radius, y);
10409
- ctx.closePath();
10410
- };
10411
-
10412
- helpers.color = !color?
10413
- function(value) {
10414
- console.error('Color.js not found!');
10415
- return value;
10416
- } :
10417
- function(value) {
10418
- /* global CanvasGradient */
10419
- if (value instanceof CanvasGradient) {
10420
- value = Chart.defaults.global.defaultColor;
10421
- }
10422
-
10423
- return color(value);
10424
- };
10425
-
10426
- helpers.isArray = Array.isArray?
10427
- function(obj) {
10428
- return Array.isArray(obj);
10429
- } :
10430
- function(obj) {
10431
- return Object.prototype.toString.call(obj) === '[object Array]';
10432
- };
10433
- // ! @see http://stackoverflow.com/a/14853974
10434
- helpers.arrayEquals = function(a0, a1) {
10435
- var i, ilen, v0, v1;
10436
-
10437
- if (!a0 || !a1 || a0.length !== a1.length) {
10438
- return false;
10439
- }
10440
-
10441
- for (i = 0, ilen=a0.length; i < ilen; ++i) {
10442
- v0 = a0[i];
10443
- v1 = a1[i];
10444
-
10445
- if (v0 instanceof Array && v1 instanceof Array) {
10446
- if (!helpers.arrayEquals(v0, v1)) {
10447
- return false;
10448
- }
10449
- } else if (v0 !== v1) {
10450
- // NOTE: two different object instances will never be equal: {x:20} != {x:20}
10451
- return false;
10452
- }
10453
- }
10454
-
10455
- return true;
10456
- };
10457
- helpers.callback = function(fn, args, thisArg) {
10458
- if (fn && typeof fn.call === 'function') {
10459
- fn.apply(thisArg, args);
10460
- }
10461
- };
10462
- helpers.getHoverColor = function(colorValue) {
10463
- /* global CanvasPattern */
10464
- return (colorValue instanceof CanvasPattern) ?
10465
- colorValue :
10466
- helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
10467
- };
10468
-
10469
- /**
10470
- * Provided for backward compatibility, use Chart.helpers#callback instead.
10471
- * @function Chart.helpers#callCallback
10472
- * @deprecated since version 2.6.0
10473
- * @todo remove at version 3
10474
- */
10475
- helpers.callCallback = helpers.callback;
10476
- };
10477
-
10478
- },{"2":2}],27:[function(require,module,exports){
10479
- 'use strict';
10480
-
10481
- module.exports = function(Chart) {
10482
- var helpers = Chart.helpers;
10483
-
10484
- /**
10485
- * Helper function to get relative position for an event
10486
- * @param {Event|IEvent} event - The event to get the position for
10487
- * @param {Chart} chart - The chart
10488
- * @returns {Point} the event position
10489
- */
10490
- function getRelativePosition(e, chart) {
10491
- if (e.native) {
10492
- return {
10493
- x: e.x,
10494
- y: e.y
10495
- };
10496
- }
10497
-
10498
- return helpers.getRelativePosition(e, chart);
10499
- }
10500
-
10501
- /**
10502
- * Helper function to traverse all of the visible elements in the chart
10503
- * @param chart {chart} the chart
10504
- * @param handler {Function} the callback to execute for each visible item
10505
- */
10506
- function parseVisibleItems(chart, handler) {
10507
- var datasets = chart.data.datasets;
10508
- var meta, i, j, ilen, jlen;
10509
-
10510
- for (i = 0, ilen = datasets.length; i < ilen; ++i) {
10511
- if (!chart.isDatasetVisible(i)) {
10512
- continue;
10513
- }
10514
-
10515
- meta = chart.getDatasetMeta(i);
10516
- for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
10517
- var element = meta.data[j];
10518
- if (!element._view.skip) {
10519
- handler(element);
10520
- }
10521
- }
10522
- }
10523
- }
10524
-
10525
- /**
10526
- * Helper function to get the items that intersect the event position
10527
- * @param items {ChartElement[]} elements to filter
10528
- * @param position {Point} the point to be nearest to
10529
- * @return {ChartElement[]} the nearest items
10530
- */
10531
- function getIntersectItems(chart, position) {
10532
- var elements = [];
10533
-
10534
- parseVisibleItems(chart, function(element) {
10535
- if (element.inRange(position.x, position.y)) {
10536
- elements.push(element);
10537
- }
10538
- });
10539
-
10540
- return elements;
10541
- }
10542
-
10543
- /**
10544
- * Helper function to get the items nearest to the event position considering all visible items in teh chart
10545
- * @param chart {Chart} the chart to look at elements from
10546
- * @param position {Point} the point to be nearest to
10547
- * @param intersect {Boolean} if true, only consider items that intersect the position
10548
- * @param distanceMetric {Function} Optional function to provide the distance between
10549
- * @return {ChartElement[]} the nearest items
10550
- */
10551
- function getNearestItems(chart, position, intersect, distanceMetric) {
10552
- var minDistance = Number.POSITIVE_INFINITY;
10553
- var nearestItems = [];
10554
-
10555
- if (!distanceMetric) {
10556
- distanceMetric = helpers.distanceBetweenPoints;
10557
- }
10558
-
10559
- parseVisibleItems(chart, function(element) {
10560
- if (intersect && !element.inRange(position.x, position.y)) {
10561
- return;
10562
- }
10563
-
10564
- var center = element.getCenterPoint();
10565
- var distance = distanceMetric(position, center);
10566
-
10567
- if (distance < minDistance) {
10568
- nearestItems = [element];
10569
- minDistance = distance;
10570
- } else if (distance === minDistance) {
10571
- // Can have multiple items at the same distance in which case we sort by size
10572
- nearestItems.push(element);
10573
- }
10574
- });
10575
-
10576
- return nearestItems;
10577
- }
10578
-
10579
- function indexMode(chart, e, options) {
10580
- var position = getRelativePosition(e, chart);
10581
- var distanceMetric = function(pt1, pt2) {
10582
- return Math.abs(pt1.x - pt2.x);
10583
- };
10584
- var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
10585
- var elements = [];
10586
-
10587
- if (!items.length) {
10588
- return [];
10589
- }
10590
-
10591
- chart.data.datasets.forEach(function(dataset, datasetIndex) {
10592
- if (chart.isDatasetVisible(datasetIndex)) {
10593
- var meta = chart.getDatasetMeta(datasetIndex),
10594
- element = meta.data[items[0]._index];
10595
-
10596
- // don't count items that are skipped (null data)
10597
- if (element && !element._view.skip) {
10598
- elements.push(element);
10599
- }
10600
- }
10601
- });
10602
-
10603
- return elements;
10604
- }
10605
-
10606
- /**
10607
- * @interface IInteractionOptions
10608
- */
10609
- /**
10610
- * If true, only consider items that intersect the point
10611
- * @name IInterfaceOptions#boolean
10612
- * @type Boolean
10613
- */
10614
-
10615
- /**
10616
- * Contains interaction related functions
10617
- * @namespace Chart.Interaction
10618
- */
10619
- Chart.Interaction = {
10620
- // Helper function for different modes
10621
- modes: {
10622
- single: function(chart, e) {
10623
- var position = getRelativePosition(e, chart);
10624
- var elements = [];
10625
-
10626
- parseVisibleItems(chart, function(element) {
10627
- if (element.inRange(position.x, position.y)) {
10628
- elements.push(element);
10629
- return elements;
10630
- }
10631
- });
10632
-
10633
- return elements.slice(0, 1);
10634
- },
10635
-
10636
- /**
10637
- * @function Chart.Interaction.modes.label
10638
- * @deprecated since version 2.4.0
10639
- * @todo remove at version 3
10640
- * @private
10641
- */
10642
- label: indexMode,
10643
-
10644
- /**
10645
- * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
10646
- * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
10647
- * @function Chart.Interaction.modes.index
10648
- * @since v2.4.0
10649
- * @param chart {chart} the chart we are returning items from
10650
- * @param e {Event} the event we are find things at
10651
- * @param options {IInteractionOptions} options to use during interaction
10652
- * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10653
- */
10654
- index: indexMode,
10655
-
10656
- /**
10657
- * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
10658
- * If the options.intersect is false, we find the nearest item and return the items in that dataset
10659
- * @function Chart.Interaction.modes.dataset
10660
- * @param chart {chart} the chart we are returning items from
10661
- * @param e {Event} the event we are find things at
10662
- * @param options {IInteractionOptions} options to use during interaction
10663
- * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10664
- */
10665
- dataset: function(chart, e, options) {
10666
- var position = getRelativePosition(e, chart);
10667
- var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false);
10668
-
10669
- if (items.length > 0) {
10670
- items = chart.getDatasetMeta(items[0]._datasetIndex).data;
10671
- }
10672
-
10673
- return items;
10674
- },
10675
-
10676
- /**
10677
- * @function Chart.Interaction.modes.x-axis
10678
- * @deprecated since version 2.4.0. Use index mode and intersect == true
10679
- * @todo remove at version 3
10680
- * @private
10681
- */
10682
- 'x-axis': function(chart, e) {
10683
- return indexMode(chart, e, true);
10684
- },
10685
-
10686
- /**
10687
- * Point mode returns all elements that hit test based on the event position
10688
- * of the event
10689
- * @function Chart.Interaction.modes.intersect
10690
- * @param chart {chart} the chart we are returning items from
10691
- * @param e {Event} the event we are find things at
10692
- * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10693
- */
10694
- point: function(chart, e) {
10695
- var position = getRelativePosition(e, chart);
10696
- return getIntersectItems(chart, position);
10697
- },
10698
-
10699
- /**
10700
- * nearest mode returns the element closest to the point
10701
- * @function Chart.Interaction.modes.intersect
10702
- * @param chart {chart} the chart we are returning items from
10703
- * @param e {Event} the event we are find things at
10704
- * @param options {IInteractionOptions} options to use
10705
- * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10706
- */
10707
- nearest: function(chart, e, options) {
10708
- var position = getRelativePosition(e, chart);
10709
- var nearestItems = getNearestItems(chart, position, options.intersect);
10710
-
10711
- // We have multiple items at the same distance from the event. Now sort by smallest
10712
- if (nearestItems.length > 1) {
10713
- nearestItems.sort(function(a, b) {
10714
- var sizeA = a.getArea();
10715
- var sizeB = b.getArea();
10716
- var ret = sizeA - sizeB;
10717
-
10718
- if (ret === 0) {
10719
- // if equal sort by dataset index
10720
- ret = a._datasetIndex - b._datasetIndex;
10721
- }
10722
-
10723
- return ret;
10724
- });
10725
- }
10726
-
10727
- // Return only 1 item
10728
- return nearestItems.slice(0, 1);
10729
- },
10730
-
10731
- /**
10732
- * x mode returns the elements that hit-test at the current x coordinate
10733
- * @function Chart.Interaction.modes.x
10734
- * @param chart {chart} the chart we are returning items from
10735
- * @param e {Event} the event we are find things at
10736
- * @param options {IInteractionOptions} options to use
10737
- * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10738
- */
10739
- x: function(chart, e, options) {
10740
- var position = getRelativePosition(e, chart);
10741
- var items = [];
10742
- var intersectsItem = false;
10743
-
10744
- parseVisibleItems(chart, function(element) {
10745
- if (element.inXRange(position.x)) {
10746
- items.push(element);
10747
- }
10748
-
10749
- if (element.inRange(position.x, position.y)) {
10750
- intersectsItem = true;
10751
- }
10752
- });
10753
-
10754
- // If we want to trigger on an intersect and we don't have any items
10755
- // that intersect the position, return nothing
10756
- if (options.intersect && !intersectsItem) {
10757
- items = [];
10758
- }
10759
- return items;
10760
- },
10761
-
10762
- /**
10763
- * y mode returns the elements that hit-test at the current y coordinate
10764
- * @function Chart.Interaction.modes.y
10765
- * @param chart {chart} the chart we are returning items from
10766
- * @param e {Event} the event we are find things at
10767
- * @param options {IInteractionOptions} options to use
10768
- * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
10769
- */
10770
- y: function(chart, e, options) {
10771
- var position = getRelativePosition(e, chart);
10772
- var items = [];
10773
- var intersectsItem = false;
10774
-
10775
- parseVisibleItems(chart, function(element) {
10776
- if (element.inYRange(position.y)) {
10777
- items.push(element);
10778
- }
10779
-
10780
- if (element.inRange(position.x, position.y)) {
10781
- intersectsItem = true;
10782
- }
10783
- });
10784
-
10785
- // If we want to trigger on an intersect and we don't have any items
10786
- // that intersect the position, return nothing
10787
- if (options.intersect && !intersectsItem) {
10788
- items = [];
10789
- }
10790
- return items;
10791
- }
10792
- }
10793
- };
10794
- };
10795
-
10796
- },{}],28:[function(require,module,exports){
10797
- 'use strict';
10798
-
10799
- module.exports = function() {
10800
-
10801
- // Occupy the global variable of Chart, and create a simple base class
10802
- var Chart = function(item, config) {
10803
- this.construct(item, config);
10804
- return this;
10805
- };
10806
-
10807
- // Globally expose the defaults to allow for user updating/changing
10808
- Chart.defaults = {
10809
- global: {
10810
- responsive: true,
10811
- responsiveAnimationDuration: 0,
10812
- maintainAspectRatio: true,
10813
- events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
10814
- hover: {
10815
- onHover: null,
10816
- mode: 'nearest',
10817
- intersect: true,
10818
- animationDuration: 400
10819
- },
10820
- onClick: null,
10821
- defaultColor: 'rgba(0,0,0,0.1)',
10822
- defaultFontColor: '#666',
10823
- defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
10824
- defaultFontSize: 12,
10825
- defaultFontStyle: 'normal',
10826
- showLines: true,
10827
-
10828
- // Element defaults defined in element extensions
10829
- elements: {},
10830
-
10831
- // Legend callback string
10832
- legendCallback: function(chart) {
10833
- var text = [];
10834
- text.push('<ul class="' + chart.id + '-legend">');
10835
- for (var i = 0; i < chart.data.datasets.length; i++) {
10836
- text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
10837
- if (chart.data.datasets[i].label) {
10838
- text.push(chart.data.datasets[i].label);
10839
- }
10840
- text.push('</li>');
10841
- }
10842
- text.push('</ul>');
10843
-
10844
- return text.join('');
10845
- }
10846
- }
10847
- };
10848
-
10849
- Chart.Chart = Chart;
10850
-
10851
- return Chart;
10852
- };
10853
-
10854
- },{}],29:[function(require,module,exports){
10855
- 'use strict';
10856
-
10857
- module.exports = function(Chart) {
10858
-
10859
- var helpers = Chart.helpers;
10860
-
10861
- function filterByPosition(array, position) {
10862
- return helpers.where(array, function(v) {
10863
- return v.position === position;
10864
- });
10865
- }
10866
-
10867
- function sortByWeight(array, reverse) {
10868
- array.forEach(function(v, i) {
10869
- v._tmpIndex_ = i;
10870
- return v;
10871
- });
10872
- array.sort(function(a, b) {
10873
- var v0 = reverse ? b : a;
10874
- var v1 = reverse ? a : b;
10875
- return v0.weight === v1.weight ?
10876
- v0._tmpIndex_ - v1._tmpIndex_ :
10877
- v0.weight - v1.weight;
10878
- });
10879
- array.forEach(function(v) {
10880
- delete v._tmpIndex_;
10881
- });
10882
- }
10883
-
10884
- /**
10885
- * @interface ILayoutItem
10886
- * @prop {String} position - The position of the item in the chart layout. Possible values are
10887
- * 'left', 'top', 'right', 'bottom', and 'chartArea'
10888
- * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
10889
- * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
10890
- * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
10891
- * @prop {Function} update - Takes two parameters: width and height. Returns size of item
10892
- * @prop {Function} getPadding - Returns an object with padding on the edges
10893
- * @prop {Number} width - Width of item. Must be valid after update()
10894
- * @prop {Number} height - Height of item. Must be valid after update()
10895
- * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
10896
- * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
10897
- * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
10898
- * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
10899
- */
10900
-
10901
- // The layout service is very self explanatory. It's responsible for the layout within a chart.
10902
- // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
10903
- // It is this service's responsibility of carrying out that layout.
10904
- Chart.layoutService = {
10905
- defaults: {},
10906
-
10907
- /**
10908
- * Register a box to a chart.
10909
- * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
10910
- * @param {Chart} chart - the chart to use
10911
- * @param {ILayoutItem} item - the item to add to be layed out
10912
- */
10913
- addBox: function(chart, item) {
10914
- if (!chart.boxes) {
10915
- chart.boxes = [];
10916
- }
10917
-
10918
- // initialize item with default values
10919
- item.fullWidth = item.fullWidth || false;
10920
- item.position = item.position || 'top';
10921
- item.weight = item.weight || 0;
10922
-
10923
- chart.boxes.push(item);
10924
- },
10925
-
10926
- /**
10927
- * Remove a layoutItem from a chart
10928
- * @param {Chart} chart - the chart to remove the box from
10929
- * @param {Object} layoutItem - the item to remove from the layout
10930
- */
10931
- removeBox: function(chart, layoutItem) {
10932
- var index = chart.boxes? chart.boxes.indexOf(layoutItem) : -1;
10933
- if (index !== -1) {
10934
- chart.boxes.splice(index, 1);
10935
- }
10936
- },
10937
-
10938
- /**
10939
- * Sets (or updates) options on the given `item`.
10940
- * @param {Chart} chart - the chart in which the item lives (or will be added to)
10941
- * @param {Object} item - the item to configure with the given options
10942
- * @param {Object} options - the new item options.
10943
- */
10944
- configure: function(chart, item, options) {
10945
- var props = ['fullWidth', 'position', 'weight'];
10946
- var ilen = props.length;
10947
- var i = 0;
10948
- var prop;
10949
-
10950
- for (; i<ilen; ++i) {
10951
- prop = props[i];
10952
- if (options.hasOwnProperty(prop)) {
10953
- item[prop] = options[prop];
10954
- }
10955
- }
10956
- },
10957
-
10958
- /**
10959
- * Fits boxes of the given chart into the given size by having each box measure itself
10960
- * then running a fitting algorithm
10961
- * @param {Chart} chart - the chart
10962
- * @param {Number} width - the width to fit into
10963
- * @param {Number} height - the height to fit into
10964
- */
10965
- update: function(chart, width, height) {
10966
- if (!chart) {
10967
- return;
10968
- }
10969
-
10970
- var layoutOptions = chart.options.layout;
10971
- var padding = layoutOptions ? layoutOptions.padding : null;
10972
-
10973
- var leftPadding = 0;
10974
- var rightPadding = 0;
10975
- var topPadding = 0;
10976
- var bottomPadding = 0;
10977
-
10978
- if (!isNaN(padding)) {
10979
- // options.layout.padding is a number. assign to all
10980
- leftPadding = padding;
10981
- rightPadding = padding;
10982
- topPadding = padding;
10983
- bottomPadding = padding;
10984
- } else {
10985
- leftPadding = padding.left || 0;
10986
- rightPadding = padding.right || 0;
10987
- topPadding = padding.top || 0;
10988
- bottomPadding = padding.bottom || 0;
10989
- }
10990
-
10991
- var leftBoxes = filterByPosition(chart.boxes, 'left');
10992
- var rightBoxes = filterByPosition(chart.boxes, 'right');
10993
- var topBoxes = filterByPosition(chart.boxes, 'top');
10994
- var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
10995
- var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');
10996
-
10997
- // Sort boxes by weight. A higher weight is further away from the chart area
10998
- sortByWeight(leftBoxes, true);
10999
- sortByWeight(rightBoxes, false);
11000
- sortByWeight(topBoxes, true);
11001
- sortByWeight(bottomBoxes, false);
11002
-
11003
- // Essentially we now have any number of boxes on each of the 4 sides.
11004
- // Our canvas looks like the following.
11005
- // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
11006
- // B1 is the bottom axis
11007
- // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
11008
- // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
11009
- // an error will be thrown.
11010
- //
11011
- // |----------------------------------------------------|
11012
- // | T1 (Full Width) |
11013
- // |----------------------------------------------------|
11014
- // | | | T2 | |
11015
- // | |----|-------------------------------------|----|
11016
- // | | | C1 | | C2 | |
11017
- // | | |----| |----| |
11018
- // | | | | |
11019
- // | L1 | L2 | ChartArea (C0) | R1 |
11020
- // | | | | |
11021
- // | | |----| |----| |
11022
- // | | | C3 | | C4 | |
11023
- // | |----|-------------------------------------|----|
11024
- // | | | B1 | |
11025
- // |----------------------------------------------------|
11026
- // | B2 (Full Width) |
11027
- // |----------------------------------------------------|
11028
- //
11029
- // What we do to find the best sizing, we do the following
11030
- // 1. Determine the minimum size of the chart area.
11031
- // 2. Split the remaining width equally between each vertical axis
11032
- // 3. Split the remaining height equally between each horizontal axis
11033
- // 4. Give each layout the maximum size it can be. The layout will return it's minimum size
11034
- // 5. Adjust the sizes of each axis based on it's minimum reported size.
11035
- // 6. Refit each axis
11036
- // 7. Position each axis in the final location
11037
- // 8. Tell the chart the final location of the chart area
11038
- // 9. Tell any axes that overlay the chart area the positions of the chart area
11039
-
11040
- // Step 1
11041
- var chartWidth = width - leftPadding - rightPadding;
11042
- var chartHeight = height - topPadding - bottomPadding;
11043
- var chartAreaWidth = chartWidth / 2; // min 50%
11044
- var chartAreaHeight = chartHeight / 2; // min 50%
11045
-
11046
- // Step 2
11047
- var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
11048
-
11049
- // Step 3
11050
- var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
11051
-
11052
- // Step 4
11053
- var maxChartAreaWidth = chartWidth;
11054
- var maxChartAreaHeight = chartHeight;
11055
- var minBoxSizes = [];
11056
-
11057
- function getMinimumBoxSize(box) {
11058
- var minSize;
11059
- var isHorizontal = box.isHorizontal();
11060
-
11061
- if (isHorizontal) {
11062
- minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
11063
- maxChartAreaHeight -= minSize.height;
11064
- } else {
11065
- minSize = box.update(verticalBoxWidth, chartAreaHeight);
11066
- maxChartAreaWidth -= minSize.width;
11067
- }
11068
-
11069
- minBoxSizes.push({
11070
- horizontal: isHorizontal,
11071
- minSize: minSize,
11072
- box: box,
11073
- });
11074
- }
11075
-
11076
- helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
11077
-
11078
- // If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
11079
- var maxHorizontalLeftPadding = 0;
11080
- var maxHorizontalRightPadding = 0;
11081
- var maxVerticalTopPadding = 0;
11082
- var maxVerticalBottomPadding = 0;
11083
-
11084
- helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
11085
- if (horizontalBox.getPadding) {
11086
- var boxPadding = horizontalBox.getPadding();
11087
- maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
11088
- maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
11089
- }
11090
- });
11091
-
11092
- helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
11093
- if (verticalBox.getPadding) {
11094
- var boxPadding = verticalBox.getPadding();
11095
- maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
11096
- maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
11097
- }
11098
- });
11099
-
11100
- // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
11101
- // be if the axes are drawn at their minimum sizes.
11102
- // Steps 5 & 6
11103
- var totalLeftBoxesWidth = leftPadding;
11104
- var totalRightBoxesWidth = rightPadding;
11105
- var totalTopBoxesHeight = topPadding;
11106
- var totalBottomBoxesHeight = bottomPadding;
11107
-
11108
- // Function to fit a box
11109
- function fitBox(box) {
11110
- var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBox) {
11111
- return minBox.box === box;
11112
- });
11113
-
11114
- if (minBoxSize) {
11115
- if (box.isHorizontal()) {
11116
- var scaleMargin = {
11117
- left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
11118
- right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
11119
- top: 0,
11120
- bottom: 0
11121
- };
11122
-
11123
- // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
11124
- // on the margin. Sometimes they need to increase in size slightly
11125
- box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
11126
- } else {
11127
- box.update(minBoxSize.minSize.width, maxChartAreaHeight);
11128
- }
11129
- }
11130
- }
11131
-
11132
- // Update, and calculate the left and right margins for the horizontal boxes
11133
- helpers.each(leftBoxes.concat(rightBoxes), fitBox);
11134
-
11135
- helpers.each(leftBoxes, function(box) {
11136
- totalLeftBoxesWidth += box.width;
11137
- });
11138
-
11139
- helpers.each(rightBoxes, function(box) {
11140
- totalRightBoxesWidth += box.width;
11141
- });
11142
-
11143
- // Set the Left and Right margins for the horizontal boxes
11144
- helpers.each(topBoxes.concat(bottomBoxes), fitBox);
11145
-
11146
- // Figure out how much margin is on the top and bottom of the vertical boxes
11147
- helpers.each(topBoxes, function(box) {
11148
- totalTopBoxesHeight += box.height;
11149
- });
11150
-
11151
- helpers.each(bottomBoxes, function(box) {
11152
- totalBottomBoxesHeight += box.height;
11153
- });
11154
-
11155
- function finalFitVerticalBox(box) {
11156
- var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) {
11157
- return minSize.box === box;
11158
- });
11159
-
11160
- var scaleMargin = {
11161
- left: 0,
11162
- right: 0,
11163
- top: totalTopBoxesHeight,
11164
- bottom: totalBottomBoxesHeight
11165
- };
11166
-
11167
- if (minBoxSize) {
11168
- box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
11169
- }
11170
- }
11171
-
11172
- // Let the left layout know the final margin
11173
- helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
11174
-
11175
- // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
11176
- totalLeftBoxesWidth = leftPadding;
11177
- totalRightBoxesWidth = rightPadding;
11178
- totalTopBoxesHeight = topPadding;
11179
- totalBottomBoxesHeight = bottomPadding;
11180
-
11181
- helpers.each(leftBoxes, function(box) {
11182
- totalLeftBoxesWidth += box.width;
11183
- });
11184
-
11185
- helpers.each(rightBoxes, function(box) {
11186
- totalRightBoxesWidth += box.width;
11187
- });
11188
-
11189
- helpers.each(topBoxes, function(box) {
11190
- totalTopBoxesHeight += box.height;
11191
- });
11192
- helpers.each(bottomBoxes, function(box) {
11193
- totalBottomBoxesHeight += box.height;
11194
- });
11195
-
11196
- // We may be adding some padding to account for rotated x axis labels
11197
- var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
11198
- totalLeftBoxesWidth += leftPaddingAddition;
11199
- totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);
11200
-
11201
- var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
11202
- totalTopBoxesHeight += topPaddingAddition;
11203
- totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);
11204
-
11205
- // Figure out if our chart area changed. This would occur if the dataset layout label rotation
11206
- // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
11207
- // without calling `fit` again
11208
- var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
11209
- var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
11210
-
11211
- if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
11212
- helpers.each(leftBoxes, function(box) {
11213
- box.height = newMaxChartAreaHeight;
11214
- });
11215
-
11216
- helpers.each(rightBoxes, function(box) {
11217
- box.height = newMaxChartAreaHeight;
11218
- });
11219
-
11220
- helpers.each(topBoxes, function(box) {
11221
- if (!box.fullWidth) {
11222
- box.width = newMaxChartAreaWidth;
11223
- }
11224
- });
11225
-
11226
- helpers.each(bottomBoxes, function(box) {
11227
- if (!box.fullWidth) {
11228
- box.width = newMaxChartAreaWidth;
11229
- }
11230
- });
11231
-
11232
- maxChartAreaHeight = newMaxChartAreaHeight;
11233
- maxChartAreaWidth = newMaxChartAreaWidth;
11234
- }
11235
-
11236
- // Step 7 - Position the boxes
11237
- var left = leftPadding + leftPaddingAddition;
11238
- var top = topPadding + topPaddingAddition;
11239
-
11240
- function placeBox(box) {
11241
- if (box.isHorizontal()) {
11242
- box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
11243
- box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
11244
- box.top = top;
11245
- box.bottom = top + box.height;
11246
-
11247
- // Move to next point
11248
- top = box.bottom;
11249
-
11250
- } else {
11251
-
11252
- box.left = left;
11253
- box.right = left + box.width;
11254
- box.top = totalTopBoxesHeight;
11255
- box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
11256
-
11257
- // Move to next point
11258
- left = box.right;
11259
- }
11260
- }
11261
-
11262
- helpers.each(leftBoxes.concat(topBoxes), placeBox);
11263
-
11264
- // Account for chart width and height
11265
- left += maxChartAreaWidth;
11266
- top += maxChartAreaHeight;
11267
-
11268
- helpers.each(rightBoxes, placeBox);
11269
- helpers.each(bottomBoxes, placeBox);
11270
-
11271
- // Step 8
11272
- chart.chartArea = {
11273
- left: totalLeftBoxesWidth,
11274
- top: totalTopBoxesHeight,
11275
- right: totalLeftBoxesWidth + maxChartAreaWidth,
11276
- bottom: totalTopBoxesHeight + maxChartAreaHeight
11277
- };
11278
-
11279
- // Step 9
11280
- helpers.each(chartAreaBoxes, function(box) {
11281
- box.left = chart.chartArea.left;
11282
- box.top = chart.chartArea.top;
11283
- box.right = chart.chartArea.right;
11284
- box.bottom = chart.chartArea.bottom;
11285
-
11286
- box.update(maxChartAreaWidth, maxChartAreaHeight);
11287
- });
11288
- }
11289
- };
11290
- };
11291
-
11292
- },{}],30:[function(require,module,exports){
11293
- 'use strict';
11294
-
11295
- module.exports = function(Chart) {
11296
-
11297
- var helpers = Chart.helpers;
11298
-
11299
- Chart.defaults.global.plugins = {};
11300
-
11301
- /**
11302
- * The plugin service singleton
11303
- * @namespace Chart.plugins
11304
- * @since 2.1.0
11305
- */
11306
- Chart.plugins = {
11307
- /**
11308
- * Globally registered plugins.
11309
- * @private
11310
- */
11311
- _plugins: [],
11312
-
11313
- /**
11314
- * This identifier is used to invalidate the descriptors cache attached to each chart
11315
- * when a global plugin is registered or unregistered. In this case, the cache ID is
11316
- * incremented and descriptors are regenerated during following API calls.
11317
- * @private
11318
- */
11319
- _cacheId: 0,
11320
-
11321
- /**
11322
- * Registers the given plugin(s) if not already registered.
11323
- * @param {Array|Object} plugins plugin instance(s).
11324
- */
11325
- register: function(plugins) {
11326
- var p = this._plugins;
11327
- ([]).concat(plugins).forEach(function(plugin) {
11328
- if (p.indexOf(plugin) === -1) {
11329
- p.push(plugin);
11330
- }
11331
- });
11332
-
11333
- this._cacheId++;
11334
- },
11335
-
11336
- /**
11337
- * Unregisters the given plugin(s) only if registered.
11338
- * @param {Array|Object} plugins plugin instance(s).
11339
- */
11340
- unregister: function(plugins) {
11341
- var p = this._plugins;
11342
- ([]).concat(plugins).forEach(function(plugin) {
11343
- var idx = p.indexOf(plugin);
11344
- if (idx !== -1) {
11345
- p.splice(idx, 1);
11346
- }
11347
- });
11348
-
11349
- this._cacheId++;
11350
- },
11351
-
11352
- /**
11353
- * Remove all registered plugins.
11354
- * @since 2.1.5
11355
- */
11356
- clear: function() {
11357
- this._plugins = [];
11358
- this._cacheId++;
11359
- },
11360
-
11361
- /**
11362
- * Returns the number of registered plugins?
11363
- * @returns {Number}
11364
- * @since 2.1.5
11365
- */
11366
- count: function() {
11367
- return this._plugins.length;
11368
- },
11369
-
11370
- /**
11371
- * Returns all registered plugin instances.
11372
- * @returns {Array} array of plugin objects.
11373
- * @since 2.1.5
11374
- */
11375
- getAll: function() {
11376
- return this._plugins;
11377
- },
11378
-
11379
- /**
11380
- * Calls enabled plugins for `chart` on the specified hook and with the given args.
11381
- * This method immediately returns as soon as a plugin explicitly returns false. The
11382
- * returned value can be used, for instance, to interrupt the current action.
11383
- * @param {Object} chart - The chart instance for which plugins should be called.
11384
- * @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
11385
- * @param {Array} [args] - Extra arguments to apply to the hook call.
11386
- * @returns {Boolean} false if any of the plugins return false, else returns true.
11387
- */
11388
- notify: function(chart, hook, args) {
11389
- var descriptors = this.descriptors(chart);
11390
- var ilen = descriptors.length;
11391
- var i, descriptor, plugin, params, method;
11392
-
11393
- for (i=0; i<ilen; ++i) {
11394
- descriptor = descriptors[i];
11395
- plugin = descriptor.plugin;
11396
- method = plugin[hook];
11397
- if (typeof method === 'function') {
11398
- params = [chart].concat(args || []);
11399
- params.push(descriptor.options);
11400
- if (method.apply(plugin, params) === false) {
11401
- return false;
11402
- }
11403
- }
11404
- }
11405
-
11406
- return true;
11407
- },
11408
-
11409
- /**
11410
- * Returns descriptors of enabled plugins for the given chart.
11411
- * @returns {Array} [{ plugin, options }]
11412
- * @private
11413
- */
11414
- descriptors: function(chart) {
11415
- var cache = chart._plugins || (chart._plugins = {});
11416
- if (cache.id === this._cacheId) {
11417
- return cache.descriptors;
11418
- }
11419
-
11420
- var plugins = [];
11421
- var descriptors = [];
11422
- var config = (chart && chart.config) || {};
11423
- var defaults = Chart.defaults.global.plugins;
11424
- var options = (config.options && config.options.plugins) || {};
11425
-
11426
- this._plugins.concat(config.plugins || []).forEach(function(plugin) {
11427
- var idx = plugins.indexOf(plugin);
11428
- if (idx !== -1) {
11429
- return;
11430
- }
11431
-
11432
- var id = plugin.id;
11433
- var opts = options[id];
11434
- if (opts === false) {
11435
- return;
11436
- }
11437
-
11438
- if (opts === true) {
11439
- opts = helpers.clone(defaults[id]);
11440
- }
11441
-
11442
- plugins.push(plugin);
11443
- descriptors.push({
11444
- plugin: plugin,
11445
- options: opts || {}
11446
- });
11447
- });
11448
-
11449
- cache.descriptors = descriptors;
11450
- cache.id = this._cacheId;
11451
- return descriptors;
11452
- }
11453
- };
11454
-
11455
- /**
11456
- * Plugin extension hooks.
11457
- * @interface IPlugin
11458
- * @since 2.1.0
11459
- */
11460
- /**
11461
- * @method IPlugin#beforeInit
11462
- * @desc Called before initializing `chart`.
11463
- * @param {Chart.Controller} chart - The chart instance.
11464
- * @param {Object} options - The plugin options.
11465
- */
11466
- /**
11467
- * @method IPlugin#afterInit
11468
- * @desc Called after `chart` has been initialized and before the first update.
11469
- * @param {Chart.Controller} chart - The chart instance.
11470
- * @param {Object} options - The plugin options.
11471
- */
11472
- /**
11473
- * @method IPlugin#beforeUpdate
11474
- * @desc Called before updating `chart`. If any plugin returns `false`, the update
11475
- * is cancelled (and thus subsequent render(s)) until another `update` is triggered.
11476
- * @param {Chart.Controller} chart - The chart instance.
11477
- * @param {Object} options - The plugin options.
11478
- * @returns {Boolean} `false` to cancel the chart update.
11479
- */
11480
- /**
11481
- * @method IPlugin#afterUpdate
11482
- * @desc Called after `chart` has been updated and before rendering. Note that this
11483
- * hook will not be called if the chart update has been previously cancelled.
11484
- * @param {Chart.Controller} chart - The chart instance.
11485
- * @param {Object} options - The plugin options.
11486
- */
11487
- /**
11488
- * @method IPlugin#beforeDatasetsUpdate
11489
- * @desc Called before updating the `chart` datasets. If any plugin returns `false`,
11490
- * the datasets update is cancelled until another `update` is triggered.
11491
- * @param {Chart.Controller} chart - The chart instance.
11492
- * @param {Object} options - The plugin options.
11493
- * @returns {Boolean} false to cancel the datasets update.
11494
- * @since version 2.1.5
11495
- */
11496
- /**
11497
- * @method IPlugin#afterDatasetsUpdate
11498
- * @desc Called after the `chart` datasets have been updated. Note that this hook
11499
- * will not be called if the datasets update has been previously cancelled.
11500
- * @param {Chart.Controller} chart - The chart instance.
11501
- * @param {Object} options - The plugin options.
11502
- * @since version 2.1.5
11503
- */
11504
- /**
11505
- * @method IPlugin#beforeDatasetUpdate
11506
- * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin
11507
- * returns `false`, the datasets update is cancelled until another `update` is triggered.
11508
- * @param {Chart} chart - The chart instance.
11509
- * @param {Object} args - The call arguments.
11510
- * @param {Object} args.index - The dataset index.
11511
- * @param {Number} args.meta - The dataset metadata.
11512
- * @param {Object} options - The plugin options.
11513
- * @returns {Boolean} `false` to cancel the chart datasets drawing.
11514
- */
11515
- /**
11516
- * @method IPlugin#afterDatasetUpdate
11517
- * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note
11518
- * that this hook will not be called if the datasets update has been previously cancelled.
11519
- * @param {Chart} chart - The chart instance.
11520
- * @param {Object} args - The call arguments.
11521
- * @param {Object} args.index - The dataset index.
11522
- * @param {Number} args.meta - The dataset metadata.
11523
- * @param {Object} options - The plugin options.
11524
- */
11525
- /**
11526
- * @method IPlugin#beforeLayout
11527
- * @desc Called before laying out `chart`. If any plugin returns `false`,
11528
- * the layout update is cancelled until another `update` is triggered.
11529
- * @param {Chart.Controller} chart - The chart instance.
11530
- * @param {Object} options - The plugin options.
11531
- * @returns {Boolean} `false` to cancel the chart layout.
11532
- */
11533
- /**
11534
- * @method IPlugin#afterLayout
11535
- * @desc Called after the `chart` has been layed out. Note that this hook will not
11536
- * be called if the layout update has been previously cancelled.
11537
- * @param {Chart.Controller} chart - The chart instance.
11538
- * @param {Object} options - The plugin options.
11539
- */
11540
- /**
11541
- * @method IPlugin#beforeRender
11542
- * @desc Called before rendering `chart`. If any plugin returns `false`,
11543
- * the rendering is cancelled until another `render` is triggered.
11544
- * @param {Chart.Controller} chart - The chart instance.
11545
- * @param {Object} options - The plugin options.
11546
- * @returns {Boolean} `false` to cancel the chart rendering.
11547
- */
11548
- /**
11549
- * @method IPlugin#afterRender
11550
- * @desc Called after the `chart` has been fully rendered (and animation completed). Note
11551
- * that this hook will not be called if the rendering has been previously cancelled.
11552
- * @param {Chart.Controller} chart - The chart instance.
11553
- * @param {Object} options - The plugin options.
11554
- */
11555
- /**
11556
- * @method IPlugin#beforeDraw
11557
- * @desc Called before drawing `chart` at every animation frame specified by the given
11558
- * easing value. If any plugin returns `false`, the frame drawing is cancelled until
11559
- * another `render` is triggered.
11560
- * @param {Chart.Controller} chart - The chart instance.
11561
- * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11562
- * @param {Object} options - The plugin options.
11563
- * @returns {Boolean} `false` to cancel the chart drawing.
11564
- */
11565
- /**
11566
- * @method IPlugin#afterDraw
11567
- * @desc Called after the `chart` has been drawn for the specific easing value. Note
11568
- * that this hook will not be called if the drawing has been previously cancelled.
11569
- * @param {Chart.Controller} chart - The chart instance.
11570
- * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11571
- * @param {Object} options - The plugin options.
11572
- */
11573
- /**
11574
- * @method IPlugin#beforeDatasetsDraw
11575
- * @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
11576
- * the datasets drawing is cancelled until another `render` is triggered.
11577
- * @param {Chart.Controller} chart - The chart instance.
11578
- * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11579
- * @param {Object} options - The plugin options.
11580
- * @returns {Boolean} `false` to cancel the chart datasets drawing.
11581
- */
11582
- /**
11583
- * @method IPlugin#afterDatasetsDraw
11584
- * @desc Called after the `chart` datasets have been drawn. Note that this hook
11585
- * will not be called if the datasets drawing has been previously cancelled.
11586
- * @param {Chart.Controller} chart - The chart instance.
11587
- * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
11588
- * @param {Object} options - The plugin options.
11589
- */
11590
- /**
11591
- * @method IPlugin#beforeDatasetDraw
11592
- * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets
11593
- * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing
11594
- * is cancelled until another `render` is triggered.
11595
- * @param {Chart} chart - The chart instance.
11596
- * @param {Object} args - The call arguments.
11597
- * @param {Object} args.index - The dataset index.
11598
- * @param {Number} args.meta - The dataset metadata.
11599
- * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11600
- * @param {Object} options - The plugin options.
11601
- * @returns {Boolean} `false` to cancel the chart datasets drawing.
11602
- */
11603
- /**
11604
- * @method IPlugin#afterDatasetDraw
11605
- * @desc Called after the `chart` datasets at the given `args.index` have been drawn
11606
- * (datasets are drawn in the reverse order). Note that this hook will not be called
11607
- * if the datasets drawing has been previously cancelled.
11608
- * @param {Chart} chart - The chart instance.
11609
- * @param {Object} args - The call arguments.
11610
- * @param {Object} args.index - The dataset index.
11611
- * @param {Number} args.meta - The dataset metadata.
11612
- * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
11613
- * @param {Object} options - The plugin options.
11614
- */
11615
- /**
11616
- * @method IPlugin#beforeEvent
11617
- * @desc Called before processing the specified `event`. If any plugin returns `false`,
11618
- * the event will be discarded.
11619
- * @param {Chart.Controller} chart - The chart instance.
11620
- * @param {IEvent} event - The event object.
11621
- * @param {Object} options - The plugin options.
11622
- */
11623
- /**
11624
- * @method IPlugin#afterEvent
11625
- * @desc Called after the `event` has been consumed. Note that this hook
11626
- * will not be called if the `event` has been previously discarded.
11627
- * @param {Chart.Controller} chart - The chart instance.
11628
- * @param {IEvent} event - The event object.
11629
- * @param {Object} options - The plugin options.
11630
- */
11631
- /**
11632
- * @method IPlugin#resize
11633
- * @desc Called after the chart as been resized.
11634
- * @param {Chart.Controller} chart - The chart instance.
11635
- * @param {Number} size - The new canvas display size (eq. canvas.style width & height).
11636
- * @param {Object} options - The plugin options.
11637
- */
11638
- /**
11639
- * @method IPlugin#destroy
11640
- * @desc Called after the chart as been destroyed.
11641
- * @param {Chart.Controller} chart - The chart instance.
11642
- * @param {Object} options - The plugin options.
11643
- */
11644
-
11645
- /**
11646
- * Provided for backward compatibility, use Chart.plugins instead
11647
- * @namespace Chart.pluginService
11648
- * @deprecated since version 2.1.5
11649
- * @todo remove at version 3
11650
- * @private
11651
- */
11652
- Chart.pluginService = Chart.plugins;
11653
-
11654
- /**
11655
- * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
11656
- * effect, instead simply create/register plugins via plain JavaScript objects.
11657
- * @interface Chart.PluginBase
11658
- * @deprecated since version 2.5.0
11659
- * @todo remove at version 3
11660
- * @private
11661
- */
11662
- Chart.PluginBase = Chart.Element.extend({});
11663
- };
11664
-
11665
- },{}],31:[function(require,module,exports){
11666
- 'use strict';
11667
-
11668
- module.exports = function(Chart) {
11669
-
11670
- var helpers = Chart.helpers;
11671
-
11672
- Chart.defaults.scale = {
11673
- display: true,
11674
- position: 'left',
11675
-
11676
- // grid line settings
11677
- gridLines: {
11678
- display: true,
11679
- color: 'rgba(0, 0, 0, 0.1)',
11680
- lineWidth: 1,
11681
- drawBorder: true,
11682
- drawOnChartArea: true,
11683
- drawTicks: true,
11684
- tickMarkLength: 10,
11685
- zeroLineWidth: 1,
11686
- zeroLineColor: 'rgba(0,0,0,0.25)',
11687
- zeroLineBorderDash: [],
11688
- zeroLineBorderDashOffset: 0.0,
11689
- offsetGridLines: false,
11690
- borderDash: [],
11691
- borderDashOffset: 0.0
11692
- },
11693
-
11694
- // scale label
11695
- scaleLabel: {
11696
- // actual label
11697
- labelString: '',
11698
-
11699
- // display property
11700
- display: false
11701
- },
11702
-
11703
- // label settings
11704
- ticks: {
11705
- beginAtZero: false,
11706
- minRotation: 0,
11707
- maxRotation: 50,
11708
- mirror: false,
11709
- padding: 0,
11710
- reverse: false,
11711
- display: true,
11712
- autoSkip: true,
11713
- autoSkipPadding: 0,
11714
- labelOffset: 0,
11715
- // We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
11716
- callback: Chart.Ticks.formatters.values
11717
- }
11718
- };
11719
-
11720
- function computeTextSize(context, tick, font) {
11721
- return helpers.isArray(tick) ?
11722
- helpers.longestText(context, font, tick) :
11723
- context.measureText(tick).width;
11724
- }
11725
-
11726
- function parseFontOptions(options) {
11727
- var getValueOrDefault = helpers.getValueOrDefault;
11728
- var globalDefaults = Chart.defaults.global;
11729
- var size = getValueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
11730
- var style = getValueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
11731
- var family = getValueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);
11732
-
11733
- return {
11734
- size: size,
11735
- style: style,
11736
- family: family,
11737
- font: helpers.fontString(size, style, family)
11738
- };
11739
- }
11740
-
11741
- Chart.Scale = Chart.Element.extend({
11742
- /**
11743
- * Get the padding needed for the scale
11744
- * @method getPadding
11745
- * @private
11746
- * @returns {Padding} the necessary padding
11747
- */
11748
- getPadding: function() {
11749
- var me = this;
11750
- return {
11751
- left: me.paddingLeft || 0,
11752
- top: me.paddingTop || 0,
11753
- right: me.paddingRight || 0,
11754
- bottom: me.paddingBottom || 0
11755
- };
11756
- },
11757
-
11758
- // These methods are ordered by lifecyle. Utilities then follow.
11759
- // Any function defined here is inherited by all scale types.
11760
- // Any function can be extended by the scale type
11761
-
11762
- beforeUpdate: function() {
11763
- helpers.callback(this.options.beforeUpdate, [this]);
11764
- },
11765
- update: function(maxWidth, maxHeight, margins) {
11766
- var me = this;
11767
-
11768
- // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
11769
- me.beforeUpdate();
11770
-
11771
- // Absorb the master measurements
11772
- me.maxWidth = maxWidth;
11773
- me.maxHeight = maxHeight;
11774
- me.margins = helpers.extend({
11775
- left: 0,
11776
- right: 0,
11777
- top: 0,
11778
- bottom: 0
11779
- }, margins);
11780
- me.longestTextCache = me.longestTextCache || {};
11781
-
11782
- // Dimensions
11783
- me.beforeSetDimensions();
11784
- me.setDimensions();
11785
- me.afterSetDimensions();
11786
-
11787
- // Data min/max
11788
- me.beforeDataLimits();
11789
- me.determineDataLimits();
11790
- me.afterDataLimits();
11791
-
11792
- // Ticks
11793
- me.beforeBuildTicks();
11794
- me.buildTicks();
11795
- me.afterBuildTicks();
11796
-
11797
- me.beforeTickToLabelConversion();
11798
- me.convertTicksToLabels();
11799
- me.afterTickToLabelConversion();
11800
-
11801
- // Tick Rotation
11802
- me.beforeCalculateTickRotation();
11803
- me.calculateTickRotation();
11804
- me.afterCalculateTickRotation();
11805
- // Fit
11806
- me.beforeFit();
11807
- me.fit();
11808
- me.afterFit();
11809
- //
11810
- me.afterUpdate();
11811
-
11812
- return me.minSize;
11813
-
11814
- },
11815
- afterUpdate: function() {
11816
- helpers.callback(this.options.afterUpdate, [this]);
11817
- },
11818
-
11819
- //
11820
-
11821
- beforeSetDimensions: function() {
11822
- helpers.callback(this.options.beforeSetDimensions, [this]);
11823
- },
11824
- setDimensions: function() {
11825
- var me = this;
11826
- // Set the unconstrained dimension before label rotation
11827
- if (me.isHorizontal()) {
11828
- // Reset position before calculating rotation
11829
- me.width = me.maxWidth;
11830
- me.left = 0;
11831
- me.right = me.width;
11832
- } else {
11833
- me.height = me.maxHeight;
11834
-
11835
- // Reset position before calculating rotation
11836
- me.top = 0;
11837
- me.bottom = me.height;
11838
- }
11839
-
11840
- // Reset padding
11841
- me.paddingLeft = 0;
11842
- me.paddingTop = 0;
11843
- me.paddingRight = 0;
11844
- me.paddingBottom = 0;
11845
- },
11846
- afterSetDimensions: function() {
11847
- helpers.callback(this.options.afterSetDimensions, [this]);
11848
- },
11849
-
11850
- // Data limits
11851
- beforeDataLimits: function() {
11852
- helpers.callback(this.options.beforeDataLimits, [this]);
11853
- },
11854
- determineDataLimits: helpers.noop,
11855
- afterDataLimits: function() {
11856
- helpers.callback(this.options.afterDataLimits, [this]);
11857
- },
11858
-
11859
- //
11860
- beforeBuildTicks: function() {
11861
- helpers.callback(this.options.beforeBuildTicks, [this]);
11862
- },
11863
- buildTicks: helpers.noop,
11864
- afterBuildTicks: function() {
11865
- helpers.callback(this.options.afterBuildTicks, [this]);
11866
- },
11867
-
11868
- beforeTickToLabelConversion: function() {
11869
- helpers.callback(this.options.beforeTickToLabelConversion, [this]);
11870
- },
11871
- convertTicksToLabels: function() {
11872
- var me = this;
11873
- // Convert ticks to strings
11874
- var tickOpts = me.options.ticks;
11875
- me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback);
11876
- },
11877
- afterTickToLabelConversion: function() {
11878
- helpers.callback(this.options.afterTickToLabelConversion, [this]);
11879
- },
11880
-
11881
- //
11882
-
11883
- beforeCalculateTickRotation: function() {
11884
- helpers.callback(this.options.beforeCalculateTickRotation, [this]);
11885
- },
11886
- calculateTickRotation: function() {
11887
- var me = this;
11888
- var context = me.ctx;
11889
- var tickOpts = me.options.ticks;
11890
-
11891
- // Get the width of each grid by calculating the difference
11892
- // between x offsets between 0 and 1.
11893
- var tickFont = parseFontOptions(tickOpts);
11894
- context.font = tickFont.font;
11895
-
11896
- var labelRotation = tickOpts.minRotation || 0;
11897
-
11898
- if (me.options.display && me.isHorizontal()) {
11899
- var originalLabelWidth = helpers.longestText(context, tickFont.font, me.ticks, me.longestTextCache);
11900
- var labelWidth = originalLabelWidth;
11901
- var cosRotation;
11902
- var sinRotation;
11903
-
11904
- // Allow 3 pixels x2 padding either side for label readability
11905
- var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
11906
-
11907
- // Max label rotation can be set or default to 90 - also act as a loop counter
11908
- while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
11909
- var angleRadians = helpers.toRadians(labelRotation);
11910
- cosRotation = Math.cos(angleRadians);
11911
- sinRotation = Math.sin(angleRadians);
11912
-
11913
- if (sinRotation * originalLabelWidth > me.maxHeight) {
11914
- // go back one step
11915
- labelRotation--;
11916
- break;
11917
- }
11918
-
11919
- labelRotation++;
11920
- labelWidth = cosRotation * originalLabelWidth;
11921
- }
11922
- }
11923
-
11924
- me.labelRotation = labelRotation;
11925
- },
11926
- afterCalculateTickRotation: function() {
11927
- helpers.callback(this.options.afterCalculateTickRotation, [this]);
11928
- },
11929
-
11930
- //
11931
-
11932
- beforeFit: function() {
11933
- helpers.callback(this.options.beforeFit, [this]);
11934
- },
11935
- fit: function() {
11936
- var me = this;
11937
- // Reset
11938
- var minSize = me.minSize = {
11939
- width: 0,
11940
- height: 0
11941
- };
11942
-
11943
- var opts = me.options;
11944
- var tickOpts = opts.ticks;
11945
- var scaleLabelOpts = opts.scaleLabel;
11946
- var gridLineOpts = opts.gridLines;
11947
- var display = opts.display;
11948
- var isHorizontal = me.isHorizontal();
11949
-
11950
- var tickFont = parseFontOptions(tickOpts);
11951
- var scaleLabelFontSize = parseFontOptions(scaleLabelOpts).size * 1.5;
11952
- var tickMarkLength = opts.gridLines.tickMarkLength;
11953
-
11954
- // Width
11955
- if (isHorizontal) {
11956
- // subtract the margins to line up with the chartArea if we are a full width scale
11957
- minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
11958
- } else {
11959
- minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
11960
- }
11961
-
11962
- // height
11963
- if (isHorizontal) {
11964
- minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
11965
- } else {
11966
- minSize.height = me.maxHeight; // fill all the height
11967
- }
11968
-
11969
- // Are we showing a title for the scale?
11970
- if (scaleLabelOpts.display && display) {
11971
- if (isHorizontal) {
11972
- minSize.height += scaleLabelFontSize;
11973
- } else {
11974
- minSize.width += scaleLabelFontSize;
11975
- }
11976
- }
11977
-
11978
- // Don't bother fitting the ticks if we are not showing them
11979
- if (tickOpts.display && display) {
11980
- var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, me.ticks, me.longestTextCache);
11981
- var tallestLabelHeightInLines = helpers.numberOfLabelLines(me.ticks);
11982
- var lineSpace = tickFont.size * 0.5;
11983
-
11984
- if (isHorizontal) {
11985
- // A horizontal axis is more constrained by the height.
11986
- me.longestLabelWidth = largestTextWidth;
11987
-
11988
- var angleRadians = helpers.toRadians(me.labelRotation);
11989
- var cosRotation = Math.cos(angleRadians);
11990
- var sinRotation = Math.sin(angleRadians);
11991
-
11992
- // TODO - improve this calculation
11993
- var labelHeight = (sinRotation * largestTextWidth)
11994
- + (tickFont.size * tallestLabelHeightInLines)
11995
- + (lineSpace * tallestLabelHeightInLines);
11996
-
11997
- minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight);
11998
- me.ctx.font = tickFont.font;
11999
-
12000
- var firstTick = me.ticks[0];
12001
- var firstLabelWidth = computeTextSize(me.ctx, firstTick, tickFont.font);
12002
-
12003
- var lastTick = me.ticks[me.ticks.length - 1];
12004
- var lastLabelWidth = computeTextSize(me.ctx, lastTick, tickFont.font);
12005
-
12006
- // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated
12007
- // by the font height
12008
- if (me.labelRotation !== 0) {
12009
- me.paddingLeft = opts.position === 'bottom'? (cosRotation * firstLabelWidth) + 3: (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
12010
- me.paddingRight = opts.position === 'bottom'? (cosRotation * lineSpace) + 3: (cosRotation * lastLabelWidth) + 3;
12011
- } else {
12012
- me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
12013
- me.paddingRight = lastLabelWidth / 2 + 3;
12014
- }
12015
- } else {
12016
- // A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first
12017
- // Account for padding
12018
-
12019
- if (tickOpts.mirror) {
12020
- largestTextWidth = 0;
12021
- } else {
12022
- largestTextWidth += me.options.ticks.padding;
12023
- }
12024
- minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
12025
- me.paddingTop = tickFont.size / 2;
12026
- me.paddingBottom = tickFont.size / 2;
12027
- }
12028
- }
12029
-
12030
- me.handleMargins();
12031
-
12032
- me.width = minSize.width;
12033
- me.height = minSize.height;
12034
- },
12035
-
12036
- /**
12037
- * Handle margins and padding interactions
12038
- * @private
12039
- */
12040
- handleMargins: function() {
12041
- var me = this;
12042
- if (me.margins) {
12043
- me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
12044
- me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
12045
- me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
12046
- me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
12047
- }
12048
- },
12049
-
12050
- afterFit: function() {
12051
- helpers.callback(this.options.afterFit, [this]);
12052
- },
12053
-
12054
- // Shared Methods
12055
- isHorizontal: function() {
12056
- return this.options.position === 'top' || this.options.position === 'bottom';
12057
- },
12058
- isFullWidth: function() {
12059
- return (this.options.fullWidth);
12060
- },
12061
-
12062
- // 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
12063
- getRightValue: function(rawValue) {
12064
- // Null and undefined values first
12065
- if (rawValue === null || typeof(rawValue) === 'undefined') {
12066
- return NaN;
12067
- }
12068
- // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
12069
- if (typeof(rawValue) === 'number' && !isFinite(rawValue)) {
12070
- return NaN;
12071
- }
12072
- // If it is in fact an object, dive in one more level
12073
- if (typeof(rawValue) === 'object') {
12074
- if ((rawValue instanceof Date) || (rawValue.isValid)) {
12075
- return rawValue;
12076
- }
12077
- return this.getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
12078
- }
12079
-
12080
- // Value is good, return it
12081
- return rawValue;
12082
- },
12083
-
12084
- // Used to get the value to display in the tooltip for the data at the given index
12085
- // function getLabelForIndex(index, datasetIndex)
12086
- getLabelForIndex: helpers.noop,
12087
-
12088
- // Used to get data value locations. Value can either be an index or a numerical value
12089
- getPixelForValue: helpers.noop,
12090
-
12091
- // Used to get the data value from a given pixel. This is the inverse of getPixelForValue
12092
- getValueForPixel: helpers.noop,
12093
-
12094
- // Used for tick location, should
12095
- getPixelForTick: function(index, includeOffset) {
12096
- var me = this;
12097
- if (me.isHorizontal()) {
12098
- var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
12099
- var tickWidth = innerWidth / Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
12100
- var pixel = (tickWidth * index) + me.paddingLeft;
12101
-
12102
- if (includeOffset) {
12103
- pixel += tickWidth / 2;
12104
- }
12105
-
12106
- var finalVal = me.left + Math.round(pixel);
12107
- finalVal += me.isFullWidth() ? me.margins.left : 0;
12108
- return finalVal;
12109
- }
12110
- var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
12111
- return me.top + (index * (innerHeight / (me.ticks.length - 1)));
12112
- },
12113
-
12114
- // Utility for getting the pixel location of a percentage of scale
12115
- getPixelForDecimal: function(decimal /* , includeOffset*/) {
12116
- var me = this;
12117
- if (me.isHorizontal()) {
12118
- var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
12119
- var valueOffset = (innerWidth * decimal) + me.paddingLeft;
12120
-
12121
- var finalVal = me.left + Math.round(valueOffset);
12122
- finalVal += me.isFullWidth() ? me.margins.left : 0;
12123
- return finalVal;
12124
- }
12125
- return me.top + (decimal * me.height);
12126
- },
12127
-
12128
- getBasePixel: function() {
12129
- return this.getPixelForValue(this.getBaseValue());
12130
- },
12131
-
12132
- getBaseValue: function() {
12133
- var me = this;
12134
- var min = me.min;
12135
- var max = me.max;
12136
-
12137
- return me.beginAtZero ? 0:
12138
- min < 0 && max < 0? max :
12139
- min > 0 && max > 0? min :
12140
- 0;
12141
- },
12142
-
12143
- // Actually draw the scale on the canvas
12144
- // @param {rectangle} chartArea : the area of the chart to draw full grid lines on
12145
- draw: function(chartArea) {
12146
- var me = this;
12147
- var options = me.options;
12148
- if (!options.display) {
12149
- return;
12150
- }
12151
-
12152
- var context = me.ctx;
12153
- var globalDefaults = Chart.defaults.global;
12154
- var optionTicks = options.ticks;
12155
- var gridLines = options.gridLines;
12156
- var scaleLabel = options.scaleLabel;
12157
-
12158
- var isRotated = me.labelRotation !== 0;
12159
- var skipRatio;
12160
- var useAutoskipper = optionTicks.autoSkip;
12161
- var isHorizontal = me.isHorizontal();
12162
-
12163
- // figure out the maximum number of gridlines to show
12164
- var maxTicks;
12165
- if (optionTicks.maxTicksLimit) {
12166
- maxTicks = optionTicks.maxTicksLimit;
12167
- }
12168
-
12169
- var tickFontColor = helpers.getValueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
12170
- var tickFont = parseFontOptions(optionTicks);
12171
-
12172
- var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
12173
-
12174
- var scaleLabelFontColor = helpers.getValueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
12175
- var scaleLabelFont = parseFontOptions(scaleLabel);
12176
-
12177
- var labelRotationRadians = helpers.toRadians(me.labelRotation);
12178
- var cosRotation = Math.cos(labelRotationRadians);
12179
- var longestRotatedLabel = me.longestLabelWidth * cosRotation;
12180
-
12181
- // Make sure we draw text in the correct color and font
12182
- context.fillStyle = tickFontColor;
12183
-
12184
- var itemsToDraw = [];
12185
-
12186
- if (isHorizontal) {
12187
- skipRatio = false;
12188
-
12189
- if ((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length > (me.width - (me.paddingLeft + me.paddingRight))) {
12190
- skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * me.ticks.length) / (me.width - (me.paddingLeft + me.paddingRight)));
12191
- }
12192
-
12193
- // if they defined a max number of optionTicks,
12194
- // increase skipRatio until that number is met
12195
- if (maxTicks && me.ticks.length > maxTicks) {
12196
- while (!skipRatio || me.ticks.length / (skipRatio || 1) > maxTicks) {
12197
- if (!skipRatio) {
12198
- skipRatio = 1;
12199
- }
12200
- skipRatio += 1;
12201
- }
12202
- }
12203
-
12204
- if (!useAutoskipper) {
12205
- skipRatio = false;
12206
- }
12207
- }
12208
-
12209
-
12210
- var xTickStart = options.position === 'right' ? me.left : me.right - tl;
12211
- var xTickEnd = options.position === 'right' ? me.left + tl : me.right;
12212
- var yTickStart = options.position === 'bottom' ? me.top : me.bottom - tl;
12213
- var yTickEnd = options.position === 'bottom' ? me.top + tl : me.bottom;
12214
-
12215
- helpers.each(me.ticks, function(label, index) {
12216
- // If the callback returned a null or undefined value, do not draw this line
12217
- if (label === undefined || label === null) {
12218
- return;
12219
- }
12220
-
12221
- var isLastTick = me.ticks.length === index + 1;
12222
-
12223
- // Since we always show the last tick,we need may need to hide the last shown one before
12224
- var shouldSkip = (skipRatio > 1 && index % skipRatio > 0) || (index % skipRatio === 0 && index + skipRatio >= me.ticks.length);
12225
- if (shouldSkip && !isLastTick || (label === undefined || label === null)) {
12226
- return;
12227
- }
12228
-
12229
- var lineWidth, lineColor, borderDash, borderDashOffset;
12230
- if (index === (typeof me.zeroLineIndex !== 'undefined' ? me.zeroLineIndex : 0)) {
12231
- // Draw the first index specially
12232
- lineWidth = gridLines.zeroLineWidth;
12233
- lineColor = gridLines.zeroLineColor;
12234
- borderDash = gridLines.zeroLineBorderDash;
12235
- borderDashOffset = gridLines.zeroLineBorderDashOffset;
12236
- } else {
12237
- lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, index);
12238
- lineColor = helpers.getValueAtIndexOrDefault(gridLines.color, index);
12239
- borderDash = helpers.getValueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
12240
- borderDashOffset = helpers.getValueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
12241
- }
12242
-
12243
- // Common properties
12244
- var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
12245
- var textAlign = 'middle';
12246
- var textBaseline = 'middle';
12247
-
12248
- if (isHorizontal) {
12249
-
12250
- if (options.position === 'bottom') {
12251
- // bottom
12252
- textBaseline = !isRotated? 'top':'middle';
12253
- textAlign = !isRotated? 'center': 'right';
12254
- labelY = me.top + tl;
12255
- } else {
12256
- // top
12257
- textBaseline = !isRotated? 'bottom':'middle';
12258
- textAlign = !isRotated? 'center': 'left';
12259
- labelY = me.bottom - tl;
12260
- }
12261
-
12262
- var xLineValue = me.getPixelForTick(index) + helpers.aliasPixel(lineWidth); // xvalues for grid lines
12263
- labelX = me.getPixelForTick(index, gridLines.offsetGridLines) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
12264
-
12265
- tx1 = tx2 = x1 = x2 = xLineValue;
12266
- ty1 = yTickStart;
12267
- ty2 = yTickEnd;
12268
- y1 = chartArea.top;
12269
- y2 = chartArea.bottom;
12270
- } else {
12271
- var isLeft = options.position === 'left';
12272
- var tickPadding = optionTicks.padding;
12273
- var labelXOffset;
12274
-
12275
- if (optionTicks.mirror) {
12276
- textAlign = isLeft ? 'left' : 'right';
12277
- labelXOffset = tickPadding;
12278
- } else {
12279
- textAlign = isLeft ? 'right' : 'left';
12280
- labelXOffset = tl + tickPadding;
12281
- }
12282
-
12283
- labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
12284
-
12285
- var yLineValue = me.getPixelForTick(index); // xvalues for grid lines
12286
- yLineValue += helpers.aliasPixel(lineWidth);
12287
- labelY = me.getPixelForTick(index, gridLines.offsetGridLines);
12288
-
12289
- tx1 = xTickStart;
12290
- tx2 = xTickEnd;
12291
- x1 = chartArea.left;
12292
- x2 = chartArea.right;
12293
- ty1 = ty2 = y1 = y2 = yLineValue;
12294
- }
12295
-
12296
- itemsToDraw.push({
12297
- tx1: tx1,
12298
- ty1: ty1,
12299
- tx2: tx2,
12300
- ty2: ty2,
12301
- x1: x1,
12302
- y1: y1,
12303
- x2: x2,
12304
- y2: y2,
12305
- labelX: labelX,
12306
- labelY: labelY,
12307
- glWidth: lineWidth,
12308
- glColor: lineColor,
12309
- glBorderDash: borderDash,
12310
- glBorderDashOffset: borderDashOffset,
12311
- rotation: -1 * labelRotationRadians,
12312
- label: label,
12313
- textBaseline: textBaseline,
12314
- textAlign: textAlign
12315
- });
12316
- });
12317
-
12318
- // Draw all of the tick labels, tick marks, and grid lines at the correct places
12319
- helpers.each(itemsToDraw, function(itemToDraw) {
12320
- if (gridLines.display) {
12321
- context.save();
12322
- context.lineWidth = itemToDraw.glWidth;
12323
- context.strokeStyle = itemToDraw.glColor;
12324
- if (context.setLineDash) {
12325
- context.setLineDash(itemToDraw.glBorderDash);
12326
- context.lineDashOffset = itemToDraw.glBorderDashOffset;
12327
- }
12328
-
12329
- context.beginPath();
12330
-
12331
- if (gridLines.drawTicks) {
12332
- context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
12333
- context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
12334
- }
12335
-
12336
- if (gridLines.drawOnChartArea) {
12337
- context.moveTo(itemToDraw.x1, itemToDraw.y1);
12338
- context.lineTo(itemToDraw.x2, itemToDraw.y2);
12339
- }
12340
-
12341
- context.stroke();
12342
- context.restore();
12343
- }
12344
-
12345
- if (optionTicks.display) {
12346
- context.save();
12347
- context.translate(itemToDraw.labelX, itemToDraw.labelY);
12348
- context.rotate(itemToDraw.rotation);
12349
- context.font = tickFont.font;
12350
- context.textBaseline = itemToDraw.textBaseline;
12351
- context.textAlign = itemToDraw.textAlign;
12352
-
12353
- var label = itemToDraw.label;
12354
- if (helpers.isArray(label)) {
12355
- for (var i = 0, y = 0; i < label.length; ++i) {
12356
- // We just make sure the multiline element is a string here..
12357
- context.fillText('' + label[i], 0, y);
12358
- // apply same lineSpacing as calculated @ L#320
12359
- y += (tickFont.size * 1.5);
12360
- }
12361
- } else {
12362
- context.fillText(label, 0, 0);
12363
- }
12364
- context.restore();
12365
- }
12366
- });
12367
-
12368
- if (scaleLabel.display) {
12369
- // Draw the scale label
12370
- var scaleLabelX;
12371
- var scaleLabelY;
12372
- var rotation = 0;
12373
-
12374
- if (isHorizontal) {
12375
- scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
12376
- scaleLabelY = options.position === 'bottom' ? me.bottom - (scaleLabelFont.size / 2) : me.top + (scaleLabelFont.size / 2);
12377
- } else {
12378
- var isLeft = options.position === 'left';
12379
- scaleLabelX = isLeft ? me.left + (scaleLabelFont.size / 2) : me.right - (scaleLabelFont.size / 2);
12380
- scaleLabelY = me.top + ((me.bottom - me.top) / 2);
12381
- rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
12382
- }
12383
-
12384
- context.save();
12385
- context.translate(scaleLabelX, scaleLabelY);
12386
- context.rotate(rotation);
12387
- context.textAlign = 'center';
12388
- context.textBaseline = 'middle';
12389
- context.fillStyle = scaleLabelFontColor; // render in correct colour
12390
- context.font = scaleLabelFont.font;
12391
- context.fillText(scaleLabel.labelString, 0, 0);
12392
- context.restore();
12393
- }
12394
-
12395
- if (gridLines.drawBorder) {
12396
- // Draw the line at the edge of the axis
12397
- context.lineWidth = helpers.getValueAtIndexOrDefault(gridLines.lineWidth, 0);
12398
- context.strokeStyle = helpers.getValueAtIndexOrDefault(gridLines.color, 0);
12399
- var x1 = me.left,
12400
- x2 = me.right,
12401
- y1 = me.top,
12402
- y2 = me.bottom;
12403
-
12404
- var aliasPixel = helpers.aliasPixel(context.lineWidth);
12405
- if (isHorizontal) {
12406
- y1 = y2 = options.position === 'top' ? me.bottom : me.top;
12407
- y1 += aliasPixel;
12408
- y2 += aliasPixel;
12409
- } else {
12410
- x1 = x2 = options.position === 'left' ? me.right : me.left;
12411
- x1 += aliasPixel;
12412
- x2 += aliasPixel;
12413
- }
12414
-
12415
- context.beginPath();
12416
- context.moveTo(x1, y1);
12417
- context.lineTo(x2, y2);
12418
- context.stroke();
12419
- }
12420
- }
12421
- });
12422
- };
12423
-
12424
- },{}],32:[function(require,module,exports){
12425
- 'use strict';
12426
-
12427
- module.exports = function(Chart) {
12428
-
12429
- var helpers = Chart.helpers;
12430
-
12431
- Chart.scaleService = {
12432
- // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
12433
- // use the new chart options to grab the correct scale
12434
- constructors: {},
12435
- // Use a registration function so that we can move to an ES6 map when we no longer need to support
12436
- // old browsers
12437
-
12438
- // Scale config defaults
12439
- defaults: {},
12440
- registerScaleType: function(type, scaleConstructor, defaults) {
12441
- this.constructors[type] = scaleConstructor;
12442
- this.defaults[type] = helpers.clone(defaults);
12443
- },
12444
- getScaleConstructor: function(type) {
12445
- return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
12446
- },
12447
- getScaleDefaults: function(type) {
12448
- // Return the scale defaults merged with the global settings so that we always use the latest ones
12449
- return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {};
12450
- },
12451
- updateScaleDefaults: function(type, additions) {
12452
- var defaults = this.defaults;
12453
- if (defaults.hasOwnProperty(type)) {
12454
- defaults[type] = helpers.extend(defaults[type], additions);
12455
- }
12456
- },
12457
- addScalesToLayout: function(chart) {
12458
- // Adds each scale to the chart.boxes array to be sized accordingly
12459
- helpers.each(chart.scales, function(scale) {
12460
- // Set ILayoutItem parameters for backwards compatibility
12461
- scale.fullWidth = scale.options.fullWidth;
12462
- scale.position = scale.options.position;
12463
- scale.weight = scale.options.weight;
12464
- Chart.layoutService.addBox(chart, scale);
12465
- });
12466
- }
12467
- };
12468
- };
12469
-
12470
- },{}],33:[function(require,module,exports){
12471
- 'use strict';
12472
-
12473
- module.exports = function(Chart) {
12474
-
12475
- var helpers = Chart.helpers;
12476
-
12477
- /**
12478
- * Namespace to hold static tick generation functions
12479
- * @namespace Chart.Ticks
12480
- */
12481
- Chart.Ticks = {
12482
- /**
12483
- * Namespace to hold generators for different types of ticks
12484
- * @namespace Chart.Ticks.generators
12485
- */
12486
- generators: {
12487
- /**
12488
- * Interface for the options provided to the numeric tick generator
12489
- * @interface INumericTickGenerationOptions
12490
- */
12491
- /**
12492
- * The maximum number of ticks to display
12493
- * @name INumericTickGenerationOptions#maxTicks
12494
- * @type Number
12495
- */
12496
- /**
12497
- * The distance between each tick.
12498
- * @name INumericTickGenerationOptions#stepSize
12499
- * @type Number
12500
- * @optional
12501
- */
12502
- /**
12503
- * Forced minimum for the ticks. If not specified, the minimum of the data range is used to calculate the tick minimum
12504
- * @name INumericTickGenerationOptions#min
12505
- * @type Number
12506
- * @optional
12507
- */
12508
- /**
12509
- * The maximum value of the ticks. If not specified, the maximum of the data range is used to calculate the tick maximum
12510
- * @name INumericTickGenerationOptions#max
12511
- * @type Number
12512
- * @optional
12513
- */
12514
-
12515
- /**
12516
- * Generate a set of linear ticks
12517
- * @method Chart.Ticks.generators.linear
12518
- * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
12519
- * @param dataRange {IRange} the range of the data
12520
- * @returns {Array<Number>} array of tick values
12521
- */
12522
- linear: function(generationOptions, dataRange) {
12523
- var ticks = [];
12524
- // To get a "nice" value for the tick spacing, we will use the appropriately named
12525
- // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
12526
- // for details.
12527
-
12528
- var spacing;
12529
- if (generationOptions.stepSize && generationOptions.stepSize > 0) {
12530
- spacing = generationOptions.stepSize;
12531
- } else {
12532
- var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
12533
- spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
12534
- }
12535
- var niceMin = Math.floor(dataRange.min / spacing) * spacing;
12536
- var niceMax = Math.ceil(dataRange.max / spacing) * spacing;
12537
-
12538
- // If min, max and stepSize is set and they make an evenly spaced scale use it.
12539
- if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
12540
- // If very close to our whole number, use it.
12541
- if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
12542
- niceMin = generationOptions.min;
12543
- niceMax = generationOptions.max;
12544
- }
12545
- }
12546
-
12547
- var numSpaces = (niceMax - niceMin) / spacing;
12548
- // If very close to our rounded value, use it.
12549
- if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
12550
- numSpaces = Math.round(numSpaces);
12551
- } else {
12552
- numSpaces = Math.ceil(numSpaces);
12553
- }
12554
-
12555
- // Put the values into the ticks array
12556
- ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
12557
- for (var j = 1; j < numSpaces; ++j) {
12558
- ticks.push(niceMin + (j * spacing));
12559
- }
12560
- ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
12561
-
12562
- return ticks;
12563
- },
12564
-
12565
- /**
12566
- * Generate a set of logarithmic ticks
12567
- * @method Chart.Ticks.generators.logarithmic
12568
- * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
12569
- * @param dataRange {IRange} the range of the data
12570
- * @returns {Array<Number>} array of tick values
12571
- */
12572
- logarithmic: function(generationOptions, dataRange) {
12573
- var ticks = [];
12574
- var getValueOrDefault = helpers.getValueOrDefault;
12575
-
12576
- // Figure out what the max number of ticks we can support it is based on the size of
12577
- // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
12578
- // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
12579
- // the graph
12580
- var tickVal = getValueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
12581
-
12582
- var endExp = Math.floor(helpers.log10(dataRange.max));
12583
- var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
12584
- var exp;
12585
- var significand;
12586
-
12587
- if (tickVal === 0) {
12588
- exp = Math.floor(helpers.log10(dataRange.minNotZero));
12589
- significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
12590
-
12591
- ticks.push(tickVal);
12592
- tickVal = significand * Math.pow(10, exp);
12593
- } else {
12594
- exp = Math.floor(helpers.log10(tickVal));
12595
- significand = Math.floor(tickVal / Math.pow(10, exp));
12596
- }
12597
-
12598
- do {
12599
- ticks.push(tickVal);
12600
-
12601
- ++significand;
12602
- if (significand === 10) {
12603
- significand = 1;
12604
- ++exp;
12605
- }
12606
-
12607
- tickVal = significand * Math.pow(10, exp);
12608
- } while (exp < endExp || (exp === endExp && significand < endSignificand));
12609
-
12610
- var lastTick = getValueOrDefault(generationOptions.max, tickVal);
12611
- ticks.push(lastTick);
12612
-
12613
- return ticks;
12614
- }
12615
- },
12616
-
12617
- /**
12618
- * Namespace to hold formatters for different types of ticks
12619
- * @namespace Chart.Ticks.formatters
12620
- */
12621
- formatters: {
12622
- /**
12623
- * Formatter for value labels
12624
- * @method Chart.Ticks.formatters.values
12625
- * @param value the value to display
12626
- * @return {String|Array} the label to display
12627
- */
12628
- values: function(value) {
12629
- return helpers.isArray(value) ? value : '' + value;
12630
- },
12631
-
12632
- /**
12633
- * Formatter for linear numeric ticks
12634
- * @method Chart.Ticks.formatters.linear
12635
- * @param tickValue {Number} the value to be formatted
12636
- * @param index {Number} the position of the tickValue parameter in the ticks array
12637
- * @param ticks {Array<Number>} the list of ticks being converted
12638
- * @return {String} string representation of the tickValue parameter
12639
- */
12640
- linear: function(tickValue, index, ticks) {
12641
- // If we have lots of ticks, don't use the ones
12642
- var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
12643
-
12644
- // If we have a number like 2.5 as the delta, figure out how many decimal places we need
12645
- if (Math.abs(delta) > 1) {
12646
- if (tickValue !== Math.floor(tickValue)) {
12647
- // not an integer
12648
- delta = tickValue - Math.floor(tickValue);
12649
- }
12650
- }
12651
-
12652
- var logDelta = helpers.log10(Math.abs(delta));
12653
- var tickString = '';
12654
-
12655
- if (tickValue !== 0) {
12656
- var numDecimal = -1 * Math.floor(logDelta);
12657
- numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
12658
- tickString = tickValue.toFixed(numDecimal);
12659
- } else {
12660
- tickString = '0'; // never show decimal places for 0
12661
- }
12662
-
12663
- return tickString;
12664
- },
12665
-
12666
- logarithmic: function(tickValue, index, ticks) {
12667
- var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue))));
12668
-
12669
- if (tickValue === 0) {
12670
- return '0';
12671
- } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
12672
- return tickValue.toExponential();
12673
- }
12674
- return '';
12675
- }
12676
- }
12677
- };
12678
- };
12679
-
12680
- },{}],34:[function(require,module,exports){
12681
- 'use strict';
12682
-
12683
- module.exports = function(Chart) {
12684
-
12685
- var helpers = Chart.helpers;
12686
-
12687
- /**
12688
- * Helper method to merge the opacity into a color
12689
- */
12690
- function mergeOpacity(colorString, opacity) {
12691
- var color = helpers.color(colorString);
12692
- return color.alpha(opacity * color.alpha()).rgbaString();
12693
- }
12694
-
12695
- Chart.defaults.global.tooltips = {
12696
- enabled: true,
12697
- custom: null,
12698
- mode: 'nearest',
12699
- position: 'average',
12700
- intersect: true,
12701
- backgroundColor: 'rgba(0,0,0,0.8)',
12702
- titleFontStyle: 'bold',
12703
- titleSpacing: 2,
12704
- titleMarginBottom: 6,
12705
- titleFontColor: '#fff',
12706
- titleAlign: 'left',
12707
- bodySpacing: 2,
12708
- bodyFontColor: '#fff',
12709
- bodyAlign: 'left',
12710
- footerFontStyle: 'bold',
12711
- footerSpacing: 2,
12712
- footerMarginTop: 6,
12713
- footerFontColor: '#fff',
12714
- footerAlign: 'left',
12715
- yPadding: 6,
12716
- xPadding: 6,
12717
- caretPadding: 2,
12718
- caretSize: 5,
12719
- cornerRadius: 6,
12720
- multiKeyBackground: '#fff',
12721
- displayColors: true,
12722
- borderColor: 'rgba(0,0,0,0)',
12723
- borderWidth: 0,
12724
- callbacks: {
12725
- // Args are: (tooltipItems, data)
12726
- beforeTitle: helpers.noop,
12727
- title: function(tooltipItems, data) {
12728
- // Pick first xLabel for now
12729
- var title = '';
12730
- var labels = data.labels;
12731
- var labelCount = labels ? labels.length : 0;
12732
-
12733
- if (tooltipItems.length > 0) {
12734
- var item = tooltipItems[0];
12735
-
12736
- if (item.xLabel) {
12737
- title = item.xLabel;
12738
- } else if (labelCount > 0 && item.index < labelCount) {
12739
- title = labels[item.index];
12740
- }
12741
- }
12742
-
12743
- return title;
12744
- },
12745
- afterTitle: helpers.noop,
12746
-
12747
- // Args are: (tooltipItems, data)
12748
- beforeBody: helpers.noop,
12749
-
12750
- // Args are: (tooltipItem, data)
12751
- beforeLabel: helpers.noop,
12752
- label: function(tooltipItem, data) {
12753
- var label = data.datasets[tooltipItem.datasetIndex].label || '';
12754
-
12755
- if (label) {
12756
- label += ': ';
12757
- }
12758
- label += tooltipItem.yLabel;
12759
- return label;
12760
- },
12761
- labelColor: function(tooltipItem, chart) {
12762
- var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
12763
- var activeElement = meta.data[tooltipItem.index];
12764
- var view = activeElement._view;
12765
- return {
12766
- borderColor: view.borderColor,
12767
- backgroundColor: view.backgroundColor
12768
- };
12769
- },
12770
- afterLabel: helpers.noop,
12771
-
12772
- // Args are: (tooltipItems, data)
12773
- afterBody: helpers.noop,
12774
-
12775
- // Args are: (tooltipItems, data)
12776
- beforeFooter: helpers.noop,
12777
- footer: helpers.noop,
12778
- afterFooter: helpers.noop
12779
- }
12780
- };
12781
-
12782
- // Helper to push or concat based on if the 2nd parameter is an array or not
12783
- function pushOrConcat(base, toPush) {
12784
- if (toPush) {
12785
- if (helpers.isArray(toPush)) {
12786
- // base = base.concat(toPush);
12787
- Array.prototype.push.apply(base, toPush);
12788
- } else {
12789
- base.push(toPush);
12790
- }
12791
- }
12792
-
12793
- return base;
12794
- }
12795
-
12796
- // Private helper to create a tooltip item model
12797
- // @param element : the chart element (point, arc, bar) to create the tooltip item for
12798
- // @return : new tooltip item
12799
- function createTooltipItem(element) {
12800
- var xScale = element._xScale;
12801
- var yScale = element._yScale || element._scale; // handle radar || polarArea charts
12802
- var index = element._index,
12803
- datasetIndex = element._datasetIndex;
12804
-
12805
- return {
12806
- xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
12807
- yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
12808
- index: index,
12809
- datasetIndex: datasetIndex,
12810
- x: element._model.x,
12811
- y: element._model.y
12812
- };
12813
- }
12814
-
12815
- /**
12816
- * Helper to get the reset model for the tooltip
12817
- * @param tooltipOpts {Object} the tooltip options
12818
- */
12819
- function getBaseModel(tooltipOpts) {
12820
- var globalDefaults = Chart.defaults.global;
12821
- var getValueOrDefault = helpers.getValueOrDefault;
12822
-
12823
- return {
12824
- // Positioning
12825
- xPadding: tooltipOpts.xPadding,
12826
- yPadding: tooltipOpts.yPadding,
12827
- xAlign: tooltipOpts.xAlign,
12828
- yAlign: tooltipOpts.yAlign,
12829
-
12830
- // Body
12831
- bodyFontColor: tooltipOpts.bodyFontColor,
12832
- _bodyFontFamily: getValueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
12833
- _bodyFontStyle: getValueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
12834
- _bodyAlign: tooltipOpts.bodyAlign,
12835
- bodyFontSize: getValueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
12836
- bodySpacing: tooltipOpts.bodySpacing,
12837
-
12838
- // Title
12839
- titleFontColor: tooltipOpts.titleFontColor,
12840
- _titleFontFamily: getValueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
12841
- _titleFontStyle: getValueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
12842
- titleFontSize: getValueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
12843
- _titleAlign: tooltipOpts.titleAlign,
12844
- titleSpacing: tooltipOpts.titleSpacing,
12845
- titleMarginBottom: tooltipOpts.titleMarginBottom,
12846
-
12847
- // Footer
12848
- footerFontColor: tooltipOpts.footerFontColor,
12849
- _footerFontFamily: getValueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
12850
- _footerFontStyle: getValueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
12851
- footerFontSize: getValueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
12852
- _footerAlign: tooltipOpts.footerAlign,
12853
- footerSpacing: tooltipOpts.footerSpacing,
12854
- footerMarginTop: tooltipOpts.footerMarginTop,
12855
-
12856
- // Appearance
12857
- caretSize: tooltipOpts.caretSize,
12858
- cornerRadius: tooltipOpts.cornerRadius,
12859
- backgroundColor: tooltipOpts.backgroundColor,
12860
- opacity: 0,
12861
- legendColorBackground: tooltipOpts.multiKeyBackground,
12862
- displayColors: tooltipOpts.displayColors,
12863
- borderColor: tooltipOpts.borderColor,
12864
- borderWidth: tooltipOpts.borderWidth
12865
- };
12866
- }
12867
-
12868
- /**
12869
- * Get the size of the tooltip
12870
- */
12871
- function getTooltipSize(tooltip, model) {
12872
- var ctx = tooltip._chart.ctx;
12873
-
12874
- var height = model.yPadding * 2; // Tooltip Padding
12875
- var width = 0;
12876
-
12877
- // Count of all lines in the body
12878
- var body = model.body;
12879
- var combinedBodyLength = body.reduce(function(count, bodyItem) {
12880
- return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
12881
- }, 0);
12882
- combinedBodyLength += model.beforeBody.length + model.afterBody.length;
12883
-
12884
- var titleLineCount = model.title.length;
12885
- var footerLineCount = model.footer.length;
12886
- var titleFontSize = model.titleFontSize,
12887
- bodyFontSize = model.bodyFontSize,
12888
- footerFontSize = model.footerFontSize;
12889
-
12890
- height += titleLineCount * titleFontSize; // Title Lines
12891
- height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
12892
- height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
12893
- height += combinedBodyLength * bodyFontSize; // Body Lines
12894
- height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
12895
- height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
12896
- height += footerLineCount * (footerFontSize); // Footer Lines
12897
- height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
12898
-
12899
- // Title width
12900
- var widthPadding = 0;
12901
- var maxLineWidth = function(line) {
12902
- width = Math.max(width, ctx.measureText(line).width + widthPadding);
12903
- };
12904
-
12905
- ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
12906
- helpers.each(model.title, maxLineWidth);
12907
-
12908
- // Body width
12909
- ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
12910
- helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
12911
-
12912
- // Body lines may include some extra width due to the color box
12913
- widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
12914
- helpers.each(body, function(bodyItem) {
12915
- helpers.each(bodyItem.before, maxLineWidth);
12916
- helpers.each(bodyItem.lines, maxLineWidth);
12917
- helpers.each(bodyItem.after, maxLineWidth);
12918
- });
12919
-
12920
- // Reset back to 0
12921
- widthPadding = 0;
12922
-
12923
- // Footer width
12924
- ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
12925
- helpers.each(model.footer, maxLineWidth);
12926
-
12927
- // Add padding
12928
- width += 2 * model.xPadding;
12929
-
12930
- return {
12931
- width: width,
12932
- height: height
12933
- };
12934
- }
12935
-
12936
- /**
12937
- * Helper to get the alignment of a tooltip given the size
12938
- */
12939
- function determineAlignment(tooltip, size) {
12940
- var model = tooltip._model;
12941
- var chart = tooltip._chart;
12942
- var chartArea = tooltip._chart.chartArea;
12943
- var xAlign = 'center';
12944
- var yAlign = 'center';
12945
-
12946
- if (model.y < size.height) {
12947
- yAlign = 'top';
12948
- } else if (model.y > (chart.height - size.height)) {
12949
- yAlign = 'bottom';
12950
- }
12951
-
12952
- var lf, rf; // functions to determine left, right alignment
12953
- var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
12954
- var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
12955
- var midX = (chartArea.left + chartArea.right) / 2;
12956
- var midY = (chartArea.top + chartArea.bottom) / 2;
12957
-
12958
- if (yAlign === 'center') {
12959
- lf = function(x) {
12960
- return x <= midX;
12961
- };
12962
- rf = function(x) {
12963
- return x > midX;
12964
- };
12965
- } else {
12966
- lf = function(x) {
12967
- return x <= (size.width / 2);
12968
- };
12969
- rf = function(x) {
12970
- return x >= (chart.width - (size.width / 2));
12971
- };
12972
- }
12973
-
12974
- olf = function(x) {
12975
- return x + size.width > chart.width;
12976
- };
12977
- orf = function(x) {
12978
- return x - size.width < 0;
12979
- };
12980
- yf = function(y) {
12981
- return y <= midY ? 'top' : 'bottom';
12982
- };
12983
-
12984
- if (lf(model.x)) {
12985
- xAlign = 'left';
12986
-
12987
- // Is tooltip too wide and goes over the right side of the chart.?
12988
- if (olf(model.x)) {
12989
- xAlign = 'center';
12990
- yAlign = yf(model.y);
12991
- }
12992
- } else if (rf(model.x)) {
12993
- xAlign = 'right';
12994
-
12995
- // Is tooltip too wide and goes outside left edge of canvas?
12996
- if (orf(model.x)) {
12997
- xAlign = 'center';
12998
- yAlign = yf(model.y);
12999
- }
13000
- }
13001
-
13002
- var opts = tooltip._options;
13003
- return {
13004
- xAlign: opts.xAlign ? opts.xAlign : xAlign,
13005
- yAlign: opts.yAlign ? opts.yAlign : yAlign
13006
- };
13007
- }
13008
-
13009
- /**
13010
- * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
13011
- */
13012
- function getBackgroundPoint(vm, size, alignment) {
13013
- // Background Position
13014
- var x = vm.x;
13015
- var y = vm.y;
13016
-
13017
- var caretSize = vm.caretSize,
13018
- caretPadding = vm.caretPadding,
13019
- cornerRadius = vm.cornerRadius,
13020
- xAlign = alignment.xAlign,
13021
- yAlign = alignment.yAlign,
13022
- paddingAndSize = caretSize + caretPadding,
13023
- radiusAndPadding = cornerRadius + caretPadding;
13024
-
13025
- if (xAlign === 'right') {
13026
- x -= size.width;
13027
- } else if (xAlign === 'center') {
13028
- x -= (size.width / 2);
13029
- }
13030
-
13031
- if (yAlign === 'top') {
13032
- y += paddingAndSize;
13033
- } else if (yAlign === 'bottom') {
13034
- y -= size.height + paddingAndSize;
13035
- } else {
13036
- y -= (size.height / 2);
13037
- }
13038
-
13039
- if (yAlign === 'center') {
13040
- if (xAlign === 'left') {
13041
- x += paddingAndSize;
13042
- } else if (xAlign === 'right') {
13043
- x -= paddingAndSize;
13044
- }
13045
- } else if (xAlign === 'left') {
13046
- x -= radiusAndPadding;
13047
- } else if (xAlign === 'right') {
13048
- x += radiusAndPadding;
13049
- }
13050
-
13051
- return {
13052
- x: x,
13053
- y: y
13054
- };
13055
- }
13056
-
13057
- Chart.Tooltip = Chart.Element.extend({
13058
- initialize: function() {
13059
- this._model = getBaseModel(this._options);
13060
- },
13061
-
13062
- // Get the title
13063
- // Args are: (tooltipItem, data)
13064
- getTitle: function() {
13065
- var me = this;
13066
- var opts = me._options;
13067
- var callbacks = opts.callbacks;
13068
-
13069
- var beforeTitle = callbacks.beforeTitle.apply(me, arguments),
13070
- title = callbacks.title.apply(me, arguments),
13071
- afterTitle = callbacks.afterTitle.apply(me, arguments);
13072
-
13073
- var lines = [];
13074
- lines = pushOrConcat(lines, beforeTitle);
13075
- lines = pushOrConcat(lines, title);
13076
- lines = pushOrConcat(lines, afterTitle);
13077
-
13078
- return lines;
13079
- },
13080
-
13081
- // Args are: (tooltipItem, data)
13082
- getBeforeBody: function() {
13083
- var lines = this._options.callbacks.beforeBody.apply(this, arguments);
13084
- return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
13085
- },
13086
-
13087
- // Args are: (tooltipItem, data)
13088
- getBody: function(tooltipItems, data) {
13089
- var me = this;
13090
- var callbacks = me._options.callbacks;
13091
- var bodyItems = [];
13092
-
13093
- helpers.each(tooltipItems, function(tooltipItem) {
13094
- var bodyItem = {
13095
- before: [],
13096
- lines: [],
13097
- after: []
13098
- };
13099
- pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
13100
- pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
13101
- pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));
13102
-
13103
- bodyItems.push(bodyItem);
13104
- });
13105
-
13106
- return bodyItems;
13107
- },
13108
-
13109
- // Args are: (tooltipItem, data)
13110
- getAfterBody: function() {
13111
- var lines = this._options.callbacks.afterBody.apply(this, arguments);
13112
- return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
13113
- },
13114
-
13115
- // Get the footer and beforeFooter and afterFooter lines
13116
- // Args are: (tooltipItem, data)
13117
- getFooter: function() {
13118
- var me = this;
13119
- var callbacks = me._options.callbacks;
13120
-
13121
- var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
13122
- var footer = callbacks.footer.apply(me, arguments);
13123
- var afterFooter = callbacks.afterFooter.apply(me, arguments);
13124
-
13125
- var lines = [];
13126
- lines = pushOrConcat(lines, beforeFooter);
13127
- lines = pushOrConcat(lines, footer);
13128
- lines = pushOrConcat(lines, afterFooter);
13129
-
13130
- return lines;
13131
- },
13132
-
13133
- update: function(changed) {
13134
- var me = this;
13135
- var opts = me._options;
13136
-
13137
- // Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
13138
- // 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
13139
- // which breaks any animations.
13140
- var existingModel = me._model;
13141
- var model = me._model = getBaseModel(opts);
13142
- var active = me._active;
13143
-
13144
- var data = me._data;
13145
-
13146
- // In the case where active.length === 0 we need to keep these at existing values for good animations
13147
- var alignment = {
13148
- xAlign: existingModel.xAlign,
13149
- yAlign: existingModel.yAlign
13150
- };
13151
- var backgroundPoint = {
13152
- x: existingModel.x,
13153
- y: existingModel.y
13154
- };
13155
- var tooltipSize = {
13156
- width: existingModel.width,
13157
- height: existingModel.height
13158
- };
13159
- var tooltipPosition = {
13160
- x: existingModel.caretX,
13161
- y: existingModel.caretY
13162
- };
13163
-
13164
- var i, len;
13165
-
13166
- if (active.length) {
13167
- model.opacity = 1;
13168
-
13169
- var labelColors = [];
13170
- tooltipPosition = Chart.Tooltip.positioners[opts.position](active, me._eventPosition);
13171
-
13172
- var tooltipItems = [];
13173
- for (i = 0, len = active.length; i < len; ++i) {
13174
- tooltipItems.push(createTooltipItem(active[i]));
13175
- }
13176
-
13177
- // If the user provided a filter function, use it to modify the tooltip items
13178
- if (opts.filter) {
13179
- tooltipItems = tooltipItems.filter(function(a) {
13180
- return opts.filter(a, data);
13181
- });
13182
- }
13183
-
13184
- // If the user provided a sorting function, use it to modify the tooltip items
13185
- if (opts.itemSort) {
13186
- tooltipItems = tooltipItems.sort(function(a, b) {
13187
- return opts.itemSort(a, b, data);
13188
- });
13189
- }
13190
-
13191
- // Determine colors for boxes
13192
- helpers.each(tooltipItems, function(tooltipItem) {
13193
- labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
13194
- });
13195
-
13196
- // Build the Text Lines
13197
- model.title = me.getTitle(tooltipItems, data);
13198
- model.beforeBody = me.getBeforeBody(tooltipItems, data);
13199
- model.body = me.getBody(tooltipItems, data);
13200
- model.afterBody = me.getAfterBody(tooltipItems, data);
13201
- model.footer = me.getFooter(tooltipItems, data);
13202
-
13203
- // Initial positioning and colors
13204
- model.x = Math.round(tooltipPosition.x);
13205
- model.y = Math.round(tooltipPosition.y);
13206
- model.caretPadding = opts.caretPadding;
13207
- model.labelColors = labelColors;
13208
-
13209
- // data points
13210
- model.dataPoints = tooltipItems;
13211
-
13212
- // We need to determine alignment of the tooltip
13213
- tooltipSize = getTooltipSize(this, model);
13214
- alignment = determineAlignment(this, tooltipSize);
13215
- // Final Size and Position
13216
- backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment);
13217
- } else {
13218
- model.opacity = 0;
13219
- }
13220
-
13221
- model.xAlign = alignment.xAlign;
13222
- model.yAlign = alignment.yAlign;
13223
- model.x = backgroundPoint.x;
13224
- model.y = backgroundPoint.y;
13225
- model.width = tooltipSize.width;
13226
- model.height = tooltipSize.height;
13227
-
13228
- // Point where the caret on the tooltip points to
13229
- model.caretX = tooltipPosition.x;
13230
- model.caretY = tooltipPosition.y;
13231
-
13232
- me._model = model;
13233
-
13234
- if (changed && opts.custom) {
13235
- opts.custom.call(me, model);
13236
- }
13237
-
13238
- return me;
13239
- },
13240
- drawCaret: function(tooltipPoint, size) {
13241
- var ctx = this._chart.ctx;
13242
- var vm = this._view;
13243
- var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
13244
-
13245
- ctx.lineTo(caretPosition.x1, caretPosition.y1);
13246
- ctx.lineTo(caretPosition.x2, caretPosition.y2);
13247
- ctx.lineTo(caretPosition.x3, caretPosition.y3);
13248
- },
13249
- getCaretPosition: function(tooltipPoint, size, vm) {
13250
- var x1, x2, x3;
13251
- var y1, y2, y3;
13252
- var caretSize = vm.caretSize;
13253
- var cornerRadius = vm.cornerRadius;
13254
- var xAlign = vm.xAlign,
13255
- yAlign = vm.yAlign;
13256
- var ptX = tooltipPoint.x,
13257
- ptY = tooltipPoint.y;
13258
- var width = size.width,
13259
- height = size.height;
13260
-
13261
- if (yAlign === 'center') {
13262
- y2 = ptY + (height / 2);
13263
-
13264
- if (xAlign === 'left') {
13265
- x1 = ptX;
13266
- x2 = x1 - caretSize;
13267
- x3 = x1;
13268
-
13269
- y1 = y2 + caretSize;
13270
- y3 = y2 - caretSize;
13271
- } else {
13272
- x1 = ptX + width;
13273
- x2 = x1 + caretSize;
13274
- x3 = x1;
13275
-
13276
- y1 = y2 - caretSize;
13277
- y3 = y2 + caretSize;
13278
- }
13279
- } else {
13280
- if (xAlign === 'left') {
13281
- x2 = ptX + cornerRadius + (caretSize);
13282
- x1 = x2 - caretSize;
13283
- x3 = x2 + caretSize;
13284
- } else if (xAlign === 'right') {
13285
- x2 = ptX + width - cornerRadius - caretSize;
13286
- x1 = x2 - caretSize;
13287
- x3 = x2 + caretSize;
13288
- } else {
13289
- x2 = ptX + (width / 2);
13290
- x1 = x2 - caretSize;
13291
- x3 = x2 + caretSize;
13292
- }
13293
- if (yAlign === 'top') {
13294
- y1 = ptY;
13295
- y2 = y1 - caretSize;
13296
- y3 = y1;
13297
- } else {
13298
- y1 = ptY + height;
13299
- y2 = y1 + caretSize;
13300
- y3 = y1;
13301
- // invert drawing order
13302
- var tmp = x3;
13303
- x3 = x1;
13304
- x1 = tmp;
13305
- }
13306
- }
13307
- return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
13308
- },
13309
- drawTitle: function(pt, vm, ctx, opacity) {
13310
- var title = vm.title;
13311
-
13312
- if (title.length) {
13313
- ctx.textAlign = vm._titleAlign;
13314
- ctx.textBaseline = 'top';
13315
-
13316
- var titleFontSize = vm.titleFontSize,
13317
- titleSpacing = vm.titleSpacing;
13318
-
13319
- ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
13320
- ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
13321
-
13322
- var i, len;
13323
- for (i = 0, len = title.length; i < len; ++i) {
13324
- ctx.fillText(title[i], pt.x, pt.y);
13325
- pt.y += titleFontSize + titleSpacing; // Line Height and spacing
13326
-
13327
- if (i + 1 === title.length) {
13328
- pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
13329
- }
13330
- }
13331
- }
13332
- },
13333
- drawBody: function(pt, vm, ctx, opacity) {
13334
- var bodyFontSize = vm.bodyFontSize;
13335
- var bodySpacing = vm.bodySpacing;
13336
- var body = vm.body;
13337
-
13338
- ctx.textAlign = vm._bodyAlign;
13339
- ctx.textBaseline = 'top';
13340
-
13341
- var textColor = mergeOpacity(vm.bodyFontColor, opacity);
13342
- ctx.fillStyle = textColor;
13343
- ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
13344
-
13345
- // Before Body
13346
- var xLinePadding = 0;
13347
- var fillLineOfText = function(line) {
13348
- ctx.fillText(line, pt.x + xLinePadding, pt.y);
13349
- pt.y += bodyFontSize + bodySpacing;
13350
- };
13351
-
13352
- // Before body lines
13353
- helpers.each(vm.beforeBody, fillLineOfText);
13354
-
13355
- var drawColorBoxes = vm.displayColors;
13356
- xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
13357
-
13358
- // Draw body lines now
13359
- helpers.each(body, function(bodyItem, i) {
13360
- helpers.each(bodyItem.before, fillLineOfText);
13361
-
13362
- helpers.each(bodyItem.lines, function(line) {
13363
- // Draw Legend-like boxes if needed
13364
- if (drawColorBoxes) {
13365
- // Fill a white rect so that colours merge nicely if the opacity is < 1
13366
- ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
13367
- ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
13368
-
13369
- // Border
13370
- ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
13371
- ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
13372
-
13373
- // Inner square
13374
- ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
13375
- ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
13376
-
13377
- ctx.fillStyle = textColor;
13378
- }
13379
-
13380
- fillLineOfText(line);
13381
- });
13382
-
13383
- helpers.each(bodyItem.after, fillLineOfText);
13384
- });
13385
-
13386
- // Reset back to 0 for after body
13387
- xLinePadding = 0;
13388
-
13389
- // After body lines
13390
- helpers.each(vm.afterBody, fillLineOfText);
13391
- pt.y -= bodySpacing; // Remove last body spacing
13392
- },
13393
- drawFooter: function(pt, vm, ctx, opacity) {
13394
- var footer = vm.footer;
13395
-
13396
- if (footer.length) {
13397
- pt.y += vm.footerMarginTop;
13398
-
13399
- ctx.textAlign = vm._footerAlign;
13400
- ctx.textBaseline = 'top';
13401
-
13402
- ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
13403
- ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
13404
-
13405
- helpers.each(footer, function(line) {
13406
- ctx.fillText(line, pt.x, pt.y);
13407
- pt.y += vm.footerFontSize + vm.footerSpacing;
13408
- });
13409
- }
13410
- },
13411
- drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
13412
- ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
13413
- ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
13414
- ctx.lineWidth = vm.borderWidth;
13415
- var xAlign = vm.xAlign;
13416
- var yAlign = vm.yAlign;
13417
- var x = pt.x;
13418
- var y = pt.y;
13419
- var width = tooltipSize.width;
13420
- var height = tooltipSize.height;
13421
- var radius = vm.cornerRadius;
13422
-
13423
- ctx.beginPath();
13424
- ctx.moveTo(x + radius, y);
13425
- if (yAlign === 'top') {
13426
- this.drawCaret(pt, tooltipSize);
13427
- }
13428
- ctx.lineTo(x + width - radius, y);
13429
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
13430
- if (yAlign === 'center' && xAlign === 'right') {
13431
- this.drawCaret(pt, tooltipSize);
13432
- }
13433
- ctx.lineTo(x + width, y + height - radius);
13434
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
13435
- if (yAlign === 'bottom') {
13436
- this.drawCaret(pt, tooltipSize);
13437
- }
13438
- ctx.lineTo(x + radius, y + height);
13439
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
13440
- if (yAlign === 'center' && xAlign === 'left') {
13441
- this.drawCaret(pt, tooltipSize);
13442
- }
13443
- ctx.lineTo(x, y + radius);
13444
- ctx.quadraticCurveTo(x, y, x + radius, y);
13445
- ctx.closePath();
13446
-
13447
- ctx.fill();
13448
-
13449
- if (vm.borderWidth > 0) {
13450
- ctx.stroke();
13451
- }
13452
- },
13453
- draw: function() {
13454
- var ctx = this._chart.ctx;
13455
- var vm = this._view;
13456
-
13457
- if (vm.opacity === 0) {
13458
- return;
13459
- }
13460
-
13461
- var tooltipSize = {
13462
- width: vm.width,
13463
- height: vm.height
13464
- };
13465
- var pt = {
13466
- x: vm.x,
13467
- y: vm.y
13468
- };
13469
-
13470
- // IE11/Edge does not like very small opacities, so snap to 0
13471
- var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
13472
-
13473
- // Truthy/falsey value for empty tooltip
13474
- var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
13475
-
13476
- if (this._options.enabled && hasTooltipContent) {
13477
- // Draw Background
13478
- this.drawBackground(pt, vm, ctx, tooltipSize, opacity);
13479
-
13480
- // Draw Title, Body, and Footer
13481
- pt.x += vm.xPadding;
13482
- pt.y += vm.yPadding;
13483
-
13484
- // Titles
13485
- this.drawTitle(pt, vm, ctx, opacity);
13486
-
13487
- // Body
13488
- this.drawBody(pt, vm, ctx, opacity);
13489
-
13490
- // Footer
13491
- this.drawFooter(pt, vm, ctx, opacity);
13492
- }
13493
- },
13494
-
13495
- /**
13496
- * Handle an event
13497
- * @private
13498
- * @param {IEvent} event - The event to handle
13499
- * @returns {Boolean} true if the tooltip changed
13500
- */
13501
- handleEvent: function(e) {
13502
- var me = this;
13503
- var options = me._options;
13504
- var changed = false;
13505
-
13506
- me._lastActive = me._lastActive || [];
13507
-
13508
- // Find Active Elements for tooltips
13509
- if (e.type === 'mouseout') {
13510
- me._active = [];
13511
- } else {
13512
- me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
13513
- }
13514
-
13515
- // Remember Last Actives
13516
- changed = !helpers.arrayEquals(me._active, me._lastActive);
13517
-
13518
- // If tooltip didn't change, do not handle the target event
13519
- if (!changed) {
13520
- return false;
13521
- }
13522
-
13523
- me._lastActive = me._active;
13524
-
13525
- if (options.enabled || options.custom) {
13526
- me._eventPosition = {
13527
- x: e.x,
13528
- y: e.y
13529
- };
13530
-
13531
- var model = me._model;
13532
- me.update(true);
13533
- me.pivot();
13534
-
13535
- // See if our tooltip position changed
13536
- changed |= (model.x !== me._model.x) || (model.y !== me._model.y);
13537
- }
13538
-
13539
- return changed;
13540
- }
13541
- });
13542
-
13543
- /**
13544
- * @namespace Chart.Tooltip.positioners
13545
- */
13546
- Chart.Tooltip.positioners = {
13547
- /**
13548
- * Average mode places the tooltip at the average position of the elements shown
13549
- * @function Chart.Tooltip.positioners.average
13550
- * @param elements {ChartElement[]} the elements being displayed in the tooltip
13551
- * @returns {Point} tooltip position
13552
- */
13553
- average: function(elements) {
13554
- if (!elements.length) {
13555
- return false;
13556
- }
13557
-
13558
- var i, len;
13559
- var x = 0;
13560
- var y = 0;
13561
- var count = 0;
13562
-
13563
- for (i = 0, len = elements.length; i < len; ++i) {
13564
- var el = elements[i];
13565
- if (el && el.hasValue()) {
13566
- var pos = el.tooltipPosition();
13567
- x += pos.x;
13568
- y += pos.y;
13569
- ++count;
13570
- }
13571
- }
13572
-
13573
- return {
13574
- x: Math.round(x / count),
13575
- y: Math.round(y / count)
13576
- };
13577
- },
13578
-
13579
- /**
13580
- * Gets the tooltip position nearest of the item nearest to the event position
13581
- * @function Chart.Tooltip.positioners.nearest
13582
- * @param elements {Chart.Element[]} the tooltip elements
13583
- * @param eventPosition {Point} the position of the event in canvas coordinates
13584
- * @returns {Point} the tooltip position
13585
- */
13586
- nearest: function(elements, eventPosition) {
13587
- var x = eventPosition.x;
13588
- var y = eventPosition.y;
13589
-
13590
- var nearestElement;
13591
- var minDistance = Number.POSITIVE_INFINITY;
13592
- var i, len;
13593
- for (i = 0, len = elements.length; i < len; ++i) {
13594
- var el = elements[i];
13595
- if (el && el.hasValue()) {
13596
- var center = el.getCenterPoint();
13597
- var d = helpers.distanceBetweenPoints(eventPosition, center);
13598
-
13599
- if (d < minDistance) {
13600
- minDistance = d;
13601
- nearestElement = el;
13602
- }
13603
- }
13604
- }
13605
-
13606
- if (nearestElement) {
13607
- var tp = nearestElement.tooltipPosition();
13608
- x = tp.x;
13609
- y = tp.y;
13610
- }
13611
-
13612
- return {
13613
- x: x,
13614
- y: y
13615
- };
13616
- }
13617
- };
13618
- };
13619
-
13620
- },{}],35:[function(require,module,exports){
13621
- 'use strict';
13622
-
13623
- module.exports = function(Chart) {
13624
-
13625
- var helpers = Chart.helpers,
13626
- globalOpts = Chart.defaults.global;
13627
-
13628
- globalOpts.elements.arc = {
13629
- backgroundColor: globalOpts.defaultColor,
13630
- borderColor: '#fff',
13631
- borderWidth: 2
13632
- };
13633
-
13634
- Chart.elements.Arc = Chart.Element.extend({
13635
- inLabelRange: function(mouseX) {
13636
- var vm = this._view;
13637
-
13638
- if (vm) {
13639
- return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
13640
- }
13641
- return false;
13642
- },
13643
- inRange: function(chartX, chartY) {
13644
- var vm = this._view;
13645
-
13646
- if (vm) {
13647
- var pointRelativePosition = helpers.getAngleFromPoint(vm, {
13648
- x: chartX,
13649
- y: chartY
13650
- }),
13651
- angle = pointRelativePosition.angle,
13652
- distance = pointRelativePosition.distance;
13653
-
13654
- // Sanitise angle range
13655
- var startAngle = vm.startAngle;
13656
- var endAngle = vm.endAngle;
13657
- while (endAngle < startAngle) {
13658
- endAngle += 2.0 * Math.PI;
13659
- }
13660
- while (angle > endAngle) {
13661
- angle -= 2.0 * Math.PI;
13662
- }
13663
- while (angle < startAngle) {
13664
- angle += 2.0 * Math.PI;
13665
- }
13666
-
13667
- // Check if within the range of the open/close angle
13668
- var betweenAngles = (angle >= startAngle && angle <= endAngle),
13669
- withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
13670
-
13671
- return (betweenAngles && withinRadius);
13672
- }
13673
- return false;
13674
- },
13675
- getCenterPoint: function() {
13676
- var vm = this._view;
13677
- var halfAngle = (vm.startAngle + vm.endAngle) / 2;
13678
- var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
13679
- return {
13680
- x: vm.x + Math.cos(halfAngle) * halfRadius,
13681
- y: vm.y + Math.sin(halfAngle) * halfRadius
13682
- };
13683
- },
13684
- getArea: function() {
13685
- var vm = this._view;
13686
- return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
13687
- },
13688
- tooltipPosition: function() {
13689
- var vm = this._view;
13690
-
13691
- var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2),
13692
- rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
13693
- return {
13694
- x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
13695
- y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
13696
- };
13697
- },
13698
- draw: function() {
13699
-
13700
- var ctx = this._chart.ctx,
13701
- vm = this._view,
13702
- sA = vm.startAngle,
13703
- eA = vm.endAngle;
13704
-
13705
- ctx.beginPath();
13706
-
13707
- ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
13708
- ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
13709
-
13710
- ctx.closePath();
13711
- ctx.strokeStyle = vm.borderColor;
13712
- ctx.lineWidth = vm.borderWidth;
13713
-
13714
- ctx.fillStyle = vm.backgroundColor;
13715
-
13716
- ctx.fill();
13717
- ctx.lineJoin = 'bevel';
13718
-
13719
- if (vm.borderWidth) {
13720
- ctx.stroke();
13721
- }
13722
- }
13723
- });
13724
- };
13725
-
13726
- },{}],36:[function(require,module,exports){
13727
- 'use strict';
13728
-
13729
- module.exports = function(Chart) {
13730
-
13731
- var helpers = Chart.helpers;
13732
- var globalDefaults = Chart.defaults.global;
13733
-
13734
- Chart.defaults.global.elements.line = {
13735
- tension: 0.4,
13736
- backgroundColor: globalDefaults.defaultColor,
13737
- borderWidth: 3,
13738
- borderColor: globalDefaults.defaultColor,
13739
- borderCapStyle: 'butt',
13740
- borderDash: [],
13741
- borderDashOffset: 0.0,
13742
- borderJoinStyle: 'miter',
13743
- capBezierPoints: true,
13744
- fill: true, // do we fill in the area between the line and its base axis
13745
- };
13746
-
13747
- Chart.elements.Line = Chart.Element.extend({
13748
- draw: function() {
13749
- var me = this;
13750
- var vm = me._view;
13751
- var ctx = me._chart.ctx;
13752
- var spanGaps = vm.spanGaps;
13753
- var points = me._children.slice(); // clone array
13754
- var globalOptionLineElements = globalDefaults.elements.line;
13755
- var lastDrawnIndex = -1;
13756
- var index, current, previous, currentVM;
13757
-
13758
- // If we are looping, adding the first point again
13759
- if (me._loop && points.length) {
13760
- points.push(points[0]);
13761
- }
13762
-
13763
- ctx.save();
13764
-
13765
- // Stroke Line Options
13766
- ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
13767
-
13768
- // IE 9 and 10 do not support line dash
13769
- if (ctx.setLineDash) {
13770
- ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
13771
- }
13772
-
13773
- ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
13774
- ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
13775
- ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
13776
- ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
13777
-
13778
- // Stroke Line
13779
- ctx.beginPath();
13780
- lastDrawnIndex = -1;
13781
-
13782
- for (index = 0; index < points.length; ++index) {
13783
- current = points[index];
13784
- previous = helpers.previousItem(points, index);
13785
- currentVM = current._view;
13786
-
13787
- // First point moves to it's starting position no matter what
13788
- if (index === 0) {
13789
- if (!currentVM.skip) {
13790
- ctx.moveTo(currentVM.x, currentVM.y);
13791
- lastDrawnIndex = index;
13792
- }
13793
- } else {
13794
- previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
13795
-
13796
- if (!currentVM.skip) {
13797
- if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
13798
- // There was a gap and this is the first point after the gap
13799
- ctx.moveTo(currentVM.x, currentVM.y);
13800
- } else {
13801
- // Line to next point
13802
- helpers.canvas.lineTo(ctx, previous._view, current._view);
13803
- }
13804
- lastDrawnIndex = index;
13805
- }
13806
- }
13807
- }
13808
-
13809
- ctx.stroke();
13810
- ctx.restore();
13811
- }
13812
- });
13813
- };
13814
-
13815
- },{}],37:[function(require,module,exports){
13816
- 'use strict';
13817
-
13818
- module.exports = function(Chart) {
13819
-
13820
- var helpers = Chart.helpers,
13821
- globalOpts = Chart.defaults.global,
13822
- defaultColor = globalOpts.defaultColor;
13823
-
13824
- globalOpts.elements.point = {
13825
- radius: 3,
13826
- pointStyle: 'circle',
13827
- backgroundColor: defaultColor,
13828
- borderWidth: 1,
13829
- borderColor: defaultColor,
13830
- // Hover
13831
- hitRadius: 1,
13832
- hoverRadius: 4,
13833
- hoverBorderWidth: 1
13834
- };
13835
-
13836
- function xRange(mouseX) {
13837
- var vm = this._view;
13838
- return vm ? (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
13839
- }
13840
-
13841
- function yRange(mouseY) {
13842
- var vm = this._view;
13843
- return vm ? (Math.pow(mouseY - vm.y, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
13844
- }
13845
-
13846
- Chart.elements.Point = Chart.Element.extend({
13847
- inRange: function(mouseX, mouseY) {
13848
- var vm = this._view;
13849
- return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
13850
- },
13851
-
13852
- inLabelRange: xRange,
13853
- inXRange: xRange,
13854
- inYRange: yRange,
13855
-
13856
- getCenterPoint: function() {
13857
- var vm = this._view;
13858
- return {
13859
- x: vm.x,
13860
- y: vm.y
13861
- };
13862
- },
13863
- getArea: function() {
13864
- return Math.PI * Math.pow(this._view.radius, 2);
13865
- },
13866
- tooltipPosition: function() {
13867
- var vm = this._view;
13868
- return {
13869
- x: vm.x,
13870
- y: vm.y,
13871
- padding: vm.radius + vm.borderWidth
13872
- };
13873
- },
13874
- draw: function(chartArea) {
13875
- var vm = this._view;
13876
- var model = this._model;
13877
- var ctx = this._chart.ctx;
13878
- var pointStyle = vm.pointStyle;
13879
- var radius = vm.radius;
13880
- var x = vm.x;
13881
- var y = vm.y;
13882
- var color = Chart.helpers.color;
13883
- var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
13884
- var ratio = 0;
13885
-
13886
- if (vm.skip) {
13887
- return;
13888
- }
13889
-
13890
- ctx.strokeStyle = vm.borderColor || defaultColor;
13891
- ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth);
13892
- ctx.fillStyle = vm.backgroundColor || defaultColor;
13893
-
13894
- // Cliping for Points.
13895
- // going out from inner charArea?
13896
- if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right*errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom*errMargin < model.y))) {
13897
- // Point fade out
13898
- if (model.x < chartArea.left) {
13899
- ratio = (x - model.x) / (chartArea.left - model.x);
13900
- } else if (chartArea.right*errMargin < model.x) {
13901
- ratio = (model.x - x) / (model.x - chartArea.right);
13902
- } else if (model.y < chartArea.top) {
13903
- ratio = (y - model.y) / (chartArea.top - model.y);
13904
- } else if (chartArea.bottom*errMargin < model.y) {
13905
- ratio = (model.y - y) / (model.y - chartArea.bottom);
13906
- }
13907
- ratio = Math.round(ratio*100) / 100;
13908
- ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
13909
- ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
13910
- }
13911
-
13912
- Chart.canvasHelpers.drawPoint(ctx, pointStyle, radius, x, y);
13913
- }
13914
- });
13915
- };
13916
-
13917
- },{}],38:[function(require,module,exports){
13918
- 'use strict';
13919
-
13920
- module.exports = function(Chart) {
13921
-
13922
- var globalOpts = Chart.defaults.global;
13923
-
13924
- globalOpts.elements.rectangle = {
13925
- backgroundColor: globalOpts.defaultColor,
13926
- borderWidth: 0,
13927
- borderColor: globalOpts.defaultColor,
13928
- borderSkipped: 'bottom'
13929
- };
13930
-
13931
- function isVertical(bar) {
13932
- return bar._view.width !== undefined;
13933
- }
13934
-
13935
- /**
13936
- * Helper function to get the bounds of the bar regardless of the orientation
13937
- * @private
13938
- * @param bar {Chart.Element.Rectangle} the bar
13939
- * @return {Bounds} bounds of the bar
13940
- */
13941
- function getBarBounds(bar) {
13942
- var vm = bar._view;
13943
- var x1, x2, y1, y2;
13944
-
13945
- if (isVertical(bar)) {
13946
- // vertical
13947
- var halfWidth = vm.width / 2;
13948
- x1 = vm.x - halfWidth;
13949
- x2 = vm.x + halfWidth;
13950
- y1 = Math.min(vm.y, vm.base);
13951
- y2 = Math.max(vm.y, vm.base);
13952
- } else {
13953
- // horizontal bar
13954
- var halfHeight = vm.height / 2;
13955
- x1 = Math.min(vm.x, vm.base);
13956
- x2 = Math.max(vm.x, vm.base);
13957
- y1 = vm.y - halfHeight;
13958
- y2 = vm.y + halfHeight;
13959
- }
13960
-
13961
- return {
13962
- left: x1,
13963
- top: y1,
13964
- right: x2,
13965
- bottom: y2
13966
- };
13967
- }
13968
-
13969
- Chart.elements.Rectangle = Chart.Element.extend({
13970
- draw: function() {
13971
- var ctx = this._chart.ctx;
13972
- var vm = this._view;
13973
- var left, right, top, bottom, signX, signY, borderSkipped;
13974
- var borderWidth = vm.borderWidth;
13975
-
13976
- if (!vm.horizontal) {
13977
- // bar
13978
- left = vm.x - vm.width / 2;
13979
- right = vm.x + vm.width / 2;
13980
- top = vm.y;
13981
- bottom = vm.base;
13982
- signX = 1;
13983
- signY = bottom > top? 1: -1;
13984
- borderSkipped = vm.borderSkipped || 'bottom';
13985
- } else {
13986
- // horizontal bar
13987
- left = vm.base;
13988
- right = vm.x;
13989
- top = vm.y - vm.height / 2;
13990
- bottom = vm.y + vm.height / 2;
13991
- signX = right > left? 1: -1;
13992
- signY = 1;
13993
- borderSkipped = vm.borderSkipped || 'left';
13994
- }
13995
-
13996
- // Canvas doesn't allow us to stroke inside the width so we can
13997
- // adjust the sizes to fit if we're setting a stroke on the line
13998
- if (borderWidth) {
13999
- // borderWidth shold be less than bar width and bar height.
14000
- var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
14001
- borderWidth = borderWidth > barSize? barSize: borderWidth;
14002
- var halfStroke = borderWidth / 2;
14003
- // Adjust borderWidth when bar top position is near vm.base(zero).
14004
- var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
14005
- var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
14006
- var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
14007
- var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
14008
- // not become a vertical line?
14009
- if (borderLeft !== borderRight) {
14010
- top = borderTop;
14011
- bottom = borderBottom;
14012
- }
14013
- // not become a horizontal line?
14014
- if (borderTop !== borderBottom) {
14015
- left = borderLeft;
14016
- right = borderRight;
14017
- }
14018
- }
14019
-
14020
- ctx.beginPath();
14021
- ctx.fillStyle = vm.backgroundColor;
14022
- ctx.strokeStyle = vm.borderColor;
14023
- ctx.lineWidth = borderWidth;
14024
-
14025
- // Corner points, from bottom-left to bottom-right clockwise
14026
- // | 1 2 |
14027
- // | 0 3 |
14028
- var corners = [
14029
- [left, bottom],
14030
- [left, top],
14031
- [right, top],
14032
- [right, bottom]
14033
- ];
14034
-
14035
- // Find first (starting) corner with fallback to 'bottom'
14036
- var borders = ['bottom', 'left', 'top', 'right'];
14037
- var startCorner = borders.indexOf(borderSkipped, 0);
14038
- if (startCorner === -1) {
14039
- startCorner = 0;
14040
- }
14041
-
14042
- function cornerAt(index) {
14043
- return corners[(startCorner + index) % 4];
14044
- }
14045
-
14046
- // Draw rectangle from 'startCorner'
14047
- var corner = cornerAt(0);
14048
- ctx.moveTo(corner[0], corner[1]);
14049
-
14050
- for (var i = 1; i < 4; i++) {
14051
- corner = cornerAt(i);
14052
- ctx.lineTo(corner[0], corner[1]);
14053
- }
14054
-
14055
- ctx.fill();
14056
- if (borderWidth) {
14057
- ctx.stroke();
14058
- }
14059
- },
14060
- height: function() {
14061
- var vm = this._view;
14062
- return vm.base - vm.y;
14063
- },
14064
- inRange: function(mouseX, mouseY) {
14065
- var inRange = false;
14066
-
14067
- if (this._view) {
14068
- var bounds = getBarBounds(this);
14069
- inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
14070
- }
14071
-
14072
- return inRange;
14073
- },
14074
- inLabelRange: function(mouseX, mouseY) {
14075
- var me = this;
14076
- if (!me._view) {
14077
- return false;
14078
- }
14079
-
14080
- var inRange = false;
14081
- var bounds = getBarBounds(me);
14082
-
14083
- if (isVertical(me)) {
14084
- inRange = mouseX >= bounds.left && mouseX <= bounds.right;
14085
- } else {
14086
- inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
14087
- }
14088
-
14089
- return inRange;
14090
- },
14091
- inXRange: function(mouseX) {
14092
- var bounds = getBarBounds(this);
14093
- return mouseX >= bounds.left && mouseX <= bounds.right;
14094
- },
14095
- inYRange: function(mouseY) {
14096
- var bounds = getBarBounds(this);
14097
- return mouseY >= bounds.top && mouseY <= bounds.bottom;
14098
- },
14099
- getCenterPoint: function() {
14100
- var vm = this._view;
14101
- var x, y;
14102
- if (isVertical(this)) {
14103
- x = vm.x;
14104
- y = (vm.y + vm.base) / 2;
14105
- } else {
14106
- x = (vm.x + vm.base) / 2;
14107
- y = vm.y;
14108
- }
14109
-
14110
- return {x: x, y: y};
14111
- },
14112
- getArea: function() {
14113
- var vm = this._view;
14114
- return vm.width * Math.abs(vm.y - vm.base);
14115
- },
14116
- tooltipPosition: function() {
14117
- var vm = this._view;
14118
- return {
14119
- x: vm.x,
14120
- y: vm.y
14121
- };
14122
- }
14123
- });
14124
-
14125
- };
14126
-
14127
- },{}],39:[function(require,module,exports){
14128
- 'use strict';
14129
-
14130
- // Chart.Platform implementation for targeting a web browser
14131
- module.exports = function(Chart) {
14132
- var helpers = Chart.helpers;
14133
-
14134
- // DOM event types -> Chart.js event types.
14135
- // Note: only events with different types are mapped.
14136
- // https://developer.mozilla.org/en-US/docs/Web/Events
14137
- var eventTypeMap = {
14138
- // Touch events
14139
- touchstart: 'mousedown',
14140
- touchmove: 'mousemove',
14141
- touchend: 'mouseup',
14142
-
14143
- // Pointer events
14144
- pointerenter: 'mouseenter',
14145
- pointerdown: 'mousedown',
14146
- pointermove: 'mousemove',
14147
- pointerup: 'mouseup',
14148
- pointerleave: 'mouseout',
14149
- pointerout: 'mouseout'
14150
- };
14151
-
14152
- /**
14153
- * The "used" size is the final value of a dimension property after all calculations have
14154
- * been performed. This method uses the computed style of `element` but returns undefined
14155
- * if the computed style is not expressed in pixels. That can happen in some cases where
14156
- * `element` has a size relative to its parent and this last one is not yet displayed,
14157
- * for example because of `display: none` on a parent node.
14158
- * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
14159
- * @returns {Number} Size in pixels or undefined if unknown.
14160
- */
14161
- function readUsedSize(element, property) {
14162
- var value = helpers.getStyle(element, property);
14163
- var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
14164
- return matches? Number(matches[1]) : undefined;
14165
- }
14166
-
14167
- /**
14168
- * Initializes the canvas style and render size without modifying the canvas display size,
14169
- * since responsiveness is handled by the controller.resize() method. The config is used
14170
- * to determine the aspect ratio to apply in case no explicit height has been specified.
14171
- */
14172
- function initCanvas(canvas, config) {
14173
- var style = canvas.style;
14174
-
14175
- // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
14176
- // returns null or '' if no explicit value has been set to the canvas attribute.
14177
- var renderHeight = canvas.getAttribute('height');
14178
- var renderWidth = canvas.getAttribute('width');
14179
-
14180
- // Chart.js modifies some canvas values that we want to restore on destroy
14181
- canvas._chartjs = {
14182
- initial: {
14183
- height: renderHeight,
14184
- width: renderWidth,
14185
- style: {
14186
- display: style.display,
14187
- height: style.height,
14188
- width: style.width
14189
- }
14190
- }
14191
- };
14192
-
14193
- // Force canvas to display as block to avoid extra space caused by inline
14194
- // elements, which would interfere with the responsive resize process.
14195
- // https://github.com/chartjs/Chart.js/issues/2538
14196
- style.display = style.display || 'block';
14197
-
14198
- if (renderWidth === null || renderWidth === '') {
14199
- var displayWidth = readUsedSize(canvas, 'width');
14200
- if (displayWidth !== undefined) {
14201
- canvas.width = displayWidth;
14202
- }
14203
- }
14204
-
14205
- if (renderHeight === null || renderHeight === '') {
14206
- if (canvas.style.height === '') {
14207
- // If no explicit render height and style height, let's apply the aspect ratio,
14208
- // which one can be specified by the user but also by charts as default option
14209
- // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
14210
- canvas.height = canvas.width / (config.options.aspectRatio || 2);
14211
- } else {
14212
- var displayHeight = readUsedSize(canvas, 'height');
14213
- if (displayWidth !== undefined) {
14214
- canvas.height = displayHeight;
14215
- }
14216
- }
14217
- }
14218
-
14219
- return canvas;
14220
- }
14221
-
14222
- function createEvent(type, chart, x, y, nativeEvent) {
14223
- return {
14224
- type: type,
14225
- chart: chart,
14226
- native: nativeEvent || null,
14227
- x: x !== undefined? x : null,
14228
- y: y !== undefined? y : null,
14229
- };
14230
- }
14231
-
14232
- function fromNativeEvent(event, chart) {
14233
- var type = eventTypeMap[event.type] || event.type;
14234
- var pos = helpers.getRelativePosition(event, chart);
14235
- return createEvent(type, chart, pos.x, pos.y, event);
14236
- }
14237
-
14238
- function createResizer(handler) {
14239
- var iframe = document.createElement('iframe');
14240
- iframe.className = 'chartjs-hidden-iframe';
14241
- iframe.style.cssText =
14242
- 'display:block;'+
14243
- 'overflow:hidden;'+
14244
- 'border:0;'+
14245
- 'margin:0;'+
14246
- 'top:0;'+
14247
- 'left:0;'+
14248
- 'bottom:0;'+
14249
- 'right:0;'+
14250
- 'height:100%;'+
14251
- 'width:100%;'+
14252
- 'position:absolute;'+
14253
- 'pointer-events:none;'+
14254
- 'z-index:-1;';
14255
-
14256
- // Prevent the iframe to gain focus on tab.
14257
- // https://github.com/chartjs/Chart.js/issues/3090
14258
- iframe.tabIndex = -1;
14259
-
14260
- // If the iframe is re-attached to the DOM, the resize listener is removed because the
14261
- // content is reloaded, so make sure to install the handler after the iframe is loaded.
14262
- // https://github.com/chartjs/Chart.js/issues/3521
14263
- helpers.addEvent(iframe, 'load', function() {
14264
- helpers.addEvent(iframe.contentWindow || iframe, 'resize', handler);
14265
-
14266
- // The iframe size might have changed while loading, which can also
14267
- // happen if the size has been changed while detached from the DOM.
14268
- handler();
14269
- });
14270
-
14271
- return iframe;
14272
- }
14273
-
14274
- function addResizeListener(node, listener, chart) {
14275
- var stub = node._chartjs = {
14276
- ticking: false
14277
- };
14278
-
14279
- // Throttle the callback notification until the next animation frame.
14280
- var notify = function() {
14281
- if (!stub.ticking) {
14282
- stub.ticking = true;
14283
- helpers.requestAnimFrame.call(window, function() {
14284
- if (stub.resizer) {
14285
- stub.ticking = false;
14286
- return listener(createEvent('resize', chart));
14287
- }
14288
- });
14289
- }
14290
- };
14291
-
14292
- // Let's keep track of this added iframe and thus avoid DOM query when removing it.
14293
- stub.resizer = createResizer(notify);
14294
-
14295
- node.insertBefore(stub.resizer, node.firstChild);
14296
- }
14297
-
14298
- function removeResizeListener(node) {
14299
- if (!node || !node._chartjs) {
14300
- return;
14301
- }
14302
-
14303
- var resizer = node._chartjs.resizer;
14304
- if (resizer) {
14305
- resizer.parentNode.removeChild(resizer);
14306
- node._chartjs.resizer = null;
14307
- }
14308
-
14309
- delete node._chartjs;
14310
- }
14311
-
14312
- return {
14313
- acquireContext: function(item, config) {
14314
- if (typeof item === 'string') {
14315
- item = document.getElementById(item);
14316
- } else if (item.length) {
14317
- // Support for array based queries (such as jQuery)
14318
- item = item[0];
14319
- }
14320
-
14321
- if (item && item.canvas) {
14322
- // Support for any object associated to a canvas (including a context2d)
14323
- item = item.canvas;
14324
- }
14325
-
14326
- // To prevent canvas fingerprinting, some add-ons undefine the getContext
14327
- // method, for example: https://github.com/kkapsner/CanvasBlocker
14328
- // https://github.com/chartjs/Chart.js/issues/2807
14329
- var context = item && item.getContext && item.getContext('2d');
14330
-
14331
- // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
14332
- // inside an iframe or when running in a protected environment. We could guess the
14333
- // types from their toString() value but let's keep things flexible and assume it's
14334
- // a sufficient condition if the item has a context2D which has item as `canvas`.
14335
- // https://github.com/chartjs/Chart.js/issues/3887
14336
- // https://github.com/chartjs/Chart.js/issues/4102
14337
- // https://github.com/chartjs/Chart.js/issues/4152
14338
- if (context && context.canvas === item) {
14339
- initCanvas(item, config);
14340
- return context;
14341
- }
14342
-
14343
- return null;
14344
- },
14345
-
14346
- releaseContext: function(context) {
14347
- var canvas = context.canvas;
14348
- if (!canvas._chartjs) {
14349
- return;
14350
- }
14351
-
14352
- var initial = canvas._chartjs.initial;
14353
- ['height', 'width'].forEach(function(prop) {
14354
- var value = initial[prop];
14355
- if (value === undefined || value === null) {
14356
- canvas.removeAttribute(prop);
14357
- } else {
14358
- canvas.setAttribute(prop, value);
14359
- }
14360
- });
14361
-
14362
- helpers.each(initial.style || {}, function(value, key) {
14363
- canvas.style[key] = value;
14364
- });
14365
-
14366
- // The canvas render size might have been changed (and thus the state stack discarded),
14367
- // we can't use save() and restore() to restore the initial state. So make sure that at
14368
- // least the canvas context is reset to the default state by setting the canvas width.
14369
- // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
14370
- canvas.width = canvas.width;
14371
-
14372
- delete canvas._chartjs;
14373
- },
14374
-
14375
- addEventListener: function(chart, type, listener) {
14376
- var canvas = chart.canvas;
14377
- if (type === 'resize') {
14378
- // Note: the resize event is not supported on all browsers.
14379
- addResizeListener(canvas.parentNode, listener, chart);
14380
- return;
14381
- }
14382
-
14383
- var stub = listener._chartjs || (listener._chartjs = {});
14384
- var proxies = stub.proxies || (stub.proxies = {});
14385
- var proxy = proxies[chart.id + '_' + type] = function(event) {
14386
- listener(fromNativeEvent(event, chart));
14387
- };
14388
-
14389
- helpers.addEvent(canvas, type, proxy);
14390
- },
14391
-
14392
- removeEventListener: function(chart, type, listener) {
14393
- var canvas = chart.canvas;
14394
- if (type === 'resize') {
14395
- // Note: the resize event is not supported on all browsers.
14396
- removeResizeListener(canvas.parentNode, listener);
14397
- return;
14398
- }
14399
-
14400
- var stub = listener._chartjs || {};
14401
- var proxies = stub.proxies || {};
14402
- var proxy = proxies[chart.id + '_' + type];
14403
- if (!proxy) {
14404
- return;
14405
- }
14406
-
14407
- helpers.removeEvent(canvas, type, proxy);
14408
- }
14409
- };
14410
- };
14411
-
14412
- },{}],40:[function(require,module,exports){
14413
- 'use strict';
14414
-
14415
- // By default, select the browser (DOM) platform.
14416
- // @TODO Make possible to select another platform at build time.
14417
- var implementation = require(39);
14418
-
14419
- module.exports = function(Chart) {
14420
- /**
14421
- * @namespace Chart.platform
14422
- * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
14423
- * @since 2.4.0
14424
- */
14425
- Chart.platform = {
14426
- /**
14427
- * Called at chart construction time, returns a context2d instance implementing
14428
- * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
14429
- * @param {*} item - The native item from which to acquire context (platform specific)
14430
- * @param {Object} options - The chart options
14431
- * @returns {CanvasRenderingContext2D} context2d instance
14432
- */
14433
- acquireContext: function() {},
14434
-
14435
- /**
14436
- * Called at chart destruction time, releases any resources associated to the context
14437
- * previously returned by the acquireContext() method.
14438
- * @param {CanvasRenderingContext2D} context - The context2d instance
14439
- * @returns {Boolean} true if the method succeeded, else false
14440
- */
14441
- releaseContext: function() {},
14442
-
14443
- /**
14444
- * Registers the specified listener on the given chart.
14445
- * @param {Chart} chart - Chart from which to listen for event
14446
- * @param {String} type - The ({@link IEvent}) type to listen for
14447
- * @param {Function} listener - Receives a notification (an object that implements
14448
- * the {@link IEvent} interface) when an event of the specified type occurs.
14449
- */
14450
- addEventListener: function() {},
14451
-
14452
- /**
14453
- * Removes the specified listener previously registered with addEventListener.
14454
- * @param {Chart} chart -Chart from which to remove the listener
14455
- * @param {String} type - The ({@link IEvent}) type to remove
14456
- * @param {Function} listener - The listener function to remove from the event target.
14457
- */
14458
- removeEventListener: function() {}
14459
- };
14460
-
14461
- /**
14462
- * @interface IPlatform
14463
- * Allows abstracting platform dependencies away from the chart
14464
- * @borrows Chart.platform.acquireContext as acquireContext
14465
- * @borrows Chart.platform.releaseContext as releaseContext
14466
- * @borrows Chart.platform.addEventListener as addEventListener
14467
- * @borrows Chart.platform.removeEventListener as removeEventListener
14468
- */
14469
-
14470
- /**
14471
- * @interface IEvent
14472
- * @prop {String} type - The event type name, possible values are:
14473
- * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
14474
- * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
14475
- * @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
14476
- * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
14477
- * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
14478
- */
14479
-
14480
- Chart.helpers.extend(Chart.platform, implementation(Chart));
14481
- };
14482
-
14483
- },{"39":39}],41:[function(require,module,exports){
14484
- 'use strict';
14485
-
14486
- module.exports = function(Chart) {
14487
- /**
14488
- * Plugin based on discussion from the following Chart.js issues:
14489
- * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569
14490
- * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897
14491
- */
14492
- Chart.defaults.global.plugins.filler = {
14493
- propagate: true
14494
- };
14495
-
14496
- var defaults = Chart.defaults;
14497
- var helpers = Chart.helpers;
14498
- var mappers = {
14499
- dataset: function(source) {
14500
- var index = source.fill;
14501
- var chart = source.chart;
14502
- var meta = chart.getDatasetMeta(index);
14503
- var visible = meta && chart.isDatasetVisible(index);
14504
- var points = (visible && meta.dataset._children) || [];
14505
-
14506
- return !points.length? null : function(point, i) {
14507
- return points[i]._view || null;
14508
- };
14509
- },
14510
-
14511
- boundary: function(source) {
14512
- var boundary = source.boundary;
14513
- var x = boundary? boundary.x : null;
14514
- var y = boundary? boundary.y : null;
14515
-
14516
- return function(point) {
14517
- return {
14518
- x: x === null? point.x : x,
14519
- y: y === null? point.y : y,
14520
- };
14521
- };
14522
- }
14523
- };
14524
-
14525
- // @todo if (fill[0] === '#')
14526
- function decodeFill(el, index, count) {
14527
- var model = el._model || {};
14528
- var fill = model.fill;
14529
- var target;
14530
-
14531
- if (fill === undefined) {
14532
- fill = !!model.backgroundColor;
14533
- }
14534
-
14535
- if (fill === false || fill === null) {
14536
- return false;
14537
- }
14538
-
14539
- if (fill === true) {
14540
- return 'origin';
14541
- }
14542
-
14543
- target = parseFloat(fill, 10);
14544
- if (isFinite(target) && Math.floor(target) === target) {
14545
- if (fill[0] === '-' || fill[0] === '+') {
14546
- target = index + target;
14547
- }
14548
-
14549
- if (target === index || target < 0 || target >= count) {
14550
- return false;
14551
- }
14552
-
14553
- return target;
14554
- }
14555
-
14556
- switch (fill) {
14557
- // compatibility
14558
- case 'bottom':
14559
- return 'start';
14560
- case 'top':
14561
- return 'end';
14562
- case 'zero':
14563
- return 'origin';
14564
- // supported boundaries
14565
- case 'origin':
14566
- case 'start':
14567
- case 'end':
14568
- return fill;
14569
- // invalid fill values
14570
- default:
14571
- return false;
14572
- }
14573
- }
14574
-
14575
- function computeBoundary(source) {
14576
- var model = source.el._model || {};
14577
- var scale = source.el._scale || {};
14578
- var fill = source.fill;
14579
- var target = null;
14580
- var horizontal;
14581
-
14582
- if (isFinite(fill)) {
14583
- return null;
14584
- }
14585
-
14586
- // Backward compatibility: until v3, we still need to support boundary values set on
14587
- // the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
14588
- // controllers might still use it (e.g. the Smith chart).
14589
-
14590
- if (fill === 'start') {
14591
- target = model.scaleBottom === undefined? scale.bottom : model.scaleBottom;
14592
- } else if (fill === 'end') {
14593
- target = model.scaleTop === undefined? scale.top : model.scaleTop;
14594
- } else if (model.scaleZero !== undefined) {
14595
- target = model.scaleZero;
14596
- } else if (scale.getBasePosition) {
14597
- target = scale.getBasePosition();
14598
- } else if (scale.getBasePixel) {
14599
- target = scale.getBasePixel();
14600
- }
14601
-
14602
- if (target !== undefined && target !== null) {
14603
- if (target.x !== undefined && target.y !== undefined) {
14604
- return target;
14605
- }
14606
-
14607
- if (typeof target === 'number' && isFinite(target)) {
14608
- horizontal = scale.isHorizontal();
14609
- return {
14610
- x: horizontal? target : null,
14611
- y: horizontal? null : target
14612
- };
14613
- }
14614
- }
14615
-
14616
- return null;
14617
- }
14618
-
14619
- function resolveTarget(sources, index, propagate) {
14620
- var source = sources[index];
14621
- var fill = source.fill;
14622
- var visited = [index];
14623
- var target;
14624
-
14625
- if (!propagate) {
14626
- return fill;
14627
- }
14628
-
14629
- while (fill !== false && visited.indexOf(fill) === -1) {
14630
- if (!isFinite(fill)) {
14631
- return fill;
14632
- }
14633
-
14634
- target = sources[fill];
14635
- if (!target) {
14636
- return false;
14637
- }
14638
-
14639
- if (target.visible) {
14640
- return fill;
14641
- }
14642
-
14643
- visited.push(fill);
14644
- fill = target.fill;
14645
- }
14646
-
14647
- return false;
14648
- }
14649
-
14650
- function createMapper(source) {
14651
- var fill = source.fill;
14652
- var type = 'dataset';
14653
-
14654
- if (fill === false) {
14655
- return null;
14656
- }
14657
-
14658
- if (!isFinite(fill)) {
14659
- type = 'boundary';
14660
- }
14661
-
14662
- return mappers[type](source);
14663
- }
14664
-
14665
- function isDrawable(point) {
14666
- return point && !point.skip;
14667
- }
14668
-
14669
- function drawArea(ctx, curve0, curve1, len0, len1) {
14670
- var i;
14671
-
14672
- if (!len0 || !len1) {
14673
- return;
14674
- }
14675
-
14676
- // building first area curve (normal)
14677
- ctx.moveTo(curve0[0].x, curve0[0].y);
14678
- for (i=1; i<len0; ++i) {
14679
- helpers.canvas.lineTo(ctx, curve0[i-1], curve0[i]);
14680
- }
14681
-
14682
- // joining the two area curves
14683
- ctx.lineTo(curve1[len1-1].x, curve1[len1-1].y);
14684
-
14685
- // building opposite area curve (reverse)
14686
- for (i=len1-1; i>0; --i) {
14687
- helpers.canvas.lineTo(ctx, curve1[i], curve1[i-1], true);
14688
- }
14689
- }
14690
-
14691
- function doFill(ctx, points, mapper, view, color, loop) {
14692
- var count = points.length;
14693
- var span = view.spanGaps;
14694
- var curve0 = [];
14695
- var curve1 = [];
14696
- var len0 = 0;
14697
- var len1 = 0;
14698
- var i, ilen, index, p0, p1, d0, d1;
14699
-
14700
- ctx.beginPath();
14701
-
14702
- for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
14703
- index = i%count;
14704
- p0 = points[index]._view;
14705
- p1 = mapper(p0, index, view);
14706
- d0 = isDrawable(p0);
14707
- d1 = isDrawable(p1);
14708
-
14709
- if (d0 && d1) {
14710
- len0 = curve0.push(p0);
14711
- len1 = curve1.push(p1);
14712
- } else if (len0 && len1) {
14713
- if (!span) {
14714
- drawArea(ctx, curve0, curve1, len0, len1);
14715
- len0 = len1 = 0;
14716
- curve0 = [];
14717
- curve1 = [];
14718
- } else {
14719
- if (d0) {
14720
- curve0.push(p0);
14721
- }
14722
- if (d1) {
14723
- curve1.push(p1);
14724
- }
14725
- }
14726
- }
14727
- }
14728
-
14729
- drawArea(ctx, curve0, curve1, len0, len1);
14730
-
14731
- ctx.closePath();
14732
- ctx.fillStyle = color;
14733
- ctx.fill();
14734
- }
14735
-
14736
- return {
14737
- id: 'filler',
14738
-
14739
- afterDatasetsUpdate: function(chart, options) {
14740
- var count = (chart.data.datasets || []).length;
14741
- var propagate = options.propagate;
14742
- var sources = [];
14743
- var meta, i, el, source;
14744
-
14745
- for (i = 0; i < count; ++i) {
14746
- meta = chart.getDatasetMeta(i);
14747
- el = meta.dataset;
14748
- source = null;
14749
-
14750
- if (el && el._model && el instanceof Chart.elements.Line) {
14751
- source = {
14752
- visible: chart.isDatasetVisible(i),
14753
- fill: decodeFill(el, i, count),
14754
- chart: chart,
14755
- el: el
14756
- };
14757
- }
14758
-
14759
- meta.$filler = source;
14760
- sources.push(source);
14761
- }
14762
-
14763
- for (i=0; i<count; ++i) {
14764
- source = sources[i];
14765
- if (!source) {
14766
- continue;
14767
- }
14768
-
14769
- source.fill = resolveTarget(sources, i, propagate);
14770
- source.boundary = computeBoundary(source);
14771
- source.mapper = createMapper(source);
14772
- }
14773
- },
14774
-
14775
- beforeDatasetDraw: function(chart, args) {
14776
- var meta = args.meta.$filler;
14777
- if (!meta) {
14778
- return;
14779
- }
14780
-
14781
- var el = meta.el;
14782
- var view = el._view;
14783
- var points = el._children || [];
14784
- var mapper = meta.mapper;
14785
- var color = view.backgroundColor || defaults.global.defaultColor;
14786
-
14787
- if (mapper && color && points.length) {
14788
- doFill(chart.ctx, points, mapper, view, color, el._loop);
14789
- }
14790
- }
14791
- };
14792
- };
14793
-
14794
- },{}],42:[function(require,module,exports){
14795
- 'use strict';
14796
-
14797
- module.exports = function(Chart) {
14798
-
14799
- var helpers = Chart.helpers;
14800
- var layout = Chart.layoutService;
14801
- var noop = helpers.noop;
14802
-
14803
- Chart.defaults.global.legend = {
14804
- display: true,
14805
- position: 'top',
14806
- fullWidth: true,
14807
- reverse: false,
14808
- weight: 1000,
14809
-
14810
- // a callback that will handle
14811
- onClick: function(e, legendItem) {
14812
- var index = legendItem.datasetIndex;
14813
- var ci = this.chart;
14814
- var meta = ci.getDatasetMeta(index);
14815
-
14816
- // See controller.isDatasetVisible comment
14817
- meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
14818
-
14819
- // We hid a dataset ... rerender the chart
14820
- ci.update();
14821
- },
14822
-
14823
- onHover: null,
14824
-
14825
- labels: {
14826
- boxWidth: 40,
14827
- padding: 10,
14828
- // Generates labels shown in the legend
14829
- // Valid properties to return:
14830
- // text : text to display
14831
- // fillStyle : fill of coloured box
14832
- // strokeStyle: stroke of coloured box
14833
- // hidden : if this legend item refers to a hidden item
14834
- // lineCap : cap style for line
14835
- // lineDash
14836
- // lineDashOffset :
14837
- // lineJoin :
14838
- // lineWidth :
14839
- generateLabels: function(chart) {
14840
- var data = chart.data;
14841
- return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
14842
- return {
14843
- text: dataset.label,
14844
- fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
14845
- hidden: !chart.isDatasetVisible(i),
14846
- lineCap: dataset.borderCapStyle,
14847
- lineDash: dataset.borderDash,
14848
- lineDashOffset: dataset.borderDashOffset,
14849
- lineJoin: dataset.borderJoinStyle,
14850
- lineWidth: dataset.borderWidth,
14851
- strokeStyle: dataset.borderColor,
14852
- pointStyle: dataset.pointStyle,
14853
-
14854
- // Below is extra data used for toggling the datasets
14855
- datasetIndex: i
14856
- };
14857
- }, this) : [];
14858
- }
14859
- }
14860
- };
14861
-
14862
- /**
14863
- * Helper function to get the box width based on the usePointStyle option
14864
- * @param labelopts {Object} the label options on the legend
14865
- * @param fontSize {Number} the label font size
14866
- * @return {Number} width of the color box area
14867
- */
14868
- function getBoxWidth(labelOpts, fontSize) {
14869
- return labelOpts.usePointStyle ?
14870
- fontSize * Math.SQRT2 :
14871
- labelOpts.boxWidth;
14872
- }
14873
-
14874
- Chart.Legend = Chart.Element.extend({
14875
-
14876
- initialize: function(config) {
14877
- helpers.extend(this, config);
14878
-
14879
- // Contains hit boxes for each dataset (in dataset order)
14880
- this.legendHitBoxes = [];
14881
-
14882
- // Are we in doughnut mode which has a different data type
14883
- this.doughnutMode = false;
14884
- },
14885
-
14886
- // These methods are ordered by lifecycle. Utilities then follow.
14887
- // Any function defined here is inherited by all legend types.
14888
- // Any function can be extended by the legend type
14889
-
14890
- beforeUpdate: noop,
14891
- update: function(maxWidth, maxHeight, margins) {
14892
- var me = this;
14893
-
14894
- // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
14895
- me.beforeUpdate();
14896
-
14897
- // Absorb the master measurements
14898
- me.maxWidth = maxWidth;
14899
- me.maxHeight = maxHeight;
14900
- me.margins = margins;
14901
-
14902
- // Dimensions
14903
- me.beforeSetDimensions();
14904
- me.setDimensions();
14905
- me.afterSetDimensions();
14906
- // Labels
14907
- me.beforeBuildLabels();
14908
- me.buildLabels();
14909
- me.afterBuildLabels();
14910
-
14911
- // Fit
14912
- me.beforeFit();
14913
- me.fit();
14914
- me.afterFit();
14915
- //
14916
- me.afterUpdate();
14917
-
14918
- return me.minSize;
14919
- },
14920
- afterUpdate: noop,
14921
-
14922
- //
14923
-
14924
- beforeSetDimensions: noop,
14925
- setDimensions: function() {
14926
- var me = this;
14927
- // Set the unconstrained dimension before label rotation
14928
- if (me.isHorizontal()) {
14929
- // Reset position before calculating rotation
14930
- me.width = me.maxWidth;
14931
- me.left = 0;
14932
- me.right = me.width;
14933
- } else {
14934
- me.height = me.maxHeight;
14935
-
14936
- // Reset position before calculating rotation
14937
- me.top = 0;
14938
- me.bottom = me.height;
14939
- }
14940
-
14941
- // Reset padding
14942
- me.paddingLeft = 0;
14943
- me.paddingTop = 0;
14944
- me.paddingRight = 0;
14945
- me.paddingBottom = 0;
14946
-
14947
- // Reset minSize
14948
- me.minSize = {
14949
- width: 0,
14950
- height: 0
14951
- };
14952
- },
14953
- afterSetDimensions: noop,
14954
-
14955
- //
14956
-
14957
- beforeBuildLabels: noop,
14958
- buildLabels: function() {
14959
- var me = this;
14960
- var labelOpts = me.options.labels;
14961
- var legendItems = labelOpts.generateLabels.call(me, me.chart);
14962
-
14963
- if (labelOpts.filter) {
14964
- legendItems = legendItems.filter(function(item) {
14965
- return labelOpts.filter(item, me.chart.data);
14966
- });
14967
- }
14968
-
14969
- if (me.options.reverse) {
14970
- legendItems.reverse();
14971
- }
14972
-
14973
- me.legendItems = legendItems;
14974
- },
14975
- afterBuildLabels: noop,
14976
-
14977
- //
14978
-
14979
- beforeFit: noop,
14980
- fit: function() {
14981
- var me = this;
14982
- var opts = me.options;
14983
- var labelOpts = opts.labels;
14984
- var display = opts.display;
14985
-
14986
- var ctx = me.ctx;
14987
-
14988
- var globalDefault = Chart.defaults.global,
14989
- itemOrDefault = helpers.getValueOrDefault,
14990
- fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
14991
- fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
14992
- fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
14993
- labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
14994
-
14995
- // Reset hit boxes
14996
- var hitboxes = me.legendHitBoxes = [];
14997
-
14998
- var minSize = me.minSize;
14999
- var isHorizontal = me.isHorizontal();
15000
-
15001
- if (isHorizontal) {
15002
- minSize.width = me.maxWidth; // fill all the width
15003
- minSize.height = display ? 10 : 0;
15004
- } else {
15005
- minSize.width = display ? 10 : 0;
15006
- minSize.height = me.maxHeight; // fill all the height
15007
- }
15008
-
15009
- // Increase sizes here
15010
- if (display) {
15011
- ctx.font = labelFont;
15012
-
15013
- if (isHorizontal) {
15014
- // Labels
15015
-
15016
- // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
15017
- var lineWidths = me.lineWidths = [0];
15018
- var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0;
15019
-
15020
- ctx.textAlign = 'left';
15021
- ctx.textBaseline = 'top';
15022
-
15023
- helpers.each(me.legendItems, function(legendItem, i) {
15024
- var boxWidth = getBoxWidth(labelOpts, fontSize);
15025
- var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
15026
-
15027
- if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) {
15028
- totalHeight += fontSize + (labelOpts.padding);
15029
- lineWidths[lineWidths.length] = me.left;
15030
- }
15031
-
15032
- // Store the hitbox width and height here. Final position will be updated in `draw`
15033
- hitboxes[i] = {
15034
- left: 0,
15035
- top: 0,
15036
- width: width,
15037
- height: fontSize
15038
- };
15039
-
15040
- lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
15041
- });
15042
-
15043
- minSize.height += totalHeight;
15044
-
15045
- } else {
15046
- var vPadding = labelOpts.padding;
15047
- var columnWidths = me.columnWidths = [];
15048
- var totalWidth = labelOpts.padding;
15049
- var currentColWidth = 0;
15050
- var currentColHeight = 0;
15051
- var itemHeight = fontSize + vPadding;
15052
-
15053
- helpers.each(me.legendItems, function(legendItem, i) {
15054
- var boxWidth = getBoxWidth(labelOpts, fontSize);
15055
- var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
15056
-
15057
- // If too tall, go to new column
15058
- if (currentColHeight + itemHeight > minSize.height) {
15059
- totalWidth += currentColWidth + labelOpts.padding;
15060
- columnWidths.push(currentColWidth); // previous column width
15061
-
15062
- currentColWidth = 0;
15063
- currentColHeight = 0;
15064
- }
15065
-
15066
- // Get max width
15067
- currentColWidth = Math.max(currentColWidth, itemWidth);
15068
- currentColHeight += itemHeight;
15069
-
15070
- // Store the hitbox width and height here. Final position will be updated in `draw`
15071
- hitboxes[i] = {
15072
- left: 0,
15073
- top: 0,
15074
- width: itemWidth,
15075
- height: fontSize
15076
- };
15077
- });
15078
-
15079
- totalWidth += currentColWidth;
15080
- columnWidths.push(currentColWidth);
15081
- minSize.width += totalWidth;
15082
- }
15083
- }
15084
-
15085
- me.width = minSize.width;
15086
- me.height = minSize.height;
15087
- },
15088
- afterFit: noop,
15089
-
15090
- // Shared Methods
15091
- isHorizontal: function() {
15092
- return this.options.position === 'top' || this.options.position === 'bottom';
15093
- },
15094
-
15095
- // Actually draw the legend on the canvas
15096
- draw: function() {
15097
- var me = this;
15098
- var opts = me.options;
15099
- var labelOpts = opts.labels;
15100
- var globalDefault = Chart.defaults.global,
15101
- lineDefault = globalDefault.elements.line,
15102
- legendWidth = me.width,
15103
- lineWidths = me.lineWidths;
15104
-
15105
- if (opts.display) {
15106
- var ctx = me.ctx,
15107
- cursor,
15108
- itemOrDefault = helpers.getValueOrDefault,
15109
- fontColor = itemOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor),
15110
- fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
15111
- fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
15112
- fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
15113
- labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
15114
-
15115
- // Canvas setup
15116
- ctx.textAlign = 'left';
15117
- ctx.textBaseline = 'top';
15118
- ctx.lineWidth = 0.5;
15119
- ctx.strokeStyle = fontColor; // for strikethrough effect
15120
- ctx.fillStyle = fontColor; // render in correct colour
15121
- ctx.font = labelFont;
15122
-
15123
- var boxWidth = getBoxWidth(labelOpts, fontSize),
15124
- hitboxes = me.legendHitBoxes;
15125
-
15126
- // current position
15127
- var drawLegendBox = function(x, y, legendItem) {
15128
- if (isNaN(boxWidth) || boxWidth <= 0) {
15129
- return;
15130
- }
15131
-
15132
- // Set the ctx for the box
15133
- ctx.save();
15134
-
15135
- ctx.fillStyle = itemOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
15136
- ctx.lineCap = itemOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
15137
- ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
15138
- ctx.lineJoin = itemOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
15139
- ctx.lineWidth = itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
15140
- ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
15141
- var isLineWidthZero = (itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);
15142
-
15143
- if (ctx.setLineDash) {
15144
- // IE 9 and 10 do not support line dash
15145
- ctx.setLineDash(itemOrDefault(legendItem.lineDash, lineDefault.borderDash));
15146
- }
15147
-
15148
- if (opts.labels && opts.labels.usePointStyle) {
15149
- // Recalculate x and y for drawPoint() because its expecting
15150
- // x and y to be center of figure (instead of top left)
15151
- var radius = fontSize * Math.SQRT2 / 2;
15152
- var offSet = radius / Math.SQRT2;
15153
- var centerX = x + offSet;
15154
- var centerY = y + offSet;
15155
-
15156
- // Draw pointStyle as legend symbol
15157
- Chart.canvasHelpers.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
15158
- } else {
15159
- // Draw box as legend symbol
15160
- if (!isLineWidthZero) {
15161
- ctx.strokeRect(x, y, boxWidth, fontSize);
15162
- }
15163
- ctx.fillRect(x, y, boxWidth, fontSize);
15164
- }
15165
-
15166
- ctx.restore();
15167
- };
15168
- var fillText = function(x, y, legendItem, textWidth) {
15169
- ctx.fillText(legendItem.text, boxWidth + (fontSize / 2) + x, y);
15170
-
15171
- if (legendItem.hidden) {
15172
- // Strikethrough the text if hidden
15173
- ctx.beginPath();
15174
- ctx.lineWidth = 2;
15175
- ctx.moveTo(boxWidth + (fontSize / 2) + x, y + (fontSize / 2));
15176
- ctx.lineTo(boxWidth + (fontSize / 2) + x + textWidth, y + (fontSize / 2));
15177
- ctx.stroke();
15178
- }
15179
- };
15180
-
15181
- // Horizontal
15182
- var isHorizontal = me.isHorizontal();
15183
- if (isHorizontal) {
15184
- cursor = {
15185
- x: me.left + ((legendWidth - lineWidths[0]) / 2),
15186
- y: me.top + labelOpts.padding,
15187
- line: 0
15188
- };
15189
- } else {
15190
- cursor = {
15191
- x: me.left + labelOpts.padding,
15192
- y: me.top + labelOpts.padding,
15193
- line: 0
15194
- };
15195
- }
15196
-
15197
- var itemHeight = fontSize + labelOpts.padding;
15198
- helpers.each(me.legendItems, function(legendItem, i) {
15199
- var textWidth = ctx.measureText(legendItem.text).width,
15200
- width = boxWidth + (fontSize / 2) + textWidth,
15201
- x = cursor.x,
15202
- y = cursor.y;
15203
-
15204
- if (isHorizontal) {
15205
- if (x + width >= legendWidth) {
15206
- y = cursor.y += itemHeight;
15207
- cursor.line++;
15208
- x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
15209
- }
15210
- } else if (y + itemHeight > me.bottom) {
15211
- x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
15212
- y = cursor.y = me.top + labelOpts.padding;
15213
- cursor.line++;
15214
- }
15215
-
15216
- drawLegendBox(x, y, legendItem);
15217
-
15218
- hitboxes[i].left = x;
15219
- hitboxes[i].top = y;
15220
-
15221
- // Fill the actual label
15222
- fillText(x, y, legendItem, textWidth);
15223
-
15224
- if (isHorizontal) {
15225
- cursor.x += width + (labelOpts.padding);
15226
- } else {
15227
- cursor.y += itemHeight;
15228
- }
15229
-
15230
- });
15231
- }
15232
- },
15233
-
15234
- /**
15235
- * Handle an event
15236
- * @private
15237
- * @param {IEvent} event - The event to handle
15238
- * @return {Boolean} true if a change occured
15239
- */
15240
- handleEvent: function(e) {
15241
- var me = this;
15242
- var opts = me.options;
15243
- var type = e.type === 'mouseup' ? 'click' : e.type;
15244
- var changed = false;
15245
-
15246
- if (type === 'mousemove') {
15247
- if (!opts.onHover) {
15248
- return;
15249
- }
15250
- } else if (type === 'click') {
15251
- if (!opts.onClick) {
15252
- return;
15253
- }
15254
- } else {
15255
- return;
15256
- }
15257
-
15258
- // Chart event already has relative position in it
15259
- var x = e.x,
15260
- y = e.y;
15261
-
15262
- if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
15263
- // See if we are touching one of the dataset boxes
15264
- var lh = me.legendHitBoxes;
15265
- for (var i = 0; i < lh.length; ++i) {
15266
- var hitBox = lh[i];
15267
-
15268
- if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
15269
- // Touching an element
15270
- if (type === 'click') {
15271
- // use e.native for backwards compatibility
15272
- opts.onClick.call(me, e.native, me.legendItems[i]);
15273
- changed = true;
15274
- break;
15275
- } else if (type === 'mousemove') {
15276
- // use e.native for backwards compatibility
15277
- opts.onHover.call(me, e.native, me.legendItems[i]);
15278
- changed = true;
15279
- break;
15280
- }
15281
- }
15282
- }
15283
- }
15284
-
15285
- return changed;
15286
- }
15287
- });
15288
-
15289
- function createNewLegendAndAttach(chart, legendOpts) {
15290
- var legend = new Chart.Legend({
15291
- ctx: chart.ctx,
15292
- options: legendOpts,
15293
- chart: chart
15294
- });
15295
-
15296
- layout.configure(chart, legend, legendOpts);
15297
- layout.addBox(chart, legend);
15298
- chart.legend = legend;
15299
- }
15300
-
15301
- return {
15302
- id: 'legend',
15303
-
15304
- beforeInit: function(chart) {
15305
- var legendOpts = chart.options.legend;
15306
-
15307
- if (legendOpts) {
15308
- createNewLegendAndAttach(chart, legendOpts);
15309
- }
15310
- },
15311
-
15312
- beforeUpdate: function(chart) {
15313
- var legendOpts = chart.options.legend;
15314
- var legend = chart.legend;
15315
-
15316
- if (legendOpts) {
15317
- legendOpts = helpers.configMerge(Chart.defaults.global.legend, legendOpts);
15318
-
15319
- if (legend) {
15320
- layout.configure(chart, legend, legendOpts);
15321
- legend.options = legendOpts;
15322
- } else {
15323
- createNewLegendAndAttach(chart, legendOpts);
15324
- }
15325
- } else if (legend) {
15326
- layout.removeBox(chart, legend);
15327
- delete chart.legend;
15328
- }
15329
- },
15330
-
15331
- afterEvent: function(chart, e) {
15332
- var legend = chart.legend;
15333
- if (legend) {
15334
- legend.handleEvent(e);
15335
- }
15336
- }
15337
- };
15338
- };
15339
-
15340
- },{}],43:[function(require,module,exports){
15341
- 'use strict';
15342
-
15343
- module.exports = function(Chart) {
15344
-
15345
- var helpers = Chart.helpers;
15346
- var layout = Chart.layoutService;
15347
- var noop = helpers.noop;
15348
-
15349
- Chart.defaults.global.title = {
15350
- display: false,
15351
- position: 'top',
15352
- fullWidth: true,
15353
- weight: 2000, // by default greater than legend (1000) to be above
15354
- fontStyle: 'bold',
15355
- padding: 10,
15356
-
15357
- // actual title
15358
- text: ''
15359
- };
15360
-
15361
- Chart.Title = Chart.Element.extend({
15362
- initialize: function(config) {
15363
- var me = this;
15364
- helpers.extend(me, config);
15365
-
15366
- // Contains hit boxes for each dataset (in dataset order)
15367
- me.legendHitBoxes = [];
15368
- },
15369
-
15370
- // These methods are ordered by lifecycle. Utilities then follow.
15371
-
15372
- beforeUpdate: noop,
15373
- update: function(maxWidth, maxHeight, margins) {
15374
- var me = this;
15375
-
15376
- // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
15377
- me.beforeUpdate();
15378
-
15379
- // Absorb the master measurements
15380
- me.maxWidth = maxWidth;
15381
- me.maxHeight = maxHeight;
15382
- me.margins = margins;
15383
-
15384
- // Dimensions
15385
- me.beforeSetDimensions();
15386
- me.setDimensions();
15387
- me.afterSetDimensions();
15388
- // Labels
15389
- me.beforeBuildLabels();
15390
- me.buildLabels();
15391
- me.afterBuildLabels();
15392
-
15393
- // Fit
15394
- me.beforeFit();
15395
- me.fit();
15396
- me.afterFit();
15397
- //
15398
- me.afterUpdate();
15399
-
15400
- return me.minSize;
15401
-
15402
- },
15403
- afterUpdate: noop,
15404
-
15405
- //
15406
-
15407
- beforeSetDimensions: noop,
15408
- setDimensions: function() {
15409
- var me = this;
15410
- // Set the unconstrained dimension before label rotation
15411
- if (me.isHorizontal()) {
15412
- // Reset position before calculating rotation
15413
- me.width = me.maxWidth;
15414
- me.left = 0;
15415
- me.right = me.width;
15416
- } else {
15417
- me.height = me.maxHeight;
15418
-
15419
- // Reset position before calculating rotation
15420
- me.top = 0;
15421
- me.bottom = me.height;
15422
- }
15423
-
15424
- // Reset padding
15425
- me.paddingLeft = 0;
15426
- me.paddingTop = 0;
15427
- me.paddingRight = 0;
15428
- me.paddingBottom = 0;
15429
-
15430
- // Reset minSize
15431
- me.minSize = {
15432
- width: 0,
15433
- height: 0
15434
- };
15435
- },
15436
- afterSetDimensions: noop,
15437
-
15438
- //
15439
-
15440
- beforeBuildLabels: noop,
15441
- buildLabels: noop,
15442
- afterBuildLabels: noop,
15443
-
15444
- //
15445
-
15446
- beforeFit: noop,
15447
- fit: function() {
15448
- var me = this,
15449
- valueOrDefault = helpers.getValueOrDefault,
15450
- opts = me.options,
15451
- globalDefaults = Chart.defaults.global,
15452
- display = opts.display,
15453
- fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
15454
- minSize = me.minSize;
15455
-
15456
- if (me.isHorizontal()) {
15457
- minSize.width = me.maxWidth; // fill all the width
15458
- minSize.height = display ? fontSize + (opts.padding * 2) : 0;
15459
- } else {
15460
- minSize.width = display ? fontSize + (opts.padding * 2) : 0;
15461
- minSize.height = me.maxHeight; // fill all the height
15462
- }
15463
-
15464
- me.width = minSize.width;
15465
- me.height = minSize.height;
15466
-
15467
- },
15468
- afterFit: noop,
15469
-
15470
- // Shared Methods
15471
- isHorizontal: function() {
15472
- var pos = this.options.position;
15473
- return pos === 'top' || pos === 'bottom';
15474
- },
15475
-
15476
- // Actually draw the title block on the canvas
15477
- draw: function() {
15478
- var me = this,
15479
- ctx = me.ctx,
15480
- valueOrDefault = helpers.getValueOrDefault,
15481
- opts = me.options,
15482
- globalDefaults = Chart.defaults.global;
15483
-
15484
- if (opts.display) {
15485
- var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
15486
- fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle),
15487
- fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily),
15488
- titleFont = helpers.fontString(fontSize, fontStyle, fontFamily),
15489
- rotation = 0,
15490
- titleX,
15491
- titleY,
15492
- top = me.top,
15493
- left = me.left,
15494
- bottom = me.bottom,
15495
- right = me.right,
15496
- maxWidth;
15497
-
15498
- ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
15499
- ctx.font = titleFont;
15500
-
15501
- // Horizontal
15502
- if (me.isHorizontal()) {
15503
- titleX = left + ((right - left) / 2); // midpoint of the width
15504
- titleY = top + ((bottom - top) / 2); // midpoint of the height
15505
- maxWidth = right - left;
15506
- } else {
15507
- titleX = opts.position === 'left' ? left + (fontSize / 2) : right - (fontSize / 2);
15508
- titleY = top + ((bottom - top) / 2);
15509
- maxWidth = bottom - top;
15510
- rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
15511
- }
15512
-
15513
- ctx.save();
15514
- ctx.translate(titleX, titleY);
15515
- ctx.rotate(rotation);
15516
- ctx.textAlign = 'center';
15517
- ctx.textBaseline = 'middle';
15518
- ctx.fillText(opts.text, 0, 0, maxWidth);
15519
- ctx.restore();
15520
- }
15521
- }
15522
- });
15523
-
15524
- function createNewTitleBlockAndAttach(chart, titleOpts) {
15525
- var title = new Chart.Title({
15526
- ctx: chart.ctx,
15527
- options: titleOpts,
15528
- chart: chart
15529
- });
15530
-
15531
- layout.configure(chart, title, titleOpts);
15532
- layout.addBox(chart, title);
15533
- chart.titleBlock = title;
15534
- }
15535
-
15536
- return {
15537
- id: 'title',
15538
-
15539
- beforeInit: function(chart) {
15540
- var titleOpts = chart.options.title;
15541
-
15542
- if (titleOpts) {
15543
- createNewTitleBlockAndAttach(chart, titleOpts);
15544
- }
15545
- },
15546
-
15547
- beforeUpdate: function(chart) {
15548
- var titleOpts = chart.options.title;
15549
- var titleBlock = chart.titleBlock;
15550
-
15551
- if (titleOpts) {
15552
- titleOpts = helpers.configMerge(Chart.defaults.global.title, titleOpts);
15553
-
15554
- if (titleBlock) {
15555
- layout.configure(chart, titleBlock, titleOpts);
15556
- titleBlock.options = titleOpts;
15557
- } else {
15558
- createNewTitleBlockAndAttach(chart, titleOpts);
15559
- }
15560
- } else if (titleBlock) {
15561
- Chart.layoutService.removeBox(chart, titleBlock);
15562
- delete chart.titleBlock;
15563
- }
15564
- }
15565
- };
15566
- };
15567
-
15568
- },{}],44:[function(require,module,exports){
15569
- 'use strict';
15570
-
15571
- module.exports = function(Chart) {
15572
-
15573
- var helpers = Chart.helpers;
15574
- // Default config for a category scale
15575
- var defaultConfig = {
15576
- position: 'bottom'
15577
- };
15578
-
15579
- var DatasetScale = Chart.Scale.extend({
15580
- /**
15581
- * Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
15582
- * else fall back to data.labels
15583
- * @private
15584
- */
15585
- getLabels: function() {
15586
- var data = this.chart.data;
15587
- return (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
15588
- },
15589
-
15590
- determineDataLimits: function() {
15591
- var me = this;
15592
- var labels = me.getLabels();
15593
- me.minIndex = 0;
15594
- me.maxIndex = labels.length - 1;
15595
- var findIndex;
15596
-
15597
- if (me.options.ticks.min !== undefined) {
15598
- // user specified min value
15599
- findIndex = helpers.indexOf(labels, me.options.ticks.min);
15600
- me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
15601
- }
15602
-
15603
- if (me.options.ticks.max !== undefined) {
15604
- // user specified max value
15605
- findIndex = helpers.indexOf(labels, me.options.ticks.max);
15606
- me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
15607
- }
15608
-
15609
- me.min = labels[me.minIndex];
15610
- me.max = labels[me.maxIndex];
15611
- },
15612
-
15613
- buildTicks: function() {
15614
- var me = this;
15615
- var labels = me.getLabels();
15616
- // If we are viewing some subset of labels, slice the original array
15617
- me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
15618
- },
15619
-
15620
- getLabelForIndex: function(index, datasetIndex) {
15621
- var me = this;
15622
- var data = me.chart.data;
15623
- var isHorizontal = me.isHorizontal();
15624
-
15625
- if (data.yLabels && !isHorizontal) {
15626
- return me.getRightValue(data.datasets[datasetIndex].data[index]);
15627
- }
15628
- return me.ticks[index - me.minIndex];
15629
- },
15630
-
15631
- // Used to get data value locations. Value can either be an index or a numerical value
15632
- getPixelForValue: function(value, index, datasetIndex, includeOffset) {
15633
- var me = this;
15634
- // 1 is added because we need the length but we have the indexes
15635
- var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
15636
-
15637
- // If value is a data object, then index is the index in the data array,
15638
- // not the index of the scale. We need to change that.
15639
- var valueCategory;
15640
- if (value !== undefined && value !== null) {
15641
- valueCategory = me.isHorizontal() ? value.x : value.y;
15642
- }
15643
- if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
15644
- var labels = me.getLabels();
15645
- value = valueCategory || value;
15646
- var idx = labels.indexOf(value);
15647
- index = idx !== -1 ? idx : index;
15648
- }
15649
-
15650
- if (me.isHorizontal()) {
15651
- var valueWidth = me.width / offsetAmt;
15652
- var widthOffset = (valueWidth * (index - me.minIndex));
15653
-
15654
- if (me.options.gridLines.offsetGridLines && includeOffset || me.maxIndex === me.minIndex && includeOffset) {
15655
- widthOffset += (valueWidth / 2);
15656
- }
15657
-
15658
- return me.left + Math.round(widthOffset);
15659
- }
15660
- var valueHeight = me.height / offsetAmt;
15661
- var heightOffset = (valueHeight * (index - me.minIndex));
15662
-
15663
- if (me.options.gridLines.offsetGridLines && includeOffset) {
15664
- heightOffset += (valueHeight / 2);
15665
- }
15666
-
15667
- return me.top + Math.round(heightOffset);
15668
- },
15669
- getPixelForTick: function(index, includeOffset) {
15670
- return this.getPixelForValue(this.ticks[index], index + this.minIndex, null, includeOffset);
15671
- },
15672
- getValueForPixel: function(pixel) {
15673
- var me = this;
15674
- var value;
15675
- var offsetAmt = Math.max((me.ticks.length - ((me.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
15676
- var horz = me.isHorizontal();
15677
- var valueDimension = (horz ? me.width : me.height) / offsetAmt;
15678
-
15679
- pixel -= horz ? me.left : me.top;
15680
-
15681
- if (me.options.gridLines.offsetGridLines) {
15682
- pixel -= (valueDimension / 2);
15683
- }
15684
-
15685
- if (pixel <= 0) {
15686
- value = 0;
15687
- } else {
15688
- value = Math.round(pixel / valueDimension);
15689
- }
15690
-
15691
- return value;
15692
- },
15693
- getBasePixel: function() {
15694
- return this.bottom;
15695
- }
15696
- });
15697
-
15698
- Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig);
15699
-
15700
- };
15701
-
15702
- },{}],45:[function(require,module,exports){
15703
- 'use strict';
15704
-
15705
- module.exports = function(Chart) {
15706
-
15707
- var helpers = Chart.helpers;
15708
-
15709
- var defaultConfig = {
15710
- position: 'left',
15711
- ticks: {
15712
- callback: Chart.Ticks.formatters.linear
15713
- }
15714
- };
15715
-
15716
- var LinearScale = Chart.LinearScaleBase.extend({
15717
-
15718
- determineDataLimits: function() {
15719
- var me = this;
15720
- var opts = me.options;
15721
- var chart = me.chart;
15722
- var data = chart.data;
15723
- var datasets = data.datasets;
15724
- var isHorizontal = me.isHorizontal();
15725
- var DEFAULT_MIN = 0;
15726
- var DEFAULT_MAX = 1;
15727
-
15728
- function IDMatches(meta) {
15729
- return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
15730
- }
15731
-
15732
- // First Calculate the range
15733
- me.min = null;
15734
- me.max = null;
15735
-
15736
- var hasStacks = opts.stacked;
15737
- if (hasStacks === undefined) {
15738
- helpers.each(datasets, function(dataset, datasetIndex) {
15739
- if (hasStacks) {
15740
- return;
15741
- }
15742
-
15743
- var meta = chart.getDatasetMeta(datasetIndex);
15744
- if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
15745
- meta.stack !== undefined) {
15746
- hasStacks = true;
15747
- }
15748
- });
15749
- }
15750
-
15751
- if (opts.stacked || hasStacks) {
15752
- var valuesPerStack = {};
15753
-
15754
- helpers.each(datasets, function(dataset, datasetIndex) {
15755
- var meta = chart.getDatasetMeta(datasetIndex);
15756
- var key = [
15757
- meta.type,
15758
- // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
15759
- ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
15760
- meta.stack
15761
- ].join('.');
15762
-
15763
- if (valuesPerStack[key] === undefined) {
15764
- valuesPerStack[key] = {
15765
- positiveValues: [],
15766
- negativeValues: []
15767
- };
15768
- }
15769
-
15770
- // Store these per type
15771
- var positiveValues = valuesPerStack[key].positiveValues;
15772
- var negativeValues = valuesPerStack[key].negativeValues;
15773
-
15774
- if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
15775
- helpers.each(dataset.data, function(rawValue, index) {
15776
- var value = +me.getRightValue(rawValue);
15777
- if (isNaN(value) || meta.data[index].hidden) {
15778
- return;
15779
- }
15780
-
15781
- positiveValues[index] = positiveValues[index] || 0;
15782
- negativeValues[index] = negativeValues[index] || 0;
15783
-
15784
- if (opts.relativePoints) {
15785
- positiveValues[index] = 100;
15786
- } else if (value < 0) {
15787
- negativeValues[index] += value;
15788
- } else {
15789
- positiveValues[index] += value;
15790
- }
15791
- });
15792
- }
15793
- });
15794
-
15795
- helpers.each(valuesPerStack, function(valuesForType) {
15796
- var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
15797
- var minVal = helpers.min(values);
15798
- var maxVal = helpers.max(values);
15799
- me.min = me.min === null ? minVal : Math.min(me.min, minVal);
15800
- me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
15801
- });
15802
-
15803
- } else {
15804
- helpers.each(datasets, function(dataset, datasetIndex) {
15805
- var meta = chart.getDatasetMeta(datasetIndex);
15806
- if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
15807
- helpers.each(dataset.data, function(rawValue, index) {
15808
- var value = +me.getRightValue(rawValue);
15809
- if (isNaN(value) || meta.data[index].hidden) {
15810
- return;
15811
- }
15812
-
15813
- if (me.min === null) {
15814
- me.min = value;
15815
- } else if (value < me.min) {
15816
- me.min = value;
15817
- }
15818
-
15819
- if (me.max === null) {
15820
- me.max = value;
15821
- } else if (value > me.max) {
15822
- me.max = value;
15823
- }
15824
- });
15825
- }
15826
- });
15827
- }
15828
-
15829
- me.min = isFinite(me.min) ? me.min : DEFAULT_MIN;
15830
- me.max = isFinite(me.max) ? me.max : DEFAULT_MAX;
15831
-
15832
- // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
15833
- this.handleTickRangeOptions();
15834
- },
15835
- getTickLimit: function() {
15836
- var maxTicks;
15837
- var me = this;
15838
- var tickOpts = me.options.ticks;
15839
-
15840
- if (me.isHorizontal()) {
15841
- maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
15842
- } else {
15843
- // The factor of 2 used to scale the font size has been experimentally determined.
15844
- var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize);
15845
- maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
15846
- }
15847
-
15848
- return maxTicks;
15849
- },
15850
- // Called after the ticks are built. We need
15851
- handleDirectionalChanges: function() {
15852
- if (!this.isHorizontal()) {
15853
- // We are in a vertical orientation. The top value is the highest. So reverse the array
15854
- this.ticks.reverse();
15855
- }
15856
- },
15857
- getLabelForIndex: function(index, datasetIndex) {
15858
- return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
15859
- },
15860
- // Utils
15861
- getPixelForValue: function(value) {
15862
- // This must be called after fit has been run so that
15863
- // this.left, this.top, this.right, and this.bottom have been defined
15864
- var me = this;
15865
- var start = me.start;
15866
-
15867
- var rightValue = +me.getRightValue(value);
15868
- var pixel;
15869
- var range = me.end - start;
15870
-
15871
- if (me.isHorizontal()) {
15872
- pixel = me.left + (me.width / range * (rightValue - start));
15873
- return Math.round(pixel);
15874
- }
15875
-
15876
- pixel = me.bottom - (me.height / range * (rightValue - start));
15877
- return Math.round(pixel);
15878
- },
15879
- getValueForPixel: function(pixel) {
15880
- var me = this;
15881
- var isHorizontal = me.isHorizontal();
15882
- var innerDimension = isHorizontal ? me.width : me.height;
15883
- var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
15884
- return me.start + ((me.end - me.start) * offset);
15885
- },
15886
- getPixelForTick: function(index) {
15887
- return this.getPixelForValue(this.ticksAsNumbers[index]);
15888
- }
15889
- });
15890
- Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig);
15891
-
15892
- };
15893
-
15894
- },{}],46:[function(require,module,exports){
15895
- 'use strict';
15896
-
15897
- module.exports = function(Chart) {
15898
-
15899
- var helpers = Chart.helpers,
15900
- noop = helpers.noop;
15901
-
15902
- Chart.LinearScaleBase = Chart.Scale.extend({
15903
- handleTickRangeOptions: function() {
15904
- var me = this;
15905
- var opts = me.options;
15906
- var tickOpts = opts.ticks;
15907
-
15908
- // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
15909
- // do nothing since that would make the chart weird. If the user really wants a weird chart
15910
- // axis, they can manually override it
15911
- if (tickOpts.beginAtZero) {
15912
- var minSign = helpers.sign(me.min);
15913
- var maxSign = helpers.sign(me.max);
15914
-
15915
- if (minSign < 0 && maxSign < 0) {
15916
- // move the top up to 0
15917
- me.max = 0;
15918
- } else if (minSign > 0 && maxSign > 0) {
15919
- // move the bottom down to 0
15920
- me.min = 0;
15921
- }
15922
- }
15923
-
15924
- if (tickOpts.min !== undefined) {
15925
- me.min = tickOpts.min;
15926
- } else if (tickOpts.suggestedMin !== undefined) {
15927
- if (me.min === null) {
15928
- me.min = tickOpts.suggestedMin;
15929
- } else {
15930
- me.min = Math.min(me.min, tickOpts.suggestedMin);
15931
- }
15932
- }
15933
-
15934
- if (tickOpts.max !== undefined) {
15935
- me.max = tickOpts.max;
15936
- } else if (tickOpts.suggestedMax !== undefined) {
15937
- if (me.max === null) {
15938
- me.max = tickOpts.suggestedMax;
15939
- } else {
15940
- me.max = Math.max(me.max, tickOpts.suggestedMax);
15941
- }
15942
- }
15943
-
15944
- if (me.min === me.max) {
15945
- me.max++;
15946
-
15947
- if (!tickOpts.beginAtZero) {
15948
- me.min--;
15949
- }
15950
- }
15951
- },
15952
- getTickLimit: noop,
15953
- handleDirectionalChanges: noop,
15954
-
15955
- buildTicks: function() {
15956
- var me = this;
15957
- var opts = me.options;
15958
- var tickOpts = opts.ticks;
15959
-
15960
- // Figure out what the max number of ticks we can support it is based on the size of
15961
- // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
15962
- // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
15963
- // the graph. Make sure we always have at least 2 ticks
15964
- var maxTicks = me.getTickLimit();
15965
- maxTicks = Math.max(2, maxTicks);
15966
-
15967
- var numericGeneratorOptions = {
15968
- maxTicks: maxTicks,
15969
- min: tickOpts.min,
15970
- max: tickOpts.max,
15971
- stepSize: helpers.getValueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
15972
- };
15973
- var ticks = me.ticks = Chart.Ticks.generators.linear(numericGeneratorOptions, me);
15974
-
15975
- me.handleDirectionalChanges();
15976
-
15977
- // At this point, we need to update our max and min given the tick values since we have expanded the
15978
- // range of the scale
15979
- me.max = helpers.max(ticks);
15980
- me.min = helpers.min(ticks);
15981
-
15982
- if (tickOpts.reverse) {
15983
- ticks.reverse();
15984
-
15985
- me.start = me.max;
15986
- me.end = me.min;
15987
- } else {
15988
- me.start = me.min;
15989
- me.end = me.max;
15990
- }
15991
- },
15992
- convertTicksToLabels: function() {
15993
- var me = this;
15994
- me.ticksAsNumbers = me.ticks.slice();
15995
- me.zeroLineIndex = me.ticks.indexOf(0);
15996
-
15997
- Chart.Scale.prototype.convertTicksToLabels.call(me);
15998
- }
15999
- });
16000
- };
16001
-
16002
- },{}],47:[function(require,module,exports){
16003
- 'use strict';
16004
-
16005
- module.exports = function(Chart) {
16006
-
16007
- var helpers = Chart.helpers;
16008
-
16009
- var defaultConfig = {
16010
- position: 'left',
16011
-
16012
- // label settings
16013
- ticks: {
16014
- callback: Chart.Ticks.formatters.logarithmic
16015
- }
16016
- };
16017
-
16018
- var LogarithmicScale = Chart.Scale.extend({
16019
- determineDataLimits: function() {
16020
- var me = this;
16021
- var opts = me.options;
16022
- var tickOpts = opts.ticks;
16023
- var chart = me.chart;
16024
- var data = chart.data;
16025
- var datasets = data.datasets;
16026
- var getValueOrDefault = helpers.getValueOrDefault;
16027
- var isHorizontal = me.isHorizontal();
16028
- function IDMatches(meta) {
16029
- return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
16030
- }
16031
-
16032
- // Calculate Range
16033
- me.min = null;
16034
- me.max = null;
16035
- me.minNotZero = null;
16036
-
16037
- var hasStacks = opts.stacked;
16038
- if (hasStacks === undefined) {
16039
- helpers.each(datasets, function(dataset, datasetIndex) {
16040
- if (hasStacks) {
16041
- return;
16042
- }
16043
-
16044
- var meta = chart.getDatasetMeta(datasetIndex);
16045
- if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
16046
- meta.stack !== undefined) {
16047
- hasStacks = true;
16048
- }
16049
- });
16050
- }
16051
-
16052
- if (opts.stacked || hasStacks) {
16053
- var valuesPerStack = {};
16054
-
16055
- helpers.each(datasets, function(dataset, datasetIndex) {
16056
- var meta = chart.getDatasetMeta(datasetIndex);
16057
- var key = [
16058
- meta.type,
16059
- // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
16060
- ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
16061
- meta.stack
16062
- ].join('.');
16063
-
16064
- if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
16065
- if (valuesPerStack[key] === undefined) {
16066
- valuesPerStack[key] = [];
16067
- }
16068
-
16069
- helpers.each(dataset.data, function(rawValue, index) {
16070
- var values = valuesPerStack[key];
16071
- var value = +me.getRightValue(rawValue);
16072
- if (isNaN(value) || meta.data[index].hidden) {
16073
- return;
16074
- }
16075
-
16076
- values[index] = values[index] || 0;
16077
-
16078
- if (opts.relativePoints) {
16079
- values[index] = 100;
16080
- } else {
16081
- // Don't need to split positive and negative since the log scale can't handle a 0 crossing
16082
- values[index] += value;
16083
- }
16084
- });
16085
- }
16086
- });
16087
-
16088
- helpers.each(valuesPerStack, function(valuesForType) {
16089
- var minVal = helpers.min(valuesForType);
16090
- var maxVal = helpers.max(valuesForType);
16091
- me.min = me.min === null ? minVal : Math.min(me.min, minVal);
16092
- me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
16093
- });
16094
-
16095
- } else {
16096
- helpers.each(datasets, function(dataset, datasetIndex) {
16097
- var meta = chart.getDatasetMeta(datasetIndex);
16098
- if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
16099
- helpers.each(dataset.data, function(rawValue, index) {
16100
- var value = +me.getRightValue(rawValue);
16101
- if (isNaN(value) || meta.data[index].hidden) {
16102
- return;
16103
- }
16104
-
16105
- if (me.min === null) {
16106
- me.min = value;
16107
- } else if (value < me.min) {
16108
- me.min = value;
16109
- }
16110
-
16111
- if (me.max === null) {
16112
- me.max = value;
16113
- } else if (value > me.max) {
16114
- me.max = value;
16115
- }
16116
-
16117
- if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
16118
- me.minNotZero = value;
16119
- }
16120
- });
16121
- }
16122
- });
16123
- }
16124
-
16125
- me.min = getValueOrDefault(tickOpts.min, me.min);
16126
- me.max = getValueOrDefault(tickOpts.max, me.max);
16127
-
16128
- if (me.min === me.max) {
16129
- if (me.min !== 0 && me.min !== null) {
16130
- me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
16131
- me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
16132
- } else {
16133
- me.min = 1;
16134
- me.max = 10;
16135
- }
16136
- }
16137
- },
16138
- buildTicks: function() {
16139
- var me = this;
16140
- var opts = me.options;
16141
- var tickOpts = opts.ticks;
16142
-
16143
- var generationOptions = {
16144
- min: tickOpts.min,
16145
- max: tickOpts.max
16146
- };
16147
- var ticks = me.ticks = Chart.Ticks.generators.logarithmic(generationOptions, me);
16148
-
16149
- if (!me.isHorizontal()) {
16150
- // We are in a vertical orientation. The top value is the highest. So reverse the array
16151
- ticks.reverse();
16152
- }
16153
-
16154
- // At this point, we need to update our max and min given the tick values since we have expanded the
16155
- // range of the scale
16156
- me.max = helpers.max(ticks);
16157
- me.min = helpers.min(ticks);
16158
-
16159
- if (tickOpts.reverse) {
16160
- ticks.reverse();
16161
-
16162
- me.start = me.max;
16163
- me.end = me.min;
16164
- } else {
16165
- me.start = me.min;
16166
- me.end = me.max;
16167
- }
16168
- },
16169
- convertTicksToLabels: function() {
16170
- this.tickValues = this.ticks.slice();
16171
-
16172
- Chart.Scale.prototype.convertTicksToLabels.call(this);
16173
- },
16174
- // Get the correct tooltip label
16175
- getLabelForIndex: function(index, datasetIndex) {
16176
- return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
16177
- },
16178
- getPixelForTick: function(index) {
16179
- return this.getPixelForValue(this.tickValues[index]);
16180
- },
16181
- getPixelForValue: function(value) {
16182
- var me = this;
16183
- var innerDimension;
16184
- var pixel;
16185
-
16186
- var start = me.start;
16187
- var newVal = +me.getRightValue(value);
16188
- var range;
16189
- var opts = me.options;
16190
- var tickOpts = opts.ticks;
16191
-
16192
- if (me.isHorizontal()) {
16193
- range = helpers.log10(me.end) - helpers.log10(start); // todo: if start === 0
16194
- if (newVal === 0) {
16195
- pixel = me.left;
16196
- } else {
16197
- innerDimension = me.width;
16198
- pixel = me.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
16199
- }
16200
- } else {
16201
- // Bottom - top since pixels increase downward on a screen
16202
- innerDimension = me.height;
16203
- if (start === 0 && !tickOpts.reverse) {
16204
- range = helpers.log10(me.end) - helpers.log10(me.minNotZero);
16205
- if (newVal === start) {
16206
- pixel = me.bottom;
16207
- } else if (newVal === me.minNotZero) {
16208
- pixel = me.bottom - innerDimension * 0.02;
16209
- } else {
16210
- pixel = me.bottom - innerDimension * 0.02 - (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
16211
- }
16212
- } else if (me.end === 0 && tickOpts.reverse) {
16213
- range = helpers.log10(me.start) - helpers.log10(me.minNotZero);
16214
- if (newVal === me.end) {
16215
- pixel = me.top;
16216
- } else if (newVal === me.minNotZero) {
16217
- pixel = me.top + innerDimension * 0.02;
16218
- } else {
16219
- pixel = me.top + innerDimension * 0.02 + (innerDimension * 0.98/ range * (helpers.log10(newVal)-helpers.log10(me.minNotZero)));
16220
- }
16221
- } else if (newVal === 0) {
16222
- pixel = tickOpts.reverse ? me.top : me.bottom;
16223
- } else {
16224
- range = helpers.log10(me.end) - helpers.log10(start);
16225
- innerDimension = me.height;
16226
- pixel = me.bottom - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
16227
- }
16228
- }
16229
- return pixel;
16230
- },
16231
- getValueForPixel: function(pixel) {
16232
- var me = this;
16233
- var range = helpers.log10(me.end) - helpers.log10(me.start);
16234
- var value, innerDimension;
16235
-
16236
- if (me.isHorizontal()) {
16237
- innerDimension = me.width;
16238
- value = me.start * Math.pow(10, (pixel - me.left) * range / innerDimension);
16239
- } else { // todo: if start === 0
16240
- innerDimension = me.height;
16241
- value = Math.pow(10, (me.bottom - pixel) * range / innerDimension) / me.start;
16242
- }
16243
- return value;
16244
- }
16245
- });
16246
- Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig);
16247
-
16248
- };
16249
-
16250
- },{}],48:[function(require,module,exports){
16251
- 'use strict';
16252
-
16253
- module.exports = function(Chart) {
16254
-
16255
- var helpers = Chart.helpers;
16256
- var globalDefaults = Chart.defaults.global;
16257
-
16258
- var defaultConfig = {
16259
- display: true,
16260
-
16261
- // Boolean - Whether to animate scaling the chart from the centre
16262
- animate: true,
16263
- position: 'chartArea',
16264
-
16265
- angleLines: {
16266
- display: true,
16267
- color: 'rgba(0, 0, 0, 0.1)',
16268
- lineWidth: 1
16269
- },
16270
-
16271
- gridLines: {
16272
- circular: false
16273
- },
16274
-
16275
- // label settings
16276
- ticks: {
16277
- // Boolean - Show a backdrop to the scale label
16278
- showLabelBackdrop: true,
16279
-
16280
- // String - The colour of the label backdrop
16281
- backdropColor: 'rgba(255,255,255,0.75)',
16282
-
16283
- // Number - The backdrop padding above & below the label in pixels
16284
- backdropPaddingY: 2,
16285
-
16286
- // Number - The backdrop padding to the side of the label in pixels
16287
- backdropPaddingX: 2,
16288
-
16289
- callback: Chart.Ticks.formatters.linear
16290
- },
16291
-
16292
- pointLabels: {
16293
- // Boolean - if true, show point labels
16294
- display: true,
16295
-
16296
- // Number - Point label font size in pixels
16297
- fontSize: 10,
16298
-
16299
- // Function - Used to convert point labels
16300
- callback: function(label) {
16301
- return label;
16302
- }
16303
- }
16304
- };
16305
-
16306
- function getValueCount(scale) {
16307
- var opts = scale.options;
16308
- return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
16309
- }
16310
-
16311
- function getPointLabelFontOptions(scale) {
16312
- var pointLabelOptions = scale.options.pointLabels;
16313
- var fontSize = helpers.getValueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
16314
- var fontStyle = helpers.getValueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
16315
- var fontFamily = helpers.getValueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
16316
- var font = helpers.fontString(fontSize, fontStyle, fontFamily);
16317
-
16318
- return {
16319
- size: fontSize,
16320
- style: fontStyle,
16321
- family: fontFamily,
16322
- font: font
16323
- };
16324
- }
16325
-
16326
- function measureLabelSize(ctx, fontSize, label) {
16327
- if (helpers.isArray(label)) {
16328
- return {
16329
- w: helpers.longestText(ctx, ctx.font, label),
16330
- h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
16331
- };
16332
- }
16333
-
16334
- return {
16335
- w: ctx.measureText(label).width,
16336
- h: fontSize
16337
- };
16338
- }
16339
-
16340
- function determineLimits(angle, pos, size, min, max) {
16341
- if (angle === min || angle === max) {
16342
- return {
16343
- start: pos - (size / 2),
16344
- end: pos + (size / 2)
16345
- };
16346
- } else if (angle < min || angle > max) {
16347
- return {
16348
- start: pos - size - 5,
16349
- end: pos
16350
- };
16351
- }
16352
-
16353
- return {
16354
- start: pos,
16355
- end: pos + size + 5
16356
- };
16357
- }
16358
-
16359
- /**
16360
- * Helper function to fit a radial linear scale with point labels
16361
- */
16362
- function fitWithPointLabels(scale) {
16363
- /*
16364
- * Right, this is really confusing and there is a lot of maths going on here
16365
- * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
16366
- *
16367
- * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
16368
- *
16369
- * Solution:
16370
- *
16371
- * We assume the radius of the polygon is half the size of the canvas at first
16372
- * at each index we check if the text overlaps.
16373
- *
16374
- * Where it does, we store that angle and that index.
16375
- *
16376
- * After finding the largest index and angle we calculate how much we need to remove
16377
- * from the shape radius to move the point inwards by that x.
16378
- *
16379
- * We average the left and right distances to get the maximum shape radius that can fit in the box
16380
- * along with labels.
16381
- *
16382
- * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
16383
- * on each side, removing that from the size, halving it and adding the left x protrusion width.
16384
- *
16385
- * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
16386
- * and position it in the most space efficient manner
16387
- *
16388
- * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
16389
- */
16390
-
16391
- var plFont = getPointLabelFontOptions(scale);
16392
-
16393
- // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
16394
- // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
16395
- var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
16396
- var furthestLimits = {
16397
- r: scale.width,
16398
- l: 0,
16399
- t: scale.height,
16400
- b: 0
16401
- };
16402
- var furthestAngles = {};
16403
- var i;
16404
- var textSize;
16405
- var pointPosition;
16406
-
16407
- scale.ctx.font = plFont.font;
16408
- scale._pointLabelSizes = [];
16409
-
16410
- var valueCount = getValueCount(scale);
16411
- for (i = 0; i < valueCount; i++) {
16412
- pointPosition = scale.getPointPosition(i, largestPossibleRadius);
16413
- textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
16414
- scale._pointLabelSizes[i] = textSize;
16415
-
16416
- // Add quarter circle to make degree 0 mean top of circle
16417
- var angleRadians = scale.getIndexAngle(i);
16418
- var angle = helpers.toDegrees(angleRadians) % 360;
16419
- var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
16420
- var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
16421
-
16422
- if (hLimits.start < furthestLimits.l) {
16423
- furthestLimits.l = hLimits.start;
16424
- furthestAngles.l = angleRadians;
16425
- }
16426
-
16427
- if (hLimits.end > furthestLimits.r) {
16428
- furthestLimits.r = hLimits.end;
16429
- furthestAngles.r = angleRadians;
16430
- }
16431
-
16432
- if (vLimits.start < furthestLimits.t) {
16433
- furthestLimits.t = vLimits.start;
16434
- furthestAngles.t = angleRadians;
16435
- }
16436
-
16437
- if (vLimits.end > furthestLimits.b) {
16438
- furthestLimits.b = vLimits.end;
16439
- furthestAngles.b = angleRadians;
16440
- }
16441
- }
16442
-
16443
- scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
16444
- }
16445
-
16446
- /**
16447
- * Helper function to fit a radial linear scale with no point labels
16448
- */
16449
- function fit(scale) {
16450
- var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
16451
- scale.drawingArea = Math.round(largestPossibleRadius);
16452
- scale.setCenterPoint(0, 0, 0, 0);
16453
- }
16454
-
16455
- function getTextAlignForAngle(angle) {
16456
- if (angle === 0 || angle === 180) {
16457
- return 'center';
16458
- } else if (angle < 180) {
16459
- return 'left';
16460
- }
16461
-
16462
- return 'right';
16463
- }
16464
-
16465
- function fillText(ctx, text, position, fontSize) {
16466
- if (helpers.isArray(text)) {
16467
- var y = position.y;
16468
- var spacing = 1.5 * fontSize;
16469
-
16470
- for (var i = 0; i < text.length; ++i) {
16471
- ctx.fillText(text[i], position.x, y);
16472
- y+= spacing;
16473
- }
16474
- } else {
16475
- ctx.fillText(text, position.x, position.y);
16476
- }
16477
- }
16478
-
16479
- function adjustPointPositionForLabelHeight(angle, textSize, position) {
16480
- if (angle === 90 || angle === 270) {
16481
- position.y -= (textSize.h / 2);
16482
- } else if (angle > 270 || angle < 90) {
16483
- position.y -= textSize.h;
16484
- }
16485
- }
16486
-
16487
- function drawPointLabels(scale) {
16488
- var ctx = scale.ctx;
16489
- var getValueOrDefault = helpers.getValueOrDefault;
16490
- var opts = scale.options;
16491
- var angleLineOpts = opts.angleLines;
16492
- var pointLabelOpts = opts.pointLabels;
16493
-
16494
- ctx.lineWidth = angleLineOpts.lineWidth;
16495
- ctx.strokeStyle = angleLineOpts.color;
16496
-
16497
- var outerDistance = scale.getDistanceFromCenterForValue(opts.reverse ? scale.min : scale.max);
16498
-
16499
- // Point Label Font
16500
- var plFont = getPointLabelFontOptions(scale);
16501
-
16502
- ctx.textBaseline = 'top';
16503
-
16504
- for (var i = getValueCount(scale) - 1; i >= 0; i--) {
16505
- if (angleLineOpts.display) {
16506
- var outerPosition = scale.getPointPosition(i, outerDistance);
16507
- ctx.beginPath();
16508
- ctx.moveTo(scale.xCenter, scale.yCenter);
16509
- ctx.lineTo(outerPosition.x, outerPosition.y);
16510
- ctx.stroke();
16511
- ctx.closePath();
16512
- }
16513
-
16514
- if (pointLabelOpts.display) {
16515
- // Extra 3px out for some label spacing
16516
- var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);
16517
-
16518
- // Keep this in loop since we may support array properties here
16519
- var pointLabelFontColor = getValueOrDefault(pointLabelOpts.fontColor, globalDefaults.defaultFontColor);
16520
- ctx.font = plFont.font;
16521
- ctx.fillStyle = pointLabelFontColor;
16522
-
16523
- var angleRadians = scale.getIndexAngle(i);
16524
- var angle = helpers.toDegrees(angleRadians);
16525
- ctx.textAlign = getTextAlignForAngle(angle);
16526
- adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
16527
- fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
16528
- }
16529
- }
16530
- }
16531
-
16532
- function drawRadiusLine(scale, gridLineOpts, radius, index) {
16533
- var ctx = scale.ctx;
16534
- ctx.strokeStyle = helpers.getValueAtIndexOrDefault(gridLineOpts.color, index - 1);
16535
- ctx.lineWidth = helpers.getValueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
16536
-
16537
- if (scale.options.gridLines.circular) {
16538
- // Draw circular arcs between the points
16539
- ctx.beginPath();
16540
- ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
16541
- ctx.closePath();
16542
- ctx.stroke();
16543
- } else {
16544
- // Draw straight lines connecting each index
16545
- var valueCount = getValueCount(scale);
16546
-
16547
- if (valueCount === 0) {
16548
- return;
16549
- }
16550
-
16551
- ctx.beginPath();
16552
- var pointPosition = scale.getPointPosition(0, radius);
16553
- ctx.moveTo(pointPosition.x, pointPosition.y);
16554
-
16555
- for (var i = 1; i < valueCount; i++) {
16556
- pointPosition = scale.getPointPosition(i, radius);
16557
- ctx.lineTo(pointPosition.x, pointPosition.y);
16558
- }
16559
-
16560
- ctx.closePath();
16561
- ctx.stroke();
16562
- }
16563
- }
16564
-
16565
- function numberOrZero(param) {
16566
- return helpers.isNumber(param) ? param : 0;
16567
- }
16568
-
16569
- var LinearRadialScale = Chart.LinearScaleBase.extend({
16570
- setDimensions: function() {
16571
- var me = this;
16572
- var opts = me.options;
16573
- var tickOpts = opts.ticks;
16574
- // Set the unconstrained dimension before label rotation
16575
- me.width = me.maxWidth;
16576
- me.height = me.maxHeight;
16577
- me.xCenter = Math.round(me.width / 2);
16578
- me.yCenter = Math.round(me.height / 2);
16579
-
16580
- var minSize = helpers.min([me.height, me.width]);
16581
- var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
16582
- me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
16583
- },
16584
- determineDataLimits: function() {
16585
- var me = this;
16586
- var chart = me.chart;
16587
- var min = Number.POSITIVE_INFINITY;
16588
- var max = Number.NEGATIVE_INFINITY;
16589
-
16590
- helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
16591
- if (chart.isDatasetVisible(datasetIndex)) {
16592
- var meta = chart.getDatasetMeta(datasetIndex);
16593
-
16594
- helpers.each(dataset.data, function(rawValue, index) {
16595
- var value = +me.getRightValue(rawValue);
16596
- if (isNaN(value) || meta.data[index].hidden) {
16597
- return;
16598
- }
16599
-
16600
- min = Math.min(value, min);
16601
- max = Math.max(value, max);
16602
- });
16603
- }
16604
- });
16605
-
16606
- me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
16607
- me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
16608
-
16609
- // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
16610
- me.handleTickRangeOptions();
16611
- },
16612
- getTickLimit: function() {
16613
- var tickOpts = this.options.ticks;
16614
- var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
16615
- return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
16616
- },
16617
- convertTicksToLabels: function() {
16618
- var me = this;
16619
- Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);
16620
-
16621
- // Point labels
16622
- me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
16623
- },
16624
- getLabelForIndex: function(index, datasetIndex) {
16625
- return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
16626
- },
16627
- fit: function() {
16628
- if (this.options.pointLabels.display) {
16629
- fitWithPointLabels(this);
16630
- } else {
16631
- fit(this);
16632
- }
16633
- },
16634
- /**
16635
- * Set radius reductions and determine new radius and center point
16636
- * @private
16637
- */
16638
- setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
16639
- var me = this;
16640
- var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
16641
- var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
16642
- var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
16643
- var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);
16644
-
16645
- radiusReductionLeft = numberOrZero(radiusReductionLeft);
16646
- radiusReductionRight = numberOrZero(radiusReductionRight);
16647
- radiusReductionTop = numberOrZero(radiusReductionTop);
16648
- radiusReductionBottom = numberOrZero(radiusReductionBottom);
16649
-
16650
- me.drawingArea = Math.min(
16651
- Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
16652
- Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
16653
- me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
16654
- },
16655
- setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
16656
- var me = this;
16657
- var maxRight = me.width - rightMovement - me.drawingArea,
16658
- maxLeft = leftMovement + me.drawingArea,
16659
- maxTop = topMovement + me.drawingArea,
16660
- maxBottom = me.height - bottomMovement - me.drawingArea;
16661
-
16662
- me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
16663
- me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
16664
- },
16665
-
16666
- getIndexAngle: function(index) {
16667
- var angleMultiplier = (Math.PI * 2) / getValueCount(this);
16668
- var startAngle = this.chart.options && this.chart.options.startAngle ?
16669
- this.chart.options.startAngle :
16670
- 0;
16671
-
16672
- var startAngleRadians = startAngle * Math.PI * 2 / 360;
16673
-
16674
- // Start from the top instead of right, so remove a quarter of the circle
16675
- return index * angleMultiplier + startAngleRadians;
16676
- },
16677
- getDistanceFromCenterForValue: function(value) {
16678
- var me = this;
16679
-
16680
- if (value === null) {
16681
- return 0; // null always in center
16682
- }
16683
-
16684
- // Take into account half font size + the yPadding of the top value
16685
- var scalingFactor = me.drawingArea / (me.max - me.min);
16686
- if (me.options.reverse) {
16687
- return (me.max - value) * scalingFactor;
16688
- }
16689
- return (value - me.min) * scalingFactor;
16690
- },
16691
- getPointPosition: function(index, distanceFromCenter) {
16692
- var me = this;
16693
- var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
16694
- return {
16695
- x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
16696
- y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
16697
- };
16698
- },
16699
- getPointPositionForValue: function(index, value) {
16700
- return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
16701
- },
16702
-
16703
- getBasePosition: function() {
16704
- var me = this;
16705
- var min = me.min;
16706
- var max = me.max;
16707
-
16708
- return me.getPointPositionForValue(0,
16709
- me.beginAtZero? 0:
16710
- min < 0 && max < 0? max :
16711
- min > 0 && max > 0? min :
16712
- 0);
16713
- },
16714
-
16715
- draw: function() {
16716
- var me = this;
16717
- var opts = me.options;
16718
- var gridLineOpts = opts.gridLines;
16719
- var tickOpts = opts.ticks;
16720
- var getValueOrDefault = helpers.getValueOrDefault;
16721
-
16722
- if (opts.display) {
16723
- var ctx = me.ctx;
16724
-
16725
- // Tick Font
16726
- var tickFontSize = getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
16727
- var tickFontStyle = getValueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
16728
- var tickFontFamily = getValueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
16729
- var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
16730
-
16731
- helpers.each(me.ticks, function(label, index) {
16732
- // Don't draw a centre value (if it is minimum)
16733
- if (index > 0 || opts.reverse) {
16734
- var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
16735
- var yHeight = me.yCenter - yCenterOffset;
16736
-
16737
- // Draw circular lines around the scale
16738
- if (gridLineOpts.display && index !== 0) {
16739
- drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
16740
- }
16741
-
16742
- if (tickOpts.display) {
16743
- var tickFontColor = getValueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
16744
- ctx.font = tickLabelFont;
16745
-
16746
- if (tickOpts.showLabelBackdrop) {
16747
- var labelWidth = ctx.measureText(label).width;
16748
- ctx.fillStyle = tickOpts.backdropColor;
16749
- ctx.fillRect(
16750
- me.xCenter - labelWidth / 2 - tickOpts.backdropPaddingX,
16751
- yHeight - tickFontSize / 2 - tickOpts.backdropPaddingY,
16752
- labelWidth + tickOpts.backdropPaddingX * 2,
16753
- tickFontSize + tickOpts.backdropPaddingY * 2
16754
- );
16755
- }
16756
-
16757
- ctx.textAlign = 'center';
16758
- ctx.textBaseline = 'middle';
16759
- ctx.fillStyle = tickFontColor;
16760
- ctx.fillText(label, me.xCenter, yHeight);
16761
- }
16762
- }
16763
- });
16764
-
16765
- if (opts.angleLines.display || opts.pointLabels.display) {
16766
- drawPointLabels(me);
16767
- }
16768
- }
16769
- }
16770
- });
16771
- Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig);
16772
-
16773
- };
16774
-
16775
- },{}],49:[function(require,module,exports){
16776
- /* global window: false */
16777
- 'use strict';
16778
-
16779
- var moment = require(6);
16780
- moment = typeof(moment) === 'function' ? moment : window.moment;
16781
-
16782
- module.exports = function(Chart) {
16783
-
16784
- var helpers = Chart.helpers;
16785
- var interval = {
16786
- millisecond: {
16787
- size: 1,
16788
- steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
16789
- },
16790
- second: {
16791
- size: 1000,
16792
- steps: [1, 2, 5, 10, 30]
16793
- },
16794
- minute: {
16795
- size: 60000,
16796
- steps: [1, 2, 5, 10, 30]
16797
- },
16798
- hour: {
16799
- size: 3600000,
16800
- steps: [1, 2, 3, 6, 12]
16801
- },
16802
- day: {
16803
- size: 86400000,
16804
- steps: [1, 2, 5]
16805
- },
16806
- week: {
16807
- size: 604800000,
16808
- maxStep: 4
16809
- },
16810
- month: {
16811
- size: 2.628e9,
16812
- maxStep: 3
16813
- },
16814
- quarter: {
16815
- size: 7.884e9,
16816
- maxStep: 4
16817
- },
16818
- year: {
16819
- size: 3.154e10,
16820
- maxStep: false
16821
- }
16822
- };
16823
-
16824
- var defaultConfig = {
16825
- position: 'bottom',
16826
-
16827
- time: {
16828
- 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
16829
- format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
16830
- unit: false, // false == automatic or override with week, month, year, etc.
16831
- round: false, // none, or override with week, month, year, etc.
16832
- displayFormat: false, // DEPRECATED
16833
- isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
16834
- minUnit: 'millisecond',
16835
-
16836
- // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
16837
- displayFormats: {
16838
- millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
16839
- second: 'h:mm:ss a', // 11:20:01 AM
16840
- minute: 'h:mm:ss a', // 11:20:01 AM
16841
- hour: 'MMM D, hA', // Sept 4, 5PM
16842
- day: 'll', // Sep 4 2015
16843
- week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
16844
- month: 'MMM YYYY', // Sept 2015
16845
- quarter: '[Q]Q - YYYY', // Q3
16846
- year: 'YYYY' // 2015
16847
- },
16848
- },
16849
- ticks: {
16850
- autoSkip: false
16851
- }
16852
- };
16853
-
16854
- /**
16855
- * Helper function to parse time to a moment object
16856
- * @param axis {TimeAxis} the time axis
16857
- * @param label {Date|string|number|Moment} The thing to parse
16858
- * @return {Moment} parsed time
16859
- */
16860
- function parseTime(axis, label) {
16861
- var timeOpts = axis.options.time;
16862
- if (typeof timeOpts.parser === 'string') {
16863
- return moment(label, timeOpts.parser);
16864
- }
16865
- if (typeof timeOpts.parser === 'function') {
16866
- return timeOpts.parser(label);
16867
- }
16868
- if (typeof label.getMonth === 'function' || typeof label === 'number') {
16869
- // Date objects
16870
- return moment(label);
16871
- }
16872
- if (label.isValid && label.isValid()) {
16873
- // Moment support
16874
- return label;
16875
- }
16876
- var format = timeOpts.format;
16877
- if (typeof format !== 'string' && format.call) {
16878
- // Custom parsing (return an instance of moment)
16879
- console.warn('options.time.format is deprecated and replaced by options.time.parser.');
16880
- return format(label);
16881
- }
16882
- // Moment format parsing
16883
- return moment(label, format);
16884
- }
16885
-
16886
- /**
16887
- * Figure out which is the best unit for the scale
16888
- * @param minUnit {String} minimum unit to use
16889
- * @param min {Number} scale minimum
16890
- * @param max {Number} scale maximum
16891
- * @return {String} the unit to use
16892
- */
16893
- function determineUnit(minUnit, min, max, maxTicks) {
16894
- var units = Object.keys(interval);
16895
- var unit;
16896
- var numUnits = units.length;
16897
-
16898
- for (var i = units.indexOf(minUnit); i < numUnits; i++) {
16899
- unit = units[i];
16900
- var unitDetails = interval[unit];
16901
- var steps = (unitDetails.steps && unitDetails.steps[unitDetails.steps.length - 1]) || unitDetails.maxStep;
16902
- if (steps === undefined || Math.ceil((max - min) / (steps * unitDetails.size)) <= maxTicks) {
16903
- break;
16904
- }
16905
- }
16906
-
16907
- return unit;
16908
- }
16909
-
16910
- /**
16911
- * Determines how we scale the unit
16912
- * @param min {Number} the scale minimum
16913
- * @param max {Number} the scale maximum
16914
- * @param unit {String} the unit determined by the {@see determineUnit} method
16915
- * @return {Number} the axis step size as a multiple of unit
16916
- */
16917
- function determineStepSize(min, max, unit, maxTicks) {
16918
- // Using our unit, figoure out what we need to scale as
16919
- var unitDefinition = interval[unit];
16920
- var unitSizeInMilliSeconds = unitDefinition.size;
16921
- var sizeInUnits = Math.ceil((max - min) / unitSizeInMilliSeconds);
16922
- var multiplier = 1;
16923
- var range = max - min;
16924
-
16925
- if (unitDefinition.steps) {
16926
- // Have an array of steps
16927
- var numSteps = unitDefinition.steps.length;
16928
- for (var i = 0; i < numSteps && sizeInUnits > maxTicks; i++) {
16929
- multiplier = unitDefinition.steps[i];
16930
- sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
16931
- }
16932
- } else {
16933
- while (sizeInUnits > maxTicks && maxTicks > 0) {
16934
- ++multiplier;
16935
- sizeInUnits = Math.ceil(range / (unitSizeInMilliSeconds * multiplier));
16936
- }
16937
- }
16938
-
16939
- return multiplier;
16940
- }
16941
-
16942
- /**
16943
- * Helper for generating axis labels.
16944
- * @param options {ITimeGeneratorOptions} the options for generation
16945
- * @param dataRange {IRange} the data range
16946
- * @param niceRange {IRange} the pretty range to display
16947
- * @return {Number[]} ticks
16948
- */
16949
- function generateTicks(options, dataRange, niceRange) {
16950
- var ticks = [];
16951
- if (options.maxTicks) {
16952
- var stepSize = options.stepSize;
16953
- ticks.push(options.min !== undefined ? options.min : niceRange.min);
16954
- var cur = moment(niceRange.min);
16955
- while (cur.add(stepSize, options.unit).valueOf() < niceRange.max) {
16956
- ticks.push(cur.valueOf());
16957
- }
16958
- var realMax = options.max || niceRange.max;
16959
- if (ticks[ticks.length - 1] !== realMax) {
16960
- ticks.push(realMax);
16961
- }
16962
- }
16963
- return ticks;
16964
- }
16965
-
16966
- /**
16967
- * @function Chart.Ticks.generators.time
16968
- * @param options {ITimeGeneratorOptions} the options for generation
16969
- * @param dataRange {IRange} the data range
16970
- * @return {Number[]} ticks
16971
- */
16972
- Chart.Ticks.generators.time = function(options, dataRange) {
16973
- var niceMin;
16974
- var niceMax;
16975
- var isoWeekday = options.isoWeekday;
16976
- if (options.unit === 'week' && isoWeekday !== false) {
16977
- niceMin = moment(dataRange.min).startOf('isoWeek').isoWeekday(isoWeekday).valueOf();
16978
- niceMax = moment(dataRange.max).startOf('isoWeek').isoWeekday(isoWeekday);
16979
- if (dataRange.max - niceMax > 0) {
16980
- niceMax.add(1, 'week');
16981
- }
16982
- niceMax = niceMax.valueOf();
16983
- } else {
16984
- niceMin = moment(dataRange.min).startOf(options.unit).valueOf();
16985
- niceMax = moment(dataRange.max).startOf(options.unit);
16986
- if (dataRange.max - niceMax > 0) {
16987
- niceMax.add(1, options.unit);
16988
- }
16989
- niceMax = niceMax.valueOf();
16990
- }
16991
- return generateTicks(options, dataRange, {
16992
- min: niceMin,
16993
- max: niceMax
16994
- });
16995
- };
16996
-
16997
- var TimeScale = Chart.Scale.extend({
16998
- initialize: function() {
16999
- if (!moment) {
17000
- 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');
17001
- }
17002
-
17003
- Chart.Scale.prototype.initialize.call(this);
17004
- },
17005
- determineDataLimits: function() {
17006
- var me = this;
17007
- var timeOpts = me.options.time;
17008
-
17009
- // We store the data range as unix millisecond timestamps so dataMin and dataMax will always be integers.
17010
- var dataMin = Number.MAX_SAFE_INTEGER;
17011
- var dataMax = Number.MIN_SAFE_INTEGER;
17012
-
17013
- var chartData = me.chart.data;
17014
- var parsedData = {
17015
- labels: [],
17016
- datasets: []
17017
- };
17018
-
17019
- var timestamp;
17020
-
17021
- helpers.each(chartData.labels, function(label, labelIndex) {
17022
- var labelMoment = parseTime(me, label);
17023
-
17024
- if (labelMoment.isValid()) {
17025
- // We need to round the time
17026
- if (timeOpts.round) {
17027
- labelMoment.startOf(timeOpts.round);
17028
- }
17029
-
17030
- timestamp = labelMoment.valueOf();
17031
- dataMin = Math.min(timestamp, dataMin);
17032
- dataMax = Math.max(timestamp, dataMax);
17033
-
17034
- // Store this value for later
17035
- parsedData.labels[labelIndex] = timestamp;
17036
- }
17037
- });
17038
-
17039
- helpers.each(chartData.datasets, function(dataset, datasetIndex) {
17040
- var timestamps = [];
17041
-
17042
- if (typeof dataset.data[0] === 'object' && dataset.data[0] !== null && me.chart.isDatasetVisible(datasetIndex)) {
17043
- // We have potential point data, so we need to parse this
17044
- helpers.each(dataset.data, function(value, dataIndex) {
17045
- var dataMoment = parseTime(me, me.getRightValue(value));
17046
-
17047
- if (dataMoment.isValid()) {
17048
- if (timeOpts.round) {
17049
- dataMoment.startOf(timeOpts.round);
17050
- }
17051
-
17052
- timestamp = dataMoment.valueOf();
17053
- dataMin = Math.min(timestamp, dataMin);
17054
- dataMax = Math.max(timestamp, dataMax);
17055
- timestamps[dataIndex] = timestamp;
17056
- }
17057
- });
17058
- } else {
17059
- // We have no x coordinates, so use the ones from the labels
17060
- timestamps = parsedData.labels.slice();
17061
- }
17062
-
17063
- parsedData.datasets[datasetIndex] = timestamps;
17064
- });
17065
-
17066
- me.dataMin = dataMin;
17067
- me.dataMax = dataMax;
17068
- me._parsedData = parsedData;
17069
- },
17070
- buildTicks: function() {
17071
- var me = this;
17072
- var timeOpts = me.options.time;
17073
-
17074
- var minTimestamp;
17075
- var maxTimestamp;
17076
- var dataMin = me.dataMin;
17077
- var dataMax = me.dataMax;
17078
-
17079
- if (timeOpts.min) {
17080
- var minMoment = parseTime(me, timeOpts.min);
17081
- if (timeOpts.round) {
17082
- minMoment.round(timeOpts.round);
17083
- }
17084
- minTimestamp = minMoment.valueOf();
17085
- }
17086
-
17087
- if (timeOpts.max) {
17088
- maxTimestamp = parseTime(me, timeOpts.max).valueOf();
17089
- }
17090
-
17091
- var maxTicks = me.getLabelCapacity(minTimestamp || dataMin);
17092
- var unit = timeOpts.unit || determineUnit(timeOpts.minUnit, minTimestamp || dataMin, maxTimestamp || dataMax, maxTicks);
17093
- me.displayFormat = timeOpts.displayFormats[unit];
17094
-
17095
- var stepSize = timeOpts.stepSize || determineStepSize(minTimestamp || dataMin, maxTimestamp || dataMax, unit, maxTicks);
17096
- me.ticks = Chart.Ticks.generators.time({
17097
- maxTicks: maxTicks,
17098
- min: minTimestamp,
17099
- max: maxTimestamp,
17100
- stepSize: stepSize,
17101
- unit: unit,
17102
- isoWeekday: timeOpts.isoWeekday
17103
- }, {
17104
- min: dataMin,
17105
- max: dataMax
17106
- });
17107
-
17108
- // At this point, we need to update our max and min given the tick values since we have expanded the
17109
- // range of the scale
17110
- me.max = helpers.max(me.ticks);
17111
- me.min = helpers.min(me.ticks);
17112
- },
17113
- // Get tooltip label
17114
- getLabelForIndex: function(index, datasetIndex) {
17115
- var me = this;
17116
- var label = me.chart.data.labels && index < me.chart.data.labels.length ? me.chart.data.labels[index] : '';
17117
- var value = me.chart.data.datasets[datasetIndex].data[index];
17118
-
17119
- if (value !== null && typeof value === 'object') {
17120
- label = me.getRightValue(value);
17121
- }
17122
-
17123
- // Format nicely
17124
- if (me.options.time.tooltipFormat) {
17125
- label = parseTime(me, label).format(me.options.time.tooltipFormat);
17126
- }
17127
-
17128
- return label;
17129
- },
17130
- // Function to format an individual tick mark
17131
- tickFormatFunction: function(tick, index, ticks) {
17132
- var formattedTick = tick.format(this.displayFormat);
17133
- var tickOpts = this.options.ticks;
17134
- var callback = helpers.getValueOrDefault(tickOpts.callback, tickOpts.userCallback);
17135
-
17136
- if (callback) {
17137
- return callback(formattedTick, index, ticks);
17138
- }
17139
- return formattedTick;
17140
- },
17141
- convertTicksToLabels: function() {
17142
- var me = this;
17143
- me.ticksAsTimestamps = me.ticks;
17144
- me.ticks = me.ticks.map(function(tick) {
17145
- return moment(tick);
17146
- }).map(me.tickFormatFunction, me);
17147
- },
17148
- getPixelForOffset: function(offset) {
17149
- var me = this;
17150
- var epochWidth = me.max - me.min;
17151
- var decimal = epochWidth ? (offset - me.min) / epochWidth : 0;
17152
-
17153
- if (me.isHorizontal()) {
17154
- var valueOffset = (me.width * decimal);
17155
- return me.left + Math.round(valueOffset);
17156
- }
17157
-
17158
- var heightOffset = (me.height * decimal);
17159
- return me.top + Math.round(heightOffset);
17160
- },
17161
- getPixelForValue: function(value, index, datasetIndex) {
17162
- var me = this;
17163
- var offset = null;
17164
- if (index !== undefined && datasetIndex !== undefined) {
17165
- offset = me._parsedData.datasets[datasetIndex][index];
17166
- }
17167
-
17168
- if (offset === null) {
17169
- if (!value || !value.isValid) {
17170
- // not already a moment object
17171
- value = parseTime(me, me.getRightValue(value));
17172
- }
17173
-
17174
- if (value && value.isValid && value.isValid()) {
17175
- offset = value.valueOf();
17176
- }
17177
- }
17178
-
17179
- if (offset !== null) {
17180
- return me.getPixelForOffset(offset);
17181
- }
17182
- },
17183
- getPixelForTick: function(index) {
17184
- return this.getPixelForOffset(this.ticksAsTimestamps[index]);
17185
- },
17186
- getValueForPixel: function(pixel) {
17187
- var me = this;
17188
- var innerDimension = me.isHorizontal() ? me.width : me.height;
17189
- var offset = (pixel - (me.isHorizontal() ? me.left : me.top)) / innerDimension;
17190
- return moment(me.min + (offset * (me.max - me.min)));
17191
- },
17192
- // Crude approximation of what the label width might be
17193
- getLabelWidth: function(label) {
17194
- var me = this;
17195
- var ticks = me.options.ticks;
17196
-
17197
- var tickLabelWidth = me.ctx.measureText(label).width;
17198
- var cosRotation = Math.cos(helpers.toRadians(ticks.maxRotation));
17199
- var sinRotation = Math.sin(helpers.toRadians(ticks.maxRotation));
17200
- var tickFontSize = helpers.getValueOrDefault(ticks.fontSize, Chart.defaults.global.defaultFontSize);
17201
- return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
17202
- },
17203
- getLabelCapacity: function(exampleTime) {
17204
- var me = this;
17205
-
17206
- me.displayFormat = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation
17207
- var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, []);
17208
- var tickLabelWidth = me.getLabelWidth(exampleLabel);
17209
-
17210
- var innerWidth = me.isHorizontal() ? me.width : me.height;
17211
- var labelCapacity = innerWidth / tickLabelWidth;
17212
- return labelCapacity;
17213
- }
17214
- });
17215
- Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig);
17216
-
17217
- };
17218
-
17219
- },{"6":6}]},{},[7])(7)
17220
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/Chart.bundle.min.js DELETED
@@ -1,16 +0,0 @@
1
- /*!
2
- * Chart.js
3
- * http://chartjs.org/
4
- * Version: 2.6.0
5
- *
6
- * Copyright 2017 Nick Downie
7
- * Released under the MIT license
8
- * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
9
- */
10
- !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Chart=t()}}(function(){var t;return function t(e,n,i){function a(o,s){if(!n[o]){if(!e[o]){var l="function"==typeof require&&require;if(!s&&l)return l(o,!0);if(r)return r(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var d=n[o]={exports:{}};e[o][0].call(d.exports,function(t){var n=e[o][1][t];return a(n?n:t)},d,d.exports,t,e,n,i)}return n[o].exports}for(var r="function"==typeof require&&require,o=0;o<i.length;o++)a(i[o]);return a}({1:[function(t,e,n){function i(t){if(t){var e=/^#([a-fA-F0-9]{3})$/,n=/^#([a-fA-F0-9]{6})$/,i=/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,a=/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,r=/(\w+)/,o=[0,0,0],s=1,l=t.match(e);if(l){l=l[1];for(var u=0;u<o.length;u++)o[u]=parseInt(l[u]+l[u],16)}else if(l=t.match(n)){l=l[1];for(var u=0;u<o.length;u++)o[u]=parseInt(l.slice(2*u,2*u+2),16)}else if(l=t.match(i)){for(var u=0;u<o.length;u++)o[u]=parseInt(l[u+1]);s=parseFloat(l[4])}else if(l=t.match(a)){for(var u=0;u<o.length;u++)o[u]=Math.round(2.55*parseFloat(l[u+1]));s=parseFloat(l[4])}else if(l=t.match(r)){if("transparent"==l[1])return[0,0,0,0];if(o=x[l[1]],!o)return}for(var u=0;u<o.length;u++)o[u]=y(o[u],0,255);return s=s||0==s?y(s,0,1):1,o[3]=s,o}}function a(t){if(t){var e=/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/,n=t.match(e);if(n){var i=parseFloat(n[4]),a=y(parseInt(n[1]),0,360),r=y(parseFloat(n[2]),0,100),o=y(parseFloat(n[3]),0,100),s=y(isNaN(i)?1:i,0,1);return[a,r,o,s]}}}function r(t){if(t){var e=/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/,n=t.match(e);if(n){var i=parseFloat(n[4]),a=y(parseInt(n[1]),0,360),r=y(parseFloat(n[2]),0,100),o=y(parseFloat(n[3]),0,100),s=y(isNaN(i)?1:i,0,1);return[a,r,o,s]}}}function o(t){var e=i(t);return e&&e.slice(0,3)}function s(t){var e=a(t);return e&&e.slice(0,3)}function l(t){var e=i(t);return e?e[3]:(e=a(t))?e[3]:(e=r(t))?e[3]:void 0}function u(t){return"#"+b(t[0])+b(t[1])+b(t[2])}function d(t,e){return e<1||t[3]&&t[3]<1?c(t,e):"rgb("+t[0]+", "+t[1]+", "+t[2]+")"}function c(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function h(t,e){if(e<1||t[3]&&t[3]<1)return f(t,e);var n=Math.round(t[0]/255*100),i=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgb("+n+"%, "+i+"%, "+a+"%)"}function f(t,e){var n=Math.round(t[0]/255*100),i=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgba("+n+"%, "+i+"%, "+a+"%, "+(e||t[3]||1)+")"}function g(t,e){return e<1||t[3]&&t[3]<1?p(t,e):"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"}function p(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function m(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"}function v(t){return _[t.slice(0,3)]}function y(t,e,n){return Math.min(Math.max(e,t),n)}function b(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var x=t(5);e.exports={getRgba:i,getHsla:a,getRgb:o,getHsl:s,getHwb:r,getAlpha:l,hexString:u,rgbString:d,rgbaString:c,percentString:h,percentaString:f,hslString:g,hslaString:p,hwbString:m,keyword:v};var _={};for(var k in x)_[x[k]]=k},{5:5}],2:[function(t,e,n){var i=t(4),a=t(1),r=function(t){if(t instanceof r)return t;if(!(this instanceof r))return new r(t);this.valid=!1,this.values={rgb:[0,0,0],hsl:[0,0,0],hsv:[0,0,0],hwb:[0,0,0],cmyk:[0,0,0,0],alpha:1};var e;"string"==typeof t?(e=a.getRgba(t),e?this.setValues("rgb",e):(e=a.getHsla(t))?this.setValues("hsl",e):(e=a.getHwb(t))&&this.setValues("hwb",e)):"object"==typeof t&&(e=t,void 0!==e.r||void 0!==e.red?this.setValues("rgb",e):void 0!==e.l||void 0!==e.lightness?this.setValues("hsl",e):void 0!==e.v||void 0!==e.value?this.setValues("hsv",e):void 0!==e.w||void 0!==e.whiteness?this.setValues("hwb",e):void 0===e.c&&void 0===e.cyan||this.setValues("cmyk",e))};r.prototype={isValid:function(){return this.valid},rgb:function(){return this.setSpace("rgb",arguments)},hsl:function(){return this.setSpace("hsl",arguments)},hsv:function(){return this.setSpace("hsv",arguments)},hwb:function(){return this.setSpace("hwb",arguments)},cmyk:function(){return this.setSpace("cmyk",arguments)},rgbArray:function(){return this.values.rgb},hslArray:function(){return this.values.hsl},hsvArray:function(){return this.values.hsv},hwbArray:function(){var t=this.values;return 1!==t.alpha?t.hwb.concat([t.alpha]):t.hwb},cmykArray:function(){return this.values.cmyk},rgbaArray:function(){var t=this.values;return t.rgb.concat([t.alpha])},hslaArray:function(){var t=this.values;return t.hsl.concat([t.alpha])},alpha:function(t){return void 0===t?this.values.alpha:(this.setValues("alpha",t),this)},red:function(t){return this.setChannel("rgb",0,t)},green:function(t){return this.setChannel("rgb",1,t)},blue:function(t){return this.setChannel("rgb",2,t)},hue:function(t){return t&&(t%=360,t=t<0?360+t:t),this.setChannel("hsl",0,t)},saturation:function(t){return this.setChannel("hsl",1,t)},lightness:function(t){return this.setChannel("hsl",2,t)},saturationv:function(t){return this.setChannel("hsv",1,t)},whiteness:function(t){return this.setChannel("hwb",1,t)},blackness:function(t){return this.setChannel("hwb",2,t)},value:function(t){return this.setChannel("hsv",2,t)},cyan:function(t){return this.setChannel("cmyk",0,t)},magenta:function(t){return this.setChannel("cmyk",1,t)},yellow:function(t){return this.setChannel("cmyk",2,t)},black:function(t){return this.setChannel("cmyk",3,t)},hexString:function(){return a.hexString(this.values.rgb)},rgbString:function(){return a.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return a.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return a.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return a.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return a.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return a.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return a.keyword(this.values.rgb,this.values.alpha)},rgbNumber:function(){var t=this.values.rgb;return t[0]<<16|t[1]<<8|t[2]},luminosity:function(){for(var t=this.values.rgb,e=[],n=0;n<t.length;n++){var i=t[n]/255;e[n]=i<=.03928?i/12.92:Math.pow((i+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),n=t.luminosity();return e>n?(e+.05)/(n+.05):(n+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb,e=(299*t[0]+587*t[1]+114*t[2])/1e3;return e<128},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;e<3;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,n=(e[0]+t)%360;return e[0]=n<0?360+n:n,this.setValues("hsl",e),this},mix:function(t,e){var n=this,i=t,a=void 0===e?.5:e,r=2*a-1,o=n.alpha()-i.alpha(),s=((r*o===-1?r:(r+o)/(1+r*o))+1)/2,l=1-s;return this.rgb(s*n.red()+l*i.red(),s*n.green()+l*i.green(),s*n.blue()+l*i.blue()).alpha(n.alpha()*a+i.alpha()*(1-a))},toJSON:function(){return this.rgb()},clone:function(){var t,e,n=new r,i=this.values,a=n.values;for(var o in i)i.hasOwnProperty(o)&&(t=i[o],e={}.toString.call(t),"[object Array]"===e?a[o]=t.slice(0):"[object Number]"===e?a[o]=t:console.error("unexpected color value:",t));return n}},r.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},r.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},r.prototype.getValues=function(t){for(var e=this.values,n={},i=0;i<t.length;i++)n[t.charAt(i)]=e[t][i];return 1!==e.alpha&&(n.a=e.alpha),n},r.prototype.setValues=function(t,e){var n,a=this.values,r=this.spaces,o=this.maxes,s=1;if(this.valid=!0,"alpha"===t)s=e;else if(e.length)a[t]=e.slice(0,t.length),s=e[t.length];else if(void 0!==e[t.charAt(0)]){for(n=0;n<t.length;n++)a[t][n]=e[t.charAt(n)];s=e.a}else if(void 0!==e[r[t][0]]){var l=r[t];for(n=0;n<t.length;n++)a[t][n]=e[l[n]];s=e.alpha}if(a.alpha=Math.max(0,Math.min(1,void 0===s?a.alpha:s)),"alpha"===t)return!1;var u;for(n=0;n<t.length;n++)u=Math.max(0,Math.min(o[t][n],a[t][n])),a[t][n]=Math.round(u);for(var d in r)d!==t&&(a[d]=i[t][d](a[t]));return!0},r.prototype.setSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n),this)},r.prototype.setChannel=function(t,e,n){var i=this.values[t];return void 0===n?i[e]:n===i[e]?this:(i[e]=n,this.setValues(t,i),this)},"undefined"!=typeof window&&(window.Color=r),e.exports=r},{1:1,4:4}],3:[function(t,e,n){function i(t){var e,n,i,a=t[0]/255,r=t[1]/255,o=t[2]/255,s=Math.min(a,r,o),l=Math.max(a,r,o),u=l-s;return l==s?e=0:a==l?e=(r-o)/u:r==l?e=2+(o-a)/u:o==l&&(e=4+(a-r)/u),e=Math.min(60*e,360),e<0&&(e+=360),i=(s+l)/2,n=l==s?0:i<=.5?u/(l+s):u/(2-l-s),[e,100*n,100*i]}function a(t){var e,n,i,a=t[0],r=t[1],o=t[2],s=Math.min(a,r,o),l=Math.max(a,r,o),u=l-s;return n=0==l?0:u/l*1e3/10,l==s?e=0:a==l?e=(r-o)/u:r==l?e=2+(o-a)/u:o==l&&(e=4+(a-r)/u),e=Math.min(60*e,360),e<0&&(e+=360),i=l/255*1e3/10,[e,n,i]}function o(t){var e=t[0],n=t[1],a=t[2],r=i(t)[0],o=1/255*Math.min(e,Math.min(n,a)),a=1-1/255*Math.max(e,Math.max(n,a));return[r,100*o,100*a]}function s(t){var e,n,i,a,r=t[0]/255,o=t[1]/255,s=t[2]/255;return a=Math.min(1-r,1-o,1-s),e=(1-r-a)/(1-a)||0,n=(1-o-a)/(1-a)||0,i=(1-s-a)/(1-a)||0,[100*e,100*n,100*i,100*a]}function l(t){return K[JSON.stringify(t)]}function u(t){var e=t[0]/255,n=t[1]/255,i=t[2]/255;e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92,n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92,i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92;var a=.4124*e+.3576*n+.1805*i,r=.2126*e+.7152*n+.0722*i,o=.0193*e+.1192*n+.9505*i;return[100*a,100*r,100*o]}function d(t){var e,n,i,a=u(t),r=a[0],o=a[1],s=a[2];return r/=95.047,o/=100,s/=108.883,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116,e=116*o-16,n=500*(r-o),i=200*(o-s),[e,n,i]}function c(t){return Y(d(t))}function h(t){var e,n,i,a,r,o=t[0]/360,s=t[1]/100,l=t[2]/100;if(0==s)return r=255*l,[r,r,r];n=l<.5?l*(1+s):l+s-l*s,e=2*l-n,a=[0,0,0];for(var u=0;u<3;u++)i=o+1/3*-(u-1),i<0&&i++,i>1&&i--,r=6*i<1?e+6*(n-e)*i:2*i<1?n:3*i<2?e+(n-e)*(2/3-i)*6:e,a[u]=255*r;return a}function f(t){var e,n,i=t[0],a=t[1]/100,r=t[2]/100;return 0===r?[0,0,0]:(r*=2,a*=r<=1?r:2-r,n=(r+a)/2,e=2*a/(r+a),[i,100*e,100*n])}function p(t){return o(h(t))}function m(t){return s(h(t))}function v(t){return l(h(t))}function y(t){var e=t[0]/60,n=t[1]/100,i=t[2]/100,a=Math.floor(e)%6,r=e-Math.floor(e),o=255*i*(1-n),s=255*i*(1-n*r),l=255*i*(1-n*(1-r)),i=255*i;switch(a){case 0:return[i,l,o];case 1:return[s,i,o];case 2:return[o,i,l];case 3:return[o,s,i];case 4:return[l,o,i];case 5:return[i,o,s]}}function x(t){var e,n,i=t[0],a=t[1]/100,r=t[2]/100;return n=(2-a)*r,e=a*r,e/=n<=1?n:2-n,e=e||0,n/=2,[i,100*e,100*n]}function _(t){return o(y(t))}function k(t){return s(y(t))}function w(t){return l(y(t))}function M(t){var e,n,i,a,o=t[0]/360,s=t[1]/100,l=t[2]/100,u=s+l;switch(u>1&&(s/=u,l/=u),e=Math.floor(6*o),n=1-l,i=6*o-e,0!=(1&e)&&(i=1-i),a=s+i*(n-s),e){default:case 6:case 0:r=n,g=a,b=s;break;case 1:r=a,g=n,b=s;break;case 2:r=s,g=n,b=a;break;case 3:r=s,g=a,b=n;break;case 4:r=a,g=s,b=n;break;case 5:r=n,g=s,b=a}return[255*r,255*g,255*b]}function S(t){return i(M(t))}function D(t){return a(M(t))}function C(t){return s(M(t))}function P(t){return l(M(t))}function T(t){var e,n,i,a=t[0]/100,r=t[1]/100,o=t[2]/100,s=t[3]/100;return e=1-Math.min(1,a*(1-s)+s),n=1-Math.min(1,r*(1-s)+s),i=1-Math.min(1,o*(1-s)+s),[255*e,255*n,255*i]}function I(t){return i(T(t))}function A(t){return a(T(t))}function F(t){return o(T(t))}function O(t){return l(T(t))}function R(t){var e,n,i,a=t[0]/100,r=t[1]/100,o=t[2]/100;return e=3.2406*a+r*-1.5372+o*-.4986,n=a*-.9689+1.8758*r+.0415*o,i=.0557*a+r*-.204+1.057*o,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:e*=12.92,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n*=12.92,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i*=12.92,e=Math.min(Math.max(0,e),1),n=Math.min(Math.max(0,n),1),i=Math.min(Math.max(0,i),1),[255*e,255*n,255*i]}function L(t){var e,n,i,a=t[0],r=t[1],o=t[2];return a/=95.047,r/=100,o/=108.883,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,e=116*r-16,n=500*(a-r),i=200*(r-o),[e,n,i]}function V(t){return Y(L(t))}function W(t){var e,n,i,a,r=t[0],o=t[1],s=t[2];return r<=8?(n=100*r/903.3,a=7.787*(n/100)+16/116):(n=100*Math.pow((r+16)/116,3),a=Math.pow(n/100,1/3)),e=e/95.047<=.008856?e=95.047*(o/500+a-16/116)/7.787:95.047*Math.pow(o/500+a,3),i=i/108.883<=.008859?i=108.883*(a-s/200-16/116)/7.787:108.883*Math.pow(a-s/200,3),[e,n,i]}function Y(t){var e,n,i,a=t[0],r=t[1],o=t[2];return e=Math.atan2(o,r),n=360*e/2/Math.PI,n<0&&(n+=360),i=Math.sqrt(r*r+o*o),[a,i,n]}function z(t){return R(W(t))}function N(t){var e,n,i,a=t[0],r=t[1],o=t[2];return i=o/360*2*Math.PI,e=r*Math.cos(i),n=r*Math.sin(i),[a,e,n]}function B(t){return W(N(t))}function E(t){return z(N(t))}function H(t){return J[t]}function j(t){return i(H(t))}function U(t){return a(H(t))}function G(t){return o(H(t))}function q(t){return s(H(t))}function Z(t){return d(H(t))}function X(t){return u(H(t))}e.exports={rgb2hsl:i,rgb2hsv:a,rgb2hwb:o,rgb2cmyk:s,rgb2keyword:l,rgb2xyz:u,rgb2lab:d,rgb2lch:c,hsl2rgb:h,hsl2hsv:f,hsl2hwb:p,hsl2cmyk:m,hsl2keyword:v,hsv2rgb:y,hsv2hsl:x,hsv2hwb:_,hsv2cmyk:k,hsv2keyword:w,hwb2rgb:M,hwb2hsl:S,hwb2hsv:D,hwb2cmyk:C,hwb2keyword:P,cmyk2rgb:T,cmyk2hsl:I,cmyk2hsv:A,cmyk2hwb:F,cmyk2keyword:O,keyword2rgb:H,keyword2hsl:j,keyword2hsv:U,keyword2hwb:G,keyword2cmyk:q,keyword2lab:Z,keyword2xyz:X,xyz2rgb:R,xyz2lab:L,xyz2lch:V,lab2xyz:W,lab2rgb:z,lab2lch:Y,lch2lab:N,lch2xyz:B,lch2rgb:E};var J={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},K={};for(var Q in J)K[JSON.stringify(J[Q])]=Q},{}],4:[function(t,e,n){var i=t(3),a=function(){return new u};for(var r in i){a[r+"Raw"]=function(t){return function(e){return"number"==typeof e&&(e=Array.prototype.slice.call(arguments)),i[t](e)}}(r);var o=/(\w+)2(\w+)/.exec(r),s=o[1],l=o[2];a[s]=a[s]||{},a[s][l]=a[r]=function(t){return function(e){"number"==typeof e&&(e=Array.prototype.slice.call(arguments));var n=i[t](e);if("string"==typeof n||void 0===n)return n;for(var a=0;a<n.length;a++)n[a]=Math.round(n[a]);return n}}(r)}var u=function(){this.convs={}};u.prototype.routeSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n))},u.prototype.setValues=function(t,e){return this.space=t,this.convs={},this.convs[t]=e,this},u.prototype.getValues=function(t){var e=this.convs[t];if(!e){var n=this.space,i=this.convs[n];e=a[n][t](i),this.convs[t]=e}return e},["rgb","hsl","hsv","cmyk","keyword"].forEach(function(t){u.prototype[t]=function(e){return this.routeSpace(t,arguments)}}),e.exports=a},{3:3}],5:[function(t,e,n){e.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},{}],6:[function(e,n,i){!function(e,a){"object"==typeof i&&"undefined"!=typeof n?n.exports=a():"function"==typeof t&&t.amd?t(a):e.moment=a()}(this,function(){"use strict";function t(){return _i.apply(null,arguments)}function i(t){_i=t}function a(t){return t instanceof Array||"[object Array]"===Object.prototype.toString.call(t)}function r(t){return null!=t&&"[object Object]"===Object.prototype.toString.call(t)}function o(t){var e;for(e in t)return!1;return!0}function s(t){return void 0===t}function l(t){return"number"==typeof t||"[object Number]"===Object.prototype.toString.call(t)}function u(t){return t instanceof Date||"[object Date]"===Object.prototype.toString.call(t)}function d(t,e){var n,i=[];for(n=0;n<t.length;++n)i.push(e(t[n],n));return i}function c(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function h(t,e){for(var n in e)c(e,n)&&(t[n]=e[n]);return c(e,"toString")&&(t.toString=e.toString),c(e,"valueOf")&&(t.valueOf=e.valueOf),t}function f(t,e,n,i){return xe(t,e,n,i,!0).utc()}function g(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],meridiem:null,rfc2822:!1,weekdayMismatch:!1}}function p(t){return null==t._pf&&(t._pf=g()),t._pf}function m(t){if(null==t._isValid){var e=p(t),n=wi.call(e.parsedDateParts,function(t){return null!=t}),i=!isNaN(t._d.getTime())&&e.overflow<0&&!e.empty&&!e.invalidMonth&&!e.invalidWeekday&&!e.nullInput&&!e.invalidFormat&&!e.userInvalidated&&(!e.meridiem||e.meridiem&&n);if(t._strict&&(i=i&&0===e.charsLeftOver&&0===e.unusedTokens.length&&void 0===e.bigHour),null!=Object.isFrozen&&Object.isFrozen(t))return i;t._isValid=i}return t._isValid}function v(t){var e=f(NaN);return null!=t?h(p(e),t):p(e).userInvalidated=!0,e}function y(t,e){var n,i,a;if(s(e._isAMomentObject)||(t._isAMomentObject=e._isAMomentObject),s(e._i)||(t._i=e._i),s(e._f)||(t._f=e._f),s(e._l)||(t._l=e._l),s(e._strict)||(t._strict=e._strict),s(e._tzm)||(t._tzm=e._tzm),s(e._isUTC)||(t._isUTC=e._isUTC),s(e._offset)||(t._offset=e._offset),s(e._pf)||(t._pf=p(e)),s(e._locale)||(t._locale=e._locale),Mi.length>0)for(n=0;n<Mi.length;n++)i=Mi[n],a=e[i],s(a)||(t[i]=a);return t}function b(e){y(this,e),this._d=new Date(null!=e._d?e._d.getTime():NaN),this.isValid()||(this._d=new Date(NaN)),Si===!1&&(Si=!0,t.updateOffset(this),Si=!1)}function x(t){return t instanceof b||null!=t&&null!=t._isAMomentObject}function _(t){return t<0?Math.ceil(t)||0:Math.floor(t)}function k(t){var e=+t,n=0;return 0!==e&&isFinite(e)&&(n=_(e)),n}function w(t,e,n){var i,a=Math.min(t.length,e.length),r=Math.abs(t.length-e.length),o=0;for(i=0;i<a;i++)(n&&t[i]!==e[i]||!n&&k(t[i])!==k(e[i]))&&o++;return o+r}function M(e){t.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+e)}function S(e,n){var i=!0;return h(function(){if(null!=t.deprecationHandler&&t.deprecationHandler(null,e),i){for(var a,r=[],o=0;o<arguments.length;o++){if(a="","object"==typeof arguments[o]){a+="\n["+o+"] ";for(var s in arguments[0])a+=s+": "+arguments[0][s]+", ";a=a.slice(0,-2)}else a=arguments[o];r.push(a)}M(e+"\nArguments: "+Array.prototype.slice.call(r).join("")+"\n"+(new Error).stack),i=!1}return n.apply(this,arguments)},n)}function D(e,n){null!=t.deprecationHandler&&t.deprecationHandler(e,n),Di[e]||(M(n),Di[e]=!0)}function C(t){return t instanceof Function||"[object Function]"===Object.prototype.toString.call(t)}function P(t){var e,n;for(n in t)e=t[n],C(e)?this[n]=e:this["_"+n]=e;this._config=t,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)}function T(t,e){var n,i=h({},t);for(n in e)c(e,n)&&(r(t[n])&&r(e[n])?(i[n]={},h(i[n],t[n]),h(i[n],e[n])):null!=e[n]?i[n]=e[n]:delete i[n]);for(n in t)c(t,n)&&!c(e,n)&&r(t[n])&&(i[n]=h({},i[n]));return i}function I(t){null!=t&&this.set(t)}function A(t,e,n){var i=this._calendar[t]||this._calendar.sameElse;return C(i)?i.call(e,n):i}function F(t){var e=this._longDateFormat[t],n=this._longDateFormat[t.toUpperCase()];return e||!n?e:(this._longDateFormat[t]=n.replace(/MMMM|MM|DD|dddd/g,function(t){return t.slice(1)}),this._longDateFormat[t])}function O(){return this._invalidDate}function R(t){return this._ordinal.replace("%d",t)}function L(t,e,n,i){var a=this._relativeTime[n];return C(a)?a(t,e,n,i):a.replace(/%d/i,t)}function V(t,e){var n=this._relativeTime[t>0?"future":"past"];return C(n)?n(e):n.replace(/%s/i,e)}function W(t,e){var n=t.toLowerCase();Vi[n]=Vi[n+"s"]=Vi[e]=t}function Y(t){return"string"==typeof t?Vi[t]||Vi[t.toLowerCase()]:void 0}function z(t){var e,n,i={};for(n in t)c(t,n)&&(e=Y(n),e&&(i[e]=t[n]));return i}function N(t,e){Wi[t]=e}function B(t){var e=[];for(var n in t)e.push({unit:n,priority:Wi[n]});return e.sort(function(t,e){return t.priority-e.priority}),e}function E(e,n){return function(i){return null!=i?(j(this,e,i),t.updateOffset(this,n),this):H(this,e)}}function H(t,e){return t.isValid()?t._d["get"+(t._isUTC?"UTC":"")+e]():NaN}function j(t,e,n){t.isValid()&&t._d["set"+(t._isUTC?"UTC":"")+e](n)}function U(t){return t=Y(t),C(this[t])?this[t]():this}function G(t,e){if("object"==typeof t){t=z(t);for(var n=B(t),i=0;i<n.length;i++)this[n[i].unit](t[n[i].unit])}else if(t=Y(t),C(this[t]))return this[t](e);return this}function q(t,e,n){var i=""+Math.abs(t),a=e-i.length,r=t>=0;return(r?n?"+":"":"-")+Math.pow(10,Math.max(0,a)).toString().substr(1)+i}function Z(t,e,n,i){var a=i;"string"==typeof i&&(a=function(){return this[i]()}),t&&(Bi[t]=a),e&&(Bi[e[0]]=function(){return q(a.apply(this,arguments),e[1],e[2])}),n&&(Bi[n]=function(){return this.localeData().ordinal(a.apply(this,arguments),t)})}function X(t){return t.match(/\[[\s\S]/)?t.replace(/^\[|\]$/g,""):t.replace(/\\/g,"")}function J(t){var e,n,i=t.match(Yi);for(e=0,n=i.length;e<n;e++)Bi[i[e]]?i[e]=Bi[i[e]]:i[e]=X(i[e]);return function(e){var a,r="";for(a=0;a<n;a++)r+=C(i[a])?i[a].call(e,t):i[a];return r}}function K(t,e){return t.isValid()?(e=Q(e,t.localeData()),Ni[e]=Ni[e]||J(e),Ni[e](t)):t.localeData().invalidDate()}function Q(t,e){function n(t){return e.longDateFormat(t)||t}var i=5;for(zi.lastIndex=0;i>=0&&zi.test(t);)t=t.replace(zi,n),zi.lastIndex=0,i-=1;return t}function $(t,e,n){ra[t]=C(e)?e:function(t,i){return t&&n?n:e}}function tt(t,e){return c(ra,t)?ra[t](e._strict,e._locale):new RegExp(et(t))}function et(t){return nt(t.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(t,e,n,i,a){return e||n||i||a}))}function nt(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function it(t,e){var n,i=e;for("string"==typeof t&&(t=[t]),l(e)&&(i=function(t,n){n[e]=k(t)}),n=0;n<t.length;n++)oa[t[n]]=i}function at(t,e){it(t,function(t,n,i,a){i._w=i._w||{},e(t,i._w,i,a)})}function rt(t,e,n){null!=e&&c(oa,t)&&oa[t](e,n._a,n,t)}function ot(t,e){return new Date(Date.UTC(t,e+1,0)).getUTCDate()}function st(t,e){return t?a(this._months)?this._months[t.month()]:this._months[(this._months.isFormat||va).test(e)?"format":"standalone"][t.month()]:a(this._months)?this._months:this._months.standalone}function lt(t,e){return t?a(this._monthsShort)?this._monthsShort[t.month()]:this._monthsShort[va.test(e)?"format":"standalone"][t.month()]:a(this._monthsShort)?this._monthsShort:this._monthsShort.standalone}function ut(t,e,n){var i,a,r,o=t.toLocaleLowerCase();if(!this._monthsParse)for(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[],i=0;i<12;++i)r=f([2e3,i]),this._shortMonthsParse[i]=this.monthsShort(r,"").toLocaleLowerCase(),this._longMonthsParse[i]=this.months(r,"").toLocaleLowerCase();return n?"MMM"===e?(a=ma.call(this._shortMonthsParse,o),a!==-1?a:null):(a=ma.call(this._longMonthsParse,o),a!==-1?a:null):"MMM"===e?(a=ma.call(this._shortMonthsParse,o),a!==-1?a:(a=ma.call(this._longMonthsParse,o),a!==-1?a:null)):(a=ma.call(this._longMonthsParse,o),a!==-1?a:(a=ma.call(this._shortMonthsParse,o),a!==-1?a:null))}function dt(t,e,n){var i,a,r;if(this._monthsParseExact)return ut.call(this,t,e,n);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),i=0;i<12;i++){if(a=f([2e3,i]),n&&!this._longMonthsParse[i]&&(this._longMonthsParse[i]=new RegExp("^"+this.months(a,"").replace(".","")+"$","i"),this._shortMonthsParse[i]=new RegExp("^"+this.monthsShort(a,"").replace(".","")+"$","i")),n||this._monthsParse[i]||(r="^"+this.months(a,"")+"|^"+this.monthsShort(a,""),this._monthsParse[i]=new RegExp(r.replace(".",""),"i")),n&&"MMMM"===e&&this._longMonthsParse[i].test(t))return i;if(n&&"MMM"===e&&this._shortMonthsParse[i].test(t))return i;if(!n&&this._monthsParse[i].test(t))return i}}function ct(t,e){var n;if(!t.isValid())return t;if("string"==typeof e)if(/^\d+$/.test(e))e=k(e);else if(e=t.localeData().monthsParse(e),
11
- !l(e))return t;return n=Math.min(t.date(),ot(t.year(),e)),t._d["set"+(t._isUTC?"UTC":"")+"Month"](e,n),t}function ht(e){return null!=e?(ct(this,e),t.updateOffset(this,!0),this):H(this,"Month")}function ft(){return ot(this.year(),this.month())}function gt(t){return this._monthsParseExact?(c(this,"_monthsRegex")||mt.call(this),t?this._monthsShortStrictRegex:this._monthsShortRegex):(c(this,"_monthsShortRegex")||(this._monthsShortRegex=xa),this._monthsShortStrictRegex&&t?this._monthsShortStrictRegex:this._monthsShortRegex)}function pt(t){return this._monthsParseExact?(c(this,"_monthsRegex")||mt.call(this),t?this._monthsStrictRegex:this._monthsRegex):(c(this,"_monthsRegex")||(this._monthsRegex=_a),this._monthsStrictRegex&&t?this._monthsStrictRegex:this._monthsRegex)}function mt(){function t(t,e){return e.length-t.length}var e,n,i=[],a=[],r=[];for(e=0;e<12;e++)n=f([2e3,e]),i.push(this.monthsShort(n,"")),a.push(this.months(n,"")),r.push(this.months(n,"")),r.push(this.monthsShort(n,""));for(i.sort(t),a.sort(t),r.sort(t),e=0;e<12;e++)i[e]=nt(i[e]),a[e]=nt(a[e]);for(e=0;e<24;e++)r[e]=nt(r[e]);this._monthsRegex=new RegExp("^("+r.join("|")+")","i"),this._monthsShortRegex=this._monthsRegex,this._monthsStrictRegex=new RegExp("^("+a.join("|")+")","i"),this._monthsShortStrictRegex=new RegExp("^("+i.join("|")+")","i")}function vt(t){return yt(t)?366:365}function yt(t){return t%4===0&&t%100!==0||t%400===0}function bt(){return yt(this.year())}function xt(t,e,n,i,a,r,o){var s=new Date(t,e,n,i,a,r,o);return t<100&&t>=0&&isFinite(s.getFullYear())&&s.setFullYear(t),s}function _t(t){var e=new Date(Date.UTC.apply(null,arguments));return t<100&&t>=0&&isFinite(e.getUTCFullYear())&&e.setUTCFullYear(t),e}function kt(t,e,n){var i=7+e-n,a=(7+_t(t,0,i).getUTCDay()-e)%7;return-a+i-1}function wt(t,e,n,i,a){var r,o,s=(7+n-i)%7,l=kt(t,i,a),u=1+7*(e-1)+s+l;return u<=0?(r=t-1,o=vt(r)+u):u>vt(t)?(r=t+1,o=u-vt(t)):(r=t,o=u),{year:r,dayOfYear:o}}function Mt(t,e,n){var i,a,r=kt(t.year(),e,n),o=Math.floor((t.dayOfYear()-r-1)/7)+1;return o<1?(a=t.year()-1,i=o+St(a,e,n)):o>St(t.year(),e,n)?(i=o-St(t.year(),e,n),a=t.year()+1):(a=t.year(),i=o),{week:i,year:a}}function St(t,e,n){var i=kt(t,e,n),a=kt(t+1,e,n);return(vt(t)-i+a)/7}function Dt(t){return Mt(t,this._week.dow,this._week.doy).week}function Ct(){return this._week.dow}function Pt(){return this._week.doy}function Tt(t){var e=this.localeData().week(this);return null==t?e:this.add(7*(t-e),"d")}function It(t){var e=Mt(this,1,4).week;return null==t?e:this.add(7*(t-e),"d")}function At(t,e){return"string"!=typeof t?t:isNaN(t)?(t=e.weekdaysParse(t),"number"==typeof t?t:null):parseInt(t,10)}function Ft(t,e){return"string"==typeof t?e.weekdaysParse(t)%7||7:isNaN(t)?null:t}function Ot(t,e){return t?a(this._weekdays)?this._weekdays[t.day()]:this._weekdays[this._weekdays.isFormat.test(e)?"format":"standalone"][t.day()]:a(this._weekdays)?this._weekdays:this._weekdays.standalone}function Rt(t){return t?this._weekdaysShort[t.day()]:this._weekdaysShort}function Lt(t){return t?this._weekdaysMin[t.day()]:this._weekdaysMin}function Vt(t,e,n){var i,a,r,o=t.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],i=0;i<7;++i)r=f([2e3,1]).day(i),this._minWeekdaysParse[i]=this.weekdaysMin(r,"").toLocaleLowerCase(),this._shortWeekdaysParse[i]=this.weekdaysShort(r,"").toLocaleLowerCase(),this._weekdaysParse[i]=this.weekdays(r,"").toLocaleLowerCase();return n?"dddd"===e?(a=ma.call(this._weekdaysParse,o),a!==-1?a:null):"ddd"===e?(a=ma.call(this._shortWeekdaysParse,o),a!==-1?a:null):(a=ma.call(this._minWeekdaysParse,o),a!==-1?a:null):"dddd"===e?(a=ma.call(this._weekdaysParse,o),a!==-1?a:(a=ma.call(this._shortWeekdaysParse,o),a!==-1?a:(a=ma.call(this._minWeekdaysParse,o),a!==-1?a:null))):"ddd"===e?(a=ma.call(this._shortWeekdaysParse,o),a!==-1?a:(a=ma.call(this._weekdaysParse,o),a!==-1?a:(a=ma.call(this._minWeekdaysParse,o),a!==-1?a:null))):(a=ma.call(this._minWeekdaysParse,o),a!==-1?a:(a=ma.call(this._weekdaysParse,o),a!==-1?a:(a=ma.call(this._shortWeekdaysParse,o),a!==-1?a:null)))}function Wt(t,e,n){var i,a,r;if(this._weekdaysParseExact)return Vt.call(this,t,e,n);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),i=0;i<7;i++){if(a=f([2e3,1]).day(i),n&&!this._fullWeekdaysParse[i]&&(this._fullWeekdaysParse[i]=new RegExp("^"+this.weekdays(a,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[i]=new RegExp("^"+this.weekdaysShort(a,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[i]=new RegExp("^"+this.weekdaysMin(a,"").replace(".",".?")+"$","i")),this._weekdaysParse[i]||(r="^"+this.weekdays(a,"")+"|^"+this.weekdaysShort(a,"")+"|^"+this.weekdaysMin(a,""),this._weekdaysParse[i]=new RegExp(r.replace(".",""),"i")),n&&"dddd"===e&&this._fullWeekdaysParse[i].test(t))return i;if(n&&"ddd"===e&&this._shortWeekdaysParse[i].test(t))return i;if(n&&"dd"===e&&this._minWeekdaysParse[i].test(t))return i;if(!n&&this._weekdaysParse[i].test(t))return i}}function Yt(t){if(!this.isValid())return null!=t?this:NaN;var e=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=t?(t=At(t,this.localeData()),this.add(t-e,"d")):e}function zt(t){if(!this.isValid())return null!=t?this:NaN;var e=(this.day()+7-this.localeData()._week.dow)%7;return null==t?e:this.add(t-e,"d")}function Nt(t){if(!this.isValid())return null!=t?this:NaN;if(null!=t){var e=Ft(t,this.localeData());return this.day(this.day()%7?e:e-7)}return this.day()||7}function Bt(t){return this._weekdaysParseExact?(c(this,"_weekdaysRegex")||jt.call(this),t?this._weekdaysStrictRegex:this._weekdaysRegex):(c(this,"_weekdaysRegex")||(this._weekdaysRegex=Ca),this._weekdaysStrictRegex&&t?this._weekdaysStrictRegex:this._weekdaysRegex)}function Et(t){return this._weekdaysParseExact?(c(this,"_weekdaysRegex")||jt.call(this),t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(c(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Pa),this._weekdaysShortStrictRegex&&t?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)}function Ht(t){return this._weekdaysParseExact?(c(this,"_weekdaysRegex")||jt.call(this),t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(c(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Ta),this._weekdaysMinStrictRegex&&t?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)}function jt(){function t(t,e){return e.length-t.length}var e,n,i,a,r,o=[],s=[],l=[],u=[];for(e=0;e<7;e++)n=f([2e3,1]).day(e),i=this.weekdaysMin(n,""),a=this.weekdaysShort(n,""),r=this.weekdays(n,""),o.push(i),s.push(a),l.push(r),u.push(i),u.push(a),u.push(r);for(o.sort(t),s.sort(t),l.sort(t),u.sort(t),e=0;e<7;e++)s[e]=nt(s[e]),l[e]=nt(l[e]),u[e]=nt(u[e]);this._weekdaysRegex=new RegExp("^("+u.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+s.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+o.join("|")+")","i")}function Ut(){return this.hours()%12||12}function Gt(){return this.hours()||24}function qt(t,e){Z(t,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),e)})}function Zt(t,e){return e._meridiemParse}function Xt(t){return"p"===(t+"").toLowerCase().charAt(0)}function Jt(t,e,n){return t>11?n?"pm":"PM":n?"am":"AM"}function Kt(t){return t?t.toLowerCase().replace("_","-"):t}function Qt(t){for(var e,n,i,a,r=0;r<t.length;){for(a=Kt(t[r]).split("-"),e=a.length,n=Kt(t[r+1]),n=n?n.split("-"):null;e>0;){if(i=$t(a.slice(0,e).join("-")))return i;if(n&&n.length>=e&&w(a,n,!0)>=e-1)break;e--}r++}return null}function $t(t){var i=null;if(!Ra[t]&&"undefined"!=typeof n&&n&&n.exports)try{i=Ia._abbr,e("./locale/"+t),te(i)}catch(t){}return Ra[t]}function te(t,e){var n;return t&&(n=s(e)?ie(t):ee(t,e),n&&(Ia=n)),Ia._abbr}function ee(t,e){if(null!==e){var n=Oa;if(e.abbr=t,null!=Ra[t])D("defineLocaleOverride","use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale See http://momentjs.com/guides/#/warnings/define-locale/ for more info."),n=Ra[t]._config;else if(null!=e.parentLocale){if(null==Ra[e.parentLocale])return La[e.parentLocale]||(La[e.parentLocale]=[]),La[e.parentLocale].push({name:t,config:e}),null;n=Ra[e.parentLocale]._config}return Ra[t]=new I(T(n,e)),La[t]&&La[t].forEach(function(t){ee(t.name,t.config)}),te(t),Ra[t]}return delete Ra[t],null}function ne(t,e){if(null!=e){var n,i=Oa;null!=Ra[t]&&(i=Ra[t]._config),e=T(i,e),n=new I(e),n.parentLocale=Ra[t],Ra[t]=n,te(t)}else null!=Ra[t]&&(null!=Ra[t].parentLocale?Ra[t]=Ra[t].parentLocale:null!=Ra[t]&&delete Ra[t]);return Ra[t]}function ie(t){var e;if(t&&t._locale&&t._locale._abbr&&(t=t._locale._abbr),!t)return Ia;if(!a(t)){if(e=$t(t))return e;t=[t]}return Qt(t)}function ae(){return Ti(Ra)}function re(t){var e,n=t._a;return n&&p(t).overflow===-2&&(e=n[la]<0||n[la]>11?la:n[ua]<1||n[ua]>ot(n[sa],n[la])?ua:n[da]<0||n[da]>24||24===n[da]&&(0!==n[ca]||0!==n[ha]||0!==n[fa])?da:n[ca]<0||n[ca]>59?ca:n[ha]<0||n[ha]>59?ha:n[fa]<0||n[fa]>999?fa:-1,p(t)._overflowDayOfYear&&(e<sa||e>ua)&&(e=ua),p(t)._overflowWeeks&&e===-1&&(e=ga),p(t)._overflowWeekday&&e===-1&&(e=pa),p(t).overflow=e),t}function oe(t){var e,n,i,a,r,o,s=t._i,l=Va.exec(s)||Wa.exec(s);if(l){for(p(t).iso=!0,e=0,n=za.length;e<n;e++)if(za[e][1].exec(l[1])){a=za[e][0],i=za[e][2]!==!1;break}if(null==a)return void(t._isValid=!1);if(l[3]){for(e=0,n=Na.length;e<n;e++)if(Na[e][1].exec(l[3])){r=(l[2]||" ")+Na[e][0];break}if(null==r)return void(t._isValid=!1)}if(!i&&null!=r)return void(t._isValid=!1);if(l[4]){if(!Ya.exec(l[4]))return void(t._isValid=!1);o="Z"}t._f=a+(r||"")+(o||""),fe(t)}else t._isValid=!1}function se(t){var e,n,i,a,r,o,s,l,u={" GMT":" +0000"," EDT":" -0400"," EST":" -0500"," CDT":" -0500"," CST":" -0600"," MDT":" -0600"," MST":" -0700"," PDT":" -0700"," PST":" -0800"},d="YXWVUTSRQPONZABCDEFGHIKLM";if(e=t._i.replace(/\([^\)]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").replace(/^\s|\s$/g,""),n=Ea.exec(e)){if(i=n[1]?"ddd"+(5===n[1].length?", ":" "):"",a="D MMM "+(n[2].length>10?"YYYY ":"YY "),r="HH:mm"+(n[4]?":ss":""),n[1]){var c=new Date(n[2]),h=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][c.getDay()];if(n[1].substr(0,3)!==h)return p(t).weekdayMismatch=!0,void(t._isValid=!1)}switch(n[5].length){case 2:0===l?s=" +0000":(l=d.indexOf(n[5][1].toUpperCase())-12,s=(l<0?" -":" +")+(""+l).replace(/^-?/,"0").match(/..$/)[0]+"00");break;case 4:s=u[n[5]];break;default:s=u[" GMT"]}n[5]=s,t._i=n.splice(1).join(""),o=" ZZ",t._f=i+a+r+o,fe(t),p(t).rfc2822=!0}else t._isValid=!1}function le(e){var n=Ba.exec(e._i);return null!==n?void(e._d=new Date(+n[1])):(oe(e),void(e._isValid===!1&&(delete e._isValid,se(e),e._isValid===!1&&(delete e._isValid,t.createFromInputFallback(e)))))}function ue(t,e,n){return null!=t?t:null!=e?e:n}function de(e){var n=new Date(t.now());return e._useUTC?[n.getUTCFullYear(),n.getUTCMonth(),n.getUTCDate()]:[n.getFullYear(),n.getMonth(),n.getDate()]}function ce(t){var e,n,i,a,r=[];if(!t._d){for(i=de(t),t._w&&null==t._a[ua]&&null==t._a[la]&&he(t),null!=t._dayOfYear&&(a=ue(t._a[sa],i[sa]),(t._dayOfYear>vt(a)||0===t._dayOfYear)&&(p(t)._overflowDayOfYear=!0),n=_t(a,0,t._dayOfYear),t._a[la]=n.getUTCMonth(),t._a[ua]=n.getUTCDate()),e=0;e<3&&null==t._a[e];++e)t._a[e]=r[e]=i[e];for(;e<7;e++)t._a[e]=r[e]=null==t._a[e]?2===e?1:0:t._a[e];24===t._a[da]&&0===t._a[ca]&&0===t._a[ha]&&0===t._a[fa]&&(t._nextDay=!0,t._a[da]=0),t._d=(t._useUTC?_t:xt).apply(null,r),null!=t._tzm&&t._d.setUTCMinutes(t._d.getUTCMinutes()-t._tzm),t._nextDay&&(t._a[da]=24)}}function he(t){var e,n,i,a,r,o,s,l;if(e=t._w,null!=e.GG||null!=e.W||null!=e.E)r=1,o=4,n=ue(e.GG,t._a[sa],Mt(_e(),1,4).year),i=ue(e.W,1),a=ue(e.E,1),(a<1||a>7)&&(l=!0);else{r=t._locale._week.dow,o=t._locale._week.doy;var u=Mt(_e(),r,o);n=ue(e.gg,t._a[sa],u.year),i=ue(e.w,u.week),null!=e.d?(a=e.d,(a<0||a>6)&&(l=!0)):null!=e.e?(a=e.e+r,(e.e<0||e.e>6)&&(l=!0)):a=r}i<1||i>St(n,r,o)?p(t)._overflowWeeks=!0:null!=l?p(t)._overflowWeekday=!0:(s=wt(n,i,a,r,o),t._a[sa]=s.year,t._dayOfYear=s.dayOfYear)}function fe(e){if(e._f===t.ISO_8601)return void oe(e);if(e._f===t.RFC_2822)return void se(e);e._a=[],p(e).empty=!0;var n,i,a,r,o,s=""+e._i,l=s.length,u=0;for(a=Q(e._f,e._locale).match(Yi)||[],n=0;n<a.length;n++)r=a[n],i=(s.match(tt(r,e))||[])[0],i&&(o=s.substr(0,s.indexOf(i)),o.length>0&&p(e).unusedInput.push(o),s=s.slice(s.indexOf(i)+i.length),u+=i.length),Bi[r]?(i?p(e).empty=!1:p(e).unusedTokens.push(r),rt(r,i,e)):e._strict&&!i&&p(e).unusedTokens.push(r);p(e).charsLeftOver=l-u,s.length>0&&p(e).unusedInput.push(s),e._a[da]<=12&&p(e).bigHour===!0&&e._a[da]>0&&(p(e).bigHour=void 0),p(e).parsedDateParts=e._a.slice(0),p(e).meridiem=e._meridiem,e._a[da]=ge(e._locale,e._a[da],e._meridiem),ce(e),re(e)}function ge(t,e,n){var i;return null==n?e:null!=t.meridiemHour?t.meridiemHour(e,n):null!=t.isPM?(i=t.isPM(n),i&&e<12&&(e+=12),i||12!==e||(e=0),e):e}function pe(t){var e,n,i,a,r;if(0===t._f.length)return p(t).invalidFormat=!0,void(t._d=new Date(NaN));for(a=0;a<t._f.length;a++)r=0,e=y({},t),null!=t._useUTC&&(e._useUTC=t._useUTC),e._f=t._f[a],fe(e),m(e)&&(r+=p(e).charsLeftOver,r+=10*p(e).unusedTokens.length,p(e).score=r,(null==i||r<i)&&(i=r,n=e));h(t,n||e)}function me(t){if(!t._d){var e=z(t._i);t._a=d([e.year,e.month,e.day||e.date,e.hour,e.minute,e.second,e.millisecond],function(t){return t&&parseInt(t,10)}),ce(t)}}function ve(t){var e=new b(re(ye(t)));return e._nextDay&&(e.add(1,"d"),e._nextDay=void 0),e}function ye(t){var e=t._i,n=t._f;return t._locale=t._locale||ie(t._l),null===e||void 0===n&&""===e?v({nullInput:!0}):("string"==typeof e&&(t._i=e=t._locale.preparse(e)),x(e)?new b(re(e)):(u(e)?t._d=e:a(n)?pe(t):n?fe(t):be(t),m(t)||(t._d=null),t))}function be(e){var n=e._i;s(n)?e._d=new Date(t.now()):u(n)?e._d=new Date(n.valueOf()):"string"==typeof n?le(e):a(n)?(e._a=d(n.slice(0),function(t){return parseInt(t,10)}),ce(e)):r(n)?me(e):l(n)?e._d=new Date(n):t.createFromInputFallback(e)}function xe(t,e,n,i,s){var l={};return n!==!0&&n!==!1||(i=n,n=void 0),(r(t)&&o(t)||a(t)&&0===t.length)&&(t=void 0),l._isAMomentObject=!0,l._useUTC=l._isUTC=s,l._l=n,l._i=t,l._f=e,l._strict=i,ve(l)}function _e(t,e,n,i){return xe(t,e,n,i,!1)}function ke(t,e){var n,i;if(1===e.length&&a(e[0])&&(e=e[0]),!e.length)return _e();for(n=e[0],i=1;i<e.length;++i)e[i].isValid()&&!e[i][t](n)||(n=e[i]);return n}function we(){var t=[].slice.call(arguments,0);return ke("isBefore",t)}function Me(){var t=[].slice.call(arguments,0);return ke("isAfter",t)}function Se(t){for(var e in t)if(Ga.indexOf(e)===-1||null!=t[e]&&isNaN(t[e]))return!1;for(var n=!1,i=0;i<Ga.length;++i)if(t[Ga[i]]){if(n)return!1;parseFloat(t[Ga[i]])!==k(t[Ga[i]])&&(n=!0)}return!0}function De(){return this._isValid}function Ce(){return Ge(NaN)}function Pe(t){var e=z(t),n=e.year||0,i=e.quarter||0,a=e.month||0,r=e.week||0,o=e.day||0,s=e.hour||0,l=e.minute||0,u=e.second||0,d=e.millisecond||0;this._isValid=Se(e),this._milliseconds=+d+1e3*u+6e4*l+1e3*s*60*60,this._days=+o+7*r,this._months=+a+3*i+12*n,this._data={},this._locale=ie(),this._bubble()}function Te(t){return t instanceof Pe}function Ie(t){return t<0?Math.round(-1*t)*-1:Math.round(t)}function Ae(t,e){Z(t,0,0,function(){var t=this.utcOffset(),n="+";return t<0&&(t=-t,n="-"),n+q(~~(t/60),2)+e+q(~~t%60,2)})}function Fe(t,e){var n=(e||"").match(t);if(null===n)return null;var i=n[n.length-1]||[],a=(i+"").match(qa)||["-",0,0],r=+(60*a[1])+k(a[2]);return 0===r?0:"+"===a[0]?r:-r}function Oe(e,n){var i,a;return n._isUTC?(i=n.clone(),a=(x(e)||u(e)?e.valueOf():_e(e).valueOf())-i.valueOf(),i._d.setTime(i._d.valueOf()+a),t.updateOffset(i,!1),i):_e(e).local()}function Re(t){return 15*-Math.round(t._d.getTimezoneOffset()/15)}function Le(e,n,i){var a,r=this._offset||0;if(!this.isValid())return null!=e?this:NaN;if(null!=e){if("string"==typeof e){if(e=Fe(na,e),null===e)return this}else Math.abs(e)<16&&!i&&(e*=60);return!this._isUTC&&n&&(a=Re(this)),this._offset=e,this._isUTC=!0,null!=a&&this.add(a,"m"),r!==e&&(!n||this._changeInProgress?Ke(this,Ge(e-r,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,t.updateOffset(this,!0),this._changeInProgress=null)),this}return this._isUTC?r:Re(this)}function Ve(t,e){return null!=t?("string"!=typeof t&&(t=-t),this.utcOffset(t,e),this):-this.utcOffset()}function We(t){return this.utcOffset(0,t)}function Ye(t){return this._isUTC&&(this.utcOffset(0,t),this._isUTC=!1,t&&this.subtract(Re(this),"m")),this}function ze(){if(null!=this._tzm)this.utcOffset(this._tzm,!1,!0);else if("string"==typeof this._i){var t=Fe(ea,this._i);null!=t?this.utcOffset(t):this.utcOffset(0,!0)}return this}function Ne(t){return!!this.isValid()&&(t=t?_e(t).utcOffset():0,(this.utcOffset()-t)%60===0)}function Be(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ee(){if(!s(this._isDSTShifted))return this._isDSTShifted;var t={};if(y(t,this),t=ye(t),t._a){var e=t._isUTC?f(t._a):_e(t._a);this._isDSTShifted=this.isValid()&&w(t._a,e.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function He(){return!!this.isValid()&&!this._isUTC}function je(){return!!this.isValid()&&this._isUTC}function Ue(){return!!this.isValid()&&(this._isUTC&&0===this._offset)}function Ge(t,e){var n,i,a,r=t,o=null;return Te(t)?r={ms:t._milliseconds,d:t._days,M:t._months}:l(t)?(r={},e?r[e]=t:r.milliseconds=t):(o=Za.exec(t))?(n="-"===o[1]?-1:1,r={y:0,d:k(o[ua])*n,h:k(o[da])*n,m:k(o[ca])*n,s:k(o[ha])*n,ms:k(Ie(1e3*o[fa]))*n}):(o=Xa.exec(t))?(n="-"===o[1]?-1:1,r={y:qe(o[2],n),M:qe(o[3],n),w:qe(o[4],n),d:qe(o[5],n),h:qe(o[6],n),m:qe(o[7],n),s:qe(o[8],n)}):null==r?r={}:"object"==typeof r&&("from"in r||"to"in r)&&(a=Xe(_e(r.from),_e(r.to)),r={},r.ms=a.milliseconds,r.M=a.months),i=new Pe(r),Te(t)&&c(t,"_locale")&&(i._locale=t._locale),i}function qe(t,e){var n=t&&parseFloat(t.replace(",","."));return(isNaN(n)?0:n)*e}function Ze(t,e){var n={milliseconds:0,months:0};return n.months=e.month()-t.month()+12*(e.year()-t.year()),t.clone().add(n.months,"M").isAfter(e)&&--n.months,n.milliseconds=+e-+t.clone().add(n.months,"M"),n}function Xe(t,e){var n;return t.isValid()&&e.isValid()?(e=Oe(e,t),t.isBefore(e)?n=Ze(t,e):(n=Ze(e,t),n.milliseconds=-n.milliseconds,n.months=-n.months),n):{milliseconds:0,months:0}}function Je(t,e){return function(n,i){var a,r;return null===i||isNaN(+i)||(D(e,"moment()."+e+"(period, number) is deprecated. Please use moment()."+e+"(number, period). See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info."),r=n,n=i,i=r),n="string"==typeof n?+n:n,a=Ge(n,i),Ke(this,a,t),this}}function Ke(e,n,i,a){var r=n._milliseconds,o=Ie(n._days),s=Ie(n._months);e.isValid()&&(a=null==a||a,r&&e._d.setTime(e._d.valueOf()+r*i),o&&j(e,"Date",H(e,"Date")+o*i),s&&ct(e,H(e,"Month")+s*i),a&&t.updateOffset(e,o||s))}function Qe(t,e){var n=t.diff(e,"days",!0);return n<-6?"sameElse":n<-1?"lastWeek":n<0?"lastDay":n<1?"sameDay":n<2?"nextDay":n<7?"nextWeek":"sameElse"}function $e(e,n){var i=e||_e(),a=Oe(i,this).startOf("day"),r=t.calendarFormat(this,a)||"sameElse",o=n&&(C(n[r])?n[r].call(this,i):n[r]);return this.format(o||this.localeData().calendar(r,this,_e(i)))}function tn(){return new b(this)}function en(t,e){var n=x(t)?t:_e(t);return!(!this.isValid()||!n.isValid())&&(e=Y(s(e)?"millisecond":e),"millisecond"===e?this.valueOf()>n.valueOf():n.valueOf()<this.clone().startOf(e).valueOf())}function nn(t,e){var n=x(t)?t:_e(t);return!(!this.isValid()||!n.isValid())&&(e=Y(s(e)?"millisecond":e),"millisecond"===e?this.valueOf()<n.valueOf():this.clone().endOf(e).valueOf()<n.valueOf())}function an(t,e,n,i){return i=i||"()",("("===i[0]?this.isAfter(t,n):!this.isBefore(t,n))&&(")"===i[1]?this.isBefore(e,n):!this.isAfter(e,n))}function rn(t,e){var n,i=x(t)?t:_e(t);return!(!this.isValid()||!i.isValid())&&(e=Y(e||"millisecond"),"millisecond"===e?this.valueOf()===i.valueOf():(n=i.valueOf(),this.clone().startOf(e).valueOf()<=n&&n<=this.clone().endOf(e).valueOf()))}function on(t,e){return this.isSame(t,e)||this.isAfter(t,e)}function sn(t,e){return this.isSame(t,e)||this.isBefore(t,e)}function ln(t,e,n){var i,a,r,o;return this.isValid()?(i=Oe(t,this),i.isValid()?(a=6e4*(i.utcOffset()-this.utcOffset()),e=Y(e),"year"===e||"month"===e||"quarter"===e?(o=un(this,i),"quarter"===e?o/=3:"year"===e&&(o/=12)):(r=this-i,o="second"===e?r/1e3:"minute"===e?r/6e4:"hour"===e?r/36e5:"day"===e?(r-a)/864e5:"week"===e?(r-a)/6048e5:r),n?o:_(o)):NaN):NaN}function un(t,e){var n,i,a=12*(e.year()-t.year())+(e.month()-t.month()),r=t.clone().add(a,"months");return e-r<0?(n=t.clone().add(a-1,"months"),i=(e-r)/(r-n)):(n=t.clone().add(a+1,"months"),i=(e-r)/(n-r)),-(a+i)||0}function dn(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function cn(){if(!this.isValid())return null;var t=this.clone().utc();return t.year()<0||t.year()>9999?K(t,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):C(Date.prototype.toISOString)?this.toDate().toISOString():K(t,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}function hn(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var t="moment",e="";this.isLocal()||(t=0===this.utcOffset()?"moment.utc":"moment.parseZone",e="Z");var n="["+t+'("]',i=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",a="-MM-DD[T]HH:mm:ss.SSS",r=e+'[")]';return this.format(n+i+a+r)}function fn(e){e||(e=this.isUtc()?t.defaultFormatUtc:t.defaultFormat);var n=K(this,e);return this.localeData().postformat(n)}function gn(t,e){return this.isValid()&&(x(t)&&t.isValid()||_e(t).isValid())?Ge({to:this,from:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()}function pn(t){return this.from(_e(),t)}function mn(t,e){return this.isValid()&&(x(t)&&t.isValid()||_e(t).isValid())?Ge({from:this,to:t}).locale(this.locale()).humanize(!e):this.localeData().invalidDate()}function vn(t){return this.to(_e(),t)}function yn(t){var e;return void 0===t?this._locale._abbr:(e=ie(t),null!=e&&(this._locale=e),this)}function bn(){return this._locale}function xn(t){switch(t=Y(t)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":case"date":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===t&&this.weekday(0),"isoWeek"===t&&this.isoWeekday(1),"quarter"===t&&this.month(3*Math.floor(this.month()/3)),this}function _n(t){return t=Y(t),void 0===t||"millisecond"===t?this:("date"===t&&(t="day"),this.startOf(t).add(1,"isoWeek"===t?"week":t).subtract(1,"ms"))}function kn(){return this._d.valueOf()-6e4*(this._offset||0)}function wn(){return Math.floor(this.valueOf()/1e3)}function Mn(){return new Date(this.valueOf())}function Sn(){var t=this;return[t.year(),t.month(),t.date(),t.hour(),t.minute(),t.second(),t.millisecond()]}function Dn(){var t=this;return{years:t.year(),months:t.month(),date:t.date(),hours:t.hours(),minutes:t.minutes(),seconds:t.seconds(),milliseconds:t.milliseconds()}}function Cn(){return this.isValid()?this.toISOString():null}function Pn(){return m(this)}function Tn(){return h({},p(this))}function In(){return p(this).overflow}function An(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}}function Fn(t,e){Z(0,[t,t.length],0,e)}function On(t){return Wn.call(this,t,this.week(),this.weekday(),this.localeData()._week.dow,this.localeData()._week.doy)}function Rn(t){return Wn.call(this,t,this.isoWeek(),this.isoWeekday(),1,4)}function Ln(){return St(this.year(),1,4)}function Vn(){var t=this.localeData()._week;return St(this.year(),t.dow,t.doy)}function Wn(t,e,n,i,a){var r;return null==t?Mt(this,i,a).year:(r=St(t,i,a),e>r&&(e=r),Yn.call(this,t,e,n,i,a))}function Yn(t,e,n,i,a){var r=wt(t,e,n,i,a),o=_t(r.year,0,r.dayOfYear);return this.year(o.getUTCFullYear()),this.month(o.getUTCMonth()),this.date(o.getUTCDate()),this}function zn(t){return null==t?Math.ceil((this.month()+1)/3):this.month(3*(t-1)+this.month()%3)}function Nn(t){var e=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==t?e:this.add(t-e,"d")}function Bn(t,e){e[fa]=k(1e3*("0."+t))}function En(){return this._isUTC?"UTC":""}function Hn(){return this._isUTC?"Coordinated Universal Time":""}function jn(t){return _e(1e3*t)}function Un(){return _e.apply(null,arguments).parseZone()}function Gn(t){return t}function qn(t,e,n,i){var a=ie(),r=f().set(i,e);return a[n](r,t)}function Zn(t,e,n){if(l(t)&&(e=t,t=void 0),t=t||"",null!=e)return qn(t,e,n,"month");var i,a=[];for(i=0;i<12;i++)a[i]=qn(t,i,n,"month");return a}function Xn(t,e,n,i){"boolean"==typeof t?(l(e)&&(n=e,e=void 0),e=e||""):(e=t,n=e,t=!1,l(e)&&(n=e,e=void 0),e=e||"");var a=ie(),r=t?a._week.dow:0;if(null!=n)return qn(e,(n+r)%7,i,"day");var o,s=[];for(o=0;o<7;o++)s[o]=qn(e,(o+r)%7,i,"day");return s}function Jn(t,e){return Zn(t,e,"months")}function Kn(t,e){return Zn(t,e,"monthsShort")}function Qn(t,e,n){return Xn(t,e,n,"weekdays")}function $n(t,e,n){return Xn(t,e,n,"weekdaysShort")}function ti(t,e,n){return Xn(t,e,n,"weekdaysMin")}function ei(){var t=this._data;return this._milliseconds=or(this._milliseconds),this._days=or(this._days),this._months=or(this._months),t.milliseconds=or(t.milliseconds),t.seconds=or(t.seconds),t.minutes=or(t.minutes),t.hours=or(t.hours),t.months=or(t.months),t.years=or(t.years),this}function ni(t,e,n,i){var a=Ge(e,n);return t._milliseconds+=i*a._milliseconds,t._days+=i*a._days,t._months+=i*a._months,t._bubble()}function ii(t,e){return ni(this,t,e,1)}function ai(t,e){return ni(this,t,e,-1)}function ri(t){return t<0?Math.floor(t):Math.ceil(t)}function oi(){var t,e,n,i,a,r=this._milliseconds,o=this._days,s=this._months,l=this._data;return r>=0&&o>=0&&s>=0||r<=0&&o<=0&&s<=0||(r+=864e5*ri(li(s)+o),o=0,s=0),l.milliseconds=r%1e3,t=_(r/1e3),l.seconds=t%60,e=_(t/60),l.minutes=e%60,n=_(e/60),l.hours=n%24,o+=_(n/24),a=_(si(o)),s+=a,o-=ri(li(a)),i=_(s/12),s%=12,l.days=o,l.months=s,l.years=i,this}function si(t){return 4800*t/146097}function li(t){return 146097*t/4800}function ui(t){if(!this.isValid())return NaN;var e,n,i=this._milliseconds;if(t=Y(t),"month"===t||"year"===t)return e=this._days+i/864e5,n=this._months+si(e),"month"===t?n:n/12;switch(e=this._days+Math.round(li(this._months)),t){case"week":return e/7+i/6048e5;case"day":return e+i/864e5;case"hour":return 24*e+i/36e5;case"minute":return 1440*e+i/6e4;case"second":return 86400*e+i/1e3;case"millisecond":return Math.floor(864e5*e)+i;default:throw new Error("Unknown unit "+t)}}function di(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*k(this._months/12):NaN}function ci(t){return function(){return this.as(t)}}function hi(t){return t=Y(t),this.isValid()?this[t+"s"]():NaN}function fi(t){return function(){return this.isValid()?this._data[t]:NaN}}function gi(){return _(this.days()/7)}function pi(t,e,n,i,a){return a.relativeTime(e||1,!!n,t,i)}function mi(t,e,n){var i=Ge(t).abs(),a=kr(i.as("s")),r=kr(i.as("m")),o=kr(i.as("h")),s=kr(i.as("d")),l=kr(i.as("M")),u=kr(i.as("y")),d=a<=wr.ss&&["s",a]||a<wr.s&&["ss",a]||r<=1&&["m"]||r<wr.m&&["mm",r]||o<=1&&["h"]||o<wr.h&&["hh",o]||s<=1&&["d"]||s<wr.d&&["dd",s]||l<=1&&["M"]||l<wr.M&&["MM",l]||u<=1&&["y"]||["yy",u];return d[2]=e,d[3]=+t>0,d[4]=n,pi.apply(null,d)}function vi(t){return void 0===t?kr:"function"==typeof t&&(kr=t,!0)}function yi(t,e){return void 0!==wr[t]&&(void 0===e?wr[t]:(wr[t]=e,"s"===t&&(wr.ss=e-1),!0))}function bi(t){if(!this.isValid())return this.localeData().invalidDate();var e=this.localeData(),n=mi(this,!t,e);return t&&(n=e.pastFuture(+this,n)),e.postformat(n)}function xi(){if(!this.isValid())return this.localeData().invalidDate();var t,e,n,i=Mr(this._milliseconds)/1e3,a=Mr(this._days),r=Mr(this._months);t=_(i/60),e=_(t/60),i%=60,t%=60,n=_(r/12),r%=12;var o=n,s=r,l=a,u=e,d=t,c=i,h=this.asSeconds();return h?(h<0?"-":"")+"P"+(o?o+"Y":"")+(s?s+"M":"")+(l?l+"D":"")+(u||d||c?"T":"")+(u?u+"H":"")+(d?d+"M":"")+(c?c+"S":""):"P0D"}var _i,ki;ki=Array.prototype.some?Array.prototype.some:function(t){for(var e=Object(this),n=e.length>>>0,i=0;i<n;i++)if(i in e&&t.call(this,e[i],i,e))return!0;return!1};var wi=ki,Mi=t.momentProperties=[],Si=!1,Di={};t.suppressDeprecationWarnings=!1,t.deprecationHandler=null;var Ci;Ci=Object.keys?Object.keys:function(t){var e,n=[];for(e in t)c(t,e)&&n.push(e);return n};var Pi,Ti=Ci,Ii={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Ai={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},Fi="Invalid date",Oi="%d",Ri=/\d{1,2}/,Li={future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Vi={},Wi={},Yi=/(\[[^\[]*\])|(\\)?([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,zi=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Ni={},Bi={},Ei=/\d/,Hi=/\d\d/,ji=/\d{3}/,Ui=/\d{4}/,Gi=/[+-]?\d{6}/,qi=/\d\d?/,Zi=/\d\d\d\d?/,Xi=/\d\d\d\d\d\d?/,Ji=/\d{1,3}/,Ki=/\d{1,4}/,Qi=/[+-]?\d{1,6}/,$i=/\d+/,ta=/[+-]?\d+/,ea=/Z|[+-]\d\d:?\d\d/gi,na=/Z|[+-]\d\d(?::?\d\d)?/gi,ia=/[+-]?\d+(\.\d{1,3})?/,aa=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,ra={},oa={},sa=0,la=1,ua=2,da=3,ca=4,ha=5,fa=6,ga=7,pa=8;Pi=Array.prototype.indexOf?Array.prototype.indexOf:function(t){var e;for(e=0;e<this.length;++e)if(this[e]===t)return e;return-1};var ma=Pi;Z("M",["MM",2],"Mo",function(){return this.month()+1}),Z("MMM",0,0,function(t){return this.localeData().monthsShort(this,t)}),Z("MMMM",0,0,function(t){return this.localeData().months(this,t)}),W("month","M"),N("month",8),$("M",qi),$("MM",qi,Hi),$("MMM",function(t,e){return e.monthsShortRegex(t)}),$("MMMM",function(t,e){return e.monthsRegex(t)}),it(["M","MM"],function(t,e){e[la]=k(t)-1}),it(["MMM","MMMM"],function(t,e,n,i){var a=n._locale.monthsParse(t,i,n._strict);null!=a?e[la]=a:p(n).invalidMonth=t});var va=/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,ya="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ba="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),xa=aa,_a=aa;Z("Y",0,0,function(){var t=this.year();return t<=9999?""+t:"+"+t}),Z(0,["YY",2],0,function(){return this.year()%100}),Z(0,["YYYY",4],0,"year"),Z(0,["YYYYY",5],0,"year"),Z(0,["YYYYYY",6,!0],0,"year"),W("year","y"),N("year",1),$("Y",ta),$("YY",qi,Hi),$("YYYY",Ki,Ui),$("YYYYY",Qi,Gi),$("YYYYYY",Qi,Gi),it(["YYYYY","YYYYYY"],sa),it("YYYY",function(e,n){n[sa]=2===e.length?t.parseTwoDigitYear(e):k(e)}),it("YY",function(e,n){n[sa]=t.parseTwoDigitYear(e)}),it("Y",function(t,e){e[sa]=parseInt(t,10)}),t.parseTwoDigitYear=function(t){return k(t)+(k(t)>68?1900:2e3)};var ka=E("FullYear",!0);Z("w",["ww",2],"wo","week"),Z("W",["WW",2],"Wo","isoWeek"),W("week","w"),W("isoWeek","W"),N("week",5),N("isoWeek",5),$("w",qi),$("ww",qi,Hi),$("W",qi),$("WW",qi,Hi),at(["w","ww","W","WW"],function(t,e,n,i){e[i.substr(0,1)]=k(t)});var wa={dow:0,doy:6};Z("d",0,"do","day"),Z("dd",0,0,function(t){return this.localeData().weekdaysMin(this,t)}),Z("ddd",0,0,function(t){return this.localeData().weekdaysShort(this,t)}),Z("dddd",0,0,function(t){return this.localeData().weekdays(this,t)}),Z("e",0,0,"weekday"),Z("E",0,0,"isoWeekday"),W("day","d"),W("weekday","e"),W("isoWeekday","E"),N("day",11),N("weekday",11),N("isoWeekday",11),$("d",qi),$("e",qi),$("E",qi),$("dd",function(t,e){return e.weekdaysMinRegex(t)}),$("ddd",function(t,e){return e.weekdaysShortRegex(t)}),$("dddd",function(t,e){return e.weekdaysRegex(t)}),at(["dd","ddd","dddd"],function(t,e,n,i){var a=n._locale.weekdaysParse(t,i,n._strict);null!=a?e.d=a:p(n).invalidWeekday=t;
12
- }),at(["d","e","E"],function(t,e,n,i){e[i]=k(t)});var Ma="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Sa="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Da="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Ca=aa,Pa=aa,Ta=aa;Z("H",["HH",2],0,"hour"),Z("h",["hh",2],0,Ut),Z("k",["kk",2],0,Gt),Z("hmm",0,0,function(){return""+Ut.apply(this)+q(this.minutes(),2)}),Z("hmmss",0,0,function(){return""+Ut.apply(this)+q(this.minutes(),2)+q(this.seconds(),2)}),Z("Hmm",0,0,function(){return""+this.hours()+q(this.minutes(),2)}),Z("Hmmss",0,0,function(){return""+this.hours()+q(this.minutes(),2)+q(this.seconds(),2)}),qt("a",!0),qt("A",!1),W("hour","h"),N("hour",13),$("a",Zt),$("A",Zt),$("H",qi),$("h",qi),$("k",qi),$("HH",qi,Hi),$("hh",qi,Hi),$("kk",qi,Hi),$("hmm",Zi),$("hmmss",Xi),$("Hmm",Zi),$("Hmmss",Xi),it(["H","HH"],da),it(["k","kk"],function(t,e,n){var i=k(t);e[da]=24===i?0:i}),it(["a","A"],function(t,e,n){n._isPm=n._locale.isPM(t),n._meridiem=t}),it(["h","hh"],function(t,e,n){e[da]=k(t),p(n).bigHour=!0}),it("hmm",function(t,e,n){var i=t.length-2;e[da]=k(t.substr(0,i)),e[ca]=k(t.substr(i)),p(n).bigHour=!0}),it("hmmss",function(t,e,n){var i=t.length-4,a=t.length-2;e[da]=k(t.substr(0,i)),e[ca]=k(t.substr(i,2)),e[ha]=k(t.substr(a)),p(n).bigHour=!0}),it("Hmm",function(t,e,n){var i=t.length-2;e[da]=k(t.substr(0,i)),e[ca]=k(t.substr(i))}),it("Hmmss",function(t,e,n){var i=t.length-4,a=t.length-2;e[da]=k(t.substr(0,i)),e[ca]=k(t.substr(i,2)),e[ha]=k(t.substr(a))});var Ia,Aa=/[ap]\.?m?\.?/i,Fa=E("Hours",!0),Oa={calendar:Ii,longDateFormat:Ai,invalidDate:Fi,ordinal:Oi,dayOfMonthOrdinalParse:Ri,relativeTime:Li,months:ya,monthsShort:ba,week:wa,weekdays:Ma,weekdaysMin:Da,weekdaysShort:Sa,meridiemParse:Aa},Ra={},La={},Va=/^\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)?)?$/,Wa=/^\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)?)?$/,Ya=/Z|[+-]\d\d(?::?\d\d)?/,za=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Na=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Ba=/^\/?Date\((\-?\d+)/i,Ea=/^((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d?\d\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?:\d\d)?\d\d\s)(\d\d:\d\d)(\:\d\d)?(\s(?:UT|GMT|[ECMP][SD]T|[A-IK-Za-ik-z]|[+-]\d{4}))$/;t.createFromInputFallback=S("value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.",function(t){t._d=new Date(t._i+(t._useUTC?" UTC":""))}),t.ISO_8601=function(){},t.RFC_2822=function(){};var Ha=S("moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var t=_e.apply(null,arguments);return this.isValid()&&t.isValid()?t<this?this:t:v()}),ja=S("moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/",function(){var t=_e.apply(null,arguments);return this.isValid()&&t.isValid()?t>this?this:t:v()}),Ua=function(){return Date.now?Date.now():+new Date},Ga=["year","quarter","month","week","day","hour","minute","second","millisecond"];Ae("Z",":"),Ae("ZZ",""),$("Z",na),$("ZZ",na),it(["Z","ZZ"],function(t,e,n){n._useUTC=!0,n._tzm=Fe(na,t)});var qa=/([\+\-]|\d\d)/gi;t.updateOffset=function(){};var Za=/^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/,Xa=/^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;Ge.fn=Pe.prototype,Ge.invalid=Ce;var Ja=Je(1,"add"),Ka=Je(-1,"subtract");t.defaultFormat="YYYY-MM-DDTHH:mm:ssZ",t.defaultFormatUtc="YYYY-MM-DDTHH:mm:ss[Z]";var Qa=S("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(t){return void 0===t?this.localeData():this.locale(t)});Z(0,["gg",2],0,function(){return this.weekYear()%100}),Z(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Fn("gggg","weekYear"),Fn("ggggg","weekYear"),Fn("GGGG","isoWeekYear"),Fn("GGGGG","isoWeekYear"),W("weekYear","gg"),W("isoWeekYear","GG"),N("weekYear",1),N("isoWeekYear",1),$("G",ta),$("g",ta),$("GG",qi,Hi),$("gg",qi,Hi),$("GGGG",Ki,Ui),$("gggg",Ki,Ui),$("GGGGG",Qi,Gi),$("ggggg",Qi,Gi),at(["gggg","ggggg","GGGG","GGGGG"],function(t,e,n,i){e[i.substr(0,2)]=k(t)}),at(["gg","GG"],function(e,n,i,a){n[a]=t.parseTwoDigitYear(e)}),Z("Q",0,"Qo","quarter"),W("quarter","Q"),N("quarter",7),$("Q",Ei),it("Q",function(t,e){e[la]=3*(k(t)-1)}),Z("D",["DD",2],"Do","date"),W("date","D"),N("date",9),$("D",qi),$("DD",qi,Hi),$("Do",function(t,e){return t?e._dayOfMonthOrdinalParse||e._ordinalParse:e._dayOfMonthOrdinalParseLenient}),it(["D","DD"],ua),it("Do",function(t,e){e[ua]=k(t.match(qi)[0],10)});var $a=E("Date",!0);Z("DDD",["DDDD",3],"DDDo","dayOfYear"),W("dayOfYear","DDD"),N("dayOfYear",4),$("DDD",Ji),$("DDDD",ji),it(["DDD","DDDD"],function(t,e,n){n._dayOfYear=k(t)}),Z("m",["mm",2],0,"minute"),W("minute","m"),N("minute",14),$("m",qi),$("mm",qi,Hi),it(["m","mm"],ca);var tr=E("Minutes",!1);Z("s",["ss",2],0,"second"),W("second","s"),N("second",15),$("s",qi),$("ss",qi,Hi),it(["s","ss"],ha);var er=E("Seconds",!1);Z("S",0,0,function(){return~~(this.millisecond()/100)}),Z(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),Z(0,["SSS",3],0,"millisecond"),Z(0,["SSSS",4],0,function(){return 10*this.millisecond()}),Z(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),Z(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),Z(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),Z(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),Z(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),W("millisecond","ms"),N("millisecond",16),$("S",Ji,Ei),$("SS",Ji,Hi),$("SSS",Ji,ji);var nr;for(nr="SSSS";nr.length<=9;nr+="S")$(nr,$i);for(nr="S";nr.length<=9;nr+="S")it(nr,Bn);var ir=E("Milliseconds",!1);Z("z",0,0,"zoneAbbr"),Z("zz",0,0,"zoneName");var ar=b.prototype;ar.add=Ja,ar.calendar=$e,ar.clone=tn,ar.diff=ln,ar.endOf=_n,ar.format=fn,ar.from=gn,ar.fromNow=pn,ar.to=mn,ar.toNow=vn,ar.get=U,ar.invalidAt=In,ar.isAfter=en,ar.isBefore=nn,ar.isBetween=an,ar.isSame=rn,ar.isSameOrAfter=on,ar.isSameOrBefore=sn,ar.isValid=Pn,ar.lang=Qa,ar.locale=yn,ar.localeData=bn,ar.max=ja,ar.min=Ha,ar.parsingFlags=Tn,ar.set=G,ar.startOf=xn,ar.subtract=Ka,ar.toArray=Sn,ar.toObject=Dn,ar.toDate=Mn,ar.toISOString=cn,ar.inspect=hn,ar.toJSON=Cn,ar.toString=dn,ar.unix=wn,ar.valueOf=kn,ar.creationData=An,ar.year=ka,ar.isLeapYear=bt,ar.weekYear=On,ar.isoWeekYear=Rn,ar.quarter=ar.quarters=zn,ar.month=ht,ar.daysInMonth=ft,ar.week=ar.weeks=Tt,ar.isoWeek=ar.isoWeeks=It,ar.weeksInYear=Vn,ar.isoWeeksInYear=Ln,ar.date=$a,ar.day=ar.days=Yt,ar.weekday=zt,ar.isoWeekday=Nt,ar.dayOfYear=Nn,ar.hour=ar.hours=Fa,ar.minute=ar.minutes=tr,ar.second=ar.seconds=er,ar.millisecond=ar.milliseconds=ir,ar.utcOffset=Le,ar.utc=We,ar.local=Ye,ar.parseZone=ze,ar.hasAlignedHourOffset=Ne,ar.isDST=Be,ar.isLocal=He,ar.isUtcOffset=je,ar.isUtc=Ue,ar.isUTC=Ue,ar.zoneAbbr=En,ar.zoneName=Hn,ar.dates=S("dates accessor is deprecated. Use date instead.",$a),ar.months=S("months accessor is deprecated. Use month instead",ht),ar.years=S("years accessor is deprecated. Use year instead",ka),ar.zone=S("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",Ve),ar.isDSTShifted=S("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",Ee);var rr=I.prototype;rr.calendar=A,rr.longDateFormat=F,rr.invalidDate=O,rr.ordinal=R,rr.preparse=Gn,rr.postformat=Gn,rr.relativeTime=L,rr.pastFuture=V,rr.set=P,rr.months=st,rr.monthsShort=lt,rr.monthsParse=dt,rr.monthsRegex=pt,rr.monthsShortRegex=gt,rr.week=Dt,rr.firstDayOfYear=Pt,rr.firstDayOfWeek=Ct,rr.weekdays=Ot,rr.weekdaysMin=Lt,rr.weekdaysShort=Rt,rr.weekdaysParse=Wt,rr.weekdaysRegex=Bt,rr.weekdaysShortRegex=Et,rr.weekdaysMinRegex=Ht,rr.isPM=Xt,rr.meridiem=Jt,te("en",{dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(t){var e=t%10,n=1===k(t%100/10)?"th":1===e?"st":2===e?"nd":3===e?"rd":"th";return t+n}}),t.lang=S("moment.lang is deprecated. Use moment.locale instead.",te),t.langData=S("moment.langData is deprecated. Use moment.localeData instead.",ie);var or=Math.abs,sr=ci("ms"),lr=ci("s"),ur=ci("m"),dr=ci("h"),cr=ci("d"),hr=ci("w"),fr=ci("M"),gr=ci("y"),pr=fi("milliseconds"),mr=fi("seconds"),vr=fi("minutes"),yr=fi("hours"),br=fi("days"),xr=fi("months"),_r=fi("years"),kr=Math.round,wr={ss:44,s:45,m:45,h:22,d:26,M:11},Mr=Math.abs,Sr=Pe.prototype;return Sr.isValid=De,Sr.abs=ei,Sr.add=ii,Sr.subtract=ai,Sr.as=ui,Sr.asMilliseconds=sr,Sr.asSeconds=lr,Sr.asMinutes=ur,Sr.asHours=dr,Sr.asDays=cr,Sr.asWeeks=hr,Sr.asMonths=fr,Sr.asYears=gr,Sr.valueOf=di,Sr._bubble=oi,Sr.get=hi,Sr.milliseconds=pr,Sr.seconds=mr,Sr.minutes=vr,Sr.hours=yr,Sr.days=br,Sr.weeks=gi,Sr.months=xr,Sr.years=_r,Sr.humanize=bi,Sr.toISOString=xi,Sr.toString=xi,Sr.toJSON=xi,Sr.locale=yn,Sr.localeData=bn,Sr.toIsoString=S("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",xi),Sr.lang=Qa,Z("X",0,0,"unix"),Z("x",0,0,"valueOf"),$("x",ta),$("X",ia),it("X",function(t,e,n){n._d=new Date(1e3*parseFloat(t,10))}),it("x",function(t,e,n){n._d=new Date(k(t))}),t.version="2.18.1",i(_e),t.fn=ar,t.min=we,t.max=Me,t.now=Ua,t.utc=f,t.unix=jn,t.months=Jn,t.isDate=u,t.locale=te,t.invalid=v,t.duration=Ge,t.isMoment=x,t.weekdays=Qn,t.parseZone=Un,t.localeData=ie,t.isDuration=Te,t.monthsShort=Kn,t.weekdaysMin=ti,t.defineLocale=ee,t.updateLocale=ne,t.locales=ae,t.weekdaysShort=$n,t.normalizeUnits=Y,t.relativeTimeRounding=vi,t.relativeTimeThreshold=yi,t.calendarFormat=Qe,t.prototype=ar,t})},{}],7:[function(t,e,n){var i=t(28)();t(26)(i),t(40)(i),t(22)(i),t(25)(i),t(30)(i),t(21)(i),t(23)(i),t(24)(i),t(29)(i),t(32)(i),t(33)(i),t(31)(i),t(27)(i),t(34)(i),t(35)(i),t(36)(i),t(37)(i),t(38)(i),t(46)(i),t(44)(i),t(45)(i),t(47)(i),t(48)(i),t(49)(i),t(15)(i),t(16)(i),t(17)(i),t(18)(i),t(19)(i),t(20)(i),t(8)(i),t(9)(i),t(10)(i),t(11)(i),t(12)(i),t(13)(i),t(14)(i);var a=[];a.push(t(41)(i),t(42)(i),t(43)(i)),i.plugins.register(a),e.exports=i,"undefined"!=typeof window&&(window.Chart=i)},{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,36:36,37:37,38:38,40:40,41:41,42:42,43:43,44:44,45:45,46:46,47:47,48:48,49:49,8:8,9:9}],8:[function(t,e,n){"use strict";e.exports=function(t){t.Bar=function(e,n){return n.type="bar",new t(e,n)}}},{}],9:[function(t,e,n){"use strict";e.exports=function(t){t.Bubble=function(e,n){return n.type="bubble",new t(e,n)}}},{}],10:[function(t,e,n){"use strict";e.exports=function(t){t.Doughnut=function(e,n){return n.type="doughnut",new t(e,n)}}},{}],11:[function(t,e,n){"use strict";e.exports=function(t){t.Line=function(e,n){return n.type="line",new t(e,n)}}},{}],12:[function(t,e,n){"use strict";e.exports=function(t){t.PolarArea=function(e,n){return n.type="polarArea",new t(e,n)}}},{}],13:[function(t,e,n){"use strict";e.exports=function(t){t.Radar=function(e,n){return n.type="radar",new t(e,n)}}},{}],14:[function(t,e,n){"use strict";e.exports=function(t){var e={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-1"}],yAxes:[{type:"linear",position:"left",id:"y-axis-1"}]},tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}};t.defaults.scatter=e,t.controllers.scatter=t.controllers.line,t.Scatter=function(e,n){return n.type="scatter",new t(e,n)}}},{}],15:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.bar={hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}},t.controllers.bar=t.DatasetController.extend({dataElementType:t.elements.Rectangle,initialize:function(){var e,n=this;t.DatasetController.prototype.initialize.apply(n,arguments),e=n.getMeta(),e.stack=n.getDataset().stack,e.bar=!0},update:function(t){var e,n,i=this,a=i.getMeta().data;for(i._ruler=i.getRuler(),e=0,n=a.length;e<n;++e)i.updateElement(a[e],e,t)},updateElement:function(t,n,i){var a=this,r=a.chart,o=a.getMeta(),s=a.getDataset(),l=t.custom||{},u=r.options.elements.rectangle;t._xScale=a.getScaleForId(o.xAxisID),t._yScale=a.getScaleForId(o.yAxisID),t._datasetIndex=a.index,t._index=n,t._model={datasetLabel:s.label,label:r.data.labels[n],borderSkipped:l.borderSkipped?l.borderSkipped:u.borderSkipped,backgroundColor:l.backgroundColor?l.backgroundColor:e.getValueAtIndexOrDefault(s.backgroundColor,n,u.backgroundColor),borderColor:l.borderColor?l.borderColor:e.getValueAtIndexOrDefault(s.borderColor,n,u.borderColor),borderWidth:l.borderWidth?l.borderWidth:e.getValueAtIndexOrDefault(s.borderWidth,n,u.borderWidth)},a.updateElementGeometry(t,n,i),t.pivot()},updateElementGeometry:function(t,e,n){var i=this,a=t._model,r=i.getValueScale(),o=r.getBasePixel(),s=r.isHorizontal(),l=i._ruler||i.getRuler(),u=i.calculateBarValuePixels(i.index,e),d=i.calculateBarIndexPixels(i.index,e,l);a.horizontal=s,a.base=n?o:u.base,a.x=s?n?o:u.head:d.center,a.y=s?d.center:n?o:u.head,a.height=s?d.size:void 0,a.width=s?void 0:d.size},getValueScaleId:function(){return this.getMeta().yAxisID},getIndexScaleId:function(){return this.getMeta().xAxisID},getValueScale:function(){return this.getScaleForId(this.getValueScaleId())},getIndexScale:function(){return this.getScaleForId(this.getIndexScaleId())},getStackCount:function(t){var e,n,i=this,a=i.chart,r=i.getIndexScale(),o=r.options.stacked,s=void 0===t?a.data.datasets.length:t+1,l=[];for(e=0;e<s;++e)n=a.getDatasetMeta(e),n.bar&&a.isDatasetVisible(e)&&(o===!1||o===!0&&l.indexOf(n.stack)===-1||void 0===o&&(void 0===n.stack||l.indexOf(n.stack)===-1))&&l.push(n.stack);return l.length},getStackIndex:function(t){return this.getStackCount(t)-1},getRuler:function(){var t=this,n=t.getIndexScale(),i=n.options,a=t.getStackCount(),r=n.isHorizontal()?n.width:n.height,o=r/n.ticks.length,s=o*i.categoryPercentage,l=s/a,u=l*i.barPercentage;return u=Math.min(e.getValueOrDefault(i.barThickness,u),e.getValueOrDefault(i.maxBarThickness,1/0)),{stackCount:a,tickSize:o,categorySize:s,categorySpacing:o-s,fullBarSize:l,barSize:u,barSpacing:l-u,scale:n}},calculateBarValuePixels:function(t,e){var n,i,a,r,o,s,l=this,u=l.chart,d=l.getMeta(),c=l.getValueScale(),h=u.data.datasets,f=Number(h[t].data[e]),g=c.options.stacked,p=d.stack,m=0;if(g||void 0===g&&void 0!==p)for(n=0;n<t;++n)i=u.getDatasetMeta(n),i.bar&&i.stack===p&&i.controller.getValueScaleId()===c.id&&u.isDatasetVisible(n)&&(a=Number(h[n].data[e]),(f<0&&a<0||f>=0&&a>0)&&(m+=a));return r=c.getPixelForValue(m),o=c.getPixelForValue(m+f),s=(o-r)/2,{size:s,base:r,head:o,center:o+s/2}},calculateBarIndexPixels:function(t,e,n){var i=this,a=n.scale,r=i.chart.isCombo,o=i.getStackIndex(t),s=a.getPixelForValue(null,e,t,r),l=n.barSize;return s-=r?n.tickSize/2:0,s+=n.fullBarSize*o,s+=n.categorySpacing/2,s+=n.barSpacing/2,{size:l,base:s,head:s+l,center:s+l/2}},draw:function(){var t,n=this,i=n.chart,a=n.getMeta().data,r=n.getDataset(),o=a.length,s=0;for(e.canvas.clipArea(i.ctx,i.chartArea);s<o;++s)t=r.data[s],null===t||void 0===t||isNaN(t)||a[s].draw();e.canvas.unclipArea(i.ctx)},setHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},r=t._model;r.backgroundColor=a.hoverBackgroundColor?a.hoverBackgroundColor:e.getValueAtIndexOrDefault(n.hoverBackgroundColor,i,e.getHoverColor(r.backgroundColor)),r.borderColor=a.hoverBorderColor?a.hoverBorderColor:e.getValueAtIndexOrDefault(n.hoverBorderColor,i,e.getHoverColor(r.borderColor)),r.borderWidth=a.hoverBorderWidth?a.hoverBorderWidth:e.getValueAtIndexOrDefault(n.hoverBorderWidth,i,r.borderWidth)},removeHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},r=t._model,o=this.chart.options.elements.rectangle;r.backgroundColor=a.backgroundColor?a.backgroundColor:e.getValueAtIndexOrDefault(n.backgroundColor,i,o.backgroundColor),r.borderColor=a.borderColor?a.borderColor:e.getValueAtIndexOrDefault(n.borderColor,i,o.borderColor),r.borderWidth=a.borderWidth?a.borderWidth:e.getValueAtIndexOrDefault(n.borderWidth,i,o.borderWidth)}}),t.defaults.horizontalBar={hover:{mode:"label"},scales:{xAxes:[{type:"linear",position:"bottom"}],yAxes:[{position:"left",type:"category",categoryPercentage:.8,barPercentage:.9,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{callbacks:{title:function(t,e){var n="";return t.length>0&&(t[0].yLabel?n=t[0].yLabel:e.labels.length>0&&t[0].index<e.labels.length&&(n=e.labels[t[0].index])),n},label:function(t,e){var n=e.datasets[t.datasetIndex].label||"";return n+": "+t.xLabel}}}},t.controllers.horizontalBar=t.controllers.bar.extend({getValueScaleId:function(){return this.getMeta().xAxisID},getIndexScaleId:function(){return this.getMeta().yAxisID}})}},{}],16:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.bubble={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(){return""},label:function(t,e){var n=e.datasets[t.datasetIndex].label||"",i=e.datasets[t.datasetIndex].data[t.index];return n+": ("+t.xLabel+", "+t.yLabel+", "+i.r+")"}}}},t.controllers.bubble=t.DatasetController.extend({dataElementType:t.elements.Point,update:function(t){var n=this,i=n.getMeta(),a=i.data;e.each(a,function(e,i){n.updateElement(e,i,t)})},updateElement:function(n,i,a){var r=this,o=r.getMeta(),s=r.getScaleForId(o.xAxisID),l=r.getScaleForId(o.yAxisID),u=n.custom||{},d=r.getDataset(),c=d.data[i],h=r.chart.options.elements.point,f=r.index;e.extend(n,{_xScale:s,_yScale:l,_datasetIndex:f,_index:i,_model:{x:a?s.getPixelForDecimal(.5):s.getPixelForValue("object"==typeof c?c:NaN,i,f,r.chart.isCombo),y:a?l.getBasePixel():l.getPixelForValue(c,i,f),radius:a?0:u.radius?u.radius:r.getRadius(c),hitRadius:u.hitRadius?u.hitRadius:e.getValueAtIndexOrDefault(d.hitRadius,i,h.hitRadius)}}),t.DatasetController.prototype.removeHoverStyle.call(r,n,h);var g=n._model;g.skip=u.skip?u.skip:isNaN(g.x)||isNaN(g.y),n.pivot()},getRadius:function(t){return t.r||this.chart.options.elements.point.radius},setHoverStyle:function(n){var i=this;t.DatasetController.prototype.setHoverStyle.call(i,n);var a=i.chart.data.datasets[n._datasetIndex],r=n._index,o=n.custom||{},s=n._model;s.radius=o.hoverRadius?o.hoverRadius:e.getValueAtIndexOrDefault(a.hoverRadius,r,i.chart.options.elements.point.hoverRadius)+i.getRadius(a.data[r])},removeHoverStyle:function(e){var n=this;t.DatasetController.prototype.removeHoverStyle.call(n,e,n.chart.options.elements.point);var i=n.chart.data.datasets[e._datasetIndex].data[e._index],a=e.custom||{},r=e._model;r.radius=a.radius?a.radius:n.getRadius(i)}})}},{}],17:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults;n.doughnut={animation:{animateRotate:!0,animateScale:!1},aspectRatio:1,hover:{mode:"single"},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var r=0;r<i[0].data.length;++r)e.push('<li><span style="background-color:'+i[0].backgroundColor[r]+'"></span>'),a[r]&&e.push(a[r]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var r=t.getDatasetMeta(0),o=n.datasets[0],s=r.data[a],l=s&&s.custom||{},u=e.getValueAtIndexOrDefault,d=t.options.elements.arc,c=l.backgroundColor?l.backgroundColor:u(o.backgroundColor,a,d.backgroundColor),h=l.borderColor?l.borderColor:u(o.borderColor,a,d.borderColor),f=l.borderWidth?l.borderWidth:u(o.borderWidth,a,d.borderWidth);return{text:i,fillStyle:c,strokeStyle:h,lineWidth:f,hidden:isNaN(o.data[a])||r.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,r=e.index,o=this.chart;for(n=0,i=(o.data.datasets||[]).length;n<i;++n)a=o.getDatasetMeta(n),a.data[r]&&(a.data[r].hidden=!a.data[r].hidden);o.update()}},cutoutPercentage:50,rotation:Math.PI*-.5,circumference:2*Math.PI,tooltips:{callbacks:{title:function(){return""},label:function(t,n){var i=n.labels[t.index],a=": "+n.datasets[t.datasetIndex].data[t.index];return e.isArray(i)?(i=i.slice(),i[0]+=a):i+=a,i}}}},n.pie=e.clone(n.doughnut),e.extend(n.pie,{cutoutPercentage:0}),t.controllers.doughnut=t.controllers.pie=t.DatasetController.extend({dataElementType:t.elements.Arc,linkScales:e.noop,getRingIndex:function(t){for(var e=0,n=0;n<t;++n)this.chart.isDatasetVisible(n)&&++e;return e},update:function(t){var n=this,i=n.chart,a=i.chartArea,r=i.options,o=r.elements.arc,s=a.right-a.left-o.borderWidth,l=a.bottom-a.top-o.borderWidth,u=Math.min(s,l),d={x:0,y:0},c=n.getMeta(),h=r.cutoutPercentage,f=r.circumference;if(f<2*Math.PI){var g=r.rotation%(2*Math.PI);g+=2*Math.PI*(g>=Math.PI?-1:g<-Math.PI?1:0);var p=g+f,m={x:Math.cos(g),y:Math.sin(g)},v={x:Math.cos(p),y:Math.sin(p)},y=g<=0&&0<=p||g<=2*Math.PI&&2*Math.PI<=p,b=g<=.5*Math.PI&&.5*Math.PI<=p||g<=2.5*Math.PI&&2.5*Math.PI<=p,x=g<=-Math.PI&&-Math.PI<=p||g<=Math.PI&&Math.PI<=p,_=g<=.5*-Math.PI&&.5*-Math.PI<=p||g<=1.5*Math.PI&&1.5*Math.PI<=p,k=h/100,w={x:x?-1:Math.min(m.x*(m.x<0?1:k),v.x*(v.x<0?1:k)),y:_?-1:Math.min(m.y*(m.y<0?1:k),v.y*(v.y<0?1:k))},M={x:y?1:Math.max(m.x*(m.x>0?1:k),v.x*(v.x>0?1:k)),y:b?1:Math.max(m.y*(m.y>0?1:k),v.y*(v.y>0?1:k))},S={width:.5*(M.x-w.x),height:.5*(M.y-w.y)};u=Math.min(s/S.width,l/S.height),d={x:(M.x+w.x)*-.5,y:(M.y+w.y)*-.5}}i.borderWidth=n.getMaxBorderWidth(c.data),i.outerRadius=Math.max((u-i.borderWidth)/2,0),i.innerRadius=Math.max(h?i.outerRadius/100*h:0,0),i.radiusLength=(i.outerRadius-i.innerRadius)/i.getVisibleDatasetCount(),i.offsetX=d.x*i.outerRadius,i.offsetY=d.y*i.outerRadius,c.total=n.calculateTotal(),n.outerRadius=i.outerRadius-i.radiusLength*n.getRingIndex(n.index),n.innerRadius=Math.max(n.outerRadius-i.radiusLength,0),e.each(c.data,function(e,i){n.updateElement(e,i,t)})},updateElement:function(t,n,i){var a=this,r=a.chart,o=r.chartArea,s=r.options,l=s.animation,u=(o.left+o.right)/2,d=(o.top+o.bottom)/2,c=s.rotation,h=s.rotation,f=a.getDataset(),g=i&&l.animateRotate?0:t.hidden?0:a.calculateCircumference(f.data[n])*(s.circumference/(2*Math.PI)),p=i&&l.animateScale?0:a.innerRadius,m=i&&l.animateScale?0:a.outerRadius,v=e.getValueAtIndexOrDefault;e.extend(t,{_datasetIndex:a.index,_index:n,_model:{x:u+r.offsetX,y:d+r.offsetY,startAngle:c,endAngle:h,circumference:g,outerRadius:m,innerRadius:p,label:v(f.label,n,r.data.labels[n])}});var y=t._model;this.removeHoverStyle(t),i&&l.animateRotate||(0===n?y.startAngle=s.rotation:y.startAngle=a.getMeta().data[n-1]._model.endAngle,y.endAngle=y.startAngle+y.circumference),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},calculateTotal:function(){var t,n=this.getDataset(),i=this.getMeta(),a=0;return e.each(i.data,function(e,i){t=n.data[i],isNaN(t)||e.hidden||(a+=Math.abs(t))}),a},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?2*Math.PI*(t/e):0},getMaxBorderWidth:function(t){for(var e,n,i=0,a=this.index,r=t.length,o=0;o<r;o++)e=t[o]._model?t[o]._model.borderWidth:0,n=t[o]._chart?t[o]._chart.config.data.datasets[a].hoverBorderWidth:0,i=e>i?e:i,i=n>i?n:i;return i}})}},{}],18:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return n.getValueOrDefault(t.showLine,e.showLines)}var n=t.helpers;t.defaults.line={showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}},t.controllers.line=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,update:function(t){var i,a,r,o=this,s=o.getMeta(),l=s.dataset,u=s.data||[],d=o.chart.options,c=d.elements.line,h=o.getScaleForId(s.yAxisID),f=o.getDataset(),g=e(f,d);for(g&&(r=l.custom||{},void 0!==f.tension&&void 0===f.lineTension&&(f.lineTension=f.tension),l._scale=h,l._datasetIndex=o.index,l._children=u,l._model={spanGaps:f.spanGaps?f.spanGaps:d.spanGaps,tension:r.tension?r.tension:n.getValueOrDefault(f.lineTension,c.tension),backgroundColor:r.backgroundColor?r.backgroundColor:f.backgroundColor||c.backgroundColor,borderWidth:r.borderWidth?r.borderWidth:f.borderWidth||c.borderWidth,borderColor:r.borderColor?r.borderColor:f.borderColor||c.borderColor,borderCapStyle:r.borderCapStyle?r.borderCapStyle:f.borderCapStyle||c.borderCapStyle,borderDash:r.borderDash?r.borderDash:f.borderDash||c.borderDash,borderDashOffset:r.borderDashOffset?r.borderDashOffset:f.borderDashOffset||c.borderDashOffset,borderJoinStyle:r.borderJoinStyle?r.borderJoinStyle:f.borderJoinStyle||c.borderJoinStyle,fill:r.fill?r.fill:void 0!==f.fill?f.fill:c.fill,steppedLine:r.steppedLine?r.steppedLine:n.getValueOrDefault(f.steppedLine,c.stepped),cubicInterpolationMode:r.cubicInterpolationMode?r.cubicInterpolationMode:n.getValueOrDefault(f.cubicInterpolationMode,c.cubicInterpolationMode)},l.pivot()),i=0,a=u.length;i<a;++i)o.updateElement(u[i],i,t);for(g&&0!==l._model.tension&&o.updateBezierControlPoints(),i=0,a=u.length;i<a;++i)u[i].pivot()},getPointBackgroundColor:function(t,e){var i=this.chart.options.elements.point.backgroundColor,a=this.getDataset(),r=t.custom||{};return r.backgroundColor?i=r.backgroundColor:a.pointBackgroundColor?i=n.getValueAtIndexOrDefault(a.pointBackgroundColor,e,i):a.backgroundColor&&(i=a.backgroundColor),i},getPointBorderColor:function(t,e){var i=this.chart.options.elements.point.borderColor,a=this.getDataset(),r=t.custom||{};return r.borderColor?i=r.borderColor:a.pointBorderColor?i=n.getValueAtIndexOrDefault(a.pointBorderColor,e,i):a.borderColor&&(i=a.borderColor),i},getPointBorderWidth:function(t,e){var i=this.chart.options.elements.point.borderWidth,a=this.getDataset(),r=t.custom||{};return isNaN(r.borderWidth)?isNaN(a.pointBorderWidth)?isNaN(a.borderWidth)||(i=a.borderWidth):i=n.getValueAtIndexOrDefault(a.pointBorderWidth,e,i):i=r.borderWidth,i},updateElement:function(t,e,i){var a,r,o=this,s=o.getMeta(),l=t.custom||{},u=o.getDataset(),d=o.index,c=u.data[e],h=o.getScaleForId(s.yAxisID),f=o.getScaleForId(s.xAxisID),g=o.chart.options.elements.point,p=o.chart.data.labels||[],m=1===p.length||1===u.data.length||o.chart.isCombo;void 0!==u.radius&&void 0===u.pointRadius&&(u.pointRadius=u.radius),void 0!==u.hitRadius&&void 0===u.pointHitRadius&&(u.pointHitRadius=u.hitRadius),a=f.getPixelForValue("object"==typeof c?c:NaN,e,d,m),r=i?h.getBasePixel():o.calculatePointY(c,e,d),t._xScale=f,t._yScale=h,t._datasetIndex=d,t._index=e,t._model={x:a,y:r,skip:l.skip||isNaN(a)||isNaN(r),radius:l.radius||n.getValueAtIndexOrDefault(u.pointRadius,e,g.radius),pointStyle:l.pointStyle||n.getValueAtIndexOrDefault(u.pointStyle,e,g.pointStyle),backgroundColor:o.getPointBackgroundColor(t,e),borderColor:o.getPointBorderColor(t,e),borderWidth:o.getPointBorderWidth(t,e),tension:s.dataset._model?s.dataset._model.tension:0,steppedLine:!!s.dataset._model&&s.dataset._model.steppedLine,hitRadius:l.hitRadius||n.getValueAtIndexOrDefault(u.pointHitRadius,e,g.hitRadius)}},calculatePointY:function(t,e,n){var i,a,r,o=this,s=o.chart,l=o.getMeta(),u=o.getScaleForId(l.yAxisID),d=0,c=0;if(u.options.stacked){for(i=0;i<n;i++)if(a=s.data.datasets[i],r=s.getDatasetMeta(i),"line"===r.type&&r.yAxisID===u.id&&s.isDatasetVisible(i)){var h=Number(u.getRightValue(a.data[e]));h<0?c+=h||0:d+=h||0}var f=Number(u.getRightValue(t));return f<0?u.getPixelForValue(c+f):u.getPixelForValue(d+f)}return u.getPixelForValue(t)},updateBezierControlPoints:function(){function t(t,e,n){return Math.max(Math.min(t,n),e)}var e,i,a,r,o,s=this,l=s.getMeta(),u=s.chart.chartArea,d=l.data||[];if(l.dataset._model.spanGaps&&(d=d.filter(function(t){return!t._model.skip})),"monotone"===l.dataset._model.cubicInterpolationMode)n.splineCurveMonotone(d);else for(e=0,i=d.length;e<i;++e)a=d[e],r=a._model,o=n.splineCurve(n.previousItem(d,e)._model,r,n.nextItem(d,e)._model,l.dataset._model.tension),r.controlPointPreviousX=o.previous.x,r.controlPointPreviousY=o.previous.y,r.controlPointNextX=o.next.x,r.controlPointNextY=o.next.y;if(s.chart.options.elements.line.capBezierPoints)for(e=0,i=d.length;e<i;++e)r=d[e]._model,r.controlPointPreviousX=t(r.controlPointPreviousX,u.left,u.right),r.controlPointPreviousY=t(r.controlPointPreviousY,u.top,u.bottom),r.controlPointNextX=t(r.controlPointNextX,u.left,u.right),r.controlPointNextY=t(r.controlPointNextY,u.top,u.bottom)},draw:function(){var n=this,i=n.chart,a=n.getMeta(),r=a.data||[],o=i.chartArea,s=r.length,l=0;for(t.canvasHelpers.clipArea(i.ctx,o),e(n.getDataset(),i.options)&&a.dataset.draw(),t.canvasHelpers.unclipArea(i.ctx);l<s;++l)r[l].draw(o)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},r=t._model;r.radius=a.hoverRadius||n.getValueAtIndexOrDefault(e.pointHoverRadius,i,this.chart.options.elements.point.hoverRadius),r.backgroundColor=a.hoverBackgroundColor||n.getValueAtIndexOrDefault(e.pointHoverBackgroundColor,i,n.getHoverColor(r.backgroundColor)),r.borderColor=a.hoverBorderColor||n.getValueAtIndexOrDefault(e.pointHoverBorderColor,i,n.getHoverColor(r.borderColor)),r.borderWidth=a.hoverBorderWidth||n.getValueAtIndexOrDefault(e.pointHoverBorderWidth,i,r.borderWidth)},removeHoverStyle:function(t){var e=this,i=e.chart.data.datasets[t._datasetIndex],a=t._index,r=t.custom||{},o=t._model;void 0!==i.radius&&void 0===i.pointRadius&&(i.pointRadius=i.radius),o.radius=r.radius||n.getValueAtIndexOrDefault(i.pointRadius,a,e.chart.options.elements.point.radius),o.backgroundColor=e.getPointBackgroundColor(t,a),o.borderColor=e.getPointBorderColor(t,a),o.borderWidth=e.getPointBorderWidth(t,a)}})}},{}],19:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.polarArea={scale:{type:"radialLinear",angleLines:{display:!1},gridLines:{circular:!0},pointLabels:{display:!1},ticks:{beginAtZero:!0}},animation:{animateRotate:!0,animateScale:!0},startAngle:-.5*Math.PI,aspectRatio:1,legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var r=0;r<i[0].data.length;++r)e.push('<li><span style="background-color:'+i[0].backgroundColor[r]+'"></span>'),a[r]&&e.push(a[r]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var n=t.data;return n.labels.length&&n.datasets.length?n.labels.map(function(i,a){var r=t.getDatasetMeta(0),o=n.datasets[0],s=r.data[a],l=s.custom||{},u=e.getValueAtIndexOrDefault,d=t.options.elements.arc,c=l.backgroundColor?l.backgroundColor:u(o.backgroundColor,a,d.backgroundColor),h=l.borderColor?l.borderColor:u(o.borderColor,a,d.borderColor),f=l.borderWidth?l.borderWidth:u(o.borderWidth,a,d.borderWidth);return{text:i,fillStyle:c,strokeStyle:h,lineWidth:f,hidden:isNaN(o.data[a])||r.data[a].hidden,index:a}}):[]}},onClick:function(t,e){var n,i,a,r=e.index,o=this.chart;for(n=0,i=(o.data.datasets||[]).length;n<i;++n)a=o.getDatasetMeta(n),a.data[r].hidden=!a.data[r].hidden;o.update()}},tooltips:{callbacks:{title:function(){
13
- return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}},t.controllers.polarArea=t.DatasetController.extend({dataElementType:t.elements.Arc,linkScales:e.noop,update:function(t){var n=this,i=n.chart,a=i.chartArea,r=n.getMeta(),o=i.options,s=o.elements.arc,l=Math.min(a.right-a.left,a.bottom-a.top);i.outerRadius=Math.max((l-s.borderWidth/2)/2,0),i.innerRadius=Math.max(o.cutoutPercentage?i.outerRadius/100*o.cutoutPercentage:1,0),i.radiusLength=(i.outerRadius-i.innerRadius)/i.getVisibleDatasetCount(),n.outerRadius=i.outerRadius-i.radiusLength*n.index,n.innerRadius=n.outerRadius-i.radiusLength,r.count=n.countVisibleElements(),e.each(r.data,function(e,i){n.updateElement(e,i,t)})},updateElement:function(t,n,i){for(var a=this,r=a.chart,o=a.getDataset(),s=r.options,l=s.animation,u=r.scale,d=e.getValueAtIndexOrDefault,c=r.data.labels,h=a.calculateCircumference(o.data[n]),f=u.xCenter,g=u.yCenter,p=0,m=a.getMeta(),v=0;v<n;++v)isNaN(o.data[v])||m.data[v].hidden||++p;var y=s.startAngle,b=t.hidden?0:u.getDistanceFromCenterForValue(o.data[n]),x=y+h*p,_=x+(t.hidden?0:h),k=l.animateScale?0:u.getDistanceFromCenterForValue(o.data[n]);e.extend(t,{_datasetIndex:a.index,_index:n,_scale:u,_model:{x:f,y:g,innerRadius:0,outerRadius:i?k:b,startAngle:i&&l.animateRotate?y:x,endAngle:i&&l.animateRotate?y:_,label:d(c,n,c[n])}}),a.removeHoverStyle(t),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},countVisibleElements:function(){var t=this.getDataset(),n=this.getMeta(),i=0;return e.each(n.data,function(e,n){isNaN(t.data[n])||e.hidden||i++}),i},calculateCircumference:function(t){var e=this.getMeta().count;return e>0&&!isNaN(t)?2*Math.PI/e:0}})}},{}],20:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.radar={aspectRatio:1,scale:{type:"radialLinear"},elements:{line:{tension:0}}},t.controllers.radar=t.DatasetController.extend({datasetElementType:t.elements.Line,dataElementType:t.elements.Point,linkScales:e.noop,update:function(t){var n=this,i=n.getMeta(),a=i.dataset,r=i.data,o=a.custom||{},s=n.getDataset(),l=n.chart.options.elements.line,u=n.chart.scale;void 0!==s.tension&&void 0===s.lineTension&&(s.lineTension=s.tension),e.extend(i.dataset,{_datasetIndex:n.index,_scale:u,_children:r,_loop:!0,_model:{tension:o.tension?o.tension:e.getValueOrDefault(s.lineTension,l.tension),backgroundColor:o.backgroundColor?o.backgroundColor:s.backgroundColor||l.backgroundColor,borderWidth:o.borderWidth?o.borderWidth:s.borderWidth||l.borderWidth,borderColor:o.borderColor?o.borderColor:s.borderColor||l.borderColor,fill:o.fill?o.fill:void 0!==s.fill?s.fill:l.fill,borderCapStyle:o.borderCapStyle?o.borderCapStyle:s.borderCapStyle||l.borderCapStyle,borderDash:o.borderDash?o.borderDash:s.borderDash||l.borderDash,borderDashOffset:o.borderDashOffset?o.borderDashOffset:s.borderDashOffset||l.borderDashOffset,borderJoinStyle:o.borderJoinStyle?o.borderJoinStyle:s.borderJoinStyle||l.borderJoinStyle}}),i.dataset.pivot(),e.each(r,function(e,i){n.updateElement(e,i,t)},n),n.updateBezierControlPoints()},updateElement:function(t,n,i){var a=this,r=t.custom||{},o=a.getDataset(),s=a.chart.scale,l=a.chart.options.elements.point,u=s.getPointPositionForValue(n,o.data[n]);void 0!==o.radius&&void 0===o.pointRadius&&(o.pointRadius=o.radius),void 0!==o.hitRadius&&void 0===o.pointHitRadius&&(o.pointHitRadius=o.hitRadius),e.extend(t,{_datasetIndex:a.index,_index:n,_scale:s,_model:{x:i?s.xCenter:u.x,y:i?s.yCenter:u.y,tension:r.tension?r.tension:e.getValueOrDefault(o.lineTension,a.chart.options.elements.line.tension),radius:r.radius?r.radius:e.getValueAtIndexOrDefault(o.pointRadius,n,l.radius),backgroundColor:r.backgroundColor?r.backgroundColor:e.getValueAtIndexOrDefault(o.pointBackgroundColor,n,l.backgroundColor),borderColor:r.borderColor?r.borderColor:e.getValueAtIndexOrDefault(o.pointBorderColor,n,l.borderColor),borderWidth:r.borderWidth?r.borderWidth:e.getValueAtIndexOrDefault(o.pointBorderWidth,n,l.borderWidth),pointStyle:r.pointStyle?r.pointStyle:e.getValueAtIndexOrDefault(o.pointStyle,n,l.pointStyle),hitRadius:r.hitRadius?r.hitRadius:e.getValueAtIndexOrDefault(o.pointHitRadius,n,l.hitRadius)}}),t._model.skip=r.skip?r.skip:isNaN(t._model.x)||isNaN(t._model.y)},updateBezierControlPoints:function(){var t=this.chart.chartArea,n=this.getMeta();e.each(n.data,function(i,a){var r=i._model,o=e.splineCurve(e.previousItem(n.data,a,!0)._model,r,e.nextItem(n.data,a,!0)._model,r.tension);r.controlPointPreviousX=Math.max(Math.min(o.previous.x,t.right),t.left),r.controlPointPreviousY=Math.max(Math.min(o.previous.y,t.bottom),t.top),r.controlPointNextX=Math.max(Math.min(o.next.x,t.right),t.left),r.controlPointNextY=Math.max(Math.min(o.next.y,t.bottom),t.top),i.pivot()})},setHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,r=t._model;r.radius=i.hoverRadius?i.hoverRadius:e.getValueAtIndexOrDefault(n.pointHoverRadius,a,this.chart.options.elements.point.hoverRadius),r.backgroundColor=i.hoverBackgroundColor?i.hoverBackgroundColor:e.getValueAtIndexOrDefault(n.pointHoverBackgroundColor,a,e.getHoverColor(r.backgroundColor)),r.borderColor=i.hoverBorderColor?i.hoverBorderColor:e.getValueAtIndexOrDefault(n.pointHoverBorderColor,a,e.getHoverColor(r.borderColor)),r.borderWidth=i.hoverBorderWidth?i.hoverBorderWidth:e.getValueAtIndexOrDefault(n.pointHoverBorderWidth,a,r.borderWidth)},removeHoverStyle:function(t){var n=this.chart.data.datasets[t._datasetIndex],i=t.custom||{},a=t._index,r=t._model,o=this.chart.options.elements.point;r.radius=i.radius?i.radius:e.getValueAtIndexOrDefault(n.pointRadius,a,o.radius),r.backgroundColor=i.backgroundColor?i.backgroundColor:e.getValueAtIndexOrDefault(n.pointBackgroundColor,a,o.backgroundColor),r.borderColor=i.borderColor?i.borderColor:e.getValueAtIndexOrDefault(n.pointBorderColor,a,o.borderColor),r.borderWidth=i.borderWidth?i.borderWidth:e.getValueAtIndexOrDefault(n.pointBorderWidth,a,o.borderWidth)}})}},{}],21:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.animation={duration:1e3,easing:"easeOutQuart",onProgress:e.noop,onComplete:e.noop},t.Animation=t.Element.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),t.animationService={frameDuration:17,animations:[],dropFrames:0,request:null,addAnimation:function(t,e,n,i){var a,r,o=this.animations;for(e.chart=t,i||(t.animating=!0),a=0,r=o.length;a<r;++a)if(o[a].chart===t)return void(o[a]=e);o.push(e),1===o.length&&this.requestAnimationFrame()},cancelAnimation:function(t){var n=e.findIndex(this.animations,function(e){return e.chart===t});n!==-1&&(this.animations.splice(n,1),t.animating=!1)},requestAnimationFrame:function(){var t=this;null===t.request&&(t.request=e.requestAnimFrame.call(window,function(){t.request=null,t.startDigest()}))},startDigest:function(){var t=this,e=Date.now(),n=0;t.dropFrames>1&&(n=Math.floor(t.dropFrames),t.dropFrames=t.dropFrames%1),t.advance(1+n);var i=Date.now();t.dropFrames+=(i-e)/t.frameDuration,t.animations.length>0&&t.requestAnimationFrame()},advance:function(t){for(var n,i,a=this.animations,r=0;r<a.length;)n=a[r],i=n.chart,n.currentStep=(n.currentStep||0)+t,n.currentStep=Math.min(n.currentStep,n.numSteps),e.callback(n.render,[i,n],i),e.callback(n.onAnimationProgress,[n],i),n.currentStep>=n.numSteps?(e.callback(n.onAnimationComplete,[n],i),i.animating=!1,a.splice(r,1)):++r}},Object.defineProperty(t.Animation.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(t.Animation.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}})}},{}],22:[function(t,e,n){"use strict";e.exports=function(t){var e=t.canvasHelpers={};e.drawPoint=function(e,n,i,a,r){var o,s,l,u,d,c;if("object"==typeof n&&(o=n.toString(),"[object HTMLImageElement]"===o||"[object HTMLCanvasElement]"===o))return void e.drawImage(n,a-n.width/2,r-n.height/2,n.width,n.height);if(!(isNaN(i)||i<=0)){switch(n){default:e.beginPath(),e.arc(a,r,i,0,2*Math.PI),e.closePath(),e.fill();break;case"triangle":e.beginPath(),s=3*i/Math.sqrt(3),d=s*Math.sqrt(3)/2,e.moveTo(a-s/2,r+d/3),e.lineTo(a+s/2,r+d/3),e.lineTo(a,r-2*d/3),e.closePath(),e.fill();break;case"rect":c=1/Math.SQRT2*i,e.beginPath(),e.fillRect(a-c,r-c,2*c,2*c),e.strokeRect(a-c,r-c,2*c,2*c);break;case"rectRounded":var h=i/Math.SQRT2,f=a-h,g=r-h,p=Math.SQRT2*i;t.helpers.drawRoundedRectangle(e,f,g,p,p,i/2),e.fill();break;case"rectRot":c=1/Math.SQRT2*i,e.beginPath(),e.moveTo(a-c,r),e.lineTo(a,r+c),e.lineTo(a+c,r),e.lineTo(a,r-c),e.closePath(),e.fill();break;case"cross":e.beginPath(),e.moveTo(a,r+i),e.lineTo(a,r-i),e.moveTo(a-i,r),e.lineTo(a+i,r),e.closePath();break;case"crossRot":e.beginPath(),l=Math.cos(Math.PI/4)*i,u=Math.sin(Math.PI/4)*i,e.moveTo(a-l,r-u),e.lineTo(a+l,r+u),e.moveTo(a-l,r+u),e.lineTo(a+l,r-u),e.closePath();break;case"star":e.beginPath(),e.moveTo(a,r+i),e.lineTo(a,r-i),e.moveTo(a-i,r),e.lineTo(a+i,r),l=Math.cos(Math.PI/4)*i,u=Math.sin(Math.PI/4)*i,e.moveTo(a-l,r-u),e.lineTo(a+l,r+u),e.moveTo(a-l,r+u),e.lineTo(a+l,r-u),e.closePath();break;case"line":e.beginPath(),e.moveTo(a-i,r),e.lineTo(a+i,r),e.closePath();break;case"dash":e.beginPath(),e.moveTo(a,r),e.lineTo(a+i,r),e.closePath()}e.stroke()}},e.clipArea=function(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()},e.unclipArea=function(t){t.restore()},e.lineTo=function(t,e,n,i){return n.steppedLine?("after"===n.steppedLine?t.lineTo(e.x,n.y):t.lineTo(n.x,e.y),void t.lineTo(n.x,n.y)):n.tension?void t.bezierCurveTo(i?e.controlPointPreviousX:e.controlPointNextX,i?e.controlPointPreviousY:e.controlPointNextY,i?n.controlPointNextX:n.controlPointPreviousX,i?n.controlPointNextY:n.controlPointPreviousY,n.x,n.y):void t.lineTo(n.x,n.y)},t.helpers.canvas=e}},{}],23:[function(t,e,n){"use strict";e.exports=function(t){function e(e){e=e||{};var n=e.data=e.data||{};return n.datasets=n.datasets||[],n.labels=n.labels||[],e.options=a.configMerge(t.defaults.global,t.defaults[e.type],e.options||{}),e}function n(t){var e=t.options;e.scale?t.scale.options=e.scale:e.scales&&e.scales.xAxes.concat(e.scales.yAxes).forEach(function(e){t.scales[e.id].options=e}),t.tooltip._options=e.tooltips}function i(t){return"top"===t||"bottom"===t}var a=t.helpers,r=t.plugins,o=t.platform;t.types={},t.instances={},t.controllers={},a.extend(t.prototype,{construct:function(n,i){var r=this;i=e(i);var s=o.acquireContext(n,i),l=s&&s.canvas,u=l&&l.height,d=l&&l.width;return r.id=a.uid(),r.ctx=s,r.canvas=l,r.config=i,r.width=d,r.height=u,r.aspectRatio=u?d/u:null,r.options=i.options,r._bufferedRender=!1,r.chart=r,r.controller=r,t.instances[r.id]=r,Object.defineProperty(r,"data",{get:function(){return r.config.data},set:function(t){r.config.data=t}}),s&&l?(r.initialize(),void r.update()):void console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return r.notify(t,"beforeInit"),a.retinaScale(t),t.bindEvents(),t.options.responsive&&t.resize(!0),t.ensureScalesHaveIDs(),t.buildScales(),t.initToolTip(),r.notify(t,"afterInit"),t},clear:function(){return a.clear(this),this},stop:function(){return t.animationService.cancelAnimation(this),this},resize:function(t){var e=this,n=e.options,i=e.canvas,o=n.maintainAspectRatio&&e.aspectRatio||null,s=Math.floor(a.getMaximumWidth(i)),l=Math.floor(o?s/o:a.getMaximumHeight(i));if((e.width!==s||e.height!==l)&&(i.width=e.width=s,i.height=e.height=l,i.style.width=s+"px",i.style.height=l+"px",a.retinaScale(e),!t)){var u={width:s,height:l};r.notify(e,"resize",[u]),e.options.onResize&&e.options.onResize(e,u),e.stop(),e.update(e.options.responsiveAnimationDuration)}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},n=t.scale;a.each(e.xAxes,function(t,e){t.id=t.id||"x-axis-"+e}),a.each(e.yAxes,function(t,e){t.id=t.id||"y-axis-"+e}),n&&(n.id=n.id||"scale")},buildScales:function(){var e=this,n=e.options,r=e.scales={},o=[];n.scales&&(o=o.concat((n.scales.xAxes||[]).map(function(t){return{options:t,dtype:"category",dposition:"bottom"}}),(n.scales.yAxes||[]).map(function(t){return{options:t,dtype:"linear",dposition:"left"}}))),n.scale&&o.push({options:n.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),a.each(o,function(n){var o=n.options,s=a.getValueOrDefault(o.type,n.dtype),l=t.scaleService.getScaleConstructor(s);if(l){i(o.position)!==i(n.dposition)&&(o.position=n.dposition);var u=new l({id:o.id,options:o,ctx:e.ctx,chart:e});r[u.id]=u,n.isDefault&&(e.scale=u)}}),t.scaleService.addScalesToLayout(this)},buildOrUpdateControllers:function(){var e=this,n=[],i=[];if(a.each(e.data.datasets,function(a,r){var o=e.getDatasetMeta(r);if(o.type||(o.type=a.type||e.config.type),n.push(o.type),o.controller)o.controller.updateIndex(r);else{var s=t.controllers[o.type];if(void 0===s)throw new Error('"'+o.type+'" is not a chart type.');o.controller=new s(e,r),i.push(o.controller)}},e),n.length>1)for(var r=1;r<n.length;r++)if(n[r]!==n[r-1]){e.isCombo=!0;break}return i},resetElements:function(){var t=this;a.each(t.data.datasets,function(e,n){t.getDatasetMeta(n).controller.reset()},t)},reset:function(){this.resetElements(),this.tooltip.initialize()},update:function(t,e){var i=this;if(n(i),r.notify(i,"beforeUpdate")!==!1){i.tooltip._data=i.data;var o=i.buildOrUpdateControllers();a.each(i.data.datasets,function(t,e){i.getDatasetMeta(e).controller.buildOrUpdateElements()},i),i.updateLayout(),a.each(o,function(t){t.reset()}),i.updateDatasets(),r.notify(i,"afterUpdate"),i._bufferedRender?i._bufferedRequest={lazy:e,duration:t}:i.render(t,e)}},updateLayout:function(){var e=this;r.notify(e,"beforeLayout")!==!1&&(t.layoutService.update(this,this.width,this.height),r.notify(e,"afterScaleUpdate"),r.notify(e,"afterLayout"))},updateDatasets:function(){var t=this;if(r.notify(t,"beforeDatasetsUpdate")!==!1){for(var e=0,n=t.data.datasets.length;e<n;++e)t.updateDataset(e);r.notify(t,"afterDatasetsUpdate")}},updateDataset:function(t){var e=this,n=e.getDatasetMeta(t),i={meta:n,index:t};r.notify(e,"beforeDatasetUpdate",[i])!==!1&&(n.controller.update(),r.notify(e,"afterDatasetUpdate",[i]))},render:function(e,n){var i=this;if(r.notify(i,"beforeRender")!==!1){var o=i.options.animation,s=function(t){r.notify(i,"afterRender"),a.callback(o&&o.onComplete,[t],i)};if(o&&("undefined"!=typeof e&&0!==e||"undefined"==typeof e&&0!==o.duration)){var l=new t.Animation({numSteps:(e||o.duration)/16.66,easing:o.easing,render:function(t,e){var n=a.easingEffects[e.easing],i=e.currentStep,r=i/e.numSteps;t.draw(n(r),r,i)},onAnimationProgress:o.onProgress,onAnimationComplete:s});t.animationService.addAnimation(i,l,e,n)}else i.draw(),s(new t.Animation({numSteps:0,chart:i}));return i}},draw:function(t){var e=this;e.clear(),void 0!==t&&null!==t||(t=1),e.transition(t),r.notify(e,"beforeDraw",[t])!==!1&&(a.each(e.boxes,function(t){t.draw(e.chartArea)},e),e.scale&&e.scale.draw(),e.drawDatasets(t),e.tooltip.draw(),r.notify(e,"afterDraw",[t]))},transition:function(t){for(var e=this,n=0,i=(e.data.datasets||[]).length;n<i;++n)e.isDatasetVisible(n)&&e.getDatasetMeta(n).controller.transition(t);e.tooltip.transition(t)},drawDatasets:function(t){var e=this;if(r.notify(e,"beforeDatasetsDraw",[t])!==!1){for(var n=(e.data.datasets||[]).length-1;n>=0;--n)e.isDatasetVisible(n)&&e.drawDataset(n,t);r.notify(e,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var n=this,i=n.getDatasetMeta(t),a={meta:i,index:t,easingValue:e};r.notify(n,"beforeDatasetDraw",[a])!==!1&&(i.controller.draw(e),r.notify(n,"afterDatasetDraw",[a]))},getElementAtEvent:function(e){return t.Interaction.modes.single(this,e)},getElementsAtEvent:function(e){return t.Interaction.modes.label(this,e,{intersect:!0})},getElementsAtXAxis:function(e){return t.Interaction.modes["x-axis"](this,e,{intersect:!0})},getElementsAtEventForMode:function(e,n,i){var a=t.Interaction.modes[n];return"function"==typeof a?a(this,e,i):[]},getDatasetAtEvent:function(e){return t.Interaction.modes.dataset(this,e,{intersect:!0})},getDatasetMeta:function(t){var e=this,n=e.data.datasets[t];n._meta||(n._meta={});var i=n._meta[e.id];return i||(i=n._meta[e.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null}),i},getVisibleDatasetCount:function(){for(var t=0,e=0,n=this.data.datasets.length;e<n;++e)this.isDatasetVisible(e)&&t++;return t},isDatasetVisible:function(t){var e=this.getDatasetMeta(t);return"boolean"==typeof e.hidden?!e.hidden:!this.data.datasets[t].hidden},generateLegend:function(){return this.options.legendCallback(this)},destroy:function(){var e,n,i,s=this,l=s.canvas;for(s.stop(),n=0,i=s.data.datasets.length;n<i;++n)e=s.getDatasetMeta(n),e.controller&&(e.controller.destroy(),e.controller=null);l&&(s.unbindEvents(),a.clear(s),o.releaseContext(s.ctx),s.canvas=null,s.ctx=null),r.notify(s,"destroy"),delete t.instances[s.id]},toBase64Image:function(){return this.canvas.toDataURL.apply(this.canvas,arguments)},initToolTip:function(){var e=this;e.tooltip=new t.Tooltip({_chart:e,_chartInstance:e,_data:e.data,_options:e.options.tooltips},e),e.tooltip.initialize()},bindEvents:function(){var t=this,e=t._listeners={},n=function(){t.eventHandler.apply(t,arguments)};a.each(t.options.events,function(i){o.addEventListener(t,i,n),e[i]=n}),t.options.responsive&&(n=function(){t.resize()},o.addEventListener(t,"resize",n),e.resize=n)},unbindEvents:function(){var t=this,e=t._listeners;e&&(delete t._listeners,a.each(e,function(e,n){o.removeEventListener(t,n,e)}))},updateHoverStyle:function(t,e,n){var i,a,r,o=n?"setHoverStyle":"removeHoverStyle";for(a=0,r=t.length;a<r;++a)i=t[a],i&&this.getDatasetMeta(i._datasetIndex).controller[o](i)},eventHandler:function(t){var e=this,n=e.tooltip;if(r.notify(e,"beforeEvent",[t])!==!1){e._bufferedRender=!0,e._bufferedRequest=null;var i=e.handleEvent(t);i|=n&&n.handleEvent(t),r.notify(e,"afterEvent",[t]);var a=e._bufferedRequest;return a?e.render(a.duration,a.lazy):i&&!e.animating&&(e.stop(),e.render(e.options.hover.animationDuration,!0)),e._bufferedRender=!1,e._bufferedRequest=null,e}},handleEvent:function(t){var e=this,n=e.options||{},i=n.hover,r=!1;return e.lastActive=e.lastActive||[],"mouseout"===t.type?e.active=[]:e.active=e.getElementsAtEventForMode(t,i.mode,i),i.onHover&&i.onHover.call(e,t.native,e.active),"mouseup"!==t.type&&"click"!==t.type||n.onClick&&n.onClick.call(e,t.native,e.active),e.lastActive.length&&e.updateHoverStyle(e.lastActive,i.mode,!1),e.active.length&&i.mode&&e.updateHoverStyle(e.active,i.mode,!0),r=!a.arrayEquals(e.active,e.lastActive),e.lastActive=e.active,r}}),t.Controller=t}},{}],24:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return t._chartjs?void t._chartjs.listeners.push(e):(Object.defineProperty(t,"_chartjs",{configurable:!0,enumerable:!1,value:{listeners:[e]}}),void a.forEach(function(e){var n="onData"+e.charAt(0).toUpperCase()+e.slice(1),a=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:function(){var e=Array.prototype.slice.call(arguments),r=a.apply(this,e);return i.each(t._chartjs.listeners,function(t){"function"==typeof t[n]&&t[n].apply(t,e)}),r}})}))}function n(t,e){var n=t._chartjs;if(n){var i=n.listeners,r=i.indexOf(e);r!==-1&&i.splice(r,1),i.length>0||(a.forEach(function(e){delete t[e]}),delete t._chartjs)}}var i=t.helpers,a=["push","pop","shift","splice","unshift"];t.DatasetController=function(t,e){this.initialize(t,e)},i.extend(t.DatasetController.prototype,{datasetElementType:null,dataElementType:null,initialize:function(t,e){var n=this;n.chart=t,n.index=e,n.linkScales(),n.addElements()},updateIndex:function(t){this.index=t},linkScales:function(){var t=this,e=t.getMeta(),n=t.getDataset();null===e.xAxisID&&(e.xAxisID=n.xAxisID||t.chart.options.scales.xAxes[0].id),null===e.yAxisID&&(e.yAxisID=n.yAxisID||t.chart.options.scales.yAxes[0].id)},getDataset:function(){return this.chart.data.datasets[this.index]},getMeta:function(){return this.chart.getDatasetMeta(this.index)},getScaleForId:function(t){return this.chart.scales[t]},reset:function(){this.update(!0)},destroy:function(){this._data&&n(this._data,this)},createMetaDataset:function(){var t=this,e=t.datasetElementType;return e&&new e({_chart:t.chart,_datasetIndex:t.index})},createMetaData:function(t){var e=this,n=e.dataElementType;return n&&new n({_chart:e.chart,_datasetIndex:e.index,_index:t})},addElements:function(){var t,e,n=this,i=n.getMeta(),a=n.getDataset().data||[],r=i.data;for(t=0,e=a.length;t<e;++t)r[t]=r[t]||n.createMetaData(t);i.dataset=i.dataset||n.createMetaDataset()},addElementAndReset:function(t){var e=this.createMetaData(t);this.getMeta().data.splice(t,0,e),this.updateElement(e,t,!0)},buildOrUpdateElements:function(){var t=this,i=t.getDataset(),a=i.data||(i.data=[]);t._data!==a&&(t._data&&n(t._data,t),e(a,t),t._data=a),t.resyncElements()},update:i.noop,transition:function(t){for(var e=this.getMeta(),n=e.data||[],i=n.length,a=0;a<i;++a)n[a].transition(t);e.dataset&&e.dataset.transition(t)},draw:function(){var t=this.getMeta(),e=t.data||[],n=e.length,i=0;for(t.dataset&&t.dataset.draw();i<n;++i)e[i].draw()},removeHoverStyle:function(t,e){var n=this.chart.data.datasets[t._datasetIndex],a=t._index,r=t.custom||{},o=i.getValueAtIndexOrDefault,s=t._model;s.backgroundColor=r.backgroundColor?r.backgroundColor:o(n.backgroundColor,a,e.backgroundColor),s.borderColor=r.borderColor?r.borderColor:o(n.borderColor,a,e.borderColor),s.borderWidth=r.borderWidth?r.borderWidth:o(n.borderWidth,a,e.borderWidth)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t._index,a=t.custom||{},r=i.getValueAtIndexOrDefault,o=i.getHoverColor,s=t._model;s.backgroundColor=a.hoverBackgroundColor?a.hoverBackgroundColor:r(e.hoverBackgroundColor,n,o(s.backgroundColor)),s.borderColor=a.hoverBorderColor?a.hoverBorderColor:r(e.hoverBorderColor,n,o(s.borderColor)),s.borderWidth=a.hoverBorderWidth?a.hoverBorderWidth:r(e.hoverBorderWidth,n,s.borderWidth)},resyncElements:function(){var t=this,e=t.getMeta(),n=t.getDataset().data,i=e.data.length,a=n.length;a<i?e.data.splice(a,i-a):a>i&&t.insertElements(i,a-i)},insertElements:function(t,e){for(var n=0;n<e;++n)this.addElementAndReset(t+n)},onDataPush:function(){this.insertElements(this.getDataset().data.length-1,arguments.length)},onDataPop:function(){this.getMeta().data.pop()},onDataShift:function(){this.getMeta().data.shift()},onDataSplice:function(t,e){this.getMeta().data.splice(t,e),this.insertElements(t,arguments.length-2)},onDataUnshift:function(){this.insertElements(0,arguments.length)}}),t.DatasetController.extend=i.inherits}},{}],25:[function(t,e,n){"use strict";var i=t(2);e.exports=function(t){function e(t,e,n,a){var r,o,s,l,u,d,c,h,f,g=Object.keys(n);for(r=0,o=g.length;r<o;++r)if(s=g[r],d=n[s],e.hasOwnProperty(s)||(e[s]=d),l=e[s],l!==d&&"_"!==s[0]){if(t.hasOwnProperty(s)||(t[s]=l),u=t[s],c=typeof d,c===typeof u)if("string"===c){if(h=i(u),h.valid&&(f=i(d),f.valid)){e[s]=f.mix(h,a).rgbString();continue}}else if("number"===c&&isFinite(u)&&isFinite(d)){e[s]=u+(d-u)*a;continue}e[s]=d}}var n=t.helpers;t.elements={},t.Element=function(t){n.extend(this,t),this.initialize.apply(this,arguments)},n.extend(t.Element.prototype,{initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=n.clone(t._model)),t._start={},t},transition:function(t){var n=this,i=n._model,a=n._start,r=n._view;return i&&1!==t?(r||(r=n._view={}),a||(a=n._start={}),e(a,r,i,t),n):(n._view=i,n._start=null,n)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return n.isNumber(this._model.x)&&n.isNumber(this._model.y)}}),t.Element.extend=n.inherits}},{2:2}],26:[function(t,e,n){"use strict";var i=t(2);e.exports=function(t){function e(t,e,n){var i;return"string"==typeof t?(i=parseInt(t,10),t.indexOf("%")!==-1&&(i=i/100*e.parentNode[n])):i=t,i}function n(t){return void 0!==t&&null!==t&&"none"!==t}function a(t,i,a){var r=document.defaultView,o=t.parentNode,s=r.getComputedStyle(t)[i],l=r.getComputedStyle(o)[i],u=n(s),d=n(l),c=Number.POSITIVE_INFINITY;return u||d?Math.min(u?e(s,t,a):c,d?e(l,o,a):c):"none"}var r=t.helpers={};r.each=function(t,e,n,i){var a,o;if(r.isArray(t))if(o=t.length,i)for(a=o-1;a>=0;a--)e.call(n,t[a],a);else for(a=0;a<o;a++)e.call(n,t[a],a);else if("object"==typeof t){var s=Object.keys(t);for(o=s.length,a=0;a<o;a++)e.call(n,t[s[a]],s[a])}},r.clone=function(t){var e={};return r.each(t,function(t,n){r.isArray(t)?e[n]=t.slice(0):"object"==typeof t&&null!==t?e[n]=r.clone(t):e[n]=t}),e},r.extend=function(t){for(var e=function(e,n){t[n]=e},n=1,i=arguments.length;n<i;n++)r.each(arguments[n],e);return t},r.configMerge=function(e){var n=r.clone(e);return r.each(Array.prototype.slice.call(arguments,1),function(e){r.each(e,function(e,i){var a=n.hasOwnProperty(i),o=a?n[i]:{};"scales"===i?n[i]=r.scaleMerge(o,e):"scale"===i?n[i]=r.configMerge(o,t.scaleService.getScaleDefaults(e.type),e):!a||"object"!=typeof o||r.isArray(o)||null===o||"object"!=typeof e||r.isArray(e)?n[i]=e:n[i]=r.configMerge(o,e)})}),n},r.scaleMerge=function(e,n){var i=r.clone(e);return r.each(n,function(e,n){"xAxes"===n||"yAxes"===n?i.hasOwnProperty(n)?r.each(e,function(e,a){var o=r.getValueOrDefault(e.type,"xAxes"===n?"category":"linear"),s=t.scaleService.getScaleDefaults(o);a>=i[n].length||!i[n][a].type?i[n].push(r.configMerge(s,e)):e.type&&e.type!==i[n][a].type?i[n][a]=r.configMerge(i[n][a],s,e):i[n][a]=r.configMerge(i[n][a],e)}):(i[n]=[],r.each(e,function(e){var a=r.getValueOrDefault(e.type,"xAxes"===n?"category":"linear");i[n].push(r.configMerge(t.scaleService.getScaleDefaults(a),e))})):i.hasOwnProperty(n)&&"object"==typeof i[n]&&null!==i[n]&&"object"==typeof e?i[n]=r.configMerge(i[n],e):i[n]=e}),i},r.getValueAtIndexOrDefault=function(t,e,n){return void 0===t||null===t?n:r.isArray(t)?e<t.length?t[e]:n:t},r.getValueOrDefault=function(t,e){return void 0===t?e:t},r.indexOf=Array.prototype.indexOf?function(t,e){return t.indexOf(e)}:function(t,e){for(var n=0,i=t.length;n<i;++n)if(t[n]===e)return n;return-1},r.where=function(t,e){if(r.isArray(t)&&Array.prototype.filter)return t.filter(e);var n=[];return r.each(t,function(t){e(t)&&n.push(t)}),n},r.findIndex=Array.prototype.findIndex?function(t,e,n){return t.findIndex(e,n)}:function(t,e,n){n=void 0===n?t:n;for(var i=0,a=t.length;i<a;++i)if(e.call(n,t[i],i,t))return i;return-1},r.findNextWhere=function(t,e,n){void 0!==n&&null!==n||(n=-1);for(var i=n+1;i<t.length;i++){var a=t[i];if(e(a))return a}},r.findPreviousWhere=function(t,e,n){void 0!==n&&null!==n||(n=t.length);for(var i=n-1;i>=0;i--){var a=t[i];if(e(a))return a}},r.inherits=function(t){var e=this,n=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},i=function(){this.constructor=n};return i.prototype=e.prototype,n.prototype=new i,n.extend=r.inherits,t&&r.extend(n.prototype,t),n.__super__=e.prototype,n},r.noop=function(){},r.uid=function(){var t=0;return function(){return t++}}(),r.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},r.almostEquals=function(t,e,n){return Math.abs(t-e)<n},r.almostWhole=function(t,e){var n=Math.round(t);return n-e<t&&n+e>t},r.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},r.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},r.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return t=+t,0===t||isNaN(t)?t:t>0?1:-1},r.log10=Math.log10?function(t){return Math.log10(t)}:function(t){return Math.log(t)/Math.LN10},r.toRadians=function(t){return t*(Math.PI/180)},r.toDegrees=function(t){return t*(180/Math.PI)},r.getAngleFromPoint=function(t,e){var n=e.x-t.x,i=e.y-t.y,a=Math.sqrt(n*n+i*i),r=Math.atan2(i,n);return r<-.5*Math.PI&&(r+=2*Math.PI),{angle:r,distance:a}},r.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},r.aliasPixel=function(t){return t%2===0?0:.5},r.splineCurve=function(t,e,n,i){var a=t.skip?e:t,r=e,o=n.skip?e:n,s=Math.sqrt(Math.pow(r.x-a.x,2)+Math.pow(r.y-a.y,2)),l=Math.sqrt(Math.pow(o.x-r.x,2)+Math.pow(o.y-r.y,2)),u=s/(s+l),d=l/(s+l);u=isNaN(u)?0:u,d=isNaN(d)?0:d;var c=i*u,h=i*d;return{previous:{x:r.x-c*(o.x-a.x),y:r.y-c*(o.y-a.y)},next:{x:r.x+h*(o.x-a.x),y:r.y+h*(o.y-a.y)}}},r.EPSILON=Number.EPSILON||1e-14,r.splineCurveMonotone=function(t){var e,n,i,a,o=(t||[]).map(function(t){return{model:t._model,deltaK:0,mK:0}}),s=o.length;for(e=0;e<s;++e)if(i=o[e],!i.model.skip){if(n=e>0?o[e-1]:null,a=e<s-1?o[e+1]:null,a&&!a.model.skip){var l=a.model.x-i.model.x;i.deltaK=0!==l?(a.model.y-i.model.y)/l:0}!n||n.model.skip?i.mK=i.deltaK:!a||a.model.skip?i.mK=n.deltaK:this.sign(n.deltaK)!==this.sign(i.deltaK)?i.mK=0:i.mK=(n.deltaK+i.deltaK)/2}var u,d,c,h;for(e=0;e<s-1;++e)i=o[e],a=o[e+1],i.model.skip||a.model.skip||(r.almostEquals(i.deltaK,0,this.EPSILON)?i.mK=a.mK=0:(u=i.mK/i.deltaK,d=a.mK/i.deltaK,h=Math.pow(u,2)+Math.pow(d,2),h<=9||(c=3/Math.sqrt(h),i.mK=u*c*i.deltaK,a.mK=d*c*i.deltaK)));var f;for(e=0;e<s;++e)i=o[e],i.model.skip||(n=e>0?o[e-1]:null,a=e<s-1?o[e+1]:null,n&&!n.model.skip&&(f=(i.model.x-n.model.x)/3,i.model.controlPointPreviousX=i.model.x-f,i.model.controlPointPreviousY=i.model.y-f*i.mK),a&&!a.model.skip&&(f=(a.model.x-i.model.x)/3,i.model.controlPointNextX=i.model.x+f,i.model.controlPointNextY=i.model.y+f*i.mK))},r.nextItem=function(t,e,n){return n?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},r.previousItem=function(t,e,n){return n?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},r.niceNum=function(t,e){var n,i=Math.floor(r.log10(t)),a=t/Math.pow(10,i);return n=e?a<1.5?1:a<3?2:a<7?5:10:a<=1?1:a<=2?2:a<=5?5:10,n*Math.pow(10,i)};var o=r.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===(t/=1)?1:(n||(n=.3),i<Math.abs(1)?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),-(i*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/n)))},easeOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===(t/=1)?1:(n||(n=.3),i<Math.abs(1)?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),i*Math.pow(2,-10*t)*Math.sin((1*t-e)*(2*Math.PI)/n)+1)},easeInOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:2===(t/=.5)?1:(n||(n=1*(.3*1.5)),i<Math.abs(1)?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),t<1?-.5*(i*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/n)):i*Math.pow(2,-10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/n)*.5+1)},easeInBack:function(t){var e=1.70158;return 1*(t/=1)*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return 1*((t=t/1-1)*t*((e+1)*t+e)+1)},easeInOutBack:function(t){var e=1.70158;
14
- return(t/=.5)<1?.5*(t*t*(((e*=1.525)+1)*t-e)):.5*((t-=2)*t*(((e*=1.525)+1)*t+e)+2)},easeInBounce:function(t){return 1-o.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?1*(7.5625*t*t):t<2/2.75?1*(7.5625*(t-=1.5/2.75)*t+.75):t<2.5/2.75?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return t<.5?.5*o.easeInBounce(2*t):.5*o.easeOutBounce(2*t-1)+.5}};r.requestAnimFrame=function(){return"undefined"==typeof window?function(t){t()}:window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),r.getRelativePosition=function(t,e){var n,i,a=t.originalEvent||t,o=t.currentTarget||t.srcElement,s=o.getBoundingClientRect(),l=a.touches;l&&l.length>0?(n=l[0].clientX,i=l[0].clientY):(n=a.clientX,i=a.clientY);var u=parseFloat(r.getStyle(o,"padding-left")),d=parseFloat(r.getStyle(o,"padding-top")),c=parseFloat(r.getStyle(o,"padding-right")),h=parseFloat(r.getStyle(o,"padding-bottom")),f=s.right-s.left-u-c,g=s.bottom-s.top-d-h;return n=Math.round((n-s.left-u)/f*o.width/e.currentDevicePixelRatio),i=Math.round((i-s.top-d)/g*o.height/e.currentDevicePixelRatio),{x:n,y:i}},r.addEvent=function(t,e,n){t.addEventListener?t.addEventListener(e,n):t.attachEvent?t.attachEvent("on"+e,n):t["on"+e]=n},r.removeEvent=function(t,e,n){t.removeEventListener?t.removeEventListener(e,n,!1):t.detachEvent?t.detachEvent("on"+e,n):t["on"+e]=r.noop},r.getConstraintWidth=function(t){return a(t,"max-width","clientWidth")},r.getConstraintHeight=function(t){return a(t,"max-height","clientHeight")},r.getMaximumWidth=function(t){var e=t.parentNode,n=parseInt(r.getStyle(e,"padding-left"),10),i=parseInt(r.getStyle(e,"padding-right"),10),a=e.clientWidth-n-i,o=r.getConstraintWidth(t);return isNaN(o)?a:Math.min(a,o)},r.getMaximumHeight=function(t){var e=t.parentNode,n=parseInt(r.getStyle(e,"padding-top"),10),i=parseInt(r.getStyle(e,"padding-bottom"),10),a=e.clientHeight-n-i,o=r.getConstraintHeight(t);return isNaN(o)?a:Math.min(a,o)},r.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},r.retinaScale=function(t){var e=t.currentDevicePixelRatio=window.devicePixelRatio||1;if(1!==e){var n=t.canvas,i=t.height,a=t.width;n.height=i*e,n.width=a*e,t.ctx.scale(e,e),n.style.height=i+"px",n.style.width=a+"px"}},r.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},r.fontString=function(t,e,n){return e+" "+t+"px "+n},r.longestText=function(t,e,n,i){i=i||{};var a=i.data=i.data||{},o=i.garbageCollect=i.garbageCollect||[];i.font!==e&&(a=i.data={},o=i.garbageCollect=[],i.font=e),t.font=e;var s=0;r.each(n,function(e){void 0!==e&&null!==e&&r.isArray(e)!==!0?s=r.measureText(t,a,o,s,e):r.isArray(e)&&r.each(e,function(e){void 0===e||null===e||r.isArray(e)||(s=r.measureText(t,a,o,s,e))})});var l=o.length/2;if(l>n.length){for(var u=0;u<l;u++)delete a[o[u]];o.splice(0,l)}return s},r.measureText=function(t,e,n,i,a){var r=e[a];return r||(r=e[a]=t.measureText(a).width,n.push(a)),r>i&&(i=r),i},r.numberOfLabelLines=function(t){var e=1;return r.each(t,function(t){r.isArray(t)&&t.length>e&&(e=t.length)}),e},r.drawRoundedRectangle=function(t,e,n,i,a,r){t.beginPath(),t.moveTo(e+r,n),t.lineTo(e+i-r,n),t.quadraticCurveTo(e+i,n,e+i,n+r),t.lineTo(e+i,n+a-r),t.quadraticCurveTo(e+i,n+a,e+i-r,n+a),t.lineTo(e+r,n+a),t.quadraticCurveTo(e,n+a,e,n+a-r),t.lineTo(e,n+r),t.quadraticCurveTo(e,n,e+r,n),t.closePath()},r.color=i?function(e){return e instanceof CanvasGradient&&(e=t.defaults.global.defaultColor),i(e)}:function(t){return console.error("Color.js not found!"),t},r.isArray=Array.isArray?function(t){return Array.isArray(t)}:function(t){return"[object Array]"===Object.prototype.toString.call(t)},r.arrayEquals=function(t,e){var n,i,a,o;if(!t||!e||t.length!==e.length)return!1;for(n=0,i=t.length;n<i;++n)if(a=t[n],o=e[n],a instanceof Array&&o instanceof Array){if(!r.arrayEquals(a,o))return!1}else if(a!==o)return!1;return!0},r.callback=function(t,e,n){t&&"function"==typeof t.call&&t.apply(n,e)},r.getHoverColor=function(t){return t instanceof CanvasPattern?t:r.color(t).saturate(.5).darken(.1).rgbString()},r.callCallback=r.callback}},{2:2}],27:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return t.native?{x:t.x,y:t.y}:o.getRelativePosition(t,e)}function n(t,e){var n,i,a,r,o,s=t.data.datasets;for(i=0,r=s.length;i<r;++i)if(t.isDatasetVisible(i))for(n=t.getDatasetMeta(i),a=0,o=n.data.length;a<o;++a){var l=n.data[a];l._view.skip||e(l)}}function i(t,e){var i=[];return n(t,function(t){t.inRange(e.x,e.y)&&i.push(t)}),i}function a(t,e,i,a){var r=Number.POSITIVE_INFINITY,s=[];return a||(a=o.distanceBetweenPoints),n(t,function(t){if(!i||t.inRange(e.x,e.y)){var n=t.getCenterPoint(),o=a(e,n);o<r?(s=[t],r=o):o===r&&s.push(t)}}),s}function r(t,n,r){var o=e(n,t),s=function(t,e){return Math.abs(t.x-e.x)},l=r.intersect?i(t,o):a(t,o,!1,s),u=[];return l.length?(t.data.datasets.forEach(function(e,n){if(t.isDatasetVisible(n)){var i=t.getDatasetMeta(n),a=i.data[l[0]._index];a&&!a._view.skip&&u.push(a)}}),u):[]}var o=t.helpers;t.Interaction={modes:{single:function(t,i){var a=e(i,t),r=[];return n(t,function(t){if(t.inRange(a.x,a.y))return r.push(t),r}),r.slice(0,1)},label:r,index:r,dataset:function(t,n,r){var o=e(n,t),s=r.intersect?i(t,o):a(t,o,!1);return s.length>0&&(s=t.getDatasetMeta(s[0]._datasetIndex).data),s},"x-axis":function(t,e){return r(t,e,!0)},point:function(t,n){var a=e(n,t);return i(t,a)},nearest:function(t,n,i){var r=e(n,t),o=a(t,r,i.intersect);return o.length>1&&o.sort(function(t,e){var n=t.getArea(),i=e.getArea(),a=n-i;return 0===a&&(a=t._datasetIndex-e._datasetIndex),a}),o.slice(0,1)},x:function(t,i,a){var r=e(i,t),o=[],s=!1;return n(t,function(t){t.inXRange(r.x)&&o.push(t),t.inRange(r.x,r.y)&&(s=!0)}),a.intersect&&!s&&(o=[]),o},y:function(t,i,a){var r=e(i,t),o=[],s=!1;return n(t,function(t){t.inYRange(r.y)&&o.push(t),t.inRange(r.x,r.y)&&(s=!0)}),a.intersect&&!s&&(o=[]),o}}}}},{}],28:[function(t,e,n){"use strict";e.exports=function(){var t=function(t,e){return this.construct(t,e),this};return t.defaults={global:{responsive:!0,responsiveAnimationDuration:0,maintainAspectRatio:!0,events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",showLines:!0,elements:{},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');for(var n=0;n<t.data.datasets.length;n++)e.push('<li><span style="background-color:'+t.data.datasets[n].backgroundColor+'"></span>'),t.data.datasets[n].label&&e.push(t.data.datasets[n].label),e.push("</li>");return e.push("</ul>"),e.join("")}}},t.Chart=t,t}},{}],29:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return i.where(t,function(t){return t.position===e})}function n(t,e){t.forEach(function(t,e){return t._tmpIndex_=e,t}),t.sort(function(t,n){var i=e?n:t,a=e?t:n;return i.weight===a.weight?i._tmpIndex_-a._tmpIndex_:i.weight-a.weight}),t.forEach(function(t){delete t._tmpIndex_})}var i=t.helpers;t.layoutService={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,t.boxes.push(e)},removeBox:function(t,e){var n=t.boxes?t.boxes.indexOf(e):-1;n!==-1&&t.boxes.splice(n,1)},configure:function(t,e,n){for(var i,a=["fullWidth","position","weight"],r=a.length,o=0;o<r;++o)i=a[o],n.hasOwnProperty(i)&&(e[i]=n[i])},update:function(t,a,r){function o(t){var e,n=t.isHorizontal();n?(e=t.update(t.fullWidth?_:C,D),P-=e.height):(e=t.update(S,M),C-=e.width),T.push({horizontal:n,minSize:e,box:t})}function s(t){var e=i.findNextWhere(T,function(e){return e.box===t});if(e)if(t.isHorizontal()){var n={left:Math.max(R,I),right:Math.max(L,A),top:0,bottom:0};t.update(t.fullWidth?_:C,k/2,n)}else t.update(e.minSize.width,P)}function l(t){var e=i.findNextWhere(T,function(e){return e.box===t}),n={left:0,right:0,top:V,bottom:W};e&&t.update(e.minSize.width,P,n)}function u(t){t.isHorizontal()?(t.left=t.fullWidth?h:R,t.right=t.fullWidth?a-f:R+C,t.top=H,t.bottom=H+t.height,H=t.bottom):(t.left=E,t.right=E+t.width,t.top=V,t.bottom=V+P,E=t.right)}if(t){var d=t.options.layout,c=d?d.padding:null,h=0,f=0,g=0,p=0;isNaN(c)?(h=c.left||0,f=c.right||0,g=c.top||0,p=c.bottom||0):(h=c,f=c,g=c,p=c);var m=e(t.boxes,"left"),v=e(t.boxes,"right"),y=e(t.boxes,"top"),b=e(t.boxes,"bottom"),x=e(t.boxes,"chartArea");n(m,!0),n(v,!1),n(y,!0),n(b,!1);var _=a-h-f,k=r-g-p,w=_/2,M=k/2,S=(a-w)/(m.length+v.length),D=(r-M)/(y.length+b.length),C=_,P=k,T=[];i.each(m.concat(v,y,b),o);var I=0,A=0,F=0,O=0;i.each(y.concat(b),function(t){if(t.getPadding){var e=t.getPadding();I=Math.max(I,e.left),A=Math.max(A,e.right)}}),i.each(m.concat(v),function(t){if(t.getPadding){var e=t.getPadding();F=Math.max(F,e.top),O=Math.max(O,e.bottom)}});var R=h,L=f,V=g,W=p;i.each(m.concat(v),s),i.each(m,function(t){R+=t.width}),i.each(v,function(t){L+=t.width}),i.each(y.concat(b),s),i.each(y,function(t){V+=t.height}),i.each(b,function(t){W+=t.height}),i.each(m.concat(v),l),R=h,L=f,V=g,W=p,i.each(m,function(t){R+=t.width}),i.each(v,function(t){L+=t.width}),i.each(y,function(t){V+=t.height}),i.each(b,function(t){W+=t.height});var Y=Math.max(I-R,0);R+=Y,L+=Math.max(A-L,0);var z=Math.max(F-V,0);V+=z,W+=Math.max(O-W,0);var N=r-V-W,B=a-R-L;B===C&&N===P||(i.each(m,function(t){t.height=N}),i.each(v,function(t){t.height=N}),i.each(y,function(t){t.fullWidth||(t.width=B)}),i.each(b,function(t){t.fullWidth||(t.width=B)}),P=N,C=B);var E=h+Y,H=g+z;i.each(m.concat(y),u),E+=C,H+=P,i.each(v,u),i.each(b,u),t.chartArea={left:R,top:V,right:R+C,bottom:V+P},i.each(x,function(e){e.left=t.chartArea.left,e.top=t.chartArea.top,e.right=t.chartArea.right,e.bottom=t.chartArea.bottom,e.update(C,P)})}}}}},{}],30:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.defaults.global.plugins={},t.plugins={_plugins:[],_cacheId:0,register:function(t){var e=this._plugins;[].concat(t).forEach(function(t){e.indexOf(t)===-1&&e.push(t)}),this._cacheId++},unregister:function(t){var e=this._plugins;[].concat(t).forEach(function(t){var n=e.indexOf(t);n!==-1&&e.splice(n,1)}),this._cacheId++},clear:function(){this._plugins=[],this._cacheId++},count:function(){return this._plugins.length},getAll:function(){return this._plugins},notify:function(t,e,n){var i,a,r,o,s,l=this.descriptors(t),u=l.length;for(i=0;i<u;++i)if(a=l[i],r=a.plugin,s=r[e],"function"==typeof s&&(o=[t].concat(n||[]),o.push(a.options),s.apply(r,o)===!1))return!1;return!0},descriptors:function(n){var i=n._plugins||(n._plugins={});if(i.id===this._cacheId)return i.descriptors;var a=[],r=[],o=n&&n.config||{},s=t.defaults.global.plugins,l=o.options&&o.options.plugins||{};return this._plugins.concat(o.plugins||[]).forEach(function(t){var n=a.indexOf(t);if(n===-1){var i=t.id,o=l[i];o!==!1&&(o===!0&&(o=e.clone(s[i])),a.push(t),r.push({plugin:t,options:o||{}}))}}),i.descriptors=r,i.id=this._cacheId,r}},t.pluginService=t.plugins,t.PluginBase=t.Element.extend({})}},{}],31:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e,n){return i.isArray(e)?i.longestText(t,n,e):t.measureText(e).width}function n(e){var n=i.getValueOrDefault,a=t.defaults.global,r=n(e.fontSize,a.defaultFontSize),o=n(e.fontStyle,a.defaultFontStyle),s=n(e.fontFamily,a.defaultFontFamily);return{size:r,style:o,family:s,font:i.fontString(r,o,s)}}var i=t.helpers;t.defaults.scale={display:!0,position:"left",gridLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,drawBorder:!0,drawOnChartArea:!0,drawTicks:!0,tickMarkLength:10,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",zeroLineBorderDash:[],zeroLineBorderDashOffset:0,offsetGridLines:!1,borderDash:[],borderDashOffset:0},scaleLabel:{labelString:"",display:!1},ticks:{beginAtZero:!1,minRotation:0,maxRotation:50,mirror:!1,padding:0,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:0,labelOffset:0,callback:t.Ticks.formatters.values}},t.Scale=t.Element.extend({getPadding:function(){var t=this;return{left:t.paddingLeft||0,top:t.paddingTop||0,right:t.paddingRight||0,bottom:t.paddingBottom||0}},beforeUpdate:function(){i.callback(this.options.beforeUpdate,[this])},update:function(t,e,n){var a=this;return a.beforeUpdate(),a.maxWidth=t,a.maxHeight=e,a.margins=i.extend({left:0,right:0,top:0,bottom:0},n),a.longestTextCache=a.longestTextCache||{},a.beforeSetDimensions(),a.setDimensions(),a.afterSetDimensions(),a.beforeDataLimits(),a.determineDataLimits(),a.afterDataLimits(),a.beforeBuildTicks(),a.buildTicks(),a.afterBuildTicks(),a.beforeTickToLabelConversion(),a.convertTicksToLabels(),a.afterTickToLabelConversion(),a.beforeCalculateTickRotation(),a.calculateTickRotation(),a.afterCalculateTickRotation(),a.beforeFit(),a.fit(),a.afterFit(),a.afterUpdate(),a.minSize},afterUpdate:function(){i.callback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){i.callback(this.options.beforeSetDimensions,[this])},setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0},afterSetDimensions:function(){i.callback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){i.callback(this.options.beforeDataLimits,[this])},determineDataLimits:i.noop,afterDataLimits:function(){i.callback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){i.callback(this.options.beforeBuildTicks,[this])},buildTicks:i.noop,afterBuildTicks:function(){i.callback(this.options.afterBuildTicks,[this])},beforeTickToLabelConversion:function(){i.callback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this,e=t.options.ticks;t.ticks=t.ticks.map(e.userCallback||e.callback)},afterTickToLabelConversion:function(){i.callback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){i.callback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t=this,e=t.ctx,a=t.options.ticks,r=n(a);e.font=r.font;var o=a.minRotation||0;if(t.options.display&&t.isHorizontal())for(var s,l,u=i.longestText(e,r.font,t.ticks,t.longestTextCache),d=u,c=t.getPixelForTick(1)-t.getPixelForTick(0)-6;d>c&&o<a.maxRotation;){var h=i.toRadians(o);if(s=Math.cos(h),l=Math.sin(h),l*u>t.maxHeight){o--;break}o++,d=s*u}t.labelRotation=o},afterCalculateTickRotation:function(){i.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){i.callback(this.options.beforeFit,[this])},fit:function(){var t=this,a=t.minSize={width:0,height:0},r=t.options,o=r.ticks,s=r.scaleLabel,l=r.gridLines,u=r.display,d=t.isHorizontal(),c=n(o),h=1.5*n(s).size,f=r.gridLines.tickMarkLength;if(d?a.width=t.isFullWidth()?t.maxWidth-t.margins.left-t.margins.right:t.maxWidth:a.width=u&&l.drawTicks?f:0,d?a.height=u&&l.drawTicks?f:0:a.height=t.maxHeight,s.display&&u&&(d?a.height+=h:a.width+=h),o.display&&u){var g=i.longestText(t.ctx,c.font,t.ticks,t.longestTextCache),p=i.numberOfLabelLines(t.ticks),m=.5*c.size;if(d){t.longestLabelWidth=g;var v=i.toRadians(t.labelRotation),y=Math.cos(v),b=Math.sin(v),x=b*g+c.size*p+m*p;a.height=Math.min(t.maxHeight,a.height+x),t.ctx.font=c.font;var _=t.ticks[0],k=e(t.ctx,_,c.font),w=t.ticks[t.ticks.length-1],M=e(t.ctx,w,c.font);0!==t.labelRotation?(t.paddingLeft="bottom"===r.position?y*k+3:y*m+3,t.paddingRight="bottom"===r.position?y*m+3:y*M+3):(t.paddingLeft=k/2+3,t.paddingRight=M/2+3)}else o.mirror?g=0:g+=t.options.ticks.padding,a.width=Math.min(t.maxWidth,a.width+g),t.paddingTop=c.size/2,t.paddingBottom=c.size/2}t.handleMargins(),t.width=a.width,t.height=a.height},handleMargins:function(){var t=this;t.margins&&(t.paddingLeft=Math.max(t.paddingLeft-t.margins.left,0),t.paddingTop=Math.max(t.paddingTop-t.margins.top,0),t.paddingRight=Math.max(t.paddingRight-t.margins.right,0),t.paddingBottom=Math.max(t.paddingBottom-t.margins.bottom,0))},afterFit:function(){i.callback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){return null===t||"undefined"==typeof t?NaN:"number"!=typeof t||isFinite(t)?"object"==typeof t?t instanceof Date||t.isValid?t:this.getRightValue(this.isHorizontal()?t.x:t.y):t:NaN},getLabelForIndex:i.noop,getPixelForValue:i.noop,getValueForPixel:i.noop,getPixelForTick:function(t,e){var n=this;if(n.isHorizontal()){var i=n.width-(n.paddingLeft+n.paddingRight),a=i/Math.max(n.ticks.length-(n.options.gridLines.offsetGridLines?0:1),1),r=a*t+n.paddingLeft;e&&(r+=a/2);var o=n.left+Math.round(r);return o+=n.isFullWidth()?n.margins.left:0}var s=n.height-(n.paddingTop+n.paddingBottom);return n.top+t*(s/(n.ticks.length-1))},getPixelForDecimal:function(t){var e=this;if(e.isHorizontal()){var n=e.width-(e.paddingLeft+e.paddingRight),i=n*t+e.paddingLeft,a=e.left+Math.round(i);return a+=e.isFullWidth()?e.margins.left:0}return e.top+t*e.height},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var t=this,e=t.min,n=t.max;return t.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0},draw:function(e){var a=this,r=a.options;if(r.display){var o,s,l=a.ctx,u=t.defaults.global,d=r.ticks,c=r.gridLines,h=r.scaleLabel,f=0!==a.labelRotation,g=d.autoSkip,p=a.isHorizontal();d.maxTicksLimit&&(s=d.maxTicksLimit);var m=i.getValueOrDefault(d.fontColor,u.defaultFontColor),v=n(d),y=c.drawTicks?c.tickMarkLength:0,b=i.getValueOrDefault(h.fontColor,u.defaultFontColor),x=n(h),_=i.toRadians(a.labelRotation),k=Math.cos(_),w=a.longestLabelWidth*k;l.fillStyle=m;var M=[];if(p){if(o=!1,(w+d.autoSkipPadding)*a.ticks.length>a.width-(a.paddingLeft+a.paddingRight)&&(o=1+Math.floor((w+d.autoSkipPadding)*a.ticks.length/(a.width-(a.paddingLeft+a.paddingRight)))),s&&a.ticks.length>s)for(;!o||a.ticks.length/(o||1)>s;)o||(o=1),o+=1;g||(o=!1)}var S="right"===r.position?a.left:a.right-y,D="right"===r.position?a.left+y:a.right,C="bottom"===r.position?a.top:a.bottom-y,P="bottom"===r.position?a.top+y:a.bottom;if(i.each(a.ticks,function(t,n){if(void 0!==t&&null!==t){var s=a.ticks.length===n+1,l=o>1&&n%o>0||n%o===0&&n+o>=a.ticks.length;if((!l||s)&&void 0!==t&&null!==t){var h,g,m,v;n===("undefined"!=typeof a.zeroLineIndex?a.zeroLineIndex:0)?(h=c.zeroLineWidth,g=c.zeroLineColor,m=c.zeroLineBorderDash,v=c.zeroLineBorderDashOffset):(h=i.getValueAtIndexOrDefault(c.lineWidth,n),g=i.getValueAtIndexOrDefault(c.color,n),m=i.getValueOrDefault(c.borderDash,u.borderDash),v=i.getValueOrDefault(c.borderDashOffset,u.borderDashOffset));var b,x,k,w,T,I,A,F,O,R,L="middle",V="middle";if(p){"bottom"===r.position?(V=f?"middle":"top",L=f?"right":"center",R=a.top+y):(V=f?"middle":"bottom",L=f?"left":"center",R=a.bottom-y);var W=a.getPixelForTick(n)+i.aliasPixel(h);O=a.getPixelForTick(n,c.offsetGridLines)+d.labelOffset,b=k=T=A=W,x=C,w=P,I=e.top,F=e.bottom}else{var Y,z="left"===r.position,N=d.padding;d.mirror?(L=z?"left":"right",Y=N):(L=z?"right":"left",Y=y+N),O=z?a.right-Y:a.left+Y;var B=a.getPixelForTick(n);B+=i.aliasPixel(h),R=a.getPixelForTick(n,c.offsetGridLines),b=S,k=D,T=e.left,A=e.right,x=w=I=F=B}M.push({tx1:b,ty1:x,tx2:k,ty2:w,x1:T,y1:I,x2:A,y2:F,labelX:O,labelY:R,glWidth:h,glColor:g,glBorderDash:m,glBorderDashOffset:v,rotation:-1*_,label:t,textBaseline:V,textAlign:L})}}}),i.each(M,function(t){if(c.display&&(l.save(),l.lineWidth=t.glWidth,l.strokeStyle=t.glColor,l.setLineDash&&(l.setLineDash(t.glBorderDash),l.lineDashOffset=t.glBorderDashOffset),l.beginPath(),c.drawTicks&&(l.moveTo(t.tx1,t.ty1),l.lineTo(t.tx2,t.ty2)),c.drawOnChartArea&&(l.moveTo(t.x1,t.y1),l.lineTo(t.x2,t.y2)),l.stroke(),l.restore()),d.display){l.save(),l.translate(t.labelX,t.labelY),l.rotate(t.rotation),l.font=v.font,l.textBaseline=t.textBaseline,l.textAlign=t.textAlign;var e=t.label;if(i.isArray(e))for(var n=0,a=0;n<e.length;++n)l.fillText(""+e[n],0,a),a+=1.5*v.size;else l.fillText(e,0,0);l.restore()}}),h.display){var T,I,A=0;if(p)T=a.left+(a.right-a.left)/2,I="bottom"===r.position?a.bottom-x.size/2:a.top+x.size/2;else{var F="left"===r.position;T=F?a.left+x.size/2:a.right-x.size/2,I=a.top+(a.bottom-a.top)/2,A=F?-.5*Math.PI:.5*Math.PI}l.save(),l.translate(T,I),l.rotate(A),l.textAlign="center",l.textBaseline="middle",l.fillStyle=b,l.font=x.font,l.fillText(h.labelString,0,0),l.restore()}if(c.drawBorder){l.lineWidth=i.getValueAtIndexOrDefault(c.lineWidth,0),l.strokeStyle=i.getValueAtIndexOrDefault(c.color,0);var O=a.left,R=a.right,L=a.top,V=a.bottom,W=i.aliasPixel(l.lineWidth);p?(L=V="top"===r.position?a.bottom:a.top,L+=W,V+=W):(O=R="left"===r.position?a.right:a.left,O+=W,R+=W),l.beginPath(),l.moveTo(O,L),l.lineTo(R,V),l.stroke()}}}})}},{}],32:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.scaleService={constructors:{},defaults:{},registerScaleType:function(t,n,i){this.constructors[t]=n,this.defaults[t]=e.clone(i)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(n){return this.defaults.hasOwnProperty(n)?e.scaleMerge(t.defaults.scale,this.defaults[n]):{}},updateScaleDefaults:function(t,n){var i=this.defaults;i.hasOwnProperty(t)&&(i[t]=e.extend(i[t],n))},addScalesToLayout:function(n){e.each(n.scales,function(e){e.fullWidth=e.options.fullWidth,e.position=e.options.position,e.weight=e.options.weight,t.layoutService.addBox(n,e)})}}}},{}],33:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers;t.Ticks={generators:{linear:function(t,n){var i,a=[];if(t.stepSize&&t.stepSize>0)i=t.stepSize;else{var r=e.niceNum(n.max-n.min,!1);i=e.niceNum(r/(t.maxTicks-1),!0)}var o=Math.floor(n.min/i)*i,s=Math.ceil(n.max/i)*i;t.min&&t.max&&t.stepSize&&e.almostWhole((t.max-t.min)/t.stepSize,i/1e3)&&(o=t.min,s=t.max);var l=(s-o)/i;l=e.almostEquals(l,Math.round(l),i/1e3)?Math.round(l):Math.ceil(l),a.push(void 0!==t.min?t.min:o);for(var u=1;u<l;++u)a.push(o+u*i);return a.push(void 0!==t.max?t.max:s),a},logarithmic:function(t,n){var i,a,r=[],o=e.getValueOrDefault,s=o(t.min,Math.pow(10,Math.floor(e.log10(n.min)))),l=Math.floor(e.log10(n.max)),u=Math.ceil(n.max/Math.pow(10,l));0===s?(i=Math.floor(e.log10(n.minNotZero)),a=Math.floor(n.minNotZero/Math.pow(10,i)),r.push(s),s=a*Math.pow(10,i)):(i=Math.floor(e.log10(s)),a=Math.floor(s/Math.pow(10,i)));do r.push(s),++a,10===a&&(a=1,++i),s=a*Math.pow(10,i);while(i<l||i===l&&a<u);var d=o(t.max,s);return r.push(d),r}},formatters:{values:function(t){return e.isArray(t)?t:""+t},linear:function(t,n,i){var a=i.length>3?i[2]-i[1]:i[1]-i[0];Math.abs(a)>1&&t!==Math.floor(t)&&(a=t-Math.floor(t));var r=e.log10(Math.abs(a)),o="";if(0!==t){var s=-1*Math.floor(r);s=Math.max(Math.min(s,20),0),o=t.toFixed(s)}else o="0";return o},logarithmic:function(t,n,i){var a=t/Math.pow(10,Math.floor(e.log10(t)));return 0===t?"0":1===a||2===a||5===a||0===n||n===i.length-1?t.toExponential():""}}}}},{}],34:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){var n=l.color(t);return n.alpha(e*n.alpha()).rgbaString()}function n(t,e){return e&&(l.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function i(t){var e=t._xScale,n=t._yScale||t._scale,i=t._index,a=t._datasetIndex;return{xLabel:e?e.getLabelForIndex(i,a):"",yLabel:n?n.getLabelForIndex(i,a):"",index:i,datasetIndex:a,x:t._model.x,y:t._model.y}}function a(e){var n=t.defaults.global,i=l.getValueOrDefault;return{xPadding:e.xPadding,yPadding:e.yPadding,xAlign:e.xAlign,yAlign:e.yAlign,bodyFontColor:e.bodyFontColor,_bodyFontFamily:i(e.bodyFontFamily,n.defaultFontFamily),_bodyFontStyle:i(e.bodyFontStyle,n.defaultFontStyle),_bodyAlign:e.bodyAlign,bodyFontSize:i(e.bodyFontSize,n.defaultFontSize),bodySpacing:e.bodySpacing,titleFontColor:e.titleFontColor,_titleFontFamily:i(e.titleFontFamily,n.defaultFontFamily),_titleFontStyle:i(e.titleFontStyle,n.defaultFontStyle),titleFontSize:i(e.titleFontSize,n.defaultFontSize),_titleAlign:e.titleAlign,titleSpacing:e.titleSpacing,titleMarginBottom:e.titleMarginBottom,footerFontColor:e.footerFontColor,_footerFontFamily:i(e.footerFontFamily,n.defaultFontFamily),_footerFontStyle:i(e.footerFontStyle,n.defaultFontStyle),footerFontSize:i(e.footerFontSize,n.defaultFontSize),_footerAlign:e.footerAlign,footerSpacing:e.footerSpacing,footerMarginTop:e.footerMarginTop,caretSize:e.caretSize,cornerRadius:e.cornerRadius,backgroundColor:e.backgroundColor,opacity:0,legendColorBackground:e.multiKeyBackground,displayColors:e.displayColors,borderColor:e.borderColor,borderWidth:e.borderWidth}}function r(t,e){var n=t._chart.ctx,i=2*e.yPadding,a=0,r=e.body,o=r.reduce(function(t,e){return t+e.before.length+e.lines.length+e.after.length},0);o+=e.beforeBody.length+e.afterBody.length;var s=e.title.length,u=e.footer.length,d=e.titleFontSize,c=e.bodyFontSize,h=e.footerFontSize;i+=s*d,i+=s?(s-1)*e.titleSpacing:0,i+=s?e.titleMarginBottom:0,i+=o*c,i+=o?(o-1)*e.bodySpacing:0,i+=u?e.footerMarginTop:0,i+=u*h,i+=u?(u-1)*e.footerSpacing:0;var f=0,g=function(t){a=Math.max(a,n.measureText(t).width+f)};return n.font=l.fontString(d,e._titleFontStyle,e._titleFontFamily),l.each(e.title,g),n.font=l.fontString(c,e._bodyFontStyle,e._bodyFontFamily),l.each(e.beforeBody.concat(e.afterBody),g),f=e.displayColors?c+2:0,l.each(r,function(t){l.each(t.before,g),l.each(t.lines,g),l.each(t.after,g)}),f=0,n.font=l.fontString(h,e._footerFontStyle,e._footerFontFamily),l.each(e.footer,g),a+=2*e.xPadding,{width:a,height:i}}function o(t,e){var n=t._model,i=t._chart,a=t._chart.chartArea,r="center",o="center";n.y<e.height?o="top":n.y>i.height-e.height&&(o="bottom");var s,l,u,d,c,h=(a.left+a.right)/2,f=(a.top+a.bottom)/2;"center"===o?(s=function(t){return t<=h},l=function(t){return t>h}):(s=function(t){return t<=e.width/2},l=function(t){return t>=i.width-e.width/2}),u=function(t){return t+e.width>i.width},d=function(t){return t-e.width<0},c=function(t){return t<=f?"top":"bottom"},s(n.x)?(r="left",u(n.x)&&(r="center",o=c(n.y))):l(n.x)&&(r="right",d(n.x)&&(r="center",o=c(n.y)));var g=t._options;return{xAlign:g.xAlign?g.xAlign:r,yAlign:g.yAlign?g.yAlign:o}}function s(t,e,n){var i=t.x,a=t.y,r=t.caretSize,o=t.caretPadding,s=t.cornerRadius,l=n.xAlign,u=n.yAlign,d=r+o,c=s+o;return"right"===l?i-=e.width:"center"===l&&(i-=e.width/2),"top"===u?a+=d:a-="bottom"===u?e.height+d:e.height/2,"center"===u?"left"===l?i+=d:"right"===l&&(i-=d):"left"===l?i-=c:"right"===l&&(i+=c),{x:i,y:a}}var l=t.helpers;t.defaults.global.tooltips={enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,callbacks:{beforeTitle:l.noop,title:function(t,e){var n="",i=e.labels,a=i?i.length:0;if(t.length>0){var r=t[0];r.xLabel?n=r.xLabel:a>0&&r.index<a&&(n=i[r.index])}return n},afterTitle:l.noop,beforeBody:l.noop,beforeLabel:l.noop,label:function(t,e){var n=e.datasets[t.datasetIndex].label||"";return n&&(n+=": "),n+=t.yLabel},labelColor:function(t,e){var n=e.getDatasetMeta(t.datasetIndex),i=n.data[t.index],a=i._view;return{borderColor:a.borderColor,backgroundColor:a.backgroundColor}},afterLabel:l.noop,afterBody:l.noop,beforeFooter:l.noop,footer:l.noop,afterFooter:l.noop}},t.Tooltip=t.Element.extend({initialize:function(){this._model=a(this._options)},getTitle:function(){var t=this,e=t._options,i=e.callbacks,a=i.beforeTitle.apply(t,arguments),r=i.title.apply(t,arguments),o=i.afterTitle.apply(t,arguments),s=[];return s=n(s,a),s=n(s,r),s=n(s,o)},getBeforeBody:function(){var t=this._options.callbacks.beforeBody.apply(this,arguments);return l.isArray(t)?t:void 0!==t?[t]:[]},getBody:function(t,e){var i=this,a=i._options.callbacks,r=[];return l.each(t,function(t){var o={before:[],lines:[],after:[]};n(o.before,a.beforeLabel.call(i,t,e)),n(o.lines,a.label.call(i,t,e)),n(o.after,a.afterLabel.call(i,t,e)),r.push(o)}),r},getAfterBody:function(){var t=this._options.callbacks.afterBody.apply(this,arguments);return l.isArray(t)?t:void 0!==t?[t]:[]},getFooter:function(){var t=this,e=t._options.callbacks,i=e.beforeFooter.apply(t,arguments),a=e.footer.apply(t,arguments),r=e.afterFooter.apply(t,arguments),o=[];return o=n(o,i),o=n(o,a),o=n(o,r)},update:function(e){var n,u,d=this,c=d._options,h=d._model,f=d._model=a(c),g=d._active,p=d._data,m={xAlign:h.xAlign,yAlign:h.yAlign},v={x:h.x,y:h.y},y={width:h.width,height:h.height},b={x:h.caretX,y:h.caretY};if(g.length){f.opacity=1;var x=[];b=t.Tooltip.positioners[c.position](g,d._eventPosition);var _=[];for(n=0,u=g.length;n<u;++n)_.push(i(g[n]));c.filter&&(_=_.filter(function(t){return c.filter(t,p)})),c.itemSort&&(_=_.sort(function(t,e){return c.itemSort(t,e,p)})),l.each(_,function(t){x.push(c.callbacks.labelColor.call(d,t,d._chart))}),f.title=d.getTitle(_,p),f.beforeBody=d.getBeforeBody(_,p),f.body=d.getBody(_,p),f.afterBody=d.getAfterBody(_,p),f.footer=d.getFooter(_,p),f.x=Math.round(b.x),f.y=Math.round(b.y),f.caretPadding=c.caretPadding,f.labelColors=x,f.dataPoints=_,y=r(this,f),m=o(this,y),v=s(f,y,m)}else f.opacity=0;return f.xAlign=m.xAlign,f.yAlign=m.yAlign,f.x=v.x,f.y=v.y,f.width=y.width,f.height=y.height,f.caretX=b.x,f.caretY=b.y,d._model=f,e&&c.custom&&c.custom.call(d,f),d},drawCaret:function(t,e){var n=this._chart.ctx,i=this._view,a=this.getCaretPosition(t,e,i);n.lineTo(a.x1,a.y1),n.lineTo(a.x2,a.y2),n.lineTo(a.x3,a.y3)},getCaretPosition:function(t,e,n){var i,a,r,o,s,l,u=n.caretSize,d=n.cornerRadius,c=n.xAlign,h=n.yAlign,f=t.x,g=t.y,p=e.width,m=e.height;if("center"===h)s=g+m/2,"left"===c?(i=f,a=i-u,r=i,o=s+u,l=s-u):(i=f+p,a=i+u,r=i,o=s-u,l=s+u);else if("left"===c?(a=f+d+u,i=a-u,r=a+u):"right"===c?(a=f+p-d-u,i=a-u,r=a+u):(a=f+p/2,i=a-u,r=a+u),"top"===h)o=g,s=o-u,l=o;else{o=g+m,s=o+u,l=o;var v=r;r=i,i=v}return{x1:i,x2:a,x3:r,y1:o,y2:s,y3:l}},drawTitle:function(t,n,i,a){var r=n.title;if(r.length){i.textAlign=n._titleAlign,i.textBaseline="top";var o=n.titleFontSize,s=n.titleSpacing;i.fillStyle=e(n.titleFontColor,a),i.font=l.fontString(o,n._titleFontStyle,n._titleFontFamily);var u,d;for(u=0,d=r.length;u<d;++u)i.fillText(r[u],t.x,t.y),t.y+=o+s,u+1===r.length&&(t.y+=n.titleMarginBottom-s)}},drawBody:function(t,n,i,a){var r=n.bodyFontSize,o=n.bodySpacing,s=n.body;i.textAlign=n._bodyAlign,i.textBaseline="top";var u=e(n.bodyFontColor,a);i.fillStyle=u,i.font=l.fontString(r,n._bodyFontStyle,n._bodyFontFamily);var d=0,c=function(e){i.fillText(e,t.x+d,t.y),t.y+=r+o};l.each(n.beforeBody,c);var h=n.displayColors;d=h?r+2:0,l.each(s,function(o,s){l.each(o.before,c),l.each(o.lines,function(o){h&&(i.fillStyle=e(n.legendColorBackground,a),i.fillRect(t.x,t.y,r,r),i.strokeStyle=e(n.labelColors[s].borderColor,a),i.strokeRect(t.x,t.y,r,r),i.fillStyle=e(n.labelColors[s].backgroundColor,a),i.fillRect(t.x+1,t.y+1,r-2,r-2),i.fillStyle=u),c(o)}),l.each(o.after,c)}),d=0,l.each(n.afterBody,c),t.y-=o},drawFooter:function(t,n,i,a){var r=n.footer;r.length&&(t.y+=n.footerMarginTop,i.textAlign=n._footerAlign,i.textBaseline="top",i.fillStyle=e(n.footerFontColor,a),i.font=l.fontString(n.footerFontSize,n._footerFontStyle,n._footerFontFamily),l.each(r,function(e){i.fillText(e,t.x,t.y),t.y+=n.footerFontSize+n.footerSpacing}))},drawBackground:function(t,n,i,a,r){i.fillStyle=e(n.backgroundColor,r),i.strokeStyle=e(n.borderColor,r),i.lineWidth=n.borderWidth;var o=n.xAlign,s=n.yAlign,l=t.x,u=t.y,d=a.width,c=a.height,h=n.cornerRadius;i.beginPath(),i.moveTo(l+h,u),"top"===s&&this.drawCaret(t,a),i.lineTo(l+d-h,u),i.quadraticCurveTo(l+d,u,l+d,u+h),
15
- "center"===s&&"right"===o&&this.drawCaret(t,a),i.lineTo(l+d,u+c-h),i.quadraticCurveTo(l+d,u+c,l+d-h,u+c),"bottom"===s&&this.drawCaret(t,a),i.lineTo(l+h,u+c),i.quadraticCurveTo(l,u+c,l,u+c-h),"center"===s&&"left"===o&&this.drawCaret(t,a),i.lineTo(l,u+h),i.quadraticCurveTo(l,u,l+h,u),i.closePath(),i.fill(),n.borderWidth>0&&i.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var n={width:e.width,height:e.height},i={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,r=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&r&&(this.drawBackground(i,e,t,n,a),i.x+=e.xPadding,i.y+=e.yPadding,this.drawTitle(i,e,t,a),this.drawBody(i,e,t,a),this.drawFooter(i,e,t,a))}},handleEvent:function(t){var e=this,n=e._options,i=!1;if(e._lastActive=e._lastActive||[],"mouseout"===t.type?e._active=[]:e._active=e._chart.getElementsAtEventForMode(t,n.mode,n),i=!l.arrayEquals(e._active,e._lastActive),!i)return!1;if(e._lastActive=e._active,n.enabled||n.custom){e._eventPosition={x:t.x,y:t.y};var a=e._model;e.update(!0),e.pivot(),i|=a.x!==e._model.x||a.y!==e._model.y}return i}}),t.Tooltip.positioners={average:function(t){if(!t.length)return!1;var e,n,i=0,a=0,r=0;for(e=0,n=t.length;e<n;++e){var o=t[e];if(o&&o.hasValue()){var s=o.tooltipPosition();i+=s.x,a+=s.y,++r}}return{x:Math.round(i/r),y:Math.round(a/r)}},nearest:function(t,e){var n,i,a,r=e.x,o=e.y,s=Number.POSITIVE_INFINITY;for(i=0,a=t.length;i<a;++i){var u=t[i];if(u&&u.hasValue()){var d=u.getCenterPoint(),c=l.distanceBetweenPoints(e,d);c<s&&(s=c,n=u)}}if(n){var h=n.tooltipPosition();r=h.x,o=h.y}return{x:r,y:o}}}}},{}],35:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global;n.elements.arc={backgroundColor:n.defaultColor,borderColor:"#fff",borderWidth:2},t.elements.Arc=t.Element.extend({inLabelRange:function(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hoverRadius,2)},inRange:function(t,n){var i=this._view;if(i){for(var a=e.getAngleFromPoint(i,{x:t,y:n}),r=a.angle,o=a.distance,s=i.startAngle,l=i.endAngle;l<s;)l+=2*Math.PI;for(;r>l;)r-=2*Math.PI;for(;r<s;)r+=2*Math.PI;var u=r>=s&&r<=l,d=o>=i.innerRadius&&o<=i.outerRadius;return u&&d}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,n=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},getArea:function(){var t=this._view;return Math.PI*((t.endAngle-t.startAngle)/(2*Math.PI))*(Math.pow(t.outerRadius,2)-Math.pow(t.innerRadius,2))},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,n=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},draw:function(){var t=this._chart.ctx,e=this._view,n=e.startAngle,i=e.endAngle;t.beginPath(),t.arc(e.x,e.y,e.outerRadius,n,i),t.arc(e.x,e.y,e.innerRadius,i,n,!0),t.closePath(),t.strokeStyle=e.borderColor,t.lineWidth=e.borderWidth,t.fillStyle=e.backgroundColor,t.fill(),t.lineJoin="bevel",e.borderWidth&&t.stroke()}})}},{}],36:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=t.defaults.global;t.defaults.global.elements.line={tension:.4,backgroundColor:n.defaultColor,borderWidth:3,borderColor:n.defaultColor,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0},t.elements.Line=t.Element.extend({draw:function(){var t,i,a,r,o=this,s=o._view,l=o._chart.ctx,u=s.spanGaps,d=o._children.slice(),c=n.elements.line,h=-1;for(o._loop&&d.length&&d.push(d[0]),l.save(),l.lineCap=s.borderCapStyle||c.borderCapStyle,l.setLineDash&&l.setLineDash(s.borderDash||c.borderDash),l.lineDashOffset=s.borderDashOffset||c.borderDashOffset,l.lineJoin=s.borderJoinStyle||c.borderJoinStyle,l.lineWidth=s.borderWidth||c.borderWidth,l.strokeStyle=s.borderColor||n.defaultColor,l.beginPath(),h=-1,t=0;t<d.length;++t)i=d[t],a=e.previousItem(d,t),r=i._view,0===t?r.skip||(l.moveTo(r.x,r.y),h=t):(a=h===-1?a:d[h],r.skip||(h!==t-1&&!u||h===-1?l.moveTo(r.x,r.y):e.canvas.lineTo(l,a._view,i._view),h=t));l.stroke(),l.restore()}})}},{}],37:[function(t,e,n){"use strict";e.exports=function(t){function e(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hitRadius,2)}function n(t){var e=this._view;return!!e&&Math.pow(t-e.y,2)<Math.pow(e.radius+e.hitRadius,2)}var i=t.helpers,a=t.defaults.global,r=a.defaultColor;a.elements.point={radius:3,pointStyle:"circle",backgroundColor:r,borderWidth:1,borderColor:r,hitRadius:1,hoverRadius:4,hoverBorderWidth:1},t.elements.Point=t.Element.extend({inRange:function(t,e){var n=this._view;return!!n&&Math.pow(t-n.x,2)+Math.pow(e-n.y,2)<Math.pow(n.hitRadius+n.radius,2)},inLabelRange:e,inXRange:e,inYRange:n,getCenterPoint:function(){var t=this._view;return{x:t.x,y:t.y}},getArea:function(){return Math.PI*Math.pow(this._view.radius,2)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y,padding:t.radius+t.borderWidth}},draw:function(e){var n=this._view,o=this._model,s=this._chart.ctx,l=n.pointStyle,u=n.radius,d=n.x,c=n.y,h=t.helpers.color,f=1.01,g=0;n.skip||(s.strokeStyle=n.borderColor||r,s.lineWidth=i.getValueOrDefault(n.borderWidth,a.elements.point.borderWidth),s.fillStyle=n.backgroundColor||r,void 0!==e&&(o.x<e.left||e.right*f<o.x||o.y<e.top||e.bottom*f<o.y)&&(o.x<e.left?g=(d-o.x)/(e.left-o.x):e.right*f<o.x?g=(o.x-d)/(o.x-e.right):o.y<e.top?g=(c-o.y)/(e.top-o.y):e.bottom*f<o.y&&(g=(o.y-c)/(o.y-e.bottom)),g=Math.round(100*g)/100,s.strokeStyle=h(s.strokeStyle).alpha(g).rgbString(),s.fillStyle=h(s.fillStyle).alpha(g).rgbString()),t.canvasHelpers.drawPoint(s,l,u,d,c))}})}},{}],38:[function(t,e,n){"use strict";e.exports=function(t){function e(t){return void 0!==t._view.width}function n(t){var n,i,a,r,o=t._view;if(e(t)){var s=o.width/2;n=o.x-s,i=o.x+s,a=Math.min(o.y,o.base),r=Math.max(o.y,o.base)}else{var l=o.height/2;n=Math.min(o.x,o.base),i=Math.max(o.x,o.base),a=o.y-l,r=o.y+l}return{left:n,top:a,right:i,bottom:r}}var i=t.defaults.global;i.elements.rectangle={backgroundColor:i.defaultColor,borderWidth:0,borderColor:i.defaultColor,borderSkipped:"bottom"},t.elements.Rectangle=t.Element.extend({draw:function(){function t(t){return v[(b+t)%4]}var e,n,i,a,r,o,s,l=this._chart.ctx,u=this._view,d=u.borderWidth;if(u.horizontal?(e=u.base,n=u.x,i=u.y-u.height/2,a=u.y+u.height/2,r=n>e?1:-1,o=1,s=u.borderSkipped||"left"):(e=u.x-u.width/2,n=u.x+u.width/2,i=u.y,a=u.base,r=1,o=a>i?1:-1,s=u.borderSkipped||"bottom"),d){var c=Math.min(Math.abs(e-n),Math.abs(i-a));d=d>c?c:d;var h=d/2,f=e+("left"!==s?h*r:0),g=n+("right"!==s?-h*r:0),p=i+("top"!==s?h*o:0),m=a+("bottom"!==s?-h*o:0);f!==g&&(i=p,a=m),p!==m&&(e=f,n=g)}l.beginPath(),l.fillStyle=u.backgroundColor,l.strokeStyle=u.borderColor,l.lineWidth=d;var v=[[e,a],[e,i],[n,i],[n,a]],y=["bottom","left","top","right"],b=y.indexOf(s,0);b===-1&&(b=0);var x=t(0);l.moveTo(x[0],x[1]);for(var _=1;_<4;_++)x=t(_),l.lineTo(x[0],x[1]);l.fill(),d&&l.stroke()},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){var i=!1;if(this._view){var a=n(this);i=t>=a.left&&t<=a.right&&e>=a.top&&e<=a.bottom}return i},inLabelRange:function(t,i){var a=this;if(!a._view)return!1;var r=!1,o=n(a);return r=e(a)?t>=o.left&&t<=o.right:i>=o.top&&i<=o.bottom},inXRange:function(t){var e=n(this);return t>=e.left&&t<=e.right},inYRange:function(t){var e=n(this);return t>=e.top&&t<=e.bottom},getCenterPoint:function(){var t,n,i=this._view;return e(this)?(t=i.x,n=(i.y+i.base)/2):(t=(i.x+i.base)/2,n=i.y),{x:t,y:n}},getArea:function(){var t=this._view;return t.width*Math.abs(t.y-t.base)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}})}},{}],39:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){var n=l.getStyle(t,e),i=n&&n.match(/^(\d+)(\.\d+)?px$/);return i?Number(i[1]):void 0}function n(t,n){var i=t.style,a=t.getAttribute("height"),r=t.getAttribute("width");if(t._chartjs={initial:{height:a,width:r,style:{display:i.display,height:i.height,width:i.width}}},i.display=i.display||"block",null===r||""===r){var o=e(t,"width");void 0!==o&&(t.width=o)}if(null===a||""===a)if(""===t.style.height)t.height=t.width/(n.options.aspectRatio||2);else{var s=e(t,"height");void 0!==o&&(t.height=s)}return t}function i(t,e,n,i,a){return{type:t,chart:e,native:a||null,x:void 0!==n?n:null,y:void 0!==i?i:null}}function a(t,e){var n=u[t.type]||t.type,a=l.getRelativePosition(t,e);return i(n,e,a.x,a.y,t)}function r(t){var e=document.createElement("iframe");return e.className="chartjs-hidden-iframe",e.style.cssText="display:block;overflow:hidden;border:0;margin:0;top:0;left:0;bottom:0;right:0;height:100%;width:100%;position:absolute;pointer-events:none;z-index:-1;",e.tabIndex=-1,l.addEvent(e,"load",function(){l.addEvent(e.contentWindow||e,"resize",t),t()}),e}function o(t,e,n){var a=t._chartjs={ticking:!1},o=function(){a.ticking||(a.ticking=!0,l.requestAnimFrame.call(window,function(){if(a.resizer)return a.ticking=!1,e(i("resize",n))}))};a.resizer=r(o),t.insertBefore(a.resizer,t.firstChild)}function s(t){if(t&&t._chartjs){var e=t._chartjs.resizer;e&&(e.parentNode.removeChild(e),t._chartjs.resizer=null),delete t._chartjs}}var l=t.helpers,u={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};return{acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var i=t&&t.getContext&&t.getContext("2d");return i&&i.canvas===t?(n(t,e),i):null},releaseContext:function(t){var e=t.canvas;if(e._chartjs){var n=e._chartjs.initial;["height","width"].forEach(function(t){var i=n[t];void 0===i||null===i?e.removeAttribute(t):e.setAttribute(t,i)}),l.each(n.style||{},function(t,n){e.style[n]=t}),e.width=e.width,delete e._chartjs}},addEventListener:function(t,e,n){var i=t.canvas;if("resize"===e)return void o(i.parentNode,n,t);var r=n._chartjs||(n._chartjs={}),s=r.proxies||(r.proxies={}),u=s[t.id+"_"+e]=function(e){n(a(e,t))};l.addEvent(i,e,u)},removeEventListener:function(t,e,n){var i=t.canvas;if("resize"===e)return void s(i.parentNode,n);var a=n._chartjs||{},r=a.proxies||{},o=r[t.id+"_"+e];o&&l.removeEvent(i,e,o)}}}},{}],40:[function(t,e,n){"use strict";var i=t(39);e.exports=function(t){t.platform={acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},t.helpers.extend(t.platform,i(t))}},{39:39}],41:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e,n){var i,a=t._model||{},r=a.fill;if(void 0===r&&(r=!!a.backgroundColor),r===!1||null===r)return!1;if(r===!0)return"origin";if(i=parseFloat(r,10),isFinite(i)&&Math.floor(i)===i)return"-"!==r[0]&&"+"!==r[0]||(i=e+i),!(i===e||i<0||i>=n)&&i;switch(r){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return r;default:return!1}}function n(t){var e,n=t.el._model||{},i=t.el._scale||{},a=t.fill,r=null;if(isFinite(a))return null;if("start"===a?r=void 0===n.scaleBottom?i.bottom:n.scaleBottom:"end"===a?r=void 0===n.scaleTop?i.top:n.scaleTop:void 0!==n.scaleZero?r=n.scaleZero:i.getBasePosition?r=i.getBasePosition():i.getBasePixel&&(r=i.getBasePixel()),void 0!==r&&null!==r){if(void 0!==r.x&&void 0!==r.y)return r;if("number"==typeof r&&isFinite(r))return e=i.isHorizontal(),{x:e?r:null,y:e?null:r}}return null}function i(t,e,n){var i,a=t[e],r=a.fill,o=[e];if(!n)return r;for(;r!==!1&&o.indexOf(r)===-1;){if(!isFinite(r))return r;if(i=t[r],!i)return!1;if(i.visible)return r;o.push(r),r=i.fill}return!1}function a(t){var e=t.fill,n="dataset";return e===!1?null:(isFinite(e)||(n="boundary"),d[n](t))}function r(t){return t&&!t.skip}function o(t,e,n,i,a){var r;if(i&&a){for(t.moveTo(e[0].x,e[0].y),r=1;r<i;++r)u.canvas.lineTo(t,e[r-1],e[r]);for(t.lineTo(n[a-1].x,n[a-1].y),r=a-1;r>0;--r)u.canvas.lineTo(t,n[r],n[r-1],!0)}}function s(t,e,n,i,a,s){var l,u,d,c,h,f,g,p=e.length,m=i.spanGaps,v=[],y=[],b=0,x=0;for(t.beginPath(),l=0,u=p+!!s;l<u;++l)d=l%p,c=e[d]._view,h=n(c,d,i),f=r(c),g=r(h),f&&g?(b=v.push(c),x=y.push(h)):b&&x&&(m?(f&&v.push(c),g&&y.push(h)):(o(t,v,y,b,x),b=x=0,v=[],y=[]));o(t,v,y,b,x),t.closePath(),t.fillStyle=a,t.fill()}t.defaults.global.plugins.filler={propagate:!0};var l=t.defaults,u=t.helpers,d={dataset:function(t){var e=t.fill,n=t.chart,i=n.getDatasetMeta(e),a=i&&n.isDatasetVisible(e),r=a&&i.dataset._children||[];return r.length?function(t,e){return r[e]._view||null}:null},boundary:function(t){var e=t.boundary,n=e?e.x:null,i=e?e.y:null;return function(t){return{x:null===n?t.x:n,y:null===i?t.y:i}}}};return{id:"filler",afterDatasetsUpdate:function(r,o){var s,l,u,d,c=(r.data.datasets||[]).length,h=o.propagate,f=[];for(l=0;l<c;++l)s=r.getDatasetMeta(l),u=s.dataset,d=null,u&&u._model&&u instanceof t.elements.Line&&(d={visible:r.isDatasetVisible(l),fill:e(u,l,c),chart:r,el:u}),s.$filler=d,f.push(d);for(l=0;l<c;++l)d=f[l],d&&(d.fill=i(f,l,h),d.boundary=n(d),d.mapper=a(d))},beforeDatasetDraw:function(t,e){var n=e.meta.$filler;if(n){var i=n.el,a=i._view,r=i._children||[],o=n.mapper,u=a.backgroundColor||l.global.defaultColor;o&&u&&r.length&&s(t.ctx,r,o,a,u,i._loop)}}}}},{}],42:[function(t,e,n){"use strict";e.exports=function(t){function e(t,e){return t.usePointStyle?e*Math.SQRT2:t.boxWidth}function n(e,n){var i=new t.Legend({ctx:e.ctx,options:n,chart:e});a.configure(e,i,n),a.addBox(e,i),e.legend=i}var i=t.helpers,a=t.layoutService,r=i.noop;return t.defaults.global.legend={display:!0,position:"top",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e){var n=e.datasetIndex,i=this.chart,a=i.getDatasetMeta(n);a.hidden=null===a.hidden?!i.data.datasets[n].hidden:null,i.update()},onHover:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data;return i.isArray(e.datasets)?e.datasets.map(function(e,n){return{text:e.label,fillStyle:i.isArray(e.backgroundColor)?e.backgroundColor[0]:e.backgroundColor,hidden:!t.isDatasetVisible(n),lineCap:e.borderCapStyle,lineDash:e.borderDash,lineDashOffset:e.borderDashOffset,lineJoin:e.borderJoinStyle,lineWidth:e.borderWidth,strokeStyle:e.borderColor,pointStyle:e.pointStyle,datasetIndex:n}},this):[]}}},t.Legend=t.Element.extend({initialize:function(t){i.extend(this,t),this.legendHitBoxes=[],this.doughnutMode=!1},beforeUpdate:r,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:r,beforeSetDimensions:r,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:r,beforeBuildLabels:r,buildLabels:function(){var t=this,e=t.options.labels,n=e.generateLabels.call(t,t.chart);e.filter&&(n=n.filter(function(n){return e.filter(n,t.chart.data)})),t.options.reverse&&n.reverse(),t.legendItems=n},afterBuildLabels:r,beforeFit:r,fit:function(){var n=this,a=n.options,r=a.labels,o=a.display,s=n.ctx,l=t.defaults.global,u=i.getValueOrDefault,d=u(r.fontSize,l.defaultFontSize),c=u(r.fontStyle,l.defaultFontStyle),h=u(r.fontFamily,l.defaultFontFamily),f=i.fontString(d,c,h),g=n.legendHitBoxes=[],p=n.minSize,m=n.isHorizontal();if(m?(p.width=n.maxWidth,p.height=o?10:0):(p.width=o?10:0,p.height=n.maxHeight),o)if(s.font=f,m){var v=n.lineWidths=[0],y=n.legendItems.length?d+r.padding:0;s.textAlign="left",s.textBaseline="top",i.each(n.legendItems,function(t,i){var a=e(r,d),o=a+d/2+s.measureText(t.text).width;v[v.length-1]+o+r.padding>=n.width&&(y+=d+r.padding,v[v.length]=n.left),g[i]={left:0,top:0,width:o,height:d},v[v.length-1]+=o+r.padding}),p.height+=y}else{var b=r.padding,x=n.columnWidths=[],_=r.padding,k=0,w=0,M=d+b;i.each(n.legendItems,function(t,n){var i=e(r,d),a=i+d/2+s.measureText(t.text).width;w+M>p.height&&(_+=k+r.padding,x.push(k),k=0,w=0),k=Math.max(k,a),w+=M,g[n]={left:0,top:0,width:a,height:d}}),_+=k,x.push(k),p.width+=_}n.width=p.width,n.height=p.height},afterFit:r,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var n=this,a=n.options,r=a.labels,o=t.defaults.global,s=o.elements.line,l=n.width,u=n.lineWidths;if(a.display){var d,c=n.ctx,h=i.getValueOrDefault,f=h(r.fontColor,o.defaultFontColor),g=h(r.fontSize,o.defaultFontSize),p=h(r.fontStyle,o.defaultFontStyle),m=h(r.fontFamily,o.defaultFontFamily),v=i.fontString(g,p,m);c.textAlign="left",c.textBaseline="top",c.lineWidth=.5,c.strokeStyle=f,c.fillStyle=f,c.font=v;var y=e(r,g),b=n.legendHitBoxes,x=function(e,n,i){if(!(isNaN(y)||y<=0)){c.save(),c.fillStyle=h(i.fillStyle,o.defaultColor),c.lineCap=h(i.lineCap,s.borderCapStyle),c.lineDashOffset=h(i.lineDashOffset,s.borderDashOffset),c.lineJoin=h(i.lineJoin,s.borderJoinStyle),c.lineWidth=h(i.lineWidth,s.borderWidth),c.strokeStyle=h(i.strokeStyle,o.defaultColor);var r=0===h(i.lineWidth,s.borderWidth);if(c.setLineDash&&c.setLineDash(h(i.lineDash,s.borderDash)),a.labels&&a.labels.usePointStyle){var l=g*Math.SQRT2/2,u=l/Math.SQRT2,d=e+u,f=n+u;t.canvasHelpers.drawPoint(c,i.pointStyle,l,d,f)}else r||c.strokeRect(e,n,y,g),c.fillRect(e,n,y,g);c.restore()}},_=function(t,e,n,i){c.fillText(n.text,y+g/2+t,e),n.hidden&&(c.beginPath(),c.lineWidth=2,c.moveTo(y+g/2+t,e+g/2),c.lineTo(y+g/2+t+i,e+g/2),c.stroke())},k=n.isHorizontal();d=k?{x:n.left+(l-u[0])/2,y:n.top+r.padding,line:0}:{x:n.left+r.padding,y:n.top+r.padding,line:0};var w=g+r.padding;i.each(n.legendItems,function(t,e){var i=c.measureText(t.text).width,a=y+g/2+i,o=d.x,s=d.y;k?o+a>=l&&(s=d.y+=w,d.line++,o=d.x=n.left+(l-u[d.line])/2):s+w>n.bottom&&(o=d.x=o+n.columnWidths[d.line]+r.padding,s=d.y=n.top+r.padding,d.line++),x(o,s,t),b[e].left=o,b[e].top=s,_(o,s,t,i),k?d.x+=a+r.padding:d.y+=w})}},handleEvent:function(t){var e=this,n=e.options,i="mouseup"===t.type?"click":t.type,a=!1;if("mousemove"===i){if(!n.onHover)return}else{if("click"!==i)return;if(!n.onClick)return}var r=t.x,o=t.y;if(r>=e.left&&r<=e.right&&o>=e.top&&o<=e.bottom)for(var s=e.legendHitBoxes,l=0;l<s.length;++l){var u=s[l];if(r>=u.left&&r<=u.left+u.width&&o>=u.top&&o<=u.top+u.height){if("click"===i){n.onClick.call(e,t.native,e.legendItems[l]),a=!0;break}if("mousemove"===i){n.onHover.call(e,t.native,e.legendItems[l]),a=!0;break}}}return a}}),{id:"legend",beforeInit:function(t){var e=t.options.legend;e&&n(t,e)},beforeUpdate:function(e){var r=e.options.legend,o=e.legend;r?(r=i.configMerge(t.defaults.global.legend,r),o?(a.configure(e,o,r),o.options=r):n(e,r)):o&&(a.removeBox(e,o),delete e.legend)},afterEvent:function(t,e){var n=t.legend;n&&n.handleEvent(e)}}}},{}],43:[function(t,e,n){"use strict";e.exports=function(t){function e(e,n){var a=new t.Title({ctx:e.ctx,options:n,chart:e});i.configure(e,a,n),i.addBox(e,a),e.titleBlock=a}var n=t.helpers,i=t.layoutService,a=n.noop;return t.defaults.global.title={display:!1,position:"top",fullWidth:!0,weight:2e3,fontStyle:"bold",padding:10,text:""},t.Title=t.Element.extend({initialize:function(t){var e=this;n.extend(e,t),e.legendHitBoxes=[]},beforeUpdate:a,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:a,beforeSetDimensions:a,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:a,beforeBuildLabels:a,buildLabels:a,afterBuildLabels:a,beforeFit:a,fit:function(){var e=this,i=n.getValueOrDefault,a=e.options,r=t.defaults.global,o=a.display,s=i(a.fontSize,r.defaultFontSize),l=e.minSize;e.isHorizontal()?(l.width=e.maxWidth,l.height=o?s+2*a.padding:0):(l.width=o?s+2*a.padding:0,l.height=e.maxHeight),e.width=l.width,e.height=l.height},afterFit:a,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var e=this,i=e.ctx,a=n.getValueOrDefault,r=e.options,o=t.defaults.global;if(r.display){var s,l,u,d=a(r.fontSize,o.defaultFontSize),c=a(r.fontStyle,o.defaultFontStyle),h=a(r.fontFamily,o.defaultFontFamily),f=n.fontString(d,c,h),g=0,p=e.top,m=e.left,v=e.bottom,y=e.right;i.fillStyle=a(r.fontColor,o.defaultFontColor),i.font=f,e.isHorizontal()?(s=m+(y-m)/2,l=p+(v-p)/2,u=y-m):(s="left"===r.position?m+d/2:y-d/2,l=p+(v-p)/2,u=v-p,g=Math.PI*("left"===r.position?-.5:.5)),i.save(),i.translate(s,l),i.rotate(g),i.textAlign="center",i.textBaseline="middle",i.fillText(r.text,0,0,u),i.restore()}}}),{id:"title",beforeInit:function(t){var n=t.options.title;n&&e(t,n)},beforeUpdate:function(a){var r=a.options.title,o=a.titleBlock;r?(r=n.configMerge(t.defaults.global.title,r),o?(i.configure(a,o,r),o.options=r):e(a,r)):o&&(t.layoutService.removeBox(a,o),delete a.titleBlock)}}}},{}],44:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"bottom"},i=t.Scale.extend({getLabels:function(){var t=this.chart.data;return(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},determineDataLimits:function(){var t=this,n=t.getLabels();t.minIndex=0,t.maxIndex=n.length-1;var i;void 0!==t.options.ticks.min&&(i=e.indexOf(n,t.options.ticks.min),t.minIndex=i!==-1?i:t.minIndex),void 0!==t.options.ticks.max&&(i=e.indexOf(n,t.options.ticks.max),t.maxIndex=i!==-1?i:t.maxIndex),t.min=n[t.minIndex],t.max=n[t.maxIndex]},buildTicks:function(){var t=this,e=t.getLabels();t.ticks=0===t.minIndex&&t.maxIndex===e.length-1?e:e.slice(t.minIndex,t.maxIndex+1)},getLabelForIndex:function(t,e){var n=this,i=n.chart.data,a=n.isHorizontal();return i.yLabels&&!a?n.getRightValue(i.datasets[e].data[t]):n.ticks[t-n.minIndex]},getPixelForValue:function(t,e,n,i){var a,r=this,o=Math.max(r.maxIndex+1-r.minIndex-(r.options.gridLines.offsetGridLines?0:1),1);if(void 0!==t&&null!==t&&(a=r.isHorizontal()?t.x:t.y),void 0!==a||void 0!==t&&isNaN(e)){var s=r.getLabels();t=a||t;var l=s.indexOf(t);e=l!==-1?l:e}if(r.isHorizontal()){var u=r.width/o,d=u*(e-r.minIndex);return(r.options.gridLines.offsetGridLines&&i||r.maxIndex===r.minIndex&&i)&&(d+=u/2),r.left+Math.round(d)}var c=r.height/o,h=c*(e-r.minIndex);return r.options.gridLines.offsetGridLines&&i&&(h+=c/2),r.top+Math.round(h)},getPixelForTick:function(t,e){return this.getPixelForValue(this.ticks[t],t+this.minIndex,null,e)},getValueForPixel:function(t){var e,n=this,i=Math.max(n.ticks.length-(n.options.gridLines.offsetGridLines?0:1),1),a=n.isHorizontal(),r=(a?n.width:n.height)/i;return t-=a?n.left:n.top,n.options.gridLines.offsetGridLines&&(t-=r/2),e=t<=0?0:Math.round(t/r)},getBasePixel:function(){return this.bottom}});t.scaleService.registerScaleType("category",i,n)}},{}],45:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:t.Ticks.formatters.linear}},i=t.LinearScaleBase.extend({determineDataLimits:function(){function t(t){return s?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=n.chart,r=a.data,o=r.datasets,s=n.isHorizontal(),l=0,u=1;n.min=null,n.max=null;var d=i.stacked;if(void 0===d&&e.each(o,function(e,n){if(!d){var i=a.getDatasetMeta(n);a.isDatasetVisible(n)&&t(i)&&void 0!==i.stack&&(d=!0)}}),i.stacked||d){var c={};e.each(o,function(r,o){var s=a.getDatasetMeta(o),l=[s.type,void 0===i.stacked&&void 0===s.stack?o:"",s.stack].join(".");void 0===c[l]&&(c[l]={positiveValues:[],negativeValues:[]});var u=c[l].positiveValues,d=c[l].negativeValues;a.isDatasetVisible(o)&&t(s)&&e.each(r.data,function(t,e){var a=+n.getRightValue(t);isNaN(a)||s.data[e].hidden||(u[e]=u[e]||0,d[e]=d[e]||0,i.relativePoints?u[e]=100:a<0?d[e]+=a:u[e]+=a)})}),e.each(c,function(t){var i=t.positiveValues.concat(t.negativeValues),a=e.min(i),r=e.max(i);n.min=null===n.min?a:Math.min(n.min,a),n.max=null===n.max?r:Math.max(n.max,r)})}else e.each(o,function(i,r){var o=a.getDatasetMeta(r);a.isDatasetVisible(r)&&t(o)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||o.data[e].hidden||(null===n.min?n.min=i:i<n.min&&(n.min=i),null===n.max?n.max=i:i>n.max&&(n.max=i))})});n.min=isFinite(n.min)?n.min:l,n.max=isFinite(n.max)?n.max:u,this.handleTickRangeOptions()},getTickLimit:function(){var n,i=this,a=i.options.ticks;if(i.isHorizontal())n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.width/50));else{var r=e.getValueOrDefault(a.fontSize,t.defaults.global.defaultFontSize);n=Math.min(a.maxTicksLimit?a.maxTicksLimit:11,Math.ceil(i.height/(2*r)))}return n},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e,n=this,i=n.start,a=+n.getRightValue(t),r=n.end-i;return n.isHorizontal()?(e=n.left+n.width/r*(a-i),Math.round(e)):(e=n.bottom-n.height/r*(a-i),Math.round(e))},getValueForPixel:function(t){var e=this,n=e.isHorizontal(),i=n?e.width:e.height,a=(n?t-e.left:e.bottom-t)/i;return e.start+(e.end-e.start)*a},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}});t.scaleService.registerScaleType("linear",i,n)}},{}],46:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n=e.noop;t.LinearScaleBase=t.Scale.extend({handleTickRangeOptions:function(){var t=this,n=t.options,i=n.ticks;if(i.beginAtZero){var a=e.sign(t.min),r=e.sign(t.max);a<0&&r<0?t.max=0:a>0&&r>0&&(t.min=0)}void 0!==i.min?t.min=i.min:void 0!==i.suggestedMin&&(null===t.min?t.min=i.suggestedMin:t.min=Math.min(t.min,i.suggestedMin)),void 0!==i.max?t.max=i.max:void 0!==i.suggestedMax&&(null===t.max?t.max=i.suggestedMax:t.max=Math.max(t.max,i.suggestedMax)),t.min===t.max&&(t.max++,i.beginAtZero||t.min--)},getTickLimit:n,handleDirectionalChanges:n,buildTicks:function(){var n=this,i=n.options,a=i.ticks,r=n.getTickLimit();r=Math.max(2,r);var o={maxTicks:r,min:a.min,max:a.max,stepSize:e.getValueOrDefault(a.fixedStepSize,a.stepSize)},s=n.ticks=t.Ticks.generators.linear(o,n);n.handleDirectionalChanges(),n.max=e.max(s),n.min=e.min(s),a.reverse?(s.reverse(),n.start=n.max,n.end=n.min):(n.start=n.min,n.end=n.max)},convertTicksToLabels:function(){var e=this;e.ticksAsNumbers=e.ticks.slice(),e.zeroLineIndex=e.ticks.indexOf(0),t.Scale.prototype.convertTicksToLabels.call(e)}})}},{}],47:[function(t,e,n){"use strict";e.exports=function(t){var e=t.helpers,n={position:"left",ticks:{callback:t.Ticks.formatters.logarithmic}},i=t.Scale.extend({determineDataLimits:function(){function t(t){return u?t.xAxisID===n.id:t.yAxisID===n.id}var n=this,i=n.options,a=i.ticks,r=n.chart,o=r.data,s=o.datasets,l=e.getValueOrDefault,u=n.isHorizontal();n.min=null,n.max=null,n.minNotZero=null;var d=i.stacked;if(void 0===d&&e.each(s,function(e,n){if(!d){var i=r.getDatasetMeta(n);r.isDatasetVisible(n)&&t(i)&&void 0!==i.stack&&(d=!0)}}),i.stacked||d){var c={};e.each(s,function(a,o){var s=r.getDatasetMeta(o),l=[s.type,void 0===i.stacked&&void 0===s.stack?o:"",s.stack].join(".");r.isDatasetVisible(o)&&t(s)&&(void 0===c[l]&&(c[l]=[]),e.each(a.data,function(t,e){var a=c[l],r=+n.getRightValue(t);isNaN(r)||s.data[e].hidden||(a[e]=a[e]||0,i.relativePoints?a[e]=100:a[e]+=r)}))}),e.each(c,function(t){var i=e.min(t),a=e.max(t);n.min=null===n.min?i:Math.min(n.min,i),n.max=null===n.max?a:Math.max(n.max,a)})}else e.each(s,function(i,a){var o=r.getDatasetMeta(a);r.isDatasetVisible(a)&&t(o)&&e.each(i.data,function(t,e){var i=+n.getRightValue(t);isNaN(i)||o.data[e].hidden||(null===n.min?n.min=i:i<n.min&&(n.min=i),null===n.max?n.max=i:i>n.max&&(n.max=i),0!==i&&(null===n.minNotZero||i<n.minNotZero)&&(n.minNotZero=i))})});n.min=l(a.min,n.min),n.max=l(a.max,n.max),n.min===n.max&&(0!==n.min&&null!==n.min?(n.min=Math.pow(10,Math.floor(e.log10(n.min))-1),n.max=Math.pow(10,Math.floor(e.log10(n.max))+1)):(n.min=1,n.max=10))},buildTicks:function(){var n=this,i=n.options,a=i.ticks,r={min:a.min,max:a.max},o=n.ticks=t.Ticks.generators.logarithmic(r,n);n.isHorizontal()||o.reverse(),n.max=e.max(o),n.min=e.min(o),a.reverse?(o.reverse(),n.start=n.max,n.end=n.min):(n.start=n.min,n.end=n.max)},convertTicksToLabels:function(){this.tickValues=this.ticks.slice(),t.Scale.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){return this.getPixelForValue(this.tickValues[t])},getPixelForValue:function(t){var n,i,a,r=this,o=r.start,s=+r.getRightValue(t),l=r.options,u=l.ticks;return r.isHorizontal()?(a=e.log10(r.end)-e.log10(o),0===s?i=r.left:(n=r.width,i=r.left+n/a*(e.log10(s)-e.log10(o)))):(n=r.height,0!==o||u.reverse?0===r.end&&u.reverse?(a=e.log10(r.start)-e.log10(r.minNotZero),i=s===r.end?r.top:s===r.minNotZero?r.top+.02*n:r.top+.02*n+.98*n/a*(e.log10(s)-e.log10(r.minNotZero))):0===s?i=u.reverse?r.top:r.bottom:(a=e.log10(r.end)-e.log10(o),n=r.height,i=r.bottom-n/a*(e.log10(s)-e.log10(o))):(a=e.log10(r.end)-e.log10(r.minNotZero),i=s===o?r.bottom:s===r.minNotZero?r.bottom-.02*n:r.bottom-.02*n-.98*n/a*(e.log10(s)-e.log10(r.minNotZero)))),i},getValueForPixel:function(t){var n,i,a=this,r=e.log10(a.end)-e.log10(a.start);return a.isHorizontal()?(i=a.width,n=a.start*Math.pow(10,(t-a.left)*r/i)):(i=a.height,n=Math.pow(10,(a.bottom-t)*r/i)/a.start),n}});t.scaleService.registerScaleType("logarithmic",i,n)}},{}],48:[function(t,e,n){"use strict";e.exports=function(t){function e(t){var e=t.options;return e.angleLines.display||e.pointLabels.display?t.chart.data.labels.length:0}function n(t){var e=t.options.pointLabels,n=f.getValueOrDefault(e.fontSize,g.defaultFontSize),i=f.getValueOrDefault(e.fontStyle,g.defaultFontStyle),a=f.getValueOrDefault(e.fontFamily,g.defaultFontFamily),r=f.fontString(n,i,a);return{size:n,style:i,family:a,font:r}}function i(t,e,n){return f.isArray(n)?{w:f.longestText(t,t.font,n),h:n.length*e+1.5*(n.length-1)*e}:{w:t.measureText(n).width,h:e}}function a(t,e,n,i,a){return t===i||t===a?{start:e-n/2,end:e+n/2}:t<i||t>a?{start:e-n-5,end:e}:{start:e,end:e+n+5}}function r(t){var r,o,s,l=n(t),u=Math.min(t.height/2,t.width/2),d={r:t.width,l:0,t:t.height,b:0},c={};t.ctx.font=l.font,t._pointLabelSizes=[];var h=e(t);for(r=0;r<h;r++){s=t.getPointPosition(r,u),o=i(t.ctx,l.size,t.pointLabels[r]||""),t._pointLabelSizes[r]=o;var g=t.getIndexAngle(r),p=f.toDegrees(g)%360,m=a(p,s.x,o.w,0,180),v=a(p,s.y,o.h,90,270);m.start<d.l&&(d.l=m.start,c.l=g),m.end>d.r&&(d.r=m.end,c.r=g),v.start<d.t&&(d.t=v.start,c.t=g),v.end>d.b&&(d.b=v.end,c.b=g)}t.setReductions(u,d,c)}function o(t){var e=Math.min(t.height/2,t.width/2);t.drawingArea=Math.round(e),t.setCenterPoint(0,0,0,0)}function s(t){return 0===t||180===t?"center":t<180?"left":"right"}function l(t,e,n,i){if(f.isArray(e))for(var a=n.y,r=1.5*i,o=0;o<e.length;++o)t.fillText(e[o],n.x,a),a+=r;else t.fillText(e,n.x,n.y)}function u(t,e,n){90===t||270===t?n.y-=e.h/2:(t>270||t<90)&&(n.y-=e.h)}function d(t){var i=t.ctx,a=f.getValueOrDefault,r=t.options,o=r.angleLines,d=r.pointLabels;i.lineWidth=o.lineWidth,i.strokeStyle=o.color;var c=t.getDistanceFromCenterForValue(r.reverse?t.min:t.max),h=n(t);i.textBaseline="top";for(var p=e(t)-1;p>=0;p--){if(o.display){var m=t.getPointPosition(p,c);i.beginPath(),i.moveTo(t.xCenter,t.yCenter),i.lineTo(m.x,m.y),i.stroke(),i.closePath()}if(d.display){var v=t.getPointPosition(p,c+5),y=a(d.fontColor,g.defaultFontColor);i.font=h.font,i.fillStyle=y;var b=t.getIndexAngle(p),x=f.toDegrees(b);i.textAlign=s(x),u(x,t._pointLabelSizes[p],v),l(i,t.pointLabels[p]||"",v,h.size)}}}function c(t,n,i,a){var r=t.ctx;if(r.strokeStyle=f.getValueAtIndexOrDefault(n.color,a-1),r.lineWidth=f.getValueAtIndexOrDefault(n.lineWidth,a-1),t.options.gridLines.circular)r.beginPath(),r.arc(t.xCenter,t.yCenter,i,0,2*Math.PI),
16
- r.closePath(),r.stroke();else{var o=e(t);if(0===o)return;r.beginPath();var s=t.getPointPosition(0,i);r.moveTo(s.x,s.y);for(var l=1;l<o;l++)s=t.getPointPosition(l,i),r.lineTo(s.x,s.y);r.closePath(),r.stroke()}}function h(t){return f.isNumber(t)?t:0}var f=t.helpers,g=t.defaults.global,p={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1},gridLines:{circular:!1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2,callback:t.Ticks.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(t){return t}}},m=t.LinearScaleBase.extend({setDimensions:function(){var t=this,e=t.options,n=e.ticks;t.width=t.maxWidth,t.height=t.maxHeight,t.xCenter=Math.round(t.width/2),t.yCenter=Math.round(t.height/2);var i=f.min([t.height,t.width]),a=f.getValueOrDefault(n.fontSize,g.defaultFontSize);t.drawingArea=e.display?i/2-(a/2+n.backdropPaddingY):i/2},determineDataLimits:function(){var t=this,e=t.chart,n=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;f.each(e.data.datasets,function(a,r){if(e.isDatasetVisible(r)){var o=e.getDatasetMeta(r);f.each(a.data,function(e,a){var r=+t.getRightValue(e);isNaN(r)||o.data[a].hidden||(n=Math.min(r,n),i=Math.max(r,i))})}}),t.min=n===Number.POSITIVE_INFINITY?0:n,t.max=i===Number.NEGATIVE_INFINITY?0:i,t.handleTickRangeOptions()},getTickLimit:function(){var t=this.options.ticks,e=f.getValueOrDefault(t.fontSize,g.defaultFontSize);return Math.min(t.maxTicksLimit?t.maxTicksLimit:11,Math.ceil(this.drawingArea/(1.5*e)))},convertTicksToLabels:function(){var e=this;t.LinearScaleBase.prototype.convertTicksToLabels.call(e),e.pointLabels=e.chart.data.labels.map(e.options.pointLabels.callback,e)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},fit:function(){this.options.pointLabels.display?r(this):o(this)},setReductions:function(t,e,n){var i=this,a=e.l/Math.sin(n.l),r=Math.max(e.r-i.width,0)/Math.sin(n.r),o=-e.t/Math.cos(n.t),s=-Math.max(e.b-i.height,0)/Math.cos(n.b);a=h(a),r=h(r),o=h(o),s=h(s),i.drawingArea=Math.min(Math.round(t-(a+r)/2),Math.round(t-(o+s)/2)),i.setCenterPoint(a,r,o,s)},setCenterPoint:function(t,e,n,i){var a=this,r=a.width-e-a.drawingArea,o=t+a.drawingArea,s=n+a.drawingArea,l=a.height-i-a.drawingArea;a.xCenter=Math.round((o+r)/2+a.left),a.yCenter=Math.round((s+l)/2+a.top)},getIndexAngle:function(t){var n=2*Math.PI/e(this),i=this.chart.options&&this.chart.options.startAngle?this.chart.options.startAngle:0,a=i*Math.PI*2/360;return t*n+a},getDistanceFromCenterForValue:function(t){var e=this;if(null===t)return 0;var n=e.drawingArea/(e.max-e.min);return e.options.reverse?(e.max-t)*n:(t-e.min)*n},getPointPosition:function(t,e){var n=this,i=n.getIndexAngle(t)-Math.PI/2;return{x:Math.round(Math.cos(i)*e)+n.xCenter,y:Math.round(Math.sin(i)*e)+n.yCenter}},getPointPositionForValue:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},getBasePosition:function(){var t=this,e=t.min,n=t.max;return t.getPointPositionForValue(0,t.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0)},draw:function(){var t=this,e=t.options,n=e.gridLines,i=e.ticks,a=f.getValueOrDefault;if(e.display){var r=t.ctx,o=a(i.fontSize,g.defaultFontSize),s=a(i.fontStyle,g.defaultFontStyle),l=a(i.fontFamily,g.defaultFontFamily),u=f.fontString(o,s,l);f.each(t.ticks,function(s,l){if(l>0||e.reverse){var d=t.getDistanceFromCenterForValue(t.ticksAsNumbers[l]),h=t.yCenter-d;if(n.display&&0!==l&&c(t,n,d,l),i.display){var f=a(i.fontColor,g.defaultFontColor);if(r.font=u,i.showLabelBackdrop){var p=r.measureText(s).width;r.fillStyle=i.backdropColor,r.fillRect(t.xCenter-p/2-i.backdropPaddingX,h-o/2-i.backdropPaddingY,p+2*i.backdropPaddingX,o+2*i.backdropPaddingY)}r.textAlign="center",r.textBaseline="middle",r.fillStyle=f,r.fillText(s,t.xCenter,h)}}}),(e.angleLines.display||e.pointLabels.display)&&d(t)}}});t.scaleService.registerScaleType("radialLinear",m,p)}},{}],49:[function(t,e,n){"use strict";var i=t(6);i="function"==typeof i?i:window.moment,e.exports=function(t){function e(t,e){var n=t.options.time;if("string"==typeof n.parser)return i(e,n.parser);if("function"==typeof n.parser)return n.parser(e);if("function"==typeof e.getMonth||"number"==typeof e)return i(e);if(e.isValid&&e.isValid())return e;var a=n.format;return"string"!=typeof a&&a.call?(console.warn("options.time.format is deprecated and replaced by options.time.parser."),a(e)):i(e,a)}function n(t,e,n,i){for(var a,r=Object.keys(s),o=r.length,l=r.indexOf(t);l<o;l++){a=r[l];var u=s[a],d=u.steps&&u.steps[u.steps.length-1]||u.maxStep;if(void 0===d||Math.ceil((n-e)/(d*u.size))<=i)break}return a}function a(t,e,n,i){var a=s[n],r=a.size,o=Math.ceil((e-t)/r),l=1,u=e-t;if(a.steps)for(var d=a.steps.length,c=0;c<d&&o>i;c++)l=a.steps[c],o=Math.ceil(u/(r*l));else for(;o>i&&i>0;)++l,o=Math.ceil(u/(r*l));return l}function r(t,e,n){var a=[];if(t.maxTicks){var r=t.stepSize;a.push(void 0!==t.min?t.min:n.min);for(var o=i(n.min);o.add(r,t.unit).valueOf()<n.max;)a.push(o.valueOf());var s=t.max||n.max;a[a.length-1]!==s&&a.push(s)}return a}var o=t.helpers,s={millisecond:{size:1,steps:[1,2,5,10,20,50,100,250,500]},second:{size:1e3,steps:[1,2,5,10,30]},minute:{size:6e4,steps:[1,2,5,10,30]},hour:{size:36e5,steps:[1,2,3,6,12]},day:{size:864e5,steps:[1,2,5]},week:{size:6048e5,maxStep:4},month:{size:2628e6,maxStep:3},quarter:{size:7884e6,maxStep:4},year:{size:3154e7,maxStep:!1}},l={position:"bottom",time:{parser:!1,format:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm:ss a",hour:"MMM D, hA",day:"ll",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"}},ticks:{autoSkip:!1}};t.Ticks.generators.time=function(t,e){var n,a,o=t.isoWeekday;return"week"===t.unit&&o!==!1?(n=i(e.min).startOf("isoWeek").isoWeekday(o).valueOf(),a=i(e.max).startOf("isoWeek").isoWeekday(o),e.max-a>0&&a.add(1,"week"),a=a.valueOf()):(n=i(e.min).startOf(t.unit).valueOf(),a=i(e.max).startOf(t.unit),e.max-a>0&&a.add(1,t.unit),a=a.valueOf()),r(t,e,{min:n,max:a})};var u=t.Scale.extend({initialize:function(){if(!i)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");t.Scale.prototype.initialize.call(this)},determineDataLimits:function(){var t,n=this,i=n.options.time,a=Number.MAX_SAFE_INTEGER,r=Number.MIN_SAFE_INTEGER,s=n.chart.data,l={labels:[],datasets:[]};o.each(s.labels,function(o,s){var u=e(n,o);u.isValid()&&(i.round&&u.startOf(i.round),t=u.valueOf(),a=Math.min(t,a),r=Math.max(t,r),l.labels[s]=t)}),o.each(s.datasets,function(s,u){var d=[];"object"==typeof s.data[0]&&null!==s.data[0]&&n.chart.isDatasetVisible(u)?o.each(s.data,function(o,s){var l=e(n,n.getRightValue(o));l.isValid()&&(i.round&&l.startOf(i.round),t=l.valueOf(),a=Math.min(t,a),r=Math.max(t,r),d[s]=t)}):d=l.labels.slice(),l.datasets[u]=d}),n.dataMin=a,n.dataMax=r,n._parsedData=l},buildTicks:function(){var i,r,s=this,l=s.options.time,u=s.dataMin,d=s.dataMax;if(l.min){var c=e(s,l.min);l.round&&c.round(l.round),i=c.valueOf()}l.max&&(r=e(s,l.max).valueOf());var h=s.getLabelCapacity(i||u),f=l.unit||n(l.minUnit,i||u,r||d,h);s.displayFormat=l.displayFormats[f];var g=l.stepSize||a(i||u,r||d,f,h);s.ticks=t.Ticks.generators.time({maxTicks:h,min:i,max:r,stepSize:g,unit:f,isoWeekday:l.isoWeekday},{min:u,max:d}),s.max=o.max(s.ticks),s.min=o.min(s.ticks)},getLabelForIndex:function(t,n){var i=this,a=i.chart.data.labels&&t<i.chart.data.labels.length?i.chart.data.labels[t]:"",r=i.chart.data.datasets[n].data[t];return null!==r&&"object"==typeof r&&(a=i.getRightValue(r)),i.options.time.tooltipFormat&&(a=e(i,a).format(i.options.time.tooltipFormat)),a},tickFormatFunction:function(t,e,n){var i=t.format(this.displayFormat),a=this.options.ticks,r=o.getValueOrDefault(a.callback,a.userCallback);return r?r(i,e,n):i},convertTicksToLabels:function(){var t=this;t.ticksAsTimestamps=t.ticks,t.ticks=t.ticks.map(function(t){return i(t)}).map(t.tickFormatFunction,t)},getPixelForOffset:function(t){var e=this,n=e.max-e.min,i=n?(t-e.min)/n:0;if(e.isHorizontal()){var a=e.width*i;return e.left+Math.round(a)}var r=e.height*i;return e.top+Math.round(r)},getPixelForValue:function(t,n,i){var a=this,r=null;if(void 0!==n&&void 0!==i&&(r=a._parsedData.datasets[i][n]),null===r&&(t&&t.isValid||(t=e(a,a.getRightValue(t))),t&&t.isValid&&t.isValid()&&(r=t.valueOf())),null!==r)return a.getPixelForOffset(r)},getPixelForTick:function(t){return this.getPixelForOffset(this.ticksAsTimestamps[t])},getValueForPixel:function(t){var e=this,n=e.isHorizontal()?e.width:e.height,a=(t-(e.isHorizontal()?e.left:e.top))/n;return i(e.min+a*(e.max-e.min))},getLabelWidth:function(e){var n=this,i=n.options.ticks,a=n.ctx.measureText(e).width,r=Math.cos(o.toRadians(i.maxRotation)),s=Math.sin(o.toRadians(i.maxRotation)),l=o.getValueOrDefault(i.fontSize,t.defaults.global.defaultFontSize);return a*r+l*s},getLabelCapacity:function(t){var e=this;e.displayFormat=e.options.time.displayFormats.millisecond;var n=e.tickFormatFunction(i(t),0,[]),a=e.getLabelWidth(n),r=e.isHorizontal()?e.width:e.height,o=r/a;return o}});t.scaleService.registerScaleType("time",u,l)}},{6:6}]},{},[7])(7)});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/woosea_key.js CHANGED
@@ -26,7 +26,7 @@ jQuery(document).ready(function($) {
26
  var license_key = $('#license-key').val();
27
 
28
  jQuery.ajax({
29
- url: 'https://www.adtribes.io/check/license.php?key=' + license_key + '&email=' + license_email + '&domain=' + root_domain + '&version=10.9.9',
30
  jsonp: 'callback',
31
  dataType: 'jsonp',
32
  type: 'GET',
26
  var license_key = $('#license-key').val();
27
 
28
  jQuery.ajax({
29
+ url: 'https://www.adtribes.io/check/license.php?key=' + license_key + '&email=' + license_email + '&domain=' + root_domain + '&version=11.0.0',
30
  jsonp: 'callback',
31
  dataType: 'jsonp',
32
  type: 'GET',
pages/admin/woosea-statistics-feed.php DELETED
@@ -1,135 +0,0 @@
1
- <?php
2
- /**
3
- * Change default footer text, asking to review our plugin
4
- **/
5
- function my_footer_text($default) {
6
- return _e( 'If you like our <strong>WooCommerce Product Feed PRO</strong> plugin please leave us a <a href="https://wordpress.org/support/plugin/woo-product-feed-pro/reviews?rate=5#new-post" target="_blank" class="woo-product-feed-pro-ratingRequest">&#9733;&#9733;&#9733;&#9733;&#9733;</a> rating. Thanks in advance!','woo-product_feed-pro' );
7
- }
8
- add_filter('admin_footer_text', 'my_footer_text');
9
-
10
- /**
11
- * Create notification object and get message and message type as WooCommerce is inactive
12
- * also set variable allowed on 0 to disable submit button on step 1 of configuration
13
- */
14
- $notifications_obj = new WooSEA_Get_Admin_Notifications;
15
- if (!in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
16
- $notifications_box = $notifications_obj->get_admin_notifications ( "9", "false" );
17
- } else {
18
- $notifications_box = $notifications_obj->get_admin_notifications ( '10', 'false' );
19
- }
20
-
21
- if (array_key_exists('project_hash', $_GET)){
22
- $project = WooSEA_Update_Project::get_project_data(sanitize_text_field($_GET['project_hash']));
23
- $project_hash = $_GET['project_hash'];
24
- $step = $_GET['step'];
25
- if(isset($project['history_products'])){
26
- $project_history = $project['history_products'];
27
- } else {
28
- $project_history = array();
29
- }
30
- $projectname = ucfirst($project['projectname']);
31
-
32
- $labels = array();
33
- $data = array();
34
-
35
- foreach($project_history as $key => $value){
36
- array_push($labels, $key);
37
- array_push($data, $value);
38
- }
39
- }
40
-
41
- ?>
42
- <div class="wrap">
43
- <div class="woo-product-feed-pro-form-style-2">
44
- <table class="woo-product-feed-pro-table">
45
- <tbody class="woo-product-feed-pro-body">
46
- <div class="woo-product-feed-pro-form-style-2-heading"><?php _e( 'Feed statistics','woo-product-feed-pro' );?></div>
47
-
48
- <div class="<?php _e($notifications_box['message_type']); ?>">
49
- <p><?php _e($notifications_box['message'], 'sample-text-domain' ); ?></p>
50
- </div>
51
-
52
- <tr>
53
- <td align="center">
54
- <input type="hidden" id="project_hash" name="project_hash" value="<?php print "$project_hash";?>">
55
- <input type="hidden" id="step" name="step" value="<?php print "$step";?>">
56
-
57
- <span style="background: white; width: 99%; display:block;">
58
- <canvas id="myChart" width="150" height="75"></canvas>
59
- </span>
60
-
61
- <script type="text/javascript">
62
- var labels = <?php echo json_encode($labels); ?>;
63
- var data = <?php echo json_encode($data); ?>;
64
- var projectname = <?php echo json_encode($projectname); ?>;
65
- var ctx = document.getElementById("myChart");
66
-
67
- var myChart = new Chart(ctx, {
68
- type: 'bar',
69
- data: {
70
- labels: labels,
71
- datasets: [{
72
- label: "Number of products in feed",
73
- data: data,
74
- backgroundColor: [
75
- 'rgba(144, 91, 137, 0.4)',
76
- 'rgba(54, 162, 235, 0.4)',
77
- 'rgba(255, 206, 86, 0.4)',
78
- 'rgba(75, 192, 192, 0.4)',
79
- 'rgba(153, 102, 255, 0.4)',
80
- 'rgba(255, 159, 64, 0.4)'
81
- ],
82
- borderColor: [
83
- 'rgba(144, 91, 137, 1)',
84
- 'rgba(54, 162, 235, 1)',
85
- 'rgba(255, 206, 86, 1)',
86
- 'rgba(75, 192, 192, 1)',
87
- 'rgba(153, 102, 255, 1)',
88
- 'rgba(255, 159, 64, 1)'
89
- ],
90
- borderWidth: 1
91
- }]
92
- },
93
- options: {
94
- responsive: true,
95
- title:{
96
- display:true,
97
- text:projectname,
98
- },
99
- tooltips: {
100
- mode: 'index',
101
- intersect: false,
102
- },
103
- hover: {
104
- mode: 'nearest',
105
- intersect: true
106
- },
107
- scales: {
108
- xAxes: [{
109
- display: true,
110
- scaleLabel: {
111
- display: true,
112
- labelString: 'Date / Time'
113
- }
114
- }],
115
- yAxes: [{
116
- display: true,
117
- scaleLabel: {
118
- display: true,
119
- labelString: 'Products'
120
- },
121
- ticks: {
122
- beginAtZero:true
123
- }
124
- }]
125
- }
126
- }
127
-
128
- });
129
- </script>
130
- </td>
131
- </tr>
132
- </tbody>
133
- </table>
134
- </div>
135
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -5,7 +5,7 @@ License URI: http://www.gnu.org/licenses/gpl.html
5
  Tags: Product Feed, Google Shopping, Google Shopping Feed, WooCommerce Product Feed, WooCommerce Product Feed PRO, Bing Shopping, Bing product feed, Bing remarking, Google Merchant Feed, Google DRM Feed, Google Dynamic Remarketing Feed, Facebook feed, Google feed, Bing feed, Facebook Product Feed, Facebook pixel, Facebook Conversion API, Facebook CAPI,Facebook Dynamic remarketing, Data Feed, WooCommerce Feed, XML product feed, CSV product feed, TSV, TXT product feed, comparison shopping engines, comparison shopping websites, vergelijk.nl, vergelijk.be, vertaa.fi, beslist.nl, kieskeurig.nl, bol.com, raketten, pricerunner, pricegrabber, Buy, leGuide, Kelkoo, Twenga, Yandex, Etsy, Dealtime, Shopzilla, Billiger, Google Product Review feed
6
  Requires at least: 4.5
7
  Tested up to: 5.8
8
- Stable tag: 10.9.9
9
 
10
  == Description ==
11
 
@@ -339,6 +339,9 @@ Questions left or unanswered? Please do not hesitate to contact us at support@ad
339
 
340
  === Changelog ===
341
 
 
 
 
342
  = 10.9.9 (2021-12-10) =
343
  * Solved a PHP notice
344
 
@@ -3510,6 +3513,9 @@ Questions left or unanswered? Please do not hesitate to contact us at support@ad
3510
 
3511
  == Upgrade Notice ==
3512
 
 
 
 
3513
  = 10.9.9 =
3514
  Solved a PHP notice
3515
 
5
  Tags: Product Feed, Google Shopping, Google Shopping Feed, WooCommerce Product Feed, WooCommerce Product Feed PRO, Bing Shopping, Bing product feed, Bing remarking, Google Merchant Feed, Google DRM Feed, Google Dynamic Remarketing Feed, Facebook feed, Google feed, Bing feed, Facebook Product Feed, Facebook pixel, Facebook Conversion API, Facebook CAPI,Facebook Dynamic remarketing, Data Feed, WooCommerce Feed, XML product feed, CSV product feed, TSV, TXT product feed, comparison shopping engines, comparison shopping websites, vergelijk.nl, vergelijk.be, vertaa.fi, beslist.nl, kieskeurig.nl, bol.com, raketten, pricerunner, pricegrabber, Buy, leGuide, Kelkoo, Twenga, Yandex, Etsy, Dealtime, Shopzilla, Billiger, Google Product Review feed
6
  Requires at least: 4.5
7
  Tested up to: 5.8
8
+ Stable tag: 11.0.0
9
 
10
  == Description ==
11
 
339
 
340
  === Changelog ===
341
 
342
+ = 11.0.0 (2012-12-11) =
343
+ * Removed unused variables from some functions and did an extra array check
344
+
345
  = 10.9.9 (2021-12-10) =
346
  * Solved a PHP notice
347
 
3513
 
3514
  == Upgrade Notice ==
3515
 
3516
+ = 11.0.0 =
3517
+ Removed unused variables from some functions and did an extra array check
3518
+
3519
  = 10.9.9 =
3520
  Solved a PHP notice
3521
 
trunk/TODO.txt ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ So you found my to-do list for this plugin? Well, hope you enjoy the little sneak preview of what's coming.
2
+ Missing some features you might like? Drop me a line at support@adtribes.io and we might just add it to the list. Thanks!
3
+
4
+ Tutorial / Blog posts:
5
+ - Explain all the different fields/attributes that can be selected from the drop-downs
6
+ - product highlight / details article
7
+
8
+ Priority issues:
9
+ - Add automotive fields for Facebook feed, see: https://developers.facebook.com/docs/marketing-api/dynamic-ads-auto/auto-catalog/
10
+ - Autosuggest for category mapping broken
11
+ - Add AddToCart event on buttons again
12
+ - Add Vivino EXTRA fields, see: https://vivino.slab.com/public/posts/9gq0o3dg
13
+ - Local product feed - store code should also work with an attribute and not just static values
14
+ - Add Pinterest Tag; https://help.pinterest.com/nl/business/article/install-the-pinterest-tag
15
+ - License key input field needs to be a password field (asterixes)
16
+ - Allow adding multiple pictures to Yandex feeds, see:https://wordpress.org/support/topic/yandex-yml-support/#post-14344829
17
+ - A seperate FB pixel per WPML website / language
18
+ - Add a preview option so only 5-10 products are being generated
19
+ - Own hosted plugin updating: https://rudrastyh.com/wordpress/self-hosted-plugin-update.html
20
+ - Google local product feed inventory in XML format (not just TXT like it is now)
21
+ - Add support for Multisites
22
+ - Add a filter on review score (and amount of reviews)
23
+ - Make extra woosea fields available for front-end usage
24
+ - Add header to extra fields on product edit pages
25
+ - Add possibility to create OR rules
26
+ - Add support for Google My Business product feeds
27
+ - AMAZON integration:
28
+ - requires a professional seller account, 39 dollar a month, before being able to create a developer account
29
+ - only then we can use their MWS service needed to connect our plugin
trunk/channels/index.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Nothing to see here
4
+ */
5
+ ?>
trunk/channels/taxonomy/google_shopping.txt ADDED
@@ -0,0 +1,5582 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 1 - Animals & Pet Supplies
2
+ 3237 - Animals & Pet Supplies > Live Animals
3
+ 2 - Animals & Pet Supplies > Pet Supplies
4
+ 3 - Animals & Pet Supplies > Pet Supplies > Bird Supplies
5
+ 7385 - Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories
6
+ 499954 - Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories > Bird Cage Bird Baths
7
+ 7386 - Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cage Accessories > Bird Cage Food & Water Dishes
8
+ 4989 - Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Cages & Stands
9
+ 4990 - Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Food
10
+ 7398 - Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Gyms & Playstands
11
+ 4991 - Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Ladders & Perches
12
+ 4992 - Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Toys
13
+ 4993 - Animals & Pet Supplies > Pet Supplies > Bird Supplies > Bird Treats
14
+ 4 - Animals & Pet Supplies > Pet Supplies > Cat Supplies
15
+ 5082 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Apparel
16
+ 4433 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Beds
17
+ 3367 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Food
18
+ 543684 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Food > Non-prescription Cat Food
19
+ 543683 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Food > Prescription Cat Food
20
+ 4997 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Furniture
21
+ 500059 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Furniture Accessories
22
+ 4999 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter
23
+ 8069 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Box Liners
24
+ 7142 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Box Mats
25
+ 5000 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Litter Boxes
26
+ 5001 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Toys
27
+ 5002 - Animals & Pet Supplies > Pet Supplies > Cat Supplies > Cat Treats
28
+ 5 - Animals & Pet Supplies > Pet Supplies > Dog Supplies
29
+ 5004 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Apparel
30
+ 4434 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Beds
31
+ 7372 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Diaper Pads & Liners
32
+ 499900 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Diapers
33
+ 3530 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Food
34
+ 543682 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Food > Non-prescription Dog Food
35
+ 543681 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Food > Prescription Dog Food
36
+ 5094 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Houses
37
+ 7428 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Kennel & Run Accessories
38
+ 7274 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Kennels & Runs
39
+ 5010 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Toys
40
+ 8123 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Treadmills
41
+ 5011 - Animals & Pet Supplies > Pet Supplies > Dog Supplies > Dog Treats
42
+ 6 - Animals & Pet Supplies > Pet Supplies > Fish Supplies
43
+ 505303 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium & Pond Tubing
44
+ 505307 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Air Stones & Diffusers
45
+ 500038 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Cleaning Supplies
46
+ 5019 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Decor
47
+ 5020 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Filters
48
+ 505306 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Fish Nets
49
+ 5021 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Gravel & Substrates
50
+ 5079 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Lighting
51
+ 6951 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Overflow Boxes
52
+ 5023 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Stands
53
+ 500062 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Temperature Controllers
54
+ 5161 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquarium Water Treatments
55
+ 3238 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquariums
56
+ 6085 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Aquatic Plant Fertilizers
57
+ 6403 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Fish Feeders
58
+ 5024 - Animals & Pet Supplies > Pet Supplies > Fish Supplies > Fish Food
59
+ 6983 - Animals & Pet Supplies > Pet Supplies > Pet Agility Equipment
60
+ 6811 - Animals & Pet Supplies > Pet Supplies > Pet Apparel Hangers
61
+ 500084 - Animals & Pet Supplies > Pet Supplies > Pet Bed Accessories
62
+ 5092 - Animals & Pet Supplies > Pet Supplies > Pet Bells & Charms
63
+ 6978 - Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors
64
+ 6980 - Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Glucose Meters
65
+ 6982 - Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Pedometers
66
+ 6981 - Animals & Pet Supplies > Pet Supplies > Pet Biometric Monitors > Pet Thermometers
67
+ 7143 - Animals & Pet Supplies > Pet Supplies > Pet Bowl Mats
68
+ 8513 - Animals & Pet Supplies > Pet Supplies > Pet Bowl Stands
69
+ 6252 - Animals & Pet Supplies > Pet Supplies > Pet Bowls, Feeders & Waterers
70
+ 500026 - Animals & Pet Supplies > Pet Supplies > Pet Carrier & Crate Accessories
71
+ 6251 - Animals & Pet Supplies > Pet Supplies > Pet Carriers & Crates
72
+ 6250 - Animals & Pet Supplies > Pet Supplies > Pet Collars & Harnesses
73
+ 6321 - Animals & Pet Supplies > Pet Supplies > Pet Containment Systems
74
+ 505811 - Animals & Pet Supplies > Pet Supplies > Pet Door Accessories
75
+ 4497 - Animals & Pet Supplies > Pet Supplies > Pet Doors
76
+ 8050 - Animals & Pet Supplies > Pet Supplies > Pet Eye Drops & Lubricants
77
+ 8068 - Animals & Pet Supplies > Pet Supplies > Pet First Aid & Emergency Kits
78
+ 6248 - Animals & Pet Supplies > Pet Supplies > Pet Flea & Tick Control
79
+ 5162 - Animals & Pet Supplies > Pet Supplies > Pet Food Containers
80
+ 5163 - Animals & Pet Supplies > Pet Supplies > Pet Food Scoops
81
+ 6383 - Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies
82
+ 6385 - Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Combs & Brushes
83
+ 503733 - Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Fragrances & Deodorizing Sprays
84
+ 6384 - Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Hair Clippers & Trimmers
85
+ 8167 - Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Hair Dryers
86
+ 7318 - Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Nail Polish
87
+ 7319 - Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Nail Tools
88
+ 6406 - Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Shampoo & Conditioner
89
+ 499917 - Animals & Pet Supplies > Pet Supplies > Pet Grooming Supplies > Pet Wipes
90
+ 500110 - Animals & Pet Supplies > Pet Supplies > Pet Heating Pad Accessories
91
+ 499743 - Animals & Pet Supplies > Pet Supplies > Pet Heating Pads
92
+ 5093 - Animals & Pet Supplies > Pet Supplies > Pet ID Tags
93
+ 6253 - Animals & Pet Supplies > Pet Supplies > Pet Leash Extensions
94
+ 6249 - Animals & Pet Supplies > Pet Supplies > Pet Leashes
95
+ 5145 - Animals & Pet Supplies > Pet Supplies > Pet Medical Collars
96
+ 6861 - Animals & Pet Supplies > Pet Supplies > Pet Medical Tape & Bandages
97
+ 5086 - Animals & Pet Supplies > Pet Supplies > Pet Medicine
98
+ 5144 - Animals & Pet Supplies > Pet Supplies > Pet Muzzles
99
+ 7144 - Animals & Pet Supplies > Pet Supplies > Pet Oral Care Supplies
100
+ 5087 - Animals & Pet Supplies > Pet Supplies > Pet Playpens
101
+ 6973 - Animals & Pet Supplies > Pet Supplies > Pet Steps & Ramps
102
+ 6276 - Animals & Pet Supplies > Pet Supplies > Pet Strollers
103
+ 7396 - Animals & Pet Supplies > Pet Supplies > Pet Sunscreen
104
+ 505314 - Animals & Pet Supplies > Pet Supplies > Pet Training Aids
105
+ 505313 - Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Clickers & Treat Dispensers
106
+ 505304 - Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Pad Holders
107
+ 6846 - Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Pads
108
+ 505311 - Animals & Pet Supplies > Pet Supplies > Pet Training Aids > Pet Training Sprays & Solutions
109
+ 5081 - Animals & Pet Supplies > Pet Supplies > Pet Vitamins & Supplements
110
+ 502982 - Animals & Pet Supplies > Pet Supplies > Pet Waste Bag Dispensers & Holders
111
+ 8070 - Animals & Pet Supplies > Pet Supplies > Pet Waste Bags
112
+ 505297 - Animals & Pet Supplies > Pet Supplies > Pet Waste Disposal Systems & Tools
113
+ 7 - Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies
114
+ 5026 - Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Food
115
+ 5027 - Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitat Accessories
116
+ 5028 - Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitat Heating & Lighting
117
+ 5029 - Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Habitats
118
+ 5030 - Animals & Pet Supplies > Pet Supplies > Reptile & Amphibian Supplies > Reptile & Amphibian Substrates
119
+ 5013 - Animals & Pet Supplies > Pet Supplies > Small Animal Supplies
120
+ 5014 - Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Bedding
121
+ 5015 - Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Food
122
+ 5016 - Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Habitat Accessories
123
+ 5017 - Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Habitats & Cages
124
+ 7517 - Animals & Pet Supplies > Pet Supplies > Small Animal Supplies > Small Animal Treats
125
+ 8474 - Animals & Pet Supplies > Pet Supplies > Vehicle Pet Barriers
126
+ 166 - Apparel & Accessories
127
+ 1604 - Apparel & Accessories > Clothing
128
+ 5322 - Apparel & Accessories > Clothing > Activewear
129
+ 5697 - Apparel & Accessories > Clothing > Activewear > Bicycle Activewear
130
+ 3128 - Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Bibs
131
+ 3455 - Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Jerseys
132
+ 3188 - Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Shorts & Briefs
133
+ 6087 - Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Skinsuits
134
+ 3729 - Apparel & Accessories > Clothing > Activewear > Bicycle Activewear > Bicycle Tights
135
+ 5378 - Apparel & Accessories > Clothing > Activewear > Boxing Shorts
136
+ 499979 - Apparel & Accessories > Clothing > Activewear > Dance Dresses, Skirts & Costumes
137
+ 3951 - Apparel & Accessories > Clothing > Activewear > Football Pants
138
+ 5460 - Apparel & Accessories > Clothing > Activewear > Hunting Clothing
139
+ 5462 - Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Ghillie Suits
140
+ 5461 - Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Hunting & Fishing Vests
141
+ 5552 - Apparel & Accessories > Clothing > Activewear > Hunting Clothing > Hunting & Tactical Pants
142
+ 5379 - Apparel & Accessories > Clothing > Activewear > Martial Arts Shorts
143
+ 5517 - Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing
144
+ 6006 - Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Jackets
145
+ 7003 - Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Pants
146
+ 5463 - Apparel & Accessories > Clothing > Activewear > Motorcycle Protective Clothing > Motorcycle Suits
147
+ 5555 - Apparel & Accessories > Clothing > Activewear > Paintball Clothing
148
+ 182 - Apparel & Accessories > Clothing > Baby & Toddler Clothing
149
+ 5408 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Bottoms
150
+ 5549 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Diaper Covers
151
+ 5424 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Dresses
152
+ 5425 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Outerwear
153
+ 5622 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Outfits
154
+ 5412 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Sleepwear
155
+ 5423 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Socks & Tights
156
+ 5409 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Swimwear
157
+ 5410 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby & Toddler Tops
158
+ 5411 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Baby One-Pieces
159
+ 5621 - Apparel & Accessories > Clothing > Baby & Toddler Clothing > Toddler Underwear
160
+ 2271 - Apparel & Accessories > Clothing > Dresses
161
+ 5182 - Apparel & Accessories > Clothing > One-Pieces
162
+ 5250 - Apparel & Accessories > Clothing > One-Pieces > Jumpsuits & Rompers
163
+ 5490 - Apparel & Accessories > Clothing > One-Pieces > Leotards & Unitards
164
+ 7132 - Apparel & Accessories > Clothing > One-Pieces > Overalls
165
+ 203 - Apparel & Accessories > Clothing > Outerwear
166
+ 5506 - Apparel & Accessories > Clothing > Outerwear > Chaps
167
+ 5598 - Apparel & Accessories > Clothing > Outerwear > Coats & Jackets
168
+ 5514 - Apparel & Accessories > Clothing > Outerwear > Rain Pants
169
+ 3066 - Apparel & Accessories > Clothing > Outerwear > Rain Suits
170
+ 5909 - Apparel & Accessories > Clothing > Outerwear > Snow Pants & Suits
171
+ 1831 - Apparel & Accessories > Clothing > Outerwear > Vests
172
+ 7313 - Apparel & Accessories > Clothing > Outfit Sets
173
+ 204 - Apparel & Accessories > Clothing > Pants
174
+ 212 - Apparel & Accessories > Clothing > Shirts & Tops
175
+ 207 - Apparel & Accessories > Clothing > Shorts
176
+ 1581 - Apparel & Accessories > Clothing > Skirts
177
+ 5344 - Apparel & Accessories > Clothing > Skorts
178
+ 208 - Apparel & Accessories > Clothing > Sleepwear & Loungewear
179
+ 5713 - Apparel & Accessories > Clothing > Sleepwear & Loungewear > Loungewear
180
+ 5513 - Apparel & Accessories > Clothing > Sleepwear & Loungewear > Nightgowns
181
+ 2580 - Apparel & Accessories > Clothing > Sleepwear & Loungewear > Pajamas
182
+ 2302 - Apparel & Accessories > Clothing > Sleepwear & Loungewear > Robes
183
+ 1594 - Apparel & Accessories > Clothing > Suits
184
+ 5183 - Apparel & Accessories > Clothing > Suits > Pant Suits
185
+ 1516 - Apparel & Accessories > Clothing > Suits > Skirt Suits
186
+ 1580 - Apparel & Accessories > Clothing > Suits > Tuxedos
187
+ 211 - Apparel & Accessories > Clothing > Swimwear
188
+ 5388 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing
189
+ 6031 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Dirndls
190
+ 5674 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Hakama Trousers
191
+ 6227 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Japanese Black Formal Wear
192
+ 5673 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimono Outerwear
193
+ 5343 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Kimonos
194
+ 5483 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Religious Ceremonial Clothing
195
+ 8149 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Religious Ceremonial Clothing > Baptism & Communion Dresses
196
+ 8248 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Saris & Lehengas
197
+ 7281 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Traditional Leather Pants
198
+ 5676 - Apparel & Accessories > Clothing > Traditional & Ceremonial Clothing > Yukata
199
+ 213 - Apparel & Accessories > Clothing > Underwear & Socks
200
+ 7207 - Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories
201
+ 7208 - Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Bra Strap Pads
202
+ 7211 - Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Bra Straps & Extenders
203
+ 7210 - Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Breast Enhancing Inserts
204
+ 7209 - Apparel & Accessories > Clothing > Underwear & Socks > Bra Accessories > Breast Petals & Concealers
205
+ 214 - Apparel & Accessories > Clothing > Underwear & Socks > Bras
206
+ 215 - Apparel & Accessories > Clothing > Underwear & Socks > Hosiery
207
+ 5327 - Apparel & Accessories > Clothing > Underwear & Socks > Jock Straps
208
+ 1772 - Apparel & Accessories > Clothing > Underwear & Socks > Lingerie
209
+ 2563 - Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories
210
+ 2160 - Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories > Garter Belts
211
+ 1675 - Apparel & Accessories > Clothing > Underwear & Socks > Lingerie Accessories > Garters
212
+ 1807 - Apparel & Accessories > Clothing > Underwear & Socks > Long Johns
213
+ 2963 - Apparel & Accessories > Clothing > Underwear & Socks > Petticoats & Pettipants
214
+ 1578 - Apparel & Accessories > Clothing > Underwear & Socks > Shapewear
215
+ 209 - Apparel & Accessories > Clothing > Underwear & Socks > Socks
216
+ 2745 - Apparel & Accessories > Clothing > Underwear & Socks > Undershirts
217
+ 2562 - Apparel & Accessories > Clothing > Underwear & Socks > Underwear
218
+ 5834 - Apparel & Accessories > Clothing > Underwear & Socks > Underwear Slips
219
+ 2306 - Apparel & Accessories > Clothing > Uniforms
220
+ 5484 - Apparel & Accessories > Clothing > Uniforms > Contractor Pants & Coveralls
221
+ 5878 - Apparel & Accessories > Clothing > Uniforms > Flight Suits
222
+ 7235 - Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms
223
+ 7237 - Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Hats
224
+ 2396 - Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Jackets
225
+ 7236 - Apparel & Accessories > Clothing > Uniforms > Food Service Uniforms > Chef's Pants
226
+ 5949 - Apparel & Accessories > Clothing > Uniforms > Military Uniforms
227
+ 206 - Apparel & Accessories > Clothing > Uniforms > School Uniforms
228
+ 3414 - Apparel & Accessories > Clothing > Uniforms > Security Uniforms
229
+ 3598 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms
230
+ 3191 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Baseball Uniforms
231
+ 3439 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Basketball Uniforms
232
+ 3683 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Cheerleading Uniforms
233
+ 3724 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Cricket Uniforms
234
+ 3888 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Football Uniforms
235
+ 3958 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Hockey Uniforms
236
+ 4003 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Martial Arts Uniforms
237
+ 3253 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Officiating Uniforms
238
+ 5564 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Soccer Uniforms
239
+ 3379 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Softball Uniforms
240
+ 3852 - Apparel & Accessories > Clothing > Uniforms > Sports Uniforms > Wrestling Uniforms
241
+ 2292 - Apparel & Accessories > Clothing > Uniforms > White Coats
242
+ 5441 - Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses
243
+ 5330 - Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses > Bridal Party Dresses
244
+ 5329 - Apparel & Accessories > Clothing > Wedding & Bridal Party Dresses > Wedding Dresses
245
+ 167 - Apparel & Accessories > Clothing Accessories
246
+ 5942 - Apparel & Accessories > Clothing Accessories > Arm Warmers & Sleeves
247
+ 5422 - Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories
248
+ 5623 - Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Belts
249
+ 5624 - Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Gloves & Mittens
250
+ 5625 - Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby & Toddler Hats
251
+ 5626 - Apparel & Accessories > Clothing Accessories > Baby & Toddler Clothing Accessories > Baby Protective Wear
252
+ 1786 - Apparel & Accessories > Clothing Accessories > Balaclavas
253
+ 168 - Apparel & Accessories > Clothing Accessories > Bandanas & Headties
254
+ 543586 - Apparel & Accessories > Clothing Accessories > Bandanas & Headties > Bandanas
255
+ 543587 - Apparel & Accessories > Clothing Accessories > Bandanas & Headties > Hair Care Wraps
256
+ 3913 - Apparel & Accessories > Clothing Accessories > Belt Buckles
257
+ 169 - Apparel & Accessories > Clothing Accessories > Belts
258
+ 5443 - Apparel & Accessories > Clothing Accessories > Bridal Accessories
259
+ 5446 - Apparel & Accessories > Clothing Accessories > Bridal Accessories > Bridal Veils
260
+ 6985 - Apparel & Accessories > Clothing Accessories > Button Studs
261
+ 6984 - Apparel & Accessories > Clothing Accessories > Collar Stays
262
+ 193 - Apparel & Accessories > Clothing Accessories > Cufflinks
263
+ 5114 - Apparel & Accessories > Clothing Accessories > Decorative Fans
264
+ 6238 - Apparel & Accessories > Clothing Accessories > Earmuffs
265
+ 170 - Apparel & Accessories > Clothing Accessories > Gloves & Mittens
266
+ 171 - Apparel & Accessories > Clothing Accessories > Hair Accessories
267
+ 8451 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Bun & Volume Shapers
268
+ 2477 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Combs
269
+ 4057 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Extensions
270
+ 1948 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Forks & Sticks
271
+ 6183 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Nets
272
+ 502988 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins, Claws & Clips
273
+ 543646 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins, Claws & Clips > Barrettes
274
+ 543645 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins, Claws & Clips > Hair Claws & Clips
275
+ 543644 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Pins, Claws & Clips > Hair Pins
276
+ 5915 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Hair Wreaths
277
+ 1662 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Headbands
278
+ 1483 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Ponytail Holders
279
+ 5914 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Tiaras
280
+ 7305 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Wig Accessories
281
+ 7307 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Wig Accessories > Wig Caps
282
+ 7306 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Wig Accessories > Wig Glue & Tape
283
+ 181 - Apparel & Accessories > Clothing Accessories > Hair Accessories > Wigs
284
+ 7133 - Apparel & Accessories > Clothing Accessories > Hand Muffs
285
+ 5207 - Apparel & Accessories > Clothing Accessories > Handkerchiefs
286
+ 173 - Apparel & Accessories > Clothing Accessories > Hats
287
+ 2020 - Apparel & Accessories > Clothing Accessories > Headwear
288
+ 7054 - Apparel & Accessories > Clothing Accessories > Headwear > Fascinators
289
+ 1922 - Apparel & Accessories > Clothing Accessories > Headwear > Headdresses
290
+ 5939 - Apparel & Accessories > Clothing Accessories > Headwear > Turbans
291
+ 5941 - Apparel & Accessories > Clothing Accessories > Leg Warmers
292
+ 6268 - Apparel & Accessories > Clothing Accessories > Leis
293
+ 502987 - Apparel & Accessories > Clothing Accessories > Maternity Belts & Support Bands
294
+ 7230 - Apparel & Accessories > Clothing Accessories > Neck Gaiters
295
+ 176 - Apparel & Accessories > Clothing Accessories > Neckties
296
+ 4179 - Apparel & Accessories > Clothing Accessories > Pinback Buttons
297
+ 499972 - Apparel & Accessories > Clothing Accessories > Sashes
298
+ 177 - Apparel & Accessories > Clothing Accessories > Scarves & Shawls
299
+ 543673 - Apparel & Accessories > Clothing Accessories > Scarves & Shawls > Scarves
300
+ 543674 - Apparel & Accessories > Clothing Accessories > Scarves & Shawls > Shawls
301
+ 178 - Apparel & Accessories > Clothing Accessories > Sunglasses
302
+ 179 - Apparel & Accessories > Clothing Accessories > Suspenders
303
+ 180 - Apparel & Accessories > Clothing Accessories > Tie Clips
304
+ 5390 - Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories
305
+ 5687 - Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Obis
306
+ 5685 - Apparel & Accessories > Clothing Accessories > Traditional Clothing Accessories > Tabi Socks
307
+ 1893 - Apparel & Accessories > Clothing Accessories > Wristbands
308
+ 184 - Apparel & Accessories > Costumes & Accessories
309
+ 5192 - Apparel & Accessories > Costumes & Accessories > Costume Accessories
310
+ 7304 - Apparel & Accessories > Costumes & Accessories > Costume Accessories > Bald Caps
311
+ 8017 - Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Accessory Sets
312
+ 5907 - Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Capes
313
+ 8200 - Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Gloves
314
+ 5426 - Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Hats
315
+ 500118 - Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Special Effects
316
+ 500008 - Apparel & Accessories > Costumes & Accessories > Costume Accessories > Costume Tobacco Products
317
+ 8018 - Apparel & Accessories > Costumes & Accessories > Costume Accessories > Pretend Jewelry
318
+ 5387 - Apparel & Accessories > Costumes & Accessories > Costume Shoes
319
+ 5193 - Apparel & Accessories > Costumes & Accessories > Costumes
320
+ 5194 - Apparel & Accessories > Costumes & Accessories > Masks
321
+ 6552 - Apparel & Accessories > Handbag & Wallet Accessories
322
+ 6460 - Apparel & Accessories > Handbag & Wallet Accessories > Checkbook Covers
323
+ 175 - Apparel & Accessories > Handbag & Wallet Accessories > Keychains
324
+ 6277 - Apparel & Accessories > Handbag & Wallet Accessories > Lanyards
325
+ 5841 - Apparel & Accessories > Handbag & Wallet Accessories > Wallet Chains
326
+ 6551 - Apparel & Accessories > Handbags, Wallets & Cases
327
+ 6170 - Apparel & Accessories > Handbags, Wallets & Cases > Badge & Pass Holders
328
+ 6169 - Apparel & Accessories > Handbags, Wallets & Cases > Business Card Cases
329
+ 3032 - Apparel & Accessories > Handbags, Wallets & Cases > Handbags
330
+ 2668 - Apparel & Accessories > Handbags, Wallets & Cases > Wallets & Money Clips
331
+ 188 - Apparel & Accessories > Jewelry
332
+ 189 - Apparel & Accessories > Jewelry > Anklets
333
+ 190 - Apparel & Accessories > Jewelry > Body Jewelry
334
+ 191 - Apparel & Accessories > Jewelry > Bracelets
335
+ 197 - Apparel & Accessories > Jewelry > Brooches & Lapel Pins
336
+ 192 - Apparel & Accessories > Jewelry > Charms & Pendants
337
+ 194 - Apparel & Accessories > Jewelry > Earrings
338
+ 6463 - Apparel & Accessories > Jewelry > Jewelry Sets
339
+ 196 - Apparel & Accessories > Jewelry > Necklaces
340
+ 200 - Apparel & Accessories > Jewelry > Rings
341
+ 5122 - Apparel & Accessories > Jewelry > Watch Accessories
342
+ 5123 - Apparel & Accessories > Jewelry > Watch Accessories > Watch Bands
343
+ 7471 - Apparel & Accessories > Jewelry > Watch Accessories > Watch Stickers & Decals
344
+ 6870 - Apparel & Accessories > Jewelry > Watch Accessories > Watch Winders
345
+ 201 - Apparel & Accessories > Jewelry > Watches
346
+ 1933 - Apparel & Accessories > Shoe Accessories
347
+ 5567 - Apparel & Accessories > Shoe Accessories > Boot Liners
348
+ 7078 - Apparel & Accessories > Shoe Accessories > Gaiters
349
+ 5385 - Apparel & Accessories > Shoe Accessories > Shoe Covers
350
+ 1856 - Apparel & Accessories > Shoe Accessories > Shoelaces
351
+ 2427 - Apparel & Accessories > Shoe Accessories > Spurs
352
+ 187 - Apparel & Accessories > Shoes
353
+ 8 - Arts & Entertainment
354
+ 499969 - Arts & Entertainment > Event Tickets
355
+ 5710 - Arts & Entertainment > Hobbies & Creative Arts
356
+ 16 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts
357
+ 505370 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits
358
+ 505374 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Candle Making Kits
359
+ 4778 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Drawing & Painting Kits
360
+ 6382 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Fabric Repair Kits
361
+ 6989 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Incense Making Kits
362
+ 502979 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Jewelry Making Kits
363
+ 6829 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Mosaic Kits
364
+ 7096 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Needlecraft Kits
365
+ 503758 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Scrapbooking & Stamping Kits
366
+ 4986 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Craft Kits > Toy Craft Kits
367
+ 505372 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials
368
+ 24 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper
369
+ 505399 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Cardstock & Scrapbooking Paper
370
+ 543510 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Cardstock & Scrapbooking Paper > Cardstock
371
+ 543511 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Cardstock & Scrapbooking Paper > Scrapbooking Paper
372
+ 2532 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Construction Paper
373
+ 8168 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Craft Foil
374
+ 505400 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Drawing & Painting Paper
375
+ 2967 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Origami Paper
376
+ 6110 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Transfer Paper
377
+ 2741 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Art & Craft Paper > Vellum Paper
378
+ 505380 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures
379
+ 4226 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Buttons & Snaps
380
+ 505408 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Clasps & Hooks
381
+ 505409 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Eyelets & Grommets
382
+ 6145 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Hook and Loop Fasteners
383
+ 500056 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Zipper Pulls
384
+ 4174 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Fasteners & Closures > Zippers
385
+ 505378 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze
386
+ 505417 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Art & Craft Paint
387
+ 500094 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Art Fixatives
388
+ 505416 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Art Ink
389
+ 499879 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Ceramic & Pottery Glazes
390
+ 505415 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Craft Dyes
391
+ 505414 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Ink Pads
392
+ 6558 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Paint, Ink & Glaze > Paint Mediums
393
+ 505381 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases
394
+ 6117 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Craft Foam & Styrofoam
395
+ 505404 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Craft Wood & Shapes
396
+ 505403 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Papier Mache Shapes
397
+ 504419 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Craft Shapes & Bases > Wreath & Floral Frames
398
+ 505376 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets
399
+ 503745 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Craft & Office Glue
400
+ 36 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Craft Magnets
401
+ 505419 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Decorative Tape
402
+ 7192 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Floral Tape
403
+ 6418 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Adhesives & Magnets > Fusible Tape
404
+ 505382 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers
405
+ 6540 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Jewelry & Beading Cord
406
+ 49 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Thread & Floss
407
+ 6140 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Unspun Fiber
408
+ 2669 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Fibers > Yarn
409
+ 505377 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire
410
+ 5062 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire > Craft Pipe Cleaners
411
+ 505418 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire > Floral Wire
412
+ 6102 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Crafting Wire > Jewelry & Beading Wire
413
+ 505379 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims
414
+ 6955 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Appliques & Patches
415
+ 32 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Beads
416
+ 505413 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Bows & Yo-Yos
417
+ 4054 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Decorative Stickers
418
+ 6146 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Elastic
419
+ 505411 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Feathers
420
+ 5996 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Jewelry Findings
421
+ 198 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Loose Stones
422
+ 5982 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Rhinestones & Flatbacks
423
+ 505412 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Ribbons & Trim
424
+ 505410 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Sequins & Glitter
425
+ 1927 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embellishments & Trims > Sew-in Labels
426
+ 6121 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Embossing Powder
427
+ 6142 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material
428
+ 505407 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material > Batting & Stuffing
429
+ 505406 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material > Filling Pellets
430
+ 505405 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Filling & Padding Material > Pillow Forms
431
+ 505383 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Leather & Vinyl
432
+ 44 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials
433
+ 3692 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Clay & Modeling Dough
434
+ 543628 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Clay & Modeling Dough > Clay
435
+ 543629 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Clay & Modeling Dough > Modeling Dough
436
+ 505401 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Papier Mache Mixes
437
+ 505804 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Plaster Gauze
438
+ 505402 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Pottery & Sculpting Materials > Pottery Slips
439
+ 505375 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Raw Candle Wax
440
+ 505384 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles
441
+ 505397 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas
442
+ 505398 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas > Needlecraft Canvas
443
+ 19 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas > Painting Canvas
444
+ 6144 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Crafting Canvas > Plastic Canvas
445
+ 47 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Fabric
446
+ 7076 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Interfacing
447
+ 505396 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Textiles > Printable Fabric
448
+ 7403 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Wick Tabs
449
+ 7402 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Materials > Wicks
450
+ 504643 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories
451
+ 232168 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Craft Knife Blades
452
+ 4580 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Craft Machine Cases & Covers
453
+ 505286 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Sewing Machine Extension Tables
454
+ 5120 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Sewing Machine Feet
455
+ 503348 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Sewing Machine Replacement Parts
456
+ 6136 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Spinning Wheel Accessories
457
+ 499918 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tool Accessories > Stamp Blocks
458
+ 504639 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools
459
+ 6152 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Blocking Mats
460
+ 6151 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Blocking Wires
461
+ 505391 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Color Mixing Tools
462
+ 1653 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Color Mixing Tools > Palette Knives
463
+ 1719 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Color Mixing Tools > Palettes
464
+ 504640 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools
465
+ 504641 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft & Office Scissors
466
+ 504642 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft Cutters & Embossers
467
+ 5136 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft Knives
468
+ 6119 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Craft Scoring Tools
469
+ 7340 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Embossing Heat Tools
470
+ 6122 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Embossing Pens & Styluses
471
+ 6161 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Seam Rippers
472
+ 6447 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Cutting & Embossing Tools > Thread & Yarn Cutters
473
+ 505386 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Decoration Makers
474
+ 505392 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools
475
+ 18 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Art Brushes
476
+ 6126 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Brayer Rollers
477
+ 4032 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Decorative Stamps
478
+ 3083 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Drafting Compasses
479
+ 6125 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Screen Printing Squeegees
480
+ 5883 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Stencil Machines
481
+ 2671 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Stencils & Die Cuts
482
+ 6160 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Stitch Markers & Counters
483
+ 6157 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Textile Art Gauges & Rulers
484
+ 505420 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Craft Measuring & Marking Tools > Wood Burning Tools
485
+ 5137 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Cutting Mats
486
+ 6150 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Dress Forms
487
+ 6133 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Felting Pads & Mats
488
+ 6158 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Frames, Hoops & Stretchers
489
+ 4073 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Glue Guns
490
+ 5921 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Light Boxes
491
+ 505393 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks
492
+ 6127 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Crochet Hooks
493
+ 5992 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Hand-Sewing Needles
494
+ 6139 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Knitting Needles
495
+ 6168 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Latch & Locker Hooks
496
+ 4579 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Needles & Hooks > Sewing Machine Needles
497
+ 6101 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Safety Pins
498
+ 6159 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Straight Pins
499
+ 505388 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines
500
+ 6134 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Felting Needles & Machines
501
+ 505422 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Hand Looms
502
+ 505421 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Mechanical Looms
503
+ 615 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Sewing Machines
504
+ 6137 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Textile Craft Machines > Spinning Wheels
505
+ 6156 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thimbles & Sewing Palms
506
+ 543639 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thimbles & Sewing Palms > Sewing Palms
507
+ 543638 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thimbles & Sewing Palms > Thimbles
508
+ 505387 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools
509
+ 6164 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Fiber Cards & Brushes
510
+ 6138 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Hand Spindles
511
+ 6163 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Needle Threaders
512
+ 6155 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Thread & Yarn Guides
513
+ 6154 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Thread & Yarn Spools
514
+ 6153 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Thread, Yarn & Bobbin Winders
515
+ 6167 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Weaving Beaters
516
+ 6166 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Art & Crafting Tools > Thread & Yarn Tools > Weaving Shuttles
517
+ 505369 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization
518
+ 505394 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization > Needle, Pin & Hook Organizers
519
+ 499971 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization > Sewing Baskets & Kits
520
+ 505395 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Craft Organization > Thread & Yarn Organizers
521
+ 505371 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds
522
+ 6999 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Beading Patterns
523
+ 8007 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Craft Molds
524
+ 6135 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Felting Molds
525
+ 505373 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Needlecraft Patterns
526
+ 3697 - Arts & Entertainment > Hobbies & Creative Arts > Arts & Crafts > Crafting Patterns & Molds > Sewing Patterns
527
+ 216 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles
528
+ 3599 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Autographs
529
+ 217 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Coins & Currency
530
+ 543607 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Coins & Currency > Collectible Banknotes
531
+ 543606 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Coins & Currency > Collectible Coins
532
+ 6997 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Trading Cards
533
+ 220 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons
534
+ 499953 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Guns
535
+ 5311 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Knives
536
+ 221 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Collectible Swords
537
+ 1340 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Collectible Weapons > Sword Stands & Displays
538
+ 219 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Postage Stamps
539
+ 218 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Rocks & Fossils
540
+ 6000 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Scale Model Accessories
541
+ 37 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Scale Models
542
+ 1312 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Seal Stamps
543
+ 3865 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles
544
+ 4333 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia
545
+ 4180 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Auto Racing Autographed Paraphernalia
546
+ 4149 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Baseball & Softball Autographed Paraphernalia
547
+ 4279 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Basketball Autographed Paraphernalia
548
+ 8210 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Boxing Autographed Paraphernalia
549
+ 4124 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Football Autographed Paraphernalia
550
+ 4144 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Hockey Autographed Paraphernalia
551
+ 4093 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Soccer Autographed Paraphernalia
552
+ 6186 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Autographed Sports Paraphernalia > Tennis Autographed Sports Paraphernalia
553
+ 3515 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories
554
+ 1051 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Auto Racing Fan Accessories
555
+ 1074 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Baseball & Softball Fan Accessories
556
+ 1084 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Basketball Fan Accessories
557
+ 1095 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Football Fan Accessories
558
+ 4006 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Hockey Fan Accessories
559
+ 3576 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Soccer Fan Accessories
560
+ 6187 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Sports Collectibles > Sports Fan Accessories > Tennis Fan Accessories
561
+ 3893 - Arts & Entertainment > Hobbies & Creative Arts > Collectibles > Vintage Advertisements
562
+ 3577 - Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies
563
+ 3014 - Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Beer Brewing Grains & Malts
564
+ 502980 - Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Bottling Bottles
565
+ 499891 - Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Homebrewing & Winemaking Kits
566
+ 2579 - Arts & Entertainment > Hobbies & Creative Arts > Homebrewing & Winemaking Supplies > Wine Making
567
+ 33 - Arts & Entertainment > Hobbies & Creative Arts > Juggling
568
+ 35 - Arts & Entertainment > Hobbies & Creative Arts > Magic & Novelties
569
+ 5999 - Arts & Entertainment > Hobbies & Creative Arts > Model Making
570
+ 3885 - Arts & Entertainment > Hobbies & Creative Arts > Model Making > Model Rocketry
571
+ 5151 - Arts & Entertainment > Hobbies & Creative Arts > Model Making > Model Train Accessories
572
+ 5150 - Arts & Entertainment > Hobbies & Creative Arts > Model Making > Model Trains & Train Sets
573
+ 4175 - Arts & Entertainment > Hobbies & Creative Arts > Model Making > Scale Model Kits
574
+ 55 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories
575
+ 57 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories
576
+ 4797 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning
577
+ 4891 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Care Kits
578
+ 4892 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Cleaners & Sanitizers
579
+ 4890 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Cleaning Tools
580
+ 4893 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Guards
581
+ 4894 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Lubricants
582
+ 4895 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Care & Cleaning > Brass Instrument Polishing Cloths
583
+ 505310 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Cases & Gigbags
584
+ 505308 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Mouthpieces
585
+ 505768 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Mutes
586
+ 4798 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Replacement Parts
587
+ 505309 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Brass Instrument Accessories > Brass Instrument Straps & Stands
588
+ 505288 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Conductor Batons
589
+ 3270 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Electronic Tuners
590
+ 505365 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Metronomes
591
+ 505328 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Benches & Stools
592
+ 500001 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Lyres & Flip Folders
593
+ 7277 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories
594
+ 7279 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories > Music Stand Bags
595
+ 7280 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories > Music Stand Lights
596
+ 7278 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stand Accessories > Sheet Music Clips
597
+ 4142 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Music Stands
598
+ 8072 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories
599
+ 6970 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Cabinets
600
+ 8461 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Covers & Cases
601
+ 8073 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Footswitches
602
+ 8462 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Knobs
603
+ 7364 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Stands
604
+ 8480 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifier Accessories > Musical Instrument Amplifier Tubes
605
+ 56 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Instrument Amplifiers
606
+ 60 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories
607
+ 7357 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories > Musical Keyboard Bags & Cases
608
+ 3588 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories > Musical Keyboard Stands
609
+ 3324 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Musical Keyboard Accessories > Sustain Pedals
610
+ 3465 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories
611
+ 7100 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Cymbal & Drum Cases
612
+ 7231 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Cymbal & Drum Mutes
613
+ 7153 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Heads
614
+ 7152 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Keys
615
+ 7099 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware
616
+ 7103 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware > Bass Drum Beaters
617
+ 7102 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware > Drum Kit Mounting Hardware
618
+ 7101 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Kit Hardware > Drum Pedals
619
+ 7150 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Stick & Brush Accessories
620
+ 7151 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Stick & Brush Accessories > Drum Stick & Brush Bags & Holders
621
+ 59 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Drum Sticks & Brushes
622
+ 7455 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Electronic Drum Modules
623
+ 7282 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Hand Percussion Accessories
624
+ 7283 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Hand Percussion Accessories > Hand Percussion Bags & Cases
625
+ 7284 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Hand Percussion Accessories > Hand Percussion Stands & Mounts
626
+ 4631 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Percussion Mallets
627
+ 7308 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Percussion Accessories > Percussion Stands
628
+ 61 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories
629
+ 3502 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories
630
+ 3775 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Acoustic Guitar Pickups
631
+ 5367 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Capos
632
+ 3412 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Electric Guitar Pickups
633
+ 3882 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Cases & Gig Bags
634
+ 503032 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Fittings & Parts
635
+ 3392 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Humidifiers
636
+ 4111 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Picks
637
+ 5368 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Slides
638
+ 3646 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Stands
639
+ 499688 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Straps
640
+ 503721 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar String Winders
641
+ 3178 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Strings
642
+ 3176 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Guitar Accessories > Guitar Tuning Pegs
643
+ 503033 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories
644
+ 8209 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Bow Cases
645
+ 503040 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Bows
646
+ 503039 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Cases
647
+ 503038 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Fittings & Parts
648
+ 503037 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Mutes
649
+ 503036 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Pickups
650
+ 503035 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Stands
651
+ 503034 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > Orchestral String Instrument Accessories > Orchestral String Instrument Strings
652
+ 4806 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning
653
+ 3374 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning > Bow Rosin
654
+ 4911 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning > String Instrument Cleaning Cloths
655
+ 4912 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > String Instrument Accessories > String Instrument Care & Cleaning > String Instrument Polish
656
+ 62 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories
657
+ 4790 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories
658
+ 4809 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Care & Cleaning
659
+ 4815 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Care & Cleaning > Bassoon Swabs
660
+ 4810 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Cases & Gigbags
661
+ 4811 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts
662
+ 4816 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts > Bassoon Bocals
663
+ 4817 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Parts > Bassoon Small Parts
664
+ 4812 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Reeds
665
+ 4813 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Stands
666
+ 4814 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Bassoon Accessories > Bassoon Straps & Supports
667
+ 4791 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories
668
+ 4818 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning
669
+ 4826 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Care Kits
670
+ 4827 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Pad Savers
671
+ 4828 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Care & Cleaning > Clarinet Swabs
672
+ 4819 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Cases & Gigbags
673
+ 4820 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Ligatures & Caps
674
+ 4822 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts
675
+ 4829 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Barrels
676
+ 4830 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Bells
677
+ 4831 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Mouthpieces
678
+ 4832 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Parts > Clarinet Small Parts
679
+ 4823 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Pegs & Stands
680
+ 4824 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Reeds
681
+ 4825 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Clarinet Accessories > Clarinet Straps & Supports
682
+ 4792 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories
683
+ 4833 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning
684
+ 4838 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Care Kits
685
+ 4839 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Cleaning Rods
686
+ 4840 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Care & Cleaning > Flute Swabs
687
+ 4834 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Cases & Gigbags
688
+ 4836 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts
689
+ 4841 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts > Flute Headjoints
690
+ 4842 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Parts > Flute Small Parts
691
+ 4837 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Flute Accessories > Flute Pegs & Stands
692
+ 4955 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Harmonica Accessories
693
+ 4956 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Harmonica Accessories > Harmonica Cases
694
+ 5046 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Harmonica Accessories > Harmonica Holders
695
+ 4793 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories
696
+ 4843 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning
697
+ 4849 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning > Oboe Care Kits
698
+ 4850 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Care & Cleaning > Oboe Swabs
699
+ 4844 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Cases & Gigbags
700
+ 4845 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Parts
701
+ 4851 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Parts > Oboe Small Parts
702
+ 4846 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Pegs & Stands
703
+ 4847 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Reeds
704
+ 4848 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Oboe & English Horn Accessories > Oboe Straps & Supports
705
+ 503747 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories
706
+ 503749 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories > Recorder Care & Cleaning
707
+ 503748 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories > Recorder Cases
708
+ 503750 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Recorder Accessories > Recorder Parts
709
+ 4794 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories
710
+ 4852 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning
711
+ 4860 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Care Kits
712
+ 4861 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Pad Savers
713
+ 4862 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Care & Cleaning > Saxophone Swabs
714
+ 4853 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Cases & Gigbags
715
+ 4854 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Ligatures & Caps
716
+ 4856 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts
717
+ 4863 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Mouthpieces
718
+ 4864 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Necks
719
+ 4865 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Parts > Saxophone Small Parts
720
+ 4857 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Pegs & Stands
721
+ 4858 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Reeds
722
+ 4859 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Saxophone Accessories > Saxophone Straps & Supports
723
+ 4866 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Cork Grease
724
+ 4867 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Polishing Cloths
725
+ 4957 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Reed Cases
726
+ 4939 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instrument & Orchestra Accessories > Woodwind Instrument Accessories > Woodwind Reed Knives
727
+ 54 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments
728
+ 4983 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Accordions & Concertinas
729
+ 4984 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Bagpipes
730
+ 63 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments
731
+ 505769 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Alto & Baritone Horns
732
+ 65 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Euphoniums
733
+ 67 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > French Horns
734
+ 70 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Trombones
735
+ 505770 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Trumpets & Cornets
736
+ 72 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Brass Instruments > Tubas
737
+ 6001 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments
738
+ 245 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Audio Samplers
739
+ 6002 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > MIDI Controllers
740
+ 74 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Musical Keyboards
741
+ 6003 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Electronic Musical Instruments > Sound Synthesizers
742
+ 75 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion
743
+ 2917 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Bass Drums
744
+ 3043 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Cymbals
745
+ 2518 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Drum Kits
746
+ 2856 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Electronic Drums
747
+ 7431 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Glockenspiels & Xylophones
748
+ 6098 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Gongs
749
+ 7285 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion
750
+ 7289 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Claves & Castanets
751
+ 7288 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Finger & Hand Cymbals
752
+ 7555 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Bells & Chimes
753
+ 7295 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums
754
+ 7298 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Bongos
755
+ 7297 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Cajons
756
+ 7296 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Congas
757
+ 7300 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Frame Drums
758
+ 7299 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Goblet Drums
759
+ 7302 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Tablas
760
+ 7301 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Hand Drums > Talking Drums
761
+ 7291 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Blocks
762
+ 7293 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Cowbells
763
+ 7286 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Scrapers & Ratchets
764
+ 7287 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Shakers
765
+ 7290 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Musical Triangles
766
+ 2515 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Tambourines
767
+ 7294 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hand Percussion > Vibraslaps
768
+ 3015 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Hi-Hats
769
+ 7232 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Practice Pads
770
+ 2797 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Snare Drums
771
+ 3005 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Percussion > Tom-Toms
772
+ 76 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Pianos
773
+ 77 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments
774
+ 79 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Cellos
775
+ 80 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Guitars
776
+ 84 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Harps
777
+ 78 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Upright Basses
778
+ 85 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Violas
779
+ 86 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > String Instruments > Violins
780
+ 87 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds
781
+ 4540 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Bassoons
782
+ 88 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Clarinets
783
+ 89 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Flutes
784
+ 7188 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Flutophones
785
+ 4743 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Harmonicas
786
+ 4744 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Jew's Harps
787
+ 5481 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Melodicas
788
+ 7250 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Musical Pipes
789
+ 4541 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Oboes & English Horns
790
+ 7249 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Ocarinas
791
+ 90 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Recorders
792
+ 91 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Saxophones
793
+ 6721 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Tin Whistles
794
+ 6728 - Arts & Entertainment > Hobbies & Creative Arts > Musical Instruments > Woodwinds > Train Whistles
795
+ 5709 - Arts & Entertainment > Party & Celebration
796
+ 2559 - Arts & Entertainment > Party & Celebration > Gift Giving
797
+ 6100 - Arts & Entertainment > Party & Celebration > Gift Giving > Corsage & Boutonnière Pins
798
+ 5916 - Arts & Entertainment > Party & Celebration > Gift Giving > Corsages & Boutonnières
799
+ 2899 - Arts & Entertainment > Party & Celebration > Gift Giving > Fresh Cut Flowers
800
+ 53 - Arts & Entertainment > Party & Celebration > Gift Giving > Gift Cards & Certificates
801
+ 94 - Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping
802
+ 5838 - Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Bags
803
+ 5091 - Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Boxes & Tins
804
+ 8213 - Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Gift Tags & Labels
805
+ 6712 - Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Tissue Paper
806
+ 2816 - Arts & Entertainment > Party & Celebration > Gift Giving > Gift Wrapping > Wrapping Paper
807
+ 95 - Arts & Entertainment > Party & Celebration > Gift Giving > Greeting & Note Cards
808
+ 96 - Arts & Entertainment > Party & Celebration > Party Supplies
809
+ 328061 - Arts & Entertainment > Party & Celebration > Party Supplies > Advice Cards
810
+ 6311 - Arts & Entertainment > Party & Celebration > Party Supplies > Balloon Kits
811
+ 2587 - Arts & Entertainment > Party & Celebration > Party Supplies > Balloons
812
+ 2531 - Arts & Entertainment > Party & Celebration > Party Supplies > Banners
813
+ 4730 - Arts & Entertainment > Party & Celebration > Party Supplies > Birthday Candles
814
+ 505763 - Arts & Entertainment > Party & Celebration > Party Supplies > Chair Sashes
815
+ 7007 - Arts & Entertainment > Party & Celebration > Party Supplies > Cocktail Decorations
816
+ 2781 - Arts & Entertainment > Party & Celebration > Party Supplies > Confetti
817
+ 8216 - Arts & Entertainment > Party & Celebration > Party Supplies > Decorative Pom-Poms
818
+ 3735 - Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games
819
+ 3361 - Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games > Beer Pong
820
+ 3440 - Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Games > Beer Pong > Beer Pong Tables
821
+ 5043 - Arts & Entertainment > Party & Celebration > Party Supplies > Drinking Straws & Stirrers
822
+ 1484 - Arts & Entertainment > Party & Celebration > Party Supplies > Envelope Seals
823
+ 8038 - Arts & Entertainment > Party & Celebration > Party Supplies > Event Programs
824
+ 4914 - Arts & Entertainment > Party & Celebration > Party Supplies > Fireworks & Firecrackers
825
+ 8110 - Arts & Entertainment > Party & Celebration > Party Supplies > Inflatable Party Decorations
826
+ 1371 - Arts & Entertainment > Party & Celebration > Party Supplies > Invitations
827
+ 2783 - Arts & Entertainment > Party & Celebration > Party Supplies > Noisemakers & Party Blowers
828
+ 5452 - Arts & Entertainment > Party & Celebration > Party Supplies > Party Favors
829
+ 5453 - Arts & Entertainment > Party & Celebration > Party Supplies > Party Favors > Wedding Favors
830
+ 7160 - Arts & Entertainment > Party & Celebration > Party Supplies > Party Games
831
+ 6906 - Arts & Entertainment > Party & Celebration > Party Supplies > Party Hats
832
+ 502981 - Arts & Entertainment > Party & Celebration > Party Supplies > Party Streamers & Curtains
833
+ 502972 - Arts & Entertainment > Party & Celebration > Party Supplies > Party Supply Kits
834
+ 3994 - Arts & Entertainment > Party & Celebration > Party Supplies > Piñatas
835
+ 5472 - Arts & Entertainment > Party & Celebration > Party Supplies > Place Card Holders
836
+ 2104 - Arts & Entertainment > Party & Celebration > Party Supplies > Place Cards
837
+ 1887 - Arts & Entertainment > Party & Celebration > Party Supplies > Response Cards
838
+ 4915 - Arts & Entertainment > Party & Celebration > Party Supplies > Sparklers
839
+ 7097 - Arts & Entertainment > Party & Celebration > Party Supplies > Special Occasion Card Boxes & Holders
840
+ 4351 - Arts & Entertainment > Party & Celebration > Party Supplies > Spray String
841
+ 408 - Arts & Entertainment > Party & Celebration > Special Effects
842
+ 5711 - Arts & Entertainment > Party & Celebration > Special Effects > Disco Balls
843
+ 409 - Arts & Entertainment > Party & Celebration > Special Effects > Fog Machines
844
+ 5967 - Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Controllers
845
+ 503028 - Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Light Stands
846
+ 410 - Arts & Entertainment > Party & Celebration > Special Effects > Special Effects Lighting
847
+ 5868 - Arts & Entertainment > Party & Celebration > Trophies & Awards
848
+ 543656 - Arts & Entertainment > Party & Celebration > Trophies & Awards > Award Certificates
849
+ 543655 - Arts & Entertainment > Party & Celebration > Trophies & Awards > Award Pins & Medals
850
+ 543657 - Arts & Entertainment > Party & Celebration > Trophies & Awards > Award Plaques
851
+ 543654 - Arts & Entertainment > Party & Celebration > Trophies & Awards > Award Ribbons
852
+ 543653 - Arts & Entertainment > Party & Celebration > Trophies & Awards > Trophies
853
+ 537 - Baby & Toddler
854
+ 4678 - Baby & Toddler > Baby Bathing
855
+ 4679 - Baby & Toddler > Baby Bathing > Baby Bathtubs & Bath Seats
856
+ 7082 - Baby & Toddler > Baby Bathing > Shower Visors
857
+ 5859 - Baby & Toddler > Baby Gift Sets
858
+ 5252 - Baby & Toddler > Baby Health
859
+ 6290 - Baby & Toddler > Baby Health > Baby Health & Grooming Kits
860
+ 5253 - Baby & Toddler > Baby Health > Nasal Aspirators
861
+ 7016 - Baby & Toddler > Baby Health > Pacifier Clips & Holders
862
+ 7309 - Baby & Toddler > Baby Health > Pacifier Wipes
863
+ 566 - Baby & Toddler > Baby Health > Pacifiers & Teethers
864
+ 540 - Baby & Toddler > Baby Safety
865
+ 6869 - Baby & Toddler > Baby Safety > Baby & Pet Gate Accessories
866
+ 542 - Baby & Toddler > Baby Safety > Baby & Pet Gates
867
+ 541 - Baby & Toddler > Baby Safety > Baby Monitors
868
+ 5049 - Baby & Toddler > Baby Safety > Baby Safety Harnesses & Leashes
869
+ 543 - Baby & Toddler > Baby Safety > Baby Safety Locks & Guards
870
+ 544 - Baby & Toddler > Baby Safety > Baby Safety Rails
871
+ 2847 - Baby & Toddler > Baby Toys & Activity Equipment
872
+ 3661 - Baby & Toddler > Baby Toys & Activity Equipment > Alphabet Toys
873
+ 7198 - Baby & Toddler > Baby Toys & Activity Equipment > Baby Activity Toys
874
+ 555 - Baby & Toddler > Baby Toys & Activity Equipment > Baby Bouncers & Rockers
875
+ 560 - Baby & Toddler > Baby Toys & Activity Equipment > Baby Jumpers & Swings
876
+ 7191 - Baby & Toddler > Baby Toys & Activity Equipment > Baby Mobile Accessories
877
+ 1242 - Baby & Toddler > Baby Toys & Activity Equipment > Baby Mobiles
878
+ 7360 - Baby & Toddler > Baby Toys & Activity Equipment > Baby Soothers
879
+ 1241 - Baby & Toddler > Baby Toys & Activity Equipment > Baby Walkers & Entertainers
880
+ 1243 - Baby & Toddler > Baby Toys & Activity Equipment > Play Mats & Gyms
881
+ 543613 - Baby & Toddler > Baby Toys & Activity Equipment > Play Mats & Gyms > Play Gyms
882
+ 543612 - Baby & Toddler > Baby Toys & Activity Equipment > Play Mats & Gyms > Play Mats
883
+ 539 - Baby & Toddler > Baby Toys & Activity Equipment > Play Yards
884
+ 3459 - Baby & Toddler > Baby Toys & Activity Equipment > Push & Pull Toys
885
+ 1244 - Baby & Toddler > Baby Toys & Activity Equipment > Rattles
886
+ 3860 - Baby & Toddler > Baby Toys & Activity Equipment > Sorting & Stacking Toys
887
+ 2764 - Baby & Toddler > Baby Transport
888
+ 547 - Baby & Toddler > Baby Transport > Baby & Toddler Car Seats
889
+ 538 - Baby & Toddler > Baby Transport > Baby Carriers
890
+ 568 - Baby & Toddler > Baby Transport > Baby Strollers
891
+ 4386 - Baby & Toddler > Baby Transport Accessories
892
+ 4486 - Baby & Toddler > Baby Transport Accessories > Baby & Toddler Car Seat Accessories
893
+ 4916 - Baby & Toddler > Baby Transport Accessories > Baby Carrier Accessories
894
+ 4387 - Baby & Toddler > Baby Transport Accessories > Baby Stroller Accessories
895
+ 8537 - Baby & Toddler > Baby Transport Accessories > Baby Transport Liners & Sacks
896
+ 5845 - Baby & Toddler > Baby Transport Accessories > Shopping Cart & High Chair Covers
897
+ 548 - Baby & Toddler > Diapering
898
+ 7200 - Baby & Toddler > Diapering > Baby Wipe Dispensers & Warmers
899
+ 553 - Baby & Toddler > Diapering > Baby Wipes
900
+ 502999 - Baby & Toddler > Diapering > Changing Mat & Tray Covers
901
+ 5628 - Baby & Toddler > Diapering > Changing Mats & Trays
902
+ 7014 - Baby & Toddler > Diapering > Diaper Kits
903
+ 6949 - Baby & Toddler > Diapering > Diaper Liners
904
+ 6883 - Baby & Toddler > Diapering > Diaper Organizers
905
+ 7001 - Baby & Toddler > Diapering > Diaper Pail Accessories
906
+ 550 - Baby & Toddler > Diapering > Diaper Pails
907
+ 2949 - Baby & Toddler > Diapering > Diaper Rash Treatments
908
+ 6971 - Baby & Toddler > Diapering > Diaper Wet Bags
909
+ 551 - Baby & Toddler > Diapering > Diapers
910
+ 561 - Baby & Toddler > Nursing & Feeding
911
+ 562 - Baby & Toddler > Nursing & Feeding > Baby & Toddler Food
912
+ 5721 - Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Cereal
913
+ 5718 - Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Drinks
914
+ 5719 - Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Food
915
+ 563 - Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Formula
916
+ 5720 - Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Baby Snacks
917
+ 8436 - Baby & Toddler > Nursing & Feeding > Baby & Toddler Food > Toddler Nutrition Drinks & Shakes
918
+ 5630 - Baby & Toddler > Nursing & Feeding > Baby Bottle Nipples & Liners
919
+ 543637 - Baby & Toddler > Nursing & Feeding > Baby Bottle Nipples & Liners > Baby Bottle Liners
920
+ 543636 - Baby & Toddler > Nursing & Feeding > Baby Bottle Nipples & Liners > Baby Bottle Nipples
921
+ 564 - Baby & Toddler > Nursing & Feeding > Baby Bottles
922
+ 4768 - Baby & Toddler > Nursing & Feeding > Baby Care Timers
923
+ 2125 - Baby & Toddler > Nursing & Feeding > Bibs
924
+ 5296 - Baby & Toddler > Nursing & Feeding > Bottle Warmers & Sterilizers
925
+ 7234 - Baby & Toddler > Nursing & Feeding > Breast Milk Storage Containers
926
+ 505366 - Baby & Toddler > Nursing & Feeding > Breast Pump Accessories
927
+ 565 - Baby & Toddler > Nursing & Feeding > Breast Pumps
928
+ 5629 - Baby & Toddler > Nursing & Feeding > Burp Cloths
929
+ 5843 - Baby & Toddler > Nursing & Feeding > Nursing Covers
930
+ 503762 - Baby & Toddler > Nursing & Feeding > Nursing Pads & Shields
931
+ 8075 - Baby & Toddler > Nursing & Feeding > Nursing Pillow Covers
932
+ 5298 - Baby & Toddler > Nursing & Feeding > Nursing Pillows
933
+ 6950 - Baby & Toddler > Nursing & Feeding > Sippy Cups
934
+ 6952 - Baby & Toddler > Potty Training
935
+ 552 - Baby & Toddler > Potty Training > Potty Seats
936
+ 6953 - Baby & Toddler > Potty Training > Potty Training Kits
937
+ 6899 - Baby & Toddler > Swaddling & Receiving Blankets
938
+ 543664 - Baby & Toddler > Swaddling & Receiving Blankets > Receiving Blankets
939
+ 543665 - Baby & Toddler > Swaddling & Receiving Blankets > Swaddling Blankets
940
+ 111 - Business & Industrial
941
+ 5863 - Business & Industrial > Advertising & Marketing
942
+ 5884 - Business & Industrial > Advertising & Marketing > Brochures
943
+ 5864 - Business & Industrial > Advertising & Marketing > Trade Show Counters
944
+ 5865 - Business & Industrial > Advertising & Marketing > Trade Show Displays
945
+ 112 - Business & Industrial > Agriculture
946
+ 6991 - Business & Industrial > Agriculture > Animal Husbandry
947
+ 499997 - Business & Industrial > Agriculture > Animal Husbandry > Egg Incubators
948
+ 505821 - Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed
949
+ 543545 - Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Cattle Feed
950
+ 543544 - Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Chicken Feed
951
+ 543547 - Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Goat & Sheep Feed
952
+ 543548 - Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Mixed Herd Feed
953
+ 543546 - Business & Industrial > Agriculture > Animal Husbandry > Livestock Feed > Pig Feed
954
+ 6990 - Business & Industrial > Agriculture > Animal Husbandry > Livestock Feeders & Waterers
955
+ 499946 - Business & Industrial > Agriculture > Animal Husbandry > Livestock Halters
956
+ 7261 - Business & Industrial > Automation Control Components
957
+ 7263 - Business & Industrial > Automation Control Components > Programmable Logic Controllers
958
+ 7262 - Business & Industrial > Automation Control Components > Variable Frequency & Adjustable Speed Drives
959
+ 114 - Business & Industrial > Construction
960
+ 134 - Business & Industrial > Construction > Surveying
961
+ 8278 - Business & Industrial > Construction > Traffic Cones & Barrels
962
+ 7497 - Business & Industrial > Dentistry
963
+ 7500 - Business & Industrial > Dentistry > Dental Cement
964
+ 7499 - Business & Industrial > Dentistry > Dental Tools
965
+ 8490 - Business & Industrial > Dentistry > Dental Tools > Dappen Dishes
966
+ 7498 - Business & Industrial > Dentistry > Dental Tools > Dental Mirrors
967
+ 7531 - Business & Industrial > Dentistry > Dental Tools > Dental Tool Sets
968
+ 8121 - Business & Industrial > Dentistry > Dental Tools > Prophy Cups
969
+ 8120 - Business & Industrial > Dentistry > Dental Tools > Prophy Heads
970
+ 8130 - Business & Industrial > Dentistry > Prophy Paste
971
+ 2155 - Business & Industrial > Film & Television
972
+ 1813 - Business & Industrial > Finance & Insurance
973
+ 7565 - Business & Industrial > Finance & Insurance > Bullion
974
+ 135 - Business & Industrial > Food Service
975
+ 7303 - Business & Industrial > Food Service > Bakery Boxes
976
+ 4217 - Business & Industrial > Food Service > Bus Tubs
977
+ 8532 - Business & Industrial > Food Service > Check Presenters
978
+ 5102 - Business & Industrial > Food Service > Concession Food Containers
979
+ 8059 - Business & Industrial > Food Service > Disposable Lids
980
+ 7088 - Business & Industrial > Food Service > Disposable Serveware
981
+ 7089 - Business & Industrial > Food Service > Disposable Serveware > Disposable Serving Trays
982
+ 4632 - Business & Industrial > Food Service > Disposable Tableware
983
+ 5098 - Business & Industrial > Food Service > Disposable Tableware > Disposable Bowls
984
+ 5099 - Business & Industrial > Food Service > Disposable Tableware > Disposable Cups
985
+ 5100 - Business & Industrial > Food Service > Disposable Tableware > Disposable Cutlery
986
+ 5101 - Business & Industrial > Food Service > Disposable Tableware > Disposable Plates
987
+ 4096 - Business & Industrial > Food Service > Food Service Baskets
988
+ 4742 - Business & Industrial > Food Service > Food Service Carts
989
+ 6786 - Business & Industrial > Food Service > Food Washers & Dryers
990
+ 6517 - Business & Industrial > Food Service > Hot Dog Rollers
991
+ 7353 - Business & Industrial > Food Service > Ice Bins
992
+ 5104 - Business & Industrial > Food Service > Plate & Dish Warmers
993
+ 8533 - Business & Industrial > Food Service > Sneeze Guards
994
+ 5097 - Business & Industrial > Food Service > Take-Out Containers
995
+ 7553 - Business & Industrial > Food Service > Tilt Skillets
996
+ 137 - Business & Industrial > Food Service > Vending Machines
997
+ 1827 - Business & Industrial > Forestry & Logging
998
+ 7240 - Business & Industrial > Hairdressing & Cosmetology
999
+ 505670 - Business & Industrial > Hairdressing & Cosmetology > Hairdressing Capes & Neck Covers
1000
+ 7242 - Business & Industrial > Hairdressing & Cosmetology > Pedicure Chairs
1001
+ 7241 - Business & Industrial > Hairdressing & Cosmetology > Salon Chairs
1002
+ 1795 - Business & Industrial > Heavy Machinery
1003
+ 2072 - Business & Industrial > Heavy Machinery > Chippers
1004
+ 1475 - Business & Industrial > Hotel & Hospitality
1005
+ 5830 - Business & Industrial > Industrial Storage
1006
+ 5832 - Business & Industrial > Industrial Storage > Industrial Cabinets
1007
+ 5833 - Business & Industrial > Industrial Storage > Industrial Shelving
1008
+ 5831 - Business & Industrial > Industrial Storage > Shipping Containers
1009
+ 8274 - Business & Industrial > Industrial Storage > Wire Partitions, Enclosures & Doors
1010
+ 8025 - Business & Industrial > Industrial Storage Accessories
1011
+ 500086 - Business & Industrial > Janitorial Carts & Caddies
1012
+ 1556 - Business & Industrial > Law Enforcement
1013
+ 1906 - Business & Industrial > Law Enforcement > Cuffs
1014
+ 361 - Business & Industrial > Law Enforcement > Metal Detectors
1015
+ 1470 - Business & Industrial > Manufacturing
1016
+ 6987 - Business & Industrial > Material Handling
1017
+ 6988 - Business & Industrial > Material Handling > Conveyors
1018
+ 131 - Business & Industrial > Material Handling > Lifts & Hoists
1019
+ 503768 - Business & Industrial > Material Handling > Lifts & Hoists > Hoists, Cranes & Trolleys
1020
+ 503771 - Business & Industrial > Material Handling > Lifts & Hoists > Jacks & Lift Trucks
1021
+ 503767 - Business & Industrial > Material Handling > Lifts & Hoists > Personnel Lifts
1022
+ 503769 - Business & Industrial > Material Handling > Lifts & Hoists > Pulleys, Blocks & Sheaves
1023
+ 503772 - Business & Industrial > Material Handling > Lifts & Hoists > Winches
1024
+ 503011 - Business & Industrial > Material Handling > Pallets & Loading Platforms
1025
+ 2496 - Business & Industrial > Medical
1026
+ 6275 - Business & Industrial > Medical > Hospital Curtains
1027
+ 1898 - Business & Industrial > Medical > Hospital Gowns
1028
+ 6303 - Business & Industrial > Medical > Medical Bedding
1029
+ 3477 - Business & Industrial > Medical > Medical Equipment
1030
+ 3230 - Business & Industrial > Medical > Medical Equipment > Automated External Defibrillators
1031
+ 503006 - Business & Industrial > Medical > Medical Equipment > Gait Belts
1032
+ 6972 - Business & Industrial > Medical > Medical Equipment > Medical Reflex Hammers & Tuning Forks
1033
+ 499858 - Business & Industrial > Medical > Medical Equipment > Medical Stretchers & Gurneys
1034
+ 4245 - Business & Industrial > Medical > Medical Equipment > Otoscopes & Ophthalmoscopes
1035
+ 7522 - Business & Industrial > Medical > Medical Equipment > Patient Lifts
1036
+ 4364 - Business & Industrial > Medical > Medical Equipment > Stethoscopes
1037
+ 6714 - Business & Industrial > Medical > Medical Equipment > Vital Signs Monitor Accessories
1038
+ 6280 - Business & Industrial > Medical > Medical Equipment > Vital Signs Monitors
1039
+ 5167 - Business & Industrial > Medical > Medical Furniture
1040
+ 5168 - Business & Industrial > Medical > Medical Furniture > Chiropractic Tables
1041
+ 5169 - Business & Industrial > Medical > Medical Furniture > Examination Chairs & Tables
1042
+ 4435 - Business & Industrial > Medical > Medical Furniture > Homecare & Hospital Beds
1043
+ 5170 - Business & Industrial > Medical > Medical Furniture > Medical Cabinets
1044
+ 5171 - Business & Industrial > Medical > Medical Furniture > Medical Carts
1045
+ 5173 - Business & Industrial > Medical > Medical Furniture > Medical Carts > Crash Carts
1046
+ 5174 - Business & Industrial > Medical > Medical Furniture > Medical Carts > IV Poles & Carts
1047
+ 5172 - Business & Industrial > Medical > Medical Furniture > Surgical Tables
1048
+ 230913 - Business & Industrial > Medical > Medical Instruments
1049
+ 6281 - Business & Industrial > Medical > Medical Instruments > Medical Forceps
1050
+ 232166 - Business & Industrial > Medical > Medical Instruments > Scalpel Blades
1051
+ 8026 - Business & Industrial > Medical > Medical Instruments > Scalpels
1052
+ 499935 - Business & Industrial > Medical > Medical Instruments > Surgical Needles & Sutures
1053
+ 2907 - Business & Industrial > Medical > Medical Supplies
1054
+ 511 - Business & Industrial > Medical > Medical Supplies > Disposable Gloves
1055
+ 7063 - Business & Industrial > Medical > Medical Supplies > Finger Cots
1056
+ 499696 - Business & Industrial > Medical > Medical Supplies > Medical Needles & Syringes
1057
+ 543672 - Business & Industrial > Medical > Medical Supplies > Medical Needles & Syringes > Medical Needle & Syringe Sets
1058
+ 543670 - Business & Industrial > Medical > Medical Supplies > Medical Needles & Syringes > Medical Needles
1059
+ 543671 - Business & Industrial > Medical > Medical Supplies > Medical Needles & Syringes > Medical Syringes
1060
+ 505828 - Business & Industrial > Medical > Medical Supplies > Ostomy Supplies
1061
+ 7324 - Business & Industrial > Medical > Medical Supplies > Tongue Depressors
1062
+ 6490 - Business & Industrial > Medical > Medical Teaching Equipment
1063
+ 6491 - Business & Industrial > Medical > Medical Teaching Equipment > Medical & Emergency Response Training Mannequins
1064
+ 5602 - Business & Industrial > Medical > Scrub Caps
1065
+ 2928 - Business & Industrial > Medical > Scrubs
1066
+ 1645 - Business & Industrial > Medical > Surgical Gowns
1067
+ 2187 - Business & Industrial > Mining & Quarrying
1068
+ 4285 - Business & Industrial > Piercing & Tattooing
1069
+ 4350 - Business & Industrial > Piercing & Tattooing > Piercing Supplies
1070
+ 4122 - Business & Industrial > Piercing & Tattooing > Piercing Supplies > Piercing Needles
1071
+ 4326 - Business & Industrial > Piercing & Tattooing > Tattooing Supplies
1072
+ 5853 - Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattoo Cover-Ups
1073
+ 4215 - Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Inks
1074
+ 4379 - Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Machines
1075
+ 4072 - Business & Industrial > Piercing & Tattooing > Tattooing Supplies > Tattooing Needles
1076
+ 138 - Business & Industrial > Retail
1077
+ 4244 - Business & Industrial > Retail > Clothing Display Racks
1078
+ 3803 - Business & Industrial > Retail > Display Mannequins
1079
+ 7128 - Business & Industrial > Retail > Mannequin Parts
1080
+ 4181 - Business & Industrial > Retail > Money Handling
1081
+ 4290 - Business & Industrial > Retail > Money Handling > Banknote Verifiers
1082
+ 505825 - Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories
1083
+ 4283 - Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories > Cash Drawers & Trays
1084
+ 505808 - Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories > Credit Card Terminals
1085
+ 5310 - Business & Industrial > Retail > Money Handling > Cash Register & POS Terminal Accessories > Signature Capture Pads
1086
+ 505824 - Business & Industrial > Retail > Money Handling > Cash Registers & POS Terminals
1087
+ 543647 - Business & Industrial > Retail > Money Handling > Cash Registers & POS Terminals > Cash Registers
1088
+ 543648 - Business & Industrial > Retail > Money Handling > Cash Registers & POS Terminals > POS Terminals
1089
+ 4151 - Business & Industrial > Retail > Money Handling > Coin & Bill Counters
1090
+ 3273 - Business & Industrial > Retail > Money Handling > Money Changers
1091
+ 4329 - Business & Industrial > Retail > Money Handling > Money Deposit Bags
1092
+ 4055 - Business & Industrial > Retail > Money Handling > Paper Coin Wrappers & Bill Straps
1093
+ 1837 - Business & Industrial > Retail > Paper & Plastic Shopping Bags
1094
+ 4127 - Business & Industrial > Retail > Pricing Guns
1095
+ 4160 - Business & Industrial > Retail > Retail Display Cases
1096
+ 499897 - Business & Industrial > Retail > Retail Display Props & Models
1097
+ 1624 - Business & Industrial > Science & Laboratory
1098
+ 6975 - Business & Industrial > Science & Laboratory > Biochemicals
1099
+ 7325 - Business & Industrial > Science & Laboratory > Dissection Kits
1100
+ 3002 - Business & Industrial > Science & Laboratory > Laboratory Chemicals
1101
+ 4335 - Business & Industrial > Science & Laboratory > Laboratory Equipment
1102
+ 4116 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Autoclaves
1103
+ 4336 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Centrifuges
1104
+ 7218 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Dry Ice Makers
1105
+ 500057 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Freeze-Drying Machines
1106
+ 4474 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Blenders
1107
+ 500114 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Freezers
1108
+ 503722 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Funnels
1109
+ 4133 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Hot Plates
1110
+ 4231 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Laboratory Ovens
1111
+ 4555 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories
1112
+ 4557 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Cameras
1113
+ 4556 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Eyepieces & Adapters
1114
+ 4665 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Objective Lenses
1115
+ 4664 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Replacement Bulbs
1116
+ 4558 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscope Accessories > Microscope Slides
1117
+ 158 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Microscopes
1118
+ 7437 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Microtomes
1119
+ 7468 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Spectrometer Accessories
1120
+ 7393 - Business & Industrial > Science & Laboratory > Laboratory Equipment > Spectrometers
1121
+ 8119 - Business & Industrial > Science & Laboratory > Laboratory Specimens
1122
+ 4255 - Business & Industrial > Science & Laboratory > Laboratory Supplies
1123
+ 4310 - Business & Industrial > Science & Laboratory > Laboratory Supplies > Beakers
1124
+ 4061 - Business & Industrial > Science & Laboratory > Laboratory Supplies > Graduated Cylinders
1125
+ 4036 - Business & Industrial > Science & Laboratory > Laboratory Supplies > Laboratory Flasks
1126
+ 4276 - Business & Industrial > Science & Laboratory > Laboratory Supplies > Petri Dishes
1127
+ 4075 - Business & Industrial > Science & Laboratory > Laboratory Supplies > Pipettes
1128
+ 4155 - Business & Industrial > Science & Laboratory > Laboratory Supplies > Test Tube Racks
1129
+ 4306 - Business & Industrial > Science & Laboratory > Laboratory Supplies > Test Tubes
1130
+ 4140 - Business & Industrial > Science & Laboratory > Laboratory Supplies > Wash Bottles
1131
+ 976 - Business & Industrial > Signage
1132
+ 7322 - Business & Industrial > Signage > Business Hour Signs
1133
+ 8155 - Business & Industrial > Signage > Digital Signs
1134
+ 4297 - Business & Industrial > Signage > Electric Signs
1135
+ 4131 - Business & Industrial > Signage > Electric Signs > LED Signs
1136
+ 4070 - Business & Industrial > Signage > Electric Signs > Neon Signs
1137
+ 5894 - Business & Industrial > Signage > Emergency & Exit Signs
1138
+ 5897 - Business & Industrial > Signage > Facility Identification Signs
1139
+ 7323 - Business & Industrial > Signage > Open & Closed Signs
1140
+ 5896 - Business & Industrial > Signage > Parking Signs & Permits
1141
+ 5900 - Business & Industrial > Signage > Policy Signs
1142
+ 5898 - Business & Industrial > Signage > Retail & Sale Signs
1143
+ 5895 - Business & Industrial > Signage > Road & Traffic Signs
1144
+ 5892 - Business & Industrial > Signage > Safety & Warning Signs
1145
+ 5893 - Business & Industrial > Signage > Security Signs
1146
+ 5899 - Business & Industrial > Signage > Sidewalk & Yard Signs
1147
+ 2047 - Business & Industrial > Work Safety Protective Gear
1148
+ 2389 - Business & Industrial > Work Safety Protective Gear > Bullet Proof Vests
1149
+ 8269 - Business & Industrial > Work Safety Protective Gear > Gas Mask & Respirator Accessories
1150
+ 2723 - Business & Industrial > Work Safety Protective Gear > Hardhats
1151
+ 2808 - Business & Industrial > Work Safety Protective Gear > Hazardous Material Suits
1152
+ 6764 - Business & Industrial > Work Safety Protective Gear > Protective Aprons
1153
+ 2227 - Business & Industrial > Work Safety Protective Gear > Protective Eyewear
1154
+ 503724 - Business & Industrial > Work Safety Protective Gear > Protective Masks
1155
+ 7407 - Business & Industrial > Work Safety Protective Gear > Protective Masks > Dust Masks
1156
+ 2349 - Business & Industrial > Work Safety Protective Gear > Protective Masks > Fireman's Masks
1157
+ 2473 - Business & Industrial > Work Safety Protective Gear > Protective Masks > Gas Masks & Respirators
1158
+ 513 - Business & Industrial > Work Safety Protective Gear > Protective Masks > Medical Masks
1159
+ 5591 - Business & Industrial > Work Safety Protective Gear > Safety Gloves
1160
+ 499961 - Business & Industrial > Work Safety Protective Gear > Safety Knee Pads
1161
+ 499927 - Business & Industrial > Work Safety Protective Gear > Welding Helmets
1162
+ 499708 - Business & Industrial > Work Safety Protective Gear > Work Safety Harnesses
1163
+ 7085 - Business & Industrial > Work Safety Protective Gear > Work Safety Tethers
1164
+ 141 - Cameras & Optics
1165
+ 2096 - Cameras & Optics > Camera & Optic Accessories
1166
+ 463625 - Cameras & Optics > Camera & Optic Accessories > Camera & Optic Replacement Cables
1167
+ 149 - Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses
1168
+ 4432 - Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses > Camera Lenses
1169
+ 5346 - Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses > Surveillance Camera Lenses
1170
+ 5280 - Cameras & Optics > Camera & Optic Accessories > Camera & Video Camera Lenses > Video Camera Lenses
1171
+ 2911 - Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories
1172
+ 5588 - Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens & Filter Adapter Rings
1173
+ 4441 - Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Bags
1174
+ 2829 - Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Caps
1175
+ 4416 - Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Converters
1176
+ 147 - Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Filters
1177
+ 2627 - Cameras & Optics > Camera & Optic Accessories > Camera Lens Accessories > Lens Hoods
1178
+ 143 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories
1179
+ 8174 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Accessory Sets
1180
+ 6308 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Bags & Cases
1181
+ 296246 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Body Replacement Panels & Doors
1182
+ 298420 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Digital Backs
1183
+ 153 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Film
1184
+ 5479 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Flash Accessories
1185
+ 148 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Flashes
1186
+ 500104 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Focus Devices
1187
+ 461567 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Gears
1188
+ 500037 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Grips
1189
+ 296248 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Image Sensors
1190
+ 461568 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Lens Zoom Units
1191
+ 5532 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Remote Controls
1192
+ 296247 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Replacement Buttons & Knobs
1193
+ 296249 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Replacement Screens & Displays
1194
+ 503020 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Silencers & Sound Blimps
1195
+ 499998 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Stabilizers & Supports
1196
+ 5429 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Straps
1197
+ 503019 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Camera Sun Hoods & Viewfinder Attachments
1198
+ 2987 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Flash Brackets
1199
+ 500107 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > On-Camera Monitors
1200
+ 5937 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Surveillance Camera Accessories
1201
+ 8535 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Underwater Camera Housing Accessories
1202
+ 6307 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Underwater Camera Housings
1203
+ 2394 - Cameras & Optics > Camera & Optic Accessories > Camera Parts & Accessories > Video Camera Lights
1204
+ 160 - Cameras & Optics > Camera & Optic Accessories > Optic Accessories
1205
+ 5282 - Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Binocular & Monocular Accessories
1206
+ 5545 - Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Optics Bags & Cases
1207
+ 5283 - Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Rangefinder Accessories
1208
+ 5542 - Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Spotting Scope Accessories
1209
+ 5284 - Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Telescope Accessories
1210
+ 4274 - Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Thermal Optic Accessories
1211
+ 5543 - Cameras & Optics > Camera & Optic Accessories > Optic Accessories > Weapon Scope & Sight Accessories
1212
+ 4638 - Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories
1213
+ 4640 - Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod & Monopod Cases
1214
+ 4639 - Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod & Monopod Heads
1215
+ 3035 - Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Collars & Mounts
1216
+ 503726 - Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Handles
1217
+ 503016 - Cameras & Optics > Camera & Optic Accessories > Tripod & Monopod Accessories > Tripod Spreaders
1218
+ 150 - Cameras & Optics > Camera & Optic Accessories > Tripods & Monopods
1219
+ 142 - Cameras & Optics > Cameras
1220
+ 499976 - Cameras & Optics > Cameras > Borescopes
1221
+ 152 - Cameras & Optics > Cameras > Digital Cameras
1222
+ 4024 - Cameras & Optics > Cameras > Disposable Cameras
1223
+ 154 - Cameras & Optics > Cameras > Film Cameras
1224
+ 362 - Cameras & Optics > Cameras > Surveillance Cameras
1225
+ 5402 - Cameras & Optics > Cameras > Trail Cameras
1226
+ 155 - Cameras & Optics > Cameras > Video Cameras
1227
+ 312 - Cameras & Optics > Cameras > Webcams
1228
+ 156 - Cameras & Optics > Optics
1229
+ 157 - Cameras & Optics > Optics > Binoculars
1230
+ 4164 - Cameras & Optics > Optics > Monoculars
1231
+ 161 - Cameras & Optics > Optics > Rangefinders
1232
+ 4040 - Cameras & Optics > Optics > Scopes
1233
+ 4136 - Cameras & Optics > Optics > Scopes > Spotting Scopes
1234
+ 165 - Cameras & Optics > Optics > Scopes > Telescopes
1235
+ 1695 - Cameras & Optics > Optics > Scopes > Weapon Scopes & Sights
1236
+ 39 - Cameras & Optics > Photography
1237
+ 41 - Cameras & Optics > Photography > Darkroom
1238
+ 2234 - Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment
1239
+ 2625 - Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Copystands
1240
+ 2999 - Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Darkroom Sinks
1241
+ 2650 - Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Developing Tanks & Reels
1242
+ 2728 - Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Print Trays, Washers & Dryers
1243
+ 2516 - Cameras & Optics > Photography > Darkroom > Developing & Processing Equipment > Retouching Equipment & Supplies
1244
+ 2520 - Cameras & Optics > Photography > Darkroom > Enlarging Equipment
1245
+ 2969 - Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Darkroom Easels
1246
+ 2543 - Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Darkroom Timers
1247
+ 3029 - Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Focusing Aids
1248
+ 2815 - Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Photographic Analyzers
1249
+ 2698 - Cameras & Optics > Photography > Darkroom > Enlarging Equipment > Photographic Enlargers
1250
+ 1622 - Cameras & Optics > Photography > Darkroom > Photographic Chemicals
1251
+ 2804 - Cameras & Optics > Photography > Darkroom > Photographic Paper
1252
+ 2600 - Cameras & Optics > Photography > Darkroom > Safelights
1253
+ 42 - Cameras & Optics > Photography > Lighting & Studio
1254
+ 5499 - Cameras & Optics > Photography > Lighting & Studio > Light Meter Accessories
1255
+ 1548 - Cameras & Optics > Photography > Lighting & Studio > Light Meters
1256
+ 1611 - Cameras & Optics > Photography > Lighting & Studio > Studio Backgrounds
1257
+ 503018 - Cameras & Optics > Photography > Lighting & Studio > Studio Light & Flash Accessories
1258
+ 2475 - Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls
1259
+ 3056 - Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Flash Diffusers
1260
+ 5431 - Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Flash Reflectors
1261
+ 2490 - Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Lighting Filters & Gobos
1262
+ 5432 - Cameras & Optics > Photography > Lighting & Studio > Studio Lighting Controls > Softboxes
1263
+ 2926 - Cameras & Optics > Photography > Lighting & Studio > Studio Lights & Flashes
1264
+ 503017 - Cameras & Optics > Photography > Lighting & Studio > Studio Stand & Mount Accessories
1265
+ 2007 - Cameras & Optics > Photography > Lighting & Studio > Studio Stands & Mounts
1266
+ 503735 - Cameras & Optics > Photography > Photo Mounting Supplies
1267
+ 4368 - Cameras & Optics > Photography > Photo Negative & Slide Storage
1268
+ 222 - Electronics
1269
+ 3356 - Electronics > Arcade Equipment
1270
+ 8085 - Electronics > Arcade Equipment > Basketball Arcade Games
1271
+ 3946 - Electronics > Arcade Equipment > Pinball Machine Accessories
1272
+ 3140 - Electronics > Arcade Equipment > Pinball Machines
1273
+ 3681 - Electronics > Arcade Equipment > Skee-Ball Machines
1274
+ 3676 - Electronics > Arcade Equipment > Video Game Arcade Cabinet Accessories
1275
+ 3117 - Electronics > Arcade Equipment > Video Game Arcade Cabinets
1276
+ 223 - Electronics > Audio
1277
+ 1420 - Electronics > Audio > Audio Accessories
1278
+ 503008 - Electronics > Audio > Audio Accessories > Audio & Video Receiver Accessories
1279
+ 505797 - Electronics > Audio > Audio Accessories > Headphone & Headset Accessories
1280
+ 503004 - Electronics > Audio > Audio Accessories > Headphone & Headset Accessories > Headphone Cushions & Tips
1281
+ 5395 - Electronics > Audio > Audio Accessories > Karaoke System Accessories
1282
+ 5396 - Electronics > Audio > Audio Accessories > Karaoke System Accessories > Karaoke Chips
1283
+ 232 - Electronics > Audio > Audio Accessories > MP3 Player Accessories
1284
+ 7566 - Electronics > Audio > Audio Accessories > MP3 Player Accessories > MP3 Player & Mobile Phone Accessory Sets
1285
+ 3055 - Electronics > Audio > Audio Accessories > MP3 Player Accessories > MP3 Player Cases
1286
+ 3306 - Electronics > Audio > Audio Accessories > Microphone Accessories
1287
+ 3912 - Electronics > Audio > Audio Accessories > Microphone Stands
1288
+ 239 - Electronics > Audio > Audio Accessories > Satellite Radio Accessories
1289
+ 7163 - Electronics > Audio > Audio Accessories > Speaker Accessories
1290
+ 500112 - Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Bags, Covers & Cases
1291
+ 500120 - Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Components & Kits
1292
+ 8047 - Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Stand Bags
1293
+ 8049 - Electronics > Audio > Audio Accessories > Speaker Accessories > Speaker Stands & Mounts
1294
+ 500119 - Electronics > Audio > Audio Accessories > Speaker Accessories > Tactile Transducers
1295
+ 2372 - Electronics > Audio > Audio Accessories > Turntable Accessories
1296
+ 2165 - Electronics > Audio > Audio Components
1297
+ 241 - Electronics > Audio > Audio Components > Audio & Video Receivers
1298
+ 224 - Electronics > Audio > Audio Components > Audio Amplifiers
1299
+ 4493 - Electronics > Audio > Audio Components > Audio Amplifiers > Headphone Amplifiers
1300
+ 5381 - Electronics > Audio > Audio Components > Audio Amplifiers > Power Amplifiers
1301
+ 236 - Electronics > Audio > Audio Components > Audio Mixers
1302
+ 5129 - Electronics > Audio > Audio Components > Audio Transmitters
1303
+ 5130 - Electronics > Audio > Audio Components > Audio Transmitters > Bluetooth Transmitters
1304
+ 4035 - Electronics > Audio > Audio Components > Audio Transmitters > FM Transmitters
1305
+ 6545 - Electronics > Audio > Audio Components > Channel Strips
1306
+ 6546 - Electronics > Audio > Audio Components > Direct Boxes
1307
+ 505771 - Electronics > Audio > Audio Components > Headphones & Headsets
1308
+ 543626 - Electronics > Audio > Audio Components > Headphones & Headsets > Headphones
1309
+ 543627 - Electronics > Audio > Audio Components > Headphones & Headsets > Headsets
1310
+ 234 - Electronics > Audio > Audio Components > Microphones
1311
+ 246 - Electronics > Audio > Audio Components > Signal Processors
1312
+ 5435 - Electronics > Audio > Audio Components > Signal Processors > Crossovers
1313
+ 247 - Electronics > Audio > Audio Components > Signal Processors > Effects Processors
1314
+ 248 - Electronics > Audio > Audio Components > Signal Processors > Equalizers
1315
+ 5597 - Electronics > Audio > Audio Components > Signal Processors > Loudspeaker Management Systems
1316
+ 3945 - Electronics > Audio > Audio Components > Signal Processors > Microphone Preamps
1317
+ 5596 - Electronics > Audio > Audio Components > Signal Processors > Noise Gates & Compressors
1318
+ 5369 - Electronics > Audio > Audio Components > Signal Processors > Phono Preamps
1319
+ 249 - Electronics > Audio > Audio Components > Speakers
1320
+ 505298 - Electronics > Audio > Audio Components > Studio Recording Bundles
1321
+ 242 - Electronics > Audio > Audio Players & Recorders
1322
+ 225 - Electronics > Audio > Audio Players & Recorders > Boomboxes
1323
+ 226 - Electronics > Audio > Audio Players & Recorders > CD Players & Recorders
1324
+ 243 - Electronics > Audio > Audio Players & Recorders > Cassette Players & Recorders
1325
+ 252 - Electronics > Audio > Audio Players & Recorders > Home Theater Systems
1326
+ 4652 - Electronics > Audio > Audio Players & Recorders > Jukeboxes
1327
+ 230 - Electronics > Audio > Audio Players & Recorders > Karaoke Systems
1328
+ 233 - Electronics > Audio > Audio Players & Recorders > MP3 Players
1329
+ 235 - Electronics > Audio > Audio Players & Recorders > MiniDisc Players & Recorders
1330
+ 5434 - Electronics > Audio > Audio Players & Recorders > Multitrack Recorders
1331
+ 6886 - Electronics > Audio > Audio Players & Recorders > Radios
1332
+ 8271 - Electronics > Audio > Audio Players & Recorders > Reel-to-Reel Tape Players & Recorders
1333
+ 251 - Electronics > Audio > Audio Players & Recorders > Stereo Systems
1334
+ 256 - Electronics > Audio > Audio Players & Recorders > Turntables & Record Players
1335
+ 244 - Electronics > Audio > Audio Players & Recorders > Voice Recorders
1336
+ 8159 - Electronics > Audio > Bullhorns
1337
+ 4921 - Electronics > Audio > DJ & Specialty Audio
1338
+ 4922 - Electronics > Audio > DJ & Specialty Audio > DJ CD Players
1339
+ 4923 - Electronics > Audio > DJ & Specialty Audio > DJ Systems
1340
+ 2154 - Electronics > Audio > Public Address Systems
1341
+ 3727 - Electronics > Audio > Stage Equipment
1342
+ 3242 - Electronics > Audio > Stage Equipment > Wireless Transmitters
1343
+ 3702 - Electronics > Circuit Boards & Components
1344
+ 500027 - Electronics > Circuit Boards & Components > Circuit Board Accessories
1345
+ 7259 - Electronics > Circuit Boards & Components > Circuit Decoders & Encoders
1346
+ 3889 - Electronics > Circuit Boards & Components > Circuit Prototyping
1347
+ 4010 - Electronics > Circuit Boards & Components > Circuit Prototyping > Breadboards
1348
+ 7258 - Electronics > Circuit Boards & Components > Electronic Filters
1349
+ 3635 - Electronics > Circuit Boards & Components > Passive Circuit Components
1350
+ 3220 - Electronics > Circuit Boards & Components > Passive Circuit Components > Capacitors
1351
+ 7260 - Electronics > Circuit Boards & Components > Passive Circuit Components > Electronic Oscillators
1352
+ 3121 - Electronics > Circuit Boards & Components > Passive Circuit Components > Inductors
1353
+ 3424 - Electronics > Circuit Boards & Components > Passive Circuit Components > Resistors
1354
+ 7264 - Electronics > Circuit Boards & Components > Printed Circuit Boards
1355
+ 298419 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Camera Circuit Boards
1356
+ 499898 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards
1357
+ 499899 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards > Computer Inverter Boards
1358
+ 8546 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards > Hard Drive Circuit Boards
1359
+ 289 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Computer Circuit Boards > Motherboards
1360
+ 3416 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Development Boards
1361
+ 499889 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Exercise Machine Circuit Boards
1362
+ 8545 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Household Appliance Circuit Boards
1363
+ 8549 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Pool & Spa Circuit Boards
1364
+ 8544 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Printer, Copier, & Fax Machine Circuit Boards
1365
+ 499675 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Scanner Circuit Boards
1366
+ 8516 - Electronics > Circuit Boards & Components > Printed Circuit Boards > Television Circuit Boards
1367
+ 3991 - Electronics > Circuit Boards & Components > Semiconductors
1368
+ 3632 - Electronics > Circuit Boards & Components > Semiconductors > Diodes
1369
+ 7257 - Electronics > Circuit Boards & Components > Semiconductors > Integrated Circuits & Chips
1370
+ 3949 - Electronics > Circuit Boards & Components > Semiconductors > Microcontrollers
1371
+ 3094 - Electronics > Circuit Boards & Components > Semiconductors > Transistors
1372
+ 262 - Electronics > Communications
1373
+ 266 - Electronics > Communications > Answering Machines
1374
+ 5275 - Electronics > Communications > Caller IDs
1375
+ 263 - Electronics > Communications > Communication Radio Accessories
1376
+ 2471 - Electronics > Communications > Communication Radios
1377
+ 2106 - Electronics > Communications > Communication Radios > CB Radios
1378
+ 4415 - Electronics > Communications > Communication Radios > Radio Scanners
1379
+ 273 - Electronics > Communications > Communication Radios > Two-Way Radios
1380
+ 5404 - Electronics > Communications > Intercom Accessories
1381
+ 360 - Electronics > Communications > Intercoms
1382
+ 268 - Electronics > Communications > Pagers
1383
+ 270 - Electronics > Communications > Telephony
1384
+ 4666 - Electronics > Communications > Telephony > Conference Phones
1385
+ 271 - Electronics > Communications > Telephony > Corded Phones
1386
+ 272 - Electronics > Communications > Telephony > Cordless Phones
1387
+ 264 - Electronics > Communications > Telephony > Mobile Phone Accessories
1388
+ 8111 - Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Camera Accessories
1389
+ 2353 - Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Cases
1390
+ 4550 - Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Charms & Straps
1391
+ 6030 - Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Pre-Paid Cards & SIM Cards
1392
+ 543515 - Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Pre-Paid Cards & SIM Cards > Mobile Phone Pre-Paid Cards
1393
+ 543516 - Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Pre-Paid Cards & SIM Cards > SIM Cards
1394
+ 7347 - Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Replacement Parts
1395
+ 5566 - Electronics > Communications > Telephony > Mobile Phone Accessories > Mobile Phone Stands
1396
+ 499916 - Electronics > Communications > Telephony > Mobile Phone Accessories > SIM Card Ejection Tools
1397
+ 267 - Electronics > Communications > Telephony > Mobile Phones
1398
+ 543513 - Electronics > Communications > Telephony > Mobile Phones > Contract Mobile Phones
1399
+ 543512 - Electronics > Communications > Telephony > Mobile Phones > Pre-paid Mobile Phones
1400
+ 543514 - Electronics > Communications > Telephony > Mobile Phones > Unlocked Mobile Phones
1401
+ 1924 - Electronics > Communications > Telephony > Satellite Phones
1402
+ 265 - Electronics > Communications > Telephony > Telephone Accessories
1403
+ 269 - Electronics > Communications > Telephony > Telephone Accessories > Phone Cards
1404
+ 274 - Electronics > Communications > Video Conferencing
1405
+ 1801 - Electronics > Components
1406
+ 7395 - Electronics > Components > Accelerometers
1407
+ 2182 - Electronics > Components > Converters
1408
+ 503001 - Electronics > Components > Converters > Audio Converters
1409
+ 2205 - Electronics > Components > Converters > Scan Converters
1410
+ 1977 - Electronics > Components > Electronics Component Connectors
1411
+ 1337 - Electronics > Components > Modulators
1412
+ 1544 - Electronics > Components > Splitters
1413
+ 278 - Electronics > Computers
1414
+ 5254 - Electronics > Computers > Barebone Computers
1415
+ 331 - Electronics > Computers > Computer Servers
1416
+ 325 - Electronics > Computers > Desktop Computers
1417
+ 298 - Electronics > Computers > Handheld Devices
1418
+ 5256 - Electronics > Computers > Handheld Devices > Data Collectors
1419
+ 3539 - Electronics > Computers > Handheld Devices > E-Book Readers
1420
+ 3769 - Electronics > Computers > Handheld Devices > PDAs
1421
+ 5255 - Electronics > Computers > Interactive Kiosks
1422
+ 328 - Electronics > Computers > Laptops
1423
+ 500002 - Electronics > Computers > Smart Glasses
1424
+ 4745 - Electronics > Computers > Tablet Computers
1425
+ 8539 - Electronics > Computers > Thin & Zero Clients
1426
+ 543668 - Electronics > Computers > Thin & Zero Clients > Thin Client Computers
1427
+ 543669 - Electronics > Computers > Thin & Zero Clients > Zero Client Computers
1428
+ 502995 - Electronics > Computers > Touch Table Computers
1429
+ 2082 - Electronics > Electronics Accessories
1430
+ 258 - Electronics > Electronics Accessories > Adapters
1431
+ 4463 - Electronics > Electronics Accessories > Adapters > Audio & Video Cable Adapters & Couplers
1432
+ 146 - Electronics > Electronics Accessories > Adapters > Memory Card Adapters
1433
+ 7182 - Electronics > Electronics Accessories > Adapters > USB Adapters
1434
+ 5476 - Electronics > Electronics Accessories > Antenna Accessories
1435
+ 5477 - Electronics > Electronics Accessories > Antenna Accessories > Antenna Mounts & Brackets
1436
+ 5478 - Electronics > Electronics Accessories > Antenna Accessories > Antenna Rotators
1437
+ 6016 - Electronics > Electronics Accessories > Antenna Accessories > Satellite LNBs
1438
+ 1718 - Electronics > Electronics Accessories > Antennas
1439
+ 8156 - Electronics > Electronics Accessories > Audio & Video Splitters & Switches
1440
+ 499944 - Electronics > Electronics Accessories > Audio & Video Splitters & Switches > DVI Splitters & Switches
1441
+ 8164 - Electronics > Electronics Accessories > Audio & Video Splitters & Switches > HDMI Splitters & Switches
1442
+ 499945 - Electronics > Electronics Accessories > Audio & Video Splitters & Switches > VGA Splitters & Switches
1443
+ 367 - Electronics > Electronics Accessories > Blank Media
1444
+ 3328 - Electronics > Electronics Accessories > Cable Management
1445
+ 3764 - Electronics > Electronics Accessories > Cable Management > Cable Clips
1446
+ 500036 - Electronics > Electronics Accessories > Cable Management > Cable Tie Guns
1447
+ 6402 - Electronics > Electronics Accessories > Cable Management > Cable Trays
1448
+ 5273 - Electronics > Electronics Accessories > Cable Management > Patch Panels
1449
+ 499686 - Electronics > Electronics Accessories > Cable Management > Wire & Cable Identification Markers
1450
+ 6780 - Electronics > Electronics Accessories > Cable Management > Wire & Cable Sleeves
1451
+ 4016 - Electronics > Electronics Accessories > Cable Management > Wire & Cable Ties
1452
+ 259 - Electronics > Electronics Accessories > Cables
1453
+ 1867 - Electronics > Electronics Accessories > Cables > Audio & Video Cables
1454
+ 3461 - Electronics > Electronics Accessories > Cables > KVM Cables
1455
+ 1480 - Electronics > Electronics Accessories > Cables > Network Cables
1456
+ 500035 - Electronics > Electronics Accessories > Cables > Storage & Data Transfer Cables
1457
+ 1763 - Electronics > Electronics Accessories > Cables > System & Power Cables
1458
+ 3541 - Electronics > Electronics Accessories > Cables > Telephone Cables
1459
+ 279 - Electronics > Electronics Accessories > Computer Accessories
1460
+ 500040 - Electronics > Electronics Accessories > Computer Accessories > Computer Accessory Sets
1461
+ 7530 - Electronics > Electronics Accessories > Computer Accessories > Computer Covers & Skins
1462
+ 5489 - Electronics > Electronics Accessories > Computer Accessories > Computer Risers & Stands
1463
+ 280 - Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories
1464
+ 4736 - Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > E-Book Reader Accessories
1465
+ 4738 - Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > E-Book Reader Accessories > E-Book Reader Cases
1466
+ 4737 - Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > PDA Accessories
1467
+ 4739 - Electronics > Electronics Accessories > Computer Accessories > Handheld Device Accessories > PDA Accessories > PDA Cases
1468
+ 6291 - Electronics > Electronics Accessories > Computer Accessories > Keyboard & Mouse Wrist Rests
1469
+ 6979 - Electronics > Electronics Accessories > Computer Accessories > Keyboard Trays & Platforms
1470
+ 300 - Electronics > Electronics Accessories > Computer Accessories > Laptop Docking Stations
1471
+ 1993 - Electronics > Electronics Accessories > Computer Accessories > Mouse Pads
1472
+ 5669 - Electronics > Electronics Accessories > Computer Accessories > Stylus Pen Nibs & Refills
1473
+ 5308 - Electronics > Electronics Accessories > Computer Accessories > Stylus Pens
1474
+ 499956 - Electronics > Electronics Accessories > Computer Accessories > Tablet Computer Docks & Stands
1475
+ 285 - Electronics > Electronics Accessories > Computer Components
1476
+ 6932 - Electronics > Electronics Accessories > Computer Components > Blade Server Enclosures
1477
+ 8158 - Electronics > Electronics Accessories > Computer Components > Computer Backplates & I/O Shields
1478
+ 291 - Electronics > Electronics Accessories > Computer Components > Computer Power Supplies
1479
+ 292 - Electronics > Electronics Accessories > Computer Components > Computer Processors
1480
+ 293 - Electronics > Electronics Accessories > Computer Components > Computer Racks & Mounts
1481
+ 294 - Electronics > Electronics Accessories > Computer Components > Computer Starter Kits
1482
+ 295 - Electronics > Electronics Accessories > Computer Components > Computer System Cooling Parts
1483
+ 296 - Electronics > Electronics Accessories > Computer Components > Desktop Computer & Server Cases
1484
+ 8162 - Electronics > Electronics Accessories > Computer Components > E-Book Reader Parts
1485
+ 8163 - Electronics > Electronics Accessories > Computer Components > E-Book Reader Parts > E-Book Reader Screens & Screen Digitizers
1486
+ 287 - Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters
1487
+ 286 - Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Audio Cards & Adapters
1488
+ 505299 - Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Computer Interface Cards & Adapters
1489
+ 503755 - Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Riser Cards
1490
+ 1487 - Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > TV Tuner Cards & Adapters
1491
+ 297 - Electronics > Electronics Accessories > Computer Components > I/O Cards & Adapters > Video Cards & Adapters
1492
+ 6475 - Electronics > Electronics Accessories > Computer Components > Input Device Accessories
1493
+ 6476 - Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Barcode Scanner Stands
1494
+ 8008 - Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Game Controller Accessories
1495
+ 503003 - Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Keyboard Keys & Caps
1496
+ 500052 - Electronics > Electronics Accessories > Computer Components > Input Device Accessories > Mice & Trackball Accessories
1497
+ 1928 - Electronics > Electronics Accessories > Computer Components > Input Devices
1498
+ 139 - Electronics > Electronics Accessories > Computer Components > Input Devices > Barcode Scanners
1499
+ 5309 - Electronics > Electronics Accessories > Computer Components > Input Devices > Digital Note Taking Pens
1500
+ 505801 - Electronics > Electronics Accessories > Computer Components > Input Devices > Electronic Card Readers
1501
+ 5366 - Electronics > Electronics Accessories > Computer Components > Input Devices > Fingerprint Readers
1502
+ 301 - Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers
1503
+ 543591 - Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Game Racing Wheels
1504
+ 543590 - Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Game Remotes
1505
+ 543589 - Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Gaming Pads
1506
+ 543588 - Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Joystick Controllers
1507
+ 543593 - Electronics > Electronics Accessories > Computer Components > Input Devices > Game Controllers > Musical Instrument Game Controllers
1508
+ 499950 - Electronics > Electronics Accessories > Computer Components > Input Devices > Gesture Control Input Devices
1509
+ 302 - Electronics > Electronics Accessories > Computer Components > Input Devices > Graphics Tablets
1510
+ 1562 - Electronics > Electronics Accessories > Computer Components > Input Devices > KVM Switches
1511
+ 303 - Electronics > Electronics Accessories > Computer Components > Input Devices > Keyboards
1512
+ 3580 - Electronics > Electronics Accessories > Computer Components > Input Devices > Memory Card Readers
1513
+ 304 - Electronics > Electronics Accessories > Computer Components > Input Devices > Mice & Trackballs
1514
+ 4512 - Electronics > Electronics Accessories > Computer Components > Input Devices > Numeric Keypads
1515
+ 308 - Electronics > Electronics Accessories > Computer Components > Input Devices > Touchpads
1516
+ 4224 - Electronics > Electronics Accessories > Computer Components > Laptop Parts
1517
+ 6416 - Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Hinges
1518
+ 4270 - Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Housings & Trim
1519
+ 7501 - Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Cables
1520
+ 4301 - Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Keyboards
1521
+ 4102 - Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Screens
1522
+ 43617 - Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Replacement Speakers
1523
+ 8160 - Electronics > Electronics Accessories > Computer Components > Laptop Parts > Laptop Screen Digitizers
1524
+ 2414 - Electronics > Electronics Accessories > Computer Components > Storage Devices
1525
+ 5268 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators
1526
+ 376 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators > CD/DVD Duplicators
1527
+ 5271 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators > Hard Drive Duplicators
1528
+ 5112 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Disk Duplicators > USB Drive Duplicators
1529
+ 1301 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Floppy Drives
1530
+ 1623 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories
1531
+ 381 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories > Hard Drive Carrying Cases
1532
+ 4417 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories > Hard Drive Docks
1533
+ 505767 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Accessories > Hard Drive Enclosures & Mounts
1534
+ 5272 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drive Arrays
1535
+ 380 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Hard Drives
1536
+ 5269 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Network Storage Systems
1537
+ 377 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Optical Drives
1538
+ 385 - Electronics > Electronics Accessories > Computer Components > Storage Devices > Tape Drives
1539
+ 3712 - Electronics > Electronics Accessories > Computer Components > Storage Devices > USB Flash Drives
1540
+ 7349 - Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts
1541
+ 503002 - Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts > Tablet Computer Housings & Trim
1542
+ 45262 - Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts > Tablet Computer Replacement Speakers
1543
+ 500013 - Electronics > Electronics Accessories > Computer Components > Tablet Computer Parts > Tablet Computer Screens & Screen Digitizers
1544
+ 311 - Electronics > Electronics Accessories > Computer Components > USB & FireWire Hubs
1545
+ 4617 - Electronics > Electronics Accessories > Electronics Cleaners
1546
+ 5466 - Electronics > Electronics Accessories > Electronics Films & Shields
1547
+ 5523 - Electronics > Electronics Accessories > Electronics Films & Shields > Electronics Stickers & Decals
1548
+ 5469 - Electronics > Electronics Accessories > Electronics Films & Shields > Keyboard Protectors
1549
+ 5467 - Electronics > Electronics Accessories > Electronics Films & Shields > Privacy Filters
1550
+ 5468 - Electronics > Electronics Accessories > Electronics Films & Shields > Screen Protectors
1551
+ 288 - Electronics > Electronics Accessories > Memory
1552
+ 1665 - Electronics > Electronics Accessories > Memory > Cache Memory
1553
+ 384 - Electronics > Electronics Accessories > Memory > Flash Memory
1554
+ 3387 - Electronics > Electronics Accessories > Memory > Flash Memory > Flash Memory Cards
1555
+ 1733 - Electronics > Electronics Accessories > Memory > RAM
1556
+ 2130 - Electronics > Electronics Accessories > Memory > ROM
1557
+ 1767 - Electronics > Electronics Accessories > Memory > Video Memory
1558
+ 3422 - Electronics > Electronics Accessories > Memory Accessories
1559
+ 3672 - Electronics > Electronics Accessories > Memory Accessories > Memory Cases
1560
+ 499878 - Electronics > Electronics Accessories > Mobile Phone & Tablet Tripods & Monopods
1561
+ 275 - Electronics > Electronics Accessories > Power
1562
+ 276 - Electronics > Electronics Accessories > Power > Batteries
1563
+ 1722 - Electronics > Electronics Accessories > Power > Batteries > Camera Batteries
1564
+ 1880 - Electronics > Electronics Accessories > Power > Batteries > Cordless Phone Batteries
1565
+ 7551 - Electronics > Electronics Accessories > Power > Batteries > E-Book Reader Batteries
1566
+ 4928 - Electronics > Electronics Accessories > Power > Batteries > General Purpose Batteries
1567
+ 1564 - Electronics > Electronics Accessories > Power > Batteries > Laptop Batteries
1568
+ 499810 - Electronics > Electronics Accessories > Power > Batteries > MP3 Player Batteries
1569
+ 1745 - Electronics > Electronics Accessories > Power > Batteries > Mobile Phone Batteries
1570
+ 5133 - Electronics > Electronics Accessories > Power > Batteries > PDA Batteries
1571
+ 7438 - Electronics > Electronics Accessories > Power > Batteries > Tablet Computer Batteries
1572
+ 6289 - Electronics > Electronics Accessories > Power > Batteries > UPS Batteries
1573
+ 2222 - Electronics > Electronics Accessories > Power > Batteries > Video Camera Batteries
1574
+ 500117 - Electronics > Electronics Accessories > Power > Batteries > Video Game Console & Controller Batteries
1575
+ 7166 - Electronics > Electronics Accessories > Power > Battery Accessories
1576
+ 6817 - Electronics > Electronics Accessories > Power > Battery Accessories > Battery Charge Controllers
1577
+ 8243 - Electronics > Electronics Accessories > Power > Battery Accessories > Battery Holders
1578
+ 3130 - Electronics > Electronics Accessories > Power > Battery Accessories > Camera Battery Chargers
1579
+ 7167 - Electronics > Electronics Accessories > Power > Battery Accessories > General Purpose Battery Chargers
1580
+ 499928 - Electronics > Electronics Accessories > Power > Battery Accessories > General Purpose Battery Testers
1581
+ 2978 - Electronics > Electronics Accessories > Power > Fuel Cells
1582
+ 6933 - Electronics > Electronics Accessories > Power > Power Adapter & Charger Accessories
1583
+ 505295 - Electronics > Electronics Accessories > Power > Power Adapters & Chargers
1584
+ 6790 - Electronics > Electronics Accessories > Power > Power Control Units
1585
+ 3160 - Electronics > Electronics Accessories > Power > Power Strips & Surge Suppressors
1586
+ 5274 - Electronics > Electronics Accessories > Power > Power Supply Enclosures
1587
+ 5380 - Electronics > Electronics Accessories > Power > Surge Protection Devices
1588
+ 7135 - Electronics > Electronics Accessories > Power > Travel Converters & Adapters
1589
+ 1348 - Electronics > Electronics Accessories > Power > UPS
1590
+ 1375 - Electronics > Electronics Accessories > Power > UPS Accessories
1591
+ 341 - Electronics > Electronics Accessories > Remote Controls
1592
+ 5473 - Electronics > Electronics Accessories > Signal Boosters
1593
+ 5695 - Electronics > Electronics Accessories > Signal Jammers
1594
+ 5612 - Electronics > Electronics Accessories > Signal Jammers > GPS Jammers
1595
+ 5696 - Electronics > Electronics Accessories > Signal Jammers > Mobile Phone Jammers
1596
+ 5589 - Electronics > Electronics Accessories > Signal Jammers > Radar Jammers
1597
+ 3895 - Electronics > GPS Accessories
1598
+ 3781 - Electronics > GPS Accessories > GPS Cases
1599
+ 3213 - Electronics > GPS Accessories > GPS Mounts
1600
+ 339 - Electronics > GPS Navigation Systems
1601
+ 6544 - Electronics > GPS Tracking Devices
1602
+ 340 - Electronics > Marine Electronics
1603
+ 1550 - Electronics > Marine Electronics > Fish Finders
1604
+ 8134 - Electronics > Marine Electronics > Marine Audio & Video Receivers
1605
+ 2178 - Electronics > Marine Electronics > Marine Chartplotters & GPS
1606
+ 1552 - Electronics > Marine Electronics > Marine Radar
1607
+ 4450 - Electronics > Marine Electronics > Marine Radios
1608
+ 8473 - Electronics > Marine Electronics > Marine Speakers
1609
+ 342 - Electronics > Networking
1610
+ 1350 - Electronics > Networking > Bridges & Routers
1611
+ 5659 - Electronics > Networking > Bridges & Routers > Network Bridges
1612
+ 2358 - Electronics > Networking > Bridges & Routers > VoIP Gateways & Routers
1613
+ 5496 - Electronics > Networking > Bridges & Routers > Wireless Access Points
1614
+ 5497 - Electronics > Networking > Bridges & Routers > Wireless Routers
1615
+ 2479 - Electronics > Networking > Concentrators & Multiplexers
1616
+ 2455 - Electronics > Networking > Hubs & Switches
1617
+ 5576 - Electronics > Networking > Modem Accessories
1618
+ 343 - Electronics > Networking > Modems
1619
+ 290 - Electronics > Networking > Network Cards & Adapters
1620
+ 3742 - Electronics > Networking > Network Security & Firewall Devices
1621
+ 6508 - Electronics > Networking > Power Over Ethernet Adapters
1622
+ 3425 - Electronics > Networking > Print Servers
1623
+ 2121 - Electronics > Networking > Repeaters & Transceivers
1624
+ 345 - Electronics > Print, Copy, Scan & Fax
1625
+ 499682 - Electronics > Print, Copy, Scan & Fax > 3D Printer Accessories
1626
+ 6865 - Electronics > Print, Copy, Scan & Fax > 3D Printers
1627
+ 502990 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories
1628
+ 5258 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables
1629
+ 5259 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Drums & Drum Kits
1630
+ 5266 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Filters
1631
+ 5262 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Maintenance Kits
1632
+ 5260 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printer Ribbons
1633
+ 5261 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Printheads
1634
+ 7362 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Toner & Inkjet Cartridge Refills
1635
+ 356 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Consumables > Toner & Inkjet Cartridges
1636
+ 5265 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Duplexers
1637
+ 1683 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Memory
1638
+ 5459 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer Stands
1639
+ 502991 - Electronics > Print, Copy, Scan & Fax > Printer, Copier & Fax Machine Accessories > Printer, Copier & Fax Machine Replacement Parts
1640
+ 500106 - Electronics > Print, Copy, Scan & Fax > Printers, Copiers & Fax Machines
1641
+ 284 - Electronics > Print, Copy, Scan & Fax > Scanner Accessories
1642
+ 306 - Electronics > Print, Copy, Scan & Fax > Scanners
1643
+ 912 - Electronics > Radar Detectors
1644
+ 500091 - Electronics > Speed Radars
1645
+ 4488 - Electronics > Toll Collection Devices
1646
+ 386 - Electronics > Video
1647
+ 305 - Electronics > Video > Computer Monitors
1648
+ 396 - Electronics > Video > Projectors
1649
+ 397 - Electronics > Video > Projectors > Multimedia Projectors
1650
+ 398 - Electronics > Video > Projectors > Overhead Projectors
1651
+ 399 - Electronics > Video > Projectors > Slide Projectors
1652
+ 5561 - Electronics > Video > Satellite & Cable TV
1653
+ 5562 - Electronics > Video > Satellite & Cable TV > Cable TV Receivers
1654
+ 401 - Electronics > Video > Satellite & Cable TV > Satellite Receivers
1655
+ 404 - Electronics > Video > Televisions
1656
+ 2027 - Electronics > Video > Video Accessories
1657
+ 4760 - Electronics > Video > Video Accessories > 3D Glasses
1658
+ 283 - Electronics > Video > Video Accessories > Computer Monitor Accessories
1659
+ 5516 - Electronics > Video > Video Accessories > Computer Monitor Accessories > Color Calibrators
1660
+ 393 - Electronics > Video > Video Accessories > Projector Accessories
1661
+ 5599 - Electronics > Video > Video Accessories > Projector Accessories > Projection & Tripod Skirts
1662
+ 4570 - Electronics > Video > Video Accessories > Projector Accessories > Projection Screen Stands
1663
+ 395 - Electronics > Video > Video Accessories > Projector Accessories > Projection Screens
1664
+ 5257 - Electronics > Video > Video Accessories > Projector Accessories > Projector Mounts
1665
+ 394 - Electronics > Video > Video Accessories > Projector Accessories > Projector Replacement Lamps
1666
+ 2145 - Electronics > Video > Video Accessories > Rewinders
1667
+ 403 - Electronics > Video > Video Accessories > Television Parts & Accessories
1668
+ 4458 - Electronics > Video > Video Accessories > Television Parts & Accessories > TV & Monitor Mounts
1669
+ 5503 - Electronics > Video > Video Accessories > Television Parts & Accessories > TV Converter Boxes
1670
+ 5471 - Electronics > Video > Video Accessories > Television Parts & Accessories > TV Replacement Lamps
1671
+ 43616 - Electronics > Video > Video Accessories > Television Parts & Accessories > TV Replacement Speakers
1672
+ 1368 - Electronics > Video > Video Editing Hardware & Production Equipment
1673
+ 1634 - Electronics > Video > Video Multiplexers
1674
+ 387 - Electronics > Video > Video Players & Recorders
1675
+ 388 - Electronics > Video > Video Players & Recorders > DVD & Blu-ray Players
1676
+ 389 - Electronics > Video > Video Players & Recorders > DVD Recorders
1677
+ 390 - Electronics > Video > Video Players & Recorders > Digital Video Recorders
1678
+ 5276 - Electronics > Video > Video Players & Recorders > Streaming & Home Media Players
1679
+ 391 - Electronics > Video > Video Players & Recorders > VCRs
1680
+ 5278 - Electronics > Video > Video Servers
1681
+ 5450 - Electronics > Video > Video Transmitters
1682
+ 1270 - Electronics > Video Game Console Accessories
1683
+ 1505 - Electronics > Video Game Console Accessories > Home Game Console Accessories
1684
+ 2070 - Electronics > Video Game Console Accessories > Portable Game Console Accessories
1685
+ 1294 - Electronics > Video Game Consoles
1686
+ 412 - Food, Beverages & Tobacco
1687
+ 413 - Food, Beverages & Tobacco > Beverages
1688
+ 499676 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages
1689
+ 414 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Beer
1690
+ 7486 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Bitters
1691
+ 5725 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Cocktail Mixes
1692
+ 543537 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Cocktail Mixes > Frozen Cocktail Mixes
1693
+ 543536 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Cocktail Mixes > Shelf-stable Cocktail Mixes
1694
+ 5887 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Flavored Alcoholic Beverages
1695
+ 6761 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Hard Cider
1696
+ 417 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits
1697
+ 505761 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Absinthe
1698
+ 2364 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Brandy
1699
+ 1671 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Gin
1700
+ 2933 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Liqueurs
1701
+ 2605 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Rum
1702
+ 502976 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Shochu & Soju
1703
+ 543642 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Shochu & Soju > Shochu
1704
+ 543643 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Shochu & Soju > Soju
1705
+ 2220 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Tequila
1706
+ 2107 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Vodka
1707
+ 1926 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Liquor & Spirits > Whiskey
1708
+ 421 - Food, Beverages & Tobacco > Beverages > Alcoholic Beverages > Wine
1709
+ 6797 - Food, Beverages & Tobacco > Beverages > Buttermilk
1710
+ 1868 - Food, Beverages & Tobacco > Beverages > Coffee
1711
+ 8030 - Food, Beverages & Tobacco > Beverages > Eggnog
1712
+ 8036 - Food, Beverages & Tobacco > Beverages > Fruit Flavored Drinks
1713
+ 415 - Food, Beverages & Tobacco > Beverages > Hot Chocolate
1714
+ 2887 - Food, Beverages & Tobacco > Beverages > Juice
1715
+ 418 - Food, Beverages & Tobacco > Beverages > Milk
1716
+ 5724 - Food, Beverages & Tobacco > Beverages > Non-Dairy Milk
1717
+ 6848 - Food, Beverages & Tobacco > Beverages > Powdered Beverage Mixes
1718
+ 2628 - Food, Beverages & Tobacco > Beverages > Soda
1719
+ 5723 - Food, Beverages & Tobacco > Beverages > Sports & Energy Drinks
1720
+ 2073 - Food, Beverages & Tobacco > Beverages > Tea & Infusions
1721
+ 7528 - Food, Beverages & Tobacco > Beverages > Vinegar Drinks
1722
+ 420 - Food, Beverages & Tobacco > Beverages > Water
1723
+ 543531 - Food, Beverages & Tobacco > Beverages > Water > Carbonated Water
1724
+ 543534 - Food, Beverages & Tobacco > Beverages > Water > Carbonated Water > Flavored Carbonated Water
1725
+ 543535 - Food, Beverages & Tobacco > Beverages > Water > Carbonated Water > Unflavored Carbonated Water
1726
+ 543530 - Food, Beverages & Tobacco > Beverages > Water > Distilled Water
1727
+ 543533 - Food, Beverages & Tobacco > Beverages > Water > Flat Mineral Water
1728
+ 543532 - Food, Beverages & Tobacco > Beverages > Water > Spring Water
1729
+ 422 - Food, Beverages & Tobacco > Food Items
1730
+ 1876 - Food, Beverages & Tobacco > Food Items > Bakery
1731
+ 1573 - Food, Beverages & Tobacco > Food Items > Bakery > Bagels
1732
+ 5904 - Food, Beverages & Tobacco > Food Items > Bakery > Bakery Assortments
1733
+ 424 - Food, Beverages & Tobacco > Food Items > Bakery > Breads & Buns
1734
+ 2194 - Food, Beverages & Tobacco > Food Items > Bakery > Cakes & Dessert Bars
1735
+ 6196 - Food, Beverages & Tobacco > Food Items > Bakery > Coffee Cakes
1736
+ 2229 - Food, Beverages & Tobacco > Food Items > Bakery > Cookies
1737
+ 6195 - Food, Beverages & Tobacco > Food Items > Bakery > Cupcakes
1738
+ 5751 - Food, Beverages & Tobacco > Food Items > Bakery > Donuts
1739
+ 5054 - Food, Beverages & Tobacco > Food Items > Bakery > Fudge
1740
+ 5790 - Food, Beverages & Tobacco > Food Items > Bakery > Ice Cream Cones
1741
+ 1895 - Food, Beverages & Tobacco > Food Items > Bakery > Muffins
1742
+ 5750 - Food, Beverages & Tobacco > Food Items > Bakery > Pastries & Scones
1743
+ 5749 - Food, Beverages & Tobacco > Food Items > Bakery > Pies & Tarts
1744
+ 6891 - Food, Beverages & Tobacco > Food Items > Bakery > Taco Shells & Tostadas
1745
+ 5748 - Food, Beverages & Tobacco > Food Items > Bakery > Tortillas & Wraps
1746
+ 6219 - Food, Beverages & Tobacco > Food Items > Candied & Chocolate Covered Fruit
1747
+ 4748 - Food, Beverages & Tobacco > Food Items > Candy & Chocolate
1748
+ 427 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces
1749
+ 6772 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Cocktail Sauce
1750
+ 6905 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Curry Sauce
1751
+ 6845 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings
1752
+ 6854 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings > Fruit Toppings
1753
+ 6844 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Dessert Toppings > Ice Cream Syrup
1754
+ 5763 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Fish Sauce
1755
+ 5762 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Gravy
1756
+ 4947 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Honey
1757
+ 6782 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Horseradish Sauce
1758
+ 4614 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Hot Sauce
1759
+ 2018 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Ketchup
1760
+ 500074 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Marinades & Grilling Sauces
1761
+ 1568 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Mayonnaise
1762
+ 1387 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Mustard
1763
+ 5760 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Olives & Capers
1764
+ 5759 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pasta Sauce
1765
+ 500076 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pickled Fruits & Vegetables
1766
+ 6203 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Pizza Sauce
1767
+ 500075 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Relish & Chutney
1768
+ 1969 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Salad Dressing
1769
+ 4615 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Satay Sauce
1770
+ 4616 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Soy Sauce
1771
+ 500089 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Sweet and Sour Sauces
1772
+ 4943 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Syrup
1773
+ 4692 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Tahini
1774
+ 6783 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Tartar Sauce
1775
+ 500105 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > White & Cream Sauces
1776
+ 6246 - Food, Beverages & Tobacco > Food Items > Condiments & Sauces > Worcestershire Sauce
1777
+ 2660 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients
1778
+ 6754 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Chips
1779
+ 5776 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Chocolate
1780
+ 5775 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Flavors & Extracts
1781
+ 2572 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Mixes
1782
+ 2803 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Powder
1783
+ 5774 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Baking Soda
1784
+ 6774 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Batter & Coating Mixes
1785
+ 4613 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Bean Paste
1786
+ 5773 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Bread Crumbs
1787
+ 500093 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Canned & Dry Milk
1788
+ 7506 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cookie Decorating Kits
1789
+ 2126 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Oils
1790
+ 5771 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Starch
1791
+ 5777 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Cooking Wine
1792
+ 5770 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Corn Syrup
1793
+ 5752 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough
1794
+ 5755 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Bread & Pastry Dough
1795
+ 5756 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Cookie & Brownie Dough
1796
+ 5753 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Dough > Pie Crusts
1797
+ 6775 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Edible Baking Decorations
1798
+ 543549 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Egg Replacers
1799
+ 5105 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Floss Sugar
1800
+ 2775 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Flour
1801
+ 7127 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Food Coloring
1802
+ 5769 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Frosting & Icing
1803
+ 499986 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Lemon & Lime Juice
1804
+ 5767 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Marshmallows
1805
+ 8076 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Meal
1806
+ 5766 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Molasses
1807
+ 5800 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Pie & Pastry Fillings
1808
+ 5765 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Shortening & Lard
1809
+ 7354 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Starter Cultures
1810
+ 503734 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Sugar & Sweeteners
1811
+ 499707 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Tapioca Pearls
1812
+ 6922 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Tomato Paste
1813
+ 5768 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Unflavored Gelatin
1814
+ 2140 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Vinegar
1815
+ 5778 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Waffle & Pancake Mixes
1816
+ 2905 - Food, Beverages & Tobacco > Food Items > Cooking & Baking Ingredients > Yeast
1817
+ 428 - Food, Beverages & Tobacco > Food Items > Dairy Products
1818
+ 5827 - Food, Beverages & Tobacco > Food Items > Dairy Products > Butter & Margarine
1819
+ 429 - Food, Beverages & Tobacco > Food Items > Dairy Products > Cheese
1820
+ 4418 - Food, Beverages & Tobacco > Food Items > Dairy Products > Coffee Creamer
1821
+ 1855 - Food, Beverages & Tobacco > Food Items > Dairy Products > Cottage Cheese
1822
+ 5786 - Food, Beverages & Tobacco > Food Items > Dairy Products > Cream
1823
+ 5787 - Food, Beverages & Tobacco > Food Items > Dairy Products > Sour Cream
1824
+ 6821 - Food, Beverages & Tobacco > Food Items > Dairy Products > Whipped Cream
1825
+ 1954 - Food, Beverages & Tobacco > Food Items > Dairy Products > Yogurt
1826
+ 5740 - Food, Beverages & Tobacco > Food Items > Dips & Spreads
1827
+ 6204 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Apple Butter
1828
+ 6831 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Cheese Dips & Spreads
1829
+ 5785 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Cream Cheese
1830
+ 5742 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Guacamole
1831
+ 5741 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Hummus
1832
+ 2188 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Jams & Jellies
1833
+ 3965 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Nut Butters
1834
+ 1702 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Salsa
1835
+ 6784 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Tapenade
1836
+ 6830 - Food, Beverages & Tobacco > Food Items > Dips & Spreads > Vegetable Dip
1837
+ 136 - Food, Beverages & Tobacco > Food Items > Food Gift Baskets
1838
+ 5788 - Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties
1839
+ 499991 - Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Cream & Frozen Yogurt
1840
+ 6873 - Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Cream Novelties
1841
+ 5789 - Food, Beverages & Tobacco > Food Items > Frozen Desserts & Novelties > Ice Pops
1842
+ 430 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables
1843
+ 5799 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Jarred Fruits
1844
+ 5798 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Jarred Vegetables
1845
+ 5797 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Canned & Prepared Beans
1846
+ 1755 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dried Fruits
1847
+ 7387 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dried Vegetables
1848
+ 5796 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Dry Beans
1849
+ 5795 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits
1850
+ 6566 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Apples
1851
+ 6571 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Atemoyas
1852
+ 6572 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Avocados
1853
+ 6573 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Babacos
1854
+ 6574 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Bananas
1855
+ 6582 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Berries
1856
+ 6589 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Breadfruit
1857
+ 6593 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Cactus Pears
1858
+ 6602 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Cherimoyas
1859
+ 503759 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits
1860
+ 6621 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Grapefruits
1861
+ 6632 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Kumquats
1862
+ 6636 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Lemons
1863
+ 6641 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Limequats
1864
+ 6642 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Limes
1865
+ 6658 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Oranges
1866
+ 6697 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Citrus Fruits > Tangelos
1867
+ 6809 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Coconuts
1868
+ 6812 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Dates
1869
+ 6614 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Feijoas
1870
+ 6810 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Figs
1871
+ 499906 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Fruit Mixes
1872
+ 6626 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Grapes
1873
+ 6625 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Guavas
1874
+ 6624 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Homely Fruits
1875
+ 6633 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Kiwis
1876
+ 6640 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Longan
1877
+ 6639 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Loquats
1878
+ 6638 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Lychees
1879
+ 6813 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Madroño
1880
+ 6647 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Mamey
1881
+ 6645 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Mangosteens
1882
+ 6649 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Melons
1883
+ 6661 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Papayas
1884
+ 6667 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Passion Fruit
1885
+ 6665 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pears
1886
+ 6672 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Persimmons
1887
+ 6671 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Physalis
1888
+ 6670 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pineapples
1889
+ 6676 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pitahayas
1890
+ 6673 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Pomegranates
1891
+ 6679 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Quince
1892
+ 6678 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Rambutans
1893
+ 6688 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sapodillo
1894
+ 6687 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sapote
1895
+ 6691 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Soursops
1896
+ 6594 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Starfruits
1897
+ 503760 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits
1898
+ 6567 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Apricots
1899
+ 6601 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Cherries
1900
+ 6646 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Mangoes
1901
+ 505301 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Peaches & Nectarines
1902
+ 6675 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Plumcots
1903
+ 6674 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Stone Fruits > Plums
1904
+ 6814 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Sugar Apples
1905
+ 6698 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Fruits > Tamarindo
1906
+ 5793 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables
1907
+ 6716 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Arracachas
1908
+ 6570 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Artichokes
1909
+ 6568 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Asparagus
1910
+ 6577 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Beans
1911
+ 6580 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Beets
1912
+ 6587 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Borage
1913
+ 6591 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Broccoli
1914
+ 6590 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Brussel Sprouts
1915
+ 6592 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cabbage
1916
+ 6808 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cactus Leaves
1917
+ 6596 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cardoon
1918
+ 6595 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Carrots
1919
+ 6600 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cauliflower
1920
+ 6599 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Celery
1921
+ 6598 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Celery Roots
1922
+ 6609 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Corn
1923
+ 6608 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Cucumbers
1924
+ 6613 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Eggplants
1925
+ 6816 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Fennel Bulbs
1926
+ 6615 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Fiddlehead Ferns
1927
+ 6616 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gai Choy
1928
+ 6617 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gai Lan
1929
+ 6620 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Garlic
1930
+ 6619 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Ginger Root
1931
+ 6618 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Gobo Root
1932
+ 6622 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens
1933
+ 6569 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Arugula
1934
+ 6581 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Beet Greens
1935
+ 6584 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Bok Choy
1936
+ 6597 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Chard
1937
+ 6717 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Chicory
1938
+ 6610 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Choy Sum
1939
+ 6629 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Kale
1940
+ 6637 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Lettuce
1941
+ 6656 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > On Choy
1942
+ 5792 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Salad Mixes
1943
+ 6695 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Spinach
1944
+ 6706 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Greens > Yu Choy
1945
+ 6631 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Horseradish Root
1946
+ 6630 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Jicama
1947
+ 6628 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Kohlrabi
1948
+ 6627 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Leeks
1949
+ 6644 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Lotus Roots
1950
+ 6643 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Malangas
1951
+ 6653 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Mushrooms
1952
+ 6657 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Okra
1953
+ 6655 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Onions
1954
+ 6664 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Parsley Roots
1955
+ 6663 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Parsnips
1956
+ 6669 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Peas
1957
+ 6668 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Peppers
1958
+ 6586 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Potatoes
1959
+ 6682 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Radishes
1960
+ 6681 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Rhubarb
1961
+ 6818 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Shallots
1962
+ 503761 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sprouts
1963
+ 505354 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Squashes & Gourds
1964
+ 6694 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sugar Cane
1965
+ 6693 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sunchokes
1966
+ 6585 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Sweet Potatoes
1967
+ 6692 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Tamarillos
1968
+ 6704 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Taro Root
1969
+ 6703 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Tomatoes
1970
+ 505329 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Turnips & Rutabagas
1971
+ 499905 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Vegetable Mixes
1972
+ 6701 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Water Chestnuts
1973
+ 6700 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Watercress
1974
+ 7193 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Wheatgrass
1975
+ 8515 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Yams
1976
+ 6705 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fresh & Frozen Vegetables > Yuca Root
1977
+ 5794 - Food, Beverages & Tobacco > Food Items > Fruits & Vegetables > Fruit Sauces
1978
+ 431 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal
1979
+ 4683 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Amaranth
1980
+ 4687 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Barley
1981
+ 4684 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Buckwheat
1982
+ 4689 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Cereal & Granola
1983
+ 7196 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Couscous
1984
+ 4686 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Millet
1985
+ 4690 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Oats, Grits & Hot Cereal
1986
+ 6259 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Quinoa
1987
+ 4682 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Rice
1988
+ 7374 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Rye
1989
+ 4688 - Food, Beverages & Tobacco > Food Items > Grains, Rice & Cereal > Wheat
1990
+ 432 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs
1991
+ 4627 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs
1992
+ 543554 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs > Egg Whites
1993
+ 543555 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs > Liquid & Frozen Eggs
1994
+ 543556 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs > Prepared Eggs
1995
+ 543557 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Eggs > Whole Eggs
1996
+ 4628 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat
1997
+ 5811 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Canned Meats
1998
+ 5805 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Fresh & Frozen Meats
1999
+ 5804 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Meat > Lunch & Deli Meats
2000
+ 4629 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood
2001
+ 5813 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood > Canned Seafood
2002
+ 5812 - Food, Beverages & Tobacco > Food Items > Meat, Seafood & Eggs > Seafood > Fresh & Frozen Seafood
2003
+ 433 - Food, Beverages & Tobacco > Food Items > Nuts & Seeds
2004
+ 434 - Food, Beverages & Tobacco > Food Items > Pasta & Noodles
2005
+ 5814 - Food, Beverages & Tobacco > Food Items > Prepared Foods
2006
+ 499989 - Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Appetizers & Side Dishes
2007
+ 499988 - Food, Beverages & Tobacco > Food Items > Prepared Foods > Prepared Meals & Entrées
2008
+ 4608 - Food, Beverages & Tobacco > Food Items > Seasonings & Spices
2009
+ 1529 - Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Herbs & Spices
2010
+ 4610 - Food, Beverages & Tobacco > Food Items > Seasonings & Spices > MSG
2011
+ 6199 - Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Pepper
2012
+ 4611 - Food, Beverages & Tobacco > Food Items > Seasonings & Spices > Salt
2013
+ 423 - Food, Beverages & Tobacco > Food Items > Snack Foods
2014
+ 7159 - Food, Beverages & Tobacco > Food Items > Snack Foods > Breadsticks
2015
+ 5747 - Food, Beverages & Tobacco > Food Items > Snack Foods > Cereal & Granola Bars
2016
+ 543651 - Food, Beverages & Tobacco > Food Items > Snack Foods > Cereal & Granola Bars > Cereal Bars
2017
+ 543652 - Food, Beverages & Tobacco > Food Items > Snack Foods > Cereal & Granola Bars > Granola Bars
2018
+ 6192 - Food, Beverages & Tobacco > Food Items > Snack Foods > Cheese Puffs
2019
+ 2392 - Food, Beverages & Tobacco > Food Items > Snack Foods > Chips
2020
+ 1445 - Food, Beverages & Tobacco > Food Items > Snack Foods > Crackers
2021
+ 5746 - Food, Beverages & Tobacco > Food Items > Snack Foods > Croutons
2022
+ 5744 - Food, Beverages & Tobacco > Food Items > Snack Foods > Fruit Snacks
2023
+ 3284 - Food, Beverages & Tobacco > Food Items > Snack Foods > Jerky
2024
+ 1534 - Food, Beverages & Tobacco > Food Items > Snack Foods > Popcorn
2025
+ 6194 - Food, Beverages & Tobacco > Food Items > Snack Foods > Pork Rinds
2026
+ 3446 - Food, Beverages & Tobacco > Food Items > Snack Foods > Pretzels
2027
+ 5743 - Food, Beverages & Tobacco > Food Items > Snack Foods > Pudding & Gelatin Snacks
2028
+ 2432 - Food, Beverages & Tobacco > Food Items > Snack Foods > Puffed Rice Cakes
2029
+ 6847 - Food, Beverages & Tobacco > Food Items > Snack Foods > Salad Toppings
2030
+ 7427 - Food, Beverages & Tobacco > Food Items > Snack Foods > Sesame Sticks
2031
+ 6785 - Food, Beverages & Tobacco > Food Items > Snack Foods > Snack Cakes
2032
+ 7327 - Food, Beverages & Tobacco > Food Items > Snack Foods > Sticky Rice Cakes
2033
+ 5745 - Food, Beverages & Tobacco > Food Items > Snack Foods > Trail & Snack Mixes
2034
+ 2423 - Food, Beverages & Tobacco > Food Items > Soups & Broths
2035
+ 5807 - Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products
2036
+ 6839 - Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Cheese Alternatives
2037
+ 6843 - Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Meat Alternatives
2038
+ 5808 - Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Seitan
2039
+ 5810 - Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Tempeh
2040
+ 5809 - Food, Beverages & Tobacco > Food Items > Tofu, Soy & Vegetarian Products > Tofu
2041
+ 435 - Food, Beverages & Tobacco > Tobacco Products
2042
+ 3916 - Food, Beverages & Tobacco > Tobacco Products > Chewing Tobacco
2043
+ 3151 - Food, Beverages & Tobacco > Tobacco Products > Cigarettes
2044
+ 3682 - Food, Beverages & Tobacco > Tobacco Products > Cigars
2045
+ 3741 - Food, Beverages & Tobacco > Tobacco Products > Loose Tobacco
2046
+ 499963 - Food, Beverages & Tobacco > Tobacco Products > Smoking Pipes
2047
+ 4091 - Food, Beverages & Tobacco > Tobacco Products > Vaporizers & Electronic Cigarettes
2048
+ 543635 - Food, Beverages & Tobacco > Tobacco Products > Vaporizers & Electronic Cigarettes > Electronic Cigarettes
2049
+ 543634 - Food, Beverages & Tobacco > Tobacco Products > Vaporizers & Electronic Cigarettes > Vaporizers
2050
+ 436 - Furniture
2051
+ 554 - Furniture > Baby & Toddler Furniture
2052
+ 6349 - Furniture > Baby & Toddler Furniture > Baby & Toddler Furniture Sets
2053
+ 7068 - Furniture > Baby & Toddler Furniture > Bassinet & Cradle Accessories
2054
+ 6393 - Furniture > Baby & Toddler Furniture > Bassinets & Cradles
2055
+ 558 - Furniture > Baby & Toddler Furniture > Changing Tables
2056
+ 7070 - Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories
2057
+ 7072 - Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories > Crib Bumpers & Liners
2058
+ 7071 - Furniture > Baby & Toddler Furniture > Crib & Toddler Bed Accessories > Crib Conversion Kits
2059
+ 6394 - Furniture > Baby & Toddler Furniture > Cribs & Toddler Beds
2060
+ 6969 - Furniture > Baby & Toddler Furniture > High Chair & Booster Seat Accessories
2061
+ 559 - Furniture > Baby & Toddler Furniture > High Chairs & Booster Seats
2062
+ 6433 - Furniture > Beds & Accessories
2063
+ 4437 - Furniture > Beds & Accessories > Bed & Bed Frame Accessories
2064
+ 505764 - Furniture > Beds & Accessories > Beds & Bed Frames
2065
+ 451 - Furniture > Beds & Accessories > Headboards & Footboards
2066
+ 2720 - Furniture > Beds & Accessories > Mattress Foundations
2067
+ 2696 - Furniture > Beds & Accessories > Mattresses
2068
+ 441 - Furniture > Benches
2069
+ 6850 - Furniture > Benches > Kitchen & Dining Benches
2070
+ 6851 - Furniture > Benches > Storage & Entryway Benches
2071
+ 4241 - Furniture > Benches > Vanity Benches
2072
+ 6356 - Furniture > Cabinets & Storage
2073
+ 4063 - Furniture > Cabinets & Storage > Armoires & Wardrobes
2074
+ 447 - Furniture > Cabinets & Storage > Buffets & Sideboards
2075
+ 448 - Furniture > Cabinets & Storage > China Cabinets & Hutches
2076
+ 4195 - Furniture > Cabinets & Storage > Dressers
2077
+ 463 - Furniture > Cabinets & Storage > File Cabinets
2078
+ 465846 - Furniture > Cabinets & Storage > Ironing Centers
2079
+ 6934 - Furniture > Cabinets & Storage > Kitchen Cabinets
2080
+ 6539 - Furniture > Cabinets & Storage > Magazine Racks
2081
+ 6358 - Furniture > Cabinets & Storage > Media Storage Cabinets & Racks
2082
+ 5938 - Furniture > Cabinets & Storage > Storage Cabinets & Lockers
2083
+ 4205 - Furniture > Cabinets & Storage > Storage Chests
2084
+ 6947 - Furniture > Cabinets & Storage > Storage Chests > Hope Chests
2085
+ 4268 - Furniture > Cabinets & Storage > Storage Chests > Toy Chests
2086
+ 4148 - Furniture > Cabinets & Storage > Vanities
2087
+ 2081 - Furniture > Cabinets & Storage > Vanities > Bathroom Vanities
2088
+ 6360 - Furniture > Cabinets & Storage > Vanities > Bedroom Vanities
2089
+ 6357 - Furniture > Cabinets & Storage > Wine & Liquor Cabinets
2090
+ 5578 - Furniture > Cabinets & Storage > Wine Racks
2091
+ 442 - Furniture > Carts & Islands
2092
+ 453 - Furniture > Carts & Islands > Kitchen & Dining Carts
2093
+ 6374 - Furniture > Carts & Islands > Kitchen Islands
2094
+ 7248 - Furniture > Chair Accessories
2095
+ 8206 - Furniture > Chair Accessories > Hanging Chair Replacement Parts
2096
+ 443 - Furniture > Chairs
2097
+ 6499 - Furniture > Chairs > Arm Chairs, Recliners & Sleeper Chairs
2098
+ 438 - Furniture > Chairs > Bean Bag Chairs
2099
+ 456 - Furniture > Chairs > Chaises
2100
+ 2919 - Furniture > Chairs > Electric Massaging Chairs
2101
+ 500051 - Furniture > Chairs > Floor Chairs
2102
+ 3358 - Furniture > Chairs > Folding Chairs & Stools
2103
+ 6800 - Furniture > Chairs > Gaming Chairs
2104
+ 7197 - Furniture > Chairs > Hanging Chairs
2105
+ 5886 - Furniture > Chairs > Kitchen & Dining Room Chairs
2106
+ 2002 - Furniture > Chairs > Rocking Chairs
2107
+ 6859 - Furniture > Chairs > Slipper Chairs
2108
+ 1463 - Furniture > Chairs > Table & Bar Stools
2109
+ 457 - Furniture > Entertainment Centers & TV Stands
2110
+ 6345 - Furniture > Furniture Sets
2111
+ 500000 - Furniture > Furniture Sets > Bathroom Furniture Sets
2112
+ 6346 - Furniture > Furniture Sets > Bedroom Furniture Sets
2113
+ 6347 - Furniture > Furniture Sets > Kitchen & Dining Furniture Sets
2114
+ 6348 - Furniture > Furniture Sets > Living Room Furniture Sets
2115
+ 6860 - Furniture > Futon Frames
2116
+ 2786 - Furniture > Futon Pads
2117
+ 450 - Furniture > Futons
2118
+ 6362 - Furniture > Office Furniture
2119
+ 4191 - Furniture > Office Furniture > Desks
2120
+ 2045 - Furniture > Office Furniture > Office Chairs
2121
+ 500061 - Furniture > Office Furniture > Office Furniture Sets
2122
+ 6363 - Furniture > Office Furniture > Workspace Tables
2123
+ 2242 - Furniture > Office Furniture > Workspace Tables > Art & Drafting Tables
2124
+ 4317 - Furniture > Office Furniture > Workspace Tables > Conference Room Tables
2125
+ 6908 - Furniture > Office Furniture > Workstations & Cubicles
2126
+ 503765 - Furniture > Office Furniture Accessories
2127
+ 503766 - Furniture > Office Furniture Accessories > Desk Parts & Accessories
2128
+ 7559 - Furniture > Office Furniture Accessories > Office Chair Accessories
2129
+ 6909 - Furniture > Office Furniture Accessories > Workstation & Cubicle Accessories
2130
+ 458 - Furniture > Ottomans
2131
+ 4299 - Furniture > Outdoor Furniture
2132
+ 6892 - Furniture > Outdoor Furniture > Outdoor Beds
2133
+ 6367 - Furniture > Outdoor Furniture > Outdoor Furniture Sets
2134
+ 6822 - Furniture > Outdoor Furniture > Outdoor Ottomans
2135
+ 6368 - Furniture > Outdoor Furniture > Outdoor Seating
2136
+ 5044 - Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Benches
2137
+ 6828 - Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Chairs
2138
+ 500111 - Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Sectional Sofa Units
2139
+ 4513 - Furniture > Outdoor Furniture > Outdoor Seating > Outdoor Sofas
2140
+ 4105 - Furniture > Outdoor Furniture > Outdoor Seating > Sunloungers
2141
+ 7310 - Furniture > Outdoor Furniture > Outdoor Storage Boxes
2142
+ 2684 - Furniture > Outdoor Furniture > Outdoor Tables
2143
+ 6963 - Furniture > Outdoor Furniture Accessories
2144
+ 6964 - Furniture > Outdoor Furniture Accessories > Outdoor Furniture Covers
2145
+ 6915 - Furniture > Room Divider Accessories
2146
+ 4163 - Furniture > Room Dividers
2147
+ 464 - Furniture > Shelving
2148
+ 465 - Furniture > Shelving > Bookcases & Standing Shelves
2149
+ 6372 - Furniture > Shelving > Wall Shelves & Ledges
2150
+ 8023 - Furniture > Shelving Accessories
2151
+ 8024 - Furniture > Shelving Accessories > Replacement Shelves
2152
+ 7212 - Furniture > Sofa Accessories
2153
+ 7213 - Furniture > Sofa Accessories > Chair & Sofa Supports
2154
+ 500064 - Furniture > Sofa Accessories > Sectional Sofa Units
2155
+ 460 - Furniture > Sofas
2156
+ 6913 - Furniture > Table Accessories
2157
+ 6911 - Furniture > Table Accessories > Table Legs
2158
+ 6910 - Furniture > Table Accessories > Table Tops
2159
+ 6392 - Furniture > Tables
2160
+ 6369 - Furniture > Tables > Accent Tables
2161
+ 1395 - Furniture > Tables > Accent Tables > Coffee Tables
2162
+ 1549 - Furniture > Tables > Accent Tables > End Tables
2163
+ 1602 - Furniture > Tables > Accent Tables > Sofa Tables
2164
+ 6351 - Furniture > Tables > Activity Tables
2165
+ 4080 - Furniture > Tables > Folding Tables
2166
+ 4355 - Furniture > Tables > Kitchen & Dining Room Tables
2167
+ 4484 - Furniture > Tables > Kotatsu
2168
+ 462 - Furniture > Tables > Nightstands
2169
+ 2693 - Furniture > Tables > Poker & Game Tables
2170
+ 5121 - Furniture > Tables > Sewing Machine Tables
2171
+ 632 - Hardware
2172
+ 503739 - Hardware > Building Consumables
2173
+ 2277 - Hardware > Building Consumables > Chemicals
2174
+ 1735 - Hardware > Building Consumables > Chemicals > Acid Neutralizers
2175
+ 6795 - Hardware > Building Consumables > Chemicals > Ammonia
2176
+ 1479 - Hardware > Building Consumables > Chemicals > Chimney Cleaners
2177
+ 7504 - Hardware > Building Consumables > Chemicals > Concrete & Masonry Cleaners
2178
+ 6191 - Hardware > Building Consumables > Chemicals > De-icers
2179
+ 7503 - Hardware > Building Consumables > Chemicals > Deck & Fence Cleaners
2180
+ 1749 - Hardware > Building Consumables > Chemicals > Drain Cleaners
2181
+ 505319 - Hardware > Building Consumables > Chemicals > Electrical Freeze Sprays
2182
+ 500088 - Hardware > Building Consumables > Chemicals > Lighter Fluid
2183
+ 7470 - Hardware > Building Consumables > Chemicals > Septic Tank & Cesspool Treatments
2184
+ 503742 - Hardware > Building Consumables > Hardware Glue & Adhesives
2185
+ 2212 - Hardware > Building Consumables > Hardware Tape
2186
+ 1753 - Hardware > Building Consumables > Lubricants
2187
+ 503743 - Hardware > Building Consumables > Masonry Consumables
2188
+ 3031 - Hardware > Building Consumables > Masonry Consumables > Bricks & Concrete Blocks
2189
+ 2282 - Hardware > Building Consumables > Masonry Consumables > Cement, Mortar & Concrete Mixes
2190
+ 499876 - Hardware > Building Consumables > Masonry Consumables > Grout
2191
+ 503740 - Hardware > Building Consumables > Painting Consumables
2192
+ 1361 - Hardware > Building Consumables > Painting Consumables > Paint
2193
+ 2474 - Hardware > Building Consumables > Painting Consumables > Paint Binders
2194
+ 2058 - Hardware > Building Consumables > Painting Consumables > Primers
2195
+ 1648 - Hardware > Building Consumables > Painting Consumables > Stains
2196
+ 503738 - Hardware > Building Consumables > Painting Consumables > Varnishes & Finishes
2197
+ 505305 - Hardware > Building Consumables > Plumbing Primer
2198
+ 503744 - Hardware > Building Consumables > Protective Coatings & Sealants
2199
+ 1995 - Hardware > Building Consumables > Solder & Flux
2200
+ 503741 - Hardware > Building Consumables > Solvents, Strippers & Thinners
2201
+ 505802 - Hardware > Building Consumables > Wall Patching Compounds & Plaster
2202
+ 115 - Hardware > Building Materials
2203
+ 2729 - Hardware > Building Materials > Countertops
2204
+ 6343 - Hardware > Building Materials > Door Hardware
2205
+ 2972 - Hardware > Building Materials > Door Hardware > Door Bells & Chimes
2206
+ 6446 - Hardware > Building Materials > Door Hardware > Door Closers
2207
+ 503727 - Hardware > Building Materials > Door Hardware > Door Frames
2208
+ 99338 - Hardware > Building Materials > Door Hardware > Door Keyhole Escutcheons
2209
+ 1356 - Hardware > Building Materials > Door Hardware > Door Knobs & Handles
2210
+ 2795 - Hardware > Building Materials > Door Hardware > Door Knockers
2211
+ 499970 - Hardware > Building Materials > Door Hardware > Door Push Plates
2212
+ 2665 - Hardware > Building Materials > Door Hardware > Door Stops
2213
+ 6458 - Hardware > Building Materials > Door Hardware > Door Strikes
2214
+ 119 - Hardware > Building Materials > Doors
2215
+ 4468 - Hardware > Building Materials > Doors > Garage Doors
2216
+ 4634 - Hardware > Building Materials > Doors > Home Doors
2217
+ 503776 - Hardware > Building Materials > Drywall
2218
+ 2826 - Hardware > Building Materials > Flooring & Carpet
2219
+ 120 - Hardware > Building Materials > Glass
2220
+ 499949 - Hardware > Building Materials > Handrails & Railing Systems
2221
+ 2030 - Hardware > Building Materials > Hatches
2222
+ 122 - Hardware > Building Materials > Insulation
2223
+ 125 - Hardware > Building Materials > Lumber & Sheet Stock
2224
+ 7112 - Hardware > Building Materials > Molding
2225
+ 503777 - Hardware > Building Materials > Rebar & Remesh
2226
+ 123 - Hardware > Building Materials > Roofing
2227
+ 4544 - Hardware > Building Materials > Roofing > Gutter Accessories
2228
+ 121 - Hardware > Building Materials > Roofing > Gutters
2229
+ 2008 - Hardware > Building Materials > Roofing > Roof Flashings
2230
+ 8270 - Hardware > Building Materials > Roofing > Roofing Shingles & Tiles
2231
+ 6943 - Hardware > Building Materials > Shutters
2232
+ 503775 - Hardware > Building Materials > Siding
2233
+ 7439 - Hardware > Building Materials > Sound Dampening Panels & Foam
2234
+ 7004 - Hardware > Building Materials > Staircases
2235
+ 7136 - Hardware > Building Materials > Wall & Ceiling Tile
2236
+ 7053 - Hardware > Building Materials > Wall Paneling
2237
+ 505300 - Hardware > Building Materials > Weather Stripping & Weatherization Supplies
2238
+ 499772 - Hardware > Building Materials > Window Hardware
2239
+ 499773 - Hardware > Building Materials > Window Hardware > Window Cranks
2240
+ 503728 - Hardware > Building Materials > Window Hardware > Window Frames
2241
+ 124 - Hardware > Building Materials > Windows
2242
+ 128 - Hardware > Fencing & Barriers
2243
+ 502983 - Hardware > Fencing & Barriers > Fence & Gate Accessories
2244
+ 502973 - Hardware > Fencing & Barriers > Fence Panels
2245
+ 1352 - Hardware > Fencing & Barriers > Fence Pickets
2246
+ 1919 - Hardware > Fencing & Barriers > Fence Posts & Rails
2247
+ 502986 - Hardware > Fencing & Barriers > Garden Borders & Edging
2248
+ 1788 - Hardware > Fencing & Barriers > Gates
2249
+ 502984 - Hardware > Fencing & Barriers > Lattice
2250
+ 499958 - Hardware > Fencing & Barriers > Safety & Crowd Control Barriers
2251
+ 543575 - Hardware > Fuel
2252
+ 543703 - Hardware > Fuel > Home Heating Oil
2253
+ 543576 - Hardware > Fuel > Kerosene
2254
+ 543579 - Hardware > Fuel > Kerosene > Clear Kerosene
2255
+ 543578 - Hardware > Fuel > Kerosene > Dyed Kerosene
2256
+ 543577 - Hardware > Fuel > Propane
2257
+ 502975 - Hardware > Fuel Containers & Tanks
2258
+ 2878 - Hardware > Hardware Accessories
2259
+ 7092 - Hardware > Hardware Accessories > Brackets & Reinforcement Braces
2260
+ 4696 - Hardware > Hardware Accessories > Cabinet Hardware
2261
+ 232167 - Hardware > Hardware Accessories > Cabinet Hardware > Cabinet & Furniture Keyhole Escutcheons
2262
+ 4697 - Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Backplates
2263
+ 4698 - Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Catches
2264
+ 4699 - Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Doors
2265
+ 4700 - Hardware > Hardware Accessories > Cabinet Hardware > Cabinet Knobs & Handles
2266
+ 499981 - Hardware > Hardware Accessories > Casters
2267
+ 502977 - Hardware > Hardware Accessories > Chain, Wire & Rope
2268
+ 6298 - Hardware > Hardware Accessories > Chain, Wire & Rope > Bungee Cords
2269
+ 1492 - Hardware > Hardware Accessories > Chain, Wire & Rope > Chains
2270
+ 4469 - Hardware > Hardware Accessories > Chain, Wire & Rope > Pull Chains
2271
+ 3053 - Hardware > Hardware Accessories > Chain, Wire & Rope > Ropes & Hardware Cable
2272
+ 6297 - Hardware > Hardware Accessories > Chain, Wire & Rope > Tie Down Straps
2273
+ 5119 - Hardware > Hardware Accessories > Chain, Wire & Rope > Twine
2274
+ 6904 - Hardware > Hardware Accessories > Chain, Wire & Rope > Utility Wire
2275
+ 1318 - Hardware > Hardware Accessories > Coils
2276
+ 7086 - Hardware > Hardware Accessories > Concrete Molds
2277
+ 7270 - Hardware > Hardware Accessories > Dowel Pins & Rods
2278
+ 8470 - Hardware > Hardware Accessories > Drawer Slides
2279
+ 1979 - Hardware > Hardware Accessories > Drop Cloths
2280
+ 1816 - Hardware > Hardware Accessories > Filters & Screens
2281
+ 7557 - Hardware > Hardware Accessories > Flagging & Caution Tape
2282
+ 6841 - Hardware > Hardware Accessories > Gas Hoses
2283
+ 8112 - Hardware > Hardware Accessories > Ground Spikes
2284
+ 500054 - Hardware > Hardware Accessories > Hardware Fasteners
2285
+ 1508 - Hardware > Hardware Accessories > Hardware Fasteners > Drywall Anchors
2286
+ 2408 - Hardware > Hardware Accessories > Hardware Fasteners > Nails
2287
+ 1739 - Hardware > Hardware Accessories > Hardware Fasteners > Nuts & Bolts
2288
+ 7062 - Hardware > Hardware Accessories > Hardware Fasteners > Rivets
2289
+ 2230 - Hardware > Hardware Accessories > Hardware Fasteners > Screw Posts
2290
+ 2251 - Hardware > Hardware Accessories > Hardware Fasteners > Screws
2291
+ 500055 - Hardware > Hardware Accessories > Hardware Fasteners > Threaded Rods
2292
+ 2195 - Hardware > Hardware Accessories > Hardware Fasteners > Washers
2293
+ 1771 - Hardware > Hardware Accessories > Hinges
2294
+ 503773 - Hardware > Hardware Accessories > Hooks, Buckles & Fasteners
2295
+ 503764 - Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Chain Connectors & Links
2296
+ 502978 - Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Gear Ties
2297
+ 503770 - Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Lifting Hooks, Clamps & Shackles
2298
+ 502992 - Hardware > Hardware Accessories > Hooks, Buckles & Fasteners > Utility Buckles
2299
+ 6770 - Hardware > Hardware Accessories > Lubrication Hoses
2300
+ 503731 - Hardware > Hardware Accessories > Metal Casting Molds
2301
+ 500030 - Hardware > Hardware Accessories > Moving & Soundproofing Blankets & Covers
2302
+ 6769 - Hardware > Hardware Accessories > Pneumatic Hoses
2303
+ 8113 - Hardware > Hardware Accessories > Post Base Plates
2304
+ 499933 - Hardware > Hardware Accessories > Springs
2305
+ 4988 - Hardware > Hardware Accessories > Tarps
2306
+ 3974 - Hardware > Hardware Accessories > Tool Storage & Organization
2307
+ 4199 - Hardware > Hardware Accessories > Tool Storage & Organization > Garden Hose Storage
2308
+ 2485 - Hardware > Hardware Accessories > Tool Storage & Organization > Tool & Equipment Belts
2309
+ 6876 - Hardware > Hardware Accessories > Tool Storage & Organization > Tool Bags
2310
+ 3980 - Hardware > Hardware Accessories > Tool Storage & Organization > Tool Boxes
2311
+ 3280 - Hardware > Hardware Accessories > Tool Storage & Organization > Tool Cabinets & Chests
2312
+ 500103 - Hardware > Hardware Accessories > Tool Storage & Organization > Tool Organizer Liners & Inserts
2313
+ 4031 - Hardware > Hardware Accessories > Tool Storage & Organization > Tool Sheaths
2314
+ 3919 - Hardware > Hardware Accessories > Tool Storage & Organization > Work Benches
2315
+ 505320 - Hardware > Hardware Accessories > Wall Jacks & Braces
2316
+ 500096 - Hardware > Hardware Pumps
2317
+ 500099 - Hardware > Hardware Pumps > Home Appliance Pumps
2318
+ 500098 - Hardware > Hardware Pumps > Pool, Fountain & Pond Pumps
2319
+ 500097 - Hardware > Hardware Pumps > Sprinkler, Booster & Irrigation System Pumps
2320
+ 500102 - Hardware > Hardware Pumps > Sump, Sewage & Effluent Pumps
2321
+ 500101 - Hardware > Hardware Pumps > Utility Pumps
2322
+ 500100 - Hardware > Hardware Pumps > Well Pumps & Systems
2323
+ 499873 - Hardware > Heating, Ventilation & Air Conditioning
2324
+ 500090 - Hardware > Heating, Ventilation & Air Conditioning > Air & Filter Dryers
2325
+ 499874 - Hardware > Heating, Ventilation & Air Conditioning > Air Ducts
2326
+ 1519 - Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls
2327
+ 2238 - Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls > Control Panels
2328
+ 500043 - Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls > Humidistats
2329
+ 1897 - Hardware > Heating, Ventilation & Air Conditioning > HVAC Controls > Thermostats
2330
+ 2766 - Hardware > Heating, Ventilation & Air Conditioning > Vents & Flues
2331
+ 1974 - Hardware > Locks & Keys
2332
+ 6488 - Hardware > Locks & Keys > Key Blanks
2333
+ 8067 - Hardware > Locks & Keys > Key Caps
2334
+ 1870 - Hardware > Locks & Keys > Key Card Entry Systems
2335
+ 503730 - Hardware > Locks & Keys > Locks & Latches
2336
+ 133 - Hardware > Plumbing
2337
+ 1810 - Hardware > Plumbing > Plumbing Fittings & Supports
2338
+ 6732 - Hardware > Plumbing > Plumbing Fittings & Supports > Gaskets & O-Rings
2339
+ 499697 - Hardware > Plumbing > Plumbing Fittings & Supports > In-Wall Carriers & Mounting Frames
2340
+ 2068 - Hardware > Plumbing > Plumbing Fittings & Supports > Nozzles
2341
+ 2710 - Hardware > Plumbing > Plumbing Fittings & Supports > Pipe Adapters & Bushings
2342
+ 2909 - Hardware > Plumbing > Plumbing Fittings & Supports > Pipe Caps & Plugs
2343
+ 2359 - Hardware > Plumbing > Plumbing Fittings & Supports > Pipe Connectors
2344
+ 1694 - Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Flanges
2345
+ 2634 - Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Pipe Clamps
2346
+ 2611 - Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Regulators
2347
+ 2466 - Hardware > Plumbing > Plumbing Fittings & Supports > Plumbing Valves
2348
+ 504635 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts
2349
+ 2996 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories
2350
+ 505368 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories > Bathtub Bases & Feet
2351
+ 5508 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories > Bathtub Skirts
2352
+ 2463 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Bathtub Accessories > Bathtub Spouts
2353
+ 504637 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components
2354
+ 2851 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Covers & Strainers
2355
+ 1514 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Frames
2356
+ 2257 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Liners
2357
+ 1932 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Openers
2358
+ 1407 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Drain Rods
2359
+ 1319 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Plumbing Traps
2360
+ 2170 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drain Components > Plumbing Wastes
2361
+ 504636 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Drains
2362
+ 1489 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Faucet Accessories
2363
+ 8115 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Faucet Accessories > Faucet Aerators
2364
+ 8116 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Faucet Accessories > Faucet Handles & Controls
2365
+ 1458 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Fixture Plates
2366
+ 2206 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts
2367
+ 8320 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Bathtub & Shower Jets
2368
+ 8277 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Electric & Power Showers
2369
+ 504638 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Arms & Connectors
2370
+ 4728 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Bases
2371
+ 2088 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Columns
2372
+ 1779 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Doors & Enclosures
2373
+ 581 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Heads
2374
+ 7130 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Walls & Surrounds
2375
+ 5048 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Shower Parts > Shower Water Filters
2376
+ 1963 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Sink Accessories
2377
+ 2410 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Sink Accessories > Sink Legs
2378
+ 2691 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories
2379
+ 1425 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Ballcocks & Flappers
2380
+ 504634 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Bidet Faucets & Sprayers
2381
+ 1865 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet & Bidet Seats
2382
+ 7358 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Seat Covers
2383
+ 7446 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Seat Lid Covers
2384
+ 5666 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Tank Covers
2385
+ 2817 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Tank Levers
2386
+ 5665 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Tanks
2387
+ 2478 - Hardware > Plumbing > Plumbing Fixture Hardware & Parts > Toilet & Bidet Accessories > Toilet Trim
2388
+ 1673 - Hardware > Plumbing > Plumbing Fixtures
2389
+ 499999 - Hardware > Plumbing > Plumbing Fixtures > Bathroom Suites
2390
+ 1636 - Hardware > Plumbing > Plumbing Fixtures > Bathtubs
2391
+ 2032 - Hardware > Plumbing > Plumbing Fixtures > Faucets
2392
+ 7244 - Hardware > Plumbing > Plumbing Fixtures > Shower Stalls & Kits
2393
+ 1687 - Hardware > Plumbing > Plumbing Fixtures > Sinks
2394
+ 2886 - Hardware > Plumbing > Plumbing Fixtures > Sinks > Bathroom Sinks
2395
+ 2757 - Hardware > Plumbing > Plumbing Fixtures > Sinks > Kitchen & Utility Sinks
2396
+ 2062 - Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets
2397
+ 2376 - Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Bidets
2398
+ 1921 - Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Toilets
2399
+ 1746 - Hardware > Plumbing > Plumbing Fixtures > Toilets & Bidets > Urinals
2400
+ 2570 - Hardware > Plumbing > Plumbing Hoses & Supply Lines
2401
+ 2216 - Hardware > Plumbing > Plumbing Pipes
2402
+ 2203 - Hardware > Plumbing > Plumbing Repair Kits
2403
+ 2273 - Hardware > Plumbing > Water Dispensing & Filtration
2404
+ 2055 - Hardware > Plumbing > Water Dispensing & Filtration > In-Line Water Filters
2405
+ 2343 - Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers
2406
+ 1821 - Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers > Drinking Fountains
2407
+ 1354 - Hardware > Plumbing > Water Dispensing & Filtration > Water Dispensers > Water Chillers
2408
+ 1390 - Hardware > Plumbing > Water Dispensing & Filtration > Water Distillers
2409
+ 2171 - Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories
2410
+ 2063 - Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories > Water Filter Cartridges
2411
+ 2406 - Hardware > Plumbing > Water Dispensing & Filtration > Water Filtration Accessories > Water Filter Housings
2412
+ 5646 - Hardware > Plumbing > Water Dispensing & Filtration > Water Softener Salt
2413
+ 1952 - Hardware > Plumbing > Water Dispensing & Filtration > Water Softeners
2414
+ 2243 - Hardware > Plumbing > Water Levelers
2415
+ 6832 - Hardware > Plumbing > Water Timers
2416
+ 1723 - Hardware > Plumbing > Well Supplies
2417
+ 127 - Hardware > Power & Electrical Supplies
2418
+ 500049 - Hardware > Power & Electrical Supplies > Armatures, Rotors & Stators
2419
+ 7183 - Hardware > Power & Electrical Supplies > Ballasts & Starters
2420
+ 499893 - Hardware > Power & Electrical Supplies > Carbon Brushes
2421
+ 6807 - Hardware > Power & Electrical Supplies > Circuit Breaker Panels
2422
+ 499768 - Hardware > Power & Electrical Supplies > Conduit & Housings
2423
+ 499770 - Hardware > Power & Electrical Supplies > Conduit & Housings > Electrical Conduit
2424
+ 3797 - Hardware > Power & Electrical Supplies > Conduit & Housings > Heat-Shrink Tubing
2425
+ 7275 - Hardware > Power & Electrical Supplies > Electrical Motors
2426
+ 2006 - Hardware > Power & Electrical Supplies > Electrical Mount Boxes & Brackets
2427
+ 5627 - Hardware > Power & Electrical Supplies > Electrical Plug Caps
2428
+ 6459 - Hardware > Power & Electrical Supplies > Electrical Switches
2429
+ 1935 - Hardware > Power & Electrical Supplies > Electrical Switches > Light Switches
2430
+ 499932 - Hardware > Power & Electrical Supplies > Electrical Switches > Specialty Electrical Switches & Relays
2431
+ 2345 - Hardware > Power & Electrical Supplies > Electrical Wires & Cable
2432
+ 6375 - Hardware > Power & Electrical Supplies > Extension Cord Accessories
2433
+ 4789 - Hardware > Power & Electrical Supplies > Extension Cords
2434
+ 4709 - Hardware > Power & Electrical Supplies > Generator Accessories
2435
+ 1218 - Hardware > Power & Electrical Supplies > Generators
2436
+ 2413 - Hardware > Power & Electrical Supplies > Home Automation Kits
2437
+ 2028 - Hardware > Power & Electrical Supplies > Phone & Data Jacks
2438
+ 5533 - Hardware > Power & Electrical Supplies > Power Converters
2439
+ 499966 - Hardware > Power & Electrical Supplies > Power Inlets
2440
+ 5142 - Hardware > Power & Electrical Supplies > Power Inverters
2441
+ 1869 - Hardware > Power & Electrical Supplies > Power Outlets & Sockets
2442
+ 4715 - Hardware > Power & Electrical Supplies > Solar Energy Kits
2443
+ 4714 - Hardware > Power & Electrical Supplies > Solar Panels
2444
+ 505318 - Hardware > Power & Electrical Supplies > Voltage Transformers & Regulators
2445
+ 2377 - Hardware > Power & Electrical Supplies > Wall Plates & Covers
2446
+ 6833 - Hardware > Power & Electrical Supplies > Wall Socket Controls & Sensors
2447
+ 2274 - Hardware > Power & Electrical Supplies > Wire Caps & Nuts
2448
+ 503729 - Hardware > Power & Electrical Supplies > Wire Terminals & Connectors
2449
+ 499982 - Hardware > Small Engines
2450
+ 1910 - Hardware > Storage Tanks
2451
+ 3650 - Hardware > Tool Accessories
2452
+ 6939 - Hardware > Tool Accessories > Abrasive Blaster Accessories
2453
+ 6940 - Hardware > Tool Accessories > Abrasive Blaster Accessories > Sandblasting Cabinets
2454
+ 7326 - Hardware > Tool Accessories > Axe Accessories
2455
+ 7370 - Hardware > Tool Accessories > Axe Accessories > Axe Handles
2456
+ 7369 - Hardware > Tool Accessories > Axe Accessories > Axe Heads
2457
+ 8117 - Hardware > Tool Accessories > Cutter Accessories
2458
+ 8118 - Hardware > Tool Accessories > Cutter Accessories > Nibbler Dies
2459
+ 3944 - Hardware > Tool Accessories > Drill & Screwdriver Accessories
2460
+ 1540 - Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill & Screwdriver Bits
2461
+ 7140 - Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Bit Extensions
2462
+ 6378 - Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Bit Sharpeners
2463
+ 8276 - Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Chucks
2464
+ 8275 - Hardware > Tool Accessories > Drill & Screwdriver Accessories > Drill Stands & Guides
2465
+ 6806 - Hardware > Tool Accessories > Drill & Screwdriver Accessories > Hole Saws
2466
+ 6471 - Hardware > Tool Accessories > Driver Accessories
2467
+ 2447 - Hardware > Tool Accessories > Flashlight Accessories
2468
+ 499859 - Hardware > Tool Accessories > Grinder Accessories
2469
+ 499860 - Hardware > Tool Accessories > Grinder Accessories > Grinding Wheels & Points
2470
+ 7056 - Hardware > Tool Accessories > Hammer Accessories
2471
+ 7087 - Hardware > Tool Accessories > Hammer Accessories > Air Hammer Accessories
2472
+ 7055 - Hardware > Tool Accessories > Hammer Accessories > Hammer Handles
2473
+ 7057 - Hardware > Tool Accessories > Hammer Accessories > Hammer Heads
2474
+ 2380 - Hardware > Tool Accessories > Industrial Staples
2475
+ 6907 - Hardware > Tool Accessories > Jigs
2476
+ 7472 - Hardware > Tool Accessories > Magnetizers & Demagnetizers
2477
+ 505323 - Hardware > Tool Accessories > Mattock & Pickaxe Accessories
2478
+ 505324 - Hardware > Tool Accessories > Mattock & Pickaxe Accessories > Mattock & Pickaxe Handles
2479
+ 5526 - Hardware > Tool Accessories > Measuring Tool & Sensor Accessories
2480
+ 5557 - Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Electrical Testing Tool Accessories
2481
+ 5556 - Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Gas Detector Accessories
2482
+ 503007 - Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Measuring Scale Accessories
2483
+ 7415 - Hardware > Tool Accessories > Measuring Tool & Sensor Accessories > Multimeter Accessories
2484
+ 499886 - Hardware > Tool Accessories > Mixing Tool Paddles
2485
+ 7019 - Hardware > Tool Accessories > Paint Tool Accessories
2486
+ 6887 - Hardware > Tool Accessories > Paint Tool Accessories > Airbrush Accessories
2487
+ 328062 - Hardware > Tool Accessories > Paint Tool Accessories > Paint Brush Cleaning Solutions
2488
+ 7020 - Hardware > Tool Accessories > Paint Tool Accessories > Paint Roller Accessories
2489
+ 6295 - Hardware > Tool Accessories > Power Tool Batteries
2490
+ 6292 - Hardware > Tool Accessories > Power Tool Chargers
2491
+ 3744 - Hardware > Tool Accessories > Router Accessories
2492
+ 3673 - Hardware > Tool Accessories > Router Accessories > Router Bits
2493
+ 3300 - Hardware > Tool Accessories > Router Accessories > Router Tables
2494
+ 4487 - Hardware > Tool Accessories > Sanding Accessories
2495
+ 3240 - Hardware > Tool Accessories > Sanding Accessories > Sandpaper & Sanding Sponges
2496
+ 6549 - Hardware > Tool Accessories > Saw Accessories
2497
+ 7515 - Hardware > Tool Accessories > Saw Accessories > Band Saw Accessories
2498
+ 7345 - Hardware > Tool Accessories > Saw Accessories > Handheld Circular Saw Accessories
2499
+ 7346 - Hardware > Tool Accessories > Saw Accessories > Jigsaw Accessories
2500
+ 6503 - Hardware > Tool Accessories > Saw Accessories > Miter Saw Accessories
2501
+ 6501 - Hardware > Tool Accessories > Saw Accessories > Table Saw Accessories
2502
+ 3470 - Hardware > Tool Accessories > Shaper Accessories
2503
+ 3210 - Hardware > Tool Accessories > Shaper Accessories > Shaper Cutters
2504
+ 3281 - Hardware > Tool Accessories > Soldering Iron Accessories
2505
+ 3629 - Hardware > Tool Accessories > Soldering Iron Accessories > Soldering Iron Stands
2506
+ 3609 - Hardware > Tool Accessories > Soldering Iron Accessories > Soldering Iron Tips
2507
+ 2174 - Hardware > Tool Accessories > Tool Blades
2508
+ 505831 - Hardware > Tool Accessories > Tool Blades > Cutter & Scraper Blades
2509
+ 2202 - Hardware > Tool Accessories > Tool Blades > Saw Blades
2510
+ 505810 - Hardware > Tool Accessories > Tool Handle Wedges
2511
+ 8258 - Hardware > Tool Accessories > Tool Safety Tethers
2512
+ 5571 - Hardware > Tool Accessories > Tool Sockets
2513
+ 4658 - Hardware > Tool Accessories > Tool Stands
2514
+ 4659 - Hardware > Tool Accessories > Tool Stands > Saw Stands
2515
+ 505812 - Hardware > Tool Accessories > Wedge Tools
2516
+ 499947 - Hardware > Tool Accessories > Welding Accessories
2517
+ 1167 - Hardware > Tools
2518
+ 6938 - Hardware > Tools > Abrasive Blasters
2519
+ 1169 - Hardware > Tools > Anvils
2520
+ 1171 - Hardware > Tools > Axes
2521
+ 7271 - Hardware > Tools > Carpentry Jointers
2522
+ 1174 - Hardware > Tools > Carving Chisels & Gouges
2523
+ 1215 - Hardware > Tools > Caulking Tools
2524
+ 2792 - Hardware > Tools > Chimney Brushes
2525
+ 4325 - Hardware > Tools > Compactors
2526
+ 2015 - Hardware > Tools > Compressors
2527
+ 4672 - Hardware > Tools > Concrete Brooms
2528
+ 1180 - Hardware > Tools > Cutters
2529
+ 1181 - Hardware > Tools > Cutters > Bolt Cutters
2530
+ 1182 - Hardware > Tools > Cutters > Glass Cutters
2531
+ 1454 - Hardware > Tools > Cutters > Handheld Metal Shears & Nibblers
2532
+ 7562 - Hardware > Tools > Cutters > Nippers
2533
+ 2080 - Hardware > Tools > Cutters > Pipe Cutters
2534
+ 1824 - Hardware > Tools > Cutters > Rebar Cutters
2535
+ 2726 - Hardware > Tools > Cutters > Tile & Shingle Cutters
2536
+ 2411 - Hardware > Tools > Cutters > Utility Knives
2537
+ 1391 - Hardware > Tools > Deburrers
2538
+ 126 - Hardware > Tools > Dollies & Hand Trucks
2539
+ 1217 - Hardware > Tools > Drills
2540
+ 1367 - Hardware > Tools > Drills > Augers
2541
+ 1216 - Hardware > Tools > Drills > Drill Presses
2542
+ 2629 - Hardware > Tools > Drills > Handheld Power Drills
2543
+ 1465 - Hardware > Tools > Drills > Mortisers
2544
+ 1994 - Hardware > Tools > Drills > Pneumatic Drills
2545
+ 6461 - Hardware > Tools > Electrician Fish Tape
2546
+ 338 - Hardware > Tools > Flashlights & Headlamps
2547
+ 543689 - Hardware > Tools > Flashlights & Headlamps > Flashlights
2548
+ 2454 - Hardware > Tools > Flashlights & Headlamps > Headlamps
2549
+ 7556 - Hardware > Tools > Grease Guns
2550
+ 1219 - Hardware > Tools > Grinders
2551
+ 1185 - Hardware > Tools > Grips
2552
+ 1186 - Hardware > Tools > Hammers
2553
+ 2208 - Hardware > Tools > Hammers > Manual Hammers
2554
+ 505364 - Hardware > Tools > Hammers > Powered Hammers
2555
+ 499887 - Hardware > Tools > Handheld Power Mixers
2556
+ 5927 - Hardware > Tools > Hardware Torches
2557
+ 1220 - Hardware > Tools > Heat Guns
2558
+ 1221 - Hardware > Tools > Impact Wrenches & Drivers
2559
+ 2456 - Hardware > Tools > Industrial Vibrators
2560
+ 7416 - Hardware > Tools > Inspection Mirrors
2561
+ 130 - Hardware > Tools > Ladders & Scaffolding
2562
+ 2416 - Hardware > Tools > Ladders & Scaffolding > Ladder Carts
2563
+ 6928 - Hardware > Tools > Ladders & Scaffolding > Ladders
2564
+ 1866 - Hardware > Tools > Ladders & Scaffolding > Scaffolding
2565
+ 635 - Hardware > Tools > Ladders & Scaffolding > Step Stools
2566
+ 1809 - Hardware > Tools > Ladders & Scaffolding > Work Platforms
2567
+ 1663 - Hardware > Tools > Lathes
2568
+ 1603 - Hardware > Tools > Light Bulb Changers
2569
+ 503774 - Hardware > Tools > Lighters & Matches
2570
+ 7030 - Hardware > Tools > Log Splitters
2571
+ 5873 - Hardware > Tools > Magnetic Sweepers
2572
+ 1832 - Hardware > Tools > Marking Tools
2573
+ 1193 - Hardware > Tools > Masonry Tools
2574
+ 1668 - Hardware > Tools > Masonry Tools > Brick Tools
2575
+ 2305 - Hardware > Tools > Masonry Tools > Cement Mixers
2576
+ 1555 - Hardware > Tools > Masonry Tools > Construction Lines
2577
+ 2337 - Hardware > Tools > Masonry Tools > Floats
2578
+ 7484 - Hardware > Tools > Masonry Tools > Grout Sponges
2579
+ 1799 - Hardware > Tools > Masonry Tools > Masonry Edgers & Groovers
2580
+ 1450 - Hardware > Tools > Masonry Tools > Masonry Jointers
2581
+ 2181 - Hardware > Tools > Masonry Tools > Masonry Trowels
2582
+ 4132 - Hardware > Tools > Masonry Tools > Power Trowels
2583
+ 3932 - Hardware > Tools > Mattocks & Pickaxes
2584
+ 1305 - Hardware > Tools > Measuring Tools & Sensors
2585
+ 5515 - Hardware > Tools > Measuring Tools & Sensors > Air Quality Meters
2586
+ 4022 - Hardware > Tools > Measuring Tools & Sensors > Altimeters
2587
+ 500058 - Hardware > Tools > Measuring Tools & Sensors > Anemometers
2588
+ 3602 - Hardware > Tools > Measuring Tools & Sensors > Barometers
2589
+ 2192 - Hardware > Tools > Measuring Tools & Sensors > Calipers
2590
+ 1533 - Hardware > Tools > Measuring Tools & Sensors > Cruising Rods
2591
+ 5487 - Hardware > Tools > Measuring Tools & Sensors > Distance Meters
2592
+ 1850 - Hardware > Tools > Measuring Tools & Sensors > Dividers
2593
+ 503737 - Hardware > Tools > Measuring Tools & Sensors > Electrical Testing Tools
2594
+ 1640 - Hardware > Tools > Measuring Tools & Sensors > Flow Meters & Controllers
2595
+ 1991 - Hardware > Tools > Measuring Tools & Sensors > Gas Detectors
2596
+ 1732 - Hardware > Tools > Measuring Tools & Sensors > Gauges
2597
+ 5371 - Hardware > Tools > Measuring Tools & Sensors > Geiger Counters
2598
+ 4754 - Hardware > Tools > Measuring Tools & Sensors > Hygrometers
2599
+ 4506 - Hardware > Tools > Measuring Tools & Sensors > Infrared Thermometers
2600
+ 2330 - Hardware > Tools > Measuring Tools & Sensors > Knife Guides
2601
+ 1191 - Hardware > Tools > Measuring Tools & Sensors > Levels
2602
+ 4081 - Hardware > Tools > Measuring Tools & Sensors > Levels > Bubble Levels
2603
+ 4931 - Hardware > Tools > Measuring Tools & Sensors > Levels > Laser Levels
2604
+ 4294 - Hardware > Tools > Measuring Tools & Sensors > Levels > Sight Levels
2605
+ 1698 - Hardware > Tools > Measuring Tools & Sensors > Measuring Scales
2606
+ 1459 - Hardware > Tools > Measuring Tools & Sensors > Measuring Wheels
2607
+ 4755 - Hardware > Tools > Measuring Tools & Sensors > Moisture Meters
2608
+ 1785 - Hardware > Tools > Measuring Tools & Sensors > Probes & Finders
2609
+ 1198 - Hardware > Tools > Measuring Tools & Sensors > Protractors
2610
+ 1539 - Hardware > Tools > Measuring Tools & Sensors > Rebar Locators
2611
+ 2021 - Hardware > Tools > Measuring Tools & Sensors > Rulers
2612
+ 4756 - Hardware > Tools > Measuring Tools & Sensors > Seismometer
2613
+ 4757 - Hardware > Tools > Measuring Tools & Sensors > Sound Meters
2614
+ 1205 - Hardware > Tools > Measuring Tools & Sensors > Squares
2615
+ 1413 - Hardware > Tools > Measuring Tools & Sensors > Straight Edges
2616
+ 1207 - Hardware > Tools > Measuring Tools & Sensors > Stud Sensors
2617
+ 2481 - Hardware > Tools > Measuring Tools & Sensors > Tape Measures
2618
+ 4340 - Hardware > Tools > Measuring Tools & Sensors > Theodolites
2619
+ 6799 - Hardware > Tools > Measuring Tools & Sensors > Thermal Imaging Cameras
2620
+ 2093 - Hardware > Tools > Measuring Tools & Sensors > Thermocouples & Thermopiles
2621
+ 7394 - Hardware > Tools > Measuring Tools & Sensors > Transducers
2622
+ 4758 - Hardware > Tools > Measuring Tools & Sensors > UV Light Meters
2623
+ 4759 - Hardware > Tools > Measuring Tools & Sensors > Vibration Meters
2624
+ 1374 - Hardware > Tools > Measuring Tools & Sensors > Weather Forecasters & Stations
2625
+ 4074 - Hardware > Tools > Measuring Tools & Sensors > pH Meters
2626
+ 5077 - Hardware > Tools > Milling Machines
2627
+ 5587 - Hardware > Tools > Multifunction Power Tools
2628
+ 1194 - Hardware > Tools > Nail Pullers
2629
+ 1206 - Hardware > Tools > Nailers & Staplers
2630
+ 5828 - Hardware > Tools > Oil Filter Drains
2631
+ 2077 - Hardware > Tools > Paint Tools
2632
+ 2486 - Hardware > Tools > Paint Tools > Airbrushes
2633
+ 1300 - Hardware > Tools > Paint Tools > Paint Brushes
2634
+ 6556 - Hardware > Tools > Paint Tools > Paint Edgers
2635
+ 1774 - Hardware > Tools > Paint Tools > Paint Rollers
2636
+ 499888 - Hardware > Tools > Paint Tools > Paint Shakers
2637
+ 1699 - Hardware > Tools > Paint Tools > Paint Sponges
2638
+ 2465 - Hardware > Tools > Paint Tools > Paint Sprayers
2639
+ 505325 - Hardware > Tools > Paint Tools > Paint Strainers
2640
+ 6557 - Hardware > Tools > Paint Tools > Paint Trays
2641
+ 1196 - Hardware > Tools > Pickup Tools
2642
+ 1667 - Hardware > Tools > Pipe & Bar Benders
2643
+ 2053 - Hardware > Tools > Pipe & Tube Cleaners
2644
+ 1862 - Hardware > Tools > Pipe Brushes
2645
+ 6868 - Hardware > Tools > Planers
2646
+ 1187 - Hardware > Tools > Planes
2647
+ 1958 - Hardware > Tools > Pliers
2648
+ 1563 - Hardware > Tools > Plungers
2649
+ 1225 - Hardware > Tools > Polishers & Buffers
2650
+ 3501 - Hardware > Tools > Post Hole Diggers
2651
+ 1179 - Hardware > Tools > Pry Bars
2652
+ 505315 - Hardware > Tools > Punches & Awls
2653
+ 1202 - Hardware > Tools > Putty Knives & Scrapers
2654
+ 1819 - Hardware > Tools > Reamers
2655
+ 7064 - Hardware > Tools > Riveting Tools
2656
+ 7065 - Hardware > Tools > Riveting Tools > Rivet Guns
2657
+ 7066 - Hardware > Tools > Riveting Tools > Rivet Pliers
2658
+ 1841 - Hardware > Tools > Routing Tools
2659
+ 1188 - Hardware > Tools > Sanders
2660
+ 4419 - Hardware > Tools > Sanding Blocks
2661
+ 1201 - Hardware > Tools > Saw Horses
2662
+ 1235 - Hardware > Tools > Saws
2663
+ 3582 - Hardware > Tools > Saws > Band Saws
2664
+ 3516 - Hardware > Tools > Saws > Cut-Off Saws
2665
+ 3594 - Hardware > Tools > Saws > Hand Saws
2666
+ 3224 - Hardware > Tools > Saws > Handheld Circular Saws
2667
+ 3725 - Hardware > Tools > Saws > Jigsaws
2668
+ 7077 - Hardware > Tools > Saws > Masonry & Tile Saws
2669
+ 3517 - Hardware > Tools > Saws > Miter Saws
2670
+ 499985 - Hardware > Tools > Saws > Panel Saws
2671
+ 3494 - Hardware > Tools > Saws > Reciprocating Saws
2672
+ 4633 - Hardware > Tools > Saws > Scroll Saws
2673
+ 3706 - Hardware > Tools > Saws > Table Saws
2674
+ 1203 - Hardware > Tools > Screwdrivers
2675
+ 1923 - Hardware > Tools > Shapers
2676
+ 1644 - Hardware > Tools > Sharpeners
2677
+ 1195 - Hardware > Tools > Socket Drivers
2678
+ 1236 - Hardware > Tools > Soldering Irons
2679
+ 1787 - Hardware > Tools > Tap Reseaters
2680
+ 1184 - Hardware > Tools > Taps & Dies
2681
+ 1584 - Hardware > Tools > Threading Machines
2682
+ 2835 - Hardware > Tools > Tool Clamps & Vises
2683
+ 3745 - Hardware > Tools > Tool Files
2684
+ 1439 - Hardware > Tools > Tool Keys
2685
+ 2198 - Hardware > Tools > Tool Knives
2686
+ 4919 - Hardware > Tools > Tool Sets
2687
+ 6965 - Hardware > Tools > Tool Sets > Hand Tool Sets
2688
+ 4716 - Hardware > Tools > Tool Sets > Power Tool Combo Sets
2689
+ 1238 - Hardware > Tools > Welding Guns & Plasma Cutters
2690
+ 1469 - Hardware > Tools > Wire & Cable Hand Tools
2691
+ 5592 - Hardware > Tools > Work Lights
2692
+ 1632 - Hardware > Tools > Wrenches
2693
+ 469 - Health & Beauty
2694
+ 491 - Health & Beauty > Health Care
2695
+ 5849 - Health & Beauty > Health Care > Acupuncture
2696
+ 5850 - Health & Beauty > Health Care > Acupuncture > Acupuncture Models
2697
+ 5851 - Health & Beauty > Health Care > Acupuncture > Acupuncture Needles
2698
+ 7220 - Health & Beauty > Health Care > Bed Pans
2699
+ 5071 - Health & Beauty > Health Care > Biometric Monitor Accessories
2700
+ 505819 - Health & Beauty > Health Care > Biometric Monitor Accessories > Activity Monitor Accessories
2701
+ 3688 - Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories
2702
+ 6323 - Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Blood Glucose Control Solution
2703
+ 3905 - Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Blood Glucose Test Strips
2704
+ 3111 - Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Glucose Meter Accessories > Lancing Devices
2705
+ 6284 - Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Pressure Monitor Accessories
2706
+ 6285 - Health & Beauty > Health Care > Biometric Monitor Accessories > Blood Pressure Monitor Accessories > Blood Pressure Monitor Cuffs
2707
+ 5072 - Health & Beauty > Health Care > Biometric Monitor Accessories > Body Weight Scale Accessories
2708
+ 494 - Health & Beauty > Health Care > Biometric Monitors
2709
+ 500009 - Health & Beauty > Health Care > Biometric Monitors > Activity Monitors
2710
+ 2246 - Health & Beauty > Health Care > Biometric Monitors > Blood Glucose Meters
2711
+ 495 - Health & Beauty > Health Care > Biometric Monitors > Blood Pressure Monitors
2712
+ 496 - Health & Beauty > Health Care > Biometric Monitors > Body Fat Analyzers
2713
+ 500 - Health & Beauty > Health Care > Biometric Monitors > Body Weight Scales
2714
+ 2633 - Health & Beauty > Health Care > Biometric Monitors > Breathalyzers
2715
+ 497 - Health & Beauty > Health Care > Biometric Monitors > Cholesterol Analyzers
2716
+ 505822 - Health & Beauty > Health Care > Biometric Monitors > Fertility Monitors and Ovulation Tests
2717
+ 543679 - Health & Beauty > Health Care > Biometric Monitors > Fertility Monitors and Ovulation Tests > Fertility Tests & Monitors
2718
+ 543680 - Health & Beauty > Health Care > Biometric Monitors > Fertility Monitors and Ovulation Tests > Ovulation Tests
2719
+ 501 - Health & Beauty > Health Care > Biometric Monitors > Medical Thermometers
2720
+ 4767 - Health & Beauty > Health Care > Biometric Monitors > Prenatal Heart Rate Monitors
2721
+ 5551 - Health & Beauty > Health Care > Biometric Monitors > Pulse Oximeters
2722
+ 775 - Health & Beauty > Health Care > Condoms
2723
+ 505820 - Health & Beauty > Health Care > Conductivity Gels & Lotions
2724
+ 7002 - Health & Beauty > Health Care > Contraceptive Cases
2725
+ 508 - Health & Beauty > Health Care > First Aid
2726
+ 2954 - Health & Beauty > Health Care > First Aid > Antiseptics & Cleaning Supplies
2727
+ 6206 - Health & Beauty > Health Care > First Aid > Cast & Bandage Protectors
2728
+ 4527 - Health & Beauty > Health Care > First Aid > Eye Wash Supplies
2729
+ 510 - Health & Beauty > Health Care > First Aid > First Aid Kits
2730
+ 516 - Health & Beauty > Health Care > First Aid > Hot & Cold Therapies
2731
+ 5848 - Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Heat Rubs
2732
+ 6205 - Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Heating Pads
2733
+ 4753 - Health & Beauty > Health Care > First Aid > Hot & Cold Therapies > Ice Packs
2734
+ 509 - Health & Beauty > Health Care > First Aid > Medical Tape & Bandages
2735
+ 2890 - Health & Beauty > Health Care > Fitness & Nutrition
2736
+ 2984 - Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Bars
2737
+ 5702 - Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Drinks & Shakes
2738
+ 6242 - Health & Beauty > Health Care > Fitness & Nutrition > Nutrition Gels & Chews
2739
+ 6871 - Health & Beauty > Health Care > Fitness & Nutrition > Nutritional Food Purées
2740
+ 7413 - Health & Beauty > Health Care > Fitness & Nutrition > Tube Feeding Supplements
2741
+ 525 - Health & Beauty > Health Care > Fitness & Nutrition > Vitamins & Supplements
2742
+ 5690 - Health & Beauty > Health Care > Hearing Aids
2743
+ 517 - Health & Beauty > Health Care > Incontinence Aids
2744
+ 500087 - Health & Beauty > Health Care > Light Therapy Lamps
2745
+ 5966 - Health & Beauty > Health Care > Medical Alarm Systems
2746
+ 5965 - Health & Beauty > Health Care > Medical Identification Tags & Jewelry
2747
+ 505293 - Health & Beauty > Health Care > Medical Tests
2748
+ 499934 - Health & Beauty > Health Care > Medical Tests > Allergy Test Kits
2749
+ 7337 - Health & Beauty > Health Care > Medical Tests > Blood Typing Test Kits
2750
+ 2552 - Health & Beauty > Health Care > Medical Tests > Drug Tests
2751
+ 7336 - Health & Beauty > Health Care > Medical Tests > HIV Tests
2752
+ 1680 - Health & Beauty > Health Care > Medical Tests > Pregnancy Tests
2753
+ 505294 - Health & Beauty > Health Care > Medical Tests > Urinary Tract Infection Tests
2754
+ 518 - Health & Beauty > Health Care > Medicine & Drugs
2755
+ 519 - Health & Beauty > Health Care > Mobility & Accessibility
2756
+ 520 - Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment
2757
+ 3512 - Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Mobility Scooters
2758
+ 7138 - Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Stair Lifts
2759
+ 502969 - Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Transfer Boards & Sheets
2760
+ 3364 - Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment > Wheelchairs
2761
+ 521 - Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Equipment Accessories
2762
+ 5488 - Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Furniture & Fixtures
2763
+ 7243 - Health & Beauty > Health Care > Mobility & Accessibility > Accessibility Furniture & Fixtures > Shower Benches & Seats
2764
+ 6929 - Health & Beauty > Health Care > Mobility & Accessibility > Walking Aid Accessories
2765
+ 5164 - Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids
2766
+ 5165 - Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Canes & Walking Sticks
2767
+ 4248 - Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Crutches
2768
+ 5166 - Health & Beauty > Health Care > Mobility & Accessibility > Walking Aids > Walkers
2769
+ 5870 - Health & Beauty > Health Care > Occupational & Physical Therapy Equipment
2770
+ 8541 - Health & Beauty > Health Care > Occupational & Physical Therapy Equipment > Electrical Muscle Stimulators
2771
+ 505352 - Health & Beauty > Health Care > Occupational & Physical Therapy Equipment > Therapeutic Swings
2772
+ 3777 - Health & Beauty > Health Care > Pillboxes
2773
+ 4551 - Health & Beauty > Health Care > Respiratory Care
2774
+ 4552 - Health & Beauty > Health Care > Respiratory Care > Nebulizers
2775
+ 499692 - Health & Beauty > Health Care > Respiratory Care > Oxygen Tanks
2776
+ 7317 - Health & Beauty > Health Care > Respiratory Care > PAP Machines
2777
+ 7316 - Health & Beauty > Health Care > Respiratory Care > PAP Masks
2778
+ 505669 - Health & Beauty > Health Care > Respiratory Care > Steam Inhalers
2779
+ 8082 - Health & Beauty > Health Care > Specimen Cups
2780
+ 7186 - Health & Beauty > Health Care > Spermicides
2781
+ 8105 - Health & Beauty > Health Care > Stump Shrinkers
2782
+ 523 - Health & Beauty > Health Care > Supports & Braces
2783
+ 5923 - Health & Beauty > Health Care > Surgical Lubricants
2784
+ 5573 - Health & Beauty > Jewelry Cleaning & Care
2785
+ 499919 - Health & Beauty > Jewelry Cleaning & Care > Jewelry Cleaning Solutions & Polishes
2786
+ 500082 - Health & Beauty > Jewelry Cleaning & Care > Jewelry Cleaning Tools
2787
+ 5974 - Health & Beauty > Jewelry Cleaning & Care > Jewelry Holders
2788
+ 500083 - Health & Beauty > Jewelry Cleaning & Care > Jewelry Steam Cleaners
2789
+ 5124 - Health & Beauty > Jewelry Cleaning & Care > Watch Repair Kits
2790
+ 2915 - Health & Beauty > Personal Care
2791
+ 493 - Health & Beauty > Personal Care > Back Care
2792
+ 7404 - Health & Beauty > Personal Care > Back Care > Back & Lumbar Support Cushions
2793
+ 473 - Health & Beauty > Personal Care > Cosmetics
2794
+ 474 - Health & Beauty > Personal Care > Cosmetics > Bath & Body
2795
+ 499913 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Adult Hygienic Wipes
2796
+ 2503 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bar Soap
2797
+ 2522 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Additives
2798
+ 2876 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Brushes
2799
+ 2875 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Bath Sponges & Loofahs
2800
+ 2747 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Body Wash
2801
+ 3691 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Hand Sanitizers & Wipes
2802
+ 3208 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Liquid Hand Soap
2803
+ 7417 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Powdered Hand Soap
2804
+ 4049 - Health & Beauty > Personal Care > Cosmetics > Bath & Body > Shower Caps
2805
+ 475 - Health & Beauty > Personal Care > Cosmetics > Bath & Body Gift Sets
2806
+ 6069 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Sets
2807
+ 6331 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tool Cleansers
2808
+ 2619 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools
2809
+ 2548 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools
2810
+ 7356 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Double Eyelid Glue & Tape
2811
+ 6555 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyebrow Stencils
2812
+ 6282 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyelash Curler Refills
2813
+ 2780 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Eyelash Curlers
2814
+ 476 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Face Mirrors
2815
+ 4121 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Facial Blotting Paper
2816
+ 502996 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories
2817
+ 7256 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories > False Eyelash Adhesive
2818
+ 7493 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories > False Eyelash Applicators
2819
+ 502997 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > False Eyelash Accessories > False Eyelash Remover
2820
+ 3025 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Makeup Brushes
2821
+ 4106 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Makeup Sponges
2822
+ 499822 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Makeup Tools > Refillable Makeup Palettes & Cases
2823
+ 2975 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools
2824
+ 2739 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Cuticle Pushers
2825
+ 3037 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Cuticle Scissors
2826
+ 7494 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Manicure & Pedicure Spacers
2827
+ 6300 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Manicure Tool Sets
2828
+ 6341 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Buffers
2829
+ 2828 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Clippers
2830
+ 499698 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Drill Accessories
2831
+ 7490 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Drills
2832
+ 5880 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Dryers
2833
+ 2734 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Nail Tools > Nail Files & Emery Boards
2834
+ 2958 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools
2835
+ 6760 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Facial Saunas
2836
+ 7190 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Foot Files
2837
+ 499926 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Lotion & Sunscreen Applicators
2838
+ 2511 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Pumice Stones
2839
+ 6261 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Care Extractors
2840
+ 7018 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Care Rollers
2841
+ 8132 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Cleansing Brush Heads
2842
+ 6260 - Health & Beauty > Personal Care > Cosmetics > Cosmetic Tools > Skin Care Tools > Skin Cleansing Brushes & Systems
2843
+ 477 - Health & Beauty > Personal Care > Cosmetics > Makeup
2844
+ 5978 - Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup
2845
+ 5981 - Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup > Body & Hair Glitter
2846
+ 5979 - Health & Beauty > Personal Care > Cosmetics > Makeup > Body Makeup > Body Paint & Foundation
2847
+ 4779 - Health & Beauty > Personal Care > Cosmetics > Makeup > Costume & Stage Makeup
2848
+ 2779 - Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup
2849
+ 8220 - Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eye Primer
2850
+ 2904 - Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eye Shadow
2851
+ 2686 - Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eyebrow Enhancers
2852
+ 2807 - Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Eyeliner
2853
+ 2761 - Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > False Eyelashes
2854
+ 6340 - Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Lash & Brow Growth Treatments
2855
+ 2834 - Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Mascara
2856
+ 8219 - Health & Beauty > Personal Care > Cosmetics > Makeup > Eye Makeup > Mascara Primer
2857
+ 2571 - Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup
2858
+ 6305 - Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Blushes & Bronzers
2859
+ 2980 - Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Face Powder
2860
+ 8218 - Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Face Primer
2861
+ 2765 - Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Foundations & Concealers
2862
+ 6304 - Health & Beauty > Personal Care > Cosmetics > Makeup > Face Makeup > Highlighters & Luminizers
2863
+ 2645 - Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup
2864
+ 6306 - Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip & Cheek Stains
2865
+ 2858 - Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Gloss
2866
+ 2589 - Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Liner
2867
+ 8217 - Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lip Primer
2868
+ 3021 - Health & Beauty > Personal Care > Cosmetics > Makeup > Lip Makeup > Lipstick
2869
+ 6072 - Health & Beauty > Personal Care > Cosmetics > Makeup > Makeup Finishing Sprays
2870
+ 3509 - Health & Beauty > Personal Care > Cosmetics > Makeup > Temporary Tattoos
2871
+ 478 - Health & Beauty > Personal Care > Cosmetics > Nail Care
2872
+ 3009 - Health & Beauty > Personal Care > Cosmetics > Nail Care > Cuticle Cream & Oil
2873
+ 4218 - Health & Beauty > Personal Care > Cosmetics > Nail Care > False Nails
2874
+ 6893 - Health & Beauty > Personal Care > Cosmetics > Nail Care > Manicure Glue
2875
+ 5975 - Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Art Kits & Accessories
2876
+ 233419 - Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Drying Drops & Sprays
2877
+ 2946 - Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Removers
2878
+ 7445 - Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polish Thinners
2879
+ 2683 - Health & Beauty > Personal Care > Cosmetics > Nail Care > Nail Polishes
2880
+ 479 - Health & Beauty > Personal Care > Cosmetics > Perfume & Cologne
2881
+ 567 - Health & Beauty > Personal Care > Cosmetics > Skin Care
2882
+ 481 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Acne Treatments & Kits
2883
+ 7429 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Anti-Aging Skin Care Kits
2884
+ 6104 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Body Oil
2885
+ 5980 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Body Powder
2886
+ 8029 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Compressed Skin Care Mask Sheets
2887
+ 2526 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Cleansers
2888
+ 7467 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Cleansing Kits
2889
+ 6791 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Facial Pore Strips
2890
+ 482 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Lip Balms & Treatments
2891
+ 543573 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Lip Balms & Treatments > Lip Balms
2892
+ 543574 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Lip Balms & Treatments > Medicated Lip Treatments
2893
+ 2592 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Lotion & Moisturizer
2894
+ 6034 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Makeup Removers
2895
+ 6753 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Petroleum Jelly
2896
+ 6262 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Skin Care Masks & Peels
2897
+ 5820 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Skin Insect Repellent
2898
+ 2844 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Sunscreen
2899
+ 2740 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products
2900
+ 5338 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products > Self Tanner
2901
+ 5339 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Tanning Products > Tanning Oil & Lotion
2902
+ 5976 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Toners & Astringents
2903
+ 543659 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Toners & Astringents > Astringents
2904
+ 543658 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Toners & Astringents > Toners
2905
+ 6863 - Health & Beauty > Personal Care > Cosmetics > Skin Care > Wart Removers
2906
+ 4929 - Health & Beauty > Personal Care > Cotton Balls
2907
+ 2934 - Health & Beauty > Personal Care > Cotton Swabs
2908
+ 484 - Health & Beauty > Personal Care > Deodorant & Anti-Perspirant
2909
+ 543599 - Health & Beauty > Personal Care > Deodorant & Anti-Perspirant > Anti-Perspirant
2910
+ 543598 - Health & Beauty > Personal Care > Deodorant & Anti-Perspirant > Deodorant
2911
+ 506 - Health & Beauty > Personal Care > Ear Care
2912
+ 5706 - Health & Beauty > Personal Care > Ear Care > Ear Candles
2913
+ 6559 - Health & Beauty > Personal Care > Ear Care > Ear Drops
2914
+ 6560 - Health & Beauty > Personal Care > Ear Care > Ear Dryers
2915
+ 500024 - Health & Beauty > Personal Care > Ear Care > Ear Picks & Spoons
2916
+ 6561 - Health & Beauty > Personal Care > Ear Care > Ear Syringes
2917
+ 6562 - Health & Beauty > Personal Care > Ear Care > Ear Wax Removal Kits
2918
+ 7542 - Health & Beauty > Personal Care > Ear Care > Earplug Dispensers
2919
+ 2596 - Health & Beauty > Personal Care > Ear Care > Earplugs
2920
+ 7134 - Health & Beauty > Personal Care > Enema Kits & Supplies
2921
+ 485 - Health & Beauty > Personal Care > Feminine Sanitary Supplies
2922
+ 6862 - Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Deodorant
2923
+ 5821 - Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Douches & Creams
2924
+ 2387 - Health & Beauty > Personal Care > Feminine Sanitary Supplies > Feminine Pads & Protectors
2925
+ 8122 - Health & Beauty > Personal Care > Feminine Sanitary Supplies > Menstrual Cups
2926
+ 2564 - Health & Beauty > Personal Care > Feminine Sanitary Supplies > Tampons
2927
+ 515 - Health & Beauty > Personal Care > Foot Care
2928
+ 2992 - Health & Beauty > Personal Care > Foot Care > Bunion Care Supplies
2929
+ 3022 - Health & Beauty > Personal Care > Foot Care > Corn & Callus Care Supplies
2930
+ 3049 - Health & Beauty > Personal Care > Foot Care > Foot Odor Removers
2931
+ 2801 - Health & Beauty > Personal Care > Foot Care > Insoles & Inserts
2932
+ 7495 - Health & Beauty > Personal Care > Foot Care > Toe Spacers
2933
+ 486 - Health & Beauty > Personal Care > Hair Care
2934
+ 8452 - Health & Beauty > Personal Care > Hair Care > Hair Care Kits
2935
+ 2814 - Health & Beauty > Personal Care > Hair Care > Hair Color
2936
+ 6053 - Health & Beauty > Personal Care > Hair Care > Hair Color Removers
2937
+ 5977 - Health & Beauty > Personal Care > Hair Care > Hair Coloring Accessories
2938
+ 6099 - Health & Beauty > Personal Care > Hair Care > Hair Loss Concealers
2939
+ 4766 - Health & Beauty > Personal Care > Hair Care > Hair Loss Treatments
2940
+ 6052 - Health & Beauty > Personal Care > Hair Care > Hair Permanents & Straighteners
2941
+ 3013 - Health & Beauty > Personal Care > Hair Care > Hair Shears
2942
+ 6429 - Health & Beauty > Personal Care > Hair Care > Hair Steamers & Heat Caps
2943
+ 1901 - Health & Beauty > Personal Care > Hair Care > Hair Styling Products
2944
+ 6018 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories
2945
+ 5317 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Curler Clips & Pins
2946
+ 4475 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Dryer Accessories
2947
+ 4569 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tool Accessories > Hair Iron Accessories
2948
+ 6019 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tools
2949
+ 487 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Combs & Brushes
2950
+ 489 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Curling Irons
2951
+ 488 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Curlers
2952
+ 490 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Dryers
2953
+ 3407 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Straighteners
2954
+ 499992 - Health & Beauty > Personal Care > Hair Care > Hair Styling Tools > Hair Styling Tool Sets
2955
+ 2441 - Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner
2956
+ 543616 - Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner > Conditioners
2957
+ 543615 - Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner > Shampoo
2958
+ 543617 - Health & Beauty > Personal Care > Hair Care > Shampoo & Conditioner > Shampoo & Conditioner Sets
2959
+ 5663 - Health & Beauty > Personal Care > Massage & Relaxation
2960
+ 500060 - Health & Beauty > Personal Care > Massage & Relaxation > Back Scratchers
2961
+ 233420 - Health & Beauty > Personal Care > Massage & Relaxation > Eye Pillows
2962
+ 1442 - Health & Beauty > Personal Care > Massage & Relaxation > Massage Chairs
2963
+ 5664 - Health & Beauty > Personal Care > Massage & Relaxation > Massage Oil
2964
+ 8530 - Health & Beauty > Personal Care > Massage & Relaxation > Massage Stone Warmers
2965
+ 8135 - Health & Beauty > Personal Care > Massage & Relaxation > Massage Stones
2966
+ 2074 - Health & Beauty > Personal Care > Massage & Relaxation > Massage Tables
2967
+ 471 - Health & Beauty > Personal Care > Massage & Relaxation > Massagers
2968
+ 543596 - Health & Beauty > Personal Care > Massage & Relaxation > Massagers > Electric Massagers
2969
+ 543597 - Health & Beauty > Personal Care > Massage & Relaxation > Massagers > Manual Massage Tools
2970
+ 543595 - Health & Beauty > Personal Care > Massage & Relaxation > Massagers > Massage Cushions
2971
+ 526 - Health & Beauty > Personal Care > Oral Care
2972
+ 6189 - Health & Beauty > Personal Care > Oral Care > Breath Spray
2973
+ 2620 - Health & Beauty > Personal Care > Oral Care > Dental Floss
2974
+ 5823 - Health & Beauty > Personal Care > Oral Care > Dental Mouthguards
2975
+ 6455 - Health & Beauty > Personal Care > Oral Care > Dental Water Jet Replacement Tips
2976
+ 5295 - Health & Beauty > Personal Care > Oral Care > Dental Water Jets
2977
+ 5155 - Health & Beauty > Personal Care > Oral Care > Denture Adhesives
2978
+ 5824 - Health & Beauty > Personal Care > Oral Care > Denture Cleaners
2979
+ 8543 - Health & Beauty > Personal Care > Oral Care > Denture Repair Kits
2980
+ 2527 - Health & Beauty > Personal Care > Oral Care > Dentures
2981
+ 2769 - Health & Beauty > Personal Care > Oral Care > Gum Stimulators
2982
+ 3040 - Health & Beauty > Personal Care > Oral Care > Mouthwash
2983
+ 505367 - Health & Beauty > Personal Care > Oral Care > Orthodontic Appliance Cases
2984
+ 6715 - Health & Beauty > Personal Care > Oral Care > Power Flossers
2985
+ 3019 - Health & Beauty > Personal Care > Oral Care > Teeth Whiteners
2986
+ 6441 - Health & Beauty > Personal Care > Oral Care > Tongue Scrapers
2987
+ 4775 - Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories
2988
+ 6920 - Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Covers
2989
+ 4776 - Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Replacement Heads
2990
+ 4942 - Health & Beauty > Personal Care > Oral Care > Toothbrush Accessories > Toothbrush Sanitizers
2991
+ 527 - Health & Beauty > Personal Care > Oral Care > Toothbrushes
2992
+ 1360 - Health & Beauty > Personal Care > Oral Care > Toothpaste
2993
+ 5154 - Health & Beauty > Personal Care > Oral Care > Toothpaste Squeezers & Dispensers
2994
+ 4316 - Health & Beauty > Personal Care > Oral Care > Toothpicks
2995
+ 777 - Health & Beauty > Personal Care > Personal Lubricants
2996
+ 528 - Health & Beauty > Personal Care > Shaving & Grooming
2997
+ 529 - Health & Beauty > Personal Care > Shaving & Grooming > Aftershave
2998
+ 8214 - Health & Beauty > Personal Care > Shaving & Grooming > Body & Facial Hair Bleach
2999
+ 531 - Health & Beauty > Personal Care > Shaving & Grooming > Electric Razor Accessories
3000
+ 532 - Health & Beauty > Personal Care > Shaving & Grooming > Electric Razors
3001
+ 6842 - Health & Beauty > Personal Care > Shaving & Grooming > Hair Clipper & Trimmer Accessories
3002
+ 533 - Health & Beauty > Personal Care > Shaving & Grooming > Hair Clippers & Trimmers
3003
+ 4507 - Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal
3004
+ 4508 - Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Depilatories
3005
+ 4509 - Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Electrolysis Devices
3006
+ 4510 - Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Epilators
3007
+ 8136 - Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Hair Removal Wax Warmers
3008
+ 7199 - Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Laser & IPL Hair Removal Devices
3009
+ 4511 - Health & Beauty > Personal Care > Shaving & Grooming > Hair Removal > Waxing Kits & Supplies
3010
+ 534 - Health & Beauty > Personal Care > Shaving & Grooming > Razors & Razor Blades
3011
+ 8531 - Health & Beauty > Personal Care > Shaving & Grooming > Shaving Bowls & Mugs
3012
+ 2681 - Health & Beauty > Personal Care > Shaving & Grooming > Shaving Brushes
3013
+ 2971 - Health & Beauty > Personal Care > Shaving & Grooming > Shaving Cream
3014
+ 5111 - Health & Beauty > Personal Care > Shaving & Grooming > Shaving Kits
3015
+ 2508 - Health & Beauty > Personal Care > Shaving & Grooming > Styptic Pencils
3016
+ 4076 - Health & Beauty > Personal Care > Sleeping Aids
3017
+ 4313 - Health & Beauty > Personal Care > Sleeping Aids > Eye Masks
3018
+ 6017 - Health & Beauty > Personal Care > Sleeping Aids > Snoring & Sleep Apnea Aids
3019
+ 4211 - Health & Beauty > Personal Care > Sleeping Aids > Travel Pillows
3020
+ 4056 - Health & Beauty > Personal Care > Sleeping Aids > White Noise Machines
3021
+ 6921 - Health & Beauty > Personal Care > Spray Tanning Tents
3022
+ 472 - Health & Beauty > Personal Care > Tanning Beds
3023
+ 2656 - Health & Beauty > Personal Care > Tweezers
3024
+ 1380 - Health & Beauty > Personal Care > Vision Care
3025
+ 3011 - Health & Beauty > Personal Care > Vision Care > Contact Lens Care
3026
+ 7363 - Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Care Kits
3027
+ 6510 - Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Cases
3028
+ 6509 - Health & Beauty > Personal Care > Vision Care > Contact Lens Care > Contact Lens Solution
3029
+ 2923 - Health & Beauty > Personal Care > Vision Care > Contact Lenses
3030
+ 2922 - Health & Beauty > Personal Care > Vision Care > Eye Drops & Lubricants
3031
+ 2733 - Health & Beauty > Personal Care > Vision Care > Eyeglass Lenses
3032
+ 524 - Health & Beauty > Personal Care > Vision Care > Eyeglasses
3033
+ 2521 - Health & Beauty > Personal Care > Vision Care > Eyewear Accessories
3034
+ 5507 - Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Cases & Holders
3035
+ 352853 - Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Lens Cleaning Solutions
3036
+ 543538 - Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Replacement Parts
3037
+ 8204 - Health & Beauty > Personal Care > Vision Care > Eyewear Accessories > Eyewear Straps & Chains
3038
+ 6977 - Health & Beauty > Personal Care > Vision Care > Sunglass Lenses
3039
+ 536 - Home & Garden
3040
+ 574 - Home & Garden > Bathroom Accessories
3041
+ 575 - Home & Garden > Bathroom Accessories > Bath Caddies
3042
+ 577 - Home & Garden > Bathroom Accessories > Bath Mats & Rugs
3043
+ 4366 - Home & Garden > Bathroom Accessories > Bath Pillows
3044
+ 7093 - Home & Garden > Bathroom Accessories > Bathroom Accessory Mounts
3045
+ 6858 - Home & Garden > Bathroom Accessories > Bathroom Accessory Sets
3046
+ 579 - Home & Garden > Bathroom Accessories > Facial Tissue Holders
3047
+ 8016 - Home & Garden > Bathroom Accessories > Hand Dryer Accessories
3048
+ 5141 - Home & Garden > Bathroom Accessories > Hand Dryers
3049
+ 2418 - Home & Garden > Bathroom Accessories > Medicine Cabinets
3050
+ 2034 - Home & Garden > Bathroom Accessories > Robe Hooks
3051
+ 8114 - Home & Garden > Bathroom Accessories > Safety Grab Bars
3052
+ 578 - Home & Garden > Bathroom Accessories > Shower Curtain Rings
3053
+ 580 - Home & Garden > Bathroom Accessories > Shower Curtains
3054
+ 1962 - Home & Garden > Bathroom Accessories > Shower Rods
3055
+ 4971 - Home & Garden > Bathroom Accessories > Soap & Lotion Dispensers
3056
+ 582 - Home & Garden > Bathroom Accessories > Soap Dishes & Holders
3057
+ 7509 - Home & Garden > Bathroom Accessories > Toilet Brush Replacement Heads
3058
+ 583 - Home & Garden > Bathroom Accessories > Toilet Brushes & Holders
3059
+ 584 - Home & Garden > Bathroom Accessories > Toilet Paper Holders
3060
+ 585 - Home & Garden > Bathroom Accessories > Toothbrush Holders
3061
+ 586 - Home & Garden > Bathroom Accessories > Towel Racks & Holders
3062
+ 359 - Home & Garden > Business & Home Security
3063
+ 5491 - Home & Garden > Business & Home Security > Dummy Surveillance Cameras
3064
+ 3873 - Home & Garden > Business & Home Security > Home Alarm Systems
3065
+ 2161 - Home & Garden > Business & Home Security > Motion Sensors
3066
+ 500025 - Home & Garden > Business & Home Security > Safety & Security Mirrors
3067
+ 363 - Home & Garden > Business & Home Security > Security Lights
3068
+ 364 - Home & Garden > Business & Home Security > Security Monitors & Recorders
3069
+ 499865 - Home & Garden > Business & Home Security > Security Safe Accessories
3070
+ 3819 - Home & Garden > Business & Home Security > Security Safes
3071
+ 365 - Home & Garden > Business & Home Security > Security System Sensors
3072
+ 696 - Home & Garden > Decor
3073
+ 572 - Home & Garden > Decor > Address Signs
3074
+ 6265 - Home & Garden > Decor > Artificial Flora
3075
+ 6266 - Home & Garden > Decor > Artificial Food
3076
+ 9 - Home & Garden > Decor > Artwork
3077
+ 500045 - Home & Garden > Decor > Artwork > Decorative Tapestries
3078
+ 500044 - Home & Garden > Decor > Artwork > Posters, Prints, & Visual Artwork
3079
+ 11 - Home & Garden > Decor > Artwork > Sculptures & Statues
3080
+ 4456 - Home & Garden > Decor > Backrest Pillows
3081
+ 573 - Home & Garden > Decor > Baskets
3082
+ 5521 - Home & Garden > Decor > Bird & Wildlife Feeder Accessories
3083
+ 6993 - Home & Garden > Decor > Bird & Wildlife Feeders
3084
+ 698 - Home & Garden > Decor > Bird & Wildlife Feeders > Bird Feeders
3085
+ 6995 - Home & Garden > Decor > Bird & Wildlife Feeders > Butterfly Feeders
3086
+ 6994 - Home & Garden > Decor > Bird & Wildlife Feeders > Squirrel Feeders
3087
+ 230911 - Home & Garden > Decor > Bird & Wildlife House Accessories
3088
+ 500078 - Home & Garden > Decor > Bird & Wildlife Houses
3089
+ 500079 - Home & Garden > Decor > Bird & Wildlife Houses > Bat Houses
3090
+ 699 - Home & Garden > Decor > Bird & Wildlife Houses > Birdhouses
3091
+ 500080 - Home & Garden > Decor > Bird & Wildlife Houses > Butterfly Houses
3092
+ 697 - Home & Garden > Decor > Bird Baths
3093
+ 587 - Home & Garden > Decor > Bookends
3094
+ 7380 - Home & Garden > Decor > Cardboard Cutouts
3095
+ 4453 - Home & Garden > Decor > Chair & Sofa Cushions
3096
+ 505827 - Home & Garden > Decor > Clock Parts
3097
+ 3890 - Home & Garden > Decor > Clocks
3098
+ 4546 - Home & Garden > Decor > Clocks > Alarm Clocks
3099
+ 6912 - Home & Garden > Decor > Clocks > Desk & Shelf Clocks
3100
+ 3696 - Home & Garden > Decor > Clocks > Floor & Grandfather Clocks
3101
+ 3840 - Home & Garden > Decor > Clocks > Wall Clocks
3102
+ 5708 - Home & Garden > Decor > Coat & Hat Racks
3103
+ 7206 - Home & Garden > Decor > Decorative Bells
3104
+ 6317 - Home & Garden > Decor > Decorative Bottles
3105
+ 6457 - Home & Garden > Decor > Decorative Bowls
3106
+ 7113 - Home & Garden > Decor > Decorative Jars
3107
+ 708 - Home & Garden > Decor > Decorative Plaques
3108
+ 5875 - Home & Garden > Decor > Decorative Plates
3109
+ 6456 - Home & Garden > Decor > Decorative Trays
3110
+ 2675 - Home & Garden > Decor > Door Mats
3111
+ 7172 - Home & Garden > Decor > Dreamcatchers
3112
+ 6936 - Home & Garden > Decor > Dried Flowers
3113
+ 6935 - Home & Garden > Decor > Ecospheres
3114
+ 5609 - Home & Garden > Decor > Figurines
3115
+ 7422 - Home & Garden > Decor > Finials
3116
+ 7419 - Home & Garden > Decor > Flag & Windsock Accessories
3117
+ 7420 - Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Pole Lights
3118
+ 503010 - Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Pole Mounting Hardware & Kits
3119
+ 7421 - Home & Garden > Decor > Flag & Windsock Accessories > Flag & Windsock Poles
3120
+ 701 - Home & Garden > Decor > Flags & Windsocks
3121
+ 4770 - Home & Garden > Decor > Flameless Candles
3122
+ 702 - Home & Garden > Decor > Fountains & Ponds
3123
+ 2921 - Home & Garden > Decor > Fountains & Ponds > Fountain & Pond Accessories
3124
+ 6763 - Home & Garden > Decor > Fountains & Ponds > Fountains & Waterfalls
3125
+ 2763 - Home & Garden > Decor > Fountains & Ponds > Ponds
3126
+ 704 - Home & Garden > Decor > Garden & Stepping Stones
3127
+ 499693 - Home & Garden > Decor > Growth Charts
3128
+ 3221 - Home & Garden > Decor > Home Decor Decals
3129
+ 500121 - Home & Garden > Decor > Home Fragrance Accessories
3130
+ 6336 - Home & Garden > Decor > Home Fragrance Accessories > Candle & Oil Warmers
3131
+ 2784 - Home & Garden > Decor > Home Fragrance Accessories > Candle Holders
3132
+ 500122 - Home & Garden > Decor > Home Fragrance Accessories > Candle Snuffers
3133
+ 4741 - Home & Garden > Decor > Home Fragrance Accessories > Incense Holders
3134
+ 592 - Home & Garden > Decor > Home Fragrances
3135
+ 3898 - Home & Garden > Decor > Home Fragrances > Air Fresheners
3136
+ 588 - Home & Garden > Decor > Home Fragrances > Candles
3137
+ 5847 - Home & Garden > Decor > Home Fragrances > Fragrance Oil
3138
+ 3686 - Home & Garden > Decor > Home Fragrances > Incense
3139
+ 4740 - Home & Garden > Decor > Home Fragrances > Potpourri
3140
+ 6767 - Home & Garden > Decor > Home Fragrances > Wax Tarts
3141
+ 503000 - Home & Garden > Decor > Hourglasses
3142
+ 7382 - Home & Garden > Decor > House Numbers & Letters
3143
+ 6547 - Home & Garden > Decor > Lawn Ornaments & Garden Sculptures
3144
+ 7436 - Home & Garden > Decor > Mail Slots
3145
+ 6333 - Home & Garden > Decor > Mailbox Accessories
3146
+ 7177 - Home & Garden > Decor > Mailbox Accessories > Mailbox Covers
3147
+ 7052 - Home & Garden > Decor > Mailbox Accessories > Mailbox Enclosures
3148
+ 7176 - Home & Garden > Decor > Mailbox Accessories > Mailbox Flags
3149
+ 6334 - Home & Garden > Decor > Mailbox Accessories > Mailbox Posts
3150
+ 7339 - Home & Garden > Decor > Mailbox Accessories > Mailbox Replacement Doors
3151
+ 706 - Home & Garden > Decor > Mailboxes
3152
+ 595 - Home & Garden > Decor > Mirrors
3153
+ 3473 - Home & Garden > Decor > Music Boxes
3154
+ 6324 - Home & Garden > Decor > Napkin Rings
3155
+ 5885 - Home & Garden > Decor > Novelty Signs
3156
+ 6927 - Home & Garden > Decor > Ottoman Cushions
3157
+ 597 - Home & Garden > Decor > Picture Frames
3158
+ 4295 - Home & Garden > Decor > Piggy Banks & Money Jars
3159
+ 709 - Home & Garden > Decor > Rain Chains
3160
+ 710 - Home & Garden > Decor > Rain Gauges
3161
+ 5876 - Home & Garden > Decor > Refrigerator Magnets
3162
+ 598 - Home & Garden > Decor > Rugs
3163
+ 596 - Home & Garden > Decor > Seasonal & Holiday Decorations
3164
+ 5359 - Home & Garden > Decor > Seasonal & Holiday Decorations > Advent Calendars
3165
+ 5504 - Home & Garden > Decor > Seasonal & Holiday Decorations > Christmas Tree Skirts
3166
+ 6603 - Home & Garden > Decor > Seasonal & Holiday Decorations > Christmas Tree Stands
3167
+ 499805 - Home & Garden > Decor > Seasonal & Holiday Decorations > Easter Egg Decorating Kits
3168
+ 6532 - Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornament Displays & Stands
3169
+ 499804 - Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornament Hooks
3170
+ 3144 - Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Ornaments
3171
+ 5990 - Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Stocking Hangers
3172
+ 5991 - Home & Garden > Decor > Seasonal & Holiday Decorations > Holiday Stockings
3173
+ 5930 - Home & Garden > Decor > Seasonal & Holiday Decorations > Japanese Traditional Dolls
3174
+ 6531 - Home & Garden > Decor > Seasonal & Holiday Decorations > Nativity Sets
3175
+ 505809 - Home & Garden > Decor > Seasonal & Holiday Decorations > Seasonal Village Sets & Accessories
3176
+ 5922 - Home & Garden > Decor > Shadow Boxes
3177
+ 599 - Home & Garden > Decor > Slipcovers
3178
+ 6535 - Home & Garden > Decor > Snow Globes
3179
+ 7173 - Home & Garden > Decor > Suncatchers
3180
+ 711 - Home & Garden > Decor > Sundials
3181
+ 4454 - Home & Garden > Decor > Throw Pillows
3182
+ 4233 - Home & Garden > Decor > Trunks
3183
+ 6424 - Home & Garden > Decor > Vase Fillers & Table Scatters
3184
+ 602 - Home & Garden > Decor > Vases
3185
+ 2334 - Home & Garden > Decor > Wallpaper
3186
+ 712 - Home & Garden > Decor > Weather Vanes & Roof Decor
3187
+ 714 - Home & Garden > Decor > Wind Chimes
3188
+ 2839 - Home & Garden > Decor > Wind Wheels & Spinners
3189
+ 6530 - Home & Garden > Decor > Window Magnets
3190
+ 6254 - Home & Garden > Decor > Window Treatment Accessories
3191
+ 6256 - Home & Garden > Decor > Window Treatment Accessories > Curtain & Drape Rings
3192
+ 6257 - Home & Garden > Decor > Window Treatment Accessories > Curtain & Drape Rods
3193
+ 6255 - Home & Garden > Decor > Window Treatment Accessories > Curtain Holdbacks & Tassels
3194
+ 8042 - Home & Garden > Decor > Window Treatment Accessories > Window Treatment Replacement Parts
3195
+ 603 - Home & Garden > Decor > Window Treatments
3196
+ 2882 - Home & Garden > Decor > Window Treatments > Curtains & Drapes
3197
+ 6492 - Home & Garden > Decor > Window Treatments > Stained Glass Panels
3198
+ 2885 - Home & Garden > Decor > Window Treatments > Window Blinds & Shades
3199
+ 5989 - Home & Garden > Decor > Window Treatments > Window Films
3200
+ 4375 - Home & Garden > Decor > Window Treatments > Window Screens
3201
+ 2621 - Home & Garden > Decor > Window Treatments > Window Valances & Cornices
3202
+ 3262 - Home & Garden > Decor > World Globes
3203
+ 6267 - Home & Garden > Decor > Wreaths & Garlands
3204
+ 5835 - Home & Garden > Emergency Preparedness
3205
+ 4490 - Home & Garden > Emergency Preparedness > Earthquake Alarms
3206
+ 6897 - Home & Garden > Emergency Preparedness > Emergency Blankets
3207
+ 5836 - Home & Garden > Emergency Preparedness > Emergency Food Kits
3208
+ 7058 - Home & Garden > Emergency Preparedness > Emergency Tools & Kits
3209
+ 4491 - Home & Garden > Emergency Preparedness > Furniture Anchors
3210
+ 2862 - Home & Garden > Fireplace & Wood Stove Accessories
3211
+ 2044 - Home & Garden > Fireplace & Wood Stove Accessories > Bellows
3212
+ 6563 - Home & Garden > Fireplace & Wood Stove Accessories > Fireplace & Wood Stove Grates
3213
+ 7523 - Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Andirons
3214
+ 7109 - Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Reflectors
3215
+ 2365 - Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Screens
3216
+ 1530 - Home & Garden > Fireplace & Wood Stove Accessories > Fireplace Tools
3217
+ 625 - Home & Garden > Fireplace & Wood Stove Accessories > Firewood & Fuel
3218
+ 7091 - Home & Garden > Fireplace & Wood Stove Accessories > Hearth Pads
3219
+ 7029 - Home & Garden > Fireplace & Wood Stove Accessories > Log Rack & Carrier Accessories
3220
+ 695 - Home & Garden > Fireplace & Wood Stove Accessories > Log Racks & Carriers
3221
+ 4918 - Home & Garden > Fireplace & Wood Stove Accessories > Wood Stove Fans & Blowers
3222
+ 6792 - Home & Garden > Fireplaces
3223
+ 1679 - Home & Garden > Flood, Fire & Gas Safety
3224
+ 7226 - Home & Garden > Flood, Fire & Gas Safety > Fire Alarm Control Panels
3225
+ 1871 - Home & Garden > Flood, Fire & Gas Safety > Fire Alarms
3226
+ 1639 - Home & Garden > Flood, Fire & Gas Safety > Fire Extinguisher & Equipment Storage
3227
+ 1434 - Home & Garden > Flood, Fire & Gas Safety > Fire Extinguishers
3228
+ 1934 - Home & Garden > Flood, Fire & Gas Safety > Fire Sprinklers
3229
+ 7227 - Home & Garden > Flood, Fire & Gas Safety > Heat Detectors
3230
+ 499673 - Home & Garden > Flood, Fire & Gas Safety > Smoke & Carbon Monoxide Detectors
3231
+ 2164 - Home & Garden > Flood, Fire & Gas Safety > Smoke & Carbon Monoxide Detectors > Carbon Monoxide Detectors
3232
+ 1471 - Home & Garden > Flood, Fire & Gas Safety > Smoke & Carbon Monoxide Detectors > Smoke Detectors
3233
+ 1306 - Home & Garden > Flood, Fire & Gas Safety > Water & Flood Detectors
3234
+ 3348 - Home & Garden > Household Appliance Accessories
3235
+ 2367 - Home & Garden > Household Appliance Accessories > Air Conditioner Accessories
3236
+ 5826 - Home & Garden > Household Appliance Accessories > Air Conditioner Accessories > Air Conditioner Covers
3237
+ 3573 - Home & Garden > Household Appliance Accessories > Air Conditioner Accessories > Air Conditioner Filters
3238
+ 3410 - Home & Garden > Household Appliance Accessories > Air Purifier Accessories
3239
+ 3667 - Home & Garden > Household Appliance Accessories > Air Purifier Accessories > Air Purifier Filters
3240
+ 4667 - Home & Garden > Household Appliance Accessories > Dehumidifier Accessories
3241
+ 5089 - Home & Garden > Household Appliance Accessories > Fan Accessories
3242
+ 4548 - Home & Garden > Household Appliance Accessories > Floor & Steam Cleaner Accessories
3243
+ 6773 - Home & Garden > Household Appliance Accessories > Furnace & Boiler Accessories
3244
+ 7110 - Home & Garden > Household Appliance Accessories > Heating Radiator Accessories
3245
+ 7111 - Home & Garden > Household Appliance Accessories > Heating Radiator Accessories > Heating Radiator Reflectors
3246
+ 3862 - Home & Garden > Household Appliance Accessories > Humidifier Accessories
3247
+ 3402 - Home & Garden > Household Appliance Accessories > Humidifier Accessories > Humidifier Filters
3248
+ 3456 - Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories
3249
+ 5158 - Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Garment Steamer Accessories
3250
+ 5159 - Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Iron Accessories
3251
+ 5160 - Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Steam Press Accessories
3252
+ 500085 - Home & Garden > Household Appliance Accessories > Laundry Appliance Accessories > Washer & Dryer Accessories
3253
+ 4650 - Home & Garden > Household Appliance Accessories > Patio Heater Accessories
3254
+ 4651 - Home & Garden > Household Appliance Accessories > Patio Heater Accessories > Patio Heater Covers
3255
+ 618 - Home & Garden > Household Appliance Accessories > Vacuum Accessories
3256
+ 2751 - Home & Garden > Household Appliance Accessories > Water Heater Accessories
3257
+ 2310 - Home & Garden > Household Appliance Accessories > Water Heater Accessories > Anode Rods
3258
+ 2175 - Home & Garden > Household Appliance Accessories > Water Heater Accessories > Hot Water Tanks
3259
+ 1744 - Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Elements
3260
+ 500063 - Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Expansion Tanks
3261
+ 1835 - Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Pans
3262
+ 2221 - Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Stacks
3263
+ 1709 - Home & Garden > Household Appliance Accessories > Water Heater Accessories > Water Heater Vents
3264
+ 604 - Home & Garden > Household Appliances
3265
+ 1626 - Home & Garden > Household Appliances > Climate Control Appliances
3266
+ 605 - Home & Garden > Household Appliances > Climate Control Appliances > Air Conditioners
3267
+ 606 - Home & Garden > Household Appliances > Climate Control Appliances > Air Purifiers
3268
+ 607 - Home & Garden > Household Appliances > Climate Control Appliances > Dehumidifiers
3269
+ 7328 - Home & Garden > Household Appliances > Climate Control Appliances > Duct Heaters
3270
+ 6727 - Home & Garden > Household Appliances > Climate Control Appliances > Evaporative Coolers
3271
+ 608 - Home & Garden > Household Appliances > Climate Control Appliances > Fans
3272
+ 1700 - Home & Garden > Household Appliances > Climate Control Appliances > Fans > Ceiling Fans
3273
+ 2535 - Home & Garden > Household Appliances > Climate Control Appliances > Fans > Desk & Pedestal Fans
3274
+ 7527 - Home & Garden > Household Appliances > Climate Control Appliances > Fans > Powered Hand Fans & Misters
3275
+ 4485 - Home & Garden > Household Appliances > Climate Control Appliances > Fans > Ventilation Fans
3276
+ 8090 - Home & Garden > Household Appliances > Climate Control Appliances > Fans > Wall Mount Fans
3277
+ 3082 - Home & Garden > Household Appliances > Climate Control Appliances > Furnaces & Boilers
3278
+ 2060 - Home & Garden > Household Appliances > Climate Control Appliances > Heating Radiators
3279
+ 613 - Home & Garden > Household Appliances > Climate Control Appliances > Humidifiers
3280
+ 6709 - Home & Garden > Household Appliances > Climate Control Appliances > Outdoor Misting Systems
3281
+ 2649 - Home & Garden > Household Appliances > Climate Control Appliances > Patio Heaters
3282
+ 611 - Home & Garden > Household Appliances > Climate Control Appliances > Space Heaters
3283
+ 235920 - Home & Garden > Household Appliances > Floor & Carpet Dryers
3284
+ 616 - Home & Garden > Household Appliances > Floor & Steam Cleaners
3285
+ 543601 - Home & Garden > Household Appliances > Floor & Steam Cleaners > Carpet Shampooers
3286
+ 543600 - Home & Garden > Household Appliances > Floor & Steam Cleaners > Carpet Steamers
3287
+ 543602 - Home & Garden > Household Appliances > Floor & Steam Cleaners > Floor Scrubbers
3288
+ 543603 - Home & Garden > Household Appliances > Floor & Steam Cleaners > Steam Mops
3289
+ 5294 - Home & Garden > Household Appliances > Floor Polishers & Buffers
3290
+ 4483 - Home & Garden > Household Appliances > Futon Dryers
3291
+ 6741 - Home & Garden > Household Appliances > Garage Door Keypads & Remotes
3292
+ 609 - Home & Garden > Household Appliances > Garage Door Openers
3293
+ 2706 - Home & Garden > Household Appliances > Laundry Appliances
3294
+ 2612 - Home & Garden > Household Appliances > Laundry Appliances > Dryers
3295
+ 5138 - Home & Garden > Household Appliances > Laundry Appliances > Garment Steamers
3296
+ 5139 - Home & Garden > Household Appliances > Laundry Appliances > Irons & Ironing Systems
3297
+ 2849 - Home & Garden > Household Appliances > Laundry Appliances > Laundry Combo Units
3298
+ 5140 - Home & Garden > Household Appliances > Laundry Appliances > Steam Presses
3299
+ 2549 - Home & Garden > Household Appliances > Laundry Appliances > Washing Machines
3300
+ 500081 - Home & Garden > Household Appliances > Ultrasonic Cleaners
3301
+ 619 - Home & Garden > Household Appliances > Vacuums
3302
+ 7121 - Home & Garden > Household Appliances > Wallpaper Steamers
3303
+ 621 - Home & Garden > Household Appliances > Water Heaters
3304
+ 630 - Home & Garden > Household Supplies
3305
+ 7351 - Home & Garden > Household Supplies > Drawer & Shelf Liners
3306
+ 499674 - Home & Garden > Household Supplies > Floor Protection Films & Runners
3307
+ 7214 - Home & Garden > Household Supplies > Furniture Floor Protectors
3308
+ 8522 - Home & Garden > Household Supplies > Garage Floor Mats
3309
+ 2374 - Home & Garden > Household Supplies > Garbage Bags
3310
+ 623 - Home & Garden > Household Supplies > Household Cleaning Supplies
3311
+ 4671 - Home & Garden > Household Supplies > Household Cleaning Supplies > Broom & Mop Handles
3312
+ 499892 - Home & Garden > Household Supplies > Household Cleaning Supplies > Broom Heads
3313
+ 2857 - Home & Garden > Household Supplies > Household Cleaning Supplies > Brooms
3314
+ 6437 - Home & Garden > Household Supplies > Household Cleaning Supplies > Buckets
3315
+ 4677 - Home & Garden > Household Supplies > Household Cleaning Supplies > Carpet Sweepers
3316
+ 5113 - Home & Garden > Household Supplies > Household Cleaning Supplies > Cleaning Gloves
3317
+ 6263 - Home & Garden > Household Supplies > Household Cleaning Supplies > Duster Refills
3318
+ 2250 - Home & Garden > Household Supplies > Household Cleaning Supplies > Dusters
3319
+ 4515 - Home & Garden > Household Supplies > Household Cleaning Supplies > Dustpans
3320
+ 6419 - Home & Garden > Household Supplies > Household Cleaning Supplies > Fabric & Upholstery Protectors
3321
+ 4973 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products
3322
+ 7330 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > All-Purpose Cleaners
3323
+ 4974 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Carpet Cleaners
3324
+ 500065 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Descalers & Decalcifiers
3325
+ 4975 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Dish Detergent & Soap
3326
+ 7510 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Dishwasher Cleaners
3327
+ 8043 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Fabric & Upholstery Cleaners
3328
+ 4977 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Floor Cleaners
3329
+ 5825 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Furniture Cleaners & Polish
3330
+ 4976 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Glass & Surface Cleaners
3331
+ 543649 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Glass & Surface Cleaners > Glass Cleaners
3332
+ 543650 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Glass & Surface Cleaners > Muti-surface Cleaners
3333
+ 6474 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Household Disinfectants
3334
+ 4978 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Oven & Grill Cleaners
3335
+ 4979 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Pet Odor & Stain Removers
3336
+ 7552 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Rinse Aids
3337
+ 7426 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Stainless Steel Cleaners & Polishes
3338
+ 4980 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Toilet Bowl Cleaners
3339
+ 4981 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Tub & Tile Cleaners
3340
+ 7462 - Home & Garden > Household Supplies > Household Cleaning Supplies > Household Cleaning Products > Washing Machine Cleaners
3341
+ 6264 - Home & Garden > Household Supplies > Household Cleaning Supplies > Mop Heads & Refills
3342
+ 2713 - Home & Garden > Household Supplies > Household Cleaning Supplies > Mops
3343
+ 499767 - Home & Garden > Household Supplies > Household Cleaning Supplies > Scrub Brush Heads & Refills
3344
+ 4670 - Home & Garden > Household Supplies > Household Cleaning Supplies > Scrub Brushes
3345
+ 8071 - Home & Garden > Household Supplies > Household Cleaning Supplies > Shop Towels & General-Purpose Cleaning Cloths
3346
+ 2796 - Home & Garden > Household Supplies > Household Cleaning Supplies > Sponges & Scouring Pads
3347
+ 2610 - Home & Garden > Household Supplies > Household Cleaning Supplies > Squeegees
3348
+ 2530 - Home & Garden > Household Supplies > Household Paper Products
3349
+ 624 - Home & Garden > Household Supplies > Household Paper Products > Facial Tissues
3350
+ 3846 - Home & Garden > Household Supplies > Household Paper Products > Paper Napkins
3351
+ 2742 - Home & Garden > Household Supplies > Household Paper Products > Paper Towels
3352
+ 629 - Home & Garden > Household Supplies > Household Paper Products > Toilet Paper
3353
+ 3355 - Home & Garden > Household Supplies > Household Thermometers
3354
+ 627 - Home & Garden > Household Supplies > Laundry Supplies
3355
+ 4982 - Home & Garden > Household Supplies > Laundry Supplies > Bleach
3356
+ 5704 - Home & Garden > Household Supplies > Laundry Supplies > Clothespins
3357
+ 7320 - Home & Garden > Household Supplies > Laundry Supplies > Dry Cleaning Kits
3358
+ 2677 - Home & Garden > Household Supplies > Laundry Supplies > Drying Racks & Hangers
3359
+ 6240 - Home & Garden > Household Supplies > Laundry Supplies > Fabric Refreshers
3360
+ 5705 - Home & Garden > Household Supplies > Laundry Supplies > Fabric Shavers
3361
+ 2794 - Home & Garden > Household Supplies > Laundry Supplies > Fabric Softeners & Dryer Sheets
3362
+ 4657 - Home & Garden > Household Supplies > Laundry Supplies > Fabric Stain Removers
3363
+ 6387 - Home & Garden > Household Supplies > Laundry Supplies > Fabric Starch
3364
+ 7457 - Home & Garden > Household Supplies > Laundry Supplies > Garment Shields
3365
+ 499937 - Home & Garden > Household Supplies > Laundry Supplies > Iron Rests
3366
+ 4656 - Home & Garden > Household Supplies > Laundry Supplies > Ironing Board Pads & Covers
3367
+ 499931 - Home & Garden > Household Supplies > Laundry Supplies > Ironing Board Replacement Parts
3368
+ 633 - Home & Garden > Household Supplies > Laundry Supplies > Ironing Boards
3369
+ 5084 - Home & Garden > Household Supplies > Laundry Supplies > Laundry Balls
3370
+ 634 - Home & Garden > Household Supplies > Laundry Supplies > Laundry Baskets
3371
+ 2754 - Home & Garden > Household Supplies > Laundry Supplies > Laundry Detergent
3372
+ 5085 - Home & Garden > Household Supplies > Laundry Supplies > Laundry Wash Bags & Frames
3373
+ 3080 - Home & Garden > Household Supplies > Laundry Supplies > Lint Rollers
3374
+ 7502 - Home & Garden > Household Supplies > Laundry Supplies > Wrinkle Releasers & Anti-Static Sprays
3375
+ 7406 - Home & Garden > Household Supplies > Moisture Absorbers
3376
+ 728 - Home & Garden > Household Supplies > Pest Control
3377
+ 4220 - Home & Garden > Household Supplies > Pest Control > Fly Swatters
3378
+ 2631 - Home & Garden > Household Supplies > Pest Control > Pest Control Traps
3379
+ 2869 - Home & Garden > Household Supplies > Pest Control > Pesticides
3380
+ 2865 - Home & Garden > Household Supplies > Pest Control > Repellents
3381
+ 7137 - Home & Garden > Household Supplies > Pest Control > Repellents > Animal & Pet Repellents
3382
+ 512 - Home & Garden > Household Supplies > Pest Control > Repellents > Household Insect Repellents
3383
+ 3307 - Home & Garden > Household Supplies > Rug Pads
3384
+ 628 - Home & Garden > Household Supplies > Shoe Care & Tools
3385
+ 5600 - Home & Garden > Household Supplies > Shoe Care & Tools > Boot Pulls
3386
+ 2301 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Bags
3387
+ 1874 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Brushes
3388
+ 8033 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Care Kits
3389
+ 2371 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Dryers
3390
+ 5601 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Horns & Dressing Aids
3391
+ 8032 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Polishers
3392
+ 1659 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Polishes & Waxes
3393
+ 8031 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Scrapers
3394
+ 5604 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Treatments & Dyes
3395
+ 2431 - Home & Garden > Household Supplies > Shoe Care & Tools > Shoe Trees & Shapers
3396
+ 499885 - Home & Garden > Household Supplies > Stair Treads
3397
+ 636 - Home & Garden > Household Supplies > Storage & Organization
3398
+ 5558 - Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage
3399
+ 3722 - Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Charging Valets
3400
+ 5714 - Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Closet Organizers & Garment Racks
3401
+ 5716 - Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Clothes Valets
3402
+ 631 - Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Hangers
3403
+ 7514 - Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Hat Boxes
3404
+ 5559 - Home & Garden > Household Supplies > Storage & Organization > Clothing & Closet Storage > Shoe Racks & Organizers
3405
+ 5128 - Home & Garden > Household Supplies > Storage & Organization > Flatware Chests
3406
+ 8058 - Home & Garden > Household Supplies > Storage & Organization > Household Drawer Organizer Inserts
3407
+ 3561 - Home & Garden > Household Supplies > Storage & Organization > Household Storage Bags
3408
+ 6986 - Home & Garden > Household Supplies > Storage & Organization > Household Storage Caddies
3409
+ 5631 - Home & Garden > Household Supplies > Storage & Organization > Household Storage Containers
3410
+ 7255 - Home & Garden > Household Supplies > Storage & Organization > Household Storage Drawers
3411
+ 4360 - Home & Garden > Household Supplies > Storage & Organization > Photo Storage
3412
+ 40 - Home & Garden > Household Supplies > Storage & Organization > Photo Storage > Photo Albums
3413
+ 4237 - Home & Garden > Household Supplies > Storage & Organization > Photo Storage > Photo Storage Boxes
3414
+ 2446 - Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks
3415
+ 499930 - Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Ironing Board Hooks & Racks
3416
+ 5494 - Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Umbrella Stands & Racks
3417
+ 5707 - Home & Garden > Household Supplies > Storage & Organization > Storage Hooks & Racks > Utility Hooks
3418
+ 5056 - Home & Garden > Household Supplies > Trash Compactor Accessories
3419
+ 4516 - Home & Garden > Household Supplies > Waste Containment
3420
+ 500039 - Home & Garden > Household Supplies > Waste Containment > Dumpsters
3421
+ 5143 - Home & Garden > Household Supplies > Waste Containment > Hazardous Waste Containers
3422
+ 4517 - Home & Garden > Household Supplies > Waste Containment > Recycling Containers
3423
+ 637 - Home & Garden > Household Supplies > Waste Containment > Trash Cans & Wastebaskets
3424
+ 6757 - Home & Garden > Household Supplies > Waste Containment Accessories
3425
+ 6765 - Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Carts
3426
+ 6726 - Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Enclosures
3427
+ 500115 - Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Labels & Signs
3428
+ 4717 - Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Lids
3429
+ 6758 - Home & Garden > Household Supplies > Waste Containment Accessories > Waste Container Wheels
3430
+ 638 - Home & Garden > Kitchen & Dining
3431
+ 649 - Home & Garden > Kitchen & Dining > Barware
3432
+ 7075 - Home & Garden > Kitchen & Dining > Barware > Absinthe Fountains
3433
+ 1817 - Home & Garden > Kitchen & Dining > Barware > Beer Dispensers & Taps
3434
+ 7569 - Home & Garden > Kitchen & Dining > Barware > Beverage Chilling Cubes & Sticks
3435
+ 505806 - Home & Garden > Kitchen & Dining > Barware > Beverage Tubs & Chillers
3436
+ 499990 - Home & Garden > Kitchen & Dining > Barware > Bottle Caps
3437
+ 4562 - Home & Garden > Kitchen & Dining > Barware > Bottle Stoppers & Savers
3438
+ 7238 - Home & Garden > Kitchen & Dining > Barware > Coaster Holders
3439
+ 2363 - Home & Garden > Kitchen & Dining > Barware > Coasters
3440
+ 6957 - Home & Garden > Kitchen & Dining > Barware > Cocktail & Barware Tool Sets
3441
+ 651 - Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools
3442
+ 4222 - Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Bar Ice Picks
3443
+ 3427 - Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Bottle Openers
3444
+ 6956 - Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Cocktail Shakers
3445
+ 505327 - Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Cocktail Strainers
3446
+ 503757 - Home & Garden > Kitchen & Dining > Barware > Cocktail Shakers & Tools > Muddlers
3447
+ 2976 - Home & Garden > Kitchen & Dining > Barware > Corkscrews
3448
+ 650 - Home & Garden > Kitchen & Dining > Barware > Decanters
3449
+ 7139 - Home & Garden > Kitchen & Dining > Barware > Foil Cutters
3450
+ 4563 - Home & Garden > Kitchen & Dining > Barware > Wine Aerators
3451
+ 8493 - Home & Garden > Kitchen & Dining > Barware > Wine Bottle Holders
3452
+ 7008 - Home & Garden > Kitchen & Dining > Barware > Wine Glass Charms
3453
+ 6070 - Home & Garden > Kitchen & Dining > Cookware & Bakeware
3454
+ 640 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware
3455
+ 4764 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Bakeware Sets
3456
+ 641 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Baking & Cookie Sheets
3457
+ 642 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Bread Pans & Molds
3458
+ 6756 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Broiling Pans
3459
+ 643 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Cake Pans & Molds
3460
+ 644 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Muffin & Pastry Pans
3461
+ 645 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pie & Quiche Pans
3462
+ 2843 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pizza Pans
3463
+ 646 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Pizza Stones
3464
+ 647 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Ramekins & Souffle Dishes
3465
+ 648 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware > Roasting Pans
3466
+ 4502 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories
3467
+ 4503 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Baking Mats & Liners
3468
+ 7131 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Baking Weights
3469
+ 4726 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Bakeware Accessories > Roasting Pan Racks
3470
+ 654 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware
3471
+ 6071 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware & Bakeware Combo Sets
3472
+ 655 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Casserole Dishes
3473
+ 4721 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Cookware Sets
3474
+ 6838 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Crêpe & Blini Pans
3475
+ 656 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Double Boilers
3476
+ 657 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Dutch Ovens
3477
+ 6518 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Fermentation & Pickling Crocks
3478
+ 658 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Griddles & Grill Pans
3479
+ 5110 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Grill Presses
3480
+ 4459 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Paella Pans
3481
+ 660 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Pressure Cookers & Canners
3482
+ 661 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Saucepans
3483
+ 4423 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Sauté Pans
3484
+ 662 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Skillets & Frying Pans
3485
+ 663 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Stock Pots
3486
+ 659 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Stovetop Kettles
3487
+ 5340 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Tagines & Clay Cooking Pots
3488
+ 664 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware > Woks
3489
+ 4424 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories
3490
+ 4661 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pot & Pan Handles
3491
+ 4660 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pot & Pan Lids
3492
+ 4501 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Pressure Cooker & Canner Accessories
3493
+ 4529 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Steamer Baskets
3494
+ 4427 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories
3495
+ 4663 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories > Wok Brushes
3496
+ 4662 - Home & Garden > Kitchen & Dining > Cookware & Bakeware > Cookware Accessories > Wok Accessories > Wok Rings
3497
+ 2920 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers
3498
+ 4722 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Airpots
3499
+ 3435 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Canteens
3500
+ 1017 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Coolers
3501
+ 4520 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves
3502
+ 4521 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves > Can & Bottle Sleeves
3503
+ 4522 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Drink Sleeves > Cup Sleeves
3504
+ 1444 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Flasks
3505
+ 2507 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Insulated Bags
3506
+ 669 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Lunch Boxes & Totes
3507
+ 671 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Picnic Baskets
3508
+ 5060 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Replacement Drink Lids
3509
+ 3800 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Thermoses
3510
+ 3809 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Water Bottles
3511
+ 6449 - Home & Garden > Kitchen & Dining > Food & Beverage Carriers > Wine Carrier Bags
3512
+ 2626 - Home & Garden > Kitchen & Dining > Food Storage
3513
+ 3337 - Home & Garden > Kitchen & Dining > Food Storage > Bread Boxes & Bags
3514
+ 6534 - Home & Garden > Kitchen & Dining > Food Storage > Candy Buckets
3515
+ 2644 - Home & Garden > Kitchen & Dining > Food Storage > Cookie Jars
3516
+ 6481 - Home & Garden > Kitchen & Dining > Food Storage > Food Container Covers
3517
+ 3591 - Home & Garden > Kitchen & Dining > Food Storage > Food Storage Bags
3518
+ 667 - Home & Garden > Kitchen & Dining > Food Storage > Food Storage Containers
3519
+ 3110 - Home & Garden > Kitchen & Dining > Food Storage > Food Wraps
3520
+ 1496 - Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Foil
3521
+ 5642 - Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Parchment Paper
3522
+ 3750 - Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Plastic Wrap
3523
+ 3956 - Home & Garden > Kitchen & Dining > Food Storage > Food Wraps > Wax Paper
3524
+ 5134 - Home & Garden > Kitchen & Dining > Food Storage > Honey Jars
3525
+ 6478 - Home & Garden > Kitchen & Dining > Food Storage Accessories
3526
+ 499924 - Home & Garden > Kitchen & Dining > Food Storage Accessories > Food & Beverage Labels
3527
+ 8039 - Home & Garden > Kitchen & Dining > Food Storage Accessories > Food Wrap Dispensers
3528
+ 6479 - Home & Garden > Kitchen & Dining > Food Storage Accessories > Oxygen Absorbers
3529
+ 5837 - Home & Garden > Kitchen & Dining > Food Storage Accessories > Twist Ties & Bag Clips
3530
+ 2901 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories
3531
+ 3489 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Breadmaker Accessories
3532
+ 3988 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories
3533
+ 6888 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Decanter Warmers
3534
+ 3239 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Decanters
3535
+ 4500 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Filter Baskets
3536
+ 3450 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Filters
3537
+ 4786 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Grinder Accessories
3538
+ 734 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Grinders
3539
+ 503736 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Maker & Espresso Machine Replacement Parts
3540
+ 5065 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Coffee Maker Water Filters
3541
+ 5066 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Frothing Pitchers
3542
+ 3838 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Coffee Maker & Espresso Machine Accessories > Portafilters
3543
+ 500004 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Cooktop, Oven & Range Accessories
3544
+ 5076 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Cotton Candy Machine Accessories
3545
+ 3954 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Deep Fryer Accessories
3546
+ 3443 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Dishwasher Parts & Accessories
3547
+ 500066 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Electric Kettle Accessories
3548
+ 7355 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Electric Skillet & Wok Accessories
3549
+ 6944 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories
3550
+ 503725 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Cooking Gel Fuels
3551
+ 6945 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Fondue Forks
3552
+ 6946 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Fondue Set Accessories > Fondue Pot Stands
3553
+ 4653 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories
3554
+ 4655 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories > Food Dehydrator Sheets
3555
+ 4654 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Dehydrator Accessories > Food Dehydrator Trays
3556
+ 4763 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Grinder Accessories
3557
+ 505765 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Food Mixer & Blender Accessories
3558
+ 7570 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Freezer Accessories
3559
+ 6747 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Garbage Disposal Accessories
3560
+ 4674 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Cream Maker Accessories
3561
+ 4675 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Cream Maker Accessories > Ice Cream Maker Freezer Bowls
3562
+ 5042 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Crusher & Shaver Accessories
3563
+ 7187 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Ice Maker Accessories
3564
+ 4519 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Juicer Accessories
3565
+ 1334 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Microwave Oven Accessories
3566
+ 3684 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories
3567
+ 5694 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Charcoal Briquettes
3568
+ 7540 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Charcoal Chimneys
3569
+ 5670 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Carts
3570
+ 3855 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Covers
3571
+ 3382 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Racks & Toppers
3572
+ 505667 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Replacement Parts
3573
+ 4560 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grill Spits & Baskets
3574
+ 5672 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Outdoor Grilling Planks
3575
+ 5671 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Outdoor Grill Accessories > Smoking Chips & Pellets
3576
+ 2540 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Pasta Maker Accessories
3577
+ 5075 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Popcorn Maker Accessories
3578
+ 7006 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Portable Cooking Stove Accessories
3579
+ 8087 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Range Hood Accessories
3580
+ 3848 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Refrigerator Accessories
3581
+ 502989 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Soda Maker Accessories
3582
+ 8051 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories
3583
+ 8052 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories > Steam Table Pan Covers
3584
+ 8053 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Steam Table Accessories > Steam Table Pans
3585
+ 7444 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Toaster Accessories
3586
+ 3523 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Vacuum Sealer Accessories
3587
+ 3124 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Vacuum Sealer Accessories > Vacuum Sealer Bags
3588
+ 499996 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Waffle Iron Accessories
3589
+ 7118 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Water Cooler Accessories
3590
+ 7119 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Water Cooler Accessories > Water Cooler Bottles
3591
+ 8106 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Wine Fridge Accessories
3592
+ 5570 - Home & Garden > Kitchen & Dining > Kitchen Appliance Accessories > Yogurt Maker Accessories
3593
+ 730 - Home & Garden > Kitchen & Dining > Kitchen Appliances
3594
+ 5287 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Beverage Warmers
3595
+ 732 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Breadmakers
3596
+ 5090 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Chocolate Tempering Machines
3597
+ 736 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines
3598
+ 1388 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Drip Coffee Makers
3599
+ 1647 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Electric & Stovetop Espresso Pots
3600
+ 2422 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Espresso Machines
3601
+ 1557 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > French Presses
3602
+ 2247 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Percolators
3603
+ 5286 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Coffee Makers & Espresso Machines > Vacuum Coffee Makers
3604
+ 679 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Cooktops
3605
+ 3319 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Cotton Candy Machines
3606
+ 738 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Deep Fryers
3607
+ 3181 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Deli Slicers
3608
+ 680 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Dishwashers
3609
+ 7165 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Griddles & Grills
3610
+ 751 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Kettles
3611
+ 4421 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Electric Skillets & Woks
3612
+ 4720 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Fondue Pots & Sets
3613
+ 4532 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers
3614
+ 739 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Egg Cookers
3615
+ 760 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Food Steamers
3616
+ 757 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Rice Cookers
3617
+ 737 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Slow Cookers
3618
+ 6523 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Thermal Cookers
3619
+ 6279 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Cookers & Steamers > Water Ovens
3620
+ 743 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Dehydrators
3621
+ 744 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Grinders & Mills
3622
+ 505666 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Mixers & Blenders
3623
+ 687 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Smokers
3624
+ 5103 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers
3625
+ 6548 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Chafing Dishes
3626
+ 5349 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Food Heat Lamps
3627
+ 504633 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Rice Keepers
3628
+ 4292 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Food Warmers > Steam Tables
3629
+ 681 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Freezers
3630
+ 5156 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Frozen Drink Makers
3631
+ 610 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Garbage Disposals
3632
+ 6524 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Gas Griddles
3633
+ 6543 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Hot Drink Makers
3634
+ 747 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Hot Plates
3635
+ 748 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Cream Makers
3636
+ 749 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Crushers & Shavers
3637
+ 4161 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Ice Makers
3638
+ 750 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Juicers
3639
+ 752 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Knife Sharpeners
3640
+ 753 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Microwave Ovens
3641
+ 3526 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Milk Frothers & Steamers
3642
+ 4482 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Mochi Makers
3643
+ 2985 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Outdoor Grills
3644
+ 683 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Ovens
3645
+ 755 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Pasta Makers
3646
+ 756 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Popcorn Makers
3647
+ 1015 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Portable Cooking Stoves
3648
+ 684 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Range Hoods
3649
+ 685 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Ranges
3650
+ 686 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Refrigerators
3651
+ 4495 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Roaster Ovens & Rotisseries
3652
+ 5577 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Soda Makers
3653
+ 5057 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Soy Milk Makers
3654
+ 4528 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Tea Makers
3655
+ 5289 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills
3656
+ 761 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Countertop & Toaster Ovens
3657
+ 6819 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Donut Makers
3658
+ 5318 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Muffin & Cupcake Makers
3659
+ 6278 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pizza Makers & Ovens
3660
+ 5291 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pizzelle Makers
3661
+ 6516 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Pretzel Makers
3662
+ 759 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Sandwich Makers
3663
+ 762 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Toasters
3664
+ 5292 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Tortilla & Flatbread Makers
3665
+ 764 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Toasters & Grills > Waffle Irons
3666
+ 688 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Trash Compactors
3667
+ 763 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Vacuum Sealers
3668
+ 3293 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Water Coolers
3669
+ 765 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Water Filters
3670
+ 4539 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Wine Fridges
3671
+ 766 - Home & Garden > Kitchen & Dining > Kitchen Appliances > Yogurt Makers
3672
+ 668 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils
3673
+ 639 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Aprons
3674
+ 3768 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Baking Peels
3675
+ 3347 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Basters
3676
+ 3430 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Basting Brushes
3677
+ 7149 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Beverage Dispensers
3678
+ 4630 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cake Decorating Supplies
3679
+ 6408 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cake Servers
3680
+ 4247 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Can Crushers
3681
+ 733 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Can Openers
3682
+ 5078 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Carving Forks
3683
+ 6522 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Channel Knives
3684
+ 653 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Colanders & Strainers
3685
+ 4777 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Condiment Dispensers
3686
+ 3850 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cookie Cutters
3687
+ 6342 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cookie Presses
3688
+ 7331 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Thermometer Accessories
3689
+ 3091 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Thermometers
3690
+ 3713 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Timers
3691
+ 5928 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooking Torches
3692
+ 3835 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cooling Racks
3693
+ 666 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Cutting Boards
3694
+ 3268 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Dish Racks & Drain Boards
3695
+ 6723 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Dough Wheels
3696
+ 6411 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knife Accessories
3697
+ 6412 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knife Accessories > Electric Knife Replacement Blades
3698
+ 741 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Electric Knives
3699
+ 5370 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Flour Sifters
3700
+ 505316 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food & Drink Stencils
3701
+ 3381 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers
3702
+ 3586 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Lobster & Crab Crackers
3703
+ 3685 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Nutcrackers
3704
+ 4214 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Crackers > Nutcrackers > Decorative Nutcrackers
3705
+ 3723 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Dispensers
3706
+ 3156 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Graters & Zesters
3707
+ 3521 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Peelers & Corers
3708
+ 7329 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Steaming Bags
3709
+ 6554 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Food Sticks & Skewers
3710
+ 503005 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Funnels
3711
+ 3385 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Garlic Presses
3712
+ 6787 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Gelatin Molds
3713
+ 4746 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ice Cube Trays
3714
+ 7485 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Jerky Guns
3715
+ 665 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Knives
3716
+ 8006 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Molds
3717
+ 2948 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers
3718
+ 6480 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Can Organizers
3719
+ 3479 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Drinkware Holders
3720
+ 6487 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Cabinet Organizers
3721
+ 3177 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Counter & Beverage Station Organizers
3722
+ 8012 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Kitchen Utensil Holders & Racks
3723
+ 5157 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Knife Blocks & Holders
3724
+ 3072 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Napkin Holders & Dispensers
3725
+ 3061 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Paper Towel Holders & Dispensers
3726
+ 3845 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Pot Racks
3727
+ 2344 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Spice Organizers
3728
+ 5059 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Straw Holders & Dispensers
3729
+ 6415 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Sugar Caddies
3730
+ 4322 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Toothpick Holders & Dispensers
3731
+ 3831 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Organizers > Utensil & Flatware Trays
3732
+ 3256 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers
3733
+ 3419 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Bench Scrapers
3734
+ 3086 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Bowl Scrapers
3735
+ 3633 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Scrapers > Grill Scrapers
3736
+ 5251 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Shears
3737
+ 3206 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Slicers
3738
+ 4765 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Kitchen Utensil Sets
3739
+ 3620 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ladles
3740
+ 3294 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mashers
3741
+ 3475 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Measuring Cups & Spoons
3742
+ 3248 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Meat Tenderizers
3743
+ 4530 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mixing Bowls
3744
+ 3999 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Mortars & Pestles
3745
+ 6526 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oil & Vinegar Dispensers
3746
+ 4771 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oven Bags
3747
+ 670 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Oven Mitts & Pot Holders
3748
+ 6749 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pasta Molds & Stamps
3749
+ 4332 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pastry Blenders
3750
+ 4708 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pastry Cloths
3751
+ 7365 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pizza Cutter Accessories
3752
+ 3421 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Pizza Cutters
3753
+ 5109 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Ricers
3754
+ 4705 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories
3755
+ 4706 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories > Rolling Pin Covers & Sleeves
3756
+ 4707 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pin Accessories > Rolling Pin Rings
3757
+ 3467 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Rolling Pins
3758
+ 6497 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Salad Dressing Mixers & Shakers
3759
+ 3914 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Salad Spinners
3760
+ 3175 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops
3761
+ 3202 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Ice Cream Scoops
3762
+ 3708 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Ice Scoops
3763
+ 3258 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Melon Ballers
3764
+ 502966 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Scoops > Popcorn & French Fry Scoops
3765
+ 6746 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sink Caddies
3766
+ 5080 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sink Mats & Grids
3767
+ 6388 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Slotted Spoons
3768
+ 3196 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spatulas
3769
+ 4788 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spice Grinder Accessories
3770
+ 4762 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spice Grinders
3771
+ 4334 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Spoon Rests
3772
+ 6974 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sugar Dispensers
3773
+ 7247 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Sushi Mats
3774
+ 4559 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Tea Strainers
3775
+ 4005 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Tongs
3776
+ 3597 - Home & Garden > Kitchen & Dining > Kitchen Tools & Utensils > Whisks
3777
+ 8161 - Home & Garden > Kitchen & Dining > Prefabricated Kitchens & Kitchenettes
3778
+ 672 - Home & Garden > Kitchen & Dining > Tableware
3779
+ 6740 - Home & Garden > Kitchen & Dining > Tableware > Coffee & Tea Sets
3780
+ 652 - Home & Garden > Kitchen & Dining > Tableware > Coffee Servers & Tea Pots
3781
+ 673 - Home & Garden > Kitchen & Dining > Tableware > Dinnerware
3782
+ 3498 - Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Bowls
3783
+ 5537 - Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Dinnerware Sets
3784
+ 3553 - Home & Garden > Kitchen & Dining > Tableware > Dinnerware > Plates
3785
+ 674 - Home & Garden > Kitchen & Dining > Tableware > Drinkware
3786
+ 7568 - Home & Garden > Kitchen & Dining > Tableware > Drinkware > Beer Glasses
3787
+ 6049 - Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Cups
3788
+ 6051 - Home & Garden > Kitchen & Dining > Tableware > Drinkware > Coffee & Tea Saucers
3789
+ 6958 - Home & Garden > Kitchen & Dining > Tableware > Drinkware > Drinkware Sets
3790
+ 2169 - Home & Garden > Kitchen & Dining > Tableware > Drinkware > Mugs
3791
+ 2694 - Home & Garden > Kitchen & Dining > Tableware > Drinkware > Shot Glasses
3792
+ 2712 - Home & Garden > Kitchen & Dining > Tableware > Drinkware > Stemware
3793
+ 2951 - Home & Garden > Kitchen & Dining > Tableware > Drinkware > Tumblers
3794
+ 675 - Home & Garden > Kitchen & Dining > Tableware > Flatware
3795
+ 6439 - Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopstick Accessories
3796
+ 3699 - Home & Garden > Kitchen & Dining > Tableware > Flatware > Chopsticks
3797
+ 5647 - Home & Garden > Kitchen & Dining > Tableware > Flatware > Flatware Sets
3798
+ 4015 - Home & Garden > Kitchen & Dining > Tableware > Flatware > Forks
3799
+ 3939 - Home & Garden > Kitchen & Dining > Tableware > Flatware > Spoons
3800
+ 3844 - Home & Garden > Kitchen & Dining > Tableware > Flatware > Table Knives
3801
+ 676 - Home & Garden > Kitchen & Dining > Tableware > Salt & Pepper Shakers
3802
+ 4026 - Home & Garden > Kitchen & Dining > Tableware > Serveware
3803
+ 6086 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Butter Dishes
3804
+ 5135 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Cake Boards
3805
+ 4372 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Cake Stands
3806
+ 7550 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Egg Cups
3807
+ 3703 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Gravy Boats
3808
+ 4735 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Punch Bowls
3809
+ 3330 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Pitchers & Carafes
3810
+ 3802 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Platters
3811
+ 4009 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Serving Trays
3812
+ 3373 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Sugar Bowls & Creamers
3813
+ 3941 - Home & Garden > Kitchen & Dining > Tableware > Serveware > Tureens
3814
+ 6425 - Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories
3815
+ 6434 - Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Punch Bowl Stands
3816
+ 6427 - Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Tureen Lids
3817
+ 6426 - Home & Garden > Kitchen & Dining > Tableware > Serveware Accessories > Tureen Stands
3818
+ 8046 - Home & Garden > Kitchen & Dining > Tableware > Tablecloth Clips & Weights
3819
+ 677 - Home & Garden > Kitchen & Dining > Tableware > Trivets
3820
+ 689 - Home & Garden > Lawn & Garden
3821
+ 2962 - Home & Garden > Lawn & Garden > Gardening
3822
+ 4085 - Home & Garden > Lawn & Garden > Gardening > Composting
3823
+ 690 - Home & Garden > Lawn & Garden > Gardening > Composting > Compost
3824
+ 6840 - Home & Garden > Lawn & Garden > Gardening > Composting > Compost Aerators
3825
+ 6436 - Home & Garden > Lawn & Garden > Gardening > Composting > Composters
3826
+ 691 - Home & Garden > Lawn & Garden > Gardening > Disease Control
3827
+ 113 - Home & Garden > Lawn & Garden > Gardening > Fertilizers
3828
+ 500033 - Home & Garden > Lawn & Garden > Gardening > Garden Pot Saucers & Trays
3829
+ 5632 - Home & Garden > Lawn & Garden > Gardening > Gardening Accessories
3830
+ 503756 - Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Gardening Scooters, Seats & Kneelers
3831
+ 5633 - Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Gardening Totes
3832
+ 7184 - Home & Garden > Lawn & Garden > Gardening > Gardening Accessories > Potting Benches
3833
+ 505326 - Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories
3834
+ 505322 - Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories > Gardening Tool Handles
3835
+ 505321 - Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories > Gardening Tool Heads
3836
+ 4972 - Home & Garden > Lawn & Garden > Gardening > Gardening Tool Accessories > Wheelbarrow Parts
3837
+ 3173 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools
3838
+ 7537 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Bulb Planting Tools
3839
+ 4000 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Cultivating Tools
3840
+ 3071 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Forks
3841
+ 505292 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Sickles & Machetes
3842
+ 3644 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Gardening Trowels
3843
+ 1967 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Lawn & Garden Sprayers
3844
+ 499922 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Lawn Rollers
3845
+ 6967 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Pruning Saws
3846
+ 3841 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Pruning Shears
3847
+ 3388 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Rakes
3848
+ 2147 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Shovels & Spades
3849
+ 3828 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Spreaders
3850
+ 3616 - Home & Garden > Lawn & Garden > Gardening > Gardening Tools > Wheelbarrows
3851
+ 693 - Home & Garden > Lawn & Garden > Gardening > Greenhouses
3852
+ 3103 - Home & Garden > Lawn & Garden > Gardening > Herbicides
3853
+ 6381 - Home & Garden > Lawn & Garden > Gardening > Landscape Fabric
3854
+ 6413 - Home & Garden > Lawn & Garden > Gardening > Landscape Fabric Accessories
3855
+ 6422 - Home & Garden > Lawn & Garden > Gardening > Landscape Fabric Accessories > Landscape Fabric Staples & Pins
3856
+ 6421 - Home & Garden > Lawn & Garden > Gardening > Landscape Fabric Accessories > Landscape Fabric Tape
3857
+ 2988 - Home & Garden > Lawn & Garden > Gardening > Mulch
3858
+ 499894 - Home & Garden > Lawn & Garden > Gardening > Plant Cages & Supports
3859
+ 6428 - Home & Garden > Lawn & Garden > Gardening > Plant Stands
3860
+ 499962 - Home & Garden > Lawn & Garden > Gardening > Pot & Planter Liners
3861
+ 721 - Home & Garden > Lawn & Garden > Gardening > Pots & Planters
3862
+ 6834 - Home & Garden > Lawn & Garden > Gardening > Rain Barrels
3863
+ 1794 - Home & Garden > Lawn & Garden > Gardening > Sands & Soils
3864
+ 543677 - Home & Garden > Lawn & Garden > Gardening > Sands & Soils > Sand
3865
+ 543678 - Home & Garden > Lawn & Garden > Gardening > Sands & Soils > Soil
3866
+ 2918 - Home & Garden > Lawn & Garden > Outdoor Living
3867
+ 499908 - Home & Garden > Lawn & Garden > Outdoor Living > Awning Accessories
3868
+ 499907 - Home & Garden > Lawn & Garden > Outdoor Living > Awnings
3869
+ 6737 - Home & Garden > Lawn & Garden > Outdoor Living > Hammock Parts & Accessories
3870
+ 717 - Home & Garden > Lawn & Garden > Outdoor Living > Hammocks
3871
+ 5910 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets
3872
+ 5911 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Beach Mats
3873
+ 5913 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Picnic Blankets
3874
+ 5912 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Blankets > Poncho Liners
3875
+ 2613 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures
3876
+ 716 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopies & Gazebos
3877
+ 6105 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories
3878
+ 6107 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Enclosure Kits
3879
+ 6106 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Frames
3880
+ 6108 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy & Gazebo Tops
3881
+ 7423 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy Poles
3882
+ 7424 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Canopy & Gazebo Accessories > Canopy Weights
3883
+ 703 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Garden Arches, Trellises, Arbors & Pergolas
3884
+ 700 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Garden Bridges
3885
+ 720 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Structures > Sheds, Garages & Carports
3886
+ 6751 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories
3887
+ 7108 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella & Sunshade Fabric
3888
+ 5493 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Bases
3889
+ 7107 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Covers
3890
+ 499948 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Enclosure Kits
3891
+ 8020 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrella & Sunshade Accessories > Outdoor Umbrella Lights
3892
+ 719 - Home & Garden > Lawn & Garden > Outdoor Living > Outdoor Umbrellas & Sunshades
3893
+ 499955 - Home & Garden > Lawn & Garden > Outdoor Living > Porch Swing Accessories
3894
+ 718 - Home & Garden > Lawn & Garden > Outdoor Living > Porch Swings
3895
+ 3798 - Home & Garden > Lawn & Garden > Outdoor Power Equipment
3896
+ 3610 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Chainsaws
3897
+ 2218 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Grass Edgers
3898
+ 3120 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Hedge Trimmers
3899
+ 500034 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Aerators & Dethatchers
3900
+ 694 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers
3901
+ 3311 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Riding Mowers
3902
+ 6788 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Robotic Mowers
3903
+ 6258 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Tow-Behind Mowers
3904
+ 3730 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Mowers > Walk-Behind Mowers
3905
+ 6789 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Lawn Vacuums
3906
+ 3340 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Leaf Blowers
3907
+ 7332 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Outdoor Power Equipment Base Units
3908
+ 7245 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Outdoor Power Equipment Sets
3909
+ 500016 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Power Sweepers
3910
+ 2204 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Power Tillers & Cultivators
3911
+ 1226 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Pressure Washers
3912
+ 1541 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Snow Blowers
3913
+ 5866 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Tractors
3914
+ 1223 - Home & Garden > Lawn & Garden > Outdoor Power Equipment > Weed Trimmers
3915
+ 4564 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories
3916
+ 4565 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories
3917
+ 4647 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories > Chainsaw Bars
3918
+ 4646 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Chainsaw Accessories > Chainsaw Chains
3919
+ 7563 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Grass Edger Accessories
3920
+ 7265 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Hedge Trimmer Accessories
3921
+ 4566 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories
3922
+ 6542 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Brush Mower Attachments
3923
+ 4645 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Bags
3924
+ 4643 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Belts
3925
+ 4641 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Blades
3926
+ 4642 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Covers
3927
+ 499923 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Mulch Kits
3928
+ 499960 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Mulch Plugs & Plates
3929
+ 4644 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Pulleys & Idlers
3930
+ 499872 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Tire Tubes
3931
+ 6095 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Tires
3932
+ 6094 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Mower Wheels
3933
+ 499921 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Striping Kits
3934
+ 6541 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Lawn Mower Accessories > Lawn Sweepers
3935
+ 7168 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Leaf Blower Accessories
3936
+ 7171 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Leaf Blower Accessories > Leaf Blower Tubes
3937
+ 8485 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments
3938
+ 7564 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Grass Edger Attachments
3939
+ 8487 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Ground & Leaf Blower Attachments
3940
+ 7334 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Hedge Trimmer Attachments
3941
+ 8489 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Pole Saw Attachments
3942
+ 8488 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Tiller & Cultivator Attachments
3943
+ 7335 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Multifunction Outdoor Power Equipment Attachments > Weed Trimmer Attachments
3944
+ 7333 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Outdoor Power Equipment Batteries
3945
+ 6328 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Pressure Washer Accessories
3946
+ 4567 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Snow Blower Accessories
3947
+ 5867 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories
3948
+ 499880 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories > Tractor Tires
3949
+ 499881 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Tractor Parts & Accessories > Tractor Wheels
3950
+ 7169 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories
3951
+ 7170 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories > Weed Trimmer Blades & Spools
3952
+ 8034 - Home & Garden > Lawn & Garden > Outdoor Power Equipment Accessories > Weed Trimmer Accessories > Weed Trimmer Spool Covers
3953
+ 5362 - Home & Garden > Lawn & Garden > Snow Removal
3954
+ 5364 - Home & Garden > Lawn & Garden > Snow Removal > Ice Scrapers & Snow Brushes
3955
+ 5363 - Home & Garden > Lawn & Garden > Snow Removal > Snow Shovels
3956
+ 3568 - Home & Garden > Lawn & Garden > Watering & Irrigation
3957
+ 4718 - Home & Garden > Lawn & Gar