source: binary-improvements2/weblegacy/leaflet/measure/leaflet-measure.js@ 407

Last change on this file since 407 was 253, checked in by alloc, 9 years ago

Fixes 6_8_10

File size: 172.1 KB
Line 
1(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){
2/* MIT license */
3var convert = require("color-convert"),
4 string = require("color-string");
5
6var Color = function(obj) {
7 if (obj instanceof Color) return obj;
8 if (! (this instanceof Color)) return new Color(obj);
9
10 this.values = {
11 rgb: [0, 0, 0],
12 hsl: [0, 0, 0],
13 hsv: [0, 0, 0],
14 hwb: [0, 0, 0],
15 cmyk: [0, 0, 0, 0],
16 alpha: 1
17 }
18
19 // parse Color() argument
20 if (typeof obj == "string") {
21 var vals = string.getRgba(obj);
22 if (vals) {
23 this.setValues("rgb", vals);
24 }
25 else if(vals = string.getHsla(obj)) {
26 this.setValues("hsl", vals);
27 }
28 else if(vals = string.getHwb(obj)) {
29 this.setValues("hwb", vals);
30 }
31 else {
32 throw new Error("Unable to parse color from string \"" + obj + "\"");
33 }
34 }
35 else if (typeof obj == "object") {
36 var vals = obj;
37 if(vals["r"] !== undefined || vals["red"] !== undefined) {
38 this.setValues("rgb", vals)
39 }
40 else if(vals["l"] !== undefined || vals["lightness"] !== undefined) {
41 this.setValues("hsl", vals)
42 }
43 else if(vals["v"] !== undefined || vals["value"] !== undefined) {
44 this.setValues("hsv", vals)
45 }
46 else if(vals["w"] !== undefined || vals["whiteness"] !== undefined) {
47 this.setValues("hwb", vals)
48 }
49 else if(vals["c"] !== undefined || vals["cyan"] !== undefined) {
50 this.setValues("cmyk", vals)
51 }
52 else {
53 throw new Error("Unable to parse color from object " + JSON.stringify(obj));
54 }
55 }
56}
57
58Color.prototype = {
59 rgb: function (vals) {
60 return this.setSpace("rgb", arguments);
61 },
62 hsl: function(vals) {
63 return this.setSpace("hsl", arguments);
64 },
65 hsv: function(vals) {
66 return this.setSpace("hsv", arguments);
67 },
68 hwb: function(vals) {
69 return this.setSpace("hwb", arguments);
70 },
71 cmyk: function(vals) {
72 return this.setSpace("cmyk", arguments);
73 },
74
75 rgbArray: function() {
76 return this.values.rgb;
77 },
78 hslArray: function() {
79 return this.values.hsl;
80 },
81 hsvArray: function() {
82 return this.values.hsv;
83 },
84 hwbArray: function() {
85 if (this.values.alpha !== 1) {
86 return this.values.hwb.concat([this.values.alpha])
87 }
88 return this.values.hwb;
89 },
90 cmykArray: function() {
91 return this.values.cmyk;
92 },
93 rgbaArray: function() {
94 var rgb = this.values.rgb;
95 return rgb.concat([this.values.alpha]);
96 },
97 hslaArray: function() {
98 var hsl = this.values.hsl;
99 return hsl.concat([this.values.alpha]);
100 },
101 alpha: function(val) {
102 if (val === undefined) {
103 return this.values.alpha;
104 }
105 this.setValues("alpha", val);
106 return this;
107 },
108
109 red: function(val) {
110 return this.setChannel("rgb", 0, val);
111 },
112 green: function(val) {
113 return this.setChannel("rgb", 1, val);
114 },
115 blue: function(val) {
116 return this.setChannel("rgb", 2, val);
117 },
118 hue: function(val) {
119 return this.setChannel("hsl", 0, val);
120 },
121 saturation: function(val) {
122 return this.setChannel("hsl", 1, val);
123 },
124 lightness: function(val) {
125 return this.setChannel("hsl", 2, val);
126 },
127 saturationv: function(val) {
128 return this.setChannel("hsv", 1, val);
129 },
130 whiteness: function(val) {
131 return this.setChannel("hwb", 1, val);
132 },
133 blackness: function(val) {
134 return this.setChannel("hwb", 2, val);
135 },
136 value: function(val) {
137 return this.setChannel("hsv", 2, val);
138 },
139 cyan: function(val) {
140 return this.setChannel("cmyk", 0, val);
141 },
142 magenta: function(val) {
143 return this.setChannel("cmyk", 1, val);
144 },
145 yellow: function(val) {
146 return this.setChannel("cmyk", 2, val);
147 },
148 black: function(val) {
149 return this.setChannel("cmyk", 3, val);
150 },
151
152 hexString: function() {
153 return string.hexString(this.values.rgb);
154 },
155 rgbString: function() {
156 return string.rgbString(this.values.rgb, this.values.alpha);
157 },
158 rgbaString: function() {
159 return string.rgbaString(this.values.rgb, this.values.alpha);
160 },
161 percentString: function() {
162 return string.percentString(this.values.rgb, this.values.alpha);
163 },
164 hslString: function() {
165 return string.hslString(this.values.hsl, this.values.alpha);
166 },
167 hslaString: function() {
168 return string.hslaString(this.values.hsl, this.values.alpha);
169 },
170 hwbString: function() {
171 return string.hwbString(this.values.hwb, this.values.alpha);
172 },
173 keyword: function() {
174 return string.keyword(this.values.rgb, this.values.alpha);
175 },
176
177 rgbNumber: function() {
178 return (this.values.rgb[0] << 16) | (this.values.rgb[1] << 8) | this.values.rgb[2];
179 },
180
181 luminosity: function() {
182 // http://www.w3.org/TR/WCAG20/#relativeluminancedef
183 var rgb = this.values.rgb;
184 var lum = [];
185 for (var i = 0; i < rgb.length; i++) {
186 var chan = rgb[i] / 255;
187 lum[i] = (chan <= 0.03928) ? chan / 12.92
188 : Math.pow(((chan + 0.055) / 1.055), 2.4)
189 }
190 return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
191 },
192
193 contrast: function(color2) {
194 // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
195 var lum1 = this.luminosity();
196 var lum2 = color2.luminosity();
197 if (lum1 > lum2) {
198 return (lum1 + 0.05) / (lum2 + 0.05)
199 };
200 return (lum2 + 0.05) / (lum1 + 0.05);
201 },
202
203 level: function(color2) {
204 var contrastRatio = this.contrast(color2);
205 return (contrastRatio >= 7.1)
206 ? 'AAA'
207 : (contrastRatio >= 4.5)
208 ? 'AA'
209 : '';
210 },
211
212 dark: function() {
213 // YIQ equation from http://24ways.org/2010/calculating-color-contrast
214 var rgb = this.values.rgb,
215 yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
216 return yiq < 128;
217 },
218
219 light: function() {
220 return !this.dark();
221 },
222
223 negate: function() {
224 var rgb = []
225 for (var i = 0; i < 3; i++) {
226 rgb[i] = 255 - this.values.rgb[i];
227 }
228 this.setValues("rgb", rgb);
229 return this;
230 },
231
232 lighten: function(ratio) {
233 this.values.hsl[2] += this.values.hsl[2] * ratio;
234 this.setValues("hsl", this.values.hsl);
235 return this;
236 },
237
238 darken: function(ratio) {
239 this.values.hsl[2] -= this.values.hsl[2] * ratio;
240 this.setValues("hsl", this.values.hsl);
241 return this;
242 },
243
244 saturate: function(ratio) {
245 this.values.hsl[1] += this.values.hsl[1] * ratio;
246 this.setValues("hsl", this.values.hsl);
247 return this;
248 },
249
250 desaturate: function(ratio) {
251 this.values.hsl[1] -= this.values.hsl[1] * ratio;
252 this.setValues("hsl", this.values.hsl);
253 return this;
254 },
255
256 whiten: function(ratio) {
257 this.values.hwb[1] += this.values.hwb[1] * ratio;
258 this.setValues("hwb", this.values.hwb);
259 return this;
260 },
261
262 blacken: function(ratio) {
263 this.values.hwb[2] += this.values.hwb[2] * ratio;
264 this.setValues("hwb", this.values.hwb);
265 return this;
266 },
267
268 greyscale: function() {
269 var rgb = this.values.rgb;
270 // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
271 var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
272 this.setValues("rgb", [val, val, val]);
273 return this;
274 },
275
276 clearer: function(ratio) {
277 this.setValues("alpha", this.values.alpha - (this.values.alpha * ratio));
278 return this;
279 },
280
281 opaquer: function(ratio) {
282 this.setValues("alpha", this.values.alpha + (this.values.alpha * ratio));
283 return this;
284 },
285
286 rotate: function(degrees) {
287 var hue = this.values.hsl[0];
288 hue = (hue + degrees) % 360;
289 hue = hue < 0 ? 360 + hue : hue;
290 this.values.hsl[0] = hue;
291 this.setValues("hsl", this.values.hsl);
292 return this;
293 },
294
295 mix: function(color2, weight) {
296 weight = 1 - (weight == null ? 0.5 : weight);
297
298 // algorithm from Sass's mix(). Ratio of first color in mix is
299 // determined by the alphas of both colors and the weight
300 var t1 = weight * 2 - 1,
301 d = this.alpha() - color2.alpha();
302
303 var weight1 = (((t1 * d == -1) ? t1 : (t1 + d) / (1 + t1 * d)) + 1) / 2;
304 var weight2 = 1 - weight1;
305
306 var rgb = this.rgbArray();
307 var rgb2 = color2.rgbArray();
308
309 for (var i = 0; i < rgb.length; i++) {
310 rgb[i] = rgb[i] * weight1 + rgb2[i] * weight2;
311 }
312 this.setValues("rgb", rgb);
313
314 var alpha = this.alpha() * weight + color2.alpha() * (1 - weight);
315 this.setValues("alpha", alpha);
316
317 return this;
318 },
319
320 toJSON: function() {
321 return this.rgb();
322 },
323
324 clone: function() {
325 return new Color(this.rgb());
326 }
327}
328
329
330Color.prototype.getValues = function(space) {
331 var vals = {};
332 for (var i = 0; i < space.length; i++) {
333 vals[space.charAt(i)] = this.values[space][i];
334 }
335 if (this.values.alpha != 1) {
336 vals["a"] = this.values.alpha;
337 }
338 // {r: 255, g: 255, b: 255, a: 0.4}
339 return vals;
340}
341
342Color.prototype.setValues = function(space, vals) {
343 var spaces = {
344 "rgb": ["red", "green", "blue"],
345 "hsl": ["hue", "saturation", "lightness"],
346 "hsv": ["hue", "saturation", "value"],
347 "hwb": ["hue", "whiteness", "blackness"],
348 "cmyk": ["cyan", "magenta", "yellow", "black"]
349 };
350
351 var maxes = {
352 "rgb": [255, 255, 255],
353 "hsl": [360, 100, 100],
354 "hsv": [360, 100, 100],
355 "hwb": [360, 100, 100],
356 "cmyk": [100, 100, 100, 100]
357 };
358
359 var alpha = 1;
360 if (space == "alpha") {
361 alpha = vals;
362 }
363 else if (vals.length) {
364 // [10, 10, 10]
365 this.values[space] = vals.slice(0, space.length);
366 alpha = vals[space.length];
367 }
368 else if (vals[space.charAt(0)] !== undefined) {
369 // {r: 10, g: 10, b: 10}
370 for (var i = 0; i < space.length; i++) {
371 this.values[space][i] = vals[space.charAt(i)];
372 }
373 alpha = vals.a;
374 }
375 else if (vals[spaces[space][0]] !== undefined) {
376 // {red: 10, green: 10, blue: 10}
377 var chans = spaces[space];
378 for (var i = 0; i < space.length; i++) {
379 this.values[space][i] = vals[chans[i]];
380 }
381 alpha = vals.alpha;
382 }
383 this.values.alpha = Math.max(0, Math.min(1, (alpha !== undefined ? alpha : this.values.alpha) ));
384 if (space == "alpha") {
385 return;
386 }
387
388 // cap values of the space prior converting all values
389 for (var i = 0; i < space.length; i++) {
390 var capped = Math.max(0, Math.min(maxes[space][i], this.values[space][i]));
391 this.values[space][i] = Math.round(capped);
392 }
393
394 // convert to all the other color spaces
395 for (var sname in spaces) {
396 if (sname != space) {
397 this.values[sname] = convert[space][sname](this.values[space])
398 }
399
400 // cap values
401 for (var i = 0; i < sname.length; i++) {
402 var capped = Math.max(0, Math.min(maxes[sname][i], this.values[sname][i]));
403 this.values[sname][i] = Math.round(capped);
404 }
405 }
406 return true;
407}
408
409Color.prototype.setSpace = function(space, args) {
410 var vals = args[0];
411 if (vals === undefined) {
412 // color.rgb()
413 return this.getValues(space);
414 }
415 // color.rgb(10, 10, 10)
416 if (typeof vals == "number") {
417 vals = Array.prototype.slice.call(args);
418 }
419 this.setValues(space, vals);
420 return this;
421}
422
423Color.prototype.setChannel = function(space, index, val) {
424 if (val === undefined) {
425 // color.red()
426 return this.values[space][index];
427 }
428 // color.red(100)
429 this.values[space][index] = val;
430 this.setValues(space, this.values[space]);
431 return this;
432}
433
434module.exports = Color;
435
436},{"color-convert":3,"color-string":4}],2:[function(require,module,exports){
437/* MIT license */
438
439module.exports = {
440 rgb2hsl: rgb2hsl,
441 rgb2hsv: rgb2hsv,
442 rgb2hwb: rgb2hwb,
443 rgb2cmyk: rgb2cmyk,
444 rgb2keyword: rgb2keyword,
445 rgb2xyz: rgb2xyz,
446 rgb2lab: rgb2lab,
447 rgb2lch: rgb2lch,
448
449 hsl2rgb: hsl2rgb,
450 hsl2hsv: hsl2hsv,
451 hsl2hwb: hsl2hwb,
452 hsl2cmyk: hsl2cmyk,
453 hsl2keyword: hsl2keyword,
454
455 hsv2rgb: hsv2rgb,
456 hsv2hsl: hsv2hsl,
457 hsv2hwb: hsv2hwb,
458 hsv2cmyk: hsv2cmyk,
459 hsv2keyword: hsv2keyword,
460
461 hwb2rgb: hwb2rgb,
462 hwb2hsl: hwb2hsl,
463 hwb2hsv: hwb2hsv,
464 hwb2cmyk: hwb2cmyk,
465 hwb2keyword: hwb2keyword,
466
467 cmyk2rgb: cmyk2rgb,
468 cmyk2hsl: cmyk2hsl,
469 cmyk2hsv: cmyk2hsv,
470 cmyk2hwb: cmyk2hwb,
471 cmyk2keyword: cmyk2keyword,
472
473 keyword2rgb: keyword2rgb,
474 keyword2hsl: keyword2hsl,
475 keyword2hsv: keyword2hsv,
476 keyword2hwb: keyword2hwb,
477 keyword2cmyk: keyword2cmyk,
478 keyword2lab: keyword2lab,
479 keyword2xyz: keyword2xyz,
480
481 xyz2rgb: xyz2rgb,
482 xyz2lab: xyz2lab,
483 xyz2lch: xyz2lch,
484
485 lab2xyz: lab2xyz,
486 lab2rgb: lab2rgb,
487 lab2lch: lab2lch,
488
489 lch2lab: lch2lab,
490 lch2xyz: lch2xyz,
491 lch2rgb: lch2rgb
492}
493
494
495function rgb2hsl(rgb) {
496 var r = rgb[0]/255,
497 g = rgb[1]/255,
498 b = rgb[2]/255,
499 min = Math.min(r, g, b),
500 max = Math.max(r, g, b),
501 delta = max - min,
502 h, s, l;
503
504 if (max == min)
505 h = 0;
506 else if (r == max)
507 h = (g - b) / delta;
508 else if (g == max)
509 h = 2 + (b - r) / delta;
510 else if (b == max)
511 h = 4 + (r - g)/ delta;
512
513 h = Math.min(h * 60, 360);
514
515 if (h < 0)
516 h += 360;
517
518 l = (min + max) / 2;
519
520 if (max == min)
521 s = 0;
522 else if (l <= 0.5)
523 s = delta / (max + min);
524 else
525 s = delta / (2 - max - min);
526
527 return [h, s * 100, l * 100];
528}
529
530function rgb2hsv(rgb) {
531 var r = rgb[0],
532 g = rgb[1],
533 b = rgb[2],
534 min = Math.min(r, g, b),
535 max = Math.max(r, g, b),
536 delta = max - min,
537 h, s, v;
538
539 if (max == 0)
540 s = 0;
541 else
542 s = (delta/max * 1000)/10;
543
544 if (max == min)
545 h = 0;
546 else if (r == max)
547 h = (g - b) / delta;
548 else if (g == max)
549 h = 2 + (b - r) / delta;
550 else if (b == max)
551 h = 4 + (r - g) / delta;
552
553 h = Math.min(h * 60, 360);
554
555 if (h < 0)
556 h += 360;
557
558 v = ((max / 255) * 1000) / 10;
559
560 return [h, s, v];
561}
562
563function rgb2hwb(rgb) {
564 var r = rgb[0],
565 g = rgb[1],
566 b = rgb[2],
567 h = rgb2hsl(rgb)[0],
568 w = 1/255 * Math.min(r, Math.min(g, b)),
569 b = 1 - 1/255 * Math.max(r, Math.max(g, b));
570
571 return [h, w * 100, b * 100];
572}
573
574function rgb2cmyk(rgb) {
575 var r = rgb[0] / 255,
576 g = rgb[1] / 255,
577 b = rgb[2] / 255,
578 c, m, y, k;
579
580 k = Math.min(1 - r, 1 - g, 1 - b);
581 c = (1 - r - k) / (1 - k) || 0;
582 m = (1 - g - k) / (1 - k) || 0;
583 y = (1 - b - k) / (1 - k) || 0;
584 return [c * 100, m * 100, y * 100, k * 100];
585}
586
587function rgb2keyword(rgb) {
588 return reverseKeywords[JSON.stringify(rgb)];
589}
590
591function rgb2xyz(rgb) {
592 var r = rgb[0] / 255,
593 g = rgb[1] / 255,
594 b = rgb[2] / 255;
595
596 // assume sRGB
597 r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
598 g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
599 b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
600
601 var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
602 var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
603 var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
604
605 return [x * 100, y *100, z * 100];
606}
607
608function rgb2lab(rgb) {
609 var xyz = rgb2xyz(rgb),
610 x = xyz[0],
611 y = xyz[1],
612 z = xyz[2],
613 l, a, b;
614
615 x /= 95.047;
616 y /= 100;
617 z /= 108.883;
618
619 x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
620 y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
621 z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
622
623 l = (116 * y) - 16;
624 a = 500 * (x - y);
625 b = 200 * (y - z);
626
627 return [l, a, b];
628}
629
630function rgb2lch(args) {
631 return lab2lch(rgb2lab(args));
632}
633
634function hsl2rgb(hsl) {
635 var h = hsl[0] / 360,
636 s = hsl[1] / 100,
637 l = hsl[2] / 100,
638 t1, t2, t3, rgb, val;
639
640 if (s == 0) {
641 val = l * 255;
642 return [val, val, val];
643 }
644
645 if (l < 0.5)
646 t2 = l * (1 + s);
647 else
648 t2 = l + s - l * s;
649 t1 = 2 * l - t2;
650
651 rgb = [0, 0, 0];
652 for (var i = 0; i < 3; i++) {
653 t3 = h + 1 / 3 * - (i - 1);
654 t3 < 0 && t3++;
655 t3 > 1 && t3--;
656
657 if (6 * t3 < 1)
658 val = t1 + (t2 - t1) * 6 * t3;
659 else if (2 * t3 < 1)
660 val = t2;
661 else if (3 * t3 < 2)
662 val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
663 else
664 val = t1;
665
666 rgb[i] = val * 255;
667 }
668
669 return rgb;
670}
671
672function hsl2hsv(hsl) {
673 var h = hsl[0],
674 s = hsl[1] / 100,
675 l = hsl[2] / 100,
676 sv, v;
677 l *= 2;
678 s *= (l <= 1) ? l : 2 - l;
679 v = (l + s) / 2;
680 sv = (2 * s) / (l + s);
681 return [h, sv * 100, v * 100];
682}
683
684function hsl2hwb(args) {
685 return rgb2hwb(hsl2rgb(args));
686}
687
688function hsl2cmyk(args) {
689 return rgb2cmyk(hsl2rgb(args));
690}
691
692function hsl2keyword(args) {
693 return rgb2keyword(hsl2rgb(args));
694}
695
696
697function hsv2rgb(hsv) {
698 var h = hsv[0] / 60,
699 s = hsv[1] / 100,
700 v = hsv[2] / 100,
701 hi = Math.floor(h) % 6;
702
703 var f = h - Math.floor(h),
704 p = 255 * v * (1 - s),
705 q = 255 * v * (1 - (s * f)),
706 t = 255 * v * (1 - (s * (1 - f))),
707 v = 255 * v;
708
709 switch(hi) {
710 case 0:
711 return [v, t, p];
712 case 1:
713 return [q, v, p];
714 case 2:
715 return [p, v, t];
716 case 3:
717 return [p, q, v];
718 case 4:
719 return [t, p, v];
720 case 5:
721 return [v, p, q];
722 }
723}
724
725function hsv2hsl(hsv) {
726 var h = hsv[0],
727 s = hsv[1] / 100,
728 v = hsv[2] / 100,
729 sl, l;
730
731 l = (2 - s) * v;
732 sl = s * v;
733 sl /= (l <= 1) ? l : 2 - l;
734 sl = sl || 0;
735 l /= 2;
736 return [h, sl * 100, l * 100];
737}
738
739function hsv2hwb(args) {
740 return rgb2hwb(hsv2rgb(args))
741}
742
743function hsv2cmyk(args) {
744 return rgb2cmyk(hsv2rgb(args));
745}
746
747function hsv2keyword(args) {
748 return rgb2keyword(hsv2rgb(args));
749}
750
751// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
752function hwb2rgb(hwb) {
753 var h = hwb[0] / 360,
754 wh = hwb[1] / 100,
755 bl = hwb[2] / 100,
756 ratio = wh + bl,
757 i, v, f, n;
758
759 // wh + bl cant be > 1
760 if (ratio > 1) {
761 wh /= ratio;
762 bl /= ratio;
763 }
764
765 i = Math.floor(6 * h);
766 v = 1 - bl;
767 f = 6 * h - i;
768 if ((i & 0x01) != 0) {
769 f = 1 - f;
770 }
771 n = wh + f * (v - wh); // linear interpolation
772
773 switch (i) {
774 default:
775 case 6:
776 case 0: r = v; g = n; b = wh; break;
777 case 1: r = n; g = v; b = wh; break;
778 case 2: r = wh; g = v; b = n; break;
779 case 3: r = wh; g = n; b = v; break;
780 case 4: r = n; g = wh; b = v; break;
781 case 5: r = v; g = wh; b = n; break;
782 }
783
784 return [r * 255, g * 255, b * 255];
785}
786
787function hwb2hsl(args) {
788 return rgb2hsl(hwb2rgb(args));
789}
790
791function hwb2hsv(args) {
792 return rgb2hsv(hwb2rgb(args));
793}
794
795function hwb2cmyk(args) {
796 return rgb2cmyk(hwb2rgb(args));
797}
798
799function hwb2keyword(args) {
800 return rgb2keyword(hwb2rgb(args));
801}
802
803function cmyk2rgb(cmyk) {
804 var c = cmyk[0] / 100,
805 m = cmyk[1] / 100,
806 y = cmyk[2] / 100,
807 k = cmyk[3] / 100,
808 r, g, b;
809
810 r = 1 - Math.min(1, c * (1 - k) + k);
811 g = 1 - Math.min(1, m * (1 - k) + k);
812 b = 1 - Math.min(1, y * (1 - k) + k);
813 return [r * 255, g * 255, b * 255];
814}
815
816function cmyk2hsl(args) {
817 return rgb2hsl(cmyk2rgb(args));
818}
819
820function cmyk2hsv(args) {
821 return rgb2hsv(cmyk2rgb(args));
822}
823
824function cmyk2hwb(args) {
825 return rgb2hwb(cmyk2rgb(args));
826}
827
828function cmyk2keyword(args) {
829 return rgb2keyword(cmyk2rgb(args));
830}
831
832
833function xyz2rgb(xyz) {
834 var x = xyz[0] / 100,
835 y = xyz[1] / 100,
836 z = xyz[2] / 100,
837 r, g, b;
838
839 r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
840 g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
841 b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
842
843 // assume sRGB
844 r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
845 : r = (r * 12.92);
846
847 g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
848 : g = (g * 12.92);
849
850 b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
851 : b = (b * 12.92);
852
853 r = Math.min(Math.max(0, r), 1);
854 g = Math.min(Math.max(0, g), 1);
855 b = Math.min(Math.max(0, b), 1);
856
857 return [r * 255, g * 255, b * 255];
858}
859
860function xyz2lab(xyz) {
861 var x = xyz[0],
862 y = xyz[1],
863 z = xyz[2],
864 l, a, b;
865
866 x /= 95.047;
867 y /= 100;
868 z /= 108.883;
869
870 x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
871 y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
872 z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
873
874 l = (116 * y) - 16;
875 a = 500 * (x - y);
876 b = 200 * (y - z);
877
878 return [l, a, b];
879}
880
881function xyz2lch(args) {
882 return lab2lch(xyz2lab(args));
883}
884
885function lab2xyz(lab) {
886 var l = lab[0],
887 a = lab[1],
888 b = lab[2],
889 x, y, z, y2;
890
891 if (l <= 8) {
892 y = (l * 100) / 903.3;
893 y2 = (7.787 * (y / 100)) + (16 / 116);
894 } else {
895 y = 100 * Math.pow((l + 16) / 116, 3);
896 y2 = Math.pow(y / 100, 1/3);
897 }
898
899 x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
900
901 z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
902
903 return [x, y, z];
904}
905
906function lab2lch(lab) {
907 var l = lab[0],
908 a = lab[1],
909 b = lab[2],
910 hr, h, c;
911
912 hr = Math.atan2(b, a);
913 h = hr * 360 / 2 / Math.PI;
914 if (h < 0) {
915 h += 360;
916 }
917 c = Math.sqrt(a * a + b * b);
918 return [l, c, h];
919}
920
921function lab2rgb(args) {
922 return xyz2rgb(lab2xyz(args));
923}
924
925function lch2lab(lch) {
926 var l = lch[0],
927 c = lch[1],
928 h = lch[2],
929 a, b, hr;
930
931 hr = h / 360 * 2 * Math.PI;
932 a = c * Math.cos(hr);
933 b = c * Math.sin(hr);
934 return [l, a, b];
935}
936
937function lch2xyz(args) {
938 return lab2xyz(lch2lab(args));
939}
940
941function lch2rgb(args) {
942 return lab2rgb(lch2lab(args));
943}
944
945function keyword2rgb(keyword) {
946 return cssKeywords[keyword];
947}
948
949function keyword2hsl(args) {
950 return rgb2hsl(keyword2rgb(args));
951}
952
953function keyword2hsv(args) {
954 return rgb2hsv(keyword2rgb(args));
955}
956
957function keyword2hwb(args) {
958 return rgb2hwb(keyword2rgb(args));
959}
960
961function keyword2cmyk(args) {
962 return rgb2cmyk(keyword2rgb(args));
963}
964
965function keyword2lab(args) {
966 return rgb2lab(keyword2rgb(args));
967}
968
969function keyword2xyz(args) {
970 return rgb2xyz(keyword2rgb(args));
971}
972
973var cssKeywords = {
974 aliceblue: [240,248,255],
975 antiquewhite: [250,235,215],
976 aqua: [0,255,255],
977 aquamarine: [127,255,212],
978 azure: [240,255,255],
979 beige: [245,245,220],
980 bisque: [255,228,196],
981 black: [0,0,0],
982 blanchedalmond: [255,235,205],
983 blue: [0,0,255],
984 blueviolet: [138,43,226],
985 brown: [165,42,42],
986 burlywood: [222,184,135],
987 cadetblue: [95,158,160],
988 chartreuse: [127,255,0],
989 chocolate: [210,105,30],
990 coral: [255,127,80],
991 cornflowerblue: [100,149,237],
992 cornsilk: [255,248,220],
993 crimson: [220,20,60],
994 cyan: [0,255,255],
995 darkblue: [0,0,139],
996 darkcyan: [0,139,139],
997 darkgoldenrod: [184,134,11],
998 darkgray: [169,169,169],
999 darkgreen: [0,100,0],
1000 darkgrey: [169,169,169],
1001 darkkhaki: [189,183,107],
1002 darkmagenta: [139,0,139],
1003 darkolivegreen: [85,107,47],
1004 darkorange: [255,140,0],
1005 darkorchid: [153,50,204],
1006 darkred: [139,0,0],
1007 darksalmon: [233,150,122],
1008 darkseagreen: [143,188,143],
1009 darkslateblue: [72,61,139],
1010 darkslategray: [47,79,79],
1011 darkslategrey: [47,79,79],
1012 darkturquoise: [0,206,209],
1013 darkviolet: [148,0,211],
1014 deeppink: [255,20,147],
1015 deepskyblue: [0,191,255],
1016 dimgray: [105,105,105],
1017 dimgrey: [105,105,105],
1018 dodgerblue: [30,144,255],
1019 firebrick: [178,34,34],
1020 floralwhite: [255,250,240],
1021 forestgreen: [34,139,34],
1022 fuchsia: [255,0,255],
1023 gainsboro: [220,220,220],
1024 ghostwhite: [248,248,255],
1025 gold: [255,215,0],
1026 goldenrod: [218,165,32],
1027 gray: [128,128,128],
1028 green: [0,128,0],
1029 greenyellow: [173,255,47],
1030 grey: [128,128,128],
1031 honeydew: [240,255,240],
1032 hotpink: [255,105,180],
1033 indianred: [205,92,92],
1034 indigo: [75,0,130],
1035 ivory: [255,255,240],
1036 khaki: [240,230,140],
1037 lavender: [230,230,250],
1038 lavenderblush: [255,240,245],
1039 lawngreen: [124,252,0],
1040 lemonchiffon: [255,250,205],
1041 lightblue: [173,216,230],
1042 lightcoral: [240,128,128],
1043 lightcyan: [224,255,255],
1044 lightgoldenrodyellow: [250,250,210],
1045 lightgray: [211,211,211],
1046 lightgreen: [144,238,144],
1047 lightgrey: [211,211,211],
1048 lightpink: [255,182,193],
1049 lightsalmon: [255,160,122],
1050 lightseagreen: [32,178,170],
1051 lightskyblue: [135,206,250],
1052 lightslategray: [119,136,153],
1053 lightslategrey: [119,136,153],
1054 lightsteelblue: [176,196,222],
1055 lightyellow: [255,255,224],
1056 lime: [0,255,0],
1057 limegreen: [50,205,50],
1058 linen: [250,240,230],
1059 magenta: [255,0,255],
1060 maroon: [128,0,0],
1061 mediumaquamarine: [102,205,170],
1062 mediumblue: [0,0,205],
1063 mediumorchid: [186,85,211],
1064 mediumpurple: [147,112,219],
1065 mediumseagreen: [60,179,113],
1066 mediumslateblue: [123,104,238],
1067 mediumspringgreen: [0,250,154],
1068 mediumturquoise: [72,209,204],
1069 mediumvioletred: [199,21,133],
1070 midnightblue: [25,25,112],
1071 mintcream: [245,255,250],
1072 mistyrose: [255,228,225],
1073 moccasin: [255,228,181],
1074 navajowhite: [255,222,173],
1075 navy: [0,0,128],
1076 oldlace: [253,245,230],
1077 olive: [128,128,0],
1078 olivedrab: [107,142,35],
1079 orange: [255,165,0],
1080 orangered: [255,69,0],
1081 orchid: [218,112,214],
1082 palegoldenrod: [238,232,170],
1083 palegreen: [152,251,152],
1084 paleturquoise: [175,238,238],
1085 palevioletred: [219,112,147],
1086 papayawhip: [255,239,213],
1087 peachpuff: [255,218,185],
1088 peru: [205,133,63],
1089 pink: [255,192,203],
1090 plum: [221,160,221],
1091 powderblue: [176,224,230],
1092 purple: [128,0,128],
1093 rebeccapurple: [102, 51, 153],
1094 red: [255,0,0],
1095 rosybrown: [188,143,143],
1096 royalblue: [65,105,225],
1097 saddlebrown: [139,69,19],
1098 salmon: [250,128,114],
1099 sandybrown: [244,164,96],
1100 seagreen: [46,139,87],
1101 seashell: [255,245,238],
1102 sienna: [160,82,45],
1103 silver: [192,192,192],
1104 skyblue: [135,206,235],
1105 slateblue: [106,90,205],
1106 slategray: [112,128,144],
1107 slategrey: [112,128,144],
1108 snow: [255,250,250],
1109 springgreen: [0,255,127],
1110 steelblue: [70,130,180],
1111 tan: [210,180,140],
1112 teal: [0,128,128],
1113 thistle: [216,191,216],
1114 tomato: [255,99,71],
1115 turquoise: [64,224,208],
1116 violet: [238,130,238],
1117 wheat: [245,222,179],
1118 white: [255,255,255],
1119 whitesmoke: [245,245,245],
1120 yellow: [255,255,0],
1121 yellowgreen: [154,205,50]
1122};
1123
1124var reverseKeywords = {};
1125for (var key in cssKeywords) {
1126 reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
1127}
1128
1129},{}],3:[function(require,module,exports){
1130var conversions = require("./conversions");
1131
1132var convert = function() {
1133 return new Converter();
1134}
1135
1136for (var func in conversions) {
1137 // export Raw versions
1138 convert[func + "Raw"] = (function(func) {
1139 // accept array or plain args
1140 return function(arg) {
1141 if (typeof arg == "number")
1142 arg = Array.prototype.slice.call(arguments);
1143 return conversions[func](arg);
1144 }
1145 })(func);
1146
1147 var pair = /(\w+)2(\w+)/.exec(func),
1148 from = pair[1],
1149 to = pair[2];
1150
1151 // export rgb2hsl and ["rgb"]["hsl"]
1152 convert[from] = convert[from] || {};
1153
1154 convert[from][to] = convert[func] = (function(func) {
1155 return function(arg) {
1156 if (typeof arg == "number")
1157 arg = Array.prototype.slice.call(arguments);
1158
1159 var val = conversions[func](arg);
1160 if (typeof val == "string" || val === undefined)
1161 return val; // keyword
1162
1163 for (var i = 0; i < val.length; i++)
1164 val[i] = Math.round(val[i]);
1165 return val;
1166 }
1167 })(func);
1168}
1169
1170
1171/* Converter does lazy conversion and caching */
1172var Converter = function() {
1173 this.convs = {};
1174};
1175
1176/* Either get the values for a space or
1177 set the values for a space, depending on args */
1178Converter.prototype.routeSpace = function(space, args) {
1179 var values = args[0];
1180 if (values === undefined) {
1181 // color.rgb()
1182 return this.getValues(space);
1183 }
1184 // color.rgb(10, 10, 10)
1185 if (typeof values == "number") {
1186 values = Array.prototype.slice.call(args);
1187 }
1188
1189 return this.setValues(space, values);
1190};
1191
1192/* Set the values for a space, invalidating cache */
1193Converter.prototype.setValues = function(space, values) {
1194 this.space = space;
1195 this.convs = {};
1196 this.convs[space] = values;
1197 return this;
1198};
1199
1200/* Get the values for a space. If there's already
1201 a conversion for the space, fetch it, otherwise
1202 compute it */
1203Converter.prototype.getValues = function(space) {
1204 var vals = this.convs[space];
1205 if (!vals) {
1206 var fspace = this.space,
1207 from = this.convs[fspace];
1208 vals = convert[fspace][space](from);
1209
1210 this.convs[space] = vals;
1211 }
1212 return vals;
1213};
1214
1215["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
1216 Converter.prototype[space] = function(vals) {
1217 return this.routeSpace(space, arguments);
1218 }
1219});
1220
1221module.exports = convert;
1222},{"./conversions":2}],4:[function(require,module,exports){
1223/* MIT license */
1224var colorNames = require('color-name');
1225
1226module.exports = {
1227 getRgba: getRgba,
1228 getHsla: getHsla,
1229 getRgb: getRgb,
1230 getHsl: getHsl,
1231 getHwb: getHwb,
1232 getAlpha: getAlpha,
1233
1234 hexString: hexString,
1235 rgbString: rgbString,
1236 rgbaString: rgbaString,
1237 percentString: percentString,
1238 percentaString: percentaString,
1239 hslString: hslString,
1240 hslaString: hslaString,
1241 hwbString: hwbString,
1242 keyword: keyword
1243}
1244
1245function getRgba(string) {
1246 if (!string) {
1247 return;
1248 }
1249 var abbr = /^#([a-fA-F0-9]{3})$/,
1250 hex = /^#([a-fA-F0-9]{6})$/,
1251 rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
1252 per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
1253 keyword = /(\D+)/;
1254
1255 var rgb = [0, 0, 0],
1256 a = 1,
1257 match = string.match(abbr);
1258 if (match) {
1259 match = match[1];
1260 for (var i = 0; i < rgb.length; i++) {
1261 rgb[i] = parseInt(match[i] + match[i], 16);
1262 }
1263 }
1264 else if (match = string.match(hex)) {
1265 match = match[1];
1266 for (var i = 0; i < rgb.length; i++) {
1267 rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
1268 }
1269 }
1270 else if (match = string.match(rgba)) {
1271 for (var i = 0; i < rgb.length; i++) {
1272 rgb[i] = parseInt(match[i + 1]);
1273 }
1274 a = parseFloat(match[4]);
1275 }
1276 else if (match = string.match(per)) {
1277 for (var i = 0; i < rgb.length; i++) {
1278 rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
1279 }
1280 a = parseFloat(match[4]);
1281 }
1282 else if (match = string.match(keyword)) {
1283 if (match[1] == "transparent") {
1284 return [0, 0, 0, 0];
1285 }
1286 rgb = colorNames[match[1]];
1287 if (!rgb) {
1288 return;
1289 }
1290 }
1291
1292 for (var i = 0; i < rgb.length; i++) {
1293 rgb[i] = scale(rgb[i], 0, 255);
1294 }
1295 if (!a && a != 0) {
1296 a = 1;
1297 }
1298 else {
1299 a = scale(a, 0, 1);
1300 }
1301 rgb[3] = a;
1302 return rgb;
1303}
1304
1305function getHsla(string) {
1306 if (!string) {
1307 return;
1308 }
1309 var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
1310 var match = string.match(hsl);
1311 if (match) {
1312 var alpha = parseFloat(match[4]);
1313 var h = scale(parseInt(match[1]), 0, 360),
1314 s = scale(parseFloat(match[2]), 0, 100),
1315 l = scale(parseFloat(match[3]), 0, 100),
1316 a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
1317 return [h, s, l, a];
1318 }
1319}
1320
1321function getHwb(string) {
1322 if (!string) {
1323 return;
1324 }
1325 var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
1326 var match = string.match(hwb);
1327 if (match) {
1328 var alpha = parseFloat(match[4]);
1329 var h = scale(parseInt(match[1]), 0, 360),
1330 w = scale(parseFloat(match[2]), 0, 100),
1331 b = scale(parseFloat(match[3]), 0, 100),
1332 a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
1333 return [h, w, b, a];
1334 }
1335}
1336
1337function getRgb(string) {
1338 var rgba = getRgba(string);
1339 return rgba && rgba.slice(0, 3);
1340}
1341
1342function getHsl(string) {
1343 var hsla = getHsla(string);
1344 return hsla && hsla.slice(0, 3);
1345}
1346
1347function getAlpha(string) {
1348 var vals = getRgba(string);
1349 if (vals) {
1350 return vals[3];
1351 }
1352 else if (vals = getHsla(string)) {
1353 return vals[3];
1354 }
1355 else if (vals = getHwb(string)) {
1356 return vals[3];
1357 }
1358}
1359
1360// generators
1361function hexString(rgb) {
1362 return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
1363 + hexDouble(rgb[2]);
1364}
1365
1366function rgbString(rgba, alpha) {
1367 if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
1368 return rgbaString(rgba, alpha);
1369 }
1370 return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
1371}
1372
1373function rgbaString(rgba, alpha) {
1374 if (alpha === undefined) {
1375 alpha = (rgba[3] !== undefined ? rgba[3] : 1);
1376 }
1377 return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
1378 + ", " + alpha + ")";
1379}
1380
1381function percentString(rgba, alpha) {
1382 if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
1383 return percentaString(rgba, alpha);
1384 }
1385 var r = Math.round(rgba[0]/255 * 100),
1386 g = Math.round(rgba[1]/255 * 100),
1387 b = Math.round(rgba[2]/255 * 100);
1388
1389 return "rgb(" + r + "%, " + g + "%, " + b + "%)";
1390}
1391
1392function percentaString(rgba, alpha) {
1393 var r = Math.round(rgba[0]/255 * 100),
1394 g = Math.round(rgba[1]/255 * 100),
1395 b = Math.round(rgba[2]/255 * 100);
1396 return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
1397}
1398
1399function hslString(hsla, alpha) {
1400 if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
1401 return hslaString(hsla, alpha);
1402 }
1403 return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
1404}
1405
1406function hslaString(hsla, alpha) {
1407 if (alpha === undefined) {
1408 alpha = (hsla[3] !== undefined ? hsla[3] : 1);
1409 }
1410 return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
1411 + alpha + ")";
1412}
1413
1414// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
1415// (hwb have alpha optional & 1 is default value)
1416function hwbString(hwb, alpha) {
1417 if (alpha === undefined) {
1418 alpha = (hwb[3] !== undefined ? hwb[3] : 1);
1419 }
1420 return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
1421 + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
1422}
1423
1424function keyword(rgb) {
1425 return reverseNames[rgb.slice(0, 3)];
1426}
1427
1428// helpers
1429function scale(num, min, max) {
1430 return Math.min(Math.max(min, num), max);
1431}
1432
1433function hexDouble(num) {
1434 var str = num.toString(16).toUpperCase();
1435 return (str.length < 2) ? "0" + str : str;
1436}
1437
1438
1439//create a list of reverse color names
1440var reverseNames = {};
1441for (var name in colorNames) {
1442 reverseNames[colorNames[name]] = name;
1443}
1444
1445},{"color-name":5}],5:[function(require,module,exports){
1446module.exports={
1447 "aliceblue": [240, 248, 255],
1448 "antiquewhite": [250, 235, 215],
1449 "aqua": [0, 255, 255],
1450 "aquamarine": [127, 255, 212],
1451 "azure": [240, 255, 255],
1452 "beige": [245, 245, 220],
1453 "bisque": [255, 228, 196],
1454 "black": [0, 0, 0],
1455 "blanchedalmond": [255, 235, 205],
1456 "blue": [0, 0, 255],
1457 "blueviolet": [138, 43, 226],
1458 "brown": [165, 42, 42],
1459 "burlywood": [222, 184, 135],
1460 "cadetblue": [95, 158, 160],
1461 "chartreuse": [127, 255, 0],
1462 "chocolate": [210, 105, 30],
1463 "coral": [255, 127, 80],
1464 "cornflowerblue": [100, 149, 237],
1465 "cornsilk": [255, 248, 220],
1466 "crimson": [220, 20, 60],
1467 "cyan": [0, 255, 255],
1468 "darkblue": [0, 0, 139],
1469 "darkcyan": [0, 139, 139],
1470 "darkgoldenrod": [184, 134, 11],
1471 "darkgray": [169, 169, 169],
1472 "darkgreen": [0, 100, 0],
1473 "darkgrey": [169, 169, 169],
1474 "darkkhaki": [189, 183, 107],
1475 "darkmagenta": [139, 0, 139],
1476 "darkolivegreen": [85, 107, 47],
1477 "darkorange": [255, 140, 0],
1478 "darkorchid": [153, 50, 204],
1479 "darkred": [139, 0, 0],
1480 "darksalmon": [233, 150, 122],
1481 "darkseagreen": [143, 188, 143],
1482 "darkslateblue": [72, 61, 139],
1483 "darkslategray": [47, 79, 79],
1484 "darkslategrey": [47, 79, 79],
1485 "darkturquoise": [0, 206, 209],
1486 "darkviolet": [148, 0, 211],
1487 "deeppink": [255, 20, 147],
1488 "deepskyblue": [0, 191, 255],
1489 "dimgray": [105, 105, 105],
1490 "dimgrey": [105, 105, 105],
1491 "dodgerblue": [30, 144, 255],
1492 "firebrick": [178, 34, 34],
1493 "floralwhite": [255, 250, 240],
1494 "forestgreen": [34, 139, 34],
1495 "fuchsia": [255, 0, 255],
1496 "gainsboro": [220, 220, 220],
1497 "ghostwhite": [248, 248, 255],
1498 "gold": [255, 215, 0],
1499 "goldenrod": [218, 165, 32],
1500 "gray": [128, 128, 128],
1501 "green": [0, 128, 0],
1502 "greenyellow": [173, 255, 47],
1503 "grey": [128, 128, 128],
1504 "honeydew": [240, 255, 240],
1505 "hotpink": [255, 105, 180],
1506 "indianred": [205, 92, 92],
1507 "indigo": [75, 0, 130],
1508 "ivory": [255, 255, 240],
1509 "khaki": [240, 230, 140],
1510 "lavender": [230, 230, 250],
1511 "lavenderblush": [255, 240, 245],
1512 "lawngreen": [124, 252, 0],
1513 "lemonchiffon": [255, 250, 205],
1514 "lightblue": [173, 216, 230],
1515 "lightcoral": [240, 128, 128],
1516 "lightcyan": [224, 255, 255],
1517 "lightgoldenrodyellow": [250, 250, 210],
1518 "lightgray": [211, 211, 211],
1519 "lightgreen": [144, 238, 144],
1520 "lightgrey": [211, 211, 211],
1521 "lightpink": [255, 182, 193],
1522 "lightsalmon": [255, 160, 122],
1523 "lightseagreen": [32, 178, 170],
1524 "lightskyblue": [135, 206, 250],
1525 "lightslategray": [119, 136, 153],
1526 "lightslategrey": [119, 136, 153],
1527 "lightsteelblue": [176, 196, 222],
1528 "lightyellow": [255, 255, 224],
1529 "lime": [0, 255, 0],
1530 "limegreen": [50, 205, 50],
1531 "linen": [250, 240, 230],
1532 "magenta": [255, 0, 255],
1533 "maroon": [128, 0, 0],
1534 "mediumaquamarine": [102, 205, 170],
1535 "mediumblue": [0, 0, 205],
1536 "mediumorchid": [186, 85, 211],
1537 "mediumpurple": [147, 112, 219],
1538 "mediumseagreen": [60, 179, 113],
1539 "mediumslateblue": [123, 104, 238],
1540 "mediumspringgreen": [0, 250, 154],
1541 "mediumturquoise": [72, 209, 204],
1542 "mediumvioletred": [199, 21, 133],
1543 "midnightblue": [25, 25, 112],
1544 "mintcream": [245, 255, 250],
1545 "mistyrose": [255, 228, 225],
1546 "moccasin": [255, 228, 181],
1547 "navajowhite": [255, 222, 173],
1548 "navy": [0, 0, 128],
1549 "oldlace": [253, 245, 230],
1550 "olive": [128, 128, 0],
1551 "olivedrab": [107, 142, 35],
1552 "orange": [255, 165, 0],
1553 "orangered": [255, 69, 0],
1554 "orchid": [218, 112, 214],
1555 "palegoldenrod": [238, 232, 170],
1556 "palegreen": [152, 251, 152],
1557 "paleturquoise": [175, 238, 238],
1558 "palevioletred": [219, 112, 147],
1559 "papayawhip": [255, 239, 213],
1560 "peachpuff": [255, 218, 185],
1561 "peru": [205, 133, 63],
1562 "pink": [255, 192, 203],
1563 "plum": [221, 160, 221],
1564 "powderblue": [176, 224, 230],
1565 "purple": [128, 0, 128],
1566 "rebeccapurple": [102, 51, 153],
1567 "red": [255, 0, 0],
1568 "rosybrown": [188, 143, 143],
1569 "royalblue": [65, 105, 225],
1570 "saddlebrown": [139, 69, 19],
1571 "salmon": [250, 128, 114],
1572 "sandybrown": [244, 164, 96],
1573 "seagreen": [46, 139, 87],
1574 "seashell": [255, 245, 238],
1575 "sienna": [160, 82, 45],
1576 "silver": [192, 192, 192],
1577 "skyblue": [135, 206, 235],
1578 "slateblue": [106, 90, 205],
1579 "slategray": [112, 128, 144],
1580 "slategrey": [112, 128, 144],
1581 "snow": [255, 250, 250],
1582 "springgreen": [0, 255, 127],
1583 "steelblue": [70, 130, 180],
1584 "tan": [210, 180, 140],
1585 "teal": [0, 128, 128],
1586 "thistle": [216, 191, 216],
1587 "tomato": [255, 99, 71],
1588 "turquoise": [64, 224, 208],
1589 "violet": [238, 130, 238],
1590 "wheat": [245, 222, 179],
1591 "white": [255, 255, 255],
1592 "whitesmoke": [245, 245, 245],
1593 "yellow": [255, 255, 0],
1594 "yellowgreen": [154, 205, 50]
1595}
1596},{}],6:[function(require,module,exports){
1597module.exports = require('./lib/geocrunch');
1598},{"./lib/geocrunch":11}],7:[function(require,module,exports){
1599// distance.js - Distance mixins for Paths
1600
1601var _ = require('underscore');
1602
1603var R = require('./constants').EARTHRADIUS;
1604var units = require('./units');
1605var flipCoords = require('./flipcoords');
1606
1607// Area conversions (from sqmeters)
1608var convertFuncs = {
1609 sqmeters: function (a) {
1610 return a;
1611 },
1612 sqmiles: function (a) {
1613 return units.sqMeters.toSqMiles(a);
1614 },
1615 acres: function (a) {
1616 return units.sqMeters.toAcres(a);
1617 }
1618};
1619
1620// Calculates area in square meters
1621// Method taken from OpenLayers API, https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Geometry/LinearRing.js#L270
1622var calcArea = function (coordArray) {
1623 var area = 0, i, l, c1, c2;
1624 for (i = 0, l = coordArray.length; i < l; i += 1) {
1625 c1 = coordArray[i];
1626 c2 = coordArray[(i + 1) % coordArray.length]; // Access next item in array until last item is i, then accesses first (0)
1627 area = area + units.degrees.toRadians(c2[0] - c1[0]) * (2 + Math.sin(units.degrees.toRadians(c1[1])) + Math.sin(units.degrees.toRadians(c2[1])));
1628 }
1629 return Math.abs(area * R * R / 2);
1630};
1631
1632var calcCenter = function (coordArray) {
1633 var offset = coordArray[0], twiceArea = 0, x = 0, y = 0, i, l, c1, c2, f;
1634 if (coordArray.length === 1) {
1635 return coordArray[0];
1636 }
1637 for (i = 0, l = coordArray.length; i < l; i += 1) {
1638 c1 = coordArray[i];
1639 c2 = coordArray[(i + 1) % coordArray.length]; // Access next item in array until last item is i, then accesses first (0)
1640 f = (c1[1] - offset[1]) * (c2[0] - offset[0]) - (c2[1] - offset[1]) * (c1[0] - offset[0]);
1641 twiceArea = twiceArea + f;
1642 x = x + ((c1[0] + c2[0] - 2 * offset[0]) * f);
1643 y = y + ((c1[1] + c2[1] - 2 * offset[1]) * f);
1644 }
1645 f = twiceArea * 3;
1646 return [x / f + offset[0], y / f + offset[1]];
1647};
1648
1649module.exports = {
1650 _internalAreaCalc: function () {
1651 // If not set, set this._calcedArea to total area in UNITS
1652 // Checks for cache to prevent additional unnecessary calcs
1653 if (!this._calcedArea) {
1654 if (this._coords.length < 3) {
1655 this._calcedArea = 0;
1656 } else {
1657 this._calcedArea = calcArea(this._coords);
1658 }
1659 }
1660 },
1661 _internalCenterCalc: function () {
1662 if (!this._calcedCenter && this._coords.length) {
1663 this._calcedCenter = calcCenter(this._coords);
1664 }
1665 },
1666 area: function (options) {
1667 var opts = _.extend({
1668 units: 'sqmeters'
1669 }, options);
1670 this._internalAreaCalc();
1671 if (_.isFunction(convertFuncs[opts.units])) {
1672 return convertFuncs[opts.units](this._calcedArea);
1673 }
1674 // TODO. Handle non-matching units
1675 },
1676 center: function () {
1677 this._internalCenterCalc();
1678 return this._options.imBackwards === true ? flipCoords(this._calcedCenter) : this._calcedCenter;
1679 }
1680};
1681},{"./constants":8,"./flipcoords":10,"./units":13,"underscore":14}],8:[function(require,module,exports){
1682// utils/constants.js
1683
1684module.exports = {
1685 EARTHRADIUS: 6371000 // R in meters
1686};
1687},{}],9:[function(require,module,exports){
1688// distance.js - Distance mixins for Paths
1689
1690var _ = require('underscore');
1691
1692var R = require('./constants').EARTHRADIUS;
1693var units = require('./units');
1694
1695// Distance conversions (from meters)
1696var convertFuncs = {
1697 meters: function (d) {
1698 return d;
1699 },
1700 kilometers: function (d) {
1701 return units.meters.toKilometers(d);
1702 },
1703 feet: function (d) {
1704 return units.meters.toFeet(d);
1705 },
1706 miles: function (d) {
1707 return units.meters.toMiles(d);
1708 }
1709};
1710
1711// Distance in meters
1712// Always positive regardless of direction
1713// Calculation based on Haversine Formula http://en.wikipedia.org/wiki/Haversine_formula
1714// Another method is @ http://www.movable-type.co.uk/scripts/latlong-vincenty.html but seems way overcomplicated
1715var calcDistance = function (coord1, coord2) {
1716 var deltaLng = units.degrees.toRadians(coord1[0] - coord2[0]),
1717 deltaLat = units.degrees.toRadians(coord1[1] - coord2[1]),
1718 lat1 = units.degrees.toRadians(coord1[1]),
1719 lat2 = units.degrees.toRadians(coord2[1]),
1720 hvsLng = Math.sin(deltaLng / 2),
1721 hvsLat = Math.sin(deltaLat / 2);
1722
1723 var a = hvsLat * hvsLat + hvsLng * hvsLng * Math.cos(lat1) * Math.cos(lat2);
1724 return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
1725};
1726
1727module.exports = {
1728 _internalDistanceCalc: function () {
1729 // If not set, set this._calcedDistance to total distance in meters
1730 // Checks for cache to prevent additional unnecessary calcs
1731 var distance = 0, i, l;
1732 if (!this._calcedDistance) {
1733 for (i = 0, l = this._coords.length; i < l; i += 1) {
1734 if (i > 0) {
1735 distance = distance + calcDistance(this._coords[i - 1], this._coords[i]);
1736 }
1737 }
1738 this._calcedDistance = distance;
1739 }
1740 },
1741 distance: function (options) {
1742 var opts = _.extend({
1743 units: 'meters'
1744 }, options);
1745 this._internalDistanceCalc();
1746 if (_.isFunction(convertFuncs[opts.units])) {
1747 return convertFuncs[opts.units](this._calcedDistance);
1748 }
1749 // TODO. Handle non-matching units
1750 }
1751};
1752},{"./constants":8,"./units":13,"underscore":14}],10:[function(require,module,exports){
1753// utils/flipcoords.js - Util functions for working with backwards coordinates [lat, lng]
1754
1755var _ = require('underscore');
1756
1757module.exports = function (backwardsCoordArray) {
1758 return _.map(backwardsCoordArray, function (backwardsCoord) {
1759 return [backwardsCoord[1], backwardsCoord[0]];
1760 });
1761};
1762},{"underscore":14}],11:[function(require,module,exports){
1763// geocrunch.js
1764
1765var _ = require('underscore');
1766
1767var Path = require('./path');
1768var distanceMixins = require('./distance'),
1769 areaMixins = require('./area');
1770
1771_.extend(Path.prototype, distanceMixins, areaMixins);
1772
1773exports.path = function (coords, options) {
1774 return new Path(coords, options);
1775};
1776},{"./area":7,"./distance":9,"./path":12,"underscore":14}],12:[function(require,module,exports){
1777// path.js - Object for working with a linear path of coordinates
1778
1779var flipCoords = require('./flipcoords');
1780
1781var Path = function (coords, options) {
1782 this._options = options || {};
1783
1784 // Set this._coords... Think about flipping at time of calcs for less iterations/better perf. May risk code clarity and mixin ease.
1785 coords = coords || [];
1786 this._coords = this._options.imBackwards === true ? flipCoords(coords) : coords;
1787};
1788
1789module.exports = Path;
1790
1791},{"./flipcoords":10}],13:[function(require,module,exports){
1792// units.js - Standard unit conversions
1793
1794exports.meters = {
1795 toFeet: function (m) {
1796 return m * 3.28084;
1797 },
1798 toKilometers: function (m) {
1799 return m * 0.001;
1800 },
1801 toMiles: function (m) {
1802 return m * 0.000621371;
1803 }
1804};
1805
1806exports.sqMeters = {
1807 toSqMiles: function (m) {
1808 return m * 0.000000386102;
1809 },
1810 toAcres: function (m) {
1811 return m * 0.000247105;
1812 }
1813};
1814
1815exports.degrees = {
1816 toRadians: function (d) {
1817 return d * Math.PI / 180;
1818 }
1819};
1820},{}],14:[function(require,module,exports){
1821// Underscore.js 1.5.2
1822// http://underscorejs.org
1823// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
1824// Underscore may be freely distributed under the MIT license.
1825
1826(function() {
1827
1828 // Baseline setup
1829 // --------------
1830
1831 // Establish the root object, `window` in the browser, or `exports` on the server.
1832 var root = this;
1833
1834 // Save the previous value of the `_` variable.
1835 var previousUnderscore = root._;
1836
1837 // Establish the object that gets returned to break out of a loop iteration.
1838 var breaker = {};
1839
1840 // Save bytes in the minified (but not gzipped) version:
1841 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
1842
1843 // Create quick reference variables for speed access to core prototypes.
1844 var
1845 push = ArrayProto.push,
1846 slice = ArrayProto.slice,
1847 concat = ArrayProto.concat,
1848 toString = ObjProto.toString,
1849 hasOwnProperty = ObjProto.hasOwnProperty;
1850
1851 // All **ECMAScript 5** native function implementations that we hope to use
1852 // are declared here.
1853 var
1854 nativeForEach = ArrayProto.forEach,
1855 nativeMap = ArrayProto.map,
1856 nativeReduce = ArrayProto.reduce,
1857 nativeReduceRight = ArrayProto.reduceRight,
1858 nativeFilter = ArrayProto.filter,
1859 nativeEvery = ArrayProto.every,
1860 nativeSome = ArrayProto.some,
1861 nativeIndexOf = ArrayProto.indexOf,
1862 nativeLastIndexOf = ArrayProto.lastIndexOf,
1863 nativeIsArray = Array.isArray,
1864 nativeKeys = Object.keys,
1865 nativeBind = FuncProto.bind;
1866
1867 // Create a safe reference to the Underscore object for use below.
1868 var _ = function(obj) {
1869 if (obj instanceof _) return obj;
1870 if (!(this instanceof _)) return new _(obj);
1871 this._wrapped = obj;
1872 };
1873
1874 // Export the Underscore object for **Node.js**, with
1875 // backwards-compatibility for the old `require()` API. If we're in
1876 // the browser, add `_` as a global object via a string identifier,
1877 // for Closure Compiler "advanced" mode.
1878 if (typeof exports !== 'undefined') {
1879 if (typeof module !== 'undefined' && module.exports) {
1880 exports = module.exports = _;
1881 }
1882 exports._ = _;
1883 } else {
1884 root._ = _;
1885 }
1886
1887 // Current version.
1888 _.VERSION = '1.5.2';
1889
1890 // Collection Functions
1891 // --------------------
1892
1893 // The cornerstone, an `each` implementation, aka `forEach`.
1894 // Handles objects with the built-in `forEach`, arrays, and raw objects.
1895 // Delegates to **ECMAScript 5**'s native `forEach` if available.
1896 var each = _.each = _.forEach = function(obj, iterator, context) {
1897 if (obj == null) return;
1898 if (nativeForEach && obj.forEach === nativeForEach) {
1899 obj.forEach(iterator, context);
1900 } else if (obj.length === +obj.length) {
1901 for (var i = 0, length = obj.length; i < length; i++) {
1902 if (iterator.call(context, obj[i], i, obj) === breaker) return;
1903 }
1904 } else {
1905 var keys = _.keys(obj);
1906 for (var i = 0, length = keys.length; i < length; i++) {
1907 if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
1908 }
1909 }
1910 };
1911
1912 // Return the results of applying the iterator to each element.
1913 // Delegates to **ECMAScript 5**'s native `map` if available.
1914 _.map = _.collect = function(obj, iterator, context) {
1915 var results = [];
1916 if (obj == null) return results;
1917 if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
1918 each(obj, function(value, index, list) {
1919 results.push(iterator.call(context, value, index, list));
1920 });
1921 return results;
1922 };
1923
1924 var reduceError = 'Reduce of empty array with no initial value';
1925
1926 // **Reduce** builds up a single result from a list of values, aka `inject`,
1927 // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
1928 _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
1929 var initial = arguments.length > 2;
1930 if (obj == null) obj = [];
1931 if (nativeReduce && obj.reduce === nativeReduce) {
1932 if (context) iterator = _.bind(iterator, context);
1933 return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
1934 }
1935 each(obj, function(value, index, list) {
1936 if (!initial) {
1937 memo = value;
1938 initial = true;
1939 } else {
1940 memo = iterator.call(context, memo, value, index, list);
1941 }
1942 });
1943 if (!initial) throw new TypeError(reduceError);
1944 return memo;
1945 };
1946
1947 // The right-associative version of reduce, also known as `foldr`.
1948 // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
1949 _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
1950 var initial = arguments.length > 2;
1951 if (obj == null) obj = [];
1952 if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
1953 if (context) iterator = _.bind(iterator, context);
1954 return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
1955 }
1956 var length = obj.length;
1957 if (length !== +length) {
1958 var keys = _.keys(obj);
1959 length = keys.length;
1960 }
1961 each(obj, function(value, index, list) {
1962 index = keys ? keys[--length] : --length;
1963 if (!initial) {
1964 memo = obj[index];
1965 initial = true;
1966 } else {
1967 memo = iterator.call(context, memo, obj[index], index, list);
1968 }
1969 });
1970 if (!initial) throw new TypeError(reduceError);
1971 return memo;
1972 };
1973
1974 // Return the first value which passes a truth test. Aliased as `detect`.
1975 _.find = _.detect = function(obj, iterator, context) {
1976 var result;
1977 any(obj, function(value, index, list) {
1978 if (iterator.call(context, value, index, list)) {
1979 result = value;
1980 return true;
1981 }
1982 });
1983 return result;
1984 };
1985
1986 // Return all the elements that pass a truth test.
1987 // Delegates to **ECMAScript 5**'s native `filter` if available.
1988 // Aliased as `select`.
1989 _.filter = _.select = function(obj, iterator, context) {
1990 var results = [];
1991 if (obj == null) return results;
1992 if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
1993 each(obj, function(value, index, list) {
1994 if (iterator.call(context, value, index, list)) results.push(value);
1995 });
1996 return results;
1997 };
1998
1999 // Return all the elements for which a truth test fails.
2000 _.reject = function(obj, iterator, context) {
2001 return _.filter(obj, function(value, index, list) {
2002 return !iterator.call(context, value, index, list);
2003 }, context);
2004 };
2005
2006 // Determine whether all of the elements match a truth test.
2007 // Delegates to **ECMAScript 5**'s native `every` if available.
2008 // Aliased as `all`.
2009 _.every = _.all = function(obj, iterator, context) {
2010 iterator || (iterator = _.identity);
2011 var result = true;
2012 if (obj == null) return result;
2013 if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
2014 each(obj, function(value, index, list) {
2015 if (!(result = result && iterator.call(context, value, index, list))) return breaker;
2016 });
2017 return !!result;
2018 };
2019
2020 // Determine if at least one element in the object matches a truth test.
2021 // Delegates to **ECMAScript 5**'s native `some` if available.
2022 // Aliased as `any`.
2023 var any = _.some = _.any = function(obj, iterator, context) {
2024 iterator || (iterator = _.identity);
2025 var result = false;
2026 if (obj == null) return result;
2027 if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
2028 each(obj, function(value, index, list) {
2029 if (result || (result = iterator.call(context, value, index, list))) return breaker;
2030 });
2031 return !!result;
2032 };
2033
2034 // Determine if the array or object contains a given value (using `===`).
2035 // Aliased as `include`.
2036 _.contains = _.include = function(obj, target) {
2037 if (obj == null) return false;
2038 if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
2039 return any(obj, function(value) {
2040 return value === target;
2041 });
2042 };
2043
2044 // Invoke a method (with arguments) on every item in a collection.
2045 _.invoke = function(obj, method) {
2046 var args = slice.call(arguments, 2);
2047 var isFunc = _.isFunction(method);
2048 return _.map(obj, function(value) {
2049 return (isFunc ? method : value[method]).apply(value, args);
2050 });
2051 };
2052
2053 // Convenience version of a common use case of `map`: fetching a property.
2054 _.pluck = function(obj, key) {
2055 return _.map(obj, function(value){ return value[key]; });
2056 };
2057
2058 // Convenience version of a common use case of `filter`: selecting only objects
2059 // containing specific `key:value` pairs.
2060 _.where = function(obj, attrs, first) {
2061 if (_.isEmpty(attrs)) return first ? void 0 : [];
2062 return _[first ? 'find' : 'filter'](obj, function(value) {
2063 for (var key in attrs) {
2064 if (attrs[key] !== value[key]) return false;
2065 }
2066 return true;
2067 });
2068 };
2069
2070 // Convenience version of a common use case of `find`: getting the first object
2071 // containing specific `key:value` pairs.
2072 _.findWhere = function(obj, attrs) {
2073 return _.where(obj, attrs, true);
2074 };
2075
2076 // Return the maximum element or (element-based computation).
2077 // Can't optimize arrays of integers longer than 65,535 elements.
2078 // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
2079 _.max = function(obj, iterator, context) {
2080 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
2081 return Math.max.apply(Math, obj);
2082 }
2083 if (!iterator && _.isEmpty(obj)) return -Infinity;
2084 var result = {computed : -Infinity, value: -Infinity};
2085 each(obj, function(value, index, list) {
2086 var computed = iterator ? iterator.call(context, value, index, list) : value;
2087 computed > result.computed && (result = {value : value, computed : computed});
2088 });
2089 return result.value;
2090 };
2091
2092 // Return the minimum element (or element-based computation).
2093 _.min = function(obj, iterator, context) {
2094 if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
2095 return Math.min.apply(Math, obj);
2096 }
2097 if (!iterator && _.isEmpty(obj)) return Infinity;
2098 var result = {computed : Infinity, value: Infinity};
2099 each(obj, function(value, index, list) {
2100 var computed = iterator ? iterator.call(context, value, index, list) : value;
2101 computed < result.computed && (result = {value : value, computed : computed});
2102 });
2103 return result.value;
2104 };
2105
2106 // Shuffle an array, using the modern version of the
2107 // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
2108 _.shuffle = function(obj) {
2109 var rand;
2110 var index = 0;
2111 var shuffled = [];
2112 each(obj, function(value) {
2113 rand = _.random(index++);
2114 shuffled[index - 1] = shuffled[rand];
2115 shuffled[rand] = value;
2116 });
2117 return shuffled;
2118 };
2119
2120 // Sample **n** random values from an array.
2121 // If **n** is not specified, returns a single random element from the array.
2122 // The internal `guard` argument allows it to work with `map`.
2123 _.sample = function(obj, n, guard) {
2124 if (arguments.length < 2 || guard) {
2125 return obj[_.random(obj.length - 1)];
2126 }
2127 return _.shuffle(obj).slice(0, Math.max(0, n));
2128 };
2129
2130 // An internal function to generate lookup iterators.
2131 var lookupIterator = function(value) {
2132 return _.isFunction(value) ? value : function(obj){ return obj[value]; };
2133 };
2134
2135 // Sort the object's values by a criterion produced by an iterator.
2136 _.sortBy = function(obj, value, context) {
2137 var iterator = lookupIterator(value);
2138 return _.pluck(_.map(obj, function(value, index, list) {
2139 return {
2140 value: value,
2141 index: index,
2142 criteria: iterator.call(context, value, index, list)
2143 };
2144 }).sort(function(left, right) {
2145 var a = left.criteria;
2146 var b = right.criteria;
2147 if (a !== b) {
2148 if (a > b || a === void 0) return 1;
2149 if (a < b || b === void 0) return -1;
2150 }
2151 return left.index - right.index;
2152 }), 'value');
2153 };
2154
2155 // An internal function used for aggregate "group by" operations.
2156 var group = function(behavior) {
2157 return function(obj, value, context) {
2158 var result = {};
2159 var iterator = value == null ? _.identity : lookupIterator(value);
2160 each(obj, function(value, index) {
2161 var key = iterator.call(context, value, index, obj);
2162 behavior(result, key, value);
2163 });
2164 return result;
2165 };
2166 };
2167
2168 // Groups the object's values by a criterion. Pass either a string attribute
2169 // to group by, or a function that returns the criterion.
2170 _.groupBy = group(function(result, key, value) {
2171 (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
2172 });
2173
2174 // Indexes the object's values by a criterion, similar to `groupBy`, but for
2175 // when you know that your index values will be unique.
2176 _.indexBy = group(function(result, key, value) {
2177 result[key] = value;
2178 });
2179
2180 // Counts instances of an object that group by a certain criterion. Pass
2181 // either a string attribute to count by, or a function that returns the
2182 // criterion.
2183 _.countBy = group(function(result, key) {
2184 _.has(result, key) ? result[key]++ : result[key] = 1;
2185 });
2186
2187 // Use a comparator function to figure out the smallest index at which
2188 // an object should be inserted so as to maintain order. Uses binary search.
2189 _.sortedIndex = function(array, obj, iterator, context) {
2190 iterator = iterator == null ? _.identity : lookupIterator(iterator);
2191 var value = iterator.call(context, obj);
2192 var low = 0, high = array.length;
2193 while (low < high) {
2194 var mid = (low + high) >>> 1;
2195 iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
2196 }
2197 return low;
2198 };
2199
2200 // Safely create a real, live array from anything iterable.
2201 _.toArray = function(obj) {
2202 if (!obj) return [];
2203 if (_.isArray(obj)) return slice.call(obj);
2204 if (obj.length === +obj.length) return _.map(obj, _.identity);
2205 return _.values(obj);
2206 };
2207
2208 // Return the number of elements in an object.
2209 _.size = function(obj) {
2210 if (obj == null) return 0;
2211 return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
2212 };
2213
2214 // Array Functions
2215 // ---------------
2216
2217 // Get the first element of an array. Passing **n** will return the first N
2218 // values in the array. Aliased as `head` and `take`. The **guard** check
2219 // allows it to work with `_.map`.
2220 _.first = _.head = _.take = function(array, n, guard) {
2221 if (array == null) return void 0;
2222 return (n == null) || guard ? array[0] : slice.call(array, 0, n);
2223 };
2224
2225 // Returns everything but the last entry of the array. Especially useful on
2226 // the arguments object. Passing **n** will return all the values in
2227 // the array, excluding the last N. The **guard** check allows it to work with
2228 // `_.map`.
2229 _.initial = function(array, n, guard) {
2230 return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
2231 };
2232
2233 // Get the last element of an array. Passing **n** will return the last N
2234 // values in the array. The **guard** check allows it to work with `_.map`.
2235 _.last = function(array, n, guard) {
2236 if (array == null) return void 0;
2237 if ((n == null) || guard) {
2238 return array[array.length - 1];
2239 } else {
2240 return slice.call(array, Math.max(array.length - n, 0));
2241 }
2242 };
2243
2244 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
2245 // Especially useful on the arguments object. Passing an **n** will return
2246 // the rest N values in the array. The **guard**
2247 // check allows it to work with `_.map`.
2248 _.rest = _.tail = _.drop = function(array, n, guard) {
2249 return slice.call(array, (n == null) || guard ? 1 : n);
2250 };
2251
2252 // Trim out all falsy values from an array.
2253 _.compact = function(array) {
2254 return _.filter(array, _.identity);
2255 };
2256
2257 // Internal implementation of a recursive `flatten` function.
2258 var flatten = function(input, shallow, output) {
2259 if (shallow && _.every(input, _.isArray)) {
2260 return concat.apply(output, input);
2261 }
2262 each(input, function(value) {
2263 if (_.isArray(value) || _.isArguments(value)) {
2264 shallow ? push.apply(output, value) : flatten(value, shallow, output);
2265 } else {
2266 output.push(value);
2267 }
2268 });
2269 return output;
2270 };
2271
2272 // Flatten out an array, either recursively (by default), or just one level.
2273 _.flatten = function(array, shallow) {
2274 return flatten(array, shallow, []);
2275 };
2276
2277 // Return a version of the array that does not contain the specified value(s).
2278 _.without = function(array) {
2279 return _.difference(array, slice.call(arguments, 1));
2280 };
2281
2282 // Produce a duplicate-free version of the array. If the array has already
2283 // been sorted, you have the option of using a faster algorithm.
2284 // Aliased as `unique`.
2285 _.uniq = _.unique = function(array, isSorted, iterator, context) {
2286 if (_.isFunction(isSorted)) {
2287 context = iterator;
2288 iterator = isSorted;
2289 isSorted = false;
2290 }
2291 var initial = iterator ? _.map(array, iterator, context) : array;
2292 var results = [];
2293 var seen = [];
2294 each(initial, function(value, index) {
2295 if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
2296 seen.push(value);
2297 results.push(array[index]);
2298 }
2299 });
2300 return results;
2301 };
2302
2303 // Produce an array that contains the union: each distinct element from all of
2304 // the passed-in arrays.
2305 _.union = function() {
2306 return _.uniq(_.flatten(arguments, true));
2307 };
2308
2309 // Produce an array that contains every item shared between all the
2310 // passed-in arrays.
2311 _.intersection = function(array) {
2312 var rest = slice.call(arguments, 1);
2313 return _.filter(_.uniq(array), function(item) {
2314 return _.every(rest, function(other) {
2315 return _.indexOf(other, item) >= 0;
2316 });
2317 });
2318 };
2319
2320 // Take the difference between one array and a number of other arrays.
2321 // Only the elements present in just the first array will remain.
2322 _.difference = function(array) {
2323 var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
2324 return _.filter(array, function(value){ return !_.contains(rest, value); });
2325 };
2326
2327 // Zip together multiple lists into a single array -- elements that share
2328 // an index go together.
2329 _.zip = function() {
2330 var length = _.max(_.pluck(arguments, "length").concat(0));
2331 var results = new Array(length);
2332 for (var i = 0; i < length; i++) {
2333 results[i] = _.pluck(arguments, '' + i);
2334 }
2335 return results;
2336 };
2337
2338 // Converts lists into objects. Pass either a single array of `[key, value]`
2339 // pairs, or two parallel arrays of the same length -- one of keys, and one of
2340 // the corresponding values.
2341 _.object = function(list, values) {
2342 if (list == null) return {};
2343 var result = {};
2344 for (var i = 0, length = list.length; i < length; i++) {
2345 if (values) {
2346 result[list[i]] = values[i];
2347 } else {
2348 result[list[i][0]] = list[i][1];
2349 }
2350 }
2351 return result;
2352 };
2353
2354 // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
2355 // we need this function. Return the position of the first occurrence of an
2356 // item in an array, or -1 if the item is not included in the array.
2357 // Delegates to **ECMAScript 5**'s native `indexOf` if available.
2358 // If the array is large and already in sort order, pass `true`
2359 // for **isSorted** to use binary search.
2360 _.indexOf = function(array, item, isSorted) {
2361 if (array == null) return -1;
2362 var i = 0, length = array.length;
2363 if (isSorted) {
2364 if (typeof isSorted == 'number') {
2365 i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
2366 } else {
2367 i = _.sortedIndex(array, item);
2368 return array[i] === item ? i : -1;
2369 }
2370 }
2371 if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
2372 for (; i < length; i++) if (array[i] === item) return i;
2373 return -1;
2374 };
2375
2376 // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
2377 _.lastIndexOf = function(array, item, from) {
2378 if (array == null) return -1;
2379 var hasIndex = from != null;
2380 if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
2381 return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
2382 }
2383 var i = (hasIndex ? from : array.length);
2384 while (i--) if (array[i] === item) return i;
2385 return -1;
2386 };
2387
2388 // Generate an integer Array containing an arithmetic progression. A port of
2389 // the native Python `range()` function. See
2390 // [the Python documentation](http://docs.python.org/library/functions.html#range).
2391 _.range = function(start, stop, step) {
2392 if (arguments.length <= 1) {
2393 stop = start || 0;
2394 start = 0;
2395 }
2396 step = arguments[2] || 1;
2397
2398 var length = Math.max(Math.ceil((stop - start) / step), 0);
2399 var idx = 0;
2400 var range = new Array(length);
2401
2402 while(idx < length) {
2403 range[idx++] = start;
2404 start += step;
2405 }
2406
2407 return range;
2408 };
2409
2410 // Function (ahem) Functions
2411 // ------------------
2412
2413 // Reusable constructor function for prototype setting.
2414 var ctor = function(){};
2415
2416 // Create a function bound to a given object (assigning `this`, and arguments,
2417 // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
2418 // available.
2419 _.bind = function(func, context) {
2420 var args, bound;
2421 if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
2422 if (!_.isFunction(func)) throw new TypeError;
2423 args = slice.call(arguments, 2);
2424 return bound = function() {
2425 if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
2426 ctor.prototype = func.prototype;
2427 var self = new ctor;
2428 ctor.prototype = null;
2429 var result = func.apply(self, args.concat(slice.call(arguments)));
2430 if (Object(result) === result) return result;
2431 return self;
2432 };
2433 };
2434
2435 // Partially apply a function by creating a version that has had some of its
2436 // arguments pre-filled, without changing its dynamic `this` context.
2437 _.partial = function(func) {
2438 var args = slice.call(arguments, 1);
2439 return function() {
2440 return func.apply(this, args.concat(slice.call(arguments)));
2441 };
2442 };
2443
2444 // Bind all of an object's methods to that object. Useful for ensuring that
2445 // all callbacks defined on an object belong to it.
2446 _.bindAll = function(obj) {
2447 var funcs = slice.call(arguments, 1);
2448 if (funcs.length === 0) throw new Error("bindAll must be passed function names");
2449 each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
2450 return obj;
2451 };
2452
2453 // Memoize an expensive function by storing its results.
2454 _.memoize = function(func, hasher) {
2455 var memo = {};
2456 hasher || (hasher = _.identity);
2457 return function() {
2458 var key = hasher.apply(this, arguments);
2459 return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
2460 };
2461 };
2462
2463 // Delays a function for the given number of milliseconds, and then calls
2464 // it with the arguments supplied.
2465 _.delay = function(func, wait) {
2466 var args = slice.call(arguments, 2);
2467 return setTimeout(function(){ return func.apply(null, args); }, wait);
2468 };
2469
2470 // Defers a function, scheduling it to run after the current call stack has
2471 // cleared.
2472 _.defer = function(func) {
2473 return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
2474 };
2475
2476 // Returns a function, that, when invoked, will only be triggered at most once
2477 // during a given window of time. Normally, the throttled function will run
2478 // as much as it can, without ever going more than once per `wait` duration;
2479 // but if you'd like to disable the execution on the leading edge, pass
2480 // `{leading: false}`. To disable execution on the trailing edge, ditto.
2481 _.throttle = function(func, wait, options) {
2482 var context, args, result;
2483 var timeout = null;
2484 var previous = 0;
2485 options || (options = {});
2486 var later = function() {
2487 previous = options.leading === false ? 0 : new Date;
2488 timeout = null;
2489 result = func.apply(context, args);
2490 };
2491 return function() {
2492 var now = new Date;
2493 if (!previous && options.leading === false) previous = now;
2494 var remaining = wait - (now - previous);
2495 context = this;
2496 args = arguments;
2497 if (remaining <= 0) {
2498 clearTimeout(timeout);
2499 timeout = null;
2500 previous = now;
2501 result = func.apply(context, args);
2502 } else if (!timeout && options.trailing !== false) {
2503 timeout = setTimeout(later, remaining);
2504 }
2505 return result;
2506 };
2507 };
2508
2509 // Returns a function, that, as long as it continues to be invoked, will not
2510 // be triggered. The function will be called after it stops being called for
2511 // N milliseconds. If `immediate` is passed, trigger the function on the
2512 // leading edge, instead of the trailing.
2513 _.debounce = function(func, wait, immediate) {
2514 var timeout, args, context, timestamp, result;
2515 return function() {
2516 context = this;
2517 args = arguments;
2518 timestamp = new Date();
2519 var later = function() {
2520 var last = (new Date()) - timestamp;
2521 if (last < wait) {
2522 timeout = setTimeout(later, wait - last);
2523 } else {
2524 timeout = null;
2525 if (!immediate) result = func.apply(context, args);
2526 }
2527 };
2528 var callNow = immediate && !timeout;
2529 if (!timeout) {
2530 timeout = setTimeout(later, wait);
2531 }
2532 if (callNow) result = func.apply(context, args);
2533 return result;
2534 };
2535 };
2536
2537 // Returns a function that will be executed at most one time, no matter how
2538 // often you call it. Useful for lazy initialization.
2539 _.once = function(func) {
2540 var ran = false, memo;
2541 return function() {
2542 if (ran) return memo;
2543 ran = true;
2544 memo = func.apply(this, arguments);
2545 func = null;
2546 return memo;
2547 };
2548 };
2549
2550 // Returns the first function passed as an argument to the second,
2551 // allowing you to adjust arguments, run code before and after, and
2552 // conditionally execute the original function.
2553 _.wrap = function(func, wrapper) {
2554 return function() {
2555 var args = [func];
2556 push.apply(args, arguments);
2557 return wrapper.apply(this, args);
2558 };
2559 };
2560
2561 // Returns a function that is the composition of a list of functions, each
2562 // consuming the return value of the function that follows.
2563 _.compose = function() {
2564 var funcs = arguments;
2565 return function() {
2566 var args = arguments;
2567 for (var i = funcs.length - 1; i >= 0; i--) {
2568 args = [funcs[i].apply(this, args)];
2569 }
2570 return args[0];
2571 };
2572 };
2573
2574 // Returns a function that will only be executed after being called N times.
2575 _.after = function(times, func) {
2576 return function() {
2577 if (--times < 1) {
2578 return func.apply(this, arguments);
2579 }
2580 };
2581 };
2582
2583 // Object Functions
2584 // ----------------
2585
2586 // Retrieve the names of an object's properties.
2587 // Delegates to **ECMAScript 5**'s native `Object.keys`
2588 _.keys = nativeKeys || function(obj) {
2589 if (obj !== Object(obj)) throw new TypeError('Invalid object');
2590 var keys = [];
2591 for (var key in obj) if (_.has(obj, key)) keys.push(key);
2592 return keys;
2593 };
2594
2595 // Retrieve the values of an object's properties.
2596 _.values = function(obj) {
2597 var keys = _.keys(obj);
2598 var length = keys.length;
2599 var values = new Array(length);
2600 for (var i = 0; i < length; i++) {
2601 values[i] = obj[keys[i]];
2602 }
2603 return values;
2604 };
2605
2606 // Convert an object into a list of `[key, value]` pairs.
2607 _.pairs = function(obj) {
2608 var keys = _.keys(obj);
2609 var length = keys.length;
2610 var pairs = new Array(length);
2611 for (var i = 0; i < length; i++) {
2612 pairs[i] = [keys[i], obj[keys[i]]];
2613 }
2614 return pairs;
2615 };
2616
2617 // Invert the keys and values of an object. The values must be serializable.
2618 _.invert = function(obj) {
2619 var result = {};
2620 var keys = _.keys(obj);
2621 for (var i = 0, length = keys.length; i < length; i++) {
2622 result[obj[keys[i]]] = keys[i];
2623 }
2624 return result;
2625 };
2626
2627 // Return a sorted list of the function names available on the object.
2628 // Aliased as `methods`
2629 _.functions = _.methods = function(obj) {
2630 var names = [];
2631 for (var key in obj) {
2632 if (_.isFunction(obj[key])) names.push(key);
2633 }
2634 return names.sort();
2635 };
2636
2637 // Extend a given object with all the properties in passed-in object(s).
2638 _.extend = function(obj) {
2639 each(slice.call(arguments, 1), function(source) {
2640 if (source) {
2641 for (var prop in source) {
2642 obj[prop] = source[prop];
2643 }
2644 }
2645 });
2646 return obj;
2647 };
2648
2649 // Return a copy of the object only containing the whitelisted properties.
2650 _.pick = function(obj) {
2651 var copy = {};
2652 var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
2653 each(keys, function(key) {
2654 if (key in obj) copy[key] = obj[key];
2655 });
2656 return copy;
2657 };
2658
2659 // Return a copy of the object without the blacklisted properties.
2660 _.omit = function(obj) {
2661 var copy = {};
2662 var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
2663 for (var key in obj) {
2664 if (!_.contains(keys, key)) copy[key] = obj[key];
2665 }
2666 return copy;
2667 };
2668
2669 // Fill in a given object with default properties.
2670 _.defaults = function(obj) {
2671 each(slice.call(arguments, 1), function(source) {
2672 if (source) {
2673 for (var prop in source) {
2674 if (obj[prop] === void 0) obj[prop] = source[prop];
2675 }
2676 }
2677 });
2678 return obj;
2679 };
2680
2681 // Create a (shallow-cloned) duplicate of an object.
2682 _.clone = function(obj) {
2683 if (!_.isObject(obj)) return obj;
2684 return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
2685 };
2686
2687 // Invokes interceptor with the obj, and then returns obj.
2688 // The primary purpose of this method is to "tap into" a method chain, in
2689 // order to perform operations on intermediate results within the chain.
2690 _.tap = function(obj, interceptor) {
2691 interceptor(obj);
2692 return obj;
2693 };
2694
2695 // Internal recursive comparison function for `isEqual`.
2696 var eq = function(a, b, aStack, bStack) {
2697 // Identical objects are equal. `0 === -0`, but they aren't identical.
2698 // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
2699 if (a === b) return a !== 0 || 1 / a == 1 / b;
2700 // A strict comparison is necessary because `null == undefined`.
2701 if (a == null || b == null) return a === b;
2702 // Unwrap any wrapped objects.
2703 if (a instanceof _) a = a._wrapped;
2704 if (b instanceof _) b = b._wrapped;
2705 // Compare `[[Class]]` names.
2706 var className = toString.call(a);
2707 if (className != toString.call(b)) return false;
2708 switch (className) {
2709 // Strings, numbers, dates, and booleans are compared by value.
2710 case '[object String]':
2711 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
2712 // equivalent to `new String("5")`.
2713 return a == String(b);
2714 case '[object Number]':
2715 // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
2716 // other numeric values.
2717 return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
2718 case '[object Date]':
2719 case '[object Boolean]':
2720 // Coerce dates and booleans to numeric primitive values. Dates are compared by their
2721 // millisecond representations. Note that invalid dates with millisecond representations
2722 // of `NaN` are not equivalent.
2723 return +a == +b;
2724 // RegExps are compared by their source patterns and flags.
2725 case '[object RegExp]':
2726 return a.source == b.source &&
2727 a.global == b.global &&
2728 a.multiline == b.multiline &&
2729 a.ignoreCase == b.ignoreCase;
2730 }
2731 if (typeof a != 'object' || typeof b != 'object') return false;
2732 // Assume equality for cyclic structures. The algorithm for detecting cyclic
2733 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
2734 var length = aStack.length;
2735 while (length--) {
2736 // Linear search. Performance is inversely proportional to the number of
2737 // unique nested structures.
2738 if (aStack[length] == a) return bStack[length] == b;
2739 }
2740 // Objects with different constructors are not equivalent, but `Object`s
2741 // from different frames are.
2742 var aCtor = a.constructor, bCtor = b.constructor;
2743 if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
2744 _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
2745 return false;
2746 }
2747 // Add the first object to the stack of traversed objects.
2748 aStack.push(a);
2749 bStack.push(b);
2750 var size = 0, result = true;
2751 // Recursively compare objects and arrays.
2752 if (className == '[object Array]') {
2753 // Compare array lengths to determine if a deep comparison is necessary.
2754 size = a.length;
2755 result = size == b.length;
2756 if (result) {
2757 // Deep compare the contents, ignoring non-numeric properties.
2758 while (size--) {
2759 if (!(result = eq(a[size], b[size], aStack, bStack))) break;
2760 }
2761 }
2762 } else {
2763 // Deep compare objects.
2764 for (var key in a) {
2765 if (_.has(a, key)) {
2766 // Count the expected number of properties.
2767 size++;
2768 // Deep compare each member.
2769 if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
2770 }
2771 }
2772 // Ensure that both objects contain the same number of properties.
2773 if (result) {
2774 for (key in b) {
2775 if (_.has(b, key) && !(size--)) break;
2776 }
2777 result = !size;
2778 }
2779 }
2780 // Remove the first object from the stack of traversed objects.
2781 aStack.pop();
2782 bStack.pop();
2783 return result;
2784 };
2785
2786 // Perform a deep comparison to check if two objects are equal.
2787 _.isEqual = function(a, b) {
2788 return eq(a, b, [], []);
2789 };
2790
2791 // Is a given array, string, or object empty?
2792 // An "empty" object has no enumerable own-properties.
2793 _.isEmpty = function(obj) {
2794 if (obj == null) return true;
2795 if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
2796 for (var key in obj) if (_.has(obj, key)) return false;
2797 return true;
2798 };
2799
2800 // Is a given value a DOM element?
2801 _.isElement = function(obj) {
2802 return !!(obj && obj.nodeType === 1);
2803 };
2804
2805 // Is a given value an array?
2806 // Delegates to ECMA5's native Array.isArray
2807 _.isArray = nativeIsArray || function(obj) {
2808 return toString.call(obj) == '[object Array]';
2809 };
2810
2811 // Is a given variable an object?
2812 _.isObject = function(obj) {
2813 return obj === Object(obj);
2814 };
2815
2816 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
2817 each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
2818 _['is' + name] = function(obj) {
2819 return toString.call(obj) == '[object ' + name + ']';
2820 };
2821 });
2822
2823 // Define a fallback version of the method in browsers (ahem, IE), where
2824 // there isn't any inspectable "Arguments" type.
2825 if (!_.isArguments(arguments)) {
2826 _.isArguments = function(obj) {
2827 return !!(obj && _.has(obj, 'callee'));
2828 };
2829 }
2830
2831 // Optimize `isFunction` if appropriate.
2832 if (typeof (/./) !== 'function') {
2833 _.isFunction = function(obj) {
2834 return typeof obj === 'function';
2835 };
2836 }
2837
2838 // Is a given object a finite number?
2839 _.isFinite = function(obj) {
2840 return isFinite(obj) && !isNaN(parseFloat(obj));
2841 };
2842
2843 // Is the given value `NaN`? (NaN is the only number which does not equal itself).
2844 _.isNaN = function(obj) {
2845 return _.isNumber(obj) && obj != +obj;
2846 };
2847
2848 // Is a given value a boolean?
2849 _.isBoolean = function(obj) {
2850 return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
2851 };
2852
2853 // Is a given value equal to null?
2854 _.isNull = function(obj) {
2855 return obj === null;
2856 };
2857
2858 // Is a given variable undefined?
2859 _.isUndefined = function(obj) {
2860 return obj === void 0;
2861 };
2862
2863 // Shortcut function for checking if an object has a given property directly
2864 // on itself (in other words, not on a prototype).
2865 _.has = function(obj, key) {
2866 return hasOwnProperty.call(obj, key);
2867 };
2868
2869 // Utility Functions
2870 // -----------------
2871
2872 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
2873 // previous owner. Returns a reference to the Underscore object.
2874 _.noConflict = function() {
2875 root._ = previousUnderscore;
2876 return this;
2877 };
2878
2879 // Keep the identity function around for default iterators.
2880 _.identity = function(value) {
2881 return value;
2882 };
2883
2884 // Run a function **n** times.
2885 _.times = function(n, iterator, context) {
2886 var accum = Array(Math.max(0, n));
2887 for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
2888 return accum;
2889 };
2890
2891 // Return a random integer between min and max (inclusive).
2892 _.random = function(min, max) {
2893 if (max == null) {
2894 max = min;
2895 min = 0;
2896 }
2897 return min + Math.floor(Math.random() * (max - min + 1));
2898 };
2899
2900 // List of HTML entities for escaping.
2901 var entityMap = {
2902 escape: {
2903 '&': '&amp;',
2904 '<': '&lt;',
2905 '>': '&gt;',
2906 '"': '&quot;',
2907 "'": '&#x27;'
2908 }
2909 };
2910 entityMap.unescape = _.invert(entityMap.escape);
2911
2912 // Regexes containing the keys and values listed immediately above.
2913 var entityRegexes = {
2914 escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
2915 unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
2916 };
2917
2918 // Functions for escaping and unescaping strings to/from HTML interpolation.
2919 _.each(['escape', 'unescape'], function(method) {
2920 _[method] = function(string) {
2921 if (string == null) return '';
2922 return ('' + string).replace(entityRegexes[method], function(match) {
2923 return entityMap[method][match];
2924 });
2925 };
2926 });
2927
2928 // If the value of the named `property` is a function then invoke it with the
2929 // `object` as context; otherwise, return it.
2930 _.result = function(object, property) {
2931 if (object == null) return void 0;
2932 var value = object[property];
2933 return _.isFunction(value) ? value.call(object) : value;
2934 };
2935
2936 // Add your own custom functions to the Underscore object.
2937 _.mixin = function(obj) {
2938 each(_.functions(obj), function(name) {
2939 var func = _[name] = obj[name];
2940 _.prototype[name] = function() {
2941 var args = [this._wrapped];
2942 push.apply(args, arguments);
2943 return result.call(this, func.apply(_, args));
2944 };
2945 });
2946 };
2947
2948 // Generate a unique integer id (unique within the entire client session).
2949 // Useful for temporary DOM ids.
2950 var idCounter = 0;
2951 _.uniqueId = function(prefix) {
2952 var id = ++idCounter + '';
2953 return prefix ? prefix + id : id;
2954 };
2955
2956 // By default, Underscore uses ERB-style template delimiters, change the
2957 // following template settings to use alternative delimiters.
2958 _.templateSettings = {
2959 evaluate : /<%([\s\S]+?)%>/g,
2960 interpolate : /<%=([\s\S]+?)%>/g,
2961 escape : /<%-([\s\S]+?)%>/g
2962 };
2963
2964 // When customizing `templateSettings`, if you don't want to define an
2965 // interpolation, evaluation or escaping regex, we need one that is
2966 // guaranteed not to match.
2967 var noMatch = /(.)^/;
2968
2969 // Certain characters need to be escaped so that they can be put into a
2970 // string literal.
2971 var escapes = {
2972 "'": "'",
2973 '\\': '\\',
2974 '\r': 'r',
2975 '\n': 'n',
2976 '\t': 't',
2977 '\u2028': 'u2028',
2978 '\u2029': 'u2029'
2979 };
2980
2981 var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
2982
2983 // JavaScript micro-templating, similar to John Resig's implementation.
2984 // Underscore templating handles arbitrary delimiters, preserves whitespace,
2985 // and correctly escapes quotes within interpolated code.
2986 _.template = function(text, data, settings) {
2987 var render;
2988 settings = _.defaults({}, settings, _.templateSettings);
2989
2990 // Combine delimiters into one regular expression via alternation.
2991 var matcher = new RegExp([
2992 (settings.escape || noMatch).source,
2993 (settings.interpolate || noMatch).source,
2994 (settings.evaluate || noMatch).source
2995 ].join('|') + '|$', 'g');
2996
2997 // Compile the template source, escaping string literals appropriately.
2998 var index = 0;
2999 var source = "__p+='";
3000 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
3001 source += text.slice(index, offset)
3002 .replace(escaper, function(match) { return '\\' + escapes[match]; });
3003
3004 if (escape) {
3005 source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
3006 }
3007 if (interpolate) {
3008 source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
3009 }
3010 if (evaluate) {
3011 source += "';\n" + evaluate + "\n__p+='";
3012 }
3013 index = offset + match.length;
3014 return match;
3015 });
3016 source += "';\n";
3017
3018 // If a variable is not specified, place data values in local scope.
3019 if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
3020
3021 source = "var __t,__p='',__j=Array.prototype.join," +
3022 "print=function(){__p+=__j.call(arguments,'');};\n" +
3023 source + "return __p;\n";
3024
3025 try {
3026 render = new Function(settings.variable || 'obj', '_', source);
3027 } catch (e) {
3028 e.source = source;
3029 throw e;
3030 }
3031
3032 if (data) return render(data, _);
3033 var template = function(data) {
3034 return render.call(this, data, _);
3035 };
3036
3037 // Provide the compiled function source as a convenience for precompilation.
3038 template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
3039
3040 return template;
3041 };
3042
3043 // Add a "chain" function, which will delegate to the wrapper.
3044 _.chain = function(obj) {
3045 return _(obj).chain();
3046 };
3047
3048 // OOP
3049 // ---------------
3050 // If Underscore is called as a function, it returns a wrapped object that
3051 // can be used OO-style. This wrapper holds altered versions of all the
3052 // underscore functions. Wrapped objects may be chained.
3053
3054 // Helper function to continue chaining intermediate results.
3055 var result = function(obj) {
3056 return this._chain ? _(obj).chain() : obj;
3057 };
3058
3059 // Add all of the Underscore functions to the wrapper object.
3060 _.mixin(_);
3061
3062 // Add all mutator Array functions to the wrapper.
3063 each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
3064 var method = ArrayProto[name];
3065 _.prototype[name] = function() {
3066 var obj = this._wrapped;
3067 method.apply(obj, arguments);
3068 if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
3069 return result.call(this, obj);
3070 };
3071 });
3072
3073 // Add all accessor Array functions to the wrapper.
3074 each(['concat', 'join', 'slice'], function(name) {
3075 var method = ArrayProto[name];
3076 _.prototype[name] = function() {
3077 return result.call(this, method.apply(this._wrapped, arguments));
3078 };
3079 });
3080
3081 _.extend(_.prototype, {
3082
3083 // Start chaining a wrapped Underscore object.
3084 chain: function() {
3085 this._chain = true;
3086 return this;
3087 },
3088
3089 // Extracts the result from a wrapped and chained object.
3090 value: function() {
3091 return this._wrapped;
3092 }
3093
3094 });
3095
3096}).call(this);
3097
3098},{}],15:[function(require,module,exports){
3099
3100(function() {
3101
3102 // Baseline setup
3103 // --------------
3104
3105 // Establish the root object, `window` in the browser, or `global` on the server.
3106 var root = this;
3107
3108 // Save the previous value of the `humanize` variable.
3109 var previousHumanize = root.humanize;
3110
3111 var humanize = {};
3112
3113 if (typeof exports !== 'undefined') {
3114 if (typeof module !== 'undefined' && module.exports) {
3115 exports = module.exports = humanize;
3116 }
3117 exports.humanize = humanize;
3118 } else {
3119 if (typeof define === 'function' && define.amd) {
3120 define('humanize', function() {
3121 return humanize;
3122 });
3123 }
3124 root.humanize = humanize;
3125 }
3126
3127 humanize.noConflict = function() {
3128 root.humanize = previousHumanize;
3129 return this;
3130 };
3131
3132 humanize.pad = function(str, count, padChar, type) {
3133 str += '';
3134 if (!padChar) {
3135 padChar = ' ';
3136 } else if (padChar.length > 1) {
3137 padChar = padChar.charAt(0);
3138 }
3139 type = (type === undefined) ? 'left' : 'right';
3140
3141 if (type === 'right') {
3142 while (str.length < count) {
3143 str = str + padChar;
3144 }
3145 } else {
3146 // default to left
3147 while (str.length < count) {
3148 str = padChar + str;
3149 }
3150 }
3151
3152 return str;
3153 };
3154
3155 // gets current unix time
3156 humanize.time = function() {
3157 return new Date().getTime() / 1000;
3158 };
3159
3160 /**
3161 * PHP-inspired date
3162 */
3163
3164 /* jan feb mar apr may jun jul aug sep oct nov dec */
3165 var dayTableCommon = [ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ];
3166 var dayTableLeap = [ 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 ];
3167 // var mtable_common[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
3168 // static int ml_table_leap[13] = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
3169
3170
3171 humanize.date = function(format, timestamp) {
3172 var jsdate = ((timestamp === undefined) ? new Date() : // Not provided
3173 (timestamp instanceof Date) ? new Date(timestamp) : // JS Date()
3174 new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int)
3175 );
3176
3177 var formatChr = /\\?([a-z])/gi;
3178 var formatChrCb = function (t, s) {
3179 return f[t] ? f[t]() : s;
3180 };
3181
3182 var shortDayTxt = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
3183 var monthTxt = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
3184
3185 var f = {
3186 /* Day */
3187 // Day of month w/leading 0; 01..31
3188 d: function () { return humanize.pad(f.j(), 2, '0'); },
3189
3190 // Shorthand day name; Mon..Sun
3191 D: function () { return f.l().slice(0, 3); },
3192
3193 // Day of month; 1..31
3194 j: function () { return jsdate.getDate(); },
3195
3196 // Full day name; Monday..Sunday
3197 l: function () { return shortDayTxt[f.w()]; },
3198
3199 // ISO-8601 day of week; 1[Mon]..7[Sun]
3200 N: function () { return f.w() || 7; },
3201
3202 // Ordinal suffix for day of month; st, nd, rd, th
3203 S: function () {
3204 var j = f.j();
3205 return j > 4 && j < 21 ? 'th' : {1: 'st', 2: 'nd', 3: 'rd'}[j % 10] || 'th';
3206 },
3207
3208 // Day of week; 0[Sun]..6[Sat]
3209 w: function () { return jsdate.getDay(); },
3210
3211 // Day of year; 0..365
3212 z: function () {
3213 return (f.L() ? dayTableLeap[f.n()] : dayTableCommon[f.n()]) + f.j() - 1;
3214 },
3215
3216 /* Week */
3217 // ISO-8601 week number
3218 W: function () {
3219 // days between midweek of this week and jan 4
3220 // (f.z() - f.N() + 1 + 3.5) - 3
3221 var midWeekDaysFromJan4 = f.z() - f.N() + 1.5;
3222 // 1 + number of weeks + rounded week
3223 return humanize.pad(1 + Math.floor(Math.abs(midWeekDaysFromJan4) / 7) + (midWeekDaysFromJan4 % 7 > 3.5 ? 1 : 0), 2, '0');
3224 },
3225
3226 /* Month */
3227 // Full month name; January..December
3228 F: function () { return monthTxt[jsdate.getMonth()]; },
3229
3230 // Month w/leading 0; 01..12
3231 m: function () { return humanize.pad(f.n(), 2, '0'); },
3232
3233 // Shorthand month name; Jan..Dec
3234 M: function () { return f.F().slice(0, 3); },
3235
3236 // Month; 1..12
3237 n: function () { return jsdate.getMonth() + 1; },
3238
3239 // Days in month; 28..31
3240 t: function () { return (new Date(f.Y(), f.n(), 0)).getDate(); },
3241
3242 /* Year */
3243 // Is leap year?; 0 or 1
3244 L: function () { return new Date(f.Y(), 1, 29).getMonth() === 1 ? 1 : 0; },
3245
3246 // ISO-8601 year
3247 o: function () {
3248 var n = f.n();
3249 var W = f.W();
3250 return f.Y() + (n === 12 && W < 9 ? -1 : n === 1 && W > 9);
3251 },
3252
3253 // Full year; e.g. 1980..2010
3254 Y: function () { return jsdate.getFullYear(); },
3255
3256 // Last two digits of year; 00..99
3257 y: function () { return (String(f.Y())).slice(-2); },
3258
3259 /* Time */
3260 // am or pm
3261 a: function () { return jsdate.getHours() > 11 ? 'pm' : 'am'; },
3262
3263 // AM or PM
3264 A: function () { return f.a().toUpperCase(); },
3265
3266 // Swatch Internet time; 000..999
3267 B: function () {
3268 var unixTime = jsdate.getTime() / 1000;
3269 var secondsPassedToday = unixTime % 86400 + 3600; // since it's based off of UTC+1
3270 if (secondsPassedToday < 0) { secondsPassedToday += 86400; }
3271 var beats = ((secondsPassedToday) / 86.4) % 1000;
3272 if (unixTime < 0) {
3273 return Math.ceil(beats);
3274 }
3275 return Math.floor(beats);
3276 },
3277
3278 // 12-Hours; 1..12
3279 g: function () { return f.G() % 12 || 12; },
3280
3281 // 24-Hours; 0..23
3282 G: function () { return jsdate.getHours(); },
3283
3284 // 12-Hours w/leading 0; 01..12
3285 h: function () { return humanize.pad(f.g(), 2, '0'); },
3286
3287 // 24-Hours w/leading 0; 00..23
3288 H: function () { return humanize.pad(f.G(), 2, '0'); },
3289
3290 // Minutes w/leading 0; 00..59
3291 i: function () { return humanize.pad(jsdate.getMinutes(), 2, '0'); },
3292
3293 // Seconds w/leading 0; 00..59
3294 s: function () { return humanize.pad(jsdate.getSeconds(), 2, '0'); },
3295
3296 // Microseconds; 000000-999000
3297 u: function () { return humanize.pad(jsdate.getMilliseconds() * 1000, 6, '0'); },
3298
3299 // Whether or not the date is in daylight savings time
3300 /*
3301 I: function () {
3302 // Compares Jan 1 minus Jan 1 UTC to Jul 1 minus Jul 1 UTC.
3303 // If they are not equal, then DST is observed.
3304 var Y = f.Y();
3305 return 0 + ((new Date(Y, 0) - Date.UTC(Y, 0)) !== (new Date(Y, 6) - Date.UTC(Y, 6)));
3306 },
3307 */
3308
3309 // Difference to GMT in hour format; e.g. +0200
3310 O: function () {
3311 var tzo = jsdate.getTimezoneOffset();
3312 var tzoNum = Math.abs(tzo);
3313 return (tzo > 0 ? '-' : '+') + humanize.pad(Math.floor(tzoNum / 60) * 100 + tzoNum % 60, 4, '0');
3314 },
3315
3316 // Difference to GMT w/colon; e.g. +02:00
3317 P: function () {
3318 var O = f.O();
3319 return (O.substr(0, 3) + ':' + O.substr(3, 2));
3320 },
3321
3322 // Timezone offset in seconds (-43200..50400)
3323 Z: function () { return -jsdate.getTimezoneOffset() * 60; },
3324
3325 // Full Date/Time, ISO-8601 date
3326 c: function () { return 'Y-m-d\\TH:i:sP'.replace(formatChr, formatChrCb); },
3327
3328 // RFC 2822
3329 r: function () { return 'D, d M Y H:i:s O'.replace(formatChr, formatChrCb); },
3330
3331 // Seconds since UNIX epoch
3332 U: function () { return jsdate.getTime() / 1000 || 0; }
3333 };
3334
3335 return format.replace(formatChr, formatChrCb);
3336 };
3337
3338
3339 /**
3340 * format number by adding thousands separaters and significant digits while rounding
3341 */
3342 humanize.numberFormat = function(number, decimals, decPoint, thousandsSep) {
3343 decimals = isNaN(decimals) ? 2 : Math.abs(decimals);
3344 decPoint = (decPoint === undefined) ? '.' : decPoint;
3345 thousandsSep = (thousandsSep === undefined) ? ',' : thousandsSep;
3346
3347 var sign = number < 0 ? '-' : '';
3348 number = Math.abs(+number || 0);
3349
3350 var intPart = parseInt(number.toFixed(decimals), 10) + '';
3351 var j = intPart.length > 3 ? intPart.length % 3 : 0;
3352
3353 return sign + (j ? intPart.substr(0, j) + thousandsSep : '') + intPart.substr(j).replace(/(\d{3})(?=\d)/g, '$1' + thousandsSep) + (decimals ? decPoint + Math.abs(number - intPart).toFixed(decimals).slice(2) : '');
3354 };
3355
3356
3357 /**
3358 * For dates that are the current day or within one day, return 'today', 'tomorrow' or 'yesterday', as appropriate.
3359 * Otherwise, format the date using the passed in format string.
3360 *
3361 * Examples (when 'today' is 17 Feb 2007):
3362 * 16 Feb 2007 becomes yesterday.
3363 * 17 Feb 2007 becomes today.
3364 * 18 Feb 2007 becomes tomorrow.
3365 * Any other day is formatted according to given argument or the DATE_FORMAT setting if no argument is given.
3366 */
3367 humanize.naturalDay = function(timestamp, format) {
3368 timestamp = (timestamp === undefined) ? humanize.time() : timestamp;
3369 format = (format === undefined) ? 'Y-m-d' : format;
3370
3371 var oneDay = 86400;
3372 var d = new Date();
3373 var today = (new Date(d.getFullYear(), d.getMonth(), d.getDate())).getTime() / 1000;
3374
3375 if (timestamp < today && timestamp >= today - oneDay) {
3376 return 'yesterday';
3377 } else if (timestamp >= today && timestamp < today + oneDay) {
3378 return 'today';
3379 } else if (timestamp >= today + oneDay && timestamp < today + 2 * oneDay) {
3380 return 'tomorrow';
3381 }
3382
3383 return humanize.date(format, timestamp);
3384 };
3385
3386 /**
3387 * returns a string representing how many seconds, minutes or hours ago it was or will be in the future
3388 * Will always return a relative time, most granular of seconds to least granular of years. See unit tests for more details
3389 */
3390 humanize.relativeTime = function(timestamp) {
3391 timestamp = (timestamp === undefined) ? humanize.time() : timestamp;
3392
3393 var currTime = humanize.time();
3394 var timeDiff = currTime - timestamp;
3395
3396 // within 2 seconds
3397 if (timeDiff < 2 && timeDiff > -2) {
3398 return (timeDiff >= 0 ? 'just ' : '') + 'now';
3399 }
3400
3401 // within a minute
3402 if (timeDiff < 60 && timeDiff > -60) {
3403 return (timeDiff >= 0 ? Math.floor(timeDiff) + ' seconds ago' : 'in ' + Math.floor(-timeDiff) + ' seconds');
3404 }
3405
3406 // within 2 minutes
3407 if (timeDiff < 120 && timeDiff > -120) {
3408 return (timeDiff >= 0 ? 'about a minute ago' : 'in about a minute');
3409 }
3410
3411 // within an hour
3412 if (timeDiff < 3600 && timeDiff > -3600) {
3413 return (timeDiff >= 0 ? Math.floor(timeDiff / 60) + ' minutes ago' : 'in ' + Math.floor(-timeDiff / 60) + ' minutes');
3414 }
3415
3416 // within 2 hours
3417 if (timeDiff < 7200 && timeDiff > -7200) {
3418 return (timeDiff >= 0 ? 'about an hour ago' : 'in about an hour');
3419 }
3420
3421 // within 24 hours
3422 if (timeDiff < 86400 && timeDiff > -86400) {
3423 return (timeDiff >= 0 ? Math.floor(timeDiff / 3600) + ' hours ago' : 'in ' + Math.floor(-timeDiff / 3600) + ' hours');
3424 }
3425
3426 // within 2 days
3427 var days2 = 2 * 86400;
3428 if (timeDiff < days2 && timeDiff > -days2) {
3429 return (timeDiff >= 0 ? '1 day ago' : 'in 1 day');
3430 }
3431
3432 // within 29 days
3433 var days29 = 29 * 86400;
3434 if (timeDiff < days29 && timeDiff > -days29) {
3435 return (timeDiff >= 0 ? Math.floor(timeDiff / 86400) + ' days ago' : 'in ' + Math.floor(-timeDiff / 86400) + ' days');
3436 }
3437
3438 // within 60 days
3439 var days60 = 60 * 86400;
3440 if (timeDiff < days60 && timeDiff > -days60) {
3441 return (timeDiff >= 0 ? 'about a month ago' : 'in about a month');
3442 }
3443
3444 var currTimeYears = parseInt(humanize.date('Y', currTime), 10);
3445 var timestampYears = parseInt(humanize.date('Y', timestamp), 10);
3446 var currTimeMonths = currTimeYears * 12 + parseInt(humanize.date('n', currTime), 10);
3447 var timestampMonths = timestampYears * 12 + parseInt(humanize.date('n', timestamp), 10);
3448
3449 // within a year
3450 var monthDiff = currTimeMonths - timestampMonths;
3451 if (monthDiff < 12 && monthDiff > -12) {
3452 return (monthDiff >= 0 ? monthDiff + ' months ago' : 'in ' + (-monthDiff) + ' months');
3453 }
3454
3455 var yearDiff = currTimeYears - timestampYears;
3456 if (yearDiff < 2 && yearDiff > -2) {
3457 return (yearDiff >= 0 ? 'a year ago' : 'in a year');
3458 }
3459
3460 return (yearDiff >= 0 ? yearDiff + ' years ago' : 'in ' + (-yearDiff) + ' years');
3461 };
3462
3463 /**
3464 * Converts an integer to its ordinal as a string.
3465 *
3466 * 1 becomes 1st
3467 * 2 becomes 2nd
3468 * 3 becomes 3rd etc
3469 */
3470 humanize.ordinal = function(number) {
3471 number = parseInt(number, 10);
3472 number = isNaN(number) ? 0 : number;
3473 var sign = number < 0 ? '-' : '';
3474 number = Math.abs(number);
3475 var tens = number % 100;
3476
3477 return sign + number + (tens > 4 && tens < 21 ? 'th' : {1: 'st', 2: 'nd', 3: 'rd'}[number % 10] || 'th');
3478 };
3479
3480 /**
3481 * Formats the value like a 'human-readable' file size (i.e. '13 KB', '4.1 MB', '102 bytes', etc).
3482 *
3483 * For example:
3484 * If value is 123456789, the output would be 117.7 MB.
3485 */
3486 humanize.filesize = function(filesize, kilo, decimals, decPoint, thousandsSep, suffixSep) {
3487 kilo = (kilo === undefined) ? 1024 : kilo;
3488 if (filesize <= 0) { return '0 bytes'; }
3489 if (filesize < kilo && decimals === undefined) { decimals = 0; }
3490 if (suffixSep === undefined) { suffixSep = ' '; }
3491 return humanize.intword(filesize, ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'], kilo, decimals, decPoint, thousandsSep, suffixSep);
3492 };
3493
3494 /**
3495 * Formats the value like a 'human-readable' number (i.e. '13 K', '4.1 M', '102', etc).
3496 *
3497 * For example:
3498 * If value is 123456789, the output would be 117.7 M.
3499 */
3500 humanize.intword = function(number, units, kilo, decimals, decPoint, thousandsSep, suffixSep) {
3501 var humanized, unit;
3502
3503 units = units || ['', 'K', 'M', 'B', 'T'],
3504 unit = units.length - 1,
3505 kilo = kilo || 1000,
3506 decimals = isNaN(decimals) ? 2 : Math.abs(decimals),
3507 decPoint = decPoint || '.',
3508 thousandsSep = thousandsSep || ',',
3509 suffixSep = suffixSep || '';
3510
3511 for (var i=0; i < units.length; i++) {
3512 if (number < Math.pow(kilo, i+1)) {
3513 unit = i;
3514 break;
3515 }
3516 }
3517 humanized = number / Math.pow(kilo, unit);
3518
3519 var suffix = units[unit] ? suffixSep + units[unit] : '';
3520 return humanize.numberFormat(humanized, decimals, decPoint, thousandsSep) + suffix;
3521 };
3522
3523 /**
3524 * Replaces line breaks in plain text with appropriate HTML
3525 * A single newline becomes an HTML line break (<br />) and a new line followed by a blank line becomes a paragraph break (</p>).
3526 *
3527 * For example:
3528 * If value is Joel\nis a\n\nslug, the output will be <p>Joel<br />is a</p><p>slug</p>
3529 */
3530 humanize.linebreaks = function(str) {
3531 // remove beginning and ending newlines
3532 str = str.replace(/^([\n|\r]*)/, '');
3533 str = str.replace(/([\n|\r]*)$/, '');
3534
3535 // normalize all to \n
3536 str = str.replace(/(\r\n|\n|\r)/g, "\n");
3537
3538 // any consecutive new lines more than 2 gets turned into p tags
3539 str = str.replace(/(\n{2,})/g, '</p><p>');
3540
3541 // any that are singletons get turned into br
3542 str = str.replace(/\n/g, '<br />');
3543 return '<p>' + str + '</p>';
3544 };
3545
3546 /**
3547 * Converts all newlines in a piece of plain text to HTML line breaks (<br />).
3548 */
3549 humanize.nl2br = function(str) {
3550 return str.replace(/(\r\n|\n|\r)/g, '<br />');
3551 };
3552
3553 /**
3554 * Truncates a string if it is longer than the specified number of characters.
3555 * Truncated strings will end with a translatable ellipsis sequence ('…').
3556 */
3557 humanize.truncatechars = function(string, length) {
3558 if (string.length <= length) { return string; }
3559 return string.substr(0, length) + '…';
3560 };
3561
3562 /**
3563 * Truncates a string after a certain number of words.
3564 * Newlines within the string will be removed.
3565 */
3566 humanize.truncatewords = function(string, numWords) {
3567 var words = string.split(' ');
3568 if (words.length < numWords) { return string; }
3569 return words.slice(0, numWords).join(' ') + '…';
3570 };
3571
3572}).call(this);
3573
3574},{}],16:[function(require,module,exports){
3575// Underscore.js 1.7.0
3576// http://underscorejs.org
3577// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
3578// Underscore may be freely distributed under the MIT license.
3579
3580(function() {
3581
3582 // Baseline setup
3583 // --------------
3584
3585 // Establish the root object, `window` in the browser, or `exports` on the server.
3586 var root = this;
3587
3588 // Save the previous value of the `_` variable.
3589 var previousUnderscore = root._;
3590
3591 // Save bytes in the minified (but not gzipped) version:
3592 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
3593
3594 // Create quick reference variables for speed access to core prototypes.
3595 var
3596 push = ArrayProto.push,
3597 slice = ArrayProto.slice,
3598 concat = ArrayProto.concat,
3599 toString = ObjProto.toString,
3600 hasOwnProperty = ObjProto.hasOwnProperty;
3601
3602 // All **ECMAScript 5** native function implementations that we hope to use
3603 // are declared here.
3604 var
3605 nativeIsArray = Array.isArray,
3606 nativeKeys = Object.keys,
3607 nativeBind = FuncProto.bind;
3608
3609 // Create a safe reference to the Underscore object for use below.
3610 var _ = function(obj) {
3611 if (obj instanceof _) return obj;
3612 if (!(this instanceof _)) return new _(obj);
3613 this._wrapped = obj;
3614 };
3615
3616 // Export the Underscore object for **Node.js**, with
3617 // backwards-compatibility for the old `require()` API. If we're in
3618 // the browser, add `_` as a global object.
3619 if (typeof exports !== 'undefined') {
3620 if (typeof module !== 'undefined' && module.exports) {
3621 exports = module.exports = _;
3622 }
3623 exports._ = _;
3624 } else {
3625 root._ = _;
3626 }
3627
3628 // Current version.
3629 _.VERSION = '1.7.0';
3630
3631 // Internal function that returns an efficient (for current engines) version
3632 // of the passed-in callback, to be repeatedly applied in other Underscore
3633 // functions.
3634 var createCallback = function(func, context, argCount) {
3635 if (context === void 0) return func;
3636 switch (argCount == null ? 3 : argCount) {
3637 case 1: return function(value) {
3638 return func.call(context, value);
3639 };
3640 case 2: return function(value, other) {
3641 return func.call(context, value, other);
3642 };
3643 case 3: return function(value, index, collection) {
3644 return func.call(context, value, index, collection);
3645 };
3646 case 4: return function(accumulator, value, index, collection) {
3647 return func.call(context, accumulator, value, index, collection);
3648 };
3649 }
3650 return function() {
3651 return func.apply(context, arguments);
3652 };
3653 };
3654
3655 // A mostly-internal function to generate callbacks that can be applied
3656 // to each element in a collection, returning the desired result — either
3657 // identity, an arbitrary callback, a property matcher, or a property accessor.
3658 _.iteratee = function(value, context, argCount) {
3659 if (value == null) return _.identity;
3660 if (_.isFunction(value)) return createCallback(value, context, argCount);
3661 if (_.isObject(value)) return _.matches(value);
3662 return _.property(value);
3663 };
3664
3665 // Collection Functions
3666 // --------------------
3667
3668 // The cornerstone, an `each` implementation, aka `forEach`.
3669 // Handles raw objects in addition to array-likes. Treats all
3670 // sparse array-likes as if they were dense.
3671 _.each = _.forEach = function(obj, iteratee, context) {
3672 if (obj == null) return obj;
3673 iteratee = createCallback(iteratee, context);
3674 var i, length = obj.length;
3675 if (length === +length) {
3676 for (i = 0; i < length; i++) {
3677 iteratee(obj[i], i, obj);
3678 }
3679 } else {
3680 var keys = _.keys(obj);
3681 for (i = 0, length = keys.length; i < length; i++) {
3682 iteratee(obj[keys[i]], keys[i], obj);
3683 }
3684 }
3685 return obj;
3686 };
3687
3688 // Return the results of applying the iteratee to each element.
3689 _.map = _.collect = function(obj, iteratee, context) {
3690 if (obj == null) return [];
3691 iteratee = _.iteratee(iteratee, context);
3692 var keys = obj.length !== +obj.length && _.keys(obj),
3693 length = (keys || obj).length,
3694 results = Array(length),
3695 currentKey;
3696 for (var index = 0; index < length; index++) {
3697 currentKey = keys ? keys[index] : index;
3698 results[index] = iteratee(obj[currentKey], currentKey, obj);
3699 }
3700 return results;
3701 };
3702
3703 var reduceError = 'Reduce of empty array with no initial value';
3704
3705 // **Reduce** builds up a single result from a list of values, aka `inject`,
3706 // or `foldl`.
3707 _.reduce = _.foldl = _.inject = function(obj, iteratee, memo, context) {
3708 if (obj == null) obj = [];
3709 iteratee = createCallback(iteratee, context, 4);
3710 var keys = obj.length !== +obj.length && _.keys(obj),
3711 length = (keys || obj).length,
3712 index = 0, currentKey;
3713 if (arguments.length < 3) {
3714 if (!length) throw new TypeError(reduceError);
3715 memo = obj[keys ? keys[index++] : index++];
3716 }
3717 for (; index < length; index++) {
3718 currentKey = keys ? keys[index] : index;
3719 memo = iteratee(memo, obj[currentKey], currentKey, obj);
3720 }
3721 return memo;
3722 };
3723
3724 // The right-associative version of reduce, also known as `foldr`.
3725 _.reduceRight = _.foldr = function(obj, iteratee, memo, context) {
3726 if (obj == null) obj = [];
3727 iteratee = createCallback(iteratee, context, 4);
3728 var keys = obj.length !== + obj.length && _.keys(obj),
3729 index = (keys || obj).length,
3730 currentKey;
3731 if (arguments.length < 3) {
3732 if (!index) throw new TypeError(reduceError);
3733 memo = obj[keys ? keys[--index] : --index];
3734 }
3735 while (index--) {
3736 currentKey = keys ? keys[index] : index;
3737 memo = iteratee(memo, obj[currentKey], currentKey, obj);
3738 }
3739 return memo;
3740 };
3741
3742 // Return the first value which passes a truth test. Aliased as `detect`.
3743 _.find = _.detect = function(obj, predicate, context) {
3744 var result;
3745 predicate = _.iteratee(predicate, context);
3746 _.some(obj, function(value, index, list) {
3747 if (predicate(value, index, list)) {
3748 result = value;
3749 return true;
3750 }
3751 });
3752 return result;
3753 };
3754
3755 // Return all the elements that pass a truth test.
3756 // Aliased as `select`.
3757 _.filter = _.select = function(obj, predicate, context) {
3758 var results = [];
3759 if (obj == null) return results;
3760 predicate = _.iteratee(predicate, context);
3761 _.each(obj, function(value, index, list) {
3762 if (predicate(value, index, list)) results.push(value);
3763 });
3764 return results;
3765 };
3766
3767 // Return all the elements for which a truth test fails.
3768 _.reject = function(obj, predicate, context) {
3769 return _.filter(obj, _.negate(_.iteratee(predicate)), context);
3770 };
3771
3772 // Determine whether all of the elements match a truth test.
3773 // Aliased as `all`.
3774 _.every = _.all = function(obj, predicate, context) {
3775 if (obj == null) return true;
3776 predicate = _.iteratee(predicate, context);
3777 var keys = obj.length !== +obj.length && _.keys(obj),
3778 length = (keys || obj).length,
3779 index, currentKey;
3780 for (index = 0; index < length; index++) {
3781 currentKey = keys ? keys[index] : index;
3782 if (!predicate(obj[currentKey], currentKey, obj)) return false;
3783 }
3784 return true;
3785 };
3786
3787 // Determine if at least one element in the object matches a truth test.
3788 // Aliased as `any`.
3789 _.some = _.any = function(obj, predicate, context) {
3790 if (obj == null) return false;
3791 predicate = _.iteratee(predicate, context);
3792 var keys = obj.length !== +obj.length && _.keys(obj),
3793 length = (keys || obj).length,
3794 index, currentKey;
3795 for (index = 0; index < length; index++) {
3796 currentKey = keys ? keys[index] : index;
3797 if (predicate(obj[currentKey], currentKey, obj)) return true;
3798 }
3799 return false;
3800 };
3801
3802 // Determine if the array or object contains a given value (using `===`).
3803 // Aliased as `include`.
3804 _.contains = _.include = function(obj, target) {
3805 if (obj == null) return false;
3806 if (obj.length !== +obj.length) obj = _.values(obj);
3807 return _.indexOf(obj, target) >= 0;
3808 };
3809
3810 // Invoke a method (with arguments) on every item in a collection.
3811 _.invoke = function(obj, method) {
3812 var args = slice.call(arguments, 2);
3813 var isFunc = _.isFunction(method);
3814 return _.map(obj, function(value) {
3815 return (isFunc ? method : value[method]).apply(value, args);
3816 });
3817 };
3818
3819 // Convenience version of a common use case of `map`: fetching a property.
3820 _.pluck = function(obj, key) {
3821 return _.map(obj, _.property(key));
3822 };
3823
3824 // Convenience version of a common use case of `filter`: selecting only objects
3825 // containing specific `key:value` pairs.
3826 _.where = function(obj, attrs) {
3827 return _.filter(obj, _.matches(attrs));
3828 };
3829
3830 // Convenience version of a common use case of `find`: getting the first object
3831 // containing specific `key:value` pairs.
3832 _.findWhere = function(obj, attrs) {
3833 return _.find(obj, _.matches(attrs));
3834 };
3835
3836 // Return the maximum element (or element-based computation).
3837 _.max = function(obj, iteratee, context) {
3838 var result = -Infinity, lastComputed = -Infinity,
3839 value, computed;
3840 if (iteratee == null && obj != null) {
3841 obj = obj.length === +obj.length ? obj : _.values(obj);
3842 for (var i = 0, length = obj.length; i < length; i++) {
3843 value = obj[i];
3844 if (value > result) {
3845 result = value;
3846 }
3847 }
3848 } else {
3849 iteratee = _.iteratee(iteratee, context);
3850 _.each(obj, function(value, index, list) {
3851 computed = iteratee(value, index, list);
3852 if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
3853 result = value;
3854 lastComputed = computed;
3855 }
3856 });
3857 }
3858 return result;
3859 };
3860
3861 // Return the minimum element (or element-based computation).
3862 _.min = function(obj, iteratee, context) {
3863 var result = Infinity, lastComputed = Infinity,
3864 value, computed;
3865 if (iteratee == null && obj != null) {
3866 obj = obj.length === +obj.length ? obj : _.values(obj);
3867 for (var i = 0, length = obj.length; i < length; i++) {
3868 value = obj[i];
3869 if (value < result) {
3870 result = value;
3871 }
3872 }
3873 } else {
3874 iteratee = _.iteratee(iteratee, context);
3875 _.each(obj, function(value, index, list) {
3876 computed = iteratee(value, index, list);
3877 if (computed < lastComputed || computed === Infinity && result === Infinity) {
3878 result = value;
3879 lastComputed = computed;
3880 }
3881 });
3882 }
3883 return result;
3884 };
3885
3886 // Shuffle a collection, using the modern version of the
3887 // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
3888 _.shuffle = function(obj) {
3889 var set = obj && obj.length === +obj.length ? obj : _.values(obj);
3890 var length = set.length;
3891 var shuffled = Array(length);
3892 for (var index = 0, rand; index < length; index++) {
3893 rand = _.random(0, index);
3894 if (rand !== index) shuffled[index] = shuffled[rand];
3895 shuffled[rand] = set[index];
3896 }
3897 return shuffled;
3898 };
3899
3900 // Sample **n** random values from a collection.
3901 // If **n** is not specified, returns a single random element.
3902 // The internal `guard` argument allows it to work with `map`.
3903 _.sample = function(obj, n, guard) {
3904 if (n == null || guard) {
3905 if (obj.length !== +obj.length) obj = _.values(obj);
3906 return obj[_.random(obj.length - 1)];
3907 }
3908 return _.shuffle(obj).slice(0, Math.max(0, n));
3909 };
3910
3911 // Sort the object's values by a criterion produced by an iteratee.
3912 _.sortBy = function(obj, iteratee, context) {
3913 iteratee = _.iteratee(iteratee, context);
3914 return _.pluck(_.map(obj, function(value, index, list) {
3915 return {
3916 value: value,
3917 index: index,
3918 criteria: iteratee(value, index, list)
3919 };
3920 }).sort(function(left, right) {
3921 var a = left.criteria;
3922 var b = right.criteria;
3923 if (a !== b) {
3924 if (a > b || a === void 0) return 1;
3925 if (a < b || b === void 0) return -1;
3926 }
3927 return left.index - right.index;
3928 }), 'value');
3929 };
3930
3931 // An internal function used for aggregate "group by" operations.
3932 var group = function(behavior) {
3933 return function(obj, iteratee, context) {
3934 var result = {};
3935 iteratee = _.iteratee(iteratee, context);
3936 _.each(obj, function(value, index) {
3937 var key = iteratee(value, index, obj);
3938 behavior(result, value, key);
3939 });
3940 return result;
3941 };
3942 };
3943
3944 // Groups the object's values by a criterion. Pass either a string attribute
3945 // to group by, or a function that returns the criterion.
3946 _.groupBy = group(function(result, value, key) {
3947 if (_.has(result, key)) result[key].push(value); else result[key] = [value];
3948 });
3949
3950 // Indexes the object's values by a criterion, similar to `groupBy`, but for
3951 // when you know that your index values will be unique.
3952 _.indexBy = group(function(result, value, key) {
3953 result[key] = value;
3954 });
3955
3956 // Counts instances of an object that group by a certain criterion. Pass
3957 // either a string attribute to count by, or a function that returns the
3958 // criterion.
3959 _.countBy = group(function(result, value, key) {
3960 if (_.has(result, key)) result[key]++; else result[key] = 1;
3961 });
3962
3963 // Use a comparator function to figure out the smallest index at which
3964 // an object should be inserted so as to maintain order. Uses binary search.
3965 _.sortedIndex = function(array, obj, iteratee, context) {
3966 iteratee = _.iteratee(iteratee, context, 1);
3967 var value = iteratee(obj);
3968 var low = 0, high = array.length;
3969 while (low < high) {
3970 var mid = low + high >>> 1;
3971 if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
3972 }
3973 return low;
3974 };
3975
3976 // Safely create a real, live array from anything iterable.
3977 _.toArray = function(obj) {
3978 if (!obj) return [];
3979 if (_.isArray(obj)) return slice.call(obj);
3980 if (obj.length === +obj.length) return _.map(obj, _.identity);
3981 return _.values(obj);
3982 };
3983
3984 // Return the number of elements in an object.
3985 _.size = function(obj) {
3986 if (obj == null) return 0;
3987 return obj.length === +obj.length ? obj.length : _.keys(obj).length;
3988 };
3989
3990 // Split a collection into two arrays: one whose elements all satisfy the given
3991 // predicate, and one whose elements all do not satisfy the predicate.
3992 _.partition = function(obj, predicate, context) {
3993 predicate = _.iteratee(predicate, context);
3994 var pass = [], fail = [];
3995 _.each(obj, function(value, key, obj) {
3996 (predicate(value, key, obj) ? pass : fail).push(value);
3997 });
3998 return [pass, fail];
3999 };
4000
4001 // Array Functions
4002 // ---------------
4003
4004 // Get the first element of an array. Passing **n** will return the first N
4005 // values in the array. Aliased as `head` and `take`. The **guard** check
4006 // allows it to work with `_.map`.
4007 _.first = _.head = _.take = function(array, n, guard) {
4008 if (array == null) return void 0;
4009 if (n == null || guard) return array[0];
4010 if (n < 0) return [];
4011 return slice.call(array, 0, n);
4012 };
4013
4014 // Returns everything but the last entry of the array. Especially useful on
4015 // the arguments object. Passing **n** will return all the values in
4016 // the array, excluding the last N. The **guard** check allows it to work with
4017 // `_.map`.
4018 _.initial = function(array, n, guard) {
4019 return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
4020 };
4021
4022 // Get the last element of an array. Passing **n** will return the last N
4023 // values in the array. The **guard** check allows it to work with `_.map`.
4024 _.last = function(array, n, guard) {
4025 if (array == null) return void 0;
4026 if (n == null || guard) return array[array.length - 1];
4027 return slice.call(array, Math.max(array.length - n, 0));
4028 };
4029
4030 // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
4031 // Especially useful on the arguments object. Passing an **n** will return
4032 // the rest N values in the array. The **guard**
4033 // check allows it to work with `_.map`.
4034 _.rest = _.tail = _.drop = function(array, n, guard) {
4035 return slice.call(array, n == null || guard ? 1 : n);
4036 };
4037
4038 // Trim out all falsy values from an array.
4039 _.compact = function(array) {
4040 return _.filter(array, _.identity);
4041 };
4042
4043 // Internal implementation of a recursive `flatten` function.
4044 var flatten = function(input, shallow, strict, output) {
4045 if (shallow && _.every(input, _.isArray)) {
4046 return concat.apply(output, input);
4047 }
4048 for (var i = 0, length = input.length; i < length; i++) {
4049 var value = input[i];
4050 if (!_.isArray(value) && !_.isArguments(value)) {
4051 if (!strict) output.push(value);
4052 } else if (shallow) {
4053 push.apply(output, value);
4054 } else {
4055 flatten(value, shallow, strict, output);
4056 }
4057 }
4058 return output;
4059 };
4060
4061 // Flatten out an array, either recursively (by default), or just one level.
4062 _.flatten = function(array, shallow) {
4063 return flatten(array, shallow, false, []);
4064 };
4065
4066 // Return a version of the array that does not contain the specified value(s).
4067 _.without = function(array) {
4068 return _.difference(array, slice.call(arguments, 1));
4069 };
4070
4071 // Produce a duplicate-free version of the array. If the array has already
4072 // been sorted, you have the option of using a faster algorithm.
4073 // Aliased as `unique`.
4074 _.uniq = _.unique = function(array, isSorted, iteratee, context) {
4075 if (array == null) return [];
4076 if (!_.isBoolean(isSorted)) {
4077 context = iteratee;
4078 iteratee = isSorted;
4079 isSorted = false;
4080 }
4081 if (iteratee != null) iteratee = _.iteratee(iteratee, context);
4082 var result = [];
4083 var seen = [];
4084 for (var i = 0, length = array.length; i < length; i++) {
4085 var value = array[i];
4086 if (isSorted) {
4087 if (!i || seen !== value) result.push(value);
4088 seen = value;
4089 } else if (iteratee) {
4090 var computed = iteratee(value, i, array);
4091 if (_.indexOf(seen, computed) < 0) {
4092 seen.push(computed);
4093 result.push(value);
4094 }
4095 } else if (_.indexOf(result, value) < 0) {
4096 result.push(value);
4097 }
4098 }
4099 return result;
4100 };
4101
4102 // Produce an array that contains the union: each distinct element from all of
4103 // the passed-in arrays.
4104 _.union = function() {
4105 return _.uniq(flatten(arguments, true, true, []));
4106 };
4107
4108 // Produce an array that contains every item shared between all the
4109 // passed-in arrays.
4110 _.intersection = function(array) {
4111 if (array == null) return [];
4112 var result = [];
4113 var argsLength = arguments.length;
4114 for (var i = 0, length = array.length; i < length; i++) {
4115 var item = array[i];
4116 if (_.contains(result, item)) continue;
4117 for (var j = 1; j < argsLength; j++) {
4118 if (!_.contains(arguments[j], item)) break;
4119 }
4120 if (j === argsLength) result.push(item);
4121 }
4122 return result;
4123 };
4124
4125 // Take the difference between one array and a number of other arrays.
4126 // Only the elements present in just the first array will remain.
4127 _.difference = function(array) {
4128 var rest = flatten(slice.call(arguments, 1), true, true, []);
4129 return _.filter(array, function(value){
4130 return !_.contains(rest, value);
4131 });
4132 };
4133
4134 // Zip together multiple lists into a single array -- elements that share
4135 // an index go together.
4136 _.zip = function(array) {
4137 if (array == null) return [];
4138 var length = _.max(arguments, 'length').length;
4139 var results = Array(length);
4140 for (var i = 0; i < length; i++) {
4141 results[i] = _.pluck(arguments, i);
4142 }
4143 return results;
4144 };
4145
4146 // Converts lists into objects. Pass either a single array of `[key, value]`
4147 // pairs, or two parallel arrays of the same length -- one of keys, and one of
4148 // the corresponding values.
4149 _.object = function(list, values) {
4150 if (list == null) return {};
4151 var result = {};
4152 for (var i = 0, length = list.length; i < length; i++) {
4153 if (values) {
4154 result[list[i]] = values[i];
4155 } else {
4156 result[list[i][0]] = list[i][1];
4157 }
4158 }
4159 return result;
4160 };
4161
4162 // Return the position of the first occurrence of an item in an array,
4163 // or -1 if the item is not included in the array.
4164 // If the array is large and already in sort order, pass `true`
4165 // for **isSorted** to use binary search.
4166 _.indexOf = function(array, item, isSorted) {
4167 if (array == null) return -1;
4168 var i = 0, length = array.length;
4169 if (isSorted) {
4170 if (typeof isSorted == 'number') {
4171 i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
4172 } else {
4173 i = _.sortedIndex(array, item);
4174 return array[i] === item ? i : -1;
4175 }
4176 }
4177 for (; i < length; i++) if (array[i] === item) return i;
4178 return -1;
4179 };
4180
4181 _.lastIndexOf = function(array, item, from) {
4182 if (array == null) return -1;
4183 var idx = array.length;
4184 if (typeof from == 'number') {
4185 idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
4186 }
4187 while (--idx >= 0) if (array[idx] === item) return idx;
4188 return -1;
4189 };
4190
4191 // Generate an integer Array containing an arithmetic progression. A port of
4192 // the native Python `range()` function. See
4193 // [the Python documentation](http://docs.python.org/library/functions.html#range).
4194 _.range = function(start, stop, step) {
4195 if (arguments.length <= 1) {
4196 stop = start || 0;
4197 start = 0;
4198 }
4199 step = step || 1;
4200
4201 var length = Math.max(Math.ceil((stop - start) / step), 0);
4202 var range = Array(length);
4203
4204 for (var idx = 0; idx < length; idx++, start += step) {
4205 range[idx] = start;
4206 }
4207
4208 return range;
4209 };
4210
4211 // Function (ahem) Functions
4212 // ------------------
4213
4214 // Reusable constructor function for prototype setting.
4215 var Ctor = function(){};
4216
4217 // Create a function bound to a given object (assigning `this`, and arguments,
4218 // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
4219 // available.
4220 _.bind = function(func, context) {
4221 var args, bound;
4222 if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
4223 if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
4224 args = slice.call(arguments, 2);
4225 bound = function() {
4226 if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
4227 Ctor.prototype = func.prototype;
4228 var self = new Ctor;
4229 Ctor.prototype = null;
4230 var result = func.apply(self, args.concat(slice.call(arguments)));
4231 if (_.isObject(result)) return result;
4232 return self;
4233 };
4234 return bound;
4235 };
4236
4237 // Partially apply a function by creating a version that has had some of its
4238 // arguments pre-filled, without changing its dynamic `this` context. _ acts
4239 // as a placeholder, allowing any combination of arguments to be pre-filled.
4240 _.partial = function(func) {
4241 var boundArgs = slice.call(arguments, 1);
4242 return function() {
4243 var position = 0;
4244 var args = boundArgs.slice();
4245 for (var i = 0, length = args.length; i < length; i++) {
4246 if (args[i] === _) args[i] = arguments[position++];
4247 }
4248 while (position < arguments.length) args.push(arguments[position++]);
4249 return func.apply(this, args);
4250 };
4251 };
4252
4253 // Bind a number of an object's methods to that object. Remaining arguments
4254 // are the method names to be bound. Useful for ensuring that all callbacks
4255 // defined on an object belong to it.
4256 _.bindAll = function(obj) {
4257 var i, length = arguments.length, key;
4258 if (length <= 1) throw new Error('bindAll must be passed function names');
4259 for (i = 1; i < length; i++) {
4260 key = arguments[i];
4261 obj[key] = _.bind(obj[key], obj);
4262 }
4263 return obj;
4264 };
4265
4266 // Memoize an expensive function by storing its results.
4267 _.memoize = function(func, hasher) {
4268 var memoize = function(key) {
4269 var cache = memoize.cache;
4270 var address = hasher ? hasher.apply(this, arguments) : key;
4271 if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
4272 return cache[address];
4273 };
4274 memoize.cache = {};
4275 return memoize;
4276 };
4277
4278 // Delays a function for the given number of milliseconds, and then calls
4279 // it with the arguments supplied.
4280 _.delay = function(func, wait) {
4281 var args = slice.call(arguments, 2);
4282 return setTimeout(function(){
4283 return func.apply(null, args);
4284 }, wait);
4285 };
4286
4287 // Defers a function, scheduling it to run after the current call stack has
4288 // cleared.
4289 _.defer = function(func) {
4290 return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
4291 };
4292
4293 // Returns a function, that, when invoked, will only be triggered at most once
4294 // during a given window of time. Normally, the throttled function will run
4295 // as much as it can, without ever going more than once per `wait` duration;
4296 // but if you'd like to disable the execution on the leading edge, pass
4297 // `{leading: false}`. To disable execution on the trailing edge, ditto.
4298 _.throttle = function(func, wait, options) {
4299 var context, args, result;
4300 var timeout = null;
4301 var previous = 0;
4302 if (!options) options = {};
4303 var later = function() {
4304 previous = options.leading === false ? 0 : _.now();
4305 timeout = null;
4306 result = func.apply(context, args);
4307 if (!timeout) context = args = null;
4308 };
4309 return function() {
4310 var now = _.now();
4311 if (!previous && options.leading === false) previous = now;
4312 var remaining = wait - (now - previous);
4313 context = this;
4314 args = arguments;
4315 if (remaining <= 0 || remaining > wait) {
4316 clearTimeout(timeout);
4317 timeout = null;
4318 previous = now;
4319 result = func.apply(context, args);
4320 if (!timeout) context = args = null;
4321 } else if (!timeout && options.trailing !== false) {
4322 timeout = setTimeout(later, remaining);
4323 }
4324 return result;
4325 };
4326 };
4327
4328 // Returns a function, that, as long as it continues to be invoked, will not
4329 // be triggered. The function will be called after it stops being called for
4330 // N milliseconds. If `immediate` is passed, trigger the function on the
4331 // leading edge, instead of the trailing.
4332 _.debounce = function(func, wait, immediate) {
4333 var timeout, args, context, timestamp, result;
4334
4335 var later = function() {
4336 var last = _.now() - timestamp;
4337
4338 if (last < wait && last > 0) {
4339 timeout = setTimeout(later, wait - last);
4340 } else {
4341 timeout = null;
4342 if (!immediate) {
4343 result = func.apply(context, args);
4344 if (!timeout) context = args = null;
4345 }
4346 }
4347 };
4348
4349 return function() {
4350 context = this;
4351 args = arguments;
4352 timestamp = _.now();
4353 var callNow = immediate && !timeout;
4354 if (!timeout) timeout = setTimeout(later, wait);
4355 if (callNow) {
4356 result = func.apply(context, args);
4357 context = args = null;
4358 }
4359
4360 return result;
4361 };
4362 };
4363
4364 // Returns the first function passed as an argument to the second,
4365 // allowing you to adjust arguments, run code before and after, and
4366 // conditionally execute the original function.
4367 _.wrap = function(func, wrapper) {
4368 return _.partial(wrapper, func);
4369 };
4370
4371 // Returns a negated version of the passed-in predicate.
4372 _.negate = function(predicate) {
4373 return function() {
4374 return !predicate.apply(this, arguments);
4375 };
4376 };
4377
4378 // Returns a function that is the composition of a list of functions, each
4379 // consuming the return value of the function that follows.
4380 _.compose = function() {
4381 var args = arguments;
4382 var start = args.length - 1;
4383 return function() {
4384 var i = start;
4385 var result = args[start].apply(this, arguments);
4386 while (i--) result = args[i].call(this, result);
4387 return result;
4388 };
4389 };
4390
4391 // Returns a function that will only be executed after being called N times.
4392 _.after = function(times, func) {
4393 return function() {
4394 if (--times < 1) {
4395 return func.apply(this, arguments);
4396 }
4397 };
4398 };
4399
4400 // Returns a function that will only be executed before being called N times.
4401 _.before = function(times, func) {
4402 var memo;
4403 return function() {
4404 if (--times > 0) {
4405 memo = func.apply(this, arguments);
4406 } else {
4407 func = null;
4408 }
4409 return memo;
4410 };
4411 };
4412
4413 // Returns a function that will be executed at most one time, no matter how
4414 // often you call it. Useful for lazy initialization.
4415 _.once = _.partial(_.before, 2);
4416
4417 // Object Functions
4418 // ----------------
4419
4420 // Retrieve the names of an object's properties.
4421 // Delegates to **ECMAScript 5**'s native `Object.keys`
4422 _.keys = function(obj) {
4423 if (!_.isObject(obj)) return [];
4424 if (nativeKeys) return nativeKeys(obj);
4425 var keys = [];
4426 for (var key in obj) if (_.has(obj, key)) keys.push(key);
4427 return keys;
4428 };
4429
4430 // Retrieve the values of an object's properties.
4431 _.values = function(obj) {
4432 var keys = _.keys(obj);
4433 var length = keys.length;
4434 var values = Array(length);
4435 for (var i = 0; i < length; i++) {
4436 values[i] = obj[keys[i]];
4437 }
4438 return values;
4439 };
4440
4441 // Convert an object into a list of `[key, value]` pairs.
4442 _.pairs = function(obj) {
4443 var keys = _.keys(obj);
4444 var length = keys.length;
4445 var pairs = Array(length);
4446 for (var i = 0; i < length; i++) {
4447 pairs[i] = [keys[i], obj[keys[i]]];
4448 }
4449 return pairs;
4450 };
4451
4452 // Invert the keys and values of an object. The values must be serializable.
4453 _.invert = function(obj) {
4454 var result = {};
4455 var keys = _.keys(obj);
4456 for (var i = 0, length = keys.length; i < length; i++) {
4457 result[obj[keys[i]]] = keys[i];
4458 }
4459 return result;
4460 };
4461
4462 // Return a sorted list of the function names available on the object.
4463 // Aliased as `methods`
4464 _.functions = _.methods = function(obj) {
4465 var names = [];
4466 for (var key in obj) {
4467 if (_.isFunction(obj[key])) names.push(key);
4468 }
4469 return names.sort();
4470 };
4471
4472 // Extend a given object with all the properties in passed-in object(s).
4473 _.extend = function(obj) {
4474 if (!_.isObject(obj)) return obj;
4475 var source, prop;
4476 for (var i = 1, length = arguments.length; i < length; i++) {
4477 source = arguments[i];
4478 for (prop in source) {
4479 if (hasOwnProperty.call(source, prop)) {
4480 obj[prop] = source[prop];
4481 }
4482 }
4483 }
4484 return obj;
4485 };
4486
4487 // Return a copy of the object only containing the whitelisted properties.
4488 _.pick = function(obj, iteratee, context) {
4489 var result = {}, key;
4490 if (obj == null) return result;
4491 if (_.isFunction(iteratee)) {
4492 iteratee = createCallback(iteratee, context);
4493 for (key in obj) {
4494 var value = obj[key];
4495 if (iteratee(value, key, obj)) result[key] = value;
4496 }
4497 } else {
4498 var keys = concat.apply([], slice.call(arguments, 1));
4499 obj = new Object(obj);
4500 for (var i = 0, length = keys.length; i < length; i++) {
4501 key = keys[i];
4502 if (key in obj) result[key] = obj[key];
4503 }
4504 }
4505 return result;
4506 };
4507
4508 // Return a copy of the object without the blacklisted properties.
4509 _.omit = function(obj, iteratee, context) {
4510 if (_.isFunction(iteratee)) {
4511 iteratee = _.negate(iteratee);
4512 } else {
4513 var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
4514 iteratee = function(value, key) {
4515 return !_.contains(keys, key);
4516 };
4517 }
4518 return _.pick(obj, iteratee, context);
4519 };
4520
4521 // Fill in a given object with default properties.
4522 _.defaults = function(obj) {
4523 if (!_.isObject(obj)) return obj;
4524 for (var i = 1, length = arguments.length; i < length; i++) {
4525 var source = arguments[i];
4526 for (var prop in source) {
4527 if (obj[prop] === void 0) obj[prop] = source[prop];
4528 }
4529 }
4530 return obj;
4531 };
4532
4533 // Create a (shallow-cloned) duplicate of an object.
4534 _.clone = function(obj) {
4535 if (!_.isObject(obj)) return obj;
4536 return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
4537 };
4538
4539 // Invokes interceptor with the obj, and then returns obj.
4540 // The primary purpose of this method is to "tap into" a method chain, in
4541 // order to perform operations on intermediate results within the chain.
4542 _.tap = function(obj, interceptor) {
4543 interceptor(obj);
4544 return obj;
4545 };
4546
4547 // Internal recursive comparison function for `isEqual`.
4548 var eq = function(a, b, aStack, bStack) {
4549 // Identical objects are equal. `0 === -0`, but they aren't identical.
4550 // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
4551 if (a === b) return a !== 0 || 1 / a === 1 / b;
4552 // A strict comparison is necessary because `null == undefined`.
4553 if (a == null || b == null) return a === b;
4554 // Unwrap any wrapped objects.
4555 if (a instanceof _) a = a._wrapped;
4556 if (b instanceof _) b = b._wrapped;
4557 // Compare `[[Class]]` names.
4558 var className = toString.call(a);
4559 if (className !== toString.call(b)) return false;
4560 switch (className) {
4561 // Strings, numbers, regular expressions, dates, and booleans are compared by value.
4562 case '[object RegExp]':
4563 // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
4564 case '[object String]':
4565 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
4566 // equivalent to `new String("5")`.
4567 return '' + a === '' + b;
4568 case '[object Number]':
4569 // `NaN`s are equivalent, but non-reflexive.
4570 // Object(NaN) is equivalent to NaN
4571 if (+a !== +a) return +b !== +b;
4572 // An `egal` comparison is performed for other numeric values.
4573 return +a === 0 ? 1 / +a === 1 / b : +a === +b;
4574 case '[object Date]':
4575 case '[object Boolean]':
4576 // Coerce dates and booleans to numeric primitive values. Dates are compared by their
4577 // millisecond representations. Note that invalid dates with millisecond representations
4578 // of `NaN` are not equivalent.
4579 return +a === +b;
4580 }
4581 if (typeof a != 'object' || typeof b != 'object') return false;
4582 // Assume equality for cyclic structures. The algorithm for detecting cyclic
4583 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
4584 var length = aStack.length;
4585 while (length--) {
4586 // Linear search. Performance is inversely proportional to the number of
4587 // unique nested structures.
4588 if (aStack[length] === a) return bStack[length] === b;
4589 }
4590 // Objects with different constructors are not equivalent, but `Object`s
4591 // from different frames are.
4592 var aCtor = a.constructor, bCtor = b.constructor;
4593 if (
4594 aCtor !== bCtor &&
4595 // Handle Object.create(x) cases
4596 'constructor' in a && 'constructor' in b &&
4597 !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
4598 _.isFunction(bCtor) && bCtor instanceof bCtor)
4599 ) {
4600 return false;
4601 }
4602 // Add the first object to the stack of traversed objects.
4603 aStack.push(a);
4604 bStack.push(b);
4605 var size, result;
4606 // Recursively compare objects and arrays.
4607 if (className === '[object Array]') {
4608 // Compare array lengths to determine if a deep comparison is necessary.
4609 size = a.length;
4610 result = size === b.length;
4611 if (result) {
4612 // Deep compare the contents, ignoring non-numeric properties.
4613 while (size--) {
4614 if (!(result = eq(a[size], b[size], aStack, bStack))) break;
4615 }
4616 }
4617 } else {
4618 // Deep compare objects.
4619 var keys = _.keys(a), key;
4620 size = keys.length;
4621 // Ensure that both objects contain the same number of properties before comparing deep equality.
4622 result = _.keys(b).length === size;
4623 if (result) {
4624 while (size--) {
4625 // Deep compare each member
4626 key = keys[size];
4627 if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
4628 }
4629 }
4630 }
4631 // Remove the first object from the stack of traversed objects.
4632 aStack.pop();
4633 bStack.pop();
4634 return result;
4635 };
4636
4637 // Perform a deep comparison to check if two objects are equal.
4638 _.isEqual = function(a, b) {
4639 return eq(a, b, [], []);
4640 };
4641
4642 // Is a given array, string, or object empty?
4643 // An "empty" object has no enumerable own-properties.
4644 _.isEmpty = function(obj) {
4645 if (obj == null) return true;
4646 if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
4647 for (var key in obj) if (_.has(obj, key)) return false;
4648 return true;
4649 };
4650
4651 // Is a given value a DOM element?
4652 _.isElement = function(obj) {
4653 return !!(obj && obj.nodeType === 1);
4654 };
4655
4656 // Is a given value an array?
4657 // Delegates to ECMA5's native Array.isArray
4658 _.isArray = nativeIsArray || function(obj) {
4659 return toString.call(obj) === '[object Array]';
4660 };
4661
4662 // Is a given variable an object?
4663 _.isObject = function(obj) {
4664 var type = typeof obj;
4665 return type === 'function' || type === 'object' && !!obj;
4666 };
4667
4668 // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
4669 _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
4670 _['is' + name] = function(obj) {
4671 return toString.call(obj) === '[object ' + name + ']';
4672 };
4673 });
4674
4675 // Define a fallback version of the method in browsers (ahem, IE), where
4676 // there isn't any inspectable "Arguments" type.
4677 if (!_.isArguments(arguments)) {
4678 _.isArguments = function(obj) {
4679 return _.has(obj, 'callee');
4680 };
4681 }
4682
4683 // Optimize `isFunction` if appropriate. Work around an IE 11 bug.
4684 if (typeof /./ !== 'function') {
4685 _.isFunction = function(obj) {
4686 return typeof obj == 'function' || false;
4687 };
4688 }
4689
4690 // Is a given object a finite number?
4691 _.isFinite = function(obj) {
4692 return isFinite(obj) && !isNaN(parseFloat(obj));
4693 };
4694
4695 // Is the given value `NaN`? (NaN is the only number which does not equal itself).
4696 _.isNaN = function(obj) {
4697 return _.isNumber(obj) && obj !== +obj;
4698 };
4699
4700 // Is a given value a boolean?
4701 _.isBoolean = function(obj) {
4702 return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
4703 };
4704
4705 // Is a given value equal to null?
4706 _.isNull = function(obj) {
4707 return obj === null;
4708 };
4709
4710 // Is a given variable undefined?
4711 _.isUndefined = function(obj) {
4712 return obj === void 0;
4713 };
4714
4715 // Shortcut function for checking if an object has a given property directly
4716 // on itself (in other words, not on a prototype).
4717 _.has = function(obj, key) {
4718 return obj != null && hasOwnProperty.call(obj, key);
4719 };
4720
4721 // Utility Functions
4722 // -----------------
4723
4724 // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
4725 // previous owner. Returns a reference to the Underscore object.
4726 _.noConflict = function() {
4727 root._ = previousUnderscore;
4728 return this;
4729 };
4730
4731 // Keep the identity function around for default iteratees.
4732 _.identity = function(value) {
4733 return value;
4734 };
4735
4736 _.constant = function(value) {
4737 return function() {
4738 return value;
4739 };
4740 };
4741
4742 _.noop = function(){};
4743
4744 _.property = function(key) {
4745 return function(obj) {
4746 return obj[key];
4747 };
4748 };
4749
4750 // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
4751 _.matches = function(attrs) {
4752 var pairs = _.pairs(attrs), length = pairs.length;
4753 return function(obj) {
4754 if (obj == null) return !length;
4755 obj = new Object(obj);
4756 for (var i = 0; i < length; i++) {
4757 var pair = pairs[i], key = pair[0];
4758 if (pair[1] !== obj[key] || !(key in obj)) return false;
4759 }
4760 return true;
4761 };
4762 };
4763
4764 // Run a function **n** times.
4765 _.times = function(n, iteratee, context) {
4766 var accum = Array(Math.max(0, n));
4767 iteratee = createCallback(iteratee, context, 1);
4768 for (var i = 0; i < n; i++) accum[i] = iteratee(i);
4769 return accum;
4770 };
4771
4772 // Return a random integer between min and max (inclusive).
4773 _.random = function(min, max) {
4774 if (max == null) {
4775 max = min;
4776 min = 0;
4777 }
4778 return min + Math.floor(Math.random() * (max - min + 1));
4779 };
4780
4781 // A (possibly faster) way to get the current timestamp as an integer.
4782 _.now = Date.now || function() {
4783 return new Date().getTime();
4784 };
4785
4786 // List of HTML entities for escaping.
4787 var escapeMap = {
4788 '&': '&amp;',
4789 '<': '&lt;',
4790 '>': '&gt;',
4791 '"': '&quot;',
4792 "'": '&#x27;',
4793 '`': '&#x60;'
4794 };
4795 var unescapeMap = _.invert(escapeMap);
4796
4797 // Functions for escaping and unescaping strings to/from HTML interpolation.
4798 var createEscaper = function(map) {
4799 var escaper = function(match) {
4800 return map[match];
4801 };
4802 // Regexes for identifying a key that needs to be escaped
4803 var source = '(?:' + _.keys(map).join('|') + ')';
4804 var testRegexp = RegExp(source);
4805 var replaceRegexp = RegExp(source, 'g');
4806 return function(string) {
4807 string = string == null ? '' : '' + string;
4808 return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
4809 };
4810 };
4811 _.escape = createEscaper(escapeMap);
4812 _.unescape = createEscaper(unescapeMap);
4813
4814 // If the value of the named `property` is a function then invoke it with the
4815 // `object` as context; otherwise, return it.
4816 _.result = function(object, property) {
4817 if (object == null) return void 0;
4818 var value = object[property];
4819 return _.isFunction(value) ? object[property]() : value;
4820 };
4821
4822 // Generate a unique integer id (unique within the entire client session).
4823 // Useful for temporary DOM ids.
4824 var idCounter = 0;
4825 _.uniqueId = function(prefix) {
4826 var id = ++idCounter + '';
4827 return prefix ? prefix + id : id;
4828 };
4829
4830 // By default, Underscore uses ERB-style template delimiters, change the
4831 // following template settings to use alternative delimiters.
4832 _.templateSettings = {
4833 evaluate : /<%([\s\S]+?)%>/g,
4834 interpolate : /<%=([\s\S]+?)%>/g,
4835 escape : /<%-([\s\S]+?)%>/g
4836 };
4837
4838 // When customizing `templateSettings`, if you don't want to define an
4839 // interpolation, evaluation or escaping regex, we need one that is
4840 // guaranteed not to match.
4841 var noMatch = /(.)^/;
4842
4843 // Certain characters need to be escaped so that they can be put into a
4844 // string literal.
4845 var escapes = {
4846 "'": "'",
4847 '\\': '\\',
4848 '\r': 'r',
4849 '\n': 'n',
4850 '\u2028': 'u2028',
4851 '\u2029': 'u2029'
4852 };
4853
4854 var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
4855
4856 var escapeChar = function(match) {
4857 return '\\' + escapes[match];
4858 };
4859
4860 // JavaScript micro-templating, similar to John Resig's implementation.
4861 // Underscore templating handles arbitrary delimiters, preserves whitespace,
4862 // and correctly escapes quotes within interpolated code.
4863 // NB: `oldSettings` only exists for backwards compatibility.
4864 _.template = function(text, settings, oldSettings) {
4865 if (!settings && oldSettings) settings = oldSettings;
4866 settings = _.defaults({}, settings, _.templateSettings);
4867
4868 // Combine delimiters into one regular expression via alternation.
4869 var matcher = RegExp([
4870 (settings.escape || noMatch).source,
4871 (settings.interpolate || noMatch).source,
4872 (settings.evaluate || noMatch).source
4873 ].join('|') + '|$', 'g');
4874
4875 // Compile the template source, escaping string literals appropriately.
4876 var index = 0;
4877 var source = "__p+='";
4878 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
4879 source += text.slice(index, offset).replace(escaper, escapeChar);
4880 index = offset + match.length;
4881
4882 if (escape) {
4883 source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
4884 } else if (interpolate) {
4885 source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
4886 } else if (evaluate) {
4887 source += "';\n" + evaluate + "\n__p+='";
4888 }
4889
4890 // Adobe VMs need the match returned to produce the correct offest.
4891 return match;
4892 });
4893 source += "';\n";
4894
4895 // If a variable is not specified, place data values in local scope.
4896 if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
4897
4898 source = "var __t,__p='',__j=Array.prototype.join," +
4899 "print=function(){__p+=__j.call(arguments,'');};\n" +
4900 source + 'return __p;\n';
4901
4902 try {
4903 var render = new Function(settings.variable || 'obj', '_', source);
4904 } catch (e) {
4905 e.source = source;
4906 throw e;
4907 }
4908
4909 var template = function(data) {
4910 return render.call(this, data, _);
4911 };
4912
4913 // Provide the compiled source as a convenience for precompilation.
4914 var argument = settings.variable || 'obj';
4915 template.source = 'function(' + argument + '){\n' + source + '}';
4916
4917 return template;
4918 };
4919
4920 // Add a "chain" function. Start chaining a wrapped Underscore object.
4921 _.chain = function(obj) {
4922 var instance = _(obj);
4923 instance._chain = true;
4924 return instance;
4925 };
4926
4927 // OOP
4928 // ---------------
4929 // If Underscore is called as a function, it returns a wrapped object that
4930 // can be used OO-style. This wrapper holds altered versions of all the
4931 // underscore functions. Wrapped objects may be chained.
4932
4933 // Helper function to continue chaining intermediate results.
4934 var result = function(obj) {
4935 return this._chain ? _(obj).chain() : obj;
4936 };
4937
4938 // Add your own custom functions to the Underscore object.
4939 _.mixin = function(obj) {
4940 _.each(_.functions(obj), function(name) {
4941 var func = _[name] = obj[name];
4942 _.prototype[name] = function() {
4943 var args = [this._wrapped];
4944 push.apply(args, arguments);
4945 return result.call(this, func.apply(_, args));
4946 };
4947 });
4948 };
4949
4950 // Add all of the Underscore functions to the wrapper object.
4951 _.mixin(_);
4952
4953 // Add all mutator Array functions to the wrapper.
4954 _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
4955 var method = ArrayProto[name];
4956 _.prototype[name] = function() {
4957 var obj = this._wrapped;
4958 method.apply(obj, arguments);
4959 if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
4960 return result.call(this, obj);
4961 };
4962 });
4963
4964 // Add all accessor Array functions to the wrapper.
4965 _.each(['concat', 'join', 'slice'], function(name) {
4966 var method = ArrayProto[name];
4967 _.prototype[name] = function() {
4968 return result.call(this, method.apply(this._wrapped, arguments));
4969 };
4970 });
4971
4972 // Extracts the result from a wrapped and chained object.
4973 _.prototype.value = function() {
4974 return this._wrapped;
4975 };
4976
4977 // AMD registration happens at the end for compatibility with AMD loaders
4978 // that may not enforce next-turn semantics on modules. Even though general
4979 // practice for AMD registration is to be anonymous, underscore registers
4980 // as a named module because, like jQuery, it is a base library that is
4981 // popular enough to be bundled in a third party lib, but not be part of
4982 // an AMD load request. Those cases could generate an error when an
4983 // anonymous define() is called outside of a loader request.
4984 if (typeof define === 'function' && define.amd) {
4985 define('underscore', [], function() {
4986 return _;
4987 });
4988 }
4989}.call(this));
4990
4991},{}],17:[function(require,module,exports){
4992// calc.js
4993// measure calculations
4994
4995var _ = require('underscore');
4996var geocrunch = require('geocrunch');
4997
4998var pad = function (num) {
4999 return num < 10 ? '0' + num.toString() : num.toString();
5000};
5001
5002var ddToDms = function (coordinate, posSymbol, negSymbol) {
5003 var dd = Math.abs(coordinate),
5004 d = Math.floor(dd),
5005 m = Math.floor((dd - d) * 60),
5006 s = Math.round((dd - d - (m/60)) * 3600 * 100)/100,
5007 directionSymbol = dd === coordinate ? posSymbol : negSymbol;
5008 return pad(d) + '&deg; ' + pad(m) + '\' ' + pad(s) + '" ' + directionSymbol;
5009};
5010
5011var measure = function (latlngs) {
5012 var last = _.last(latlngs);
5013 var path = geocrunch.path(_.map(latlngs, function (latlng) {
5014 return [latlng.lng, latlng.lat];
5015 }));
5016
5017 var meters = path.distance({
5018 units: 'meters'
5019 });
5020 var sqMeters = path.area({
5021 units: 'sqmeters'
5022 });
5023
5024 return {
5025 lastCoord: {
5026 dd: {
5027 x: last.lng,
5028 y: last.lat
5029 },
5030 dms: {
5031 x: ddToDms(last.lng, 'E', 'W'),
5032 y: ddToDms(last.lat, 'N', 'S')
5033 }
5034 },
5035 length: meters,
5036 area: sqMeters
5037 };
5038};
5039
5040module.exports = {
5041 measure: measure // `measure(latLngArray)` - returns object with calced measurements for passed points
5042};
5043},{"geocrunch":6,"underscore":16}],18:[function(require,module,exports){
5044// dom.js
5045// utility functions for managing DOM elements
5046
5047var selectOne = function (selector, el) {
5048 if (!el) {
5049 el = document;
5050 }
5051 return el.querySelector(selector);
5052};
5053
5054var selectAll = function (selector, el) {
5055 if (!el) {
5056 el = document;
5057 }
5058 return Array.prototype.slice.call(el.querySelectorAll(selector));
5059};
5060
5061var hide = function (el) {
5062 if (el) {
5063 el.setAttribute('style', 'display:none;');
5064 return el;
5065 }
5066};
5067
5068var show = function (el) {
5069 if (el) {
5070 el.removeAttribute('style');
5071 return el;
5072 }
5073};
5074
5075module.exports = {
5076 $: selectOne, // `$('.myclass', baseElement)` - returns selected element or undefined
5077 $$: selectAll, // `$$('.myclass', baseElement)` - returns array of selected elements
5078 hide: hide, // `hide(someElement)` - hide passed dom element
5079 show: show // `show(someElement)` - show passed dom element
5080};
5081},{}],19:[function(require,module,exports){
5082(function (global){
5083// leaflet-measure.js
5084
5085var _ = require('underscore');
5086var L = (typeof window !== "undefined" ? window.L : typeof global !== "undefined" ? global.L : null);
5087var humanize = require('humanize');
5088
5089var units = require('./units');
5090var calc = require('./calc');
5091var dom = require('./dom');
5092var $ = dom.$;
5093
5094var Symbology = require('./mapsymbology');
5095
5096
5097var controlTemplate = _.template("<a class=\"<%= model.className %>-toggle js-toggle\" href=\"#\" title=\"Measure distances and areas\">Measure</a>\n<div class=\"<%= model.className %>-interaction js-interaction\">\n <div class=\"js-startprompt startprompt\">\n <h3>Measure Distances and Areas</h3>\n <ul class=\"tasks\">\n <a href=\"#\" class=\"js-start start\">Create a new measurement</a>\n </ul>\n </div>\n <div class=\"js-measuringprompt\">\n <h3>Measure Distances and Areas</h3>\n <p class=\"js-starthelp\">Start creating a measurement by adding points to the map</h3>\n <div class=\"js-results results\"></div>\n <ul class=\"js-measuretasks tasks\">\n <li><a href=\"#\" class=\"js-cancel cancel\">Cancel</a></li>\n <li><a href=\"#\" class=\"js-finish finish\">Finish Measurement</a></li>\n </ul>\n </div>\n</div>");
5098var resultsTemplate = _.template("<div class=\"group\">\n<p class=\"lastpoint heading\">Last Point</p>\n<p><%= model.lastCoord.dms.y %> <span class=\"coorddivider\">/</span> <%= model.lastCoord.dms.x %></p>\n<p><%= humanize.numberFormat(model.lastCoord.dd.y, 6) %> <span class=\"coorddivider\">/</span> <%= humanize.numberFormat(model.lastCoord.dd.x, 6) %></p>\n</div>\n<% if (model.pointCount > 1) { %>\n<div class=\"group\">\n<p><span class=\"heading\">Path Distance</span> <%= model.lengthDisplay %></p>\n</div>\n<% } %>\n<% if (model.pointCount > 2) { %>\n<div class=\"group\">\n<p><span class=\"heading\">Area</span> <%= model.areaDisplay %></p>\n</div>\n<% } %>");
5099var pointPopupTemplate = _.template("<h3>Point Location</h3>\n<p><%= model.lastCoord.dms.y %> <span class=\"coorddivider\">/</span> <%= model.lastCoord.dms.x %></p>\n<p><%= humanize.numberFormat(model.lastCoord.dd.y, 6) %> <span class=\"coorddivider\">/</span> <%= humanize.numberFormat(model.lastCoord.dd.x, 6) %></p>\n<ul class=\"tasks\">\n <li><a href=\"#\" class=\"js-zoomto zoomto\">Center on this Location</a></li>\n <li><a href=\"#\" class=\"js-deletemarkup deletemarkup\">Delete</a></li>\n</ul>");
5100var linePopupTemplate = _.template("<h3>Linear Measurement</h3>\n<p><%= model.lengthDisplay %></p>\n<ul class=\"tasks\">\n <li><a href=\"#\" class=\"js-zoomto zoomto\">Center on this Line</a></li>\n <li><a href=\"#\" class=\"js-deletemarkup deletemarkup\">Delete</a></li>\n</ul>");
5101var areaPopupTemplate = _.template("<h3>Area Measurement</h3>\n<p><%= model.areaDisplay %></p>\n<p><%= model.lengthDisplay %> Perimeter</p>\n<ul class=\"tasks\">\n <li><a href=\"#\" class=\"js-zoomto zoomto\">Center on this Area</a></li>\n <li><a href=\"#\" class=\"js-deletemarkup deletemarkup\">Delete</a></li>\n</ul>");
5102
5103L.Control.Measure = L.Control.extend({
5104 _className: 'leaflet-control-measure',
5105 options: {
5106 units: {},
5107 position: 'topright',
5108 primaryLengthUnit: 'feet',
5109 secondaryLengthUnit: 'miles',
5110 primaryAreaUnit: 'acres',
5111 activeColor: '#ABE67E', // base color for map features while actively measuring
5112 completedColor: '#C8F2BE', // base color for permenant features generated from completed measure
5113 popupOptions: { // standard leaflet popup options http://leafletjs.com/reference.html#popup-options
5114 className: 'leaflet-measure-resultpopup',
5115 autoPanPadding: [10, 10]
5116 }
5117 },
5118 initialize: function (options) {
5119 L.setOptions(this, options);
5120 this.options.units = L.extend({}, units, this.options.units);
5121 this._symbols = new Symbology(_.pick(this.options, 'activeColor', 'completedColor'));
5122 },
5123 onAdd: function (map) {
5124 this._map = map;
5125 this._latlngs = [];
5126 this._initLayout();
5127 map.on('click', this._collapse, this);
5128 this._layer = L.layerGroup().addTo(map);
5129 return this._container;
5130 },
5131 onRemove: function (map) {
5132 map.off('click', this._collapse, this);
5133 map.removeLayer(this._layer);
5134 },
5135 _initLayout: function () {
5136 var className = this._className, container = this._container = L.DomUtil.create('div', className);
5137 var $toggle, $start, $cancel, $finish;
5138
5139 container.innerHTML = controlTemplate({
5140 model: {
5141 className: className
5142 }
5143 });
5144
5145 // copied from leaflet
5146 // https://bitbucket.org/ljagis/js-mapbootstrap/src/4ab1e9e896c08bdbc8164d4053b2f945143f4f3a/app/components/measure/leaflet-measure-control.js?at=master#cl-30
5147 container.setAttribute('aria-haspopup', true);
5148 if (!L.Browser.touch) {
5149 L.DomEvent.disableClickPropagation(container);
5150 L.DomEvent.disableScrollPropagation(container);
5151 } else {
5152 L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
5153 }
5154
5155 $toggle = this.$toggle = $('.js-toggle', container); // collapsed content
5156 this.$interaction = $('.js-interaction', container); // expanded content
5157 $start = $('.js-start', container); // start button
5158 $cancel = $('.js-cancel', container); // cancel button
5159 $finish = $('.js-finish', container); // finish button
5160 this.$startPrompt = $('.js-startprompt', container); // full area with button to start measurment
5161 this.$measuringPrompt = $('.js-measuringprompt', container); // full area with all stuff for active measurement
5162 this.$startHelp = $('.js-starthelp', container); // "Start creating a measurement by adding points"
5163 this.$results = $('.js-results', container); // div with coordinate, linear, area results
5164 this.$measureTasks = $('.js-measuretasks', container); // active measure buttons container
5165
5166 this._collapse();
5167 this._updateMeasureNotStarted();
5168
5169 if (!L.Browser.android) {
5170 L.DomEvent.on(container, 'mouseenter', this._expand, this);
5171 L.DomEvent.on(container, 'mouseleave', this._collapse, this);
5172 }
5173 L.DomEvent.on($toggle, 'click', L.DomEvent.stop);
5174 if (L.Browser.touch) {
5175 L.DomEvent.on($toggle, 'click', this._expand, this);
5176 } else {
5177 L.DomEvent.on($toggle, 'focus', this._expand, this);
5178 }
5179 L.DomEvent.on($start, 'click', L.DomEvent.stop);
5180 L.DomEvent.on($start, 'click', this._startMeasure, this);
5181 L.DomEvent.on($cancel, 'click', L.DomEvent.stop);
5182 L.DomEvent.on($cancel, 'click', this._finishMeasure, this);
5183 L.DomEvent.on($finish, 'click', L.DomEvent.stop);
5184 L.DomEvent.on($finish, 'click', this._handleMeasureDoubleClick, this);
5185 },
5186 _expand: function () {
5187 dom.hide(this.$toggle);
5188 dom.show(this.$interaction);
5189 },
5190 _collapse: function () {
5191 if (!this._locked) {
5192 dom.hide(this.$interaction);
5193 dom.show(this.$toggle);
5194 }
5195 },
5196 // move between basic states:
5197 // measure not started, started/in progress but no points added, in progress and with points
5198 _updateMeasureNotStarted: function () {
5199 dom.hide(this.$startHelp);
5200 dom.hide(this.$results);
5201 dom.hide(this.$measureTasks);
5202 dom.hide(this.$measuringPrompt);
5203 dom.show(this.$startPrompt);
5204 },
5205 _updateMeasureStartedNoPoints: function () {
5206 dom.hide(this.$results);
5207 dom.show(this.$startHelp);
5208 dom.show(this.$measureTasks);
5209 dom.hide(this.$startPrompt);
5210 dom.show(this.$measuringPrompt);
5211 },
5212 _updateMeasureStartedWithPoints: function () {
5213 dom.hide(this.$startHelp);
5214 dom.show(this.$results);
5215 dom.show(this.$measureTasks);
5216 dom.hide(this.$startPrompt);
5217 dom.show(this.$measuringPrompt);
5218 },
5219 // get state vars and interface ready for measure
5220 _startMeasure: function () {
5221 this._locked = true;
5222
5223 this._map.doubleClickZoom.disable(); // double click now finishes measure
5224 this._map.on('mouseout', this._handleMapMouseOut, this);
5225
5226 L.DomEvent.on(this._container, 'mouseenter', this._handleMapMouseOut, this);
5227
5228 this._map.on('mousemove', this._handleMeasureMove, this);
5229 this._map.on('dblclick', this._handleMeasureDoubleClick, this);
5230 this._map.on('click', this._handleMeasureClick, this);
5231
5232 this._measureVertexes = L.featureGroup().addTo(this._layer);
5233
5234 this._updateMeasureStartedNoPoints();
5235 },
5236 // return to state with no measure in progress, undo `this._startMeasure`
5237 _finishMeasure: function () {
5238 this._locked = false;
5239
5240 this._map.doubleClickZoom.enable();
5241 this._map.off('mouseout', this._handleMapMouseOut, this);
5242
5243 L.DomEvent.off(this._container, 'mouseover', this._handleMapMouseOut, this);
5244
5245 this._clearMeasure();
5246
5247 this._map.off('mousemove', this._handleMeasureMove, this);
5248 this._map.off('dblclick', this._handleMeasureDoubleClick, this);
5249 this._map.off('click', this._handleMeasureClick, this);
5250
5251 this._layer.removeLayer(this._measureVertexes);
5252 this._measureVertexes = null;
5253
5254 this._updateMeasureNotStarted();
5255 this._collapse();
5256 },
5257 // clear all running measure data
5258 _clearMeasure: function () {
5259 this._latlngs = [];
5260 this._measureVertexes.clearLayers();
5261 if (this._measureDrag) {
5262 this._layer.removeLayer(this._measureDrag);
5263 }
5264 if (this._measureArea) {
5265 this._layer.removeLayer(this._measureArea);
5266 }
5267 if (this._measureBoundary) {
5268 this._layer.removeLayer(this._measureBoundary);
5269 }
5270 this._measureDrag = null;
5271 this._measureArea = null;
5272 this._measureBoundary = null;
5273 },
5274 // format measurements to nice display string based on units in options. `{ lengthDisplay: '100 Feet (0.02 Miles)', areaDisplay: ... }`
5275 _getMeasurementDisplayStrings: function (measurement) {
5276 var unitDefinitions = this.options.units;
5277
5278 return {
5279 lengthDisplay: buildDisplay(measurement.length, this.options.primaryLengthUnit, this.options.secondaryLengthUnit),
5280 areaDisplay: buildDisplay(measurement.area, this.options.primaryAreaUnit, this.options.secondaryAreaUnit)
5281 };
5282
5283 function buildDisplay (val, primaryUnit, secondaryUnit) {
5284 var display;
5285 if (primaryUnit && unitDefinitions[primaryUnit]) {
5286 display = formatMeasure(val, unitDefinitions[primaryUnit]);
5287 if (secondaryUnit && unitDefinitions[secondaryUnit]) {
5288 display = display + ' (' + formatMeasure(val, unitDefinitions[secondaryUnit]) + ')';
5289 }
5290 } else {
5291 display = formatMeasure(val);
5292 }
5293 return display;
5294 }
5295
5296 function formatMeasure (val, unit) {
5297 return unit && unit.factor && unit.display ?
5298 humanize.numberFormat(val * unit.factor, unit.decimals || 0) + ' ' + unit.display :
5299 humanize.numberFormat(val, 0);
5300 }
5301 },
5302 // update results area of dom with calced measure from `this._latlngs`
5303 _updateResults: function () {
5304 var calced = calc.measure(this._latlngs);
5305 this.$results.innerHTML = resultsTemplate({
5306 model: _.extend({}, calced, this._getMeasurementDisplayStrings(calced), {
5307 pointCount: this._latlngs.length
5308 }),
5309 humanize: humanize
5310 });
5311 },
5312 // mouse move handler while measure in progress
5313 // adds floating measure marker under cursor
5314 _handleMeasureMove: function (evt) {
5315 if (!this._measureDrag) {
5316 this._measureDrag = L.circleMarker(evt.latlng, this._symbols.getSymbol('measureDrag')).addTo(this._layer);
5317 } else {
5318 this._measureDrag.setLatLng(evt.latlng);
5319 }
5320 this._measureDrag.bringToFront();
5321 },
5322 // handler for both double click and clicking finish button
5323 // do final calc and finish out current measure, clear dom and internal state, add permanent map features
5324 _handleMeasureDoubleClick: function () {
5325 var latlngs = this._latlngs, calced, resultFeature, popupContainer, popupContent, zoomLink, deleteLink;
5326
5327 this._finishMeasure();
5328
5329 if (!latlngs.length) {
5330 return;
5331 }
5332
5333 if (latlngs.length > 2) {
5334 latlngs.push(_.first(latlngs)); // close path to get full perimeter measurement for areas
5335 }
5336
5337 calced = calc.measure(latlngs);
5338
5339 if (latlngs.length === 1) {
5340 resultFeature = L.circleMarker(latlngs[0], this._symbols.getSymbol('resultPoint'));
5341 popupContent = pointPopupTemplate({
5342 model: calced,
5343 humanize: humanize
5344 });
5345 } else if (latlngs.length === 2) {
5346 resultFeature = L.polyline(latlngs, this._symbols.getSymbol('resultLine')).addTo(this._map);
5347 popupContent = linePopupTemplate({
5348 model: _.extend({}, calced, this._getMeasurementDisplayStrings(calced)),
5349 humanize: humanize
5350 });
5351 } else {
5352 resultFeature = L.polygon(latlngs, this._symbols.getSymbol('resultArea'));
5353 popupContent = areaPopupTemplate({
5354 model: _.extend({}, calced, this._getMeasurementDisplayStrings(calced)),
5355 humanize: humanize,
5356 units: this._units
5357 });
5358 }
5359
5360 popupContainer = L.DomUtil.create('div', '');
5361 popupContainer.innerHTML = popupContent;
5362
5363 zoomLink = $('.js-zoomto', popupContainer);
5364 if (zoomLink) {
5365 L.DomEvent.on(zoomLink, 'click', L.DomEvent.stop);
5366 L.DomEvent.on(zoomLink, 'click', function () {
5367 this._map.fitBounds(resultFeature.getBounds(), {
5368 padding: [20, 20],
5369 maxZoom: 17
5370 });
5371 }, this);
5372 }
5373
5374 deleteLink = $('.js-deletemarkup', popupContainer);
5375 if (deleteLink) {
5376 L.DomEvent.on(deleteLink, 'click', L.DomEvent.stop);
5377 L.DomEvent.on(deleteLink, 'click', function () {
5378 // TODO. maybe remove any event handlers on zoom and delete buttons?
5379 this._map.removeLayer(resultFeature);
5380 }, this);
5381 }
5382
5383 resultFeature.addTo(this._map);
5384 resultFeature.bindPopup(popupContainer, this.options.popupOptions);
5385 resultFeature.openPopup(resultFeature.getBounds().getCenter());
5386 },
5387 // handle map click during ongoing measurement
5388 // add new clicked point, update measure layers and results ui
5389 _handleMeasureClick: function (evt) {
5390 var latlng = evt.latlng, lastClick = _.last(this._latlngs), vertexSymbol = this._symbols.getSymbol('measureVertex');
5391
5392 if (!lastClick || !latlng.equals(lastClick)) { // skip if same point as last click, happens on `dblclick`
5393 this._latlngs.push(latlng);
5394 this._addMeasureArea(this._latlngs);
5395 this._addMeasureBoundary(this._latlngs);
5396
5397 this._measureVertexes.eachLayer(function (layer) {
5398 layer.setStyle(vertexSymbol);
5399 // reset all vertexes to non-active class - only last vertex is active
5400 // `layer.setStyle({ className: 'layer-measurevertex'})` doesn't work. https://github.com/leaflet/leaflet/issues/2662
5401 // set attribute on path directly
5402 layer._path.setAttribute('class', vertexSymbol.className);
5403 });
5404
5405 this._addNewVertex(latlng);
5406
5407 if (this._measureBoundary) {
5408 this._measureBoundary.bringToFront();
5409 }
5410 this._measureVertexes.bringToFront();
5411 }
5412
5413 this._updateResults();
5414 this._updateMeasureStartedWithPoints();
5415 },
5416 // handle map mouse out during ongoing measure
5417 // remove floating cursor vertex from map
5418 _handleMapMouseOut: function () {
5419 if (this._measureDrag) {
5420 this._layer.removeLayer(this._measureDrag);
5421 this._measureDrag = null;
5422 }
5423 },
5424 // add various measure graphics to map - vertex, area, boundary
5425 _addNewVertex: function (latlng) {
5426 L.circleMarker(latlng, this._symbols.getSymbol('measureVertexActive')).addTo(this._measureVertexes);
5427 },
5428 _addMeasureArea: function (latlngs) {
5429 if (latlngs.length < 3) {
5430 if (this._measureArea) {
5431 this._layer.removeLayer(this._measureArea);
5432 this._measureArea = null;
5433 }
5434 return;
5435 }
5436 if (!this._measureArea) {
5437 this._measureArea = L.polygon(latlngs, this._symbols.getSymbol('measureArea')).addTo(this._layer);
5438 } else {
5439 this._measureArea.setLatLngs(latlngs);
5440 }
5441 },
5442 _addMeasureBoundary: function (latlngs) {
5443 if (latlngs.length < 2) {
5444 if (this._measureBoundary) {
5445 this._layer.removeLayer(this._measureBoundary);
5446 this._measureBoundary = null;
5447 }
5448 return;
5449 }
5450 if (!this._measureBoundary) {
5451 this._measureBoundary = L.polyline(latlngs, this._symbols.getSymbol('measureBoundary')).addTo(this._layer);
5452 } else {
5453 this._measureBoundary.setLatLngs(latlngs);
5454 }
5455 }
5456});
5457
5458L.Map.mergeOptions({
5459 measureControl: false
5460});
5461
5462L.Map.addInitHook(function () {
5463 if (this.options.measureControl) {
5464 this.measureControl = (new L.Control.Measure()).addTo(this);
5465 }
5466});
5467
5468L.control.measure = function (options) {
5469 return new L.Control.Measure(options);
5470};
5471
5472}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
5473},{"./calc":17,"./dom":18,"./mapsymbology":20,"./units":21,"humanize":15,"underscore":16}],20:[function(require,module,exports){
5474// mapsymbology.js
5475
5476var _ = require('underscore');
5477
5478var color = require('color');
5479
5480var Symbology = function (options) {
5481 this.setOptions(options);
5482};
5483
5484Symbology.DEFAULTS = {
5485 activeColor: '#ABE67E', // base color for map features while actively measuring
5486 completedColor: '#C8F2BE' // base color for permenant features generated from completed measure
5487};
5488
5489_.extend(Symbology.prototype, {
5490 setOptions: function (options) {
5491 this._options = _.extend({}, Symbology.DEFAULTS, this._options, options);
5492 return this;
5493 },
5494 getSymbol: function (name) {
5495 var symbols = {
5496 measureDrag: {
5497 clickable: false,
5498 radius: 4,
5499 color: this._options.activeColor,
5500 weight: 2,
5501 opacity: 0.7,
5502 fillColor: this._options.activeColor,
5503 fillOpacity: 0.5,
5504 className: 'layer-measuredrag'
5505 },
5506 measureArea: {
5507 clickable: false,
5508 stroke: false,
5509 fillColor: this._options.activeColor,
5510 fillOpacity: 0.2,
5511 className: 'layer-measurearea'
5512 },
5513 measureBoundary: {
5514 clickable: false,
5515 color: this._options.activeColor,
5516 weight: 2,
5517 opacity: 0.9,
5518 fill: false,
5519 className: 'layer-measureboundary'
5520 },
5521 measureVertex: {
5522 clickable: false,
5523 radius: 4,
5524 color: this._options.activeColor,
5525 weight: 2,
5526 opacity: 1,
5527 fillColor: this._options.activeColor,
5528 fillOpacity: 0.7,
5529 className: 'layer-measurevertex'
5530 },
5531 measureVertexActive: {
5532 clickable: false,
5533 radius: 4,
5534 color: this._options.activeColor,
5535 weight: 2,
5536 opacity: 1,
5537 fillColor: color(this._options.activeColor).darken(0.15),
5538 fillOpacity: 0.7,
5539 className: 'layer-measurevertex active'
5540 },
5541 resultArea: {
5542 clickable: true,
5543 color: this._options.completedColor,
5544 weight: 2,
5545 opacity: 0.9,
5546 fillColor: this._options.completedColor,
5547 fillOpacity: 0.2,
5548 className: 'layer-measure-resultarea'
5549 },
5550 resultLine: {
5551 clickable: true,
5552 color: this._options.completedColor,
5553 weight: 3,
5554 opacity: 0.9,
5555 fill: false,
5556 className: 'layer-measure-resultline'
5557 },
5558 resultPoint: {
5559 clickable: true,
5560 radius: 4,
5561 color: this._options.completedColor,
5562 weight: 2,
5563 opacity: 1,
5564 fillColor: this._options.completedColor,
5565 fillOpacity: 0.7,
5566 className: 'layer-measure-resultpoint'
5567 }
5568 };
5569 return symbols[name];
5570 }
5571});
5572
5573module.exports = Symbology;
5574},{"color":1,"underscore":16}],21:[function(require,module,exports){
5575// units.js
5576// Unit configurations
5577// Factor is with respect to meters/sqmeters
5578
5579module.exports = {
5580 acres: {
5581 factor: 0.00024711,
5582 display: 'Acres',
5583 decimals: 2
5584 },
5585 feet: {
5586 factor: 3.2808,
5587 display: 'Feet',
5588 decimals: 0
5589 },
5590 kilometers: {
5591 factor: 0.001,
5592 display: 'Kilometers',
5593 decimals: 2
5594 },
5595 hectares: {
5596 factor: 0.0001,
5597 display: 'Hectares',
5598 decimals: 2
5599 },
5600 meters: {
5601 factor: 1,
5602 display: 'Meters',
5603 decimals: 0
5604 },
5605 miles: {
5606 factor: 3.2808 / 5280,
5607 display: 'Miles',
5608 decimals: 2
5609 },
5610 sqfeet: {
5611 factor: 10.7639,
5612 display: 'Sq Feet',
5613 decimals: 0
5614 },
5615 sqmeters: {
5616 factor: 1,
5617 display: 'Sq Meters',
5618 decimals: 0
5619 },
5620 sqmiles: {
5621 factor: 0.000000386102,
5622 display: 'Sq Miles',
5623 decimals: 2
5624 }
5625};
5626},{}]},{},[19]);
Note: See TracBrowser for help on using the repository browser.