analytics-js-rails 0.11.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in analytics-js-rails.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Phill Baker
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,51 @@
1
+ # Analytics.js-Rails
2
+
3
+ A self-hosted copy of [Analytics.js](https://github.com/segmentio/analytics.js), a wrapper for web analytics services, for the Ruby on Rails 3.1+ asset pipeline.
4
+
5
+ Service A is good at X and Service B is good at Y, unfortunate but true. Use one common interface to standardize and modularize analytics setup across services.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'analytics-js-rails'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install analytics-js-rails
20
+
21
+ ## Usage
22
+
23
+ Add this line to your application.html.erb, for example:
24
+
25
+ <%= render 'analytics-js/loader', providers: {
26
+ 'Google Analytics' => 'google_analytics_key',
27
+ 'KISSmetrics' => 'kissmetrics_key'
28
+ } %>
29
+
30
+ Of course, keys should probably be stored in config files, not hard coded.
31
+
32
+ Add to your ```config/environments/production.rb```:
33
+
34
+ config.assets.precompile += %w( analytics.js )
35
+
36
+
37
+ You can now use rickshaw in your app.
38
+
39
+ ## Version
40
+
41
+ The version of this gem reflects the Analytics.js version.
42
+
43
+ ## Contributing
44
+
45
+ Yes, please. Pull requests are very welcome. If it's not tested, we will not pull it.
46
+
47
+ 1. Fork it
48
+ 2. Bonus points for feature branches (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'analytics-js/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "analytics-js-rails"
8
+ spec.version = AnalyticsJs::VERSION
9
+ spec.authors = ["Phill Baker"]
10
+ spec.email = ["phill@generalassemb.ly"]
11
+ spec.description = %q{A self-hosted copy of Analytics.js, a wrapper for web analytics services, for the Ruby on Rails 3.1+ asset pipeline.}
12
+ spec.summary = %q{Rails + your app + analytics.js = analytics in all the right places}
13
+ spec.homepage = "https://github.com/phillbaker/analytics-js-rails"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "railties", ">= 3.1.0"
22
+ spec.add_development_dependency "bundler", ">= 1.0.0"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "rspec"
25
+ end
@@ -0,0 +1,3787 @@
1
+ ;(function(){
2
+
3
+ /**
4
+ * Require the given path.
5
+ *
6
+ * @param {String} path
7
+ * @return {Object} exports
8
+ * @api public
9
+ */
10
+
11
+ function require(path, parent, orig) {
12
+ var resolved = require.resolve(path);
13
+
14
+ // lookup failed
15
+ if (null == resolved) {
16
+ orig = orig || path;
17
+ parent = parent || 'root';
18
+ var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
19
+ err.path = orig;
20
+ err.parent = parent;
21
+ err.require = true;
22
+ throw err;
23
+ }
24
+
25
+ var module = require.modules[resolved];
26
+
27
+ // perform real require()
28
+ // by invoking the module's
29
+ // registered function
30
+ if (!module.exports) {
31
+ module.exports = {};
32
+ module.client = module.component = true;
33
+ module.call(this, module.exports, require.relative(resolved), module);
34
+ }
35
+
36
+ return module.exports;
37
+ }
38
+
39
+ /**
40
+ * Registered modules.
41
+ */
42
+
43
+ require.modules = {};
44
+
45
+ /**
46
+ * Registered aliases.
47
+ */
48
+
49
+ require.aliases = {};
50
+
51
+ /**
52
+ * Resolve `path`.
53
+ *
54
+ * Lookup:
55
+ *
56
+ * - PATH/index.js
57
+ * - PATH.js
58
+ * - PATH
59
+ *
60
+ * @param {String} path
61
+ * @return {String} path or null
62
+ * @api private
63
+ */
64
+
65
+ require.resolve = function(path) {
66
+ if (path.charAt(0) === '/') path = path.slice(1);
67
+
68
+ var paths = [
69
+ path,
70
+ path + '.js',
71
+ path + '.json',
72
+ path + '/index.js',
73
+ path + '/index.json'
74
+ ];
75
+
76
+ for (var i = 0; i < paths.length; i++) {
77
+ var path = paths[i];
78
+ if (require.modules.hasOwnProperty(path)) return path;
79
+ if (require.aliases.hasOwnProperty(path)) return require.aliases[path];
80
+ }
81
+ };
82
+
83
+ /**
84
+ * Normalize `path` relative to the current path.
85
+ *
86
+ * @param {String} curr
87
+ * @param {String} path
88
+ * @return {String}
89
+ * @api private
90
+ */
91
+
92
+ require.normalize = function(curr, path) {
93
+ var segs = [];
94
+
95
+ if ('.' != path.charAt(0)) return path;
96
+
97
+ curr = curr.split('/');
98
+ path = path.split('/');
99
+
100
+ for (var i = 0; i < path.length; ++i) {
101
+ if ('..' == path[i]) {
102
+ curr.pop();
103
+ } else if ('.' != path[i] && '' != path[i]) {
104
+ segs.push(path[i]);
105
+ }
106
+ }
107
+
108
+ return curr.concat(segs).join('/');
109
+ };
110
+
111
+ /**
112
+ * Register module at `path` with callback `definition`.
113
+ *
114
+ * @param {String} path
115
+ * @param {Function} definition
116
+ * @api private
117
+ */
118
+
119
+ require.register = function(path, definition) {
120
+ require.modules[path] = definition;
121
+ };
122
+
123
+ /**
124
+ * Alias a module definition.
125
+ *
126
+ * @param {String} from
127
+ * @param {String} to
128
+ * @api private
129
+ */
130
+
131
+ require.alias = function(from, to) {
132
+ if (!require.modules.hasOwnProperty(from)) {
133
+ throw new Error('Failed to alias "' + from + '", it does not exist');
134
+ }
135
+ require.aliases[to] = from;
136
+ };
137
+
138
+ /**
139
+ * Return a require function relative to the `parent` path.
140
+ *
141
+ * @param {String} parent
142
+ * @return {Function}
143
+ * @api private
144
+ */
145
+
146
+ require.relative = function(parent) {
147
+ var p = require.normalize(parent, '..');
148
+
149
+ /**
150
+ * lastIndexOf helper.
151
+ */
152
+
153
+ function lastIndexOf(arr, obj) {
154
+ var i = arr.length;
155
+ while (i--) {
156
+ if (arr[i] === obj) return i;
157
+ }
158
+ return -1;
159
+ }
160
+
161
+ /**
162
+ * The relative require() itself.
163
+ */
164
+
165
+ function localRequire(path) {
166
+ var resolved = localRequire.resolve(path);
167
+ return require(resolved, parent, path);
168
+ }
169
+
170
+ /**
171
+ * Resolve relative to the parent.
172
+ */
173
+
174
+ localRequire.resolve = function(path) {
175
+ var c = path.charAt(0);
176
+ if ('/' == c) return path.slice(1);
177
+ if ('.' == c) return require.normalize(p, path);
178
+
179
+ // resolve deps by returning
180
+ // the dep in the nearest "deps"
181
+ // directory
182
+ var segs = parent.split('/');
183
+ var i = lastIndexOf(segs, 'deps') + 1;
184
+ if (!i) i = 0;
185
+ path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
186
+ return path;
187
+ };
188
+
189
+ /**
190
+ * Check if module is defined at `path`.
191
+ */
192
+
193
+ localRequire.exists = function(path) {
194
+ return require.modules.hasOwnProperty(localRequire.resolve(path));
195
+ };
196
+
197
+ return localRequire;
198
+ };
199
+ require.register("avetisk-defaults/index.js", function(exports, require, module){
200
+ 'use strict';
201
+
202
+ /**
203
+ * Merge default values.
204
+ *
205
+ * @param {Object} dest
206
+ * @param {Object} defaults
207
+ * @return {Object}
208
+ * @api public
209
+ */
210
+ var defaults = function (dest, src, recursive) {
211
+ for (var prop in src) {
212
+ if (recursive && dest[prop] instanceof Object && src[prop] instanceof Object) {
213
+ dest[prop] = defaults(dest[prop], src[prop], true);
214
+ } else if (! (prop in dest)) {
215
+ dest[prop] = src[prop];
216
+ }
217
+ }
218
+
219
+ return dest;
220
+ };
221
+
222
+ /**
223
+ * Expose `defaults`.
224
+ */
225
+ module.exports = defaults;
226
+
227
+ });
228
+ require.register("component-clone/index.js", function(exports, require, module){
229
+
230
+ /**
231
+ * Module dependencies.
232
+ */
233
+
234
+ var type;
235
+
236
+ try {
237
+ type = require('type');
238
+ } catch(e){
239
+ type = require('type-component');
240
+ }
241
+
242
+ /**
243
+ * Module exports.
244
+ */
245
+
246
+ module.exports = clone;
247
+
248
+ /**
249
+ * Clones objects.
250
+ *
251
+ * @param {Mixed} any object
252
+ * @api public
253
+ */
254
+
255
+ function clone(obj){
256
+ switch (type(obj)) {
257
+ case 'object':
258
+ var copy = {};
259
+ for (var key in obj) {
260
+ if (obj.hasOwnProperty(key)) {
261
+ copy[key] = clone(obj[key]);
262
+ }
263
+ }
264
+ return copy;
265
+
266
+ case 'array':
267
+ var copy = new Array(obj.length);
268
+ for (var i = 0, l = obj.length; i < l; i++) {
269
+ copy[i] = clone(obj[i]);
270
+ }
271
+ return copy;
272
+
273
+ case 'regexp':
274
+ // from millermedeiros/amd-utils - MIT
275
+ var flags = '';
276
+ flags += obj.multiline ? 'm' : '';
277
+ flags += obj.global ? 'g' : '';
278
+ flags += obj.ignoreCase ? 'i' : '';
279
+ return new RegExp(obj.source, flags);
280
+
281
+ case 'date':
282
+ return new Date(obj.getTime());
283
+
284
+ default: // string, number, boolean, …
285
+ return obj;
286
+ }
287
+ }
288
+
289
+ });
290
+ require.register("component-cookie/index.js", function(exports, require, module){
291
+ /**
292
+ * Encode.
293
+ */
294
+
295
+ var encode = encodeURIComponent;
296
+
297
+ /**
298
+ * Decode.
299
+ */
300
+
301
+ var decode = decodeURIComponent;
302
+
303
+ /**
304
+ * Set or get cookie `name` with `value` and `options` object.
305
+ *
306
+ * @param {String} name
307
+ * @param {String} value
308
+ * @param {Object} options
309
+ * @return {Mixed}
310
+ * @api public
311
+ */
312
+
313
+ module.exports = function(name, value, options){
314
+ switch (arguments.length) {
315
+ case 3:
316
+ case 2:
317
+ return set(name, value, options);
318
+ case 1:
319
+ return get(name);
320
+ default:
321
+ return all();
322
+ }
323
+ };
324
+
325
+ /**
326
+ * Set cookie `name` to `value`.
327
+ *
328
+ * @param {String} name
329
+ * @param {String} value
330
+ * @param {Object} options
331
+ * @api private
332
+ */
333
+
334
+ function set(name, value, options) {
335
+ options = options || {};
336
+ var str = encode(name) + '=' + encode(value);
337
+
338
+ if (null == value) options.maxage = -1;
339
+
340
+ if (options.maxage) {
341
+ options.expires = new Date(+new Date + options.maxage);
342
+ }
343
+
344
+ if (options.path) str += '; path=' + options.path;
345
+ if (options.domain) str += '; domain=' + options.domain;
346
+ if (options.expires) str += '; expires=' + options.expires.toUTCString();
347
+ if (options.secure) str += '; secure';
348
+
349
+ document.cookie = str;
350
+ }
351
+
352
+ /**
353
+ * Return all cookies.
354
+ *
355
+ * @return {Object}
356
+ * @api private
357
+ */
358
+
359
+ function all() {
360
+ return parse(document.cookie);
361
+ }
362
+
363
+ /**
364
+ * Get cookie `name`.
365
+ *
366
+ * @param {String} name
367
+ * @return {String}
368
+ * @api private
369
+ */
370
+
371
+ function get(name) {
372
+ return all()[name];
373
+ }
374
+
375
+ /**
376
+ * Parse cookie `str`.
377
+ *
378
+ * @param {String} str
379
+ * @return {Object}
380
+ * @api private
381
+ */
382
+
383
+ function parse(str) {
384
+ var obj = {};
385
+ var pairs = str.split(/ *; */);
386
+ var pair;
387
+ if ('' == pairs[0]) return obj;
388
+ for (var i = 0; i < pairs.length; ++i) {
389
+ pair = pairs[i].split('=');
390
+ obj[decode(pair[0])] = decode(pair[1]);
391
+ }
392
+ return obj;
393
+ }
394
+
395
+ });
396
+ require.register("component-each/index.js", function(exports, require, module){
397
+
398
+ /**
399
+ * Module dependencies.
400
+ */
401
+
402
+ var type = require('type');
403
+
404
+ /**
405
+ * HOP reference.
406
+ */
407
+
408
+ var has = Object.prototype.hasOwnProperty;
409
+
410
+ /**
411
+ * Iterate the given `obj` and invoke `fn(val, i)`.
412
+ *
413
+ * @param {String|Array|Object} obj
414
+ * @param {Function} fn
415
+ * @api public
416
+ */
417
+
418
+ module.exports = function(obj, fn){
419
+ switch (type(obj)) {
420
+ case 'array':
421
+ return array(obj, fn);
422
+ case 'object':
423
+ if ('number' == typeof obj.length) return array(obj, fn);
424
+ return object(obj, fn);
425
+ case 'string':
426
+ return string(obj, fn);
427
+ }
428
+ };
429
+
430
+ /**
431
+ * Iterate string chars.
432
+ *
433
+ * @param {String} obj
434
+ * @param {Function} fn
435
+ * @api private
436
+ */
437
+
438
+ function string(obj, fn) {
439
+ for (var i = 0; i < obj.length; ++i) {
440
+ fn(obj.charAt(i), i);
441
+ }
442
+ }
443
+
444
+ /**
445
+ * Iterate object keys.
446
+ *
447
+ * @param {Object} obj
448
+ * @param {Function} fn
449
+ * @api private
450
+ */
451
+
452
+ function object(obj, fn) {
453
+ for (var key in obj) {
454
+ if (has.call(obj, key)) {
455
+ fn(key, obj[key]);
456
+ }
457
+ }
458
+ }
459
+
460
+ /**
461
+ * Iterate array-ish.
462
+ *
463
+ * @param {Array|Object} obj
464
+ * @param {Function} fn
465
+ * @api private
466
+ */
467
+
468
+ function array(obj, fn) {
469
+ for (var i = 0; i < obj.length; ++i) {
470
+ fn(obj[i], i);
471
+ }
472
+ }
473
+ });
474
+ require.register("component-event/index.js", function(exports, require, module){
475
+
476
+ /**
477
+ * Bind `el` event `type` to `fn`.
478
+ *
479
+ * @param {Element} el
480
+ * @param {String} type
481
+ * @param {Function} fn
482
+ * @param {Boolean} capture
483
+ * @return {Function}
484
+ * @api public
485
+ */
486
+
487
+ exports.bind = function(el, type, fn, capture){
488
+ if (el.addEventListener) {
489
+ el.addEventListener(type, fn, capture || false);
490
+ } else {
491
+ el.attachEvent('on' + type, fn);
492
+ }
493
+ return fn;
494
+ };
495
+
496
+ /**
497
+ * Unbind `el` event `type`'s callback `fn`.
498
+ *
499
+ * @param {Element} el
500
+ * @param {String} type
501
+ * @param {Function} fn
502
+ * @param {Boolean} capture
503
+ * @return {Function}
504
+ * @api public
505
+ */
506
+
507
+ exports.unbind = function(el, type, fn, capture){
508
+ if (el.removeEventListener) {
509
+ el.removeEventListener(type, fn, capture || false);
510
+ } else {
511
+ el.detachEvent('on' + type, fn);
512
+ }
513
+ return fn;
514
+ };
515
+
516
+ });
517
+ require.register("component-inherit/index.js", function(exports, require, module){
518
+
519
+ module.exports = function(a, b){
520
+ var fn = function(){};
521
+ fn.prototype = b.prototype;
522
+ a.prototype = new fn;
523
+ a.prototype.constructor = a;
524
+ };
525
+ });
526
+ require.register("component-object/index.js", function(exports, require, module){
527
+
528
+ /**
529
+ * HOP ref.
530
+ */
531
+
532
+ var has = Object.prototype.hasOwnProperty;
533
+
534
+ /**
535
+ * Return own keys in `obj`.
536
+ *
537
+ * @param {Object} obj
538
+ * @return {Array}
539
+ * @api public
540
+ */
541
+
542
+ exports.keys = Object.keys || function(obj){
543
+ var keys = [];
544
+ for (var key in obj) {
545
+ if (has.call(obj, key)) {
546
+ keys.push(key);
547
+ }
548
+ }
549
+ return keys;
550
+ };
551
+
552
+ /**
553
+ * Return own values in `obj`.
554
+ *
555
+ * @param {Object} obj
556
+ * @return {Array}
557
+ * @api public
558
+ */
559
+
560
+ exports.values = function(obj){
561
+ var vals = [];
562
+ for (var key in obj) {
563
+ if (has.call(obj, key)) {
564
+ vals.push(obj[key]);
565
+ }
566
+ }
567
+ return vals;
568
+ };
569
+
570
+ /**
571
+ * Merge `b` into `a`.
572
+ *
573
+ * @param {Object} a
574
+ * @param {Object} b
575
+ * @return {Object} a
576
+ * @api public
577
+ */
578
+
579
+ exports.merge = function(a, b){
580
+ for (var key in b) {
581
+ if (has.call(b, key)) {
582
+ a[key] = b[key];
583
+ }
584
+ }
585
+ return a;
586
+ };
587
+
588
+ /**
589
+ * Return length of `obj`.
590
+ *
591
+ * @param {Object} obj
592
+ * @return {Number}
593
+ * @api public
594
+ */
595
+
596
+ exports.length = function(obj){
597
+ return exports.keys(obj).length;
598
+ };
599
+
600
+ /**
601
+ * Check if `obj` is empty.
602
+ *
603
+ * @param {Object} obj
604
+ * @return {Boolean}
605
+ * @api public
606
+ */
607
+
608
+ exports.isEmpty = function(obj){
609
+ return 0 == exports.length(obj);
610
+ };
611
+ });
612
+ require.register("component-trim/index.js", function(exports, require, module){
613
+
614
+ exports = module.exports = trim;
615
+
616
+ function trim(str){
617
+ return str.replace(/^\s*|\s*$/g, '');
618
+ }
619
+
620
+ exports.left = function(str){
621
+ return str.replace(/^\s*/, '');
622
+ };
623
+
624
+ exports.right = function(str){
625
+ return str.replace(/\s*$/, '');
626
+ };
627
+
628
+ });
629
+ require.register("component-querystring/index.js", function(exports, require, module){
630
+
631
+ /**
632
+ * Module dependencies.
633
+ */
634
+
635
+ var trim = require('trim');
636
+
637
+ /**
638
+ * Parse the given query `str`.
639
+ *
640
+ * @param {String} str
641
+ * @return {Object}
642
+ * @api public
643
+ */
644
+
645
+ exports.parse = function(str){
646
+ if ('string' != typeof str) return {};
647
+
648
+ str = trim(str);
649
+ if ('' == str) return {};
650
+
651
+ var obj = {};
652
+ var pairs = str.split('&');
653
+ for (var i = 0; i < pairs.length; i++) {
654
+ var parts = pairs[i].split('=');
655
+ obj[parts[0]] = null == parts[1]
656
+ ? ''
657
+ : decodeURIComponent(parts[1]);
658
+ }
659
+
660
+ return obj;
661
+ };
662
+
663
+ /**
664
+ * Stringify the given `obj`.
665
+ *
666
+ * @param {Object} obj
667
+ * @return {String}
668
+ * @api public
669
+ */
670
+
671
+ exports.stringify = function(obj){
672
+ if (!obj) return '';
673
+ var pairs = [];
674
+ for (var key in obj) {
675
+ pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
676
+ }
677
+ return pairs.join('&');
678
+ };
679
+
680
+ });
681
+ require.register("component-type/index.js", function(exports, require, module){
682
+
683
+ /**
684
+ * toString ref.
685
+ */
686
+
687
+ var toString = Object.prototype.toString;
688
+
689
+ /**
690
+ * Return the type of `val`.
691
+ *
692
+ * @param {Mixed} val
693
+ * @return {String}
694
+ * @api public
695
+ */
696
+
697
+ module.exports = function(val){
698
+ switch (toString.call(val)) {
699
+ case '[object Function]': return 'function';
700
+ case '[object Date]': return 'date';
701
+ case '[object RegExp]': return 'regexp';
702
+ case '[object Arguments]': return 'arguments';
703
+ case '[object Array]': return 'array';
704
+ case '[object String]': return 'string';
705
+ }
706
+
707
+ if (val === null) return 'null';
708
+ if (val === undefined) return 'undefined';
709
+ if (val && val.nodeType === 1) return 'element';
710
+ if (val === Object(val)) return 'object';
711
+
712
+ return typeof val;
713
+ };
714
+
715
+ });
716
+ require.register("component-url/index.js", function(exports, require, module){
717
+
718
+ /**
719
+ * Parse the given `url`.
720
+ *
721
+ * @param {String} str
722
+ * @return {Object}
723
+ * @api public
724
+ */
725
+
726
+ exports.parse = function(url){
727
+ var a = document.createElement('a');
728
+ a.href = url;
729
+ return {
730
+ href: a.href,
731
+ host: a.host || location.host,
732
+ port: ('0' === a.port || '' === a.port) ? location.port : a.port,
733
+ hash: a.hash,
734
+ hostname: a.hostname || location.hostname,
735
+ pathname: a.pathname.charAt(0) != '/' ? '/' + a.pathname : a.pathname,
736
+ protocol: !a.protocol || ':' == a.protocol ? location.protocol : a.protocol,
737
+ search: a.search,
738
+ query: a.search.slice(1)
739
+ };
740
+ };
741
+
742
+ /**
743
+ * Check if `url` is absolute.
744
+ *
745
+ * @param {String} url
746
+ * @return {Boolean}
747
+ * @api public
748
+ */
749
+
750
+ exports.isAbsolute = function(url){
751
+ return 0 == url.indexOf('//') || !!~url.indexOf('://');
752
+ };
753
+
754
+ /**
755
+ * Check if `url` is relative.
756
+ *
757
+ * @param {String} url
758
+ * @return {Boolean}
759
+ * @api public
760
+ */
761
+
762
+ exports.isRelative = function(url){
763
+ return !exports.isAbsolute(url);
764
+ };
765
+
766
+ /**
767
+ * Check if `url` is cross domain.
768
+ *
769
+ * @param {String} url
770
+ * @return {Boolean}
771
+ * @api public
772
+ */
773
+
774
+ exports.isCrossDomain = function(url){
775
+ url = exports.parse(url);
776
+ return url.hostname !== location.hostname
777
+ || url.port !== location.port
778
+ || url.protocol !== location.protocol;
779
+ };
780
+ });
781
+ require.register("segmentio-after/index.js", function(exports, require, module){
782
+
783
+ module.exports = function after (times, func) {
784
+ // After 0, really?
785
+ if (times <= 0) return func();
786
+
787
+ // That's more like it.
788
+ return function() {
789
+ if (--times < 1) {
790
+ return func.apply(this, arguments);
791
+ }
792
+ };
793
+ };
794
+ });
795
+ require.register("segmentio-alias/index.js", function(exports, require, module){
796
+
797
+ module.exports = function alias (object, aliases) {
798
+ // For each of our aliases, rename our object's keys.
799
+ for (var oldKey in aliases) {
800
+ var newKey = aliases[oldKey];
801
+ if (object[oldKey] !== undefined) {
802
+ object[newKey] = object[oldKey];
803
+ delete object[oldKey];
804
+ }
805
+ }
806
+ };
807
+ });
808
+ require.register("component-bind/index.js", function(exports, require, module){
809
+
810
+ /**
811
+ * Slice reference.
812
+ */
813
+
814
+ var slice = [].slice;
815
+
816
+ /**
817
+ * Bind `obj` to `fn`.
818
+ *
819
+ * @param {Object} obj
820
+ * @param {Function|String} fn or string
821
+ * @return {Function}
822
+ * @api public
823
+ */
824
+
825
+ module.exports = function(obj, fn){
826
+ if ('string' == typeof fn) fn = obj[fn];
827
+ if ('function' != typeof fn) throw new Error('bind() requires a function');
828
+ var args = [].slice.call(arguments, 2);
829
+ return function(){
830
+ return fn.apply(obj, args.concat(slice.call(arguments)));
831
+ }
832
+ };
833
+
834
+ });
835
+ require.register("segmentio-bind-all/index.js", function(exports, require, module){
836
+
837
+ var bind = require('bind')
838
+ , type = require('type');
839
+
840
+
841
+ module.exports = function (obj) {
842
+ for (var key in obj) {
843
+ var val = obj[key];
844
+ if (type(val) === 'function') obj[key] = bind(obj, obj[key]);
845
+ }
846
+ return obj;
847
+ };
848
+ });
849
+ require.register("segmentio-canonical/index.js", function(exports, require, module){
850
+ module.exports = function canonical () {
851
+ var tags = document.getElementsByTagName('link');
852
+ for (var i = 0, tag; tag = tags[i]; i++) {
853
+ if ('canonical' == tag.getAttribute('rel')) return tag.getAttribute('href');
854
+ }
855
+ };
856
+ });
857
+ require.register("segmentio-extend/index.js", function(exports, require, module){
858
+
859
+ module.exports = function extend (object) {
860
+ // Takes an unlimited number of extenders.
861
+ var args = Array.prototype.slice.call(arguments, 1);
862
+
863
+ // For each extender, copy their properties on our object.
864
+ for (var i = 0, source; source = args[i]; i++) {
865
+ if (!source) continue;
866
+ for (var property in source) {
867
+ object[property] = source[property];
868
+ }
869
+ }
870
+
871
+ return object;
872
+ };
873
+ });
874
+ require.register("segmentio-is-email/index.js", function(exports, require, module){
875
+
876
+ module.exports = function isEmail (string) {
877
+ return (/.+\@.+\..+/).test(string);
878
+ };
879
+ });
880
+ require.register("segmentio-is-meta/index.js", function(exports, require, module){
881
+ module.exports = function isMeta (e) {
882
+ if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return true;
883
+
884
+ // Logic that handles checks for the middle mouse button, based
885
+ // on [jQuery](https://github.com/jquery/jquery/blob/master/src/event.js#L466).
886
+ var which = e.which, button = e.button;
887
+ if (!which && button !== undefined) {
888
+ return (!button & 1) && (!button & 2) && (button & 4);
889
+ } else if (which === 2) {
890
+ return true;
891
+ }
892
+
893
+ return false;
894
+ };
895
+ });
896
+ require.register("component-json-fallback/index.js", function(exports, require, module){
897
+ /*
898
+ json2.js
899
+ 2011-10-19
900
+
901
+ Public Domain.
902
+
903
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
904
+
905
+ See http://www.JSON.org/js.html
906
+
907
+
908
+ This code should be minified before deployment.
909
+ See http://javascript.crockford.com/jsmin.html
910
+
911
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
912
+ NOT CONTROL.
913
+
914
+
915
+ This file creates a global JSON object containing two methods: stringify
916
+ and parse.
917
+
918
+ JSON.stringify(value, replacer, space)
919
+ value any JavaScript value, usually an object or array.
920
+
921
+ replacer an optional parameter that determines how object
922
+ values are stringified for objects. It can be a
923
+ function or an array of strings.
924
+
925
+ space an optional parameter that specifies the indentation
926
+ of nested structures. If it is omitted, the text will
927
+ be packed without extra whitespace. If it is a number,
928
+ it will specify the number of spaces to indent at each
929
+ level. If it is a string (such as '\t' or '&nbsp;'),
930
+ it contains the characters used to indent at each level.
931
+
932
+ This method produces a JSON text from a JavaScript value.
933
+
934
+ When an object value is found, if the object contains a toJSON
935
+ method, its toJSON method will be called and the result will be
936
+ stringified. A toJSON method does not serialize: it returns the
937
+ value represented by the name/value pair that should be serialized,
938
+ or undefined if nothing should be serialized. The toJSON method
939
+ will be passed the key associated with the value, and this will be
940
+ bound to the value
941
+
942
+ For example, this would serialize Dates as ISO strings.
943
+
944
+ Date.prototype.toJSON = function (key) {
945
+ function f(n) {
946
+ // Format integers to have at least two digits.
947
+ return n < 10 ? '0' + n : n;
948
+ }
949
+
950
+ return this.getUTCFullYear() + '-' +
951
+ f(this.getUTCMonth() + 1) + '-' +
952
+ f(this.getUTCDate()) + 'T' +
953
+ f(this.getUTCHours()) + ':' +
954
+ f(this.getUTCMinutes()) + ':' +
955
+ f(this.getUTCSeconds()) + 'Z';
956
+ };
957
+
958
+ You can provide an optional replacer method. It will be passed the
959
+ key and value of each member, with this bound to the containing
960
+ object. The value that is returned from your method will be
961
+ serialized. If your method returns undefined, then the member will
962
+ be excluded from the serialization.
963
+
964
+ If the replacer parameter is an array of strings, then it will be
965
+ used to select the members to be serialized. It filters the results
966
+ such that only members with keys listed in the replacer array are
967
+ stringified.
968
+
969
+ Values that do not have JSON representations, such as undefined or
970
+ functions, will not be serialized. Such values in objects will be
971
+ dropped; in arrays they will be replaced with null. You can use
972
+ a replacer function to replace those with JSON values.
973
+ JSON.stringify(undefined) returns undefined.
974
+
975
+ The optional space parameter produces a stringification of the
976
+ value that is filled with line breaks and indentation to make it
977
+ easier to read.
978
+
979
+ If the space parameter is a non-empty string, then that string will
980
+ be used for indentation. If the space parameter is a number, then
981
+ the indentation will be that many spaces.
982
+
983
+ Example:
984
+
985
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
986
+ // text is '["e",{"pluribus":"unum"}]'
987
+
988
+
989
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
990
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
991
+
992
+ text = JSON.stringify([new Date()], function (key, value) {
993
+ return this[key] instanceof Date ?
994
+ 'Date(' + this[key] + ')' : value;
995
+ });
996
+ // text is '["Date(---current time---)"]'
997
+
998
+
999
+ JSON.parse(text, reviver)
1000
+ This method parses a JSON text to produce an object or array.
1001
+ It can throw a SyntaxError exception.
1002
+
1003
+ The optional reviver parameter is a function that can filter and
1004
+ transform the results. It receives each of the keys and values,
1005
+ and its return value is used instead of the original value.
1006
+ If it returns what it received, then the structure is not modified.
1007
+ If it returns undefined then the member is deleted.
1008
+
1009
+ Example:
1010
+
1011
+ // Parse the text. Values that look like ISO date strings will
1012
+ // be converted to Date objects.
1013
+
1014
+ myData = JSON.parse(text, function (key, value) {
1015
+ var a;
1016
+ if (typeof value === 'string') {
1017
+ a =
1018
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
1019
+ if (a) {
1020
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
1021
+ +a[5], +a[6]));
1022
+ }
1023
+ }
1024
+ return value;
1025
+ });
1026
+
1027
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
1028
+ var d;
1029
+ if (typeof value === 'string' &&
1030
+ value.slice(0, 5) === 'Date(' &&
1031
+ value.slice(-1) === ')') {
1032
+ d = new Date(value.slice(5, -1));
1033
+ if (d) {
1034
+ return d;
1035
+ }
1036
+ }
1037
+ return value;
1038
+ });
1039
+
1040
+
1041
+ This is a reference implementation. You are free to copy, modify, or
1042
+ redistribute.
1043
+ */
1044
+
1045
+ /*jslint evil: true, regexp: true */
1046
+
1047
+ /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
1048
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
1049
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
1050
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
1051
+ test, toJSON, toString, valueOf
1052
+ */
1053
+
1054
+
1055
+ // Create a JSON object only if one does not already exist. We create the
1056
+ // methods in a closure to avoid creating global variables.
1057
+
1058
+ var JSON = {};
1059
+
1060
+ (function () {
1061
+ 'use strict';
1062
+
1063
+ function f(n) {
1064
+ // Format integers to have at least two digits.
1065
+ return n < 10 ? '0' + n : n;
1066
+ }
1067
+
1068
+ if (typeof Date.prototype.toJSON !== 'function') {
1069
+
1070
+ Date.prototype.toJSON = function (key) {
1071
+
1072
+ return isFinite(this.valueOf())
1073
+ ? this.getUTCFullYear() + '-' +
1074
+ f(this.getUTCMonth() + 1) + '-' +
1075
+ f(this.getUTCDate()) + 'T' +
1076
+ f(this.getUTCHours()) + ':' +
1077
+ f(this.getUTCMinutes()) + ':' +
1078
+ f(this.getUTCSeconds()) + 'Z'
1079
+ : null;
1080
+ };
1081
+
1082
+ String.prototype.toJSON =
1083
+ Number.prototype.toJSON =
1084
+ Boolean.prototype.toJSON = function (key) {
1085
+ return this.valueOf();
1086
+ };
1087
+ }
1088
+
1089
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
1090
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
1091
+ gap,
1092
+ indent,
1093
+ meta = { // table of character substitutions
1094
+ '\b': '\\b',
1095
+ '\t': '\\t',
1096
+ '\n': '\\n',
1097
+ '\f': '\\f',
1098
+ '\r': '\\r',
1099
+ '"' : '\\"',
1100
+ '\\': '\\\\'
1101
+ },
1102
+ rep;
1103
+
1104
+
1105
+ function quote(string) {
1106
+
1107
+ // If the string contains no control characters, no quote characters, and no
1108
+ // backslash characters, then we can safely slap some quotes around it.
1109
+ // Otherwise we must also replace the offending characters with safe escape
1110
+ // sequences.
1111
+
1112
+ escapable.lastIndex = 0;
1113
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
1114
+ var c = meta[a];
1115
+ return typeof c === 'string'
1116
+ ? c
1117
+ : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
1118
+ }) + '"' : '"' + string + '"';
1119
+ }
1120
+
1121
+
1122
+ function str(key, holder) {
1123
+
1124
+ // Produce a string from holder[key].
1125
+
1126
+ var i, // The loop counter.
1127
+ k, // The member key.
1128
+ v, // The member value.
1129
+ length,
1130
+ mind = gap,
1131
+ partial,
1132
+ value = holder[key];
1133
+
1134
+ // If the value has a toJSON method, call it to obtain a replacement value.
1135
+
1136
+ if (value && typeof value === 'object' &&
1137
+ typeof value.toJSON === 'function') {
1138
+ value = value.toJSON(key);
1139
+ }
1140
+
1141
+ // If we were called with a replacer function, then call the replacer to
1142
+ // obtain a replacement value.
1143
+
1144
+ if (typeof rep === 'function') {
1145
+ value = rep.call(holder, key, value);
1146
+ }
1147
+
1148
+ // What happens next depends on the value's type.
1149
+
1150
+ switch (typeof value) {
1151
+ case 'string':
1152
+ return quote(value);
1153
+
1154
+ case 'number':
1155
+
1156
+ // JSON numbers must be finite. Encode non-finite numbers as null.
1157
+
1158
+ return isFinite(value) ? String(value) : 'null';
1159
+
1160
+ case 'boolean':
1161
+ case 'null':
1162
+
1163
+ // If the value is a boolean or null, convert it to a string. Note:
1164
+ // typeof null does not produce 'null'. The case is included here in
1165
+ // the remote chance that this gets fixed someday.
1166
+
1167
+ return String(value);
1168
+
1169
+ // If the type is 'object', we might be dealing with an object or an array or
1170
+ // null.
1171
+
1172
+ case 'object':
1173
+
1174
+ // Due to a specification blunder in ECMAScript, typeof null is 'object',
1175
+ // so watch out for that case.
1176
+
1177
+ if (!value) {
1178
+ return 'null';
1179
+ }
1180
+
1181
+ // Make an array to hold the partial results of stringifying this object value.
1182
+
1183
+ gap += indent;
1184
+ partial = [];
1185
+
1186
+ // Is the value an array?
1187
+
1188
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
1189
+
1190
+ // The value is an array. Stringify every element. Use null as a placeholder
1191
+ // for non-JSON values.
1192
+
1193
+ length = value.length;
1194
+ for (i = 0; i < length; i += 1) {
1195
+ partial[i] = str(i, value) || 'null';
1196
+ }
1197
+
1198
+ // Join all of the elements together, separated with commas, and wrap them in
1199
+ // brackets.
1200
+
1201
+ v = partial.length === 0
1202
+ ? '[]'
1203
+ : gap
1204
+ ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
1205
+ : '[' + partial.join(',') + ']';
1206
+ gap = mind;
1207
+ return v;
1208
+ }
1209
+
1210
+ // If the replacer is an array, use it to select the members to be stringified.
1211
+
1212
+ if (rep && typeof rep === 'object') {
1213
+ length = rep.length;
1214
+ for (i = 0; i < length; i += 1) {
1215
+ if (typeof rep[i] === 'string') {
1216
+ k = rep[i];
1217
+ v = str(k, value);
1218
+ if (v) {
1219
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
1220
+ }
1221
+ }
1222
+ }
1223
+ } else {
1224
+
1225
+ // Otherwise, iterate through all of the keys in the object.
1226
+
1227
+ for (k in value) {
1228
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
1229
+ v = str(k, value);
1230
+ if (v) {
1231
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
1232
+ }
1233
+ }
1234
+ }
1235
+ }
1236
+
1237
+ // Join all of the member texts together, separated with commas,
1238
+ // and wrap them in braces.
1239
+
1240
+ v = partial.length === 0
1241
+ ? '{}'
1242
+ : gap
1243
+ ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
1244
+ : '{' + partial.join(',') + '}';
1245
+ gap = mind;
1246
+ return v;
1247
+ }
1248
+ }
1249
+
1250
+ // If the JSON object does not yet have a stringify method, give it one.
1251
+
1252
+ if (typeof JSON.stringify !== 'function') {
1253
+ JSON.stringify = function (value, replacer, space) {
1254
+
1255
+ // The stringify method takes a value and an optional replacer, and an optional
1256
+ // space parameter, and returns a JSON text. The replacer can be a function
1257
+ // that can replace values, or an array of strings that will select the keys.
1258
+ // A default replacer method can be provided. Use of the space parameter can
1259
+ // produce text that is more easily readable.
1260
+
1261
+ var i;
1262
+ gap = '';
1263
+ indent = '';
1264
+
1265
+ // If the space parameter is a number, make an indent string containing that
1266
+ // many spaces.
1267
+
1268
+ if (typeof space === 'number') {
1269
+ for (i = 0; i < space; i += 1) {
1270
+ indent += ' ';
1271
+ }
1272
+
1273
+ // If the space parameter is a string, it will be used as the indent string.
1274
+
1275
+ } else if (typeof space === 'string') {
1276
+ indent = space;
1277
+ }
1278
+
1279
+ // If there is a replacer, it must be a function or an array.
1280
+ // Otherwise, throw an error.
1281
+
1282
+ rep = replacer;
1283
+ if (replacer && typeof replacer !== 'function' &&
1284
+ (typeof replacer !== 'object' ||
1285
+ typeof replacer.length !== 'number')) {
1286
+ throw new Error('JSON.stringify');
1287
+ }
1288
+
1289
+ // Make a fake root object containing our value under the key of ''.
1290
+ // Return the result of stringifying the value.
1291
+
1292
+ return str('', {'': value});
1293
+ };
1294
+ }
1295
+
1296
+
1297
+ // If the JSON object does not yet have a parse method, give it one.
1298
+
1299
+ if (typeof JSON.parse !== 'function') {
1300
+ JSON.parse = function (text, reviver) {
1301
+
1302
+ // The parse method takes a text and an optional reviver function, and returns
1303
+ // a JavaScript value if the text is a valid JSON text.
1304
+
1305
+ var j;
1306
+
1307
+ function walk(holder, key) {
1308
+
1309
+ // The walk method is used to recursively walk the resulting structure so
1310
+ // that modifications can be made.
1311
+
1312
+ var k, v, value = holder[key];
1313
+ if (value && typeof value === 'object') {
1314
+ for (k in value) {
1315
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
1316
+ v = walk(value, k);
1317
+ if (v !== undefined) {
1318
+ value[k] = v;
1319
+ } else {
1320
+ delete value[k];
1321
+ }
1322
+ }
1323
+ }
1324
+ }
1325
+ return reviver.call(holder, key, value);
1326
+ }
1327
+
1328
+
1329
+ // Parsing happens in four stages. In the first stage, we replace certain
1330
+ // Unicode characters with escape sequences. JavaScript handles many characters
1331
+ // incorrectly, either silently deleting them, or treating them as line endings.
1332
+
1333
+ text = String(text);
1334
+ cx.lastIndex = 0;
1335
+ if (cx.test(text)) {
1336
+ text = text.replace(cx, function (a) {
1337
+ return '\\u' +
1338
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
1339
+ });
1340
+ }
1341
+
1342
+ // In the second stage, we run the text against regular expressions that look
1343
+ // for non-JSON patterns. We are especially concerned with '()' and 'new'
1344
+ // because they can cause invocation, and '=' because it can cause mutation.
1345
+ // But just to be safe, we want to reject all unexpected forms.
1346
+
1347
+ // We split the second stage into 4 regexp operations in order to work around
1348
+ // crippling inefficiencies in IE's and Safari's regexp engines. First we
1349
+ // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
1350
+ // replace all simple value tokens with ']' characters. Third, we delete all
1351
+ // open brackets that follow a colon or comma or that begin the text. Finally,
1352
+ // we look to see that the remaining characters are only whitespace or ']' or
1353
+ // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
1354
+
1355
+ if (/^[\],:{}\s]*$/
1356
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
1357
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
1358
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
1359
+
1360
+ // In the third stage we use the eval function to compile the text into a
1361
+ // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
1362
+ // in JavaScript: it can begin a block or an object literal. We wrap the text
1363
+ // in parens to eliminate the ambiguity.
1364
+
1365
+ j = eval('(' + text + ')');
1366
+
1367
+ // In the optional fourth stage, we recursively walk the new structure, passing
1368
+ // each name/value pair to a reviver function for possible transformation.
1369
+
1370
+ return typeof reviver === 'function'
1371
+ ? walk({'': j}, '')
1372
+ : j;
1373
+ }
1374
+
1375
+ // If the text is not JSON parseable, then a SyntaxError is thrown.
1376
+
1377
+ throw new SyntaxError('JSON.parse');
1378
+ };
1379
+ }
1380
+ }());
1381
+
1382
+ module.exports = JSON
1383
+ });
1384
+ require.register("segmentio-json/index.js", function(exports, require, module){
1385
+
1386
+ module.exports = 'undefined' == typeof JSON
1387
+ ? require('json-fallback')
1388
+ : JSON;
1389
+
1390
+ });
1391
+ require.register("segmentio-load-date/index.js", function(exports, require, module){
1392
+
1393
+
1394
+ /*
1395
+ * Load date.
1396
+ *
1397
+ * For reference: http://www.html5rocks.com/en/tutorials/webperformance/basics/
1398
+ */
1399
+
1400
+ var time = new Date()
1401
+ , perf = window.performance;
1402
+
1403
+ if (perf && perf.timing && perf.timing.responseEnd) {
1404
+ time = new Date(perf.timing.responseEnd);
1405
+ }
1406
+
1407
+ module.exports = time;
1408
+ });
1409
+ require.register("segmentio-load-script/index.js", function(exports, require, module){
1410
+ var type = require('type');
1411
+
1412
+
1413
+ module.exports = function loadScript (options, callback) {
1414
+ if (!options) throw new Error('Cant load nothing...');
1415
+
1416
+ // Allow for the simplest case, just passing a `src` string.
1417
+ if (type(options) === 'string') options = { src : options };
1418
+
1419
+ var https = document.location.protocol === 'https:';
1420
+
1421
+ // If you use protocol relative URLs, third-party scripts like Google
1422
+ // Analytics break when testing with `file:` so this fixes that.
1423
+ if (options.src && options.src.indexOf('//') === 0) {
1424
+ options.src = https ? 'https:' + options.src : 'http:' + options.src;
1425
+ }
1426
+
1427
+ // Allow them to pass in different URLs depending on the protocol.
1428
+ if (https && options.https) options.src = options.https;
1429
+ else if (!https && options.http) options.src = options.http;
1430
+
1431
+ // Make the `<script>` element and insert it before the first script on the
1432
+ // page, which is guaranteed to exist since this Javascript is running.
1433
+ var script = document.createElement('script');
1434
+ script.type = 'text/javascript';
1435
+ script.async = true;
1436
+ script.src = options.src;
1437
+
1438
+ var firstScript = document.getElementsByTagName('script')[0];
1439
+ firstScript.parentNode.insertBefore(script, firstScript);
1440
+
1441
+ // If we have a callback, attach event handlers, even in IE. Based off of
1442
+ // the Third-Party Javascript script loading example:
1443
+ // https://github.com/thirdpartyjs/thirdpartyjs-code/blob/master/examples/templates/02/loading-files/index.html
1444
+ if (callback && type(callback) === 'function') {
1445
+ if (script.addEventListener) {
1446
+ script.addEventListener('load', callback, false);
1447
+ } else if (script.attachEvent) {
1448
+ script.attachEvent('onreadystatechange', function () {
1449
+ if (/complete|loaded/.test(script.readyState)) callback();
1450
+ });
1451
+ }
1452
+ }
1453
+
1454
+ // Return the script element in case they want to do anything special, like
1455
+ // give it an ID or attributes.
1456
+ return script;
1457
+ };
1458
+ });
1459
+ require.register("segmentio-type/index.js", function(exports, require, module){
1460
+
1461
+ /**
1462
+ * toString ref.
1463
+ */
1464
+
1465
+ var toString = Object.prototype.toString;
1466
+
1467
+ /**
1468
+ * Return the type of `val`.
1469
+ *
1470
+ * @param {Mixed} val
1471
+ * @return {String}
1472
+ * @api public
1473
+ */
1474
+
1475
+ module.exports = function(val){
1476
+ switch (toString.call(val)) {
1477
+ case '[object Function]': return 'function';
1478
+ case '[object Date]': return 'date';
1479
+ case '[object RegExp]': return 'regexp';
1480
+ case '[object Arguments]': return 'arguments';
1481
+ case '[object Array]': return 'array';
1482
+ case '[object String]': return 'string';
1483
+ }
1484
+
1485
+ if (val === null) return 'null';
1486
+ if (val === undefined) return 'undefined';
1487
+ if (val && val.nodeType === 1) return 'element';
1488
+ if (val === Object(val)) return 'object';
1489
+
1490
+ return typeof val;
1491
+ };
1492
+
1493
+ });
1494
+ require.register("segmentio-new-date/index.js", function(exports, require, module){
1495
+ var type = require('type');
1496
+
1497
+
1498
+ /**
1499
+ * Returns a new Javascript Date object, allowing a variety of extra input types
1500
+ * over the native one.
1501
+ *
1502
+ * @param {Date|String|Number} input
1503
+ */
1504
+
1505
+ module.exports = function newDate (input) {
1506
+
1507
+ // Convert input from seconds to milliseconds.
1508
+ input = toMilliseconds(input);
1509
+
1510
+ // By default, delegate to Date, which will return `Invalid Date`s if wrong.
1511
+ var date = new Date(input);
1512
+
1513
+ // If we have a string that the Date constructor couldn't parse, convert it.
1514
+ if (isNaN(date.getTime()) && 'string' === type(input)) {
1515
+ var milliseconds = toMilliseconds(parseInt(input, 10));
1516
+ date = new Date(milliseconds);
1517
+ }
1518
+
1519
+ return date;
1520
+ };
1521
+
1522
+
1523
+ /**
1524
+ * If the number passed in is seconds from the epoch, turn it into milliseconds.
1525
+ * Milliseconds would be greater than 31557600000 (December 31, 1970).
1526
+ *
1527
+ * @param seconds
1528
+ */
1529
+
1530
+ function toMilliseconds (seconds) {
1531
+ if ('number' === type(seconds) && seconds < 31557600000) return seconds * 1000;
1532
+ return seconds;
1533
+ }
1534
+ });
1535
+ require.register("segmentio-on-body/index.js", function(exports, require, module){
1536
+ var each = require('each');
1537
+
1538
+
1539
+ /**
1540
+ * Cache whether `<body>` exists.
1541
+ */
1542
+
1543
+ var body = false;
1544
+
1545
+
1546
+ /**
1547
+ * Callbacks to call when the body exists.
1548
+ */
1549
+
1550
+ var callbacks = [];
1551
+
1552
+
1553
+ /**
1554
+ * Export a way to add handlers to be invoked once the body exists.
1555
+ *
1556
+ * @param {Function} callback A function to call when the body exists.
1557
+ */
1558
+
1559
+ module.exports = function onBody (callback) {
1560
+ if (body) {
1561
+ call(callback);
1562
+ } else {
1563
+ callbacks.push(callback);
1564
+ }
1565
+ };
1566
+
1567
+
1568
+ /**
1569
+ * Set an interval to check for `document.body`.
1570
+ */
1571
+
1572
+ var interval = setInterval(function () {
1573
+ if (!document.body) return;
1574
+ body = true;
1575
+ each(callbacks, call);
1576
+ clearInterval(interval);
1577
+ }, 5);
1578
+
1579
+
1580
+ /**
1581
+ * Call a callback, passing it the body.
1582
+ *
1583
+ * @param {Function} callback The callback to call.
1584
+ */
1585
+
1586
+ function call (callback) {
1587
+ callback(document.body);
1588
+ }
1589
+ });
1590
+ require.register("segmentio-store.js/store.js", function(exports, require, module){
1591
+ var json = require('json')
1592
+ , store = {}
1593
+ , win = window
1594
+ , doc = win.document
1595
+ , localStorageName = 'localStorage'
1596
+ , namespace = '__storejs__'
1597
+ , storage;
1598
+
1599
+ store.disabled = false
1600
+ store.set = function(key, value) {}
1601
+ store.get = function(key) {}
1602
+ store.remove = function(key) {}
1603
+ store.clear = function() {}
1604
+ store.transact = function(key, defaultVal, transactionFn) {
1605
+ var val = store.get(key)
1606
+ if (transactionFn == null) {
1607
+ transactionFn = defaultVal
1608
+ defaultVal = null
1609
+ }
1610
+ if (typeof val == 'undefined') { val = defaultVal || {} }
1611
+ transactionFn(val)
1612
+ store.set(key, val)
1613
+ }
1614
+ store.getAll = function() {}
1615
+
1616
+ store.serialize = function(value) {
1617
+ return json.stringify(value)
1618
+ }
1619
+ store.deserialize = function(value) {
1620
+ if (typeof value != 'string') { return undefined }
1621
+ try { return json.parse(value) }
1622
+ catch(e) { return value || undefined }
1623
+ }
1624
+
1625
+ // Functions to encapsulate questionable FireFox 3.6.13 behavior
1626
+ // when about.config::dom.storage.enabled === false
1627
+ // See https://github.com/marcuswestin/store.js/issues#issue/13
1628
+ function isLocalStorageNameSupported() {
1629
+ try { return (localStorageName in win && win[localStorageName]) }
1630
+ catch(err) { return false }
1631
+ }
1632
+
1633
+ if (isLocalStorageNameSupported()) {
1634
+ storage = win[localStorageName]
1635
+ store.set = function(key, val) {
1636
+ if (val === undefined) { return store.remove(key) }
1637
+ storage.setItem(key, store.serialize(val))
1638
+ return val
1639
+ }
1640
+ store.get = function(key) { return store.deserialize(storage.getItem(key)) }
1641
+ store.remove = function(key) { storage.removeItem(key) }
1642
+ store.clear = function() { storage.clear() }
1643
+ store.getAll = function() {
1644
+ var ret = {}
1645
+ for (var i=0; i<storage.length; ++i) {
1646
+ var key = storage.key(i)
1647
+ ret[key] = store.get(key)
1648
+ }
1649
+ return ret
1650
+ }
1651
+ } else if (doc.documentElement.addBehavior) {
1652
+ var storageOwner,
1653
+ storageContainer
1654
+ // Since #userData storage applies only to specific paths, we need to
1655
+ // somehow link our data to a specific path. We choose /favicon.ico
1656
+ // as a pretty safe option, since all browsers already make a request to
1657
+ // this URL anyway and being a 404 will not hurt us here. We wrap an
1658
+ // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
1659
+ // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
1660
+ // since the iframe access rules appear to allow direct access and
1661
+ // manipulation of the document element, even for a 404 page. This
1662
+ // document can be used instead of the current document (which would
1663
+ // have been limited to the current path) to perform #userData storage.
1664
+ try {
1665
+ storageContainer = new ActiveXObject('htmlfile')
1666
+ storageContainer.open()
1667
+ storageContainer.write('<s' + 'cript>document.w=window</s' + 'cript><iframe src="/favicon.ico"></iframe>')
1668
+ storageContainer.close()
1669
+ storageOwner = storageContainer.w.frames[0].document
1670
+ storage = storageOwner.createElement('div')
1671
+ } catch(e) {
1672
+ // somehow ActiveXObject instantiation failed (perhaps some special
1673
+ // security settings or otherwse), fall back to per-path storage
1674
+ storage = doc.createElement('div')
1675
+ storageOwner = doc.body
1676
+ }
1677
+ function withIEStorage(storeFunction) {
1678
+ return function() {
1679
+ var args = Array.prototype.slice.call(arguments, 0)
1680
+ args.unshift(storage)
1681
+ // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
1682
+ // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
1683
+ storageOwner.appendChild(storage)
1684
+ storage.addBehavior('#default#userData')
1685
+ storage.load(localStorageName)
1686
+ var result = storeFunction.apply(store, args)
1687
+ storageOwner.removeChild(storage)
1688
+ return result
1689
+ }
1690
+ }
1691
+
1692
+ // In IE7, keys may not contain special chars. See all of https://github.com/marcuswestin/store.js/issues/40
1693
+ var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g")
1694
+ function ieKeyFix(key) {
1695
+ return key.replace(forbiddenCharsRegex, '___')
1696
+ }
1697
+ store.set = withIEStorage(function(storage, key, val) {
1698
+ key = ieKeyFix(key)
1699
+ if (val === undefined) { return store.remove(key) }
1700
+ storage.setAttribute(key, store.serialize(val))
1701
+ storage.save(localStorageName)
1702
+ return val
1703
+ })
1704
+ store.get = withIEStorage(function(storage, key) {
1705
+ key = ieKeyFix(key)
1706
+ return store.deserialize(storage.getAttribute(key))
1707
+ })
1708
+ store.remove = withIEStorage(function(storage, key) {
1709
+ key = ieKeyFix(key)
1710
+ storage.removeAttribute(key)
1711
+ storage.save(localStorageName)
1712
+ })
1713
+ store.clear = withIEStorage(function(storage) {
1714
+ var attributes = storage.XMLDocument.documentElement.attributes
1715
+ storage.load(localStorageName)
1716
+ for (var i=0, attr; attr=attributes[i]; i++) {
1717
+ storage.removeAttribute(attr.name)
1718
+ }
1719
+ storage.save(localStorageName)
1720
+ })
1721
+ store.getAll = withIEStorage(function(storage) {
1722
+ var attributes = storage.XMLDocument.documentElement.attributes
1723
+ var ret = {}
1724
+ for (var i=0, attr; attr=attributes[i]; ++i) {
1725
+ var key = ieKeyFix(attr.name)
1726
+ ret[attr.name] = store.deserialize(storage.getAttribute(key))
1727
+ }
1728
+ return ret
1729
+ })
1730
+ }
1731
+
1732
+ try {
1733
+ store.set(namespace, namespace)
1734
+ if (store.get(namespace) != namespace) { store.disabled = true }
1735
+ store.remove(namespace)
1736
+ } catch(e) {
1737
+ store.disabled = true
1738
+ }
1739
+ store.enabled = !store.disabled
1740
+
1741
+ module.exports = store;
1742
+ });
1743
+ require.register("segmentio-top-domain/index.js", function(exports, require, module){
1744
+
1745
+ var url = require('url');
1746
+
1747
+ // Official Grammar: http://tools.ietf.org/html/rfc883#page-56
1748
+ // Look for tlds with up to 2-6 characters.
1749
+
1750
+ module.exports = function (urlStr) {
1751
+
1752
+ var host = url.parse(urlStr).hostname
1753
+ , topLevel = host.match(/[a-z0-9][a-z0-9\-]*[a-z0-9]\.[a-z\.]{2,6}$/i);
1754
+
1755
+ return topLevel ? topLevel[0] : host;
1756
+ };
1757
+ });
1758
+ require.register("timoxley-next-tick/index.js", function(exports, require, module){
1759
+ "use strict"
1760
+
1761
+ if (typeof setImmediate == 'function') {
1762
+ module.exports = function(f){ setImmediate(f) }
1763
+ }
1764
+ // legacy node.js
1765
+ else if (typeof process != 'undefined' && typeof process.nextTick == 'function') {
1766
+ module.exports = process.nextTick
1767
+ }
1768
+ // fallback for other environments / postMessage behaves badly on IE8
1769
+ else if (typeof window == 'undefined' || window.ActiveXObject || !window.postMessage) {
1770
+ module.exports = function(f){ setTimeout(f) };
1771
+ } else {
1772
+ var q = [];
1773
+
1774
+ window.addEventListener('message', function(){
1775
+ var i = 0;
1776
+ while (i < q.length) {
1777
+ try { q[i++](); }
1778
+ catch (e) {
1779
+ q = q.slice(i);
1780
+ window.postMessage('tic!', '*');
1781
+ throw e;
1782
+ }
1783
+ }
1784
+ q.length = 0;
1785
+ }, true);
1786
+
1787
+ module.exports = function(fn){
1788
+ if (!q.length) window.postMessage('tic!', '*');
1789
+ q.push(fn);
1790
+ }
1791
+ }
1792
+
1793
+ });
1794
+ require.register("yields-prevent/index.js", function(exports, require, module){
1795
+
1796
+ /**
1797
+ * prevent default on the given `e`.
1798
+ *
1799
+ * examples:
1800
+ *
1801
+ * anchor.onclick = prevent;
1802
+ * anchor.onclick = function(e){
1803
+ * if (something) return prevent(e);
1804
+ * };
1805
+ *
1806
+ * @param {Event} e
1807
+ */
1808
+
1809
+ module.exports = function(e){
1810
+ e = e || window.event
1811
+ return e.preventDefault
1812
+ ? e.preventDefault()
1813
+ : e.returnValue = false;
1814
+ };
1815
+
1816
+ });
1817
+ require.register("analytics/src/index.js", function(exports, require, module){
1818
+ // Analytics.js
1819
+ //
1820
+ // (c) 2013 Segment.io Inc.
1821
+ // Analytics.js may be freely distributed under the MIT license.
1822
+
1823
+ var Analytics = require('./analytics')
1824
+ , providers = require('./providers');
1825
+
1826
+
1827
+ module.exports = new Analytics(providers);
1828
+ });
1829
+ require.register("analytics/src/analytics.js", function(exports, require, module){
1830
+ var after = require('after')
1831
+ , bind = require('event').bind
1832
+ , clone = require('clone')
1833
+ , cookie = require('./cookie')
1834
+ , each = require('each')
1835
+ , extend = require('extend')
1836
+ , isEmail = require('is-email')
1837
+ , isMeta = require('is-meta')
1838
+ , localStore = require('./localStore')
1839
+ , newDate = require('new-date')
1840
+ , size = require('object').length
1841
+ , preventDefault = require('prevent')
1842
+ , Provider = require('./provider')
1843
+ , providers = require('./providers')
1844
+ , querystring = require('querystring')
1845
+ , type = require('type')
1846
+ , url = require('url')
1847
+ , user = require('./user')
1848
+ , utils = require('./utils');
1849
+
1850
+
1851
+ module.exports = Analytics;
1852
+
1853
+
1854
+ /**
1855
+ * Analytics.
1856
+ *
1857
+ * @param {Object} Providers - Provider classes that the user can initialize.
1858
+ */
1859
+
1860
+ function Analytics (Providers) {
1861
+ var self = this;
1862
+
1863
+ this.VERSION = '0.11.10';
1864
+
1865
+ each(Providers, function (Provider) {
1866
+ self.addProvider(Provider);
1867
+ });
1868
+
1869
+ // Wrap `onload` with our own that will cache the loaded state of the page.
1870
+ var oldonload = window.onload;
1871
+ window.onload = function () {
1872
+ self.loaded = true;
1873
+ if ('function' === type(oldonload)) oldonload();
1874
+ };
1875
+ }
1876
+
1877
+
1878
+ /**
1879
+ * Extend the Analytics prototype.
1880
+ */
1881
+
1882
+ extend(Analytics.prototype, {
1883
+
1884
+ // Whether `onload` has fired.
1885
+ loaded : false,
1886
+
1887
+ // Whether `analytics` has been initialized.
1888
+ initialized : false,
1889
+
1890
+ // Whether all of our analytics providers are ready to accept calls. Give it a
1891
+ // real jank name since we already use `analytics.ready` for the method.
1892
+ readied : false,
1893
+
1894
+ // A queue for ready callbacks to run when our `readied` state becomes `true`.
1895
+ callbacks : [],
1896
+
1897
+ // Milliseconds to wait for requests to clear before leaving the current page.
1898
+ timeout : 300,
1899
+
1900
+ // A reference to the current user object.
1901
+ user : user,
1902
+
1903
+ // The default Provider.
1904
+ Provider : Provider,
1905
+
1906
+ // Providers that can be initialized. Add using `this.addProvider`.
1907
+ _providers : {},
1908
+
1909
+ // The currently initialized providers.
1910
+ providers : [],
1911
+
1912
+
1913
+ /**
1914
+ * Add a provider to `_providers` to be initialized later.
1915
+ *
1916
+ * @param {String} name - The name of the provider.
1917
+ * @param {Function} Provider - The provider's class.
1918
+ */
1919
+
1920
+ addProvider : function (Provider) {
1921
+ this._providers[Provider.prototype.name] = Provider;
1922
+ },
1923
+
1924
+
1925
+ /**
1926
+ * Initialize
1927
+ *
1928
+ * Call `initialize` to setup analytics.js before identifying or
1929
+ * tracking any users or events. For example:
1930
+ *
1931
+ * analytics.initialize({
1932
+ * 'Google Analytics' : 'UA-XXXXXXX-X',
1933
+ * 'Segment.io' : 'XXXXXXXXXXX',
1934
+ * 'KISSmetrics' : 'XXXXXXXXXXX'
1935
+ * });
1936
+ *
1937
+ * @param {Object} providers - a dictionary of the providers you want to
1938
+ * enable. The keys are the names of the providers and their values are either
1939
+ * an api key, or dictionary of extra settings (including the api key).
1940
+ *
1941
+ * @param {Object} options (optional) - extra settings to initialize with.
1942
+ */
1943
+
1944
+ initialize : function (providers, options) {
1945
+ options || (options = {});
1946
+
1947
+ var self = this;
1948
+
1949
+ // Reset our state.
1950
+ this.providers = [];
1951
+ this.initialized = false;
1952
+ this.readied = false;
1953
+
1954
+ // Set the storage options
1955
+ cookie.options(options.cookie);
1956
+ localStore.options(options.localStorage);
1957
+
1958
+ // Set the options for loading and saving the user
1959
+ user.options(options.user);
1960
+ user.load();
1961
+
1962
+ // Create a ready method that will call all of our ready callbacks after all
1963
+ // of our providers have been initialized and loaded. We'll pass the
1964
+ // function into each provider's initialize method, so they can callback
1965
+ // after they've loaded successfully.
1966
+ var ready = after(size(providers), function () {
1967
+ self.readied = true;
1968
+ var callback;
1969
+ while(callback = self.callbacks.shift()) {
1970
+ callback();
1971
+ }
1972
+ });
1973
+
1974
+ // Initialize a new instance of each provider with their `options`, and
1975
+ // copy the provider into `this.providers`.
1976
+ each(providers, function (key, options) {
1977
+ var Provider = self._providers[key];
1978
+ if (!Provider) return;
1979
+ self.providers.push(new Provider(options, ready, self));
1980
+ });
1981
+
1982
+ // Identify and track any `ajs_uid` and `ajs_event` parameters in the URL.
1983
+ var query = url.parse(window.location.href).query;
1984
+ var queries = querystring.parse(query);
1985
+ if (queries.ajs_uid) this.identify(queries.ajs_uid);
1986
+ if (queries.ajs_event) this.track(queries.ajs_event);
1987
+
1988
+ // Update the initialized state that other methods rely on.
1989
+ this.initialized = true;
1990
+ },
1991
+
1992
+
1993
+ /**
1994
+ * Ready
1995
+ *
1996
+ * Add a callback that will get called when all of the analytics services you
1997
+ * initialize are ready to be called. It's like jQuery's `ready` except for
1998
+ * analytics instead of the DOM.
1999
+ *
2000
+ * If we're already ready, it will callback immediately.
2001
+ *
2002
+ * @param {Function} callback - The callback to attach.
2003
+ */
2004
+
2005
+ ready : function (callback) {
2006
+ if (type(callback) !== 'function') return;
2007
+ if (this.readied) return callback();
2008
+ this.callbacks.push(callback);
2009
+ },
2010
+
2011
+
2012
+ /**
2013
+ * Identify
2014
+ *
2015
+ * Identifying a user ties all of their actions to an ID you recognize
2016
+ * and records properties about a user. For example:
2017
+ *
2018
+ * analytics.identify('4d3ed089fb60ab534684b7e0', {
2019
+ * name : 'Achilles',
2020
+ * email : 'achilles@segment.io',
2021
+ * age : 23
2022
+ * });
2023
+ *
2024
+ * @param {String} userId (optional) - The ID you recognize the user by.
2025
+ * Ideally this isn't an email, because that might change in the future.
2026
+ *
2027
+ * @param {Object} traits (optional) - A dictionary of traits you know about
2028
+ * the user. Things like `name`, `age`, etc.
2029
+ *
2030
+ * @param {Object} options (optional) - Settings for the identify call.
2031
+ *
2032
+ * @param {Function} callback (optional) - A function to call after a small
2033
+ * timeout, giving the identify call time to make requests.
2034
+ */
2035
+
2036
+ identify : function (userId, traits, options, callback) {
2037
+ if (!this.initialized) return;
2038
+
2039
+ // Allow for optional arguments.
2040
+ if (type(options) === 'function') {
2041
+ callback = options;
2042
+ options = undefined;
2043
+ }
2044
+ if (type(traits) === 'function') {
2045
+ callback = traits;
2046
+ traits = undefined;
2047
+ }
2048
+ if (type(userId) === 'object') {
2049
+ if (traits && type(traits) === 'function') callback = traits;
2050
+ traits = userId;
2051
+ userId = undefined;
2052
+ }
2053
+
2054
+ // Use our cookied ID if they didn't provide one.
2055
+ if (userId === undefined || user === null) userId = user.id();
2056
+
2057
+ // Update the cookie with the new userId and traits.
2058
+ var alias = user.update(userId, traits);
2059
+
2060
+ // Clone `traits` before we manipulate it, so we don't do anything uncouth
2061
+ // and take the user.traits() so anonymous users carry over traits.
2062
+ traits = cleanTraits(userId, clone(user.traits()));
2063
+
2064
+ // Call `identify` on all of our enabled providers that support it.
2065
+ each(this.providers, function (provider) {
2066
+ if (provider.identify && isEnabled(provider, options)) {
2067
+ var args = [userId, clone(traits), clone(options)];
2068
+ if (provider.ready) {
2069
+ provider.identify.apply(provider, args);
2070
+ } else {
2071
+ provider.enqueue('identify', args);
2072
+ }
2073
+ }
2074
+ });
2075
+
2076
+ // If we should alias, go ahead and do it.
2077
+ // if (alias) this.alias(userId);
2078
+
2079
+ if (callback && type(callback) === 'function') {
2080
+ setTimeout(callback, this.timeout);
2081
+ }
2082
+ },
2083
+
2084
+
2085
+
2086
+ /**
2087
+ * Group
2088
+ *
2089
+ * Groups multiple users together under one "account" or "team" or "company".
2090
+ * Acts on the currently identified user, so you need to call identify before
2091
+ * calling group. For example:
2092
+ *
2093
+ * analytics.identify('4d3ed089fb60ab534684b7e0', {
2094
+ * name : 'Achilles',
2095
+ * email : 'achilles@segment.io',
2096
+ * age : 23
2097
+ * });
2098
+ *
2099
+ * analytics.group('5we93je3889fb60a937dk033', {
2100
+ * name : 'Acme Co.',
2101
+ * numberOfEmployees : 42,
2102
+ * location : 'San Francisco'
2103
+ * });
2104
+ *
2105
+ * @param {String} groupId - The ID you recognize the group by.
2106
+ *
2107
+ * @param {Object} properties (optional) - A dictionary of properties you know
2108
+ * about the group. Things like `numberOfEmployees`, `location`, etc.
2109
+ *
2110
+ * @param {Object} options (optional) - Settings for the group call.
2111
+ *
2112
+ * @param {Function} callback (optional) - A function to call after a small
2113
+ * timeout, giving the group call time to make requests.
2114
+ */
2115
+
2116
+ group : function (groupId, properties, options, callback) {
2117
+ if (!this.initialized) return;
2118
+
2119
+ // Allow for optional arguments.
2120
+ if (type(options) === 'function') {
2121
+ callback = options;
2122
+ options = undefined;
2123
+ }
2124
+ if (type(properties) === 'function') {
2125
+ callback = properties;
2126
+ properties = undefined;
2127
+ }
2128
+
2129
+ // Clone `properties` before we manipulate it, so we don't do anything bad,
2130
+ // and back it by an empty object so that providers can assume it exists.
2131
+ properties = clone(properties) || {};
2132
+
2133
+ // Convert dates from more types of input into Date objects.
2134
+ if (properties.created) properties.created = newDate(properties.created);
2135
+
2136
+ // Call `group` on all of our enabled providers that support it.
2137
+ each(this.providers, function (provider) {
2138
+ if (provider.group && isEnabled(provider, options)) {
2139
+ var args = [groupId, clone(properties), clone(options)];
2140
+ if (provider.ready) {
2141
+ provider.group.apply(provider, args);
2142
+ } else {
2143
+ provider.enqueue('group', args);
2144
+ }
2145
+ }
2146
+ });
2147
+
2148
+ // If we have a callback, call it after a small timeout.
2149
+ if (callback && type(callback) === 'function') {
2150
+ setTimeout(callback, this.timeout);
2151
+ }
2152
+ },
2153
+
2154
+
2155
+ /**
2156
+ * Track
2157
+ *
2158
+ * Record an event (or action) that your user has triggered. For example:
2159
+ *
2160
+ * analytics.track('Added a Friend', {
2161
+ * level : 'hard',
2162
+ * volume : 11
2163
+ * });
2164
+ *
2165
+ * @param {String} event - The name of your event.
2166
+ *
2167
+ * @param {Object} properties (optional) - A dictionary of properties of the
2168
+ * event. `properties` are all camelCase (we'll automatically conver them to
2169
+ * the proper case each provider needs).
2170
+ *
2171
+ * @param {Object} options (optional) - Settings for the track call.
2172
+ *
2173
+ * @param {Function} callback - A function to call after a small
2174
+ * timeout, giving the identify time to make requests.
2175
+ */
2176
+
2177
+ track : function (event, properties, options, callback) {
2178
+ if (!this.initialized) return;
2179
+
2180
+ // Allow for optional arguments.
2181
+ if (type(options) === 'function') {
2182
+ callback = options;
2183
+ options = undefined;
2184
+ }
2185
+ if (type(properties) === 'function') {
2186
+ callback = properties;
2187
+ properties = undefined;
2188
+ }
2189
+
2190
+ // Call `track` on all of our enabled providers that support it.
2191
+ each(this.providers, function (provider) {
2192
+ if (provider.track && isEnabled(provider, options)) {
2193
+ var args = [event, clone(properties), clone(options)];
2194
+ if (provider.ready) {
2195
+ provider.track.apply(provider, args);
2196
+ } else {
2197
+ provider.enqueue('track', args);
2198
+ }
2199
+ }
2200
+ });
2201
+
2202
+ if (callback && type(callback) === 'function') {
2203
+ setTimeout(callback, this.timeout);
2204
+ }
2205
+ },
2206
+
2207
+
2208
+ /**
2209
+ * Track Link
2210
+ *
2211
+ * A helper for tracking outbound links that would normally navigate away from
2212
+ * the page before the track requests were made. It works by wrapping the
2213
+ * calls in a short timeout, giving the requests time to fire.
2214
+ *
2215
+ * @param {Element|Array} links - The link element or array of link elements
2216
+ * to bind to. (Allowing arrays makes it easy to pass in jQuery objects.)
2217
+ *
2218
+ * @param {String|Function} event - Passed directly to `track`. Or in the case
2219
+ * that it's a function, it will be called with the link element as the first
2220
+ * argument.
2221
+ *
2222
+ * @param {Object|Function} properties (optional) - Passed directly to
2223
+ * `track`. Or in the case that it's a function, it will be called with the
2224
+ * link element as the first argument.
2225
+ */
2226
+
2227
+ trackLink : function (links, event, properties) {
2228
+ if (!links) return;
2229
+
2230
+ // Turn a single link into an array so that we're always handling
2231
+ // arrays, which allows for passing jQuery objects.
2232
+ if ('element' === type(links)) links = [links];
2233
+
2234
+ var self = this
2235
+ , eventFunction = 'function' === type(event)
2236
+ , propertiesFunction = 'function' === type(properties);
2237
+
2238
+ each(links, function (el) {
2239
+ bind(el, 'click', function (e) {
2240
+
2241
+ // Allow for `event` or `properties` to be a function. And pass it the
2242
+ // link element that was clicked.
2243
+ var newEvent = eventFunction ? event(el) : event;
2244
+ var newProperties = propertiesFunction ? properties(el) : properties;
2245
+
2246
+ self.track(newEvent, newProperties);
2247
+
2248
+ // To justify us preventing the default behavior we must:
2249
+ //
2250
+ // * Have an `href` to use.
2251
+ // * Not have a `target="_blank"` attribute.
2252
+ // * Not have any special keys pressed, because they might be trying to
2253
+ // open in a new tab, or window, or download.
2254
+ //
2255
+ // This might not cover all cases, but we'd rather throw out an event
2256
+ // than miss a case that breaks the user experience.
2257
+ if (el.href && el.target !== '_blank' && !isMeta(e)) {
2258
+
2259
+ preventDefault(e);
2260
+
2261
+ // Navigate to the url after just enough of a timeout.
2262
+ setTimeout(function () {
2263
+ window.location.href = el.href;
2264
+ }, self.timeout);
2265
+ }
2266
+ });
2267
+ });
2268
+ },
2269
+
2270
+
2271
+ /**
2272
+ * Track Form
2273
+ *
2274
+ * Similar to `trackClick`, this is a helper for tracking form submissions
2275
+ * that would normally navigate away from the page before a track request can
2276
+ * be sent. It works by preventing the default submit event, sending our
2277
+ * track requests, and then submitting the form programmatically.
2278
+ *
2279
+ * @param {Element|Array} forms - The form element or array of form elements
2280
+ * to bind to. (Allowing arrays makes it easy to pass in jQuery objects.)
2281
+ *
2282
+ * @param {String|Function} event - Passed directly to `track`. Or in the case
2283
+ * that it's a function, it will be called with the form element as the first
2284
+ * argument.
2285
+ *
2286
+ * @param {Object|Function} properties (optional) - Passed directly to
2287
+ * `track`. Or in the case that it's a function, it will be called with the
2288
+ * form element as the first argument.
2289
+ */
2290
+
2291
+ trackForm : function (form, event, properties) {
2292
+ if (!form) return;
2293
+
2294
+ // Turn a single element into an array so that we're always handling arrays,
2295
+ // which allows for passing jQuery objects.
2296
+ if ('element' === type(form)) form = [form];
2297
+
2298
+ var self = this
2299
+ , eventFunction = 'function' === type(event)
2300
+ , propertiesFunction = 'function' === type(properties);
2301
+
2302
+ each(form, function (el) {
2303
+ var handler = function (e) {
2304
+
2305
+ // Allow for `event` or `properties` to be a function. And pass it the
2306
+ // form element that was submitted.
2307
+ var newEvent = eventFunction ? event(el) : event;
2308
+ var newProperties = propertiesFunction ? properties(el) : properties;
2309
+
2310
+ self.track(newEvent, newProperties);
2311
+
2312
+ preventDefault(e);
2313
+
2314
+ // Submit the form after a timeout, giving the event time to fire.
2315
+ setTimeout(function () {
2316
+ el.submit();
2317
+ }, self.timeout);
2318
+ };
2319
+
2320
+ // Support the form being submitted via jQuery instead of for real. This
2321
+ // doesn't happen automatically because `el.submit()` doesn't actually
2322
+ // fire submit handlers, which is what jQuery uses internally. >_<
2323
+ var dom = window.jQuery || window.Zepto;
2324
+ if (dom) {
2325
+ dom(el).submit(handler);
2326
+ } else {
2327
+ bind(el, 'submit', handler);
2328
+ }
2329
+ });
2330
+ },
2331
+
2332
+
2333
+ /**
2334
+ * Pageview
2335
+ *
2336
+ * Simulate a pageview in single-page applications, where real pageviews don't
2337
+ * occur. This isn't support by all providers.
2338
+ *
2339
+ * @param {String} url (optional) - The path of the page (eg. '/login'). Most
2340
+ * providers will default to the current pages URL, so you don't need this.
2341
+ *
2342
+ * @param {Object} options (optional) - Settings for the pageview call.
2343
+ *
2344
+ */
2345
+
2346
+ pageview : function (url,options) {
2347
+ if (!this.initialized) return;
2348
+
2349
+ // Call `pageview` on all of our enabled providers that support it.
2350
+ each(this.providers, function (provider) {
2351
+ if (provider.pageview && isEnabled(provider, options)) {
2352
+ var args = [url];
2353
+ if (provider.ready) {
2354
+ provider.pageview.apply(provider, args);
2355
+ } else {
2356
+ provider.enqueue('pageview', args);
2357
+ }
2358
+ }
2359
+ });
2360
+ },
2361
+
2362
+
2363
+ /**
2364
+ * Alias
2365
+ *
2366
+ * Merges two previously unassociate user identities. This comes in handy if
2367
+ * the same user visits from two different devices and you want to combine
2368
+ * their analytics history.
2369
+ *
2370
+ * Some providers don't support merging users.
2371
+ *
2372
+ * @param {String} newId - The new ID you want to recognize the user by.
2373
+ *
2374
+ * @param {String} originalId (optional) - The original ID that the user was
2375
+ * recognized by. This defaults to the current identified user's ID if there
2376
+ * is one. In most cases you don't need to pass in the `originalId`.
2377
+ */
2378
+
2379
+ alias : function (newId, originalId, options) {
2380
+ if (!this.initialized) return;
2381
+
2382
+ if (type(originalId) === 'object') {
2383
+ options = originalId;
2384
+ originalId = undefined;
2385
+ }
2386
+
2387
+ // Call `alias` on all of our enabled providers that support it.
2388
+ each(this.providers, function (provider) {
2389
+ if (provider.alias && isEnabled(provider, options)) {
2390
+ var args = [newId, originalId];
2391
+ if (provider.ready) {
2392
+ provider.alias.apply(provider, args);
2393
+ } else {
2394
+ provider.enqueue('alias', args);
2395
+ }
2396
+ }
2397
+ });
2398
+ },
2399
+
2400
+
2401
+ /**
2402
+ * Log
2403
+ *
2404
+ * Log an error to analytics providers that support it, like Sentry.
2405
+ *
2406
+ * @param {Error|String} error - The error or string to log.
2407
+ * @param {Object} properties - Properties about the error.
2408
+ * @param {Object} options (optional) - Settings for the log call.
2409
+ */
2410
+
2411
+ log : function (error, properties, options) {
2412
+ if (!this.initialized) return;
2413
+
2414
+ each(this.providers, function (provider) {
2415
+ if (provider.log && isEnabled(provider, options)) {
2416
+ var args = [error, properties, options];
2417
+ if (provider.ready) {
2418
+ provider.log.apply(provider, args);
2419
+ } else {
2420
+ provider.enqueue('log', args);
2421
+ }
2422
+ }
2423
+ });
2424
+ }
2425
+
2426
+ });
2427
+
2428
+
2429
+ /**
2430
+ * Backwards compatibility.
2431
+ */
2432
+
2433
+ // Alias `trackClick` and `trackSubmit`.
2434
+ Analytics.prototype.trackClick = Analytics.prototype.trackLink;
2435
+ Analytics.prototype.trackSubmit = Analytics.prototype.trackForm;
2436
+
2437
+
2438
+ /**
2439
+ * Determine whether a provider is enabled or not based on the options object.
2440
+ *
2441
+ * @param {Object} provider - the current provider.
2442
+ * @param {Object} options - the current call's options.
2443
+ *
2444
+ * @return {Boolean} - wether the provider is enabled.
2445
+ */
2446
+
2447
+ var isEnabled = function (provider, options) {
2448
+ var enabled = true;
2449
+ if (!options || !options.providers) return enabled;
2450
+
2451
+ // Default to the 'all' or 'All' setting.
2452
+ var map = options.providers;
2453
+ if (map.all !== undefined) enabled = map.all;
2454
+ if (map.All !== undefined) enabled = map.All;
2455
+
2456
+ // Look for this provider's specific setting.
2457
+ var name = provider.name;
2458
+ if (map[name] !== undefined) enabled = map[name];
2459
+
2460
+ return enabled;
2461
+ };
2462
+
2463
+
2464
+ /**
2465
+ * Clean up traits, default some useful things both so the user doesn't have to
2466
+ * and so we don't have to do it on a provider-basis.
2467
+ *
2468
+ * @param {Object} traits The traits object.
2469
+ * @return {Object} The new traits object.
2470
+ */
2471
+
2472
+ var cleanTraits = function (userId, traits) {
2473
+
2474
+ // Add the `email` trait if it doesn't exist and the `userId` is an email.
2475
+ if (!traits.email && isEmail(userId)) traits.email = userId;
2476
+
2477
+ // Create the `name` trait if it doesn't exist and `firstName` and `lastName`
2478
+ // are both supplied.
2479
+ if (!traits.name && traits.firstName && traits.lastName) {
2480
+ traits.name = traits.firstName + ' ' + traits.lastName;
2481
+ }
2482
+
2483
+ // Convert dates from more types of input into Date objects.
2484
+ if (traits.created) traits.created = newDate(traits.created);
2485
+ if (traits.company && traits.company.created) {
2486
+ traits.company.created = newDate(traits.company.created);
2487
+ }
2488
+
2489
+ return traits;
2490
+ };
2491
+
2492
+ });
2493
+ require.register("analytics/src/cookie.js", function(exports, require, module){
2494
+
2495
+ var bindAll = require('bind-all')
2496
+ , cookie = require('cookie')
2497
+ , clone = require('clone')
2498
+ , defaults = require('defaults')
2499
+ , json = require('json')
2500
+ , topDomain = require('top-domain');
2501
+
2502
+
2503
+ function Cookie (options) {
2504
+ this.options(options);
2505
+ }
2506
+
2507
+ /**
2508
+ * Get or set the cookie options
2509
+ *
2510
+ * @param {Object} options
2511
+ * @field {Number} maxage (1 year)
2512
+ * @field {String} domain
2513
+ * @field {String} path
2514
+ * @field {Boolean} secure
2515
+ */
2516
+
2517
+ Cookie.prototype.options = function (options) {
2518
+ if (arguments.length === 0) return this._options;
2519
+
2520
+ options || (options = {});
2521
+
2522
+ var domain = '.' + topDomain(window.location.href);
2523
+
2524
+ // localhost cookies are special: http://curl.haxx.se/rfc/cookie_spec.html
2525
+ if (domain === '.localhost') domain = '';
2526
+
2527
+ defaults(options, {
2528
+ maxage : 31536000000, // default to a year
2529
+ path : '/',
2530
+ domain : domain
2531
+ });
2532
+
2533
+ this._options = options;
2534
+ };
2535
+
2536
+
2537
+ /**
2538
+ * Set a value in our cookie
2539
+ *
2540
+ * @param {String} key
2541
+ * @param {Object} value
2542
+ * @return {Boolean} saved
2543
+ */
2544
+
2545
+ Cookie.prototype.set = function (key, value) {
2546
+ try {
2547
+ value = json.stringify(value);
2548
+ cookie(key, value, clone(this._options));
2549
+ return true;
2550
+ } catch (e) {
2551
+ return false;
2552
+ }
2553
+ };
2554
+
2555
+
2556
+ /**
2557
+ * Get a value from our cookie
2558
+ * @param {String} key
2559
+ * @return {Object} value
2560
+ */
2561
+
2562
+ Cookie.prototype.get = function (key) {
2563
+ try {
2564
+ var value = cookie(key);
2565
+ value = value ? json.parse(value) : null;
2566
+ return value;
2567
+ } catch (e) {
2568
+ return null;
2569
+ }
2570
+ };
2571
+
2572
+
2573
+ /**
2574
+ * Remove a value from the cookie
2575
+ *
2576
+ * @param {String} key
2577
+ * @return {Boolean} removed
2578
+ */
2579
+
2580
+ Cookie.prototype.remove = function (key) {
2581
+ try {
2582
+ cookie(key, null, clone(this._options));
2583
+ return true;
2584
+ } catch (e) {
2585
+ return false;
2586
+ }
2587
+ };
2588
+
2589
+
2590
+ /**
2591
+ * Export singleton cookie
2592
+ */
2593
+
2594
+ module.exports = bindAll(new Cookie());
2595
+
2596
+
2597
+ module.exports.Cookie = Cookie;
2598
+
2599
+ });
2600
+ require.register("analytics/src/localStore.js", function(exports, require, module){
2601
+
2602
+ var bindAll = require('bind-all')
2603
+ , defaults = require('defaults')
2604
+ , store = require('store');
2605
+
2606
+
2607
+ function Store (options) {
2608
+ this.options(options);
2609
+ }
2610
+
2611
+
2612
+ /**
2613
+ * Sets the options for the store
2614
+ *
2615
+ * @param {Object} options
2616
+ * @field {Boolean} enabled (true)
2617
+ */
2618
+
2619
+ Store.prototype.options = function (options) {
2620
+ if (arguments.length === 0) return this._options;
2621
+
2622
+ options || (options = {});
2623
+ defaults(options, { enabled : true });
2624
+
2625
+ this.enabled = options.enabled && store.enabled;
2626
+ this._options = options;
2627
+ };
2628
+
2629
+
2630
+ /**
2631
+ * Sets a value in local storage
2632
+ *
2633
+ * @param {String} key
2634
+ * @param {Object} value
2635
+ */
2636
+
2637
+ Store.prototype.set = function (key, value) {
2638
+ if (!this.enabled) return false;
2639
+ return store.set(key, value);
2640
+ };
2641
+
2642
+
2643
+ /**
2644
+ * Gets a value from local storage
2645
+ *
2646
+ * @param {String} key
2647
+ * @return {Object}
2648
+ */
2649
+
2650
+ Store.prototype.get = function (key) {
2651
+ if (!this.enabled) return null;
2652
+ return store.get(key);
2653
+ };
2654
+
2655
+
2656
+ /**
2657
+ * Removes a value from local storage
2658
+ *
2659
+ * @param {String} key
2660
+ */
2661
+
2662
+ Store.prototype.remove = function (key) {
2663
+ if (!this.enabled) return false;
2664
+ return store.remove(key);
2665
+ };
2666
+
2667
+
2668
+ /**
2669
+ * Singleton exports
2670
+ */
2671
+
2672
+ module.exports = bindAll(new Store());
2673
+ });
2674
+ require.register("analytics/src/provider.js", function(exports, require, module){
2675
+ var each = require('each')
2676
+ , extend = require('extend')
2677
+ , type = require('type');
2678
+
2679
+
2680
+ module.exports = Provider;
2681
+
2682
+
2683
+ /**
2684
+ * Provider
2685
+ *
2686
+ * @param {Object} options - settings to initialize the Provider with. This will
2687
+ * be merged with the Provider's own defaults.
2688
+ *
2689
+ * @param {Function} ready - a ready callback, to be called when the provider is
2690
+ * ready to handle analytics calls.
2691
+ */
2692
+
2693
+ function Provider (options, ready, analytics) {
2694
+ var self = this;
2695
+
2696
+ // Store the reference to the global `analytics` object.
2697
+ this.analytics = analytics;
2698
+
2699
+ // Make a queue of `{ method : 'identify', args : [] }` to unload once ready.
2700
+ this.queue = [];
2701
+ this.ready = false;
2702
+
2703
+ // Allow for `options` to only be a string if the provider has specified
2704
+ // a default `key`, in which case convert `options` into a dictionary. Also
2705
+ // allow for it to be `true`, like in Optimizely's case where there is no need
2706
+ // for any default key.
2707
+ if (type(options) !== 'object') {
2708
+ if (options === true) {
2709
+ options = {};
2710
+ } else if (this.key) {
2711
+ var key = options;
2712
+ options = {};
2713
+ options[this.key] = key;
2714
+ } else {
2715
+ throw new Error('Couldnt resolve options.');
2716
+ }
2717
+ }
2718
+
2719
+ // Extend the passed-in options with our defaults.
2720
+ this.options = extend({}, this.defaults, options);
2721
+
2722
+ // Wrap our ready function, so that it ready from our internal queue first
2723
+ // and then marks us as ready.
2724
+ var dequeue = function () {
2725
+ each(self.queue, function (call) {
2726
+ var method = call.method
2727
+ , args = call.args;
2728
+ self[method].apply(self, args);
2729
+ });
2730
+ self.ready = true;
2731
+ self.queue = [];
2732
+ ready();
2733
+ };
2734
+
2735
+ // Call our initialize method.
2736
+ this.initialize.call(this, this.options, dequeue);
2737
+ }
2738
+
2739
+
2740
+ /**
2741
+ * Inheritance helper.
2742
+ *
2743
+ * Modeled after Backbone's `extend` method:
2744
+ * https://github.com/documentcloud/backbone/blob/master/backbone.js#L1464
2745
+ */
2746
+
2747
+ Provider.extend = function (properties) {
2748
+ var parent = this;
2749
+ var child = function () { return parent.apply(this, arguments); };
2750
+ var Surrogate = function () { this.constructor = child; };
2751
+ Surrogate.prototype = parent.prototype;
2752
+ child.prototype = new Surrogate();
2753
+ extend(child.prototype, properties);
2754
+ return child;
2755
+ };
2756
+
2757
+
2758
+ /**
2759
+ * Augment Provider's prototype.
2760
+ */
2761
+
2762
+ extend(Provider.prototype, {
2763
+
2764
+ /**
2765
+ * Default settings for the provider.
2766
+ */
2767
+
2768
+ options : {},
2769
+
2770
+
2771
+ /**
2772
+ * The single required API key for the provider. This lets us support a terse
2773
+ * initialization syntax:
2774
+ *
2775
+ * analytics.initialize({
2776
+ * 'Provider' : 'XXXXXXX'
2777
+ * });
2778
+ *
2779
+ * Only add this if the provider has a _single_ required key.
2780
+ */
2781
+
2782
+ key : undefined,
2783
+
2784
+
2785
+ /**
2786
+ * Initialize our provider.
2787
+ *
2788
+ * @param {Object} options - the settings for the provider.
2789
+ * @param {Function} ready - a ready callback to call when we're ready to
2790
+ * start accept analytics method calls.
2791
+ */
2792
+ initialize : function (options, ready) {
2793
+ ready();
2794
+ },
2795
+
2796
+
2797
+ /**
2798
+ * Adds an item to the our internal pre-ready queue.
2799
+ *
2800
+ * @param {String} method - the analytics method to call (eg. 'track').
2801
+ * @param {Object} args - the arguments to pass to the method.
2802
+ */
2803
+ enqueue : function (method, args) {
2804
+ this.queue.push({
2805
+ method : method,
2806
+ args : args
2807
+ });
2808
+ }
2809
+
2810
+ });
2811
+ });
2812
+ require.register("analytics/src/user.js", function(exports, require, module){
2813
+ var bindAll = require('bind-all')
2814
+ , clone = require('clone')
2815
+ , cookie = require('./cookie')
2816
+ , defaults = require('defaults')
2817
+ , extend = require('extend')
2818
+ , localStore = require('./localStore');
2819
+
2820
+
2821
+ function User (options) {
2822
+ this._id = null;
2823
+ this._traits = {};
2824
+ this.options(options);
2825
+ }
2826
+
2827
+
2828
+ /**
2829
+ * Sets the options for the user
2830
+ *
2831
+ * @param {Object} options
2832
+ * @field {Object} cookie
2833
+ * @field {Object} localStorage
2834
+ * @field {Boolean} persist (true)
2835
+ */
2836
+
2837
+ User.prototype.options = function (options) {
2838
+ options || (options = {});
2839
+
2840
+ defaults(options, {
2841
+ persist : true
2842
+ });
2843
+
2844
+ this.cookie(options.cookie);
2845
+ this.localStorage(options.localStorage);
2846
+ this.persist = options.persist;
2847
+ };
2848
+
2849
+
2850
+ /**
2851
+ * Get or set cookie options
2852
+ *
2853
+ * @param {Object} options
2854
+ */
2855
+
2856
+ User.prototype.cookie = function (options) {
2857
+ if (arguments.length === 0) return this.cookieOptions;
2858
+
2859
+ options || (options = {});
2860
+ defaults(options, {
2861
+ key : 'ajs_user_id',
2862
+ oldKey : 'ajs_user'
2863
+ });
2864
+ this.cookieOptions = options;
2865
+ };
2866
+
2867
+
2868
+ /**
2869
+ * Get or set local storage options
2870
+ *
2871
+ * @param {Object} options
2872
+ */
2873
+
2874
+ User.prototype.localStorage = function (options) {
2875
+ if (arguments.length === 0) return this.localStorageOptions;
2876
+
2877
+ options || (options = {});
2878
+ defaults(options, {
2879
+ key : 'ajs_user_traits'
2880
+ });
2881
+ this.localStorageOptions = options;
2882
+ };
2883
+
2884
+
2885
+ /**
2886
+ * Get or set the user id
2887
+ *
2888
+ * @param {String} id
2889
+ */
2890
+
2891
+ User.prototype.id = function (id) {
2892
+ if (arguments.length === 0) return this._id;
2893
+ this._id = id;
2894
+ };
2895
+
2896
+
2897
+ /**
2898
+ * Get or set the user traits
2899
+ *
2900
+ * @param {Object} traits
2901
+ */
2902
+
2903
+ User.prototype.traits = function (traits) {
2904
+ if (arguments.length === 0) return clone(this._traits);
2905
+ traits || (traits = {});
2906
+
2907
+ this._traits = traits;
2908
+ };
2909
+
2910
+
2911
+ /**
2912
+ * Updates the current stored user with id and traits.
2913
+ *
2914
+ * @param {String} userId - the new user ID.
2915
+ * @param {Object} traits - any new traits.
2916
+ * @return {Boolean} whether alias should be called.
2917
+ */
2918
+
2919
+ User.prototype.update = function (userId, traits) {
2920
+
2921
+ // Make an alias call if there was no previous userId, there is one
2922
+ // now, and we are using a cookie between page loads.
2923
+ var alias = !this.id() && userId && this.persist;
2924
+
2925
+ traits || (traits = {});
2926
+
2927
+ // If there is a current user and the new user isn't the same,
2928
+ // we want to just replace their traits. Otherwise extend.
2929
+ if (this.id() && userId && this.id() !== userId) this.traits(traits);
2930
+ else this.traits(extend(this.traits(), traits));
2931
+
2932
+ if (userId) this.id(userId);
2933
+
2934
+ this.save();
2935
+
2936
+ return alias;
2937
+ };
2938
+
2939
+
2940
+ /**
2941
+ * Save the user to localstorage and cookie
2942
+ *
2943
+ * @return {Boolean} saved
2944
+ */
2945
+
2946
+ User.prototype.save = function () {
2947
+ if (!this.persist) return false;
2948
+
2949
+ cookie.set(this.cookie().key, this.id());
2950
+ localStore.set(this.localStorage().key, this.traits());
2951
+ return true;
2952
+ };
2953
+
2954
+
2955
+ /**
2956
+ * Loads a saved user, and set its information
2957
+ *
2958
+ * @return {Object} user
2959
+ */
2960
+
2961
+ User.prototype.load = function () {
2962
+ if (this.loadOldCookie()) return this.toJSON();
2963
+
2964
+ var id = cookie.get(this.cookie().key)
2965
+ , traits = localStore.get(this.localStorage().key);
2966
+
2967
+ this.id(id);
2968
+ this.traits(traits);
2969
+ return this.toJSON();
2970
+ };
2971
+
2972
+
2973
+ /**
2974
+ * Clears the user, and removes the stored version
2975
+ *
2976
+ */
2977
+
2978
+ User.prototype.clear = function () {
2979
+ cookie.remove(this.cookie().key);
2980
+ localStore.remove(this.localStorage().key);
2981
+ this.id(null);
2982
+ this.traits({});
2983
+ };
2984
+
2985
+
2986
+ /**
2987
+ * Load the old user from the cookie. Should be phased
2988
+ * out at some point
2989
+ *
2990
+ * @return {Boolean} loaded
2991
+ */
2992
+
2993
+ User.prototype.loadOldCookie = function () {
2994
+ var user = cookie.get(this.cookie().oldKey);
2995
+ if (!user) return false;
2996
+
2997
+ this.id(user.id);
2998
+ this.traits(user.traits);
2999
+ cookie.remove(this.cookie().oldKey);
3000
+ return true;
3001
+ };
3002
+
3003
+
3004
+ /**
3005
+ * Get the user info
3006
+ *
3007
+ * @return {Object}
3008
+ */
3009
+
3010
+ User.prototype.toJSON = function () {
3011
+ return {
3012
+ id : this.id(),
3013
+ traits : this.traits()
3014
+ };
3015
+ };
3016
+
3017
+
3018
+ /**
3019
+ * Export the new user as a singleton.
3020
+ */
3021
+
3022
+ module.exports = bindAll(new User());
3023
+
3024
+ });
3025
+ require.register("analytics/src/utils.js", function(exports, require, module){
3026
+ // A helper to track events based on the 'anjs' url parameter
3027
+ exports.getUrlParameter = function (urlSearchParameter, paramKey) {
3028
+ var params = urlSearchParameter.replace('?', '').split('&');
3029
+ for (var i = 0; i < params.length; i += 1) {
3030
+ var param = params[i].split('=');
3031
+ if (param.length === 2 && param[0] === paramKey) {
3032
+ return decodeURIComponent(param[1]);
3033
+ }
3034
+ }
3035
+ };
3036
+ });
3037
+ require.register("analytics/src/providers/adroll.js", function(exports, require, module){
3038
+ // https://www.adroll.com/dashboard
3039
+
3040
+ var Provider = require('../provider')
3041
+ , load = require('load-script');
3042
+
3043
+
3044
+ module.exports = Provider.extend({
3045
+
3046
+ name : 'AdRoll',
3047
+
3048
+ defaults : {
3049
+ // Adroll requires two options: `advId` and `pixId`.
3050
+ advId : null,
3051
+ pixId : null
3052
+ },
3053
+
3054
+ initialize : function (options, ready) {
3055
+ window.adroll_adv_id = options.advId;
3056
+ window.adroll_pix_id = options.pixId;
3057
+ window.__adroll_loaded = true;
3058
+
3059
+ load({
3060
+ http : 'http://a.adroll.com/j/roundtrip.js',
3061
+ https : 'https://s.adroll.com/j/roundtrip.js'
3062
+ }, ready);
3063
+ }
3064
+
3065
+ });
3066
+ });
3067
+ require.register("analytics/src/providers/amplitude.js", function(exports, require, module){
3068
+ // https://github.com/amplitude/Amplitude-Javascript
3069
+
3070
+ var Provider = require('../provider')
3071
+ , alias = require('alias')
3072
+ , load = require('load-script');
3073
+
3074
+
3075
+ module.exports = Provider.extend({
3076
+
3077
+ name : 'Amplitude',
3078
+
3079
+ key : 'apiKey',
3080
+
3081
+ defaults : {
3082
+ // Amplitude's required API key.
3083
+ apiKey : null,
3084
+ // Whether to track pageviews to Amplitude.
3085
+ pageview : false
3086
+ },
3087
+
3088
+ initialize : function (options, ready) {
3089
+ // Create the Amplitude global and queuer methods.
3090
+ (function(e,t){var r=e.amplitude||{};
3091
+ r._q=[];function i(e){r[e]=function(){r._q.push([e].concat(Array.prototype.slice.call(arguments,0)))}}
3092
+ var s=["init","logEvent","setUserId","setGlobalUserProperties","setVersionName"];
3093
+ for(var c=0;c<s.length;c++){i(s[c])}e.amplitude=r})(window,document);
3094
+
3095
+ // Load the Amplitude script and initialize with the API key.
3096
+ load('https://d24n15hnbwhuhn.cloudfront.net/libs/amplitude-1.0-min.js');
3097
+ window.amplitude.init(options.apiKey);
3098
+
3099
+ // Amplitude creates a queue, so it's ready immediately.
3100
+ ready();
3101
+ },
3102
+
3103
+ identify : function (userId, traits) {
3104
+ if (userId) window.amplitude.setUserId(userId);
3105
+ if (traits) window.amplitude.setGlobalUserProperties(traits);
3106
+ },
3107
+
3108
+ track : function (event, properties) {
3109
+ window.amplitude.logEvent(event, properties);
3110
+ },
3111
+
3112
+ pageview : function (url) {
3113
+ if (!this.options.pageview) return;
3114
+
3115
+ var properties = {
3116
+ url : url || document.location.href,
3117
+ name : document.title
3118
+ };
3119
+
3120
+ this.track('Loaded a Page', properties);
3121
+ }
3122
+
3123
+ });
3124
+ });
3125
+ require.register("analytics/src/providers/bitdeli.js", function(exports, require, module){
3126
+ // https://bitdeli.com/docs
3127
+ // https://bitdeli.com/docs/javascript-api.html
3128
+
3129
+ var Provider = require('../provider')
3130
+ , load = require('load-script');
3131
+
3132
+
3133
+ module.exports = Provider.extend({
3134
+
3135
+ name : 'Bitdeli',
3136
+
3137
+ defaults : {
3138
+ // BitDeli requires two options: `inputId` and `authToken`.
3139
+ inputId : null,
3140
+ authToken : null,
3141
+ // Whether or not to track an initial pageview when the page first
3142
+ // loads. You might not want this if you're using a single-page app.
3143
+ initialPageview : true
3144
+ },
3145
+
3146
+
3147
+ initialize : function (options, ready) {
3148
+ window._bdq = window._bdq || [];
3149
+ window._bdq.push(["setAccount", options.inputId, options.authToken]);
3150
+
3151
+ if (options.initialPageview) this.pageview();
3152
+
3153
+ load('//d2flrkr957qc5j.cloudfront.net/bitdeli.min.js');
3154
+
3155
+ // Bitdeli just uses a queue, so it's ready right away.
3156
+ ready();
3157
+ },
3158
+
3159
+
3160
+ // Bitdeli uses two separate methods: `identify` for storing the `userId`
3161
+ // and `set` for storing `traits`.
3162
+ identify : function (userId, traits) {
3163
+ if (userId) window._bdq.push(['identify', userId]);
3164
+ if (traits) window._bdq.push(['set', traits]);
3165
+ },
3166
+
3167
+
3168
+ track : function (event, properties) {
3169
+ window._bdq.push(['track', event, properties]);
3170
+ },
3171
+
3172
+
3173
+ // If `url` is undefined, Bitdeli uses the current page URL instead.
3174
+ pageview : function (url) {
3175
+ window._bdq.push(['trackPageview', url]);
3176
+ }
3177
+
3178
+ });
3179
+ });
3180
+ require.register("analytics/src/providers/bugherd.js", function(exports, require, module){
3181
+ // http://support.bugherd.com/home
3182
+
3183
+ var Provider = require('../provider')
3184
+ , load = require('load-script');
3185
+
3186
+
3187
+ module.exports = Provider.extend({
3188
+
3189
+ name : 'BugHerd',
3190
+
3191
+ key : 'apiKey',
3192
+
3193
+ defaults : {
3194
+ apiKey : null,
3195
+ // Optionally hide the feedback tab if you want to build your own.
3196
+ // http://support.bugherd.com/entries/21497629-Create-your-own-Send-Feedback-tab
3197
+ showFeedbackTab : true
3198
+ },
3199
+
3200
+ initialize : function (options, ready) {
3201
+ if (!options.showFeedbackTab) {
3202
+ window.BugHerdConfig = { "feedback" : { "hide" : true } };
3203
+ }
3204
+ load('//www.bugherd.com/sidebarv2.js?apikey=' + options.apiKey, ready);
3205
+ }
3206
+
3207
+ });
3208
+ });
3209
+ require.register("analytics/src/providers/chartbeat.js", function(exports, require, module){
3210
+ // http://chartbeat.com/docs/adding_the_code/
3211
+ // http://chartbeat.com/docs/configuration_variables/
3212
+ // http://chartbeat.com/docs/handling_virtual_page_changes/
3213
+
3214
+ var Provider = require('../provider')
3215
+ , load = require('load-script');
3216
+
3217
+
3218
+ module.exports = Provider.extend({
3219
+
3220
+ name : 'Chartbeat',
3221
+
3222
+ defaults : {
3223
+ // Chartbeat requires two options: `domain` and `uid`. All other
3224
+ // configuration options are passed straight in!
3225
+ domain : null,
3226
+ uid : null
3227
+ },
3228
+
3229
+
3230
+ initialize : function (options, ready) {
3231
+ // Since all the custom options just get passed through, update the
3232
+ // Chartbeat `_sf_async_config` variable with options.
3233
+ window._sf_async_config = options;
3234
+
3235
+ // Chartbeat's javascript should only load after the body
3236
+ // is available, see https://github.com/segmentio/analytics.js/issues/107
3237
+ var loadChartbeat = function () {
3238
+ // We loop until the body is available.
3239
+ if (!document.body) return setTimeout(loadChartbeat, 5);
3240
+
3241
+ // Use the stored date from when chartbeat was loaded.
3242
+ window._sf_endpt = (new Date()).getTime();
3243
+
3244
+ // Load the Chartbeat javascript.
3245
+ load({
3246
+ https : 'https://a248.e.akamai.net/chartbeat.download.akamai.com/102508/js/chartbeat.js',
3247
+ http : 'http://static.chartbeat.com/js/chartbeat.js'
3248
+ }, ready);
3249
+ };
3250
+ loadChartbeat();
3251
+ },
3252
+
3253
+
3254
+ pageview : function (url) {
3255
+ // In case the Chartbeat library hasn't loaded yet.
3256
+ if (!window.pSUPERFLY) return;
3257
+
3258
+ // Requires a path, so default to the current one.
3259
+ window.pSUPERFLY.virtualPage(url || window.location.pathname);
3260
+ }
3261
+
3262
+ });
3263
+ });
3264
+ require.register("analytics/src/providers/clicktale.js", function(exports, require, module){
3265
+ // http://wiki.clicktale.com/Article/JavaScript_API
3266
+
3267
+ var date = require('load-date')
3268
+ , Provider = require('../provider')
3269
+ , load = require('load-script')
3270
+ , onBody = require('on-body');
3271
+
3272
+ module.exports = Provider.extend({
3273
+
3274
+ name : 'ClickTale',
3275
+
3276
+ key : 'projectId',
3277
+
3278
+ defaults : {
3279
+
3280
+ // If you sign up for a free account, this is the default http (non-ssl) CDN URL
3281
+ // that you get. If you sign up for a premium account, you get a different
3282
+ // custom CDN URL, so we have to leave it as an option.
3283
+ httpCdnUrl : 'http://s.clicktale.net/WRe0.js',
3284
+
3285
+ // SSL support is only for premium accounts. Each premium account seems to have
3286
+ // a different custom secure CDN URL, so we have to leave it as an option.
3287
+ httpsCdnUrl : null,
3288
+
3289
+ // The Project ID is loaded in after the ClickTale CDN javascript has loaded.
3290
+ projectId : null,
3291
+
3292
+ // The recording ratio specifies what fraction of people to screen-record.
3293
+ // ClickTale has a special calculator in their setup flow that tells you
3294
+ // what number to set for this.
3295
+ recordingRatio : 0.01,
3296
+
3297
+ // The Partition ID determines where ClickTale stores the data according to
3298
+ // http://wiki.clicktale.com/Article/JavaScript_API
3299
+ partitionId : null
3300
+ },
3301
+
3302
+
3303
+ initialize : function (options, ready) {
3304
+ // If we're on https:// but don't have a secure library, return early.
3305
+ if (document.location.protocol === 'https:' && !options.httpsCdnUrl) return;
3306
+
3307
+ // ClickTale wants this at the "top" of the page. The analytics.js snippet
3308
+ // sets this date synchronously now, and makes it available via load-date.
3309
+ window.WRInitTime = date.getTime();
3310
+
3311
+ // Add the required ClickTale div to the body.
3312
+ onBody(function (body) {
3313
+ var div = document.createElement('div');
3314
+ div.setAttribute('id', 'ClickTaleDiv');
3315
+ div.setAttribute('style', 'display: none;');
3316
+ body.appendChild(div);
3317
+ });
3318
+
3319
+ var onloaded = function () {
3320
+ window.ClickTale(
3321
+ options.projectId,
3322
+ options.recordingRatio,
3323
+ options.partitionId
3324
+ );
3325
+ ready();
3326
+ };
3327
+
3328
+ // If no SSL library is provided and we're on SSL then we can't load
3329
+ // anything (always true for non-premium accounts).
3330
+ load({
3331
+ http : options.httpCdnUrl,
3332
+ https : options.httpsCdnUrl
3333
+ }, onloaded);
3334
+ },
3335
+
3336
+ identify : function (userId, traits) {
3337
+ // We set the userId as the ClickTale UID.
3338
+ if (window.ClickTaleSetUID) window.ClickTaleSetUID(userId);
3339
+
3340
+ // We iterate over all the traits and set them as key-value field pairs.
3341
+ if (window.ClickTaleField) {
3342
+ for (var traitKey in traits) {
3343
+ window.ClickTaleField(traitKey, traits[traitKey]);
3344
+ }
3345
+ }
3346
+ },
3347
+
3348
+ track : function (event, properties) {
3349
+ // ClickTaleEvent is an alias for ClickTaleTag
3350
+ if (window.ClickTaleEvent) window.ClickTaleEvent(event);
3351
+ }
3352
+
3353
+ });
3354
+ });
3355
+ require.register("analytics/src/providers/clicky.js", function(exports, require, module){
3356
+ // http://clicky.com/help/customization/manual?new-domain
3357
+ // http://clicky.com/help/customization/manual?new-domain#/help/customization#session
3358
+
3359
+ var Provider = require('../provider')
3360
+ , user = require('../user')
3361
+ , extend = require('extend')
3362
+ , load = require('load-script');
3363
+
3364
+
3365
+ module.exports = Provider.extend({
3366
+
3367
+ name : 'Clicky',
3368
+
3369
+ key : 'siteId',
3370
+
3371
+ defaults : {
3372
+ siteId : null
3373
+ },
3374
+
3375
+ initialize : function (options, ready) {
3376
+ window.clicky_site_ids = window.clicky_site_ids || [];
3377
+ window.clicky_site_ids.push(options.siteId);
3378
+
3379
+ var userId = user.id()
3380
+ , traits = user.traits()
3381
+ , session = {};
3382
+
3383
+ if (userId) session.id = userId;
3384
+ extend(session, traits);
3385
+
3386
+ window.clicky_custom = { session : session };
3387
+
3388
+ load('//static.getclicky.com/js', ready);
3389
+ },
3390
+
3391
+ track : function (event, properties) {
3392
+ window.clicky.log(window.location.href, event);
3393
+ }
3394
+
3395
+ });
3396
+ });
3397
+ require.register("analytics/src/providers/comscore.js", function(exports, require, module){
3398
+ // http://direct.comscore.com/clients/help/FAQ.aspx#faqTagging
3399
+
3400
+ var Provider = require('../provider')
3401
+ , load = require('load-script');
3402
+
3403
+
3404
+ module.exports = Provider.extend({
3405
+
3406
+ name : 'comScore',
3407
+
3408
+ key : 'c2',
3409
+
3410
+ defaults : {
3411
+ c1 : '2',
3412
+ c2 : null
3413
+ },
3414
+
3415
+ // Pass the entire options object directly into comScore.
3416
+ initialize : function (options, ready) {
3417
+ window._comscore = window._comscore || [];
3418
+ window._comscore.push(options);
3419
+ load({
3420
+ http : 'http://b.scorecardresearch.com/beacon.js',
3421
+ https : 'https://sb.scorecardresearch.com/beacon.js'
3422
+ }, ready);
3423
+ }
3424
+
3425
+ });
3426
+ });
3427
+ require.register("analytics/src/providers/crazyegg.js", function(exports, require, module){
3428
+ var Provider = require('../provider')
3429
+ , load = require('load-script');
3430
+
3431
+
3432
+ module.exports = Provider.extend({
3433
+
3434
+ name : 'CrazyEgg',
3435
+
3436
+ key : 'accountNumber',
3437
+
3438
+ defaults : {
3439
+ accountNumber : null
3440
+ },
3441
+
3442
+ initialize : function (options, ready) {
3443
+ var accountPath = options.accountNumber.slice(0,4) + '/' + options.accountNumber.slice(4);
3444
+ load('//dnn506yrbagrg.cloudfront.net/pages/scripts/'+accountPath+'.js?'+Math.floor(new Date().getTime()/3600000), ready);
3445
+ }
3446
+
3447
+ });
3448
+ });
3449
+ require.register("analytics/src/providers/customerio.js", function(exports, require, module){
3450
+ // http://customer.io/docs/api/javascript.html
3451
+
3452
+ var Provider = require('../provider')
3453
+ , isEmail = require('is-email')
3454
+ , load = require('load-script');
3455
+
3456
+
3457
+ module.exports = Provider.extend({
3458
+
3459
+ name : 'Customer.io',
3460
+
3461
+ key : 'siteId',
3462
+
3463
+ defaults : {
3464
+ siteId : null
3465
+ },
3466
+
3467
+ initialize : function (options, ready) {
3468
+ var _cio = window._cio = window._cio || [];
3469
+ (function() {
3470
+ var a,b,c;
3471
+ a = function (f) {
3472
+ return function () {
3473
+ _cio.push([f].concat(Array.prototype.slice.call(arguments,0)));
3474
+ };
3475
+ };
3476
+ b = ['identify', 'track'];
3477
+ for (c = 0; c < b.length; c++) {
3478
+ _cio[b[c]] = a(b[c]);
3479
+ }
3480
+ })();
3481
+
3482
+ // Load the Customer.io script and add the required `id` and `data-site-id`.
3483
+ var script = load('https://assets.customer.io/assets/track.js');
3484
+ script.id = 'cio-tracker';
3485
+ script.setAttribute('data-site-id', options.siteId);
3486
+
3487
+ // Since Customer.io creates their required methods in their snippet, we
3488
+ // don't need to wait to be ready.
3489
+ ready();
3490
+ },
3491
+
3492
+ identify : function (userId, traits) {
3493
+ // Don't do anything if we just have traits, because Customer.io
3494
+ // requires a `userId`.
3495
+ if (!userId) return;
3496
+
3497
+ // Customer.io takes the `userId` as part of the traits object.
3498
+ traits.id = userId;
3499
+
3500
+ // Swap the `created` trait to the `created_at` that Customer.io needs
3501
+ // and convert it from milliseconds to seconds.
3502
+ if (traits.created) {
3503
+ traits.created_at = Math.floor(traits.created/1000);
3504
+ delete traits.created;
3505
+ }
3506
+
3507
+ window._cio.identify(traits);
3508
+ },
3509
+
3510
+ track : function (event, properties) {
3511
+ window._cio.track(event, properties);
3512
+ }
3513
+
3514
+ });
3515
+ });
3516
+ require.register("analytics/src/providers/errorception.js", function(exports, require, module){
3517
+ // http://errorception.com/
3518
+
3519
+ var Provider = require('../provider')
3520
+ , extend = require('extend')
3521
+ , load = require('load-script')
3522
+ , type = require('type');
3523
+
3524
+
3525
+ module.exports = Provider.extend({
3526
+
3527
+ name : 'Errorception',
3528
+
3529
+ key : 'projectId',
3530
+
3531
+ defaults : {
3532
+ projectId : null,
3533
+ // Whether to store metadata about the user on `identify` calls, using
3534
+ // the [Errorception `meta` API](http://blog.errorception.com/2012/11/capture-custom-data-with-your-errors.html).
3535
+ meta : true
3536
+ },
3537
+
3538
+ initialize : function (options, ready) {
3539
+ window._errs = window._errs || [options.projectId];
3540
+ load('//d15qhc0lu1ghnk.cloudfront.net/beacon.js');
3541
+
3542
+ // Attach the window `onerror` event.
3543
+ var oldOnError = window.onerror;
3544
+ window.onerror = function () {
3545
+ window._errs.push(arguments);
3546
+ // Chain the old onerror handler after we finish our work.
3547
+ if ('function' === type(oldOnError)) {
3548
+ oldOnError.apply(this, arguments);
3549
+ }
3550
+ };
3551
+
3552
+ // Errorception makes a queue, so it's ready immediately.
3553
+ ready();
3554
+ },
3555
+
3556
+ // Add the traits to the Errorception meta object.
3557
+ identify : function (userId, traits) {
3558
+ if (!this.options.meta) return;
3559
+
3560
+ // If the custom metadata object hasn't ever been made, make it.
3561
+ window._errs.meta || (window._errs.meta = {});
3562
+
3563
+ // Add `userId` to traits.
3564
+ traits.id = userId;
3565
+
3566
+ // Add all of the traits as metadata.
3567
+ extend(window._errs.meta, traits);
3568
+ }
3569
+
3570
+ });
3571
+ });
3572
+ require.register("analytics/src/providers/foxmetrics.js", function(exports, require, module){
3573
+ // http://foxmetrics.com/documentation/apijavascript
3574
+
3575
+ var Provider = require('../provider')
3576
+ , load = require('load-script');
3577
+
3578
+
3579
+ module.exports = Provider.extend({
3580
+
3581
+ name : 'FoxMetrics',
3582
+
3583
+ key : 'appId',
3584
+
3585
+ defaults : {
3586
+ appId : null
3587
+ },
3588
+
3589
+ initialize : function (options, ready) {
3590
+ var _fxm = window._fxm || {};
3591
+ window._fxm = _fxm.events || [];
3592
+ load('//d35tca7vmefkrc.cloudfront.net/scripts/' + options.appId + '.js');
3593
+
3594
+ // FoxMetrics makes a queue, so it's ready immediately.
3595
+ ready();
3596
+ },
3597
+
3598
+ identify : function (userId, traits) {
3599
+ // A `userId` is required for profile updates.
3600
+ if (!userId) return;
3601
+
3602
+ // FoxMetrics needs the first and last name seperately. Fallback to
3603
+ // splitting the `name` trait if we don't have what we need.
3604
+ var firstName = traits.firstName
3605
+ , lastName = traits.lastName;
3606
+
3607
+ if (!firstName && traits.name) firstName = traits.name.split(' ')[0];
3608
+ if (!lastName && traits.name) lastName = traits.name.split(' ')[1];
3609
+
3610
+ window._fxm.push([
3611
+ '_fxm.visitor.profile',
3612
+ userId, // user id
3613
+ firstName, // first name
3614
+ lastName, // last name
3615
+ traits.email, // email
3616
+ traits.address, // address
3617
+ undefined, // social
3618
+ undefined, // partners
3619
+ traits // attributes
3620
+ ]);
3621
+ },
3622
+
3623
+ track : function (event, properties) {
3624
+ window._fxm.push([
3625
+ event, // event name
3626
+ properties.category, // category
3627
+ properties // properties
3628
+ ]);
3629
+ },
3630
+
3631
+ pageview : function (url) {
3632
+ window._fxm.push([
3633
+ '_fxm.pages.view',
3634
+ undefined, // title
3635
+ undefined, // name
3636
+ undefined, // category
3637
+ url, // url
3638
+ undefined // referrer
3639
+ ]);
3640
+ }
3641
+
3642
+ });
3643
+ });
3644
+ require.register("analytics/src/providers/gauges.js", function(exports, require, module){
3645
+ // http://get.gaug.es/documentation/tracking/
3646
+
3647
+ var Provider = require('../provider')
3648
+ , load = require('load-script');
3649
+
3650
+
3651
+ module.exports = Provider.extend({
3652
+
3653
+ name : 'Gauges',
3654
+
3655
+ key : 'siteId',
3656
+
3657
+ defaults : {
3658
+ siteId : null
3659
+ },
3660
+
3661
+ initialize : function (options, ready) {
3662
+ window._gauges = window._gauges || [];
3663
+ var script = load('//secure.gaug.es/track.js');
3664
+ // Gauges needs a few attributes on its script element.
3665
+ script.id = 'gauges-tracker';
3666
+ script.setAttribute('data-site-id', options.siteId);
3667
+
3668
+ // Gauges make a queue so it's ready immediately.
3669
+ ready();
3670
+ },
3671
+
3672
+ pageview : function (url) {
3673
+ window._gauges.push(['track']);
3674
+ }
3675
+
3676
+ });
3677
+ });
3678
+ require.register("analytics/src/providers/get-satisfaction.js", function(exports, require, module){
3679
+ // You have to be signed in to access the snippet code:
3680
+ // https://console.getsatisfaction.com/start/101022?signup=true#engage
3681
+
3682
+ var Provider = require('../provider')
3683
+ , load = require('load-script')
3684
+ , onBody = require('on-body');
3685
+
3686
+
3687
+ module.exports = Provider.extend({
3688
+
3689
+ name : 'Get Satisfaction',
3690
+
3691
+ key : 'widgetId',
3692
+
3693
+ defaults : {
3694
+ widgetId : null
3695
+ },
3696
+
3697
+ initialize : function (options, ready) {
3698
+ // Get Satisfaction requires a div that will become their widget tab. Append
3699
+ // it once `document.body` exists.
3700
+ var div = document.createElement('div');
3701
+ var id = div.id = 'getsat-widget-' + options.widgetId;
3702
+ onBody(function (body) {
3703
+ body.appendChild(div);
3704
+ });
3705
+
3706
+ // Usually they load their snippet synchronously, so we need to wait for it
3707
+ // to come back before initializing the tab.
3708
+ load('https://loader.engage.gsfn.us/loader.js', function () {
3709
+ if (window.GSFN !== undefined) {
3710
+ window.GSFN.loadWidget(options.widgetId, { containerId : id });
3711
+ }
3712
+ ready();
3713
+ });
3714
+
3715
+ }
3716
+
3717
+ });
3718
+ });
3719
+ require.register("analytics/src/providers/google-analytics.js", function(exports, require, module){
3720
+ // https://developers.google.com/analytics/devguides/collection/gajs/
3721
+
3722
+ var Provider = require('../provider')
3723
+ , load = require('load-script')
3724
+ , type = require('type')
3725
+ , url = require('url')
3726
+ , canonical = require('canonical');
3727
+
3728
+
3729
+ module.exports = Provider.extend({
3730
+
3731
+ name : 'Google Analytics',
3732
+
3733
+ key : 'trackingId',
3734
+
3735
+ defaults : {
3736
+ // Whether to anonymize the IP address collected for the user.
3737
+ anonymizeIp : false,
3738
+ // An optional domain setting, to restrict where events can originate from.
3739
+ domain : null,
3740
+ // Whether to enable GOogle's DoubleClick remarketing feature.
3741
+ doubleClick : false,
3742
+ // Whether to use Google Analytics's Enhanced Link Attribution feature:
3743
+ // http://support.google.com/analytics/bin/answer.py?hl=en&answer=2558867
3744
+ enhancedLinkAttribution : false,
3745
+ // A domain to ignore for referrers. Maps to _addIgnoredRef
3746
+ ignoreReferrer : null,
3747
+ // Whether or not to track and initial pageview when initialized.
3748
+ initialPageview : true,
3749
+ // The setting to use for Google Analytics's Site Speed Sample Rate feature:
3750
+ // https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiBasicConfiguration#_gat.GA_Tracker_._setSiteSpeedSampleRate
3751
+ siteSpeedSampleRate : null,
3752
+ // Your Google Analytics Tracking ID.
3753
+ trackingId : null,
3754
+ // Whether you're using the new Universal Analytics or not.
3755
+ universalClient: false
3756
+ },
3757
+
3758
+ initialize : function (options, ready) {
3759
+ if (options.universalClient) this.initializeUniversal(options, ready);
3760
+ else this.initializeClassic(options, ready);
3761
+ },
3762
+
3763
+ initializeClassic: function (options, ready) {
3764
+ window._gaq = window._gaq || [];
3765
+ window._gaq.push(['_setAccount', options.trackingId]);
3766
+
3767
+ // Apply a bunch of optional settings.
3768
+ if (options.domain) {
3769
+ window._gaq.push(['_setDomainName', options.domain]);
3770
+ }
3771
+ if (options.enhancedLinkAttribution) {
3772
+ var protocol = 'https:' === document.location.protocol ? 'https:' : 'http:';
3773
+ var pluginUrl = protocol + '//www.google-analytics.com/plugins/ga/inpage_linkid.js';
3774
+ window._gaq.push(['_require', 'inpage_linkid', pluginUrl]);
3775
+ }
3776
+ if (type(options.siteSpeedSampleRate) === 'number') {
3777
+ window._gaq.push(['_setSiteSpeedSampleRate', options.siteSpeedSampleRate]);
3778
+ }
3779
+ if (options.anonymizeIp) {
3780
+ window._gaq.push(['_gat._anonymizeIp']);
3781
+ }
3782
+ if (options.ignoreReferrer) {
3783
+ window._gaq.push(['_addIgnoredRef', options.ignoreReferrer]);
3784
+ }
3785
+ if (options.initialPageview) {
3786
+ var path, canon = canonical();
3787
+ if (canon)