text: (function webpackUniversalModuleDefinition(root, factory) {
  	if(typeof exports === 'object' && typeof module === 'object')
  		module.exports = factory();
  	else if(typeof define === 'function' && define.amd)
  		define([], factory);
  	else {
  		var a = factory();
  		for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
  	}
  })(this, function() {
  return /******/ (function(modules) { // webpackBootstrap
  /******/ 	// The module cache
  /******/ 	var installedModules = {};
  
  /******/ 	// The require function
  /******/ 	function __webpack_require__(moduleId) {
  
  /******/ 		// Check if module is in cache
  /******/ 		if(installedModules[moduleId])
  /******/ 			return installedModules[moduleId].exports;
  
  /******/ 		// Create a new module (and put it into the cache)
  /******/ 		var module = installedModules[moduleId] = {
  /******/ 			exports: {},
  /******/ 			id: moduleId,
  /******/ 			loaded: false
  /******/ 		};
  
  /******/ 		// Execute the module function
  /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  
  /******/ 		// Flag the module as loaded
  /******/ 		module.loaded = true;
  
  /******/ 		// Return the exports of the module
  /******/ 		return module.exports;
  /******/ 	}
  
  
  /******/ 	// expose the modules object (__webpack_modules__)
  /******/ 	__webpack_require__.m = modules;
  
  /******/ 	// expose the module cache
  /******/ 	__webpack_require__.c = installedModules;
  
  /******/ 	// __webpack_public_path__
  /******/ 	__webpack_require__.p = "";
  
  /******/ 	// Load entry module and return exports
  /******/ 	return __webpack_require__(0);
  /******/ })
  /************************************************************************/
  /******/ ([
  /* 0 */
  /***/ function(module, exports, __webpack_require__) {
  
  	module.exports = __webpack_require__(1);
  
  
  /***/ },
  /* 1 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * gremlins.js 0.1.0 Copyright (c) 2014, marmelab
  	 * Available via the MIT license.
  	 * see: http://github.com/marmelab/gremlins.js for details
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var Chance = __webpack_require__(2);
  
  	    var gremlins = {
  	        species: {
  	            clicker:    __webpack_require__(3),
  	            toucher:    __webpack_require__(6),
  	            formFiller: __webpack_require__(7),
  	            scroller:   __webpack_require__(8),
  	            typer:      __webpack_require__(9)
  	        },
  	        mogwais: {
  	            alert:      __webpack_require__(10),
  	            fps:        __webpack_require__(12),
  	            gizmo:      __webpack_require__(13)
  	        },
  	        strategies: {
  	            allTogether:  __webpack_require__(14),
  	            bySpecies:    __webpack_require__(16),
  	            distribution: __webpack_require__(17)
  	        }
  	    };
  
  	    var executeInSeries = __webpack_require__(15);
  
  	    var GremlinsHorde = function() {
  	        this._gremlins = [];
  	        this._mogwais = [];
  	        this._strategies = [];
  	        this._beforeCallbacks = [];
  	        this._afterCallbacks = [];
  	        this._logger = console; // logs to console by default
  	        this._randomizer = new Chance();
  	    };
  
  	    /**
  	     * Add a gremlin to the horde.
  	     *
  	     * A gremlin is nothing more than a function. Gremlins mess up with the
  	     * application in order to test its robustness. Once unleashed, the horde
  	     * executes each gremlin function several times (see unleash()).
  	     *
  	     *   horde.gremlin(function() {
  	     *     // do nasty things to the application
  	     *   });
  	     *
  	     * The gremlins object contains a few gremlin species that you can add:
  	     *
  	     *   horde.gremlin(gremlins.species.clicker());
  	     *
  	     * A gremlin can be asynchronous if it takes an argument, which means that
  	     * the horde is paused until the argument is executed.
  	     *
  	     *   horde.gremlin(function(done) {
  	     *     // do nasty things to the application asynchronously
  	     *     done();
  	     *   });
  	     *
  	     * If the gremlin provides a logger() function, the horde logger object is
  	     * injected, to allow the gremlin to record activity.
  	     *
  	     *
  	     * If the gremlin provides a randomizer() function, the horde randomizer
  	     * object is injected, to allow the gremlin to generate random data in a
  	     * repeatable way.
  	     *
  	     * Here is a more sophisticated gremlin function example:
  	     *
  	     *   var logger;
  	     *   function arrayDestroyer() {
  	     *     Array.prototype.indexOf = function() { return 42; };
  	     *     if (logger && logger.log) {
  	     *       logger.log('All arrays are now equal');
  	     *     }
  	     *   });
  	     *   arrayDestroyer.logger = function(loggerObject) {
  	     *     logger = loggerObject;
  	     *   };
  	     *   horde.gremlin(arrayDestroyer);
  	     *
  	     * Gremlin functions are executed in the context of the horde, however it
  	     * is a good practice to avoid using "this" inside gremlin functions to
  	     * allow standalone gremlin execution, and to ease debugging.
  	     *
  	     *   horde.gremlin(function() {
  	     *     var oldIndexOf = Array.prototype.indexOf;
  	     *     Array.prototype.indexOf = function() { return 42; };
  	     *     // "this" is the horde
  	     *     this.after(function(){
  	     *       array.prototype.indexOf = oldIndexOf;
  	     *     });
  	     *   });
  	     *
  	     * If a horde is unleashed without manually adding at least a single
  	     * gremlin, all the default gremlin species are added (see allGremlins()).
  	     *
  	     * @param {Function} gremlin - A callback to be executed to mess up the app
  	     * @return {GremlinsHorde}
  	     */
  	    GremlinsHorde.prototype.gremlin = function(gremlin) {
  	        this._gremlins.push(gremlin);
  	        return this;
  	    };
  
  	    /**
  	     * Add all the registered gremlin species to the horde.
  	     *
  	     * The gremlin species are available in gremlins.species. You can add your
  	     * own easily:
  	     *
  	     *   gremlins.species.greenMutant = function(logger) { //... };
  	     *
  	     * @return {GremlinsHorde}
  	     */
  	    GremlinsHorde.prototype.allGremlins = function() {
  	        for (var gremlinName in gremlins.species) {
  	            this.gremlin(gremlins.species[gremlinName]());
  	        }
  	        return this;
  	    };
  
  	    /**
  	     * Add a mogwai to the horde.
  	     *
  	     * A mogwai is nothing more than a function. Mogwais monitor application
  	     * activity in order to detect when gremlins do damages. Contrary to
  	     * gremlins, mogwais should do no harm to the current application.
  	     *
  	     *   // this example mogwai monitors javascript alerts
  	     *   horde.mogwai(function() {
  	     *     var oldAlert = window.alert;
  	     *     window.alert = function(message) {
  	     *       // do stuff
  	     *       oldAlert(message);
  	     *     }
  	     *   });
  	     *
  	     * The gremlins object contains a few mogwai species than you can add:
  	     *
  	     *   horde.mogwai(gremlins.mogwais.alert());
  	     *
  	     * Mogwais are called once before the horde is unleashed. Just like a
  	     * before() callback, a mogwai can be synchronous or asynchronous.
  	     *
  	     * What distinguishes a mogwai function from a simple before() function
  	     * is that mogwai functions can provide a cleanUp() function to be called
  	     * once after the gremlins finished their job.
  	     *
  	     * When added, if the mogwai provides a logger() function, the horde
  	     * logger object is injected, to allow the mogwai to record activity.
  	     *
  	     * Here is a more sophisticated mogwai function example:
  	     *
  	     *   var oldAlert = window.alert;
  	     *   var logger;
  	     *   function alert() {
  	     *     window.alert = function(message) {
  	     *       oldAlert(message);
  	     *       if (logger && logger.log) {
  	     *         logger.log('alert', msg);
  	     *       }
  	     *     }
  	     *   });
  	     *   alert.cleanUp = function() {
  	     *     window.alert = oldAlert;
  	     *   };
  	     *   alert.logger = function(loggerObject) {
  	     *     logger = loggerObject;
  	     *   };
  	     *   horde.mogwai(alert);
  	     *
  	     * The cleanUp() and logger() support for mogwais allow to build
  	     * sophisticated monitoring features without using "this", and make
  	     * the mogwais portable and testable.
  	     *
  	     * If a horde is unleashed without manually adding at least a single
  	     * mogwai, all the default mogwai species are added (see allMogwais()).
  	     *
  	     * If you want to disable default mogwais, just add an empty function.
  	     *
  	     *   horde.mogwai(function() {});
  	     *
  	     * @param {Function} mogwai - A callback to be executed when the test starts
  	     * @return {GremlinsHorde}
  	     */
  	    GremlinsHorde.prototype.mogwai = function(mogwai) {
  	        this._mogwais.push(mogwai);
  	        return this;
  	    };
  
  	    /**
  	     * Add all the registered mogwai species to the horde.
  	     *
  	     * The mogwai species are available in gremlins.mogwais. You can add your
  	     * own easily:
  	     *
  	     *   gremlins.mogwais.gizmo = function() { //... };
  	     *
  	     * @return {GremlinsHorde}
  	     */
  	    GremlinsHorde.prototype.allMogwais = function() {
  	        for (var mogwaiName in gremlins.mogwais) {
  	            this.mogwai(gremlins.mogwais[mogwaiName]());
  	        }
  	        return this;
  	    };
  
  	    /**
  	     * Add an attack strategy to run gremlins.
  	     *
  	     * A strategy is an asynchronous function taking the following arguments:
  	     *  - gremlins: array of gremlin species added to the horde
  	     *  - params: the parameters passed as first argument of unleash()
  	     *  - done: a callback to execute once the strategy is finished
  	     *
  	     * A strategy function executes registered gremlins in a certain order,
  	     * a certain number of times.
  	     *
  	     *   horde.strategy(function allAtOnceStrategy(gremlins, params, done) {
  	     *     gremlins.forEach(function(gremlin) {
  	     *       gremlin.apply(horde);
  	     *     });
  	     *     done();
  	     *   });
  	     *
  	     * The gremlins object contains a few strategies than you can add:
  	     *
  	     *   horde.strategy(gremlins.strategies.bySpecies());
  	     *
  	     * You can add several strategies by calling strategy() more than once.
  	     * They will be executed in the order they were registered.
  	     *
  	     * If a horde is unleashed without manually adding at least a single
  	     * strategy, all the default strategy (allTogether) is used.
  	     *
  	     * @param {Function} strategy - A callback to be executed when the test starts
  	     * @return {GremlinsHorde}
  	     */
  	    GremlinsHorde.prototype.strategy = function(strategy) {
  	        this._strategies.push(strategy);
  	        return this;
  	    };
  
  	    /**
  	     * Add a callback to be executed before gremlins are unleashed.
  	     *
  	     * Use it to setup the page before the stress test (disable some features,
  	     * set default data, bootstrap the application, start a profiler).
  	     *
  	     *   horde.before(function() {
  	     *     console.profile('gremlins'); // start the Chrome profiler
  	     *   });
  	     *
  	     * If the callback takes no argument, it is executed synchronously.
  	     *
  	     *   horde.before(function() {
  	     *     // do things synchronously
  	     *   });
  	     *
  	     * If the callback takes an argument, it is executed asynchronously, which
  	     * means that the horde is paused until the argument is executed.
  	     *
  	     *   horde.before(function(done) {
  	     *     // do things asynchronously
  	     *     done();
  	     *   });
  	     *
  	     * before() callbacks are executed in the context of the horde.
  	     *
  	     *   horde.before(function() {
  	     *     // "this" is the horde
  	     *     this.log('Preparing the attack');
  	     *   });
  	     *
  	     * You can add several callbacks by calling before() more than once.
  	     * They will be executed in the order they were registered.
  	     *
  	     * @param {Function} beforeCallback - A callback to be executed before the stress test
  	     * @return {GremlinsHorde}
  	     */
  	    GremlinsHorde.prototype.before = function(beforeCallback) {
  	        this._beforeCallbacks.push(beforeCallback);
  	        return this;
  	    };
  
  	    /**
  	     * Add a callback to be executed after gremlins finished their job.
  	     *
  	     * Use it to collect insights of the gremlins activity, stop a profiler,
  	     * or re-enable features that were disabled for the test.
  	     *
  	     *   horde.after(function() {
  	     *     console.profileEnd(); // stop the Chrome profiler
  	     *   });
  	     *
  	     * If the callback takes no argument, it is executed synchronously.
  	     *
  	     *   horde.after(function() {
  	     *     // do things synchronously
  	     *   });
  	     *
  	     * If the callback takes an argument, it is executed asynchronously, which
  	     * means that the horde is paused until the argument is executed.
  	     *
  	     *   horde.after(function(done) {
  	     *     // do things asynchronously
  	     *     done();
  	     *   });
  	     *
  	     * after() callbacks are executed in the context of the horde.
  	     *
  	     *   horde.after(function() {
  	     *     // "this" is the horde
  	     *     this.log('Cleaning up the mess after the attack');
  	     *   });
  	     *
  	     * You can add several callbacks by calling after() more than once.
  	     * They will be executed in the order they were registered.
  	     *
  	     * @param {Function} afterCallback - A callback to be executed at the end of the stress test
  	     * @return {GremlinsHorde}
  	     */
  	    GremlinsHorde.prototype.after = function(afterCallback) {
  	        this._afterCallbacks.push(afterCallback);
  	        return this;
  	    };
  
  	    /**
  	     * Set the logger object to use for logging.
  	     *
  	     * When called with no parameter, return the current logger.
  	     *
  	     * The logger object must provide 4 functions: log, info, warn, and error.
  	     *
  	     *   var consoleLogger = {
  	     *       log:   console.log.bind(console),
  	     *       info:  console.info.bind(console),
  	     *       warn:  console.warn.bind(console),
  	     *       error: console.error.bind(console)
  	     *   };
  	     *   horde.logger(consoleLogger);
  	     *
  	     * The logger object is injected to mogwais, and to gremlins.
  	     *
  	     * By default, a horde uses the global console object as logger.
  	     *
  	     * @param {Object} [logger] - A logger object
  	     * @return {GremlinsHorde}
  	     */
  	    GremlinsHorde.prototype.logger = function(logger) {
  	        if (!arguments.length) return this._logger;
  	        this._logger = logger;
  	        return this;
  	    };
  
  	    /**
  	     * Shortcut to the logger's log() method.
  	     *
  	     * Mostly useful for before() and after() callbacks. Only supports a
  	     * single argument.
  	     *
  	     * @param {String} msg The message to log
  	     */
  	    GremlinsHorde.prototype.log = function(msg) {
  	        this._logger.log(msg);
  	    };
  
  	    /**
  	     * Set the randomizer object to use for generating random data.
  	     *
  	     * When called with no parameter, return the current randomizer.
  	     *
  	     * The randomizer object must be compatible with chance.js.
  	     *
  	     * The randomizer object is injected to mogwais, and to gremlins.
  	     *
  	     * By default, a horde uses a new Chance object as logger.
  	     *
  	     * @param {Object} [randomizer] - A randomizer object
  	     * @return {GremlinsHorde}
  	     */
  	    GremlinsHorde.prototype.randomizer = function(randomizer) {
  	        if (!arguments.length) return this._randomizer;
  	        this._randomizer = randomizer;
  	        return this;
  	    };
  
  	    /**
  	     * Seed the random number generator
  	     *
  	     * Useful to generate repeatable random results actions.
  	     *
  	     * You can pass either an integer, or a random data generator callback
  	     *
  	     * @see Chance() constructor
  	     */
  	    GremlinsHorde.prototype.seed = function(seed) {
  	        this._randomizer = new Chance(seed);
  	        return this;
  	    };
  
  	    /**
  	     * Start the stress test by executing gremlins according to the strategies
  	     *
  	     * Gremlins and mogwais do nothing until the horde is unleashed.
  	     * When unleashing, you can pass parameters to the strategies, such as the
  	     * number of gremlin waves in the default strategy.
  	     *
  	     *   horde.unleash({ nb: 50 }); // all gremlins will attack 50 times
  	     *
  	     * unleash() executes asynchronously, so you must use the second argument
  	     * if you need to execute code after the stress test.
  	     *
  	     *   horde.unleash({}, function() {
  	     *     console.log('Phew! Stress test is over.');
  	     *   });
  	     *
  	     * Alternately, you can use the after() method.
  	     *
  	     *   horde
  	     *     .after(function() {
  	     *       console.log('Phew! Stress test is over.');
  	     *     })
  	     *     .unleash();
  	     *
  	     * @param {Object} [params] - A list of parameters passed to each strategy.
  	     * @param {Function} [done] - A callback to be executed once the stress test is over
  	     */
  	    GremlinsHorde.prototype.unleash = function(params, done) {
  	        if (this._gremlins.length === 0) {
  	            this.allGremlins();
  	        }
  	        if (this._mogwais.length === 0) {
  	            this.allMogwais();
  	        }
  	        if (this._strategies.length === 0) {
  	            this.strategy(gremlins.strategies.distribution());
  	        }
  
  	        var gremlinsAndMogwais = [].concat(this._gremlins, this._mogwais);
  	        var allCallbacks = gremlinsAndMogwais.concat(this._strategies, this._beforeCallbacks, this._afterCallbacks);
  	        inject({'logger': this._logger, 'randomizer': this._randomizer}, allCallbacks);
  	        var beforeCallbacks = this._beforeCallbacks;
  	        beforeCallbacks = beforeCallbacks.concat(this._mogwais);
  	        var afterCallbacks  = this._afterCallbacks;
  	        for (var i = 0, count = gremlinsAndMogwais.length; i < count; i++) {
  	            if (typeof gremlinsAndMogwais[i].cleanUp == 'function') {
  	                afterCallbacks.push(gremlinsAndMogwais[i].cleanUp);
  	            }
  	        }
  
  	        var horde = this;
  
  	        executeInSeries(beforeCallbacks, [], horde, function() {
  	            executeInSeries(horde._strategies, [horde._gremlins, params], horde, function() {
  	                executeInSeries(afterCallbacks, [], horde, function () {
  	                    if (typeof done === 'function') {
  	                        done();
  	                    }
  	                });
  	            });
  	        });
  	    };
  
  	    function inject(services, objects) {
  	        for (var i = 0, count = objects.length; i < count; i++) {
  	            for (var name in services) {
  	                if (typeof objects[i][name] === "function" && !objects[i][name]()) {
  	                    objects[i][name](services[name]);
  	                }
  	            }
  	        }
  	    }
  
  	    /**
  	     * Stop a running test
  	     *
  	     * Delegate the stop message to all registered strategies. Calling
  	     * this method before starting the test or after it is finished has
  	     * no effect.
  	     *
  	     * stop() will only work properly if strategies implement their own stop()
  	     * method.
  	     */
  	    GremlinsHorde.prototype.stop = function() {
  	        var strategies = this._strategies;
  	        for (var i = 0, count = strategies.length; i < count; i++) {
  	            strategies[i].stop();
  	        }
  	    };
  
  	    /**
  	     * Get a new horde instance
  	     *
  	     * @return {GremlinsHorde}
  	     */
  	    gremlins.createHorde = function() {
  	        return new GremlinsHorde();
  	    };
  
  	    if (window) {
  	        window.gremlins = gremlins;
  	    }
  
  	    return gremlins;
  
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 2 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;//  Chance.js 0.5.4
  	//  http://chancejs.com
  	//  (c) 2013 Victor Quinn
  	//  Chance may be freely distributed or modified under the MIT license.
  
  	(function () {
  
  	    // Constants
  	    var MAX_INT = 9007199254740992;
  	    var MIN_INT = -MAX_INT;
  	    var NUMBERS = '0123456789';
  	    var CHARS_LOWER = 'abcdefghijklmnopqrstuvwxyz';
  	    var CHARS_UPPER = CHARS_LOWER.toUpperCase();
  	    var HEX_POOL  = NUMBERS + "abcdef";
  
  	    // Constructor
  	    var Chance = function (seed) {
  	        if (seed !== undefined) {
  	            // If we were passed a generator rather than a seed, use it.
  	            if (typeof seed === 'function') {
  	                this.random = seed;
  	            } else {
  	                this.seed = seed;
  	            }
  	        }
  
  	        // If no generator function was provided, use our MT
  	        if (typeof this.random === 'undefined') {
  	            this.mt = this.mersenne_twister(seed);
  	            this.random = function () {
  	                return this.mt.random(this.seed);
  	            };
  	        }
  	    };
  
  	    // Random helper functions
  	    function initOptions(options, defaults) {
  	        options || (options = {});
  	        if (!defaults) {
  	            return options;
  	        }
  	        for (var i in defaults) {
  	            if (typeof options[i] === 'undefined') {
  	                options[i] = defaults[i];
  	            }
  	        }
  	        return options;
  	    }
  
  	    function testRange(test, errorMessage) {
  	        if (test) {
  	            throw new RangeError(errorMessage);
  	        }
  	    }
  
  	    // -- Basics --
  
  	    Chance.prototype.bool = function (options) {
  
  	        // likelihood of success (true)
  	        options = initOptions(options, {likelihood : 50});
  
  	        testRange(
  	            options.likelihood < 0 || options.likelihood > 100,
  	            "Chance: Likelihood accepts values from 0 to 100."
  	        );
  
  	        return this.random() * 100 < options.likelihood;
  	    };
  
  	    Chance.prototype.character = function (options) {
  	        options = initOptions(options);
  
  	        var symbols = "!@#$%^&*()[]",
  	            letters, pool;
  
  	        testRange(
  	            options.alpha && options.symbols,
  	            "Chance: Cannot specify both alpha and symbols."
  	        );
  
  
  	        if (options.casing === 'lower') {
  	            letters = CHARS_LOWER;
  	        } else if (options.casing === 'upper') {
  	            letters = CHARS_UPPER;
  	        } else {
  	            letters = CHARS_LOWER + CHARS_UPPER;
  	        }
  
  	        if (options.pool) {
  	            pool = options.pool;
  	        } else if (options.alpha) {
  	            pool = letters;
  	        } else if (options.symbols) {
  	            pool = symbols;
  	        } else {
  	            pool = letters + NUMBERS + symbols;
  	        }
  
  	        return pool.charAt(this.natural({max: (pool.length - 1)}));
  	    };
  
  	    // Note, wanted to use "float" or "double" but those are both JS reserved words.
  
  	    // Note, fixed means N OR LESS digits after the decimal. This because
  	    // It could be 14.9000 but in JavaScript, when this is cast as a number,
  	    // the trailing zeroes are dropped. Left to the consumer if trailing zeroes are
  	    // needed
  	    Chance.prototype.floating = function (options) {
  	        var num, range;
  
  	        options = initOptions(options, {fixed : 4});
  	        var fixed = Math.pow(10, options.fixed);
  
  	        testRange(
  	            options.fixed && options.precision,
  	            "Chance: Cannot specify both fixed and precision."
  	        );
  
  	        var max = MAX_INT / fixed;
  	        var min = -max;
  
  	        testRange(
  	            options.min && options.fixed && options.min < min,
  	            "Chance: Min specified is out of range with fixed. Min should be, at least, " + min
  	        );
  	        testRange(
  	            options.max && options.fixed && options.max > max,
  	            "Chance: Max specified is out of range with fixed. Max should be, at most, " + max
  	        );
  
  	        options = initOptions(options, {min : min, max : max});
  
  	        // Todo - Make this work!
  	        // options.precision = (typeof options.precision !== "undefined") ? options.precision : false;
  
  	        num = this.integer({min: options.min * fixed, max: options.max * fixed});
  	        var num_fixed = (num / fixed).toFixed(options.fixed);
  
  	        return parseFloat(num_fixed);
  	    };
  
  	    Chance.prototype.integer = function (options) {
  	        var num, range;
  
  	        options = initOptions(options, {min : MIN_INT, max : MAX_INT});
  
  	        // Greatest of absolute value of either max or min so we know we're
  	        // including the entire search domain.
  	        range = Math.max(Math.abs(options.min), Math.abs(options.max));
  
  	        // Probably a better way to do this...
  	        do {
  	            num = this.natural({max: range});
  	            num = this.bool() ? num : num * -1;
  	        } while (num < options.min || num > options.max);
  
  	        return num;
  	    };
  
  	    // NOTE the max and min are INCLUDED in the range. So:
  	    //
  	    // chance.natural({min: 1, max: 3});
  	    //
  	    // would return either 1, 2, or 3.
  
  	    Chance.prototype.natural = function (options) {
  
  	        // 9007199254740992 (2^53) is the max integer number in JavaScript
  	        // See: http://vq.io/132sa2j
  	        options = initOptions(options, {min: 0, max: MAX_INT});
  
  	        testRange(options.min > options.max, "Chance: Min cannot be greater than Max.");
  
  	        return Math.floor(this.random() * (options.max - options.min + 1) + options.min);
  	    };
  
  	    Chance.prototype.normal = function (options) {
  	        options = initOptions(options, {mean : 0, dev : 1});
  
  	        // The Marsaglia Polar method
  	        var s, u, v, norm,
  	            mean = options.mean,
  	            dev = options.dev;
  
  	        do {
  	            // U and V are from the uniform distribution on (-1, 1)
  	            u = this.random() * 2 - 1;
  	            v = this.random() * 2 - 1;
  
  	            s = u * u + v * v;
  	        } while (s >= 1);
  
  	        // Compute the standard normal variate
  	        norm = u * Math.sqrt(-2 * Math.log(s) / s);
  
  	        // Shape and scale
  	        return dev * norm + mean;
  	    };
  
  	    Chance.prototype.string = function (options) {
  	        options = initOptions(options);
  
  	        var length = options.length || this.natural({min: 5, max: 20}),
  	            text = '',
  	            pool = options.pool;
  
  	        for (var i = 0; i < length; i++) {
  	            text += this.character({pool: pool});
  	        }
  	        return text;
  	    };
  
  	    // -- End Basics --
  
  	    // -- Helpers --
  
  	    Chance.prototype.capitalize = function (word) {
  	        return word.charAt(0).toUpperCase() + word.substr(1);
  	    };
  
  	    Chance.prototype.mixin = function (obj) {
  	        var chance = this;
  	        for (var func_name in obj) {
  	            Chance.prototype[func_name] = obj[func_name];
  	        }
  	        return this;
  	    };
  
  	    Chance.prototype.pick = function (arr, count) {
  	        if (!count || count === 1) {
  	            return arr[this.natural({max: arr.length - 1})];
  	        } else {
  	            return this.shuffle(arr).slice(0, count);
  	        }
  	    };
  
  	    Chance.prototype.shuffle = function (arr) {
  	        var old_array = arr.slice(0),
  	            new_array = [],
  	            j = 0,
  	            length = Number(old_array.length);
  
  	        for (var i = 0; i < length; i++) {
  	            // Pick a random index from the array
  	            j = this.natural({max: old_array.length - 1});
  	            // Add it to the new array
  	            new_array[i] = old_array[j];
  	            // Remove that element from the original array
  	            old_array.splice(j, 1);
  	        }
  
  	        return new_array;
  	    };
  
  	    // -- End Helpers --
  
  	    // -- Text --
  
  	    Chance.prototype.paragraph = function (options) {
  	        options = initOptions(options);
  
  	        var sentences = options.sentences || this.natural({min: 3, max: 7}),
  	            sentence_array = [];
  
  	        for (var i = 0; i < sentences; i++) {
  	            sentence_array.push(this.sentence());
  	        }
  
  	        return sentence_array.join(' ');
  	    };
  
  	    // Could get smarter about this than generating random words and
  	    // chaining them together. Such as: http://vq.io/1a5ceOh
  	    Chance.prototype.sentence = function (options) {
  	        options = initOptions(options);
  
  	        var words = options.words || this.natural({min: 12, max: 18}),
  	            text, word_array = [];
  
  	        for (var i = 0; i < words; i++) {
  	            word_array.push(this.word());
  	        }
  
  	        text = word_array.join(' ');
  
  	        // Capitalize first letter of sentence, add period at end
  	        text = this.capitalize(text) + '.';
  
  	        return text;
  	    };
  
  	    Chance.prototype.syllable = function (options) {
  	        options = initOptions(options);
  
  	        var length = options.length || this.natural({min: 2, max: 3}),
  	            consanants = 'bcdfghjklmnprstvwz', // consonants except hard to speak ones
  	            vowels = 'aeiou', // vowels
  	            all = consanants + vowels, // all
  	            text = '',
  	            chr;
  
  	        // I'm sure there's a more elegant way to do this, but this works
  	        // decently well.
  	        for (var i = 0; i < length; i++) {
  	            if (i === 0) {
  	                // First character can be anything
  	                chr = this.character({pool: all});
  	            } else if (consanants.indexOf(chr) === -1) {
  	                // Last charcter was a vowel, now we want a consanant
  	                chr = this.character({pool: consanants});
  	            } else {
  	                // Last charcter was a consanant, now we want a vowel
  	                chr = this.character({pool: vowels});
  	            }
  
  	            text += chr;
  	        }
  
  	        return text;
  	    };
  
  	    Chance.prototype.word = function (options) {
  	        options = initOptions(options);
  
  	        testRange(
  	            options.syllables && options.length,
  	            "Chance: Cannot specify both syllables AND length."
  	        );
  
  	        var syllables = options.syllables || this.natural({min: 1, max: 3}),
  	            text = '';
  
  	        if (options.length) {
  	            // Either bound word by length
  	            do {
  	                text += this.syllable();
  	            } while (text.length < options.length);
  	            text = text.substring(0, options.length);
  	        } else {
  	            // Or by number of syllables
  	            for (var i = 0; i < syllables; i++) {
  	                text += this.syllable();
  	            }
  	        }
  	        return text;
  	    };
  
  	    // -- End Text --
  
  	    // -- Person --
  
  	    Chance.prototype.age = function (options) {
  	        options = initOptions(options);
  	        var age;
  
  	        switch (options.type) {
  	        case 'child':
  	            age = this.natural({min: 1, max: 12});
  	            break;
  	        case 'teen':
  	            age = this.natural({min: 13, max: 19});
  	            break;
  	        case 'adult':
  	            age = this.natural({min: 18, max: 120});
  	            break;
  	        case 'senior':
  	            age = this.natural({min: 65, max: 120});
  	            break;
  	        default:
  	            age = this.natural({min: 1, max: 120});
  	            break;
  	        }
  
  	        return age;
  	    };
  
  	    Chance.prototype.birthday = function (options) {
  	        options = initOptions(options, {
  	            year: (new Date().getFullYear() - this.age(options))
  	        });
  
  	        return this.date(options);
  	    };
  
  	    var firstNames = ['Sophia', 'Emma', 'Isabella', 'Jacob', 'Mason', 'Ethan', 'Noah', 'Olivia', 'William', 'Liam', 'Jayden', 'Michael', 'Ava', 'Alexander', 'Aiden', 'Daniel', 'Matthew', 'Elijah', 'Emily', 'James', 'Anthony', 'Benjamin', 'Abigail', 'Joshua', 'Andrew', 'David', 'Joseph', 'Logan', 'Jackson', 'Mia', 'Christopher', 'Gabriel', 'Madison', 'Samuel', 'Ryan', 'Lucas', 'John', 'Nathan', 'Isaac', 'Dylan', 'Caleb', 'Elizabeth', 'Chloe', 'Christian', 'Landon', 'Jonathan', 'Carter', 'Ella', 'Luke', 'Owen', 'Brayden', 'Avery', 'Gavin', 'Wyatt', 'Addison', 'Isaiah', 'Aubrey', 'Henry', 'Eli', 'Hunter', 'Lily', 'Jack', 'Natalie', 'Evan', 'Sofia', 'Jordan', 'Nicholas', 'Tyler', 'Aaron', 'Charlotte', 'Zoey', 'Jeremiah', 'Julian', 'Cameron', 'Grace', 'Hannah', 'Amelia', 'Harper', 'Levi', 'Lillian', 'Brandon', 'Angel', 'Austin', 'Connor', 'Adrian', 'Robert', 'Samantha', 'Charles', 'Evelyn', 'Victoria', 'Thomas', 'Brooklyn', 'Sebastian', 'Zoe', 'Colton', 'Jaxon', 'Layla', 'Kevin', 'Zachary', 'Ayden', 'Dominic', 'Blake', 'Jose', 'Hailey', 'Oliver', 'Justin', 'Bentley', 'Leah', 'Jason', 'Chase', 'Ian', 'Kaylee', 'Anna', 'Aaliyah', 'Gabriella', 'Josiah', 'Allison', 'Parker', 'Xavier', 'Nevaeh', 'Alexis', 'Adam', 'Audrey', 'Cooper', 'Savannah', 'Sarah', 'Alyssa', 'Claire', 'Taylor', 'Riley', 'Camila', 'Nathaniel', 'Arianna', 'Ashley', 'Grayson', 'Jace', 'Brianna', 'Carson', 'Sophie', 'Peyton', 'Nolan', 'Tristan', 'Luis', 'Brody', 'Bella', 'Khloe', 'Genesis', 'Alexa', 'Juan', 'Hudson', 'Serenity', 'Kylie', 'Aubree', 'Scarlett', 'Bryson', 'Carlos', 'Stella', 'Maya', 'Easton', 'Katherine', 'Julia', 'Damian', 'Alex', 'Kayden', 'Ryder', 'Lucy', 'Madelyn', 'Jesus', 'Cole', 'Autumn', 'Makayla', 'Kayla', 'Mackenzie', 'Micah', 'Vincent', 'Max', 'Lauren', 'Jaxson', 'Gianna', 'Eric', 'Ariana', 'Asher', 'Hayden', 'Faith', 'Alexandra', 'Melanie', 'Sydney', 'Bailey', 'Caroline', 'Naomi', 'Morgan', 'Kennedy', 'Ellie', 'Jasmine', 'Eva', 'Skylar', 'Diego', 'Kimberly', 'Violet', 'Molly', 'Miles', 'Steven', 'Aria', 'Ivan', 'Jocelyn', 'Trinity', 'Elias', 'Aidan', 'Maxwell', 'London', 'Bryce', 'Lydia', 'Madeline', 'Antonio', 'Giovanni', 'Reagan', 'Timothy', 'Bryan', 'Piper', 'Andrea', 'Santiago', 'Annabelle', 'Maria', 'Colin', 'Richard', 'Braxton', 'Kaleb', 'Brooke', 'Kyle', 'Kaden', 'Preston', 'Payton', 'Miguel', 'Jonah', 'Paisley', 'Paige', 'Lincoln', 'Ruby', 'Nora', 'Riley', 'Mariah', 'Leo', 'Victor', 'Brady', 'Jeremy', 'Mateo', 'Brian', 'Jaden', 'Ashton', 'Patrick', 'Rylee', 'Declan', 'Lilly', 'Brielle', 'Sean', 'Joel', 'Gael', 'Sawyer', 'Alejandro', 'Jade', 'Marcus', 'Destiny', 'Leonardo', 'Jesse', 'Caden', 'Jake', 'Kaiden', 'Nicole', 'Mila', 'Wesley', 'Kendall', 'Liliana', 'Camden', 'Kaitlyn', 'Natalia', 'Sadie', 'Edward', 'Brantley', 'Jordyn', 'Roman', 'Vanessa', 'Mary', 'Mya', 'Penelope', 'Isabelle', 'Alice', 'Axel', 'Silas', 'Jude', 'Grant', 'Reese', 'Gabrielle', 'Hadley', 'Katelyn', 'Angelina', 'Rachel', 'Isabel', 'Eleanor', 'Cayden', 'Emmanuel', 'George', 'Clara', 'Brooklynn', 'Jessica', 'Maddox', 'Malachi', 'Bradley', 'Alan', 'Weston', 'Elena', 'Gage', 'Aliyah', 'Vivian', 'Laila', 'Sara', 'Amy', 'Devin', 'Eliana', 'Greyson', 'Lyla', 'Juliana', 'Kenneth', 'Mark', 'Oscar', 'Tanner', 'Rylan', 'Valeria', 'Adriana', 'Nicolas', 'Makenzie', 'Harrison', 'Elise', 'Mckenzie', 'Derek', 'Quinn', 'Delilah', 'Peyton', 'Ezra', 'Cora', 'Kylee', 'Tucker', 'Emmett', 'Avery', 'Cody', 'Rebecca', 'Gracie', 'Izabella', 'Calvin', 'Andres', 'Jorge', 'Abel', 'Paul', 'Abraham', 'Kai', 'Josephine', 'Alaina', 'Michelle', 'Jennifer', 'Collin', 'Theodore', 'Ezekiel', 'Eden', 'Omar', 'Jayce', 'Valentina', 'Conner', 'Bennett', 'Aurora', 'Catherine', 'Stephanie', 'Trevor', 'Valerie', 'Eduardo', 'Peter', 'Maximus', 'Jayla', 'Jaiden', 'Willow', 'Jameson', 'Seth', 'Daisy', 'Alana', 'Melody', 'Hazel', 'Kingston', 'Summer', 'Melissa', 'Javier', 'Margaret', 'Travis', 'Kinsley', 'Kinley', 'Garrett', 'Everett', 'Ariel', 'Lila', 'Graham', 'Giselle', 'Ryleigh', 'Xander', 'Haley', 'Julianna', 'Ivy', 'Alivia', 'Cristian', 'Brynn', 'Damien', 'Ryker', 'Griffin', 'Keira', 'Daniela', 'Aniyah', 'Angela', 'Kate', 'Londyn', 'Corbin', 'Myles', 'Hayden', 'Harmony', 'Adalyn', 'Luca', 'Zane', 'Francisco', 'Ricardo', 'Alexis', 'Stephen', 'Zayden', 'Megan', 'Allie', 'Gabriela', 'Iker', 'Drake', 'Alayna', 'Lukas', 'Presley', 'Charlie', 'Spencer', 'Zion', 'Erick', 'Jenna', 'Josue', 'Alexandria', 'Ashlyn', 'Adrianna', 'Jada', 'Jeffrey', 'Trenton', 'Fiona', 'Chance', 'Norah', 'Paxton', 'Elliot', 'Emery', 'Fernando', 'Maci', 'Miranda', 'Keegan', 'Landen', 'Ximena', 'Amaya', 'Manuel', 'Amir', 'Shane', 'Cecilia', 'Raymond', 'Andre', 'Ana', 'Shelby', 'Katie', 'Hope', 'Callie', 'Jordan', 'Luna', 'Leilani', 'Eliza', 'Mckenna', 'Angel', 'Genevieve', 'Makenna', 'Isla', 'Lola', 'Danielle', 'Chelsea', 'Leila', 'Tessa', 'Adelyn', 'Camille', 'Mikayla', 'Adeline', 'Adalynn', 'Sienna', 'Esther', 'Jacqueline', 'Emerson', 'Arabella', 'Maggie', 'Athena', 'Lucia', 'Lexi', 'Ayla'];
  
  	    Chance.prototype.first = function () {
  	        return this.pick(firstNames);
  	    };
  
  	    Chance.prototype.gender = function () {
  	        return this.pick(['Male', 'Female']);
  	    };
  
  	    var lastNames = ['Smith', 'Johnson', 'Williams', 'Jones', 'Brown', 'Davis', 'Miller', 'Wilson', 'Moore', 'Taylor', 'Anderson', 'Thomas', 'Jackson', 'White', 'Harris', 'Martin', 'Thompson', 'Garcia', 'Martinez', 'Robinson', 'Clark', 'Rodriguez', 'Lewis', 'Lee', 'Walker', 'Hall', 'Allen', 'Young', 'Hernandez', 'King', 'Wright', 'Lopez', 'Hill', 'Scott', 'Green', 'Adams', 'Baker', 'Gonzalez', 'Nelson', 'Carter', 'Mitchell', 'Perez', 'Roberts', 'Turner', 'Phillips', 'Campbell', 'Parker', 'Evans', 'Edwards', 'Collins', 'Stewart', 'Sanchez', 'Morris', 'Rogers', 'Reed', 'Cook', 'Morgan', 'Bell', 'Murphy', 'Bailey', 'Rivera', 'Cooper', 'Richardson', 'Cox', 'Howard', 'Ward', 'Torres', 'Peterson', 'Gray', 'Ramirez', 'James', 'Watson', 'Brooks', 'Kelly', 'Sanders', 'Price', 'Bennett', 'Wood', 'Barnes', 'Ross', 'Henderson', 'Coleman', 'Jenkins', 'Perry', 'Powell', 'Long', 'Patterson', 'Hughes', 'Flores', 'Washington', 'Butler', 'Simmons', 'Foster', 'Gonzales', 'Bryant', 'Alexander', 'Russell', 'Griffin', 'Diaz', 'Hayes', 'Myers', 'Ford', 'Hamilton', 'Graham', 'Sullivan', 'Wallace', 'Woods', 'Cole', 'West', 'Jordan', 'Owens', 'Reynolds', 'Fisher', 'Ellis', 'Harrison', 'Gibson', 'McDonald', 'Cruz', 'Marshall', 'Ortiz', 'Gomez', 'Murray', 'Freeman', 'Wells', 'Webb', 'Simpson', 'Stevens', 'Tucker', 'Porter', 'Hunter', 'Hicks', 'Crawford', 'Henry', 'Boyd', 'Mason', 'Morales', 'Kennedy', 'Warren', 'Dixon', 'Ramos', 'Reyes', 'Burns', 'Gordon', 'Shaw', 'Holmes', 'Rice', 'Robertson', 'Hunt', 'Black', 'Daniels', 'Palmer', 'Mills', 'Nichols', 'Grant', 'Knight', 'Ferguson', 'Rose', 'Stone', 'Hawkins', 'Dunn', 'Perkins', 'Hudson', 'Spencer', 'Gardner', 'Stephens', 'Payne', 'Pierce', 'Berry', 'Matthews', 'Arnold', 'Wagner', 'Willis', 'Ray', 'Watkins', 'Olson', 'Carroll', 'Duncan', 'Snyder', 'Hart', 'Cunningham', 'Bradley', 'Lane', 'Andrews', 'Ruiz', 'Harper', 'Fox', 'Riley', 'Armstrong', 'Carpenter', 'Weaver', 'Greene', 'Lawrence', 'Elliott', 'Chavez', 'Sims', 'Austin', 'Peters', 'Kelley', 'Franklin', 'Lawson', 'Fields', 'Gutierrez', 'Ryan', 'Schmidt', 'Carr', 'Vasquez', 'Castillo', 'Wheeler', 'Chapman', 'Oliver', 'Montgomery', 'Richards', 'Williamson', 'Johnston', 'Banks', 'Meyer', 'Bishop', 'McCoy', 'Howell', 'Alvarez', 'Morrison', 'Hansen', 'Fernandez', 'Garza', 'Harvey', 'Little', 'Burton', 'Stanley', 'Nguyen', 'George', 'Jacobs', 'Reid', 'Kim', 'Fuller', 'Lynch', 'Dean', 'Gilbert', 'Garrett', 'Romero', 'Welch', 'Larson', 'Frazier', 'Burke', 'Hanson', 'Day', 'Mendoza', 'Moreno', 'Bowman', 'Medina', 'Fowler', 'Brewer', 'Hoffman', 'Carlson', 'Silva', 'Pearson', 'Holland', 'Douglas', 'Fleming', 'Jensen', 'Vargas', 'Byrd', 'Davidson', 'Hopkins', 'May', 'Terry', 'Herrera', 'Wade', 'Soto', 'Walters', 'Curtis', 'Neal', 'Caldwell', 'Lowe', 'Jennings', 'Barnett', 'Graves', 'Jimenez', 'Horton', 'Shelton', 'Barrett', 'Obrien', 'Castro', 'Sutton', 'Gregory', 'McKinney', 'Lucas', 'Miles', 'Craig', 'Rodriquez', 'Chambers', 'Holt', 'Lambert', 'Fletcher', 'Watts', 'Bates', 'Hale', 'Rhodes', 'Pena', 'Beck', 'Newman', 'Haynes', 'McDaniel', 'Mendez', 'Bush', 'Vaughn', 'Parks', 'Dawson', 'Santiago', 'Norris', 'Hardy', 'Love', 'Steele', 'Curry', 'Powers', 'Schultz', 'Barker', 'Guzman', 'Page', 'Munoz', 'Ball', 'Keller', 'Chandler', 'Weber', 'Leonard', 'Walsh', 'Lyons', 'Ramsey', 'Wolfe', 'Schneider', 'Mullins', 'Benson', 'Sharp', 'Bowen', 'Daniel', 'Barber', 'Cummings', 'Hines', 'Baldwin', 'Griffith', 'Valdez', 'Hubbard', 'Salazar', 'Reeves', 'Warner', 'Stevenson', 'Burgess', 'Santos', 'Tate', 'Cross', 'Garner', 'Mann', 'Mack', 'Moss', 'Thornton', 'Dennis', 'McGee', 'Farmer', 'Delgado', 'Aguilar', 'Vega', 'Glover', 'Manning', 'Cohen', 'Harmon', 'Rodgers', 'Robbins', 'Newton', 'Todd', 'Blair', 'Higgins', 'Ingram', 'Reese', 'Cannon', 'Strickland', 'Townsend', 'Potter', 'Goodwin', 'Walton', 'Rowe', 'Hampton', 'Ortega', 'Patton', 'Swanson', 'Joseph', 'Francis', 'Goodman', 'Maldonado', 'Yates', 'Becker', 'Erickson', 'Hodges', 'Rios', 'Conner', 'Adkins', 'Webster', 'Norman', 'Malone', 'Hammond', 'Flowers', 'Cobb', 'Moody', 'Quinn', 'Blake', 'Maxwell', 'Pope', 'Floyd', 'Osborne', 'Paul', 'McCarthy', 'Guerrero', 'Lindsey', 'Estrada', 'Sandoval', 'Gibbs', 'Tyler', 'Gross', 'Fitzgerald', 'Stokes', 'Doyle', 'Sherman', 'Saunders', 'Wise', 'Colon', 'Gill', 'Alvarado', 'Greer', 'Padilla', 'Simon', 'Waters', 'Nunez', 'Ballard', 'Schwartz', 'McBride', 'Houston', 'Christensen', 'Klein', 'Pratt', 'Briggs', 'Parsons', 'McLaughlin', 'Zimmerman', 'French', 'Buchanan', 'Moran', 'Copeland', 'Roy', 'Pittman', 'Brady', 'McCormick', 'Holloway', 'Brock', 'Poole', 'Frank', 'Logan', 'Owen', 'Bass', 'Marsh', 'Drake', 'Wong', 'Jefferson', 'Park', 'Morton', 'Abbott', 'Sparks', 'Patrick', 'Norton', 'Huff', 'Clayton', 'Massey', 'Lloyd', 'Figueroa', 'Carson', 'Bowers', 'Roberson', 'Barton', 'Tran', 'Lamb', 'Harrington', 'Casey', 'Boone', 'Cortez', 'Clarke', 'Mathis', 'Singleton', 'Wilkins', 'Cain', 'Bryan', 'Underwood', 'Hogan', 'McKenzie', 'Collier', 'Luna', 'Phelps', 'McGuire', 'Allison', 'Bridges', 'Wilkerson', 'Nash', 'Summers', 'Atkins'];
  
  	    Chance.prototype.last = function () {
  	        return this.pick(lastNames);
  	    };
  
  	    Chance.prototype.name = function (options) {
  	        options = initOptions(options);
  
  	        var first = this.first(),
  	            last = this.last(),
  	            name;
  
  	        if (options.middle) {
  	            name = first + ' ' + this.first() + ' ' + last;
  	        } else if (options.middle_initial) {
  	            name = first + ' ' + this.character({alpha: true, casing: 'upper'}) + '. ' + last;
  	        } else {
  	            name = first + ' ' + last;
  	        }
  
  	        if (options.prefix) {
  	            name = this.prefix() + ' ' + name;
  	        }
  
  	        return name;
  	    };
  
  	    Chance.prototype.name_prefixes = function () {
  	        return [
  	            {name: 'Doctor', abbreviation: 'Dr.'},
  	            {name: 'Miss', abbreviation: 'Miss'},
  	            {name: 'Misses', abbreviation: 'Mrs.'},
  	            {name: 'Mister', abbreviation: 'Mr.'}
  	        ];
  	    };
  
  	    // Alias for name_prefix
  	    Chance.prototype.prefix = function (options) {
  	        return this.name_prefix(options);
  	    };
  
  	    Chance.prototype.name_prefix = function (options) {
  	        options = initOptions(options);
  	        return options.full ?
  	            this.pick(this.name_prefixes()).name :
  	            this.pick(this.name_prefixes()).abbreviation;
  	    };
  
  	    // -- End Person --
  
  	    // -- Web --
  
  	    Chance.prototype.color = function (options) {
  	        function gray(value, delimiter) {
  	            return [value, value, value].join(delimiter || '');
  	        }
  
  	        options = initOptions(options, {format: this.pick(['hex', 'shorthex', 'rgb']), grayscale: false});
  	        var isGrayscale = options.grayscale;
  
  	        if (options.format === 'hex') {
  	            return '#' + (isGrayscale ? gray(this.hash({length: 2})) : this.hash({length: 6}));
  	        }
  
  	        if (options.format === 'shorthex') {
  	            return '#' + (isGrayscale ? gray(this.hash({length: 1})) : this.hash({length: 3}));
  	        }
  
  	        if (options.format === 'rgb') {
  	            if (isGrayscale) {
  	                return 'rgb(' + gray(this.natural({max: 255}), ',') + ')';
  	            } else {
  	                return 'rgb(' + this.natural({max: 255}) + ',' + this.natural({max: 255}) + ',' + this.natural({max: 255}) + ')';
  	            }
  	        }
  
  	        throw new Error('Invalid format provided. Please provide one of "hex", "shorthex", or "rgb"');
  	    };
  
  	    Chance.prototype.domain = function (options) {
  	        options = initOptions(options);
  	        return this.word() + '.' + (options.tld || this.tld());
  	    };
  
  	    Chance.prototype.email = function (options) {
  	        options = initOptions(options);
  	        return this.word() + '@' + (options.domain || this.domain());
  	    };
  
  	    Chance.prototype.fbid = function () {
  	        return parseInt('10000' + this.natural({max: 100000000000}), 10);
  	    };
  
  	    Chance.prototype.hashtag = function () {
  	        return '#' + this.word();
  	    };
  
  	    Chance.prototype.ip = function () {
  	        // Todo: This could return some reserved IPs. See http://vq.io/137dgYy
  	        // this should probably be updated to account for that rare as it may be
  	        return this.natural({max: 255}) + '.' +
  	               this.natural({max: 255}) + '.' +
  	               this.natural({max: 255}) + '.' +
  	               this.natural({max: 255});
  	    };
  
  	    Chance.prototype.ipv6 = function () {
  	        var ip_addr = "";
  
  	        for (var i = 0; i < 8; i++) {
  	            ip_addr += this.hash({length: 4}) + ':';
  	        }
  	        return ip_addr.substr(0, ip_addr.length - 1);
  	    };
  
  	    Chance.prototype.klout = function () {
  	        return this.natural({min: 1, max: 99});
  	    };
  
  	    Chance.prototype.tlds = function () {
  	        return ['com', 'org', 'edu', 'gov', 'co.uk', 'net', 'io'];
  	    };
  
  	    Chance.prototype.tld = function () {
  	        return this.pick(this.tlds());
  	    };
  
  	    Chance.prototype.twitter = function () {
  	        return '@' + this.word();
  	    };
  
  	    // -- End Web --
  
  	    // -- Address --
  
  	    Chance.prototype.address = function (options) {
  	        options = initOptions(options);
  	        return this.natural({min: 5, max: 2000}) + ' ' + this.street(options);
  	    };
  
  	    Chance.prototype.areacode = function (options) {
  	        options = initOptions(options, {parens : true});
  	        // Don't want area codes to start with 1, or have a 9 as the second digit
  	        var areacode = this.natural({min: 2, max: 9}).toString() + this.natural({min: 0, max: 8}).toString() + this.natural({min: 0, max: 9}).toString();
  	        return options.parens ? '(' + areacode + ')' : areacode;
  	    };
  
  	    Chance.prototype.city = function () {
  	        return this.capitalize(this.word({syllables: 3}));
  	    };
  
  	    Chance.prototype.coordinates = function (options) {
  	        options = initOptions(options);
  	        return this.latitude(options) + ', ' + this.longitude(options);
  	    };
  
  	    Chance.prototype.latitude = function (options) {
  	        options = initOptions(options, {fixed : 5});
  	        return this.floating({min: -90, max: 90, fixed: options.fixed});
  	    };
  
  	    Chance.prototype.longitude = function (options) {
  	        options = initOptions(options, {fixed : 5});
  	        return this.floating({min: 0, max: 180, fixed: options.fixed});
  	    };
  
  	    Chance.prototype.phone = function (options) {
  	        options = initOptions(options, {formatted : true});
  	        if (!options.formatted) {
  	            options.parens = false;
  	        }
  	        var areacode = this.areacode(options).toString();
  	        var exchange = this.natural({min: 2, max: 9}).toString() + this.natural({min: 0, max: 9}).toString() + this.natural({min: 0, max: 9}).toString();
  	        var subscriber = this.natural({min: 1000, max: 9999}).toString(); // this could be random [0-9]{4}
  	        return options.formatted ? areacode + ' ' + exchange + '-' + subscriber : areacode + exchange + subscriber;
  	    };
  
  	    Chance.prototype.postal = function () {
  	        // Postal District
  	        var pd = this.character({pool: "XVTSRPNKLMHJGECBA"});
  	        // Forward Sortation Area (FSA)
  	        var fsa = pd + this.natural({max: 9}) + this.character({alpha: true, casing: "upper"});
  	        // Local Delivery Unut (LDU)
  	        var ldu = this.natural({max: 9}) + this.character({alpha: true, casing: "upper"}) + this.natural({max: 9});
  
  	        return fsa + " " + ldu;
  	    };
  
  	    Chance.prototype.provinces = function () {
  	        return [
  	            {name: 'Alberta', abbreviation: 'AB'},
  	            {name: 'British Columbia', abbreviation: 'BC'},
  	            {name: 'Manitoba', abbreviation: 'MB'},
  	            {name: 'New Brunswick', abbreviation: 'NB'},
  	            {name: 'Newfoundland and Labrador', abbreviation: 'NL'},
  	            {name: 'Nova Scotia', abbreviation: 'NS'},
  	            {name: 'Ontario', abbreviation: 'ON'},
  	            {name: 'Prince Edward Island', abbreviation: 'PE'},
  	            {name: 'Quebec', abbreviation: 'QC'},
  	            {name: 'Saskatchewan', abbreviation: 'SK'},
  
  	            // The case could be made that the following are not actually provinces
  	            // since they are technically considered "territories" however they all
  	            // look the same on an envelope!
  	            {name: 'Northwest Territories', abbreviation: 'NT'},
  	            {name: 'Nunavut', abbreviation: 'NU'},
  	            {name: 'Yukon', abbreviation: 'YT'}
  	        ];
  	    };
  
  	    Chance.prototype.province = function (options) {
  	        return (options && options.full) ?
  	            this.pick(this.provinces()).name :
  	            this.pick(this.provinces()).abbreviation;
  	    };
  
  	    Chance.prototype.radio = function (options) {
  	        // Initial Letter (Typically Designated by Side of Mississippi River)
  	        options = initOptions(options, {side : "?"});
  	        var fl = "";
  	        switch (options.side.toLowerCase()) {
  	        case "east":
  	        case "e":
  	            fl = "W";
  	            break;
  	        case "west":
  	        case "w":
  	            fl = "K";
  	            break;
  	        default:
  	            fl = this.character({pool: "KW"});
  	            break;
  	        }
  
  	        return fl + this.character({alpha: true, casing: "upper"}) + this.character({alpha: true, casing: "upper"}) + this.character({alpha: true, casing: "upper"});
  	    };
  
  	    Chance.prototype.state = function (options) {
  	        return (options && options.full) ?
  	            this.pick(this.states()).name :
  	            this.pick(this.states()).abbreviation;
  	    };
  
  	    Chance.prototype.states = function () {
  	        return [
  	            {name: 'Alabama', abbreviation: 'AL'},
  	            {name: 'Alaska', abbreviation: 'AK'},
  	            {name: 'American Samoa', abbreviation: 'AS'},
  	            {name: 'Arizona', abbreviation: 'AZ'},
  	            {name: 'Arkansas', abbreviation: 'AR'},
  	            {name: 'Armed Forces Europe', abbreviation: 'AE'},
  	            {name: 'Armed Forces Pacific', abbreviation: 'AP'},
  	            {name: 'Armed Forces the Americas', abbreviation: 'AA'},
  	            {name: 'California', abbreviation: 'CA'},
  	            {name: 'Colorado', abbreviation: 'CO'},
  	            {name: 'Connecticut', abbreviation: 'CT'},
  	            {name: 'Delaware', abbreviation: 'DE'},
  	            {name: 'District of Columbia', abbreviation: 'DC'},
  	            {name: 'Federated States of Micronesia', abbreviation: 'FM'},
  	            {name: 'Florida', abbreviation: 'FL'},
  	            {name: 'Georgia', abbreviation: 'GA'},
  	            {name: 'Guam', abbreviation: 'GU'},
  	            {name: 'Hawaii', abbreviation: 'HI'},
  	            {name: 'Idaho', abbreviation: 'ID'},
  	            {name: 'Illinois', abbreviation: 'IL'},
  	            {name: 'Indiana', abbreviation: 'IN'},
  	            {name: 'Iowa', abbreviation: 'IA'},
  	            {name: 'Kansas', abbreviation: 'KS'},
  	            {name: 'Kentucky', abbreviation: 'KY'},
  	            {name: 'Louisiana', abbreviation: 'LA'},
  	            {name: 'Maine', abbreviation: 'ME'},
  	            {name: 'Marshall Islands', abbreviation: 'MH'},
  	            {name: 'Maryland', abbreviation: 'MD'},
  	            {name: 'Massachusetts', abbreviation: 'MA'},
  	            {name: 'Michigan', abbreviation: 'MI'},
  	            {name: 'Minnesota', abbreviation: 'MN'},
  	            {name: 'Mississippi', abbreviation: 'MS'},
  	            {name: 'Missouri', abbreviation: 'MO'},
  	            {name: 'Montana', abbreviation: 'MT'},
  	            {name: 'Nebraska', abbreviation: 'NE'},
  	            {name: 'Nevada', abbreviation: 'NV'},
  	            {name: 'New Hampshire', abbreviation: 'NH'},
  	            {name: 'New Jersey', abbreviation: 'NJ'},
  	            {name: 'New Mexico', abbreviation: 'NM'},
  	            {name: 'New York', abbreviation: 'NY'},
  	            {name: 'North Carolina', abbreviation: 'NC'},
  	            {name: 'North Dakota', abbreviation: 'ND'},
  	            {name: 'Northern Mariana Islands', abbreviation: 'MP'},
  	            {name: 'Ohio', abbreviation: 'OH'},
  	            {name: 'Oklahoma', abbreviation: 'OK'},
  	            {name: 'Oregon', abbreviation: 'OR'},
  	            {name: 'Pennsylvania', abbreviation: 'PA'},
  	            {name: 'Puerto Rico', abbreviation: 'PR'},
  	            {name: 'Rhode Island', abbreviation: 'RI'},
  	            {name: 'South Carolina', abbreviation: 'SC'},
  	            {name: 'South Dakota', abbreviation: 'SD'},
  	            {name: 'Tennessee', abbreviation: 'TN'},
  	            {name: 'Texas', abbreviation: 'TX'},
  	            {name: 'Utah', abbreviation: 'UT'},
  	            {name: 'Vermont', abbreviation: 'VT'},
  	            {name: 'Virgin Islands, U.S.', abbreviation: 'VI'},
  	            {name: 'Virginia', abbreviation: 'VA'},
  	            {name: 'Washington', abbreviation: 'WA'},
  	            {name: 'West Virginia', abbreviation: 'WV'},
  	            {name: 'Wisconsin', abbreviation: 'WI'},
  	            {name: 'Wyoming', abbreviation: 'WY'}
  	        ];
  	    };
  
  	    Chance.prototype.street = function (options) {
  	        options = initOptions(options);
  
  	        var street = this.word({syllables: 2});
  	        street = this.capitalize(street);
  	        street += ' ';
  	        street += options.short_suffix ?
  	            this.street_suffix().abbreviation :
  	            this.street_suffix().name;
  	        return street;
  	    };
  
  	    Chance.prototype.street_suffix = function () {
  	        return this.pick(this.street_suffixes());
  	    };
  
  	    Chance.prototype.street_suffixes = function () {
  	        // These are the most common suffixes.
  	        return [
  	            {name: 'Avenue', abbreviation: 'Ave'},
  	            {name: 'Boulevard', abbreviation: 'Blvd'},
  	            {name: 'Center', abbreviation: 'Ctr'},
  	            {name: 'Circle', abbreviation: 'Cir'},
  	            {name: 'Court', abbreviation: 'Ct'},
  	            {name: 'Drive', abbreviation: 'Dr'},
  	            {name: 'Extension', abbreviation: 'Ext'},
  	            {name: 'Glen', abbreviation: 'Gln'},
  	            {name: 'Grove', abbreviation: 'Grv'},
  	            {name: 'Heights', abbreviation: 'Hts'},
  	            {name: 'Highway', abbreviation: 'Hwy'},
  	            {name: 'Junction', abbreviation: 'Jct'},
  	            {name: 'Key', abbreviation: 'Key'},
  	            {name: 'Lane', abbreviation: 'Ln'},
  	            {name: 'Loop', abbreviation: 'Loop'},
  	            {name: 'Manor', abbreviation: 'Mnr'},
  	            {name: 'Mill', abbreviation: 'Mill'},
  	            {name: 'Park', abbreviation: 'Park'},
  	            {name: 'Parkway', abbreviation: 'Pkwy'},
  	            {name: 'Pass', abbreviation: 'Pass'},
  	            {name: 'Path', abbreviation: 'Path'},
  	            {name: 'Pike', abbreviation: 'Pike'},
  	            {name: 'Place', abbreviation: 'Pl'},
  	            {name: 'Plaza', abbreviation: 'Plz'},
  	            {name: 'Point', abbreviation: 'Pt'},
  	            {name: 'Ridge', abbreviation: 'Rdg'},
  	            {name: 'River', abbreviation: 'Riv'},
  	            {name: 'Road', abbreviation: 'Rd'},
  	            {name: 'Square', abbreviation: 'Sq'},
  	            {name: 'Street', abbreviation: 'St'},
  	            {name: 'Terrace', abbreviation: 'Ter'},
  	            {name: 'Trail', abbreviation: 'Trl'},
  	            {name: 'Turnpike', abbreviation: 'Tpke'},
  	            {name: 'View', abbreviation: 'Vw'},
  	            {name: 'Way', abbreviation: 'Way'}
  	        ];
  	    };
  
  	    Chance.prototype.tv = function (options) {
  	        return this.radio(options);
  	    };
  
  	    // Note: only returning US zip codes, internationalization will be a whole
  	    // other beast to tackle at some point.
  	    Chance.prototype.zip = function (options) {
  	        var zip = "";
  
  	        for (var i = 0; i < 5; i++) {
  	            zip += this.natural({max: 9}).toString();
  	        }
  
  	        if (options && options.plusfour === true) {
  	            zip += '-';
  	            for (i = 0; i < 4; i++) {
  	                zip += this.natural({max: 9}).toString();
  	            }
  	        }
  
  	        return zip;
  	    };
  
  	    // -- End Address --
  
  	    // -- Time
  
  	    Chance.prototype.ampm = function () {
  	        return this.bool() ? 'am' : 'pm';
  	    };
  
  	    Chance.prototype.date = function (options) {
  	        var m = this.month({raw: true}),
  	            date_string;
  
  	        options = initOptions(options, {
  	            year: parseInt(this.year(), 10),
  	            // Necessary to subtract 1 because Date() 0-indexes month but not day or year
  	            // for some reason.
  	            month: m.numeric - 1,
  	            day: this.natural({min: 1, max: m.days}),
  	            hour: this.hour(),
  	            minute: this.minute(),
  	            second: this.second(),
  	            millisecond: this.millisecond(),
  	            american: true,
  	            string: false
  	        });
  
  	        var date = new Date(options.year, options.month, options.day, options.hour, options.minute, options.second, options.millisecond);
  
  	        if (options.american) {
  	            // Adding 1 to the month is necessary because Date() 0-indexes
  	            // months but not day for some odd reason.
  	            date_string = (date.getMonth() + 1) + '/' + date.getDate() + '/' + date.getFullYear();
  	        } else {
  	            date_string = date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear();
  	        }
  
  	        return options.string ? date_string : date;
  	    };
  
  	    Chance.prototype.hammertime = function (options) {
  	        return this.date(options).getTime();
  	    };
  
  	    Chance.prototype.hour = function (options) {
  	        options = initOptions(options);
  	        var max = options.twentyfour ? 24 : 12;
  	        return this.natural({min: 1, max: max});
  	    };
  
  	    Chance.prototype.millisecond = function () {
  	        return this.natural({max: 999});
  	    };
  
  	    Chance.prototype.minute = Chance.prototype.second = function () {
  	        return this.natural({max: 59});
  	    };
  
  	    Chance.prototype.month = function (options) {
  	        options = initOptions(options);
  	        var month = this.pick(this.months());
  	        return options.raw ? month : month.name;
  	    };
  
  	    Chance.prototype.months = function () {
  	        return [
  	            {name: 'January', short_name: 'Jan', numeric: '01', days: 31},
  	            // Not messing with leap years...
  	            {name: 'February', short_name: 'Feb', numeric: '02', days: 28},
  	            {name: 'March', short_name: 'Mar', numeric: '03', days: 31},
  	            {name: 'April', short_name: 'Apr', numeric: '04', days: 30},
  	            {name: 'May', short_name: 'May', numeric: '05', days: 31},
  	            {name: 'June', short_name: 'Jun', numeric: '06', days: 30},
  	            {name: 'July', short_name: 'Jul', numeric: '07', days: 31},
  	            {name: 'August', short_name: 'Aug', numeric: '08', days: 31},
  	            {name: 'September', short_name: 'Sep', numeric: '09', days: 30},
  	            {name: 'October', short_name: 'Oct', numeric: '10', days: 31},
  	            {name: 'November', short_name: 'Nov', numeric: '11', days: 30},
  	            {name: 'December', short_name: 'Dec', numeric: '12', days: 31}
  	        ];
  	    };
  
  	    Chance.prototype.second = function () {
  	        return this.natural({max: 59});
  	    };
  
  	    Chance.prototype.timestamp = function () {
  	        return this.natural({min: 1, max: parseInt(new Date().getTime() / 1000, 10)});
  	    };
  
  	    Chance.prototype.year = function (options) {
  	        // Default to current year as min if none specified
  	        options = initOptions(options, {min: new Date().getFullYear()});
  
  	        // Default to one century after current year as max if none specified
  	        options.max = (typeof options.max !== "undefined") ? options.max : options.min + 100;
  
  	        return this.natural(options).toString();
  	    };
  
  	    // -- End Time
  
  	    // -- Finance --
  
  	    Chance.prototype.cc = function (options) {
  	        options = initOptions(options);
  
  	        var type, number, to_generate, type_name;
  
  	        type = (options.type) ?
  	                    this.cc_type({ name: options.type, raw: true }) :
  	                    this.cc_type({ raw: true });
  	        number = type.prefix.split("");
  	        to_generate = type.length - type.prefix.length - 1;
  
  	        // Generates n - 1 digits
  	        for (var i = 0; i < to_generate; i++) {
  	            number.push(this.integer({min: 0, max: 9}));
  	        }
  
  	        // Generates the last digit according to Luhn algorithm
  	        number.push(this.luhn_calculate(number.join("")));
  
  	        return number.join("");
  	    };
  
  	    Chance.prototype.cc_types = function () {
  	        // http://en.wikipedia.org/wiki/Bank_card_number#Issuer_identification_number_.28IIN.29
  	        return [
  	            {name: "American Express", short_name: 'amex', prefix: '34', length: 15},
  	            {name: "Bankcard", short_name: 'bankcard', prefix: '5610', length: 16},
  	            {name: "China UnionPay", short_name: 'chinaunion', prefix: '62', length: 16},
  	            {name: "Diners Club Carte Blanche", short_name: 'dccarte', prefix: '300', length: 14},
  	            {name: "Diners Club enRoute", short_name: 'dcenroute', prefix: '2014', length: 15},
  	            {name: "Diners Club International", short_name: 'dcintl', prefix: '36', length: 14},
  	            {name: "Diners Club United States & Canada", short_name: 'dcusc', prefix: '54', length: 16},
  	            {name: "Discover Card", short_name: 'discover', prefix: '6011', length: 16},
  	            {name: "InstaPayment", short_name: 'instapay', prefix: '637', length: 16},
  	            {name: "JCB", short_name: 'jcb', prefix: '3528', length: 16},
  	            {name: "Laser", short_name: 'laser', prefix: '6304', length: 16},
  	            {name: "Maestro", short_name: 'maestro', prefix: '5018', length: 16},
  	            {name: "Mastercard", short_name: 'mc', prefix: '51', length: 16},
  	            {name: "Solo", short_name: 'solo', prefix: '6334', length: 16},
  	            {name: "Switch", short_name: 'switch', prefix: '4903', length: 16},
  	            {name: "Visa", short_name: 'visa', prefix: '4', length: 16},
  	            {name: "Visa Electron", short_name: 'electron', prefix: '4026', length: 16}
  	        ];
  	    };
  
  	    Chance.prototype.cc_type = function (options) {
  	        options = initOptions(options);
  	        var types = this.cc_types(),
  	            type = null;
  
  	        if (options.name) {
  	            for (var i = 0; i < types.length; i++) {
  	                // Accept either name or short_name to specify card type
  	                if (types[i].name === options.name || types[i].short_name === options.name) {
  	                    type = types[i];
  	                    break;
  	                }
  	            }
  	            if (type === null) {
  	                throw new Error("Credit card type '" + options.name + "'' is not suppoted");
  	            }
  	        } else {
  	            type = this.pick(types);
  	        }
  
  	        return options.raw ? type : type.name;
  	    };
  
  	    Chance.prototype.dollar = function (options) {
  	        // By default, a somewhat more sane max for dollar than all available numbers
  	        options = initOptions(options, {max : 10000, min : 0});
  
  	        var dollar = this.floating({min: options.min, max: options.max, fixed: 2}).toString(),
  	            cents = dollar.split('.')[1];
  
  	        if (cents === undefined) {
  	            dollar += '.00';
  	        } else if (cents.length < 2) {
  	            dollar = dollar + '0';
  	        }
  
  	        if (dollar < 0) {
  	            return '-$' + dollar.replace('-', '');
  	        } else {
  	            return '$' + dollar;
  	        }
  	    };
  
  	    Chance.prototype.exp = function (options) {
  	        options = initOptions(options);
  	        var exp = {};
  
  	        exp.year = this.exp_year();
  
  	        // If the year is this year, need to ensure month is greater than the
  	        // current month or this expiration will not be valid
  	        if (exp.year === (new Date().getFullYear())) {
  	            exp.month = this.exp_month({future: true});
  	        } else {
  	            exp.month = this.exp_month();
  	        }
  
  	        return options.raw ? exp : exp.month + '/' + exp.year;
  	    };
  
  	    Chance.prototype.exp_month = function (options) {
  	        options = initOptions(options);
  	        var month, month_int;
  
  	        if (options.future) {
  	            do {
  	                month = this.month({raw: true}).numeric;
  	                month_int = parseInt(month, 10);
  	            } while (month_int < new Date().getMonth());
  	        } else {
  	            month = this.month({raw: true}).numeric;
  	        }
  
  	        return month;
  	    };
  
  	    Chance.prototype.exp_year = function () {
  	        return this.year({max: new Date().getFullYear() + 10});
  	    };
  
  	    // -- End Finance
  
  	    // -- Miscellaneous --
  
  	    // Dice - For all the board game geeks out there, myself included ;)
  	    Chance.prototype.d4 = function () { return this.natural({min: 1, max: 4}); };
  	    Chance.prototype.d6 = function () { return this.natural({min: 1, max: 6}); };
  	    Chance.prototype.d8 = function () { return this.natural({min: 1, max: 8}); };
  	    Chance.prototype.d10 = function () { return this.natural({min: 1, max: 10}); };
  	    Chance.prototype.d12 = function () { return this.natural({min: 1, max: 12}); };
  	    Chance.prototype.d20 = function () { return this.natural({min: 1, max: 20}); };
  	    Chance.prototype.d30 = function () { return this.natural({min: 1, max: 30}); };
  	    Chance.prototype.d100 = function () { return this.natural({min: 1, max: 100}); };
  	    Chance.prototype.rpg = function (thrown, options) {
  	        options = initOptions(options);
  	        if (thrown === null) {
  	            throw new Error("A type of die roll must be included");
  	        } else {
  	            var bits = thrown.toLowerCase().split("d"),
  	                rolls = [];
  
  	            if (bits.length !== 2 || !parseInt(bits[0], 10) || !parseInt(bits[1], 10)) {
  	                throw new Error("Invalid format provided. Please provide #d# where the first # is the number of dice to roll, the second # is the max of each die");
  	            }
  	            for (var i = bits[0]; i > 0; i--) {
  	                rolls[i - 1] = this.natural({min: 1, max: bits[1]});
  	            }
  	            return (typeof options.sum !== 'undefined' && options.sum) ? rolls.reduce(function (p, c) { return p + c; }) : rolls;
  	        }
  	    };
  
  	    // Guid
  	    Chance.prototype.guid = function (options) {
  	        options = options || {version: 5};
  	        
  	        var guid_pool = "ABCDEF1234567890",
  	            variant_pool = "AB89",
  	            guid = this.string({pool: guid_pool, length: 8}) + '-' +
  	                   this.string({pool: guid_pool, length: 4}) + '-' +
  	                   // The Version
  	                   options.version +
  	                   this.string({pool: guid_pool, length: 3}) + '-' +
  	                   // The Variant
  	                   this.string({pool: variant_pool, length: 1}) +
  	                   this.string({pool: guid_pool, length: 3}) + '-' +
  	                   this.string({pool: guid_pool, length: 12});
  	        return guid;
  	    };
  
  	    // Hash
  	    Chance.prototype.hash = function (options) {
  	        options = initOptions(options, {length : 40, casing: 'lower'});
  	        var pool = options.casing === 'upper' ? HEX_POOL.toUpperCase() : HEX_POOL;
  	        return this.string({pool: pool, length: options.length});
  	    };
  
  	    Chance.prototype.luhn_check = function (num) {
  	        var str = num.toString();
  	        var checkDigit = +str.substring(str.length - 1);
  	        return checkDigit === this.luhn_calculate(+str.substring(0, str.length - 1));
  	    };
  
  	    Chance.prototype.luhn_calculate = function (num) {
  	        var digits = num.toString().split("").reverse();
  	        var sum = 0;
  	        for (var i = 0, l = digits.length; l > i; ++i) {
  	            var digit = +digits[i];
  	            if (i % 2 === 0) {
  	                digit *= 2;
  	                if (digit > 9) {
  	                    digit -= 9;
  	                }
  	            }
  	            sum += digit;
  	        }
  	        return (sum * 9) % 10;
  	    };
  
  	    Chance.prototype.mersenne_twister = function (seed) {
  	        return new MersenneTwister(seed);
  	    };
  
  	    // -- End Miscellaneous --
  
  	    Chance.prototype.VERSION = "0.5.4";
  
  	    // Mersenne Twister from https://gist.github.com/banksean/300494
  	    var MersenneTwister = function (seed) {
  	        if (seed === undefined) {
  	            seed = new Date().getTime();
  	        }
  	        /* Period parameters */
  	        this.N = 624;
  	        this.M = 397;
  	        this.MATRIX_A = 0x9908b0df;   /* constant vector a */
  	        this.UPPER_MASK = 0x80000000; /* most significant w-r bits */
  	        this.LOWER_MASK = 0x7fffffff; /* least significant r bits */
  
  	        this.mt = new Array(this.N); /* the array for the state vector */
  	        this.mti = this.N + 1; /* mti==N + 1 means mt[N] is not initialized */
  
  	        this.init_genrand(seed);
  	    };
  
  	    /* initializes mt[N] with a seed */
  	    MersenneTwister.prototype.init_genrand = function (s) {
  	        this.mt[0] = s >>> 0;
  	        for (this.mti = 1; this.mti < this.N; this.mti++) {
  	            s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30);
  	            this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253) + this.mti;
  	            /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
  	            /* In the previous versions, MSBs of the seed affect   */
  	            /* only MSBs of the array mt[].                        */
  	            /* 2002/01/09 modified by Makoto Matsumoto             */
  	            this.mt[this.mti] >>>= 0;
  	            /* for >32 bit machines */
  	        }
  	    };
  
  	    /* initialize by an array with array-length */
  	    /* init_key is the array for initializing keys */
  	    /* key_length is its length */
  	    /* slight change for C++, 2004/2/26 */
  	    MersenneTwister.prototype.init_by_array = function (init_key, key_length) {
  	        var i = 1, j = 0, k, s;
  	        this.init_genrand(19650218);
  	        k = (this.N > key_length ? this.N : key_length);
  	        for (; k; k--) {
  	            s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);
  	            this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1664525) << 16) + ((s & 0x0000ffff) * 1664525))) + init_key[j] + j; /* non linear */
  	            this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
  	            i++;
  	            j++;
  	            if (i >= this.N) { this.mt[0] = this.mt[this.N - 1]; i = 1; }
  	            if (j >= key_length) { j = 0; }
  	        }
  	        for (k = this.N - 1; k; k--) {
  	            s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30);
  	            this.mt[i] = (this.mt[i] ^ (((((s & 0xffff0000) >>> 16) * 1566083941) << 16) + (s & 0x0000ffff) * 1566083941)) - i; /* non linear */
  	            this.mt[i] >>>= 0; /* for WORDSIZE > 32 machines */
  	            i++;
  	            if (i >= this.N) { this.mt[0] = this.mt[this.N - 1]; i = 1; }
  	        }
  
  	        this.mt[0] = 0x80000000; /* MSB is 1; assuring non-zero initial array */
  	    };
  
  	    /* generates a random number on [0,0xffffffff]-interval */
  	    MersenneTwister.prototype.genrand_int32 = function () {
  	        var y;
  	        var mag01 = new Array(0x0, this.MATRIX_A);
  	        /* mag01[x] = x * MATRIX_A  for x=0,1 */
  
  	        if (this.mti >= this.N) { /* generate N words at one time */
  	            var kk;
  
  	            if (this.mti === this.N + 1) {   /* if init_genrand() has not been called, */
  	                this.init_genrand(5489); /* a default initial seed is used */
  	            }
  	            for (kk = 0; kk < this.N - this.M; kk++) {
  	                y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk + 1]&this.LOWER_MASK);
  	                this.mt[kk] = this.mt[kk + this.M] ^ (y >>> 1) ^ mag01[y & 0x1];
  	            }
  	            for (;kk < this.N - 1; kk++) {
  	                y = (this.mt[kk]&this.UPPER_MASK)|(this.mt[kk + 1]&this.LOWER_MASK);
  	                this.mt[kk] = this.mt[kk + (this.M - this.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
  	            }
  	            y = (this.mt[this.N - 1]&this.UPPER_MASK)|(this.mt[0]&this.LOWER_MASK);
  	            this.mt[this.N - 1] = this.mt[this.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];
  
  	            this.mti = 0;
  	        }
  
  	        y = this.mt[this.mti++];
  
  	        /* Tempering */
  	        y ^= (y >>> 11);
  	        y ^= (y << 7) & 0x9d2c5680;
  	        y ^= (y << 15) & 0xefc60000;
  	        y ^= (y >>> 18);
  
  	        return y >>> 0;
  	    };
  
  	    /* generates a random number on [0,0x7fffffff]-interval */
  	    MersenneTwister.prototype.genrand_int31 = function () {
  	        return (this.genrand_int32() >>> 1);
  	    };
  
  	    /* generates a random number on [0,1]-real-interval */
  	    MersenneTwister.prototype.genrand_real1 = function () {
  	        return this.genrand_int32() * (1.0 / 4294967295.0);
  	        /* divided by 2^32-1 */
  	    };
  
  	    /* generates a random number on [0,1)-real-interval */
  	    MersenneTwister.prototype.random = function () {
  	        return this.genrand_int32() * (1.0 / 4294967296.0);
  	        /* divided by 2^32 */
  	    };
  
  	    /* generates a random number on (0,1)-real-interval */
  	    MersenneTwister.prototype.genrand_real3 = function () {
  	        return (this.genrand_int32() + 0.5) * (1.0 / 4294967296.0);
  	        /* divided by 2^32 */
  	    };
  
  	    /* generates a random number on [0,1) with 53-bit resolution*/
  	    MersenneTwister.prototype.genrand_res53 = function () {
  	        var a = this.genrand_int32()>>>5, b = this.genrand_int32()>>>6;
  	        return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
  	    };
  
  
  	    // CommonJS module
  	    if (true) {
  	        if (typeof module !== 'undefined' && module.exports) {
  	            exports = module.exports = Chance;
  	        }
  	        exports.Chance = Chance;
  	    }
  
  	    // Register as a named AMD module
  	    if (true) {
  	        !(__WEBPACK_AMD_DEFINE_RESULT__ = function () {
  	            return Chance;
  	        }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  	    }
  
  	    // If there is a window object, that at least has a document property,
  	    // instantiate and define chance on the window
  	    if (typeof window === "object" && typeof window.document === "object") {
  	        window.Chance = Chance;
  	        window.chance = new Chance();
  	    }
  	})();
  
  
  /***/ },
  /* 3 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * The clicker gremlin clicks anywhere on the visible area of the document
  	 *
  	 * The clicker gremlin triggers mouse events (click, dblclick, mousedown,
  	 * mouseup, mouseover, mouseover, mouseover, mousemove, and mouseout) on 
  	 * random targets displayed on the viewport.
  	 *
  	 * By default, the clicker gremlin activity is showed by a red circle.
  	 *
  	 *   var clickerGremlin = gremlins.species.clicker();
  	 *   horde.gremlin(clickerGremlin);
  	 *
  	 * The clicker gremlin can be customized as follows:
  	 *
  	 *   clickerGremlin.clickTypes(['click', 'mouseover']); // the mouse event types to trigger
  	 *   clickerGremlin.positionSelector(function() { // find a random pair of coordinates to click });
  	 *   clickerGremlin.showAction(function(x, y) { // show the gremlin activity on screen });
  	 *   clickerGremlin.canClick(function(element) { return true }); // to limit where the gremlin can click
  	 *   clickerGremlin.maxNbTries(5); // How many times the gremlin must look for a clickable element before quitting
  	 *   clickerGremlin.logger(loggerObject); // inject a logger
  	 *   clickerGremlin.randomizer(randomizerObject); // inject a randomizer
  	 *
  	 * Example usage:
  	 *
  	 *   horde.gremlin(gremlins.species.clicker()
  	 *     .clickTypes(['click'])
  	 *     .positionSelector(function() {
  	 *        // only click inside the foo element area
  	 *        var $el = $('#foo');
  	 *        var offset = $el.offset();
  	 *        return [
  	 *          parseInt(Math.random() * $el.outerWidth() + offset.left),
  	 *          parseInt(Math.random() * $el.outerHeight() + offset.top)
  	 *        ];
  	 *     })
  	 *     .canClick(function(element) {
  	 *       // only click elements in bar
  	 *       return $(element).parents('#bar').length;
  	 *       // when canClick returns false, the gremlin will look for another
  	 *       // element to click on until maxNbTries is reached
  	 *     })
  	 *     . showAction(function(x, y) {
  	 *       // do nothing (hide the gremlin action on screen)
  	 *     })
  	 *   );
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var configurable = __webpack_require__(4);
  	    var Chance = __webpack_require__(2);
  	    var RandomizerRequiredException = __webpack_require__(5);
  
  	    return function() {
  
  	        var document = window.document,
  	            body = document.body;
  
  	        var defaultClickTypes = ['click', 'click', 'click', 'click', 'click', 'click', 'dblclick', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseover', 'mouseover', 'mousemove', 'mouseout'];
  
  	        function defaultPositionSelector() {
  	            return [
  	                config.randomizer.natural({ max: document.documentElement.clientWidth - 1 }),
  	                config.randomizer.natural({ max: document.documentElement.clientHeight - 1 })
  	            ];
  	        }
  
  	        function defaultShowAction(x, y) {
  	            var clickSignal = document.createElement('div');
  	            clickSignal.style.zIndex = 2000;
  	            clickSignal.style.border = "3px solid red";
  	            clickSignal.style['border-radius'] = '50%'; // Chrome
  	            clickSignal.style.borderRadius = '50%';     // Mozilla
  	            clickSignal.style.width = "40px";
  	            clickSignal.style.height = "40px";
  	            clickSignal.style['box-sizing'] = 'border-box';
  	            clickSignal.style.position = "absolute";
  	            clickSignal.style.webkitTransition = 'opacity 1s ease-out';
  	            clickSignal.style.mozTransition = 'opacity 1s ease-out';
  	            clickSignal.style.transition = 'opacity 1s ease-out';
  	            clickSignal.style.left = (x - 20 ) + 'px';
  	            clickSignal.style.top = (y - 20 )+ 'px';
  	            var element = body.appendChild(clickSignal);
  	            setTimeout(function() {
  	                body.removeChild(element);
  	            }, 1000);
  	            setTimeout(function() {
  	                element.style.opacity = 0;
  	            }, 50);
  	        }
  
  	        function defaultCanClick() {
  	            return true;
  	        }
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            clickTypes:       defaultClickTypes,
  	            positionSelector: defaultPositionSelector,
  	            showAction:       defaultShowAction,
  	            canClick:         defaultCanClick,
  	            maxNbTries:       10,
  	            logger:           null,
  	            randomizer:       null
  	        };
  
  	        /**
  	         * @mixes config
  	         */
  	        function clickerGremlin() {
  	            if (!config.randomizer) {
  	                throw new RandomizerRequiredException();
  	            }
  	            var position, posX, posY, targetElement, nbTries = 0;
  	            do {
  	                position = config.positionSelector();
  	                posX = position[0];
  	                posY = position[1];
  	                targetElement = document.elementFromPoint(posX, posY);
  	                nbTries++;
  	                if (nbTries > config.maxNbTries) return false;
  	            } while (!targetElement || !config.canClick(targetElement));
  
  	            var evt = document.createEvent("MouseEvents");
  	            var clickType = config.randomizer.pick(config.clickTypes);
  	            evt.initMouseEvent(clickType, true, true, window, 0, 0, 0, posX, posY, false, false, false, false, 0, null);
  	            targetElement.dispatchEvent(evt);
  
  	            if (typeof config.showAction == 'function') {
  	                config.showAction(posX, posY, clickType);
  	            }
  
  	            if (config.logger && typeof config.logger.log == 'function') {
  	                config.logger.log('gremlin', 'clicker   ', clickType, 'at', posX, posY);
  	            }
  	        }
  
  	        configurable(clickerGremlin, config);
  
  	        return clickerGremlin;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 4 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    /**
  	     * Make a function configurable
  	     *
  	     * Configurable functions modify their configuration. The configuration
  	     * must be an object defined in the function closure.
  	     *
  	     *   var config = {
  	     *     foo: 1
  	     *   };
  	     *   function bar() {
  	     *      console.log('foo value is', config.foo);
  	     *   }
  	     *   bar(); // 'foo value is 1'
  	     *   config.foo = 3;     
  	     *   bar(); // 'foo value is 3'
  	     *
  	     * The configurable behavior modifies the function object, adding one
  	     * method for each item in the configuration.
  	     * 
  	     * The added methods use the same name as the configuration items. The
  	     * added methods are both setters and getters, which means that they return
  	     * the config value when called without argument, and they modify the 
  	     * config value when called with an argument.
  	     *
  	     *   configurable(bar, config);
  	     *   // Now bar has a foo() method
  	     *
  	     *   bar.foo(2)
  	     *   bar(); // 'foo value is 2'
  	     *   bar.foo(); // 2
  	     *
  	     * @param {Function} targetFunction - The functions to make configurable
  	     * @param {Object} config - The configuration object with the default config values
  	     */
  	    function configurable(targetFunction, config) {
  	        for (var item in config) {
  	            (function(item) {
  	                targetFunction[item] = function(value) {
  	                    if (!arguments.length) return config[item];
  	                    config[item] = value;
  	                    return targetFunction;
  	                };
  	            })(item); // for doesn't create a closure, forcing it
  	        }
  	    }
  
  	    return configurable;
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 5 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    function RandomizerRequiredException() {
  	        this.message = 'This gremlin requires a randomizer to run. Please call randomizer(randomizerObject) before executing the gremlin';
  	        this.toString = function() {
  	            return this.message;
  	        };
  	    }
  
  	    return RandomizerRequiredException;
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 6 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * The toucher gremlin touches anywhere on the visible area of the document.
  	 *
  	 * The toucher gremlin triggers touch events (touchstart, touchmove, touchcancel
  	 * and touchend), by doing gestures on random targets displayed on the viewport.
  	 * Touch gestures can last several seconds, so this gremlin isn't instantaneous.
  	 *
  	 * By default, the touch gremlin activity is showed by a red disc.
  	 *
  	 *   var toucherGremlin = gremlins.species.toucher();
  	 *   horde.gremlin(toucherGremlin);
  	 *
  	 * The toucher gremlin can be customized as follows:
  	 *
  	 *   toucherGremlin.touchTypes(['tap', 'gesture']); // the mouse event types to trigger
  	 *   toucherGremlin.positionSelector(function() { // find a random pair of coordinates to touch });
  	 *   toucherGremlin.showAction(function(x, y) { // show the gremlin activity on screen });
  	 *   toucherGremlin.canTouch(function(element) { return true }); // to limit where the gremlin can touch
  	 *   toucherGremlin.maxNbTries(5); // How many times the gremlin must look for a touchable element before quitting
  	 *   toucherGremlin.logger(loggerObject); // inject a logger
  	 *   toucherGremlin.randomizer(randomizerObject); // inject a randomizer
  	 *
  	 * Example usage:
  	 *
  	 *   horde.gremlin(gremlins.species.toucher()
  	 *     .touchTypes(['gesture'])
  	 *     .positionSelector(function() {
  	 *        // only touch inside the foo element area
  	 *        var $el = $('#foo');
  	 *        var offset = $el.offset();
  	 *        return [
  	 *          parseInt(Math.random() * $el.outerWidth() + offset.left),
  	 *          parseInt(Math.random() * $el.outerHeight() + offset.top)
  	 *        ];
  	 *     })
  	 *     . showAction(function(x, y) {
  	 *       // do nothing (hide the gremlin action on screen)
  	 *     })
  	 *   );
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var configurable = __webpack_require__(4);
  	    var Chance = __webpack_require__(2);
  	    var RandomizerRequiredException = __webpack_require__(5);
  
  	    return function() {
  
  	        var document = window.document,
  	            body = document.body;
  
  	        var defaultTouchTypes = ['tap', 'tap', 'tap', 'doubletap', 'gesture', 'gesture', 'gesture', 'multitouch', 'multitouch'];
  
  	        function defaultPositionSelector() {
  	            return [
  	                config.randomizer.natural({ max: document.documentElement.clientWidth - 1 }),
  	                config.randomizer.natural({ max: document.documentElement.clientHeight - 1 })
  	            ];
  	        }
  
  	        function defaultShowAction(touches) {
  	            var fragment = document.createDocumentFragment();
  	            touches.forEach(function(touch) {
  	                var touchSignal = document.createElement('div');
  	                touchSignal.style.zIndex = 2000;
  	                touchSignal.style.background = "red";
  	                touchSignal.style['border-radius'] = '50%'; // Chrome
  	                touchSignal.style.borderRadius = '50%';     // Mozilla
  	                touchSignal.style.width = "20px";
  	                touchSignal.style.height = "20px";
  	                touchSignal.style.position = "absolute";
  	                touchSignal.style.webkitTransition = 'opacity .5s ease-out';
  	                touchSignal.style.mozTransition = 'opacity .5s ease-out';
  	                touchSignal.style.transition = 'opacity .5s ease-out';
  	                touchSignal.style.left = (touch.x - 10 ) + 'px';
  	                touchSignal.style.top = (touch.y - 10 ) + 'px';
  
  	                var element = fragment.appendChild(touchSignal);
  	                setTimeout(function() {
  	                    body.removeChild(element);
  	                }, 500);
  	                setTimeout(function() {
  	                    element.style.opacity = 0;
  	                }, 50);
  	            });
  	            document.body.appendChild(fragment);
  	        }
  
  	        function defaultCanTouch() {
  	            return true;
  	        }
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            touchTypes: defaultTouchTypes,
  	            positionSelector: defaultPositionSelector,
  	            showAction: defaultShowAction,
  	            canTouch: defaultCanTouch,
  	            maxNbTries: 10,
  	            logger: null,
  	            randomizer: null,
  	            maxTouches: 2
  	        };
  
  	        /**
  	         * generate a list of x/y around the center
  	         * @param center
  	         * @param points
  	         * @param [radius=100]
  	         * @param [rotation=0]
  	         */
  	        function getTouches(center, points, radius, degrees) {
  	            var cx = center[0],
  	                cy = center[1],
  	                touches = [],
  	                slice, i, angle;
  
  	            // just one touch, at the center
  	            if (points === 1) {
  	                return [{ x: cx, y: cy }];
  	            }
  
  	            radius = radius || 100;
  	            degrees = degrees !== null ? (degrees * Math.PI / 180) : 0;
  	            slice = 2 * Math.PI / points;
  
  	            for (i = 0; i < points; i++) {
  	                angle = (slice * i) + degrees;
  	                touches.push({
  	                    x: (cx + radius * Math.cos(angle)),
  	                    y: (cy + radius * Math.sin(angle))
  	                });
  	            }
  	            return touches;
  	        }
  
  
  	        /**
  	         * trigger a touchevent
  	         * @param touches
  	         * @param element
  	         * @param type
  	         */
  	        function triggerTouch(touches, element, type) {
  	            var touchlist = [],
  	                event = document.createEvent('Event');
  
  	            event.initEvent('touch' + type, true, true);
  
  	            touchlist.identifiedTouch = touchlist.item = function(index) {
  	                return this[index] || {};
  	            };
  
  	            touches.forEach(function(touch, i) {
  	                var x = Math.round(touch.x),
  	                    y = Math.round(touch.y);
  	                touchlist.push({
  	                    pageX: x,
  	                    pageY: y,
  	                    clientX: x,
  	                    clientY: y,
  	                    screenX: x,
  	                    screenY: y,
  	                    target: element,
  	                    identifier: i
  	                });
  	            });
  
  	            event.touches = (type == 'end') ? [] : touchlist;
  	            event.targetTouches = (type == 'end') ? [] : touchlist;
  	            event.changedTouches = touchlist;
  
  	            element.dispatchEvent(event);
  	            config.showAction(touches);
  	        }
  
  	        /**
  	         * trigger a gesture
  	         * @param element
  	         * @param startPos
  	         * @param startTouches
  	         * @param gesture
  	         * @param done
  	         */
  	        function triggerGesture(element, startPos, startTouches, gesture, done) {
  	            var interval = 10,
  	                loops = Math.ceil(gesture.duration / interval),
  	                loop = 1;
  
  	            function gestureLoop() {
  	                // calculate the radius
  	                var radius = gesture.radius;
  	                if (gesture.scale !== 1) {
  	                    radius = gesture.radius - (gesture.radius * (1 - gesture.scale) * (1 / loops * loop));
  	                }
  
  	                // calculate new position/rotation
  	                var posX = startPos[0] + (gesture.distanceX / loops * loop),
  	                    posY = startPos[1] + (gesture.distanceY / loops * loop),
  	                    rotation = typeof gesture.rotation == 'number' ? (gesture.rotation / loops * loop) : null,
  	                    touches = getTouches([posX, posY], startTouches.length, radius, rotation),
  	                    isFirst = (loop == 1),
  	                    isLast = (loop == loops);
  
  	                if (isFirst) {
  	                    triggerTouch(touches, element, 'start');
  	                } else if (isLast) {
  	                    triggerTouch(touches, element, 'end');
  	                    return done(touches);
  	                } else {
  	                    triggerTouch(touches, element, 'move');
  	                }
  
  	                setTimeout(gestureLoop, interval);
  	                loop++;
  	            }
  	            gestureLoop();
  	        }
  
  
  	        var touchTypes = {
  	            // tap, like a click event, only 1 touch
  	            // could also be a slow tap, that could turn out to be a hold
  	            tap: function tap(position, element, done) {
  	                var touches = getTouches(position, 1);
  	                var gesture = {
  	                    duration: config.randomizer.integer({ min: 20, max: 700 })
  	                };
  
  	                triggerTouch(touches, element, 'start');
  
  	                setTimeout(function() {
  	                    triggerTouch(touches, element, 'end');
  	                    done(touches, gesture);
  	                }, gesture.duration);
  	            },
  
  	            // doubletap, like a dblclick event, only 1 touch
  	            // could also be a slow doubletap, that could turn out to be a hold
  	            doubletap: function doubletap(position, element, done) {
  	                touchTypes.tap(position, element, function() {
  	                    setTimeout(function() {
  	                        touchTypes.tap(position, element, done);
  	                    }, 30);
  	                });
  	            },
  
  	            // single touch gesture, could be a drag and swipe, with 1 points
  	            gesture: function gesture(position, element, done) {
  	                var gesture = {
  	                    distanceX: config.randomizer.integer({ min: -100, max: 200 }),
  	                    distanceY: config.randomizer.integer({ min: -100, max: 200 }),
  	                    duration:  config.randomizer.integer({ min: 20, max: 500 })
  	                };
  	                var touches = getTouches(position, 1, gesture.radius);
  
  	                triggerGesture(element, position, touches, gesture, function(touches) {
  	                    done(touches, gesture);
  	                });
  	            },
  
  	            // multitouch gesture, could be a drag, swipe, pinch and rotate, with 2 or more points
  	            multitouch: function multitouch(position, element, done) {
  	                var points = config.randomizer.integer({ min: 2, max: config.maxTouches});
  	                var gesture = {
  	                    scale:     config.randomizer.floating({ min: 0, max: 2 }),
  	                    rotation:  config.randomizer.natural({ min: -100, max: 100 }),
  	                    radius:    config.randomizer.integer({ min: 50, max: 200 }),
  	                    distanceX: config.randomizer.integer({ min: -20, max: 20 }),
  	                    distanceY: config.randomizer.integer({ min: -20, max: 20 }),
  	                    duration:  config.randomizer.integer({ min: 100, max: 1500 })
  	                };
  	                var touches = getTouches(position, points, gesture.radius);
  
  	                triggerGesture(element, position, touches, gesture, function(touches) {
  	                    done(touches, gesture);
  	                });
  	            }
  	        };
  
  
  	        /**
  	         * @mixes config
  	         */
  	        function toucherGremlin(done) {
  	            if (!config.randomizer) {
  	                throw new RandomizerRequiredException();
  	            }
  
  	            var position,
  	                posX, posY,
  	                targetElement,
  	                nbTries = 0;
  
  	            do {
  	                position = config.positionSelector();
  	                posX = position[0];
  	                posY = position[1];
  	                targetElement = document.elementFromPoint(posX, posY);
  	                nbTries++;
  	                if(nbTries > config.maxNbTries) return;
  	            } while (!targetElement || !config.canTouch(targetElement));
  
  	            var touchType = config.randomizer.pick(config.touchTypes);
  	            touchTypes[touchType](position, targetElement, logGremlin);
  
  	            function logGremlin(touches, details) {
  	                if (typeof config.showAction == 'function') {
  	                    config.showAction(touches);
  	                }
  	                if (config.logger && typeof config.logger.log == 'function') {
  	                    config.logger.log('gremlin', 'toucher   ', touchType, 'at', posX, posY, details);
  	                }
  	                done();
  	            }
  	        }
  
  	        configurable(toucherGremlin, config);
  
  	        return toucherGremlin;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 7 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * The formFiller gremlin fills forms by entering data, selecting options, clicking checkboxes, etc
  	 *
  	 * As much as possible, the form filling is done using mouse and keyboard
  	 * events, to trigger any listener bound to it.
  	 *
  	 * By default, the formFiller gremlin activity is showed by changing the 
  	 * element border to solid red.
  	 *
  	 *   var formFillerGremlin = gremlins.species.formFiller();
  	 *   horde.gremlin(formFillerGremlin);
  	 *
  	 * The formFiller gremlin can be customized as follows:
  	 *
  	 *   formFillerGremlin.elementMapTypes({'select': function selectFiller(element) {} }); // form element filler functions
  	 *   formFillerGremlin.showAction(function(element) { // show the gremlin activity on screen });
  	 *   formFillerGremlin.canFillElement(function(element) { return true }); // to limit where the gremlin can fill
  	 *   formFillerGremlin.maxNbTries(5); // How many times the gremlin must look for a fillable element before quitting
  	 *   formFillerGremlin.logger(loggerObject); // inject a logger
  	 *   formFillerGremlin.randomizer(randomizerObject); // inject a randomizer
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var configurable = __webpack_require__(4);
  	    var Chance = __webpack_require__(2);
  	    var RandomizerRequiredException = __webpack_require__(5);
  
  	    return function() {
  
  	        var document = window.document;
  
  	        var defaultMapElements = {
  	            'textarea': fillTextElement,
  	            'input[type="text"]': fillTextElement,
  	            'input[type="password"]': fillTextElement,
  	            'input[type="number"]': fillNumberElement,
  	            'select': fillSelect,
  	            'input[type="radio"]': fillRadio,
  	            'input[type="checkbox"]': fillCheckbox,
  	            'input[type="email"]': fillEmail,
  	            'input:not([type])': fillTextElement
  	        };
  
  	        function defaultShowAction(element) {
  	            if(typeof element.attributes['data-old-border'] === 'undefined') {
  	                element.attributes['data-old-border'] = element.style.border;
  	            }
  
  	            var oldBorder = element.attributes['data-old-border'];
  	            element.style.border = "1px solid red";
  
  	            setTimeout(function() {
  	                element.style.border = oldBorder;
  	            }, 500);
  	        }
  
  	        function defaultCanFillElement() {
  	            return true;
  	        }
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            elementMapTypes: defaultMapElements,
  	            showAction:      defaultShowAction,
  	            canFillElement:  defaultCanFillElement,
  	            maxNbTries:      10,
  	            logger:          null,
  	            randomizer:      null
  	        };
  
  	        /**
  	         * @mixes config
  	         */
  	        function formFillerGremlin() {
  	            if (!config.randomizer) {
  	                throw new RandomizerRequiredException();
  	            }
  
  	            // Retrieve all selectors
  	            var elementTypes = [];
  
  	            for (var key in config.elementMapTypes) {
  	                if(config.elementMapTypes.hasOwnProperty(key)) {
  	                    elementTypes.push(key);
  	                }
  	            }
  
  	            var element, nbTries = 0;
  
  	            do {
  	                // Find a random element within all selectors
  	                var elements = document.querySelectorAll(elementTypes.join(','));
  	                if (elements.length === 0) return false;
  	                element = config.randomizer.pick(elements);
  	                nbTries++;
  	                if (nbTries > config.maxNbTries) return false;
  	            } while (!element || !config.canFillElement(element));
  
  	            // Retrieve element type
  	            var elementType = null;
  	            for (var selector in config.elementMapTypes) {
  	                if (matchesSelector(element, selector)) {
  	                    elementType = selector;
  	                    break;
  	                }
  	            }
  
  	            var value = config.elementMapTypes[elementType](element);
  
  	            if (typeof config.showAction == 'function') {
  	                config.showAction(element);
  	            }
  
  	            if (config.logger && typeof config.logger.log == 'function') {
  	                config.logger.log('gremlin', 'formFiller', 'input', value, 'in', element);
  	            }
  	        }
  
  	        function fillTextElement(element) {
  	            var character = config.randomizer.character();
  	            element.value += character;
  
  	            return character;
  	        }
  
  	        function fillNumberElement(element) {
  	            var number = config.randomizer.character({pool: '0123456789'});
  	            element.value += number;
  
  	            return number;
  	        }
  
  	        function fillSelect(element) {
  	            var options = element.querySelectorAll('option');
  	            if (options.length === 0) return;
  	            var randomOption = config.randomizer.pick(options);
  
  	            for (var i = 0, c = options.length; i < c; i++) {
  	                var option = options[i];
  	                option.selected = option.value == randomOption.value;
  	            }
  
  	            return randomOption.value;
  	        }
  
  	        function fillRadio(element) {
  	            // using mouse events to trigger listeners
  	            var evt = document.createEvent("MouseEvents");
  	            evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  	            element.dispatchEvent(evt);
  
  	            return element.value;
  	        }
  
  	        function fillCheckbox(element) {
  	            // using mouse events to trigger listeners
  	            var evt = document.createEvent("MouseEvents");
  	            evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
  	            element.dispatchEvent(evt);
  
  	            return element.value;
  	        }
  
  	        function fillEmail(element) {
  	            var email = config.randomizer.email();
  	            element.value = email;
  
  	            return email;
  	        }
  
  	        function matchesSelector(el, selector) {
  	            if (el.webkitMatchesSelector) {
  	                matchesSelector = function(el, selector) {
  	                    return el.webkitMatchesSelector(selector);
  	                };
  	            } else if (el.mozMatchesSelector) {
  	                matchesSelector = function(el, selector) {
  	                    return el.mozMatchesSelector(selector);
  	                };
  	            } else if (el.msMatchesSelector) {
  	                matchesSelector = function(el, selector) {
  	                    return el.msMatchesSelector(selector);
  	                };
  	            } else if (el.oMatchesSelector) {
  	                matchesSelector = function(el, selector) {
  	                    return el.oMatchesSelector(selector);
  	                };
  	            } else {
  	                throw new Error('Unsupported browser');
  	            }
  	            return matchesSelector(el, selector);
  	        }
  
  	        configurable(formFillerGremlin, config);
  
  	        return formFillerGremlin;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 8 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * The scroller gremlin scrolls the viewport to reveal another part of the document
  	 *
  	 *   var scrollerGremlin = gremlins.species.scroller();
  	 *   horde.gremlin(scrollerGremlin);
  	 *
  	 * The scrollerGremlin gremlin can be customized as follows:
  	 *
  	 *   scrollerGremlin.positionSelector(function() { // return a random position to scroll to });
  	 *   scrollerGremlin.showAction(function(element) { // show the gremlin activity on screen });
  	 *   scrollerGremlin.logger(loggerObject); // inject a logger
  	 *   scrollerGremlin.randomizer(randomizerObject); // inject a randomizer
  	 *
  	 * Example usage:
  	 *
  	 *   horde.gremlin(gremlins.species.scroller()
  	 *     .positionSelector(function() {
  	 *       // only click in the app
  	 *       var $list = $('#todoapp');
  	 *       var offset = $list.offset();
  	 *       return [
  	 *         parseInt(Math.random() * $list.outerWidth() + offset.left),
  	 *         parseInt(Math.random() * ($list.outerHeight() + $('#info').outerHeight()) + offset.top)
  	 *       ];
  	 *     })
  	 *   )
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var configurable = __webpack_require__(4);
  	    var Chance = __webpack_require__(2);
  	    var RandomizerRequiredException = __webpack_require__(5);
  
  	    return function() {
  
  	        var document = window.document,
  	            documentElement = document.documentElement,
  	            body = document.body;
  
  	        function defaultPositionSelector() {
  	            var documentWidth = Math.max(body.scrollWidth, body.offsetWidth, documentElement.scrollWidth, documentElement.offsetWidth, documentElement.clientWidth),
  	                documentHeight = Math.max(body.scrollHeight, body.offsetHeight, documentElement.scrollHeight, documentElement.offsetHeight, documentElement.clientHeight);
  
  	            return [
  	                config.randomizer.natural({ max: documentWidth  - documentElement.clientWidth }),
  	                config.randomizer.natural({ max: documentHeight  - documentElement.clientHeight })
  	            ];
  	        }
  
  	        function defaultShowAction(scrollX, scrollY) {
  	            var scrollSignal = document.createElement('div');
  	            scrollSignal.style.zIndex = 2000;
  	            scrollSignal.style.border = "3px solid red";
  	            scrollSignal.style.width = (documentElement.clientWidth - 25) + "px";
  	            scrollSignal.style.height = (documentElement.clientHeight - 25) + "px";
  	            scrollSignal.style.position = "absolute";
  	            scrollSignal.style.webkitTransition = 'opacity 1s ease-out';
  	            scrollSignal.style.mozTransition = 'opacity 1s ease-out';
  	            scrollSignal.style.transition = 'opacity 1s ease-out';
  	            scrollSignal.style.left = (scrollX + 10) + 'px';
  	            scrollSignal.style.top = (scrollY + 10) + 'px';
  	            var element = body.appendChild(scrollSignal);
  	            setTimeout(function() {
  	                body.removeChild(element);
  	            }, 1000);
  	            setTimeout(function() {
  	                element.style.opacity = 0;
  	            }, 50);
  	        }
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            positionSelector: defaultPositionSelector,
  	            showAction:       defaultShowAction,
  	            logger:           null,
  	            randomizer:       null
  	        };
  
  	        /**
  	         * @mixes config
  	         */
  	        function scrollerGremlin() {
  	            if (!config.randomizer) {
  	                throw new RandomizerRequiredException();
  	            }
  
  	            var position = config.positionSelector(),
  	                scrollX = position[0],
  	                scrollY = position[1];
  
  	            window.scrollTo(scrollX, scrollY);
  
  	            if (typeof config.showAction == 'function') {
  	                config.showAction(scrollX, scrollY);
  	            }
  
  	            if (typeof config.logger.log == 'function') {
  	                config.logger.log('gremlin', 'scroller  ', 'scroll to', scrollX, scrollY);
  	            }
  	        }
  
  	        configurable(scrollerGremlin, config);
  
  	        return scrollerGremlin;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 9 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * The typer gremlin types keys on the keyboard
  	 *
  	 * Note that keyboard events must be localized somewhere on screen, so this
  	 * gremlins picks a random screen location first.
  	 *
  	 * By default, the typer gremlin activity is showed by a letter surrounded by
  	 * a orange circle with a keyname on it.
  	 *
  	 *   var typerGremlin = gremlins.species.typer();
  	 *   horde.gremlin(typerGremlin);
  	 *
  	 * The typerGremlin gremlin can be customized as follows:
  	 *
  	 *   typerGremlin.eventTypes(['keypress', 'keyup', 'keydown']); // types of events to trigger
  	 *   typerGremlin.showAction(function(element) { // show the gremlin activity on screen });
  	 *   typerGremlin.logger(loggerObject); // inject a logger
  	 *   typerGremlin.randomizer(randomizerObject); // inject a randomizer
  	 *
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var configurable = __webpack_require__(4);
  	    var Chance = __webpack_require__(2);
  	    var RandomizerRequiredException = __webpack_require__(5);
  
  	    return function() {
  
  	        var document = window.document,
  	            documentElement = document.documentElement,
  	            body = document.body;
  
  	        var defaultEventTypes = ['keypress', 'keyup', 'keydown'];
  
  	        function defaultKeyGenerator() {
  	            return config.randomizer.natural({ min: 3, max: 254});
  	        }
  
  	        function defaultTargetElement(x, y) {
  	            return document.elementFromPoint(x, y);
  	        }
  
  	        function defaultShowAction(targetElement, x, y, key) {
  	            var typeSignal = document.createElement('div');
  	            typeSignal.style.zIndex = 2000;
  	            typeSignal.style.border = "3px solid orange";
  	            typeSignal.style['border-radius'] = '50%'; // Chrome
  	            typeSignal.style.borderRadius = '50%';     // Mozilla
  	            typeSignal.style.width = "40px";
  	            typeSignal.style.height = "40px";
  	            typeSignal.style['box-sizing'] = 'border-box';
  	            typeSignal.style.position = "absolute";
  	            typeSignal.style.webkitTransition = 'opacity 1s ease-out';
  	            typeSignal.style.mozTransition = 'opacity 1s ease-out';
  	            typeSignal.style.transition = 'opacity 1s ease-out';
  	            typeSignal.style.left = x + 'px';
  	            typeSignal.style.top = y + 'px';
  	            typeSignal.style.textAlign = 'center';
  	            typeSignal.style.paddingTop = '7px';
  	            typeSignal.innerHTML = String.fromCharCode(key);
  
  	            var element = body.appendChild(typeSignal);
  	            setTimeout(function () {
  	                body.removeChild(element);
  	            }, 1000);
  	            setTimeout(function () {
  	                element.style.opacity = 0;
  	            }, 50);
  	        }
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            eventTypes: defaultEventTypes,
  	            showAction: defaultShowAction,
  	            keyGenerator: defaultKeyGenerator,
  	            targetElement: defaultTargetElement,
  	            logger:     null,
  	            randomizer: null
  	        };
  
  	        /**
  	         * @mixes config
  	         */
  	        function typerGremlin() {
  	            if (!config.randomizer) {
  	                throw new RandomizerRequiredException();
  	            }
  
  	            var keyboardEvent = document.createEventObject ? document.createEventObject() : document.createEvent("Events"),
  	                eventType = config.randomizer.pick(config.eventTypes),
  	                key = config.keyGenerator(),
  	                posX = config.randomizer.natural({ max: documentElement.clientWidth - 1 }),
  	                posY = config.randomizer.natural({ max: documentElement.clientHeight - 1 }),
  	                targetElement = config.targetElement(posX, posY);
  
  	            if(keyboardEvent.initEvent){
  	                keyboardEvent.initEvent(eventType, true, true);
  	            }
  
  	            keyboardEvent.keyCode = key;
  	            keyboardEvent.which = key;
  	            keyboardEvent.keyCodeVal = key;
  
  	            targetElement.dispatchEvent ? targetElement.dispatchEvent(keyboardEvent) : targetElement.fireEvent("on" + eventType, keyboardEvent);
  
  	            if (typeof config.showAction === 'function') {
  	                config.showAction(targetElement, posX, posY, key);
  	            }
  
  	            if (config.logger && typeof config.logger.log == 'function') {
  	                config.logger.log('gremlin', 'typer       type', String.fromCharCode(key), 'at', posX, posY);
  	            }
  	        }
  
  	        configurable(typerGremlin, config);
  
  	        return typerGremlin;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 10 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * The alert mogwai answers calls to alert()
  	 *
  	 * The alert mogwai overrides window.alert, window.confirm, and window.prompt
  	 * to avoid stopping the stress test with blocking JavaScript calls. Instead
  	 * of displaying a dialog, these methods are simply replaced by a write in the
  	 * logger.
  	 *
  	 *   var alertMogwai = gremlins.mogwais.alert();
  	 *   horde.mogwai(alertMogwai);
  	 *
  	 * The alert mogwai can be customized as follows:
  	 *
  	 *   alertMogwai.watchEvents(['alert', 'confirm', 'prompt']); // select the events to catch
  	 *   alertMogwai.confirmResponse(function() { // what a call to confirm() should return });
  	 *   alertMogwai.promptResponse(function() { // what a call to prompt() should return });
  	 *   alertMogwai.logger(loggerObject); // inject a logger
  	 *   alertMogwai.randomizer(randomizerObject); // inject a randomizer
  	 *
  	 * Example usage:
  	 *
  	 *   horde.mogwai(gremlins.mogwais.alert()
  	 *     .watchEvents(['prompt'])
  	 *     .promptResponse(function() { return 'I typed garbage'; })
  	 *   );
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var configurable = __webpack_require__(4);
  	    var Chance = __webpack_require__(2);
  	    var LoggerRequiredException = __webpack_require__(11);
  
  	    return function() {
  
  	        var defaultWatchEvents = ['alert', 'confirm', 'prompt'];
  
  	        function defaultConfirmResponse() {
  	            // Random OK or cancel
  	            return config.randomizer.bool();
  	        }
  
  	        function defaultPromptResponse() {
  	            // Return a random string
  	            return config.randomizer.sentence();
  	        }
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            watchEvents:     defaultWatchEvents,
  	            confirmResponse: defaultConfirmResponse,
  	            promptResponse:  defaultPromptResponse,
  	            logger:          null,
  	            randomizer:      null
  	        };
  
  	        var alert   = window.alert;
  	        var confirm = window.confirm;
  	        var prompt  = window.prompt;
  
  	        /**
  	         * @mixes config
  	         */
  	        function alertMogwai() {
  
  	            if (!config.logger) {
  	                throw new LoggerRequiredException();
  	            }
  
  	            if (config.watchEvents.indexOf('alert') !== -1) {
  	                window.alert = function (msg) {
  	                    config.logger.warn('mogwai ', 'alert     ', msg, 'alert');
  	                };
  	            }
  	            if (config.watchEvents.indexOf('confirm') !== -1) {
  	                window.confirm = function (msg) {
  	                    config.confirmResponse();
  	                    config.logger.warn('mogwai ', 'alert     ', msg, 'confirm');
  	                };
  	            }
  	            if (config.watchEvents.indexOf('prompt') !== -1) {
  	                window.prompt = function (msg) {
  	                    config.promptResponse();
  	                    config.logger.warn('mogwai ', 'alert     ', msg, 'prompt');
  	                };
  	            }
  	        }
  
  	        alertMogwai.cleanUp = function() {
  	            window.alert   = alert;
  	            window.confirm = confirm;
  	            window.prompt  = prompt;
  	            return alertMogwai;
  	        };
  
  	        configurable(alertMogwai, config);
  
  	        return alertMogwai;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 11 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    function LoggerRequiredException() {
  	        this.message = 'This mogwai requires a logger to run. Please call logger(loggerObject) before executing the mogwai';
  	        this.toString = function() {
  	            return this.message;
  	        };
  	    }
  
  	    return LoggerRequiredException;
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 12 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * The fps mogwai logs the number of frames per seconds (FPS) of the browser
  	 * 
  	 * The normal (and maximal) FPS rate is 60. It decreases when the browser is
  	 * busy refreshing the layout, or executing JavaScript.
  	 *
  	 * This mogwai logs with the error level once the FPS rate drops below 10.
  	 *
  	 *   var fpsMogwai = gremlins.mogwais.fps();
  	 *   horde.mogwai(fpsMogwai);
  	 *
  	 * The fps mogwai can be customized as follows:
  	 *
  	 *   fpsMogwai.delay(500); // the interval for FPS measurements
  	 *   fpsMogwai.levelSelector(function(fps) { // select logging level according to fps value });
  	 *   fpsMogwai.logger(loggerObject); // inject a logger
  	 *
  	 * Example usage:
  	 *
  	 *   horde.mogwai(gremlins.mogwais.fps()
  	 *     .delay(250)
  	 *     .levelSelector(function(fps) {
  	 *       if (fps < 5) return 'error';
  	 *       if (fps < 10) return 'warn';
  	 *       return 'log';
  	 *     })
  	 *   );
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var configurable = __webpack_require__(4);
  	    var LoggerRequiredException = __webpack_require__(11);
  
  	    return function() {
  
  	        if (!window.requestAnimationFrame) {
  	            // shim layer with setTimeout fallback
  	            window.requestAnimationFrame =
  	                window.mozRequestAnimationFrame ||
  	                window.webkitRequestAnimationFrame ||
  	                window.msRequestAnimationFrame ||
  	                function (callback) {
  	                    window.setTimeout(callback, 1000 / 60);
  	                };
  	        }
  
  	        function defaultLevelSelector(fps) {
  	            if (fps < 10) return 'error';
  	            if (fps < 20) return 'warn';
  	            return 'log';
  	        }
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            delay: 500, // how often should the fps be measured
  	            levelSelector: defaultLevelSelector,
  	            logger: null
  	        };
  
  	        var initialTime = -Infinity; // force initial measure
  	        var enabled;
  
  	        function loop(time) {
  	            if ((time - initialTime) > config.delay) {
  	                measureFPS(time);
  	                initialTime = time;
  	            }
  	            if (!enabled) return;
  	            window.requestAnimationFrame(loop);
  	        }
  
  	        function measureFPS() {
  	            var lastTime;
  	            function init(time) {
  	                lastTime = time;
  	                window.requestAnimationFrame(measure);
  	            }
  	            function measure(time) {
  	                var fps = (time - lastTime < 16) ? 60 : 1000/(time - lastTime);
  	                var level = config.levelSelector(fps);
  	                config.logger[level]('mogwai ', 'fps       ', fps);
  	            }
  	            window.requestAnimationFrame(init);
  	        }
  
  	        /**
  	         * @mixes config
  	         */
  	        function fpsMogwai() {
  	            if (!config.logger) {
  	                throw new LoggerRequiredException();
  	            }
  	            enabled = true;
  	            window.requestAnimationFrame(loop);
  	        }
  
  	        fpsMogwai.cleanUp = function() {
  	            enabled = false;
  	            return fpsMogwai;
  	        };
  
  	        configurable(fpsMogwai, config);
  
  	        return fpsMogwai;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 13 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * Gizmo is a special mogwai who can stop the gremlins when they go too far
  	 *
  	 * The gizom mogwai monitors the JavaScript alerts and the calls to
  	 * console.alert(), and stops the stress test execution once the number of
  	 * errors pass a certain threshold (10 errors by default).
  	 *
  	 *   var gizmoMogwai = gremlins.mogwais.gizmo();
  	 *   horde.mogwai(gizmoMogwai);
  	 *
  	 * The gizmo mogwai can be customized as follows:
  	 *
  	 *   gizmoMogwai.maxErrors(10); // the number of errors after which the test stops
  	 *   gizmoMogwai.logger(loggerObject); // inject a logger
  	 *
  	 * Example usage:
  	 *
  	 *   horde.mogwai(gremlins.mogwais.gizmo()
  	 *     .maxErrors(5)
  	 *   );
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var configurable = __webpack_require__(4);
  
  	    return function() {
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            maxErrors: 10,
  	            logger:    null
  	        };
  
  	        var realOnError, realLoggerError;
  
  	        /**
  	         * @mixes config
  	         */
  	        function gizmoMogwai() {
  	            var nbErrors = 0;
  	            var horde = this; // this is exceptional - don't use 'this' for mogwais in general
  	            function incrementNbErrors() {
  	                nbErrors++;
  	                if (nbErrors == config.maxErrors) {
  	                    horde.stop();
  	                    if (!config.logger) return;
  	                    window.setTimeout(function() {
  	                        // display the mogwai error after the caught error
  	                        config.logger.warn('mogwai ', 'gizmo     ', 'stopped test execution after ', config.maxErrors, 'errors');
  	                    }, 4);
  	                }
  	            }
  
  	            // general JavaScript errors
  	            realOnError = window.onerror;
  	            window.onerror = function(message, url, linenumber) {
  	                incrementNbErrors();
  	                return realOnError ? realOnError(message, url, linenumber) : false;
  	            };
  
  	            // console errors
  	            realLoggerError = console.error;
  	            console.error = function() {
  	                incrementNbErrors();
  	                realLoggerError.apply(console, arguments);
  	            };
  	        }
  
  	        gizmoMogwai.cleanUp = function() {
  	            window.onerror = realOnError;
  	            console.error = realLoggerError.bind(console);
  	            return gizmoMogwai;
  	        };
  
  	        configurable(gizmoMogwai, config);
  
  	        return gizmoMogwai;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 14 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * Execute all Gremlins species at once ; repeat 10ms after for 100 times
  	 *
  	 *   var allTogetherStrategy = gremlins.strategies.allTogether();
  	 *   horde.strategy(allTogetherStrategy);
  	 *
  	 * The actual attack duration depends on the number of species in the horde.
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var executeInSeries = __webpack_require__(15);
  	    var configurable = __webpack_require__(4);
  
  	    return function() {
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            delay: 10, // delay in milliseconds between each wave
  	            nb: 100    // number of waves to execute (can be overridden in params)
  	        };
  
  	        var stopped;
  	        var doneCallback;
  
  	        /**
  	         * @mixes config
  	         */
  	        function allTogetherStrategy(gremlins, params, done) {
  	            var nb = params && params.nb ? params.nb : config.nb,
  	                horde = this;
  
  	            stopped = false;
  	            doneCallback = done; // done can also be called by stop()
  
  	            function executeAllGremlins(callback) {
  	                executeInSeries(gremlins, [], horde, callback);
  	            }
  
  	            function executeNextWave(i) {
  	                if (stopped) return;
  	                if (i >= nb) return callDone();
  	                executeAllGremlins(function() {
  	                    setTimeout(function() {
  	                        executeNextWave(++i);
  	                    }, config.delay);
  	                });
  	            }
  
  	            executeNextWave(0);
  	        }
  
  	        function callDone() {
  	            if (typeof doneCallback === 'function') {
  	                doneCallback();
  	            }
  	            doneCallback = null;
  	        }
  
  	        allTogetherStrategy.stop = function() {
  	            stopped = true;
  	            setTimeout(callDone, 4);
  	        };
  
  	        configurable(allTogetherStrategy, config);
  
  	        return allTogetherStrategy;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 15 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    /**
  	     * Execute a list of functions one after the other.
  	     *
  	     * Functions can be asynchronous or asynchronous, they will always be
  	     * executed in the order of the list.
  	     *
  	     * @param {Function[]} callbacks - The functions to execute
  	     * @param {Array} args - The arguments passed to each function
  	     * @param {Object|null} context - The object the functions must be bound to
  	     * @param {Function} done - The final callback to execute once all functions are executed
  	     */
  	    function executeInSeries(callbacks, args, context, done) {
  	        var nbArguments = args.length;
  	        callbacks = callbacks.slice(0); // clone the array to avoid modifying the original
  
  	        var iterator = function(callbacks, args) {
  	            if (!callbacks.length) {
  	                return typeof done === 'function' ? done() : true;
  	            }
  
  	            var callback = callbacks.shift();
  	            callback.apply(context, args);
  
  	            // Is the callback synchronous ?
  	            if (callback.length === nbArguments) {
  	                iterator(callbacks, args, done);
  	            }
  	        };
  
  	        args.push(function(){
  	            iterator(callbacks, args, done);
  	        });
  
  	        iterator(callbacks, args, done);
  	    }
  
  	    return executeInSeries;
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 16 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * For each species, execute the gremlin 200 times, separated by a 10ms delay
  	 *
  	 *   var bySpeciesStrategy = gremlins.strategies.bySpecies();
  	 *   horde.strategy(bySpeciesStrategy);
  	 *
  	 * The actual attack duration depends on the number of species in the horde.
  	 *
  	 * The bySpecies strategy can be customized as follows:
  	 *
  	 *   bySpeciesStrategy.delay(10); // delay in milliseconds between each gremlin action
  	 *   bySpeciesStrategy.nb(200);   // number times to execute each gremlin
  	 *
  	 * Example usage:
  	 *
  	 *   horde
  	 *     .gremlin(gremlins.species.clicker())
  	 *     .gremlin(gremlins.species.formFiller())
  	 *     .strategy(gremlins.strategies.bySpecies()
  	 *       .delay(1000) // one action per second
  	 *       .nb(10)      // each gremlin will act 10 times
  	 *     )
  	 *     .unleash();
  	 *
  	 *   // t     clickerGremlin clicked
  	 *   // t+1s  clickerGremlin clicked
  	 *   // ...
  	 *   // t+9s  clickerGremlin clicked
  	 *   // t+10s formFillerGremlin filled
  	 *   // t+11s formFillerGremlin filled
  	 *   // ...
  	 *   // t+19s formFillerGremlin filled
  	 *   // t+20s, end of the attack
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var executeInSeries = __webpack_require__(15);
  	    var configurable = __webpack_require__(4);
  
  	    return function() {
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            delay: 10, // delay in milliseconds between each attack
  	            nb: 200    // number of attacks to execute (can be overridden in params)
  	        };
  
  	        var stopped;
  	        var doneCallback;
  
  	        /**
  	         * @mixes config
  	         */
  	        function bySpeciesStrategy(gremlins, params, done) {
  	            var nb = params && params.nb ? params.nb : config.nb,
  	                gremlins = gremlins.slice(0), // clone the array to avoid modifying the original
  	                horde = this;
  
  	            stopped = false;
  	            doneCallback = done; // done can also be called by stop()
  
  	            function executeNext(gremlin, i, callback) {
  	                if (stopped) return;
  	                if (i >= nb) return callback();
  	                executeInSeries([gremlin], [], horde, function() {
  	                    setTimeout(function() {
  	                        executeNext(gremlin, ++i, callback);
  	                    }, config.delay);
  	                });
  	            }
  
  	            function executeNextGremlin() {
  	                if (stopped) return;
  	                if (gremlins.length === 0) {
  	                    return callDone();
  	                }
  	                executeNext(gremlins.shift(), 0, executeNextGremlin);
  	            }
  
  	            executeNextGremlin();
  	        }
  
  	        bySpeciesStrategy.stop = function() {
  	            stopped = true;
  	            setTimeout(callDone, 4);
  	        };
  
  	        function callDone() {
  	            if (typeof doneCallback === 'function') {
  	                doneCallback();
  	            }
  	            doneCallback = null;
  	        }
  
  	        configurable(bySpeciesStrategy, config);
  
  	        return bySpeciesStrategy;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ },
  /* 17 */
  /***/ function(module, exports, __webpack_require__) {
  
  	var __WEBPACK_AMD_DEFINE_RESULT__;/**
  	 * Execute all Gremlins randomly following a distribution, separated by a 10ms
  	 * delay, for 100 times
  	 *
  	 * This is the default attack strategy, so selecting no strategy is equivalent to
  	 *
  	 *   var distributionStrategy = gremlins.strategies.distribution();
  	 *   horde.strategy(distributionStrategy);
  	 *
  	 * The attack duration is roughly equivalent to delay * nb, although setTimeout
  	 * may make it longer when delay is small.
  	 *
  	 * By default, this strategy uses a uniform distribution, i.e. all gremlins
  	 * have an equal chance to be selected for the next action.
  	 *
  	 * The distribution strategy can be customized as follows:
  	 *
  	 *   distributionStrategy.distribution([0.25, 0.25, 0.25, 0.25]); // chances for each gremlin to be selected ; total must equal 1
  	 *   distributionStrategy.delay(10); // delay in milliseconds between each wave
  	 *   distributionStrategy.nb(100); // number of waves to execute (can be overridden in params)
  	 *   distributionStrategy.randomizer(randomizerObject); // inject a randomizer
  	 *
  	 * Example usage:
  	 *
  	 *   horde.strategy(gremlins.strategies.distribution()
  	 *     .delay(50)
  	 *     .distribution([
  	 *       0.3, // first gremlin
  	 *       0.3, // second gremlin
  	 *       0.3, // third gremlin
  	 *       0.1, // fourth gremlin
  	 *     ])
  	 *   )
  	 */
  	!(__WEBPACK_AMD_DEFINE_RESULT__ = function(require) {
  	    "use strict";
  
  	    var executeInSeries = __webpack_require__(15);
  	    var configurable = __webpack_require__(4);
  	    var Chance = __webpack_require__(2);
  
  	    return function() {
  
  	        /**
  	         * @mixin
  	         */
  	        var config = {
  	            distribution: [],  // percentage of each gremlin species ; the sum of all values should equal to 1
  	            delay:        10,  // delay in milliseconds between each wave
  	            nb:           1000, // number of waves to execute (can be overridden in params)
  	            randomizer:   new Chance()
  	        };
  
  	        var stopped;
  	        var doneCallback;
  
  	        /**
  	         * @mixes config
  	         */
  	        function distributionStrategy(gremlins, params, done) {
  	            var nb = params && params.nb ? params.nb : config.nb,
  	                gremlins = gremlins.slice(0), // clone the array to avoid modifying the original
  	                distribution = config.distribution.length === 0 ? getUniformDistribution(gremlins) : config.distribution,
  	                horde = this;
  
  	            if (nb === 0) return done();
  
  	            stopped = false;
  	            doneCallback = done; // done can also be called by stop()
  
  	            function executeNext(gremlin, i, callback) {
  	                if (stopped) return;
  	                if (i >= nb) return callDone();
  	                executeInSeries([gremlin], [], horde, function() {
  	                    setTimeout(function() {
  	                        executeNext(pickGremlin(gremlins, distribution), ++i, callback);
  	                    }, config.delay);
  	                });
  	            }
  
  	            executeNext(pickGremlin(gremlins, distribution), 0, executeNext);
  	        }
  
  	        function getUniformDistribution(gremlins) {
  	            var len = gremlins.length;
  	            if (len === 0) return [];
  	            var distribution = [];
  	            var value = 1 / len;
  	            for (var i = 0; i < len ; i++) {
  	                distribution.push(value);
  	            }
  	            return distribution;
  	        }
  
  	        function pickGremlin(gremlins, distribution) {
  	            var chance = 0;
  	            var random = config.randomizer.floating({ min: 0, max: 1 });
  	            for (var i = 0, count = gremlins.length; i < count; i++) {
  	                chance += distribution[i];
  	                if (random <= chance) return gremlins[i];
  	            }
  	            // no gremlin - probably error in the distribution
  	            return function() {};
  	        }
  
  	        distributionStrategy.stop = function() {
  	            stopped = true;
  	            setTimeout(callDone, 4);
  	        };
  
  	        function callDone() {
  	            if (typeof doneCallback === 'function') {
  	                doneCallback();
  	            }
  	            doneCallback = null;
  	        }
  
  	        configurable(distributionStrategy, config);
  
  	        return distributionStrategy;
  	    };
  	}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  
  
  /***/ }
  /******/ ])
  });
  ;