\").append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t}).complete( callback && function( jqXHR, status ) {\n\t\t\tself.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t});\n\t}\n\n\treturn this;\n};\n\n\n\n\njQuery.expr.filters.animated = function( elem ) {\n\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t}).length;\n};\n\n\n\n\n\nvar docElem = window.document.documentElement;\n\n/**\n * Gets a window from an element\n */\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ?\n\t\telem :\n\t\telem.nodeType === 9 ?\n\t\t\telem.defaultView || elem.parentWindow :\n\t\t\tfalse;\n}\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\tjQuery.inArray(\"auto\", [ curCSSTop, curCSSLeft ] ) > -1;\n\n\t\t// need to be able to calculate position if either top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\t\t\toptions = options.call( elem, i, curOffset );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend({\n\toffset: function( options ) {\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each(function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t});\n\t\t}\n\n\t\tvar docElem, win,\n\t\t\tbox = { top: 0, left: 0 },\n\t\t\telem = this[ 0 ],\n\t\t\tdoc = elem && elem.ownerDocument;\n\n\t\tif ( !doc ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocElem = doc.documentElement;\n\n\t\t// Make sure it's not a disconnected DOM node\n\t\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\t\treturn box;\n\t\t}\n\n\t\t// If we don't have gBCR, just use 0,0 rather than error\n\t\t// BlackBerry 5, iOS 3 (original iPhone)\n\t\tif ( typeof elem.getBoundingClientRect !== strundefined ) {\n\t\t\tbox = elem.getBoundingClientRect();\n\t\t}\n\t\twin = getWindow( doc );\n\t\treturn {\n\t\t\ttop: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),\n\t\t\tleft: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )\n\t\t};\n\t},\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\tparentOffset = { top: 0, left: 0 },\n\t\t\telem = this[ 0 ];\n\n\t\t// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\t\t\t// we assume that getBoundingClientRect is available when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\t\t} else {\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\tparentOffset.top += jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true );\n\t\t\tparentOffset.left += jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true );\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\t// note: when an element has margin: auto the offsetLeft and marginLeft\n\t\t// are the same in Safari causing offset.left to incorrectly be 0\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true)\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || docElem;\n\n\t\t\twhile ( offsetParent && ( !jQuery.nodeName( offsetParent, \"html\" ) && jQuery.css( offsetParent, \"position\" ) === \"static\" ) ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\t\t\treturn offsetParent || docElem;\n\t\t});\n\t}\n});\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = /Y/.test( prop );\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? (prop in win) ? win[ prop ] :\n\t\t\t\t\twin.document.documentElement[ method ] :\n\t\t\t\t\telem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : jQuery( win ).scrollLeft(),\n\t\t\t\t\ttop ? val : jQuery( win ).scrollTop()\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length, null );\n\t};\n});\n\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// getComputedStyle returns percent when specified for top/left/bottom/right\n// rather than make the css module depend on the offset module, we just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\t\t\t\t// if curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n});\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name }, function( defaultExtra, funcName ) {\n\t\t// margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t\t\t// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there\n\t\t\t\t\t// isn't a whole lot we can do. See pull request at this URL for discussion:\n\t\t\t\t\t// https://github.com/jquery/jquery/pull/764\n\t\t\t\t\treturn elem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest\n\t\t\t\t\t// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable, null );\n\t\t};\n\t});\n});\n\n\n// The number of elements contained in the matched element set\njQuery.fn.size = function() {\n\treturn this.length;\n};\n\njQuery.fn.andSelf = jQuery.fn.addBack;\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t});\n}\n\n\n\n\nvar\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in\n// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( typeof noGlobal === strundefined ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n\n}));\n\n","// Underscore.js 1.8.3\n// http://underscorejs.org\n// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n// Underscore may be freely distributed under the MIT license.\n\n(function() {\n\n // Baseline setup\n // --------------\n\n // Establish the root object, `window` in the browser, or `exports` on the server.\n var root = this;\n\n // Save the previous value of the `_` variable.\n var previousUnderscore = root._;\n\n // Save bytes in the minified (but not gzipped) version:\n var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;\n\n // Create quick reference variables for speed access to core prototypes.\n var\n push = ArrayProto.push,\n slice = ArrayProto.slice,\n toString = ObjProto.toString,\n hasOwnProperty = ObjProto.hasOwnProperty;\n\n // All **ECMAScript 5** native function implementations that we hope to use\n // are declared here.\n var\n nativeIsArray = Array.isArray,\n nativeKeys = Object.keys,\n nativeBind = FuncProto.bind,\n nativeCreate = Object.create;\n\n // Naked function reference for surrogate-prototype-swapping.\n var Ctor = function(){};\n\n // Create a safe reference to the Underscore object for use below.\n var _ = function(obj) {\n if (obj instanceof _) return obj;\n if (!(this instanceof _)) return new _(obj);\n this._wrapped = obj;\n };\n\n // Export the Underscore object for **Node.js**, with\n // backwards-compatibility for the old `require()` API. If we're in\n // the browser, add `_` as a global object.\n if (typeof exports !== 'undefined') {\n if (typeof module !== 'undefined' && module.exports) {\n exports = module.exports = _;\n }\n exports._ = _;\n } else {\n root._ = _;\n }\n\n // Current version.\n _.VERSION = '1.8.3';\n\n // Internal function that returns an efficient (for current engines) version\n // of the passed-in callback, to be repeatedly applied in other Underscore\n // functions.\n var optimizeCb = function(func, context, argCount) {\n if (context === void 0) return func;\n switch (argCount == null ? 3 : argCount) {\n case 1: return function(value) {\n return func.call(context, value);\n };\n case 2: return function(value, other) {\n return func.call(context, value, other);\n };\n case 3: return function(value, index, collection) {\n return func.call(context, value, index, collection);\n };\n case 4: return function(accumulator, value, index, collection) {\n return func.call(context, accumulator, value, index, collection);\n };\n }\n return function() {\n return func.apply(context, arguments);\n };\n };\n\n // A mostly-internal function to generate callbacks that can be applied\n // to each element in a collection, returning the desired result — either\n // identity, an arbitrary callback, a property matcher, or a property accessor.\n var cb = function(value, context, argCount) {\n if (value == null) return _.identity;\n if (_.isFunction(value)) return optimizeCb(value, context, argCount);\n if (_.isObject(value)) return _.matcher(value);\n return _.property(value);\n };\n _.iteratee = function(value, context) {\n return cb(value, context, Infinity);\n };\n\n // An internal function for creating assigner functions.\n var createAssigner = function(keysFunc, undefinedOnly) {\n return function(obj) {\n var length = arguments.length;\n if (length < 2 || obj == null) return obj;\n for (var index = 1; index < length; index++) {\n var source = arguments[index],\n keys = keysFunc(source),\n l = keys.length;\n for (var i = 0; i < l; i++) {\n var key = keys[i];\n if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];\n }\n }\n return obj;\n };\n };\n\n // An internal function for creating a new object that inherits from another.\n var baseCreate = function(prototype) {\n if (!_.isObject(prototype)) return {};\n if (nativeCreate) return nativeCreate(prototype);\n Ctor.prototype = prototype;\n var result = new Ctor;\n Ctor.prototype = null;\n return result;\n };\n\n var property = function(key) {\n return function(obj) {\n return obj == null ? void 0 : obj[key];\n };\n };\n\n // Helper for collection methods to determine whether a collection\n // should be iterated as an array or as an object\n // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength\n // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094\n var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;\n var getLength = property('length');\n var isArrayLike = function(collection) {\n var length = getLength(collection);\n return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;\n };\n\n // Collection Functions\n // --------------------\n\n // The cornerstone, an `each` implementation, aka `forEach`.\n // Handles raw objects in addition to array-likes. Treats all\n // sparse array-likes as if they were dense.\n _.each = _.forEach = function(obj, iteratee, context) {\n iteratee = optimizeCb(iteratee, context);\n var i, length;\n if (isArrayLike(obj)) {\n for (i = 0, length = obj.length; i < length; i++) {\n iteratee(obj[i], i, obj);\n }\n } else {\n var keys = _.keys(obj);\n for (i = 0, length = keys.length; i < length; i++) {\n iteratee(obj[keys[i]], keys[i], obj);\n }\n }\n return obj;\n };\n\n // Return the results of applying the iteratee to each element.\n _.map = _.collect = function(obj, iteratee, context) {\n iteratee = cb(iteratee, context);\n var keys = !isArrayLike(obj) && _.keys(obj),\n length = (keys || obj).length,\n results = Array(length);\n for (var index = 0; index < length; index++) {\n var currentKey = keys ? keys[index] : index;\n results[index] = iteratee(obj[currentKey], currentKey, obj);\n }\n return results;\n };\n\n // Create a reducing function iterating left or right.\n function createReduce(dir) {\n // Optimized iterator function as using arguments.length\n // in the main function will deoptimize the, see #1991.\n function iterator(obj, iteratee, memo, keys, index, length) {\n for (; index >= 0 && index < length; index += dir) {\n var currentKey = keys ? keys[index] : index;\n memo = iteratee(memo, obj[currentKey], currentKey, obj);\n }\n return memo;\n }\n\n return function(obj, iteratee, memo, context) {\n iteratee = optimizeCb(iteratee, context, 4);\n var keys = !isArrayLike(obj) && _.keys(obj),\n length = (keys || obj).length,\n index = dir > 0 ? 0 : length - 1;\n // Determine the initial value if none is provided.\n if (arguments.length < 3) {\n memo = obj[keys ? keys[index] : index];\n index += dir;\n }\n return iterator(obj, iteratee, memo, keys, index, length);\n };\n }\n\n // **Reduce** builds up a single result from a list of values, aka `inject`,\n // or `foldl`.\n _.reduce = _.foldl = _.inject = createReduce(1);\n\n // The right-associative version of reduce, also known as `foldr`.\n _.reduceRight = _.foldr = createReduce(-1);\n\n // Return the first value which passes a truth test. Aliased as `detect`.\n _.find = _.detect = function(obj, predicate, context) {\n var key;\n if (isArrayLike(obj)) {\n key = _.findIndex(obj, predicate, context);\n } else {\n key = _.findKey(obj, predicate, context);\n }\n if (key !== void 0 && key !== -1) return obj[key];\n };\n\n // Return all the elements that pass a truth test.\n // Aliased as `select`.\n _.filter = _.select = function(obj, predicate, context) {\n var results = [];\n predicate = cb(predicate, context);\n _.each(obj, function(value, index, list) {\n if (predicate(value, index, list)) results.push(value);\n });\n return results;\n };\n\n // Return all the elements for which a truth test fails.\n _.reject = function(obj, predicate, context) {\n return _.filter(obj, _.negate(cb(predicate)), context);\n };\n\n // Determine whether all of the elements match a truth test.\n // Aliased as `all`.\n _.every = _.all = function(obj, predicate, context) {\n predicate = cb(predicate, context);\n var keys = !isArrayLike(obj) && _.keys(obj),\n length = (keys || obj).length;\n for (var index = 0; index < length; index++) {\n var currentKey = keys ? keys[index] : index;\n if (!predicate(obj[currentKey], currentKey, obj)) return false;\n }\n return true;\n };\n\n // Determine if at least one element in the object matches a truth test.\n // Aliased as `any`.\n _.some = _.any = function(obj, predicate, context) {\n predicate = cb(predicate, context);\n var keys = !isArrayLike(obj) && _.keys(obj),\n length = (keys || obj).length;\n for (var index = 0; index < length; index++) {\n var currentKey = keys ? keys[index] : index;\n if (predicate(obj[currentKey], currentKey, obj)) return true;\n }\n return false;\n };\n\n // Determine if the array or object contains a given item (using `===`).\n // Aliased as `includes` and `include`.\n _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {\n if (!isArrayLike(obj)) obj = _.values(obj);\n if (typeof fromIndex != 'number' || guard) fromIndex = 0;\n return _.indexOf(obj, item, fromIndex) >= 0;\n };\n\n // Invoke a method (with arguments) on every item in a collection.\n _.invoke = function(obj, method) {\n var args = slice.call(arguments, 2);\n var isFunc = _.isFunction(method);\n return _.map(obj, function(value) {\n var func = isFunc ? method : value[method];\n return func == null ? func : func.apply(value, args);\n });\n };\n\n // Convenience version of a common use case of `map`: fetching a property.\n _.pluck = function(obj, key) {\n return _.map(obj, _.property(key));\n };\n\n // Convenience version of a common use case of `filter`: selecting only objects\n // containing specific `key:value` pairs.\n _.where = function(obj, attrs) {\n return _.filter(obj, _.matcher(attrs));\n };\n\n // Convenience version of a common use case of `find`: getting the first object\n // containing specific `key:value` pairs.\n _.findWhere = function(obj, attrs) {\n return _.find(obj, _.matcher(attrs));\n };\n\n // Return the maximum element (or element-based computation).\n _.max = function(obj, iteratee, context) {\n var result = -Infinity, lastComputed = -Infinity,\n value, computed;\n if (iteratee == null && obj != null) {\n obj = isArrayLike(obj) ? obj : _.values(obj);\n for (var i = 0, length = obj.length; i < length; i++) {\n value = obj[i];\n if (value > result) {\n result = value;\n }\n }\n } else {\n iteratee = cb(iteratee, context);\n _.each(obj, function(value, index, list) {\n computed = iteratee(value, index, list);\n if (computed > lastComputed || computed === -Infinity && result === -Infinity) {\n result = value;\n lastComputed = computed;\n }\n });\n }\n return result;\n };\n\n // Return the minimum element (or element-based computation).\n _.min = function(obj, iteratee, context) {\n var result = Infinity, lastComputed = Infinity,\n value, computed;\n if (iteratee == null && obj != null) {\n obj = isArrayLike(obj) ? obj : _.values(obj);\n for (var i = 0, length = obj.length; i < length; i++) {\n value = obj[i];\n if (value < result) {\n result = value;\n }\n }\n } else {\n iteratee = cb(iteratee, context);\n _.each(obj, function(value, index, list) {\n computed = iteratee(value, index, list);\n if (computed < lastComputed || computed === Infinity && result === Infinity) {\n result = value;\n lastComputed = computed;\n }\n });\n }\n return result;\n };\n\n // Shuffle a collection, using the modern version of the\n // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).\n _.shuffle = function(obj) {\n var set = isArrayLike(obj) ? obj : _.values(obj);\n var length = set.length;\n var shuffled = Array(length);\n for (var index = 0, rand; index < length; index++) {\n rand = _.random(0, index);\n if (rand !== index) shuffled[index] = shuffled[rand];\n shuffled[rand] = set[index];\n }\n return shuffled;\n };\n\n // Sample **n** random values from a collection.\n // If **n** is not specified, returns a single random element.\n // The internal `guard` argument allows it to work with `map`.\n _.sample = function(obj, n, guard) {\n if (n == null || guard) {\n if (!isArrayLike(obj)) obj = _.values(obj);\n return obj[_.random(obj.length - 1)];\n }\n return _.shuffle(obj).slice(0, Math.max(0, n));\n };\n\n // Sort the object's values by a criterion produced by an iteratee.\n _.sortBy = function(obj, iteratee, context) {\n iteratee = cb(iteratee, context);\n return _.pluck(_.map(obj, function(value, index, list) {\n return {\n value: value,\n index: index,\n criteria: iteratee(value, index, list)\n };\n }).sort(function(left, right) {\n var a = left.criteria;\n var b = right.criteria;\n if (a !== b) {\n if (a > b || a === void 0) return 1;\n if (a < b || b === void 0) return -1;\n }\n return left.index - right.index;\n }), 'value');\n };\n\n // An internal function used for aggregate \"group by\" operations.\n var group = function(behavior) {\n return function(obj, iteratee, context) {\n var result = {};\n iteratee = cb(iteratee, context);\n _.each(obj, function(value, index) {\n var key = iteratee(value, index, obj);\n behavior(result, value, key);\n });\n return result;\n };\n };\n\n // Groups the object's values by a criterion. Pass either a string attribute\n // to group by, or a function that returns the criterion.\n _.groupBy = group(function(result, value, key) {\n if (_.has(result, key)) result[key].push(value); else result[key] = [value];\n });\n\n // Indexes the object's values by a criterion, similar to `groupBy`, but for\n // when you know that your index values will be unique.\n _.indexBy = group(function(result, value, key) {\n result[key] = value;\n });\n\n // Counts instances of an object that group by a certain criterion. Pass\n // either a string attribute to count by, or a function that returns the\n // criterion.\n _.countBy = group(function(result, value, key) {\n if (_.has(result, key)) result[key]++; else result[key] = 1;\n });\n\n // Safely create a real, live array from anything iterable.\n _.toArray = function(obj) {\n if (!obj) return [];\n if (_.isArray(obj)) return slice.call(obj);\n if (isArrayLike(obj)) return _.map(obj, _.identity);\n return _.values(obj);\n };\n\n // Return the number of elements in an object.\n _.size = function(obj) {\n if (obj == null) return 0;\n return isArrayLike(obj) ? obj.length : _.keys(obj).length;\n };\n\n // Split a collection into two arrays: one whose elements all satisfy the given\n // predicate, and one whose elements all do not satisfy the predicate.\n _.partition = function(obj, predicate, context) {\n predicate = cb(predicate, context);\n var pass = [], fail = [];\n _.each(obj, function(value, key, obj) {\n (predicate(value, key, obj) ? pass : fail).push(value);\n });\n return [pass, fail];\n };\n\n // Array Functions\n // ---------------\n\n // Get the first element of an array. Passing **n** will return the first N\n // values in the array. Aliased as `head` and `take`. The **guard** check\n // allows it to work with `_.map`.\n _.first = _.head = _.take = function(array, n, guard) {\n if (array == null) return void 0;\n if (n == null || guard) return array[0];\n return _.initial(array, array.length - n);\n };\n\n // Returns everything but the last entry of the array. Especially useful on\n // the arguments object. Passing **n** will return all the values in\n // the array, excluding the last N.\n _.initial = function(array, n, guard) {\n return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));\n };\n\n // Get the last element of an array. Passing **n** will return the last N\n // values in the array.\n _.last = function(array, n, guard) {\n if (array == null) return void 0;\n if (n == null || guard) return array[array.length - 1];\n return _.rest(array, Math.max(0, array.length - n));\n };\n\n // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.\n // Especially useful on the arguments object. Passing an **n** will return\n // the rest N values in the array.\n _.rest = _.tail = _.drop = function(array, n, guard) {\n return slice.call(array, n == null || guard ? 1 : n);\n };\n\n // Trim out all falsy values from an array.\n _.compact = function(array) {\n return _.filter(array, _.identity);\n };\n\n // Internal implementation of a recursive `flatten` function.\n var flatten = function(input, shallow, strict, startIndex) {\n var output = [], idx = 0;\n for (var i = startIndex || 0, length = getLength(input); i < length; i++) {\n var value = input[i];\n if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {\n //flatten current level of array or arguments object\n if (!shallow) value = flatten(value, shallow, strict);\n var j = 0, len = value.length;\n output.length += len;\n while (j < len) {\n output[idx++] = value[j++];\n }\n } else if (!strict) {\n output[idx++] = value;\n }\n }\n return output;\n };\n\n // Flatten out an array, either recursively (by default), or just one level.\n _.flatten = function(array, shallow) {\n return flatten(array, shallow, false);\n };\n\n // Return a version of the array that does not contain the specified value(s).\n _.without = function(array) {\n return _.difference(array, slice.call(arguments, 1));\n };\n\n // Produce a duplicate-free version of the array. If the array has already\n // been sorted, you have the option of using a faster algorithm.\n // Aliased as `unique`.\n _.uniq = _.unique = function(array, isSorted, iteratee, context) {\n if (!_.isBoolean(isSorted)) {\n context = iteratee;\n iteratee = isSorted;\n isSorted = false;\n }\n if (iteratee != null) iteratee = cb(iteratee, context);\n var result = [];\n var seen = [];\n for (var i = 0, length = getLength(array); i < length; i++) {\n var value = array[i],\n computed = iteratee ? iteratee(value, i, array) : value;\n if (isSorted) {\n if (!i || seen !== computed) result.push(value);\n seen = computed;\n } else if (iteratee) {\n if (!_.contains(seen, computed)) {\n seen.push(computed);\n result.push(value);\n }\n } else if (!_.contains(result, value)) {\n result.push(value);\n }\n }\n return result;\n };\n\n // Produce an array that contains the union: each distinct element from all of\n // the passed-in arrays.\n _.union = function() {\n return _.uniq(flatten(arguments, true, true));\n };\n\n // Produce an array that contains every item shared between all the\n // passed-in arrays.\n _.intersection = function(array) {\n var result = [];\n var argsLength = arguments.length;\n for (var i = 0, length = getLength(array); i < length; i++) {\n var item = array[i];\n if (_.contains(result, item)) continue;\n for (var j = 1; j < argsLength; j++) {\n if (!_.contains(arguments[j], item)) break;\n }\n if (j === argsLength) result.push(item);\n }\n return result;\n };\n\n // Take the difference between one array and a number of other arrays.\n // Only the elements present in just the first array will remain.\n _.difference = function(array) {\n var rest = flatten(arguments, true, true, 1);\n return _.filter(array, function(value){\n return !_.contains(rest, value);\n });\n };\n\n // Zip together multiple lists into a single array -- elements that share\n // an index go together.\n _.zip = function() {\n return _.unzip(arguments);\n };\n\n // Complement of _.zip. Unzip accepts an array of arrays and groups\n // each array's elements on shared indices\n _.unzip = function(array) {\n var length = array && _.max(array, getLength).length || 0;\n var result = Array(length);\n\n for (var index = 0; index < length; index++) {\n result[index] = _.pluck(array, index);\n }\n return result;\n };\n\n // Converts lists into objects. Pass either a single array of `[key, value]`\n // pairs, or two parallel arrays of the same length -- one of keys, and one of\n // the corresponding values.\n _.object = function(list, values) {\n var result = {};\n for (var i = 0, length = getLength(list); i < length; i++) {\n if (values) {\n result[list[i]] = values[i];\n } else {\n result[list[i][0]] = list[i][1];\n }\n }\n return result;\n };\n\n // Generator function to create the findIndex and findLastIndex functions\n function createPredicateIndexFinder(dir) {\n return function(array, predicate, context) {\n predicate = cb(predicate, context);\n var length = getLength(array);\n var index = dir > 0 ? 0 : length - 1;\n for (; index >= 0 && index < length; index += dir) {\n if (predicate(array[index], index, array)) return index;\n }\n return -1;\n };\n }\n\n // Returns the first index on an array-like that passes a predicate test\n _.findIndex = createPredicateIndexFinder(1);\n _.findLastIndex = createPredicateIndexFinder(-1);\n\n // Use a comparator function to figure out the smallest index at which\n // an object should be inserted so as to maintain order. Uses binary search.\n _.sortedIndex = function(array, obj, iteratee, context) {\n iteratee = cb(iteratee, context, 1);\n var value = iteratee(obj);\n var low = 0, high = getLength(array);\n while (low < high) {\n var mid = Math.floor((low + high) / 2);\n if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;\n }\n return low;\n };\n\n // Generator function to create the indexOf and lastIndexOf functions\n function createIndexFinder(dir, predicateFind, sortedIndex) {\n return function(array, item, idx) {\n var i = 0, length = getLength(array);\n if (typeof idx == 'number') {\n if (dir > 0) {\n i = idx >= 0 ? idx : Math.max(idx + length, i);\n } else {\n length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;\n }\n } else if (sortedIndex && idx && length) {\n idx = sortedIndex(array, item);\n return array[idx] === item ? idx : -1;\n }\n if (item !== item) {\n idx = predicateFind(slice.call(array, i, length), _.isNaN);\n return idx >= 0 ? idx + i : -1;\n }\n for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {\n if (array[idx] === item) return idx;\n }\n return -1;\n };\n }\n\n // Return the position of the first occurrence of an item in an array,\n // or -1 if the item is not included in the array.\n // If the array is large and already in sort order, pass `true`\n // for **isSorted** to use binary search.\n _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);\n _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);\n\n // Generate an integer Array containing an arithmetic progression. A port of\n // the native Python `range()` function. See\n // [the Python documentation](http://docs.python.org/library/functions.html#range).\n _.range = function(start, stop, step) {\n if (stop == null) {\n stop = start || 0;\n start = 0;\n }\n step = step || 1;\n\n var length = Math.max(Math.ceil((stop - start) / step), 0);\n var range = Array(length);\n\n for (var idx = 0; idx < length; idx++, start += step) {\n range[idx] = start;\n }\n\n return range;\n };\n\n // Function (ahem) Functions\n // ------------------\n\n // Determines whether to execute a function as a constructor\n // or a normal function with the provided arguments\n var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {\n if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);\n var self = baseCreate(sourceFunc.prototype);\n var result = sourceFunc.apply(self, args);\n if (_.isObject(result)) return result;\n return self;\n };\n\n // Create a function bound to a given object (assigning `this`, and arguments,\n // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if\n // available.\n _.bind = function(func, context) {\n if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));\n if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');\n var args = slice.call(arguments, 2);\n var bound = function() {\n return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));\n };\n return bound;\n };\n\n // Partially apply a function by creating a version that has had some of its\n // arguments pre-filled, without changing its dynamic `this` context. _ acts\n // as a placeholder, allowing any combination of arguments to be pre-filled.\n _.partial = function(func) {\n var boundArgs = slice.call(arguments, 1);\n var bound = function() {\n var position = 0, length = boundArgs.length;\n var args = Array(length);\n for (var i = 0; i < length; i++) {\n args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];\n }\n while (position < arguments.length) args.push(arguments[position++]);\n return executeBound(func, bound, this, this, args);\n };\n return bound;\n };\n\n // Bind a number of an object's methods to that object. Remaining arguments\n // are the method names to be bound. Useful for ensuring that all callbacks\n // defined on an object belong to it.\n _.bindAll = function(obj) {\n var i, length = arguments.length, key;\n if (length <= 1) throw new Error('bindAll must be passed function names');\n for (i = 1; i < length; i++) {\n key = arguments[i];\n obj[key] = _.bind(obj[key], obj);\n }\n return obj;\n };\n\n // Memoize an expensive function by storing its results.\n _.memoize = function(func, hasher) {\n var memoize = function(key) {\n var cache = memoize.cache;\n var address = '' + (hasher ? hasher.apply(this, arguments) : key);\n if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);\n return cache[address];\n };\n memoize.cache = {};\n return memoize;\n };\n\n // Delays a function for the given number of milliseconds, and then calls\n // it with the arguments supplied.\n _.delay = function(func, wait) {\n var args = slice.call(arguments, 2);\n return setTimeout(function(){\n return func.apply(null, args);\n }, wait);\n };\n\n // Defers a function, scheduling it to run after the current call stack has\n // cleared.\n _.defer = _.partial(_.delay, _, 1);\n\n // Returns a function, that, when invoked, will only be triggered at most once\n // during a given window of time. Normally, the throttled function will run\n // as much as it can, without ever going more than once per `wait` duration;\n // but if you'd like to disable the execution on the leading edge, pass\n // `{leading: false}`. To disable execution on the trailing edge, ditto.\n _.throttle = function(func, wait, options) {\n var context, args, result;\n var timeout = null;\n var previous = 0;\n if (!options) options = {};\n var later = function() {\n previous = options.leading === false ? 0 : _.now();\n timeout = null;\n result = func.apply(context, args);\n if (!timeout) context = args = null;\n };\n return function() {\n var now = _.now();\n if (!previous && options.leading === false) previous = now;\n var remaining = wait - (now - previous);\n context = this;\n args = arguments;\n if (remaining <= 0 || remaining > wait) {\n if (timeout) {\n clearTimeout(timeout);\n timeout = null;\n }\n previous = now;\n result = func.apply(context, args);\n if (!timeout) context = args = null;\n } else if (!timeout && options.trailing !== false) {\n timeout = setTimeout(later, remaining);\n }\n return result;\n };\n };\n\n // Returns a function, that, as long as it continues to be invoked, will not\n // be triggered. The function will be called after it stops being called for\n // N milliseconds. If `immediate` is passed, trigger the function on the\n // leading edge, instead of the trailing.\n _.debounce = function(func, wait, immediate) {\n var timeout, args, context, timestamp, result;\n\n var later = function() {\n var last = _.now() - timestamp;\n\n if (last < wait && last >= 0) {\n timeout = setTimeout(later, wait - last);\n } else {\n timeout = null;\n if (!immediate) {\n result = func.apply(context, args);\n if (!timeout) context = args = null;\n }\n }\n };\n\n return function() {\n context = this;\n args = arguments;\n timestamp = _.now();\n var callNow = immediate && !timeout;\n if (!timeout) timeout = setTimeout(later, wait);\n if (callNow) {\n result = func.apply(context, args);\n context = args = null;\n }\n\n return result;\n };\n };\n\n // Returns the first function passed as an argument to the second,\n // allowing you to adjust arguments, run code before and after, and\n // conditionally execute the original function.\n _.wrap = function(func, wrapper) {\n return _.partial(wrapper, func);\n };\n\n // Returns a negated version of the passed-in predicate.\n _.negate = function(predicate) {\n return function() {\n return !predicate.apply(this, arguments);\n };\n };\n\n // Returns a function that is the composition of a list of functions, each\n // consuming the return value of the function that follows.\n _.compose = function() {\n var args = arguments;\n var start = args.length - 1;\n return function() {\n var i = start;\n var result = args[start].apply(this, arguments);\n while (i--) result = args[i].call(this, result);\n return result;\n };\n };\n\n // Returns a function that will only be executed on and after the Nth call.\n _.after = function(times, func) {\n return function() {\n if (--times < 1) {\n return func.apply(this, arguments);\n }\n };\n };\n\n // Returns a function that will only be executed up to (but not including) the Nth call.\n _.before = function(times, func) {\n var memo;\n return function() {\n if (--times > 0) {\n memo = func.apply(this, arguments);\n }\n if (times <= 1) func = null;\n return memo;\n };\n };\n\n // Returns a function that will be executed at most one time, no matter how\n // often you call it. Useful for lazy initialization.\n _.once = _.partial(_.before, 2);\n\n // Object Functions\n // ----------------\n\n // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.\n var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');\n var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',\n 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];\n\n function collectNonEnumProps(obj, keys) {\n var nonEnumIdx = nonEnumerableProps.length;\n var constructor = obj.constructor;\n var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;\n\n // Constructor is a special case.\n var prop = 'constructor';\n if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);\n\n while (nonEnumIdx--) {\n prop = nonEnumerableProps[nonEnumIdx];\n if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {\n keys.push(prop);\n }\n }\n }\n\n // Retrieve the names of an object's own properties.\n // Delegates to **ECMAScript 5**'s native `Object.keys`\n _.keys = function(obj) {\n if (!_.isObject(obj)) return [];\n if (nativeKeys) return nativeKeys(obj);\n var keys = [];\n for (var key in obj) if (_.has(obj, key)) keys.push(key);\n // Ahem, IE < 9.\n if (hasEnumBug) collectNonEnumProps(obj, keys);\n return keys;\n };\n\n // Retrieve all the property names of an object.\n _.allKeys = function(obj) {\n if (!_.isObject(obj)) return [];\n var keys = [];\n for (var key in obj) keys.push(key);\n // Ahem, IE < 9.\n if (hasEnumBug) collectNonEnumProps(obj, keys);\n return keys;\n };\n\n // Retrieve the values of an object's properties.\n _.values = function(obj) {\n var keys = _.keys(obj);\n var length = keys.length;\n var values = Array(length);\n for (var i = 0; i < length; i++) {\n values[i] = obj[keys[i]];\n }\n return values;\n };\n\n // Returns the results of applying the iteratee to each element of the object\n // In contrast to _.map it returns an object\n _.mapObject = function(obj, iteratee, context) {\n iteratee = cb(iteratee, context);\n var keys = _.keys(obj),\n length = keys.length,\n results = {},\n currentKey;\n for (var index = 0; index < length; index++) {\n currentKey = keys[index];\n results[currentKey] = iteratee(obj[currentKey], currentKey, obj);\n }\n return results;\n };\n\n // Convert an object into a list of `[key, value]` pairs.\n _.pairs = function(obj) {\n var keys = _.keys(obj);\n var length = keys.length;\n var pairs = Array(length);\n for (var i = 0; i < length; i++) {\n pairs[i] = [keys[i], obj[keys[i]]];\n }\n return pairs;\n };\n\n // Invert the keys and values of an object. The values must be serializable.\n _.invert = function(obj) {\n var result = {};\n var keys = _.keys(obj);\n for (var i = 0, length = keys.length; i < length; i++) {\n result[obj[keys[i]]] = keys[i];\n }\n return result;\n };\n\n // Return a sorted list of the function names available on the object.\n // Aliased as `methods`\n _.functions = _.methods = function(obj) {\n var names = [];\n for (var key in obj) {\n if (_.isFunction(obj[key])) names.push(key);\n }\n return names.sort();\n };\n\n // Extend a given object with all the properties in passed-in object(s).\n _.extend = createAssigner(_.allKeys);\n\n // Assigns a given object with all the own properties in the passed-in object(s)\n // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)\n _.extendOwn = _.assign = createAssigner(_.keys);\n\n // Returns the first key on an object that passes a predicate test\n _.findKey = function(obj, predicate, context) {\n predicate = cb(predicate, context);\n var keys = _.keys(obj), key;\n for (var i = 0, length = keys.length; i < length; i++) {\n key = keys[i];\n if (predicate(obj[key], key, obj)) return key;\n }\n };\n\n // Return a copy of the object only containing the whitelisted properties.\n _.pick = function(object, oiteratee, context) {\n var result = {}, obj = object, iteratee, keys;\n if (obj == null) return result;\n if (_.isFunction(oiteratee)) {\n keys = _.allKeys(obj);\n iteratee = optimizeCb(oiteratee, context);\n } else {\n keys = flatten(arguments, false, false, 1);\n iteratee = function(value, key, obj) { return key in obj; };\n obj = Object(obj);\n }\n for (var i = 0, length = keys.length; i < length; i++) {\n var key = keys[i];\n var value = obj[key];\n if (iteratee(value, key, obj)) result[key] = value;\n }\n return result;\n };\n\n // Return a copy of the object without the blacklisted properties.\n _.omit = function(obj, iteratee, context) {\n if (_.isFunction(iteratee)) {\n iteratee = _.negate(iteratee);\n } else {\n var keys = _.map(flatten(arguments, false, false, 1), String);\n iteratee = function(value, key) {\n return !_.contains(keys, key);\n };\n }\n return _.pick(obj, iteratee, context);\n };\n\n // Fill in a given object with default properties.\n _.defaults = createAssigner(_.allKeys, true);\n\n // Creates an object that inherits from the given prototype object.\n // If additional properties are provided then they will be added to the\n // created object.\n _.create = function(prototype, props) {\n var result = baseCreate(prototype);\n if (props) _.extendOwn(result, props);\n return result;\n };\n\n // Create a (shallow-cloned) duplicate of an object.\n _.clone = function(obj) {\n if (!_.isObject(obj)) return obj;\n return _.isArray(obj) ? obj.slice() : _.extend({}, obj);\n };\n\n // Invokes interceptor with the obj, and then returns obj.\n // The primary purpose of this method is to \"tap into\" a method chain, in\n // order to perform operations on intermediate results within the chain.\n _.tap = function(obj, interceptor) {\n interceptor(obj);\n return obj;\n };\n\n // Returns whether an object has a given set of `key:value` pairs.\n _.isMatch = function(object, attrs) {\n var keys = _.keys(attrs), length = keys.length;\n if (object == null) return !length;\n var obj = Object(object);\n for (var i = 0; i < length; i++) {\n var key = keys[i];\n if (attrs[key] !== obj[key] || !(key in obj)) return false;\n }\n return true;\n };\n\n\n // Internal recursive comparison function for `isEqual`.\n var eq = function(a, b, aStack, bStack) {\n // Identical objects are equal. `0 === -0`, but they aren't identical.\n // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).\n if (a === b) return a !== 0 || 1 / a === 1 / b;\n // A strict comparison is necessary because `null == undefined`.\n if (a == null || b == null) return a === b;\n // Unwrap any wrapped objects.\n if (a instanceof _) a = a._wrapped;\n if (b instanceof _) b = b._wrapped;\n // Compare `[[Class]]` names.\n var className = toString.call(a);\n if (className !== toString.call(b)) return false;\n switch (className) {\n // Strings, numbers, regular expressions, dates, and booleans are compared by value.\n case '[object RegExp]':\n // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')\n case '[object String]':\n // Primitives and their corresponding object wrappers are equivalent; thus, `\"5\"` is\n // equivalent to `new String(\"5\")`.\n return '' + a === '' + b;\n case '[object Number]':\n // `NaN`s are equivalent, but non-reflexive.\n // Object(NaN) is equivalent to NaN\n if (+a !== +a) return +b !== +b;\n // An `egal` comparison is performed for other numeric values.\n return +a === 0 ? 1 / +a === 1 / b : +a === +b;\n case '[object Date]':\n case '[object Boolean]':\n // Coerce dates and booleans to numeric primitive values. Dates are compared by their\n // millisecond representations. Note that invalid dates with millisecond representations\n // of `NaN` are not equivalent.\n return +a === +b;\n }\n\n var areArrays = className === '[object Array]';\n if (!areArrays) {\n if (typeof a != 'object' || typeof b != 'object') return false;\n\n // Objects with different constructors are not equivalent, but `Object`s or `Array`s\n // from different frames are.\n var aCtor = a.constructor, bCtor = b.constructor;\n if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&\n _.isFunction(bCtor) && bCtor instanceof bCtor)\n && ('constructor' in a && 'constructor' in b)) {\n return false;\n }\n }\n // Assume equality for cyclic structures. The algorithm for detecting cyclic\n // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.\n\n // Initializing stack of traversed objects.\n // It's done here since we only need them for objects and arrays comparison.\n aStack = aStack || [];\n bStack = bStack || [];\n var length = aStack.length;\n while (length--) {\n // Linear search. Performance is inversely proportional to the number of\n // unique nested structures.\n if (aStack[length] === a) return bStack[length] === b;\n }\n\n // Add the first object to the stack of traversed objects.\n aStack.push(a);\n bStack.push(b);\n\n // Recursively compare objects and arrays.\n if (areArrays) {\n // Compare array lengths to determine if a deep comparison is necessary.\n length = a.length;\n if (length !== b.length) return false;\n // Deep compare the contents, ignoring non-numeric properties.\n while (length--) {\n if (!eq(a[length], b[length], aStack, bStack)) return false;\n }\n } else {\n // Deep compare objects.\n var keys = _.keys(a), key;\n length = keys.length;\n // Ensure that both objects contain the same number of properties before comparing deep equality.\n if (_.keys(b).length !== length) return false;\n while (length--) {\n // Deep compare each member\n key = keys[length];\n if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;\n }\n }\n // Remove the first object from the stack of traversed objects.\n aStack.pop();\n bStack.pop();\n return true;\n };\n\n // Perform a deep comparison to check if two objects are equal.\n _.isEqual = function(a, b) {\n return eq(a, b);\n };\n\n // Is a given array, string, or object empty?\n // An \"empty\" object has no enumerable own-properties.\n _.isEmpty = function(obj) {\n if (obj == null) return true;\n if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;\n return _.keys(obj).length === 0;\n };\n\n // Is a given value a DOM element?\n _.isElement = function(obj) {\n return !!(obj && obj.nodeType === 1);\n };\n\n // Is a given value an array?\n // Delegates to ECMA5's native Array.isArray\n _.isArray = nativeIsArray || function(obj) {\n return toString.call(obj) === '[object Array]';\n };\n\n // Is a given variable an object?\n _.isObject = function(obj) {\n var type = typeof obj;\n return type === 'function' || type === 'object' && !!obj;\n };\n\n // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.\n _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {\n _['is' + name] = function(obj) {\n return toString.call(obj) === '[object ' + name + ']';\n };\n });\n\n // Define a fallback version of the method in browsers (ahem, IE < 9), where\n // there isn't any inspectable \"Arguments\" type.\n if (!_.isArguments(arguments)) {\n _.isArguments = function(obj) {\n return _.has(obj, 'callee');\n };\n }\n\n // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,\n // IE 11 (#1621), and in Safari 8 (#1929).\n if (typeof /./ != 'function' && typeof Int8Array != 'object') {\n _.isFunction = function(obj) {\n return typeof obj == 'function' || false;\n };\n }\n\n // Is a given object a finite number?\n _.isFinite = function(obj) {\n return isFinite(obj) && !isNaN(parseFloat(obj));\n };\n\n // Is the given value `NaN`? (NaN is the only number which does not equal itself).\n _.isNaN = function(obj) {\n return _.isNumber(obj) && obj !== +obj;\n };\n\n // Is a given value a boolean?\n _.isBoolean = function(obj) {\n return obj === true || obj === false || toString.call(obj) === '[object Boolean]';\n };\n\n // Is a given value equal to null?\n _.isNull = function(obj) {\n return obj === null;\n };\n\n // Is a given variable undefined?\n _.isUndefined = function(obj) {\n return obj === void 0;\n };\n\n // Shortcut function for checking if an object has a given property directly\n // on itself (in other words, not on a prototype).\n _.has = function(obj, key) {\n return obj != null && hasOwnProperty.call(obj, key);\n };\n\n // Utility Functions\n // -----------------\n\n // Run Underscore.js in *noConflict* mode, returning the `_` variable to its\n // previous owner. Returns a reference to the Underscore object.\n _.noConflict = function() {\n root._ = previousUnderscore;\n return this;\n };\n\n // Keep the identity function around for default iteratees.\n _.identity = function(value) {\n return value;\n };\n\n // Predicate-generating functions. Often useful outside of Underscore.\n _.constant = function(value) {\n return function() {\n return value;\n };\n };\n\n _.noop = function(){};\n\n _.property = property;\n\n // Generates a function for a given object that returns a given property.\n _.propertyOf = function(obj) {\n return obj == null ? function(){} : function(key) {\n return obj[key];\n };\n };\n\n // Returns a predicate for checking whether an object has a given set of\n // `key:value` pairs.\n _.matcher = _.matches = function(attrs) {\n attrs = _.extendOwn({}, attrs);\n return function(obj) {\n return _.isMatch(obj, attrs);\n };\n };\n\n // Run a function **n** times.\n _.times = function(n, iteratee, context) {\n var accum = Array(Math.max(0, n));\n iteratee = optimizeCb(iteratee, context, 1);\n for (var i = 0; i < n; i++) accum[i] = iteratee(i);\n return accum;\n };\n\n // Return a random integer between min and max (inclusive).\n _.random = function(min, max) {\n if (max == null) {\n max = min;\n min = 0;\n }\n return min + Math.floor(Math.random() * (max - min + 1));\n };\n\n // A (possibly faster) way to get the current timestamp as an integer.\n _.now = Date.now || function() {\n return new Date().getTime();\n };\n\n // List of HTML entities for escaping.\n var escapeMap = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n '`': '`'\n };\n var unescapeMap = _.invert(escapeMap);\n\n // Functions for escaping and unescaping strings to/from HTML interpolation.\n var createEscaper = function(map) {\n var escaper = function(match) {\n return map[match];\n };\n // Regexes for identifying a key that needs to be escaped\n var source = '(?:' + _.keys(map).join('|') + ')';\n var testRegexp = RegExp(source);\n var replaceRegexp = RegExp(source, 'g');\n return function(string) {\n string = string == null ? '' : '' + string;\n return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;\n };\n };\n _.escape = createEscaper(escapeMap);\n _.unescape = createEscaper(unescapeMap);\n\n // If the value of the named `property` is a function then invoke it with the\n // `object` as context; otherwise, return it.\n _.result = function(object, property, fallback) {\n var value = object == null ? void 0 : object[property];\n if (value === void 0) {\n value = fallback;\n }\n return _.isFunction(value) ? value.call(object) : value;\n };\n\n // Generate a unique integer id (unique within the entire client session).\n // Useful for temporary DOM ids.\n var idCounter = 0;\n _.uniqueId = function(prefix) {\n var id = ++idCounter + '';\n return prefix ? prefix + id : id;\n };\n\n // By default, Underscore uses ERB-style template delimiters, change the\n // following template settings to use alternative delimiters.\n _.templateSettings = {\n evaluate : /<%([\\s\\S]+?)%>/g,\n interpolate : /<%=([\\s\\S]+?)%>/g,\n escape : /<%-([\\s\\S]+?)%>/g\n };\n\n // When customizing `templateSettings`, if you don't want to define an\n // interpolation, evaluation or escaping regex, we need one that is\n // guaranteed not to match.\n var noMatch = /(.)^/;\n\n // Certain characters need to be escaped so that they can be put into a\n // string literal.\n var escapes = {\n \"'\": \"'\",\n '\\\\': '\\\\',\n '\\r': 'r',\n '\\n': 'n',\n '\\u2028': 'u2028',\n '\\u2029': 'u2029'\n };\n\n var escaper = /\\\\|'|\\r|\\n|\\u2028|\\u2029/g;\n\n var escapeChar = function(match) {\n return '\\\\' + escapes[match];\n };\n\n // JavaScript micro-templating, similar to John Resig's implementation.\n // Underscore templating handles arbitrary delimiters, preserves whitespace,\n // and correctly escapes quotes within interpolated code.\n // NB: `oldSettings` only exists for backwards compatibility.\n _.template = function(text, settings, oldSettings) {\n if (!settings && oldSettings) settings = oldSettings;\n settings = _.defaults({}, settings, _.templateSettings);\n\n // Combine delimiters into one regular expression via alternation.\n var matcher = RegExp([\n (settings.escape || noMatch).source,\n (settings.interpolate || noMatch).source,\n (settings.evaluate || noMatch).source\n ].join('|') + '|$', 'g');\n\n // Compile the template source, escaping string literals appropriately.\n var index = 0;\n var source = \"__p+='\";\n text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {\n source += text.slice(index, offset).replace(escaper, escapeChar);\n index = offset + match.length;\n\n if (escape) {\n source += \"'+\\n((__t=(\" + escape + \"))==null?'':_.escape(__t))+\\n'\";\n } else if (interpolate) {\n source += \"'+\\n((__t=(\" + interpolate + \"))==null?'':__t)+\\n'\";\n } else if (evaluate) {\n source += \"';\\n\" + evaluate + \"\\n__p+='\";\n }\n\n // Adobe VMs need the match returned to produce the correct offest.\n return match;\n });\n source += \"';\\n\";\n\n // If a variable is not specified, place data values in local scope.\n if (!settings.variable) source = 'with(obj||{}){\\n' + source + '}\\n';\n\n source = \"var __t,__p='',__j=Array.prototype.join,\" +\n \"print=function(){__p+=__j.call(arguments,'');};\\n\" +\n source + 'return __p;\\n';\n\n try {\n var render = new Function(settings.variable || 'obj', '_', source);\n } catch (e) {\n e.source = source;\n throw e;\n }\n\n var template = function(data) {\n return render.call(this, data, _);\n };\n\n // Provide the compiled source as a convenience for precompilation.\n var argument = settings.variable || 'obj';\n template.source = 'function(' + argument + '){\\n' + source + '}';\n\n return template;\n };\n\n // Add a \"chain\" function. Start chaining a wrapped Underscore object.\n _.chain = function(obj) {\n var instance = _(obj);\n instance._chain = true;\n return instance;\n };\n\n // OOP\n // ---------------\n // If Underscore is called as a function, it returns a wrapped object that\n // can be used OO-style. This wrapper holds altered versions of all the\n // underscore functions. Wrapped objects may be chained.\n\n // Helper function to continue chaining intermediate results.\n var result = function(instance, obj) {\n return instance._chain ? _(obj).chain() : obj;\n };\n\n // Add your own custom functions to the Underscore object.\n _.mixin = function(obj) {\n _.each(_.functions(obj), function(name) {\n var func = _[name] = obj[name];\n _.prototype[name] = function() {\n var args = [this._wrapped];\n push.apply(args, arguments);\n return result(this, func.apply(_, args));\n };\n });\n };\n\n // Add all of the Underscore functions to the wrapper object.\n _.mixin(_);\n\n // Add all mutator Array functions to the wrapper.\n _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {\n var method = ArrayProto[name];\n _.prototype[name] = function() {\n var obj = this._wrapped;\n method.apply(obj, arguments);\n if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];\n return result(this, obj);\n };\n });\n\n // Add all accessor Array functions to the wrapper.\n _.each(['concat', 'join', 'slice'], function(name) {\n var method = ArrayProto[name];\n _.prototype[name] = function() {\n return result(this, method.apply(this._wrapped, arguments));\n };\n });\n\n // Extracts the result from a wrapped and chained object.\n _.prototype.value = function() {\n return this._wrapped;\n };\n\n // Provide unwrapping proxy for some methods used in engine operations\n // such as arithmetic and JSON stringification.\n _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;\n\n _.prototype.toString = function() {\n return '' + this._wrapped;\n };\n\n // AMD registration happens at the end for compatibility with AMD loaders\n // that may not enforce next-turn semantics on modules. Even though general\n // practice for AMD registration is to be anonymous, underscore registers\n // as a named module because, like jQuery, it is a base library that is\n // popular enough to be bundled in a third party lib, but not be part of\n // an AMD load request. Those cases could generate an error when an\n // anonymous define() is called outside of a loader request.\n if (typeof define === 'function' && define.amd) {\n define('underscore', [], function() {\n return _;\n });\n }\n}.call(this));\n\n","/*! Hammer.JS - v2.0.4 - 2014-09-28\n * http://hammerjs.github.io/\n *\n * Copyright (c) 2014 Jorik Tangelder;\n * Licensed under the MIT license */\n(function(window, document, exportName, undefined) {\n 'use strict';\n\nvar VENDOR_PREFIXES = ['', 'webkit', 'moz', 'MS', 'ms', 'o'];\nvar TEST_ELEMENT = document.createElement('div');\n\nvar TYPE_FUNCTION = 'function';\n\nvar round = Math.round;\nvar abs = Math.abs;\nvar now = Date.now;\n\n/**\n * set a timeout with a given scope\n * @param {Function} fn\n * @param {Number} timeout\n * @param {Object} context\n * @returns {number}\n */\nfunction setTimeoutContext(fn, timeout, context) {\n return setTimeout(bindFn(fn, context), timeout);\n}\n\n/**\n * if the argument is an array, we want to execute the fn on each entry\n * if it aint an array we don't want to do a thing.\n * this is used by all the methods that accept a single and array argument.\n * @param {*|Array} arg\n * @param {String} fn\n * @param {Object} [context]\n * @returns {Boolean}\n */\nfunction invokeArrayArg(arg, fn, context) {\n if (Array.isArray(arg)) {\n each(arg, context[fn], context);\n return true;\n }\n return false;\n}\n\n/**\n * walk objects and arrays\n * @param {Object} obj\n * @param {Function} iterator\n * @param {Object} context\n */\nfunction each(obj, iterator, context) {\n var i;\n\n if (!obj) {\n return;\n }\n\n if (obj.forEach) {\n obj.forEach(iterator, context);\n } else if (obj.length !== undefined) {\n i = 0;\n while (i < obj.length) {\n iterator.call(context, obj[i], i, obj);\n i++;\n }\n } else {\n for (i in obj) {\n obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);\n }\n }\n}\n\n/**\n * extend object.\n * means that properties in dest will be overwritten by the ones in src.\n * @param {Object} dest\n * @param {Object} src\n * @param {Boolean} [merge]\n * @returns {Object} dest\n */\nfunction extend(dest, src, merge) {\n var keys = Object.keys(src);\n var i = 0;\n while (i < keys.length) {\n if (!merge || (merge && dest[keys[i]] === undefined)) {\n dest[keys[i]] = src[keys[i]];\n }\n i++;\n }\n return dest;\n}\n\n/**\n * merge the values from src in the dest.\n * means that properties that exist in dest will not be overwritten by src\n * @param {Object} dest\n * @param {Object} src\n * @returns {Object} dest\n */\nfunction merge(dest, src) {\n return extend(dest, src, true);\n}\n\n/**\n * simple class inheritance\n * @param {Function} child\n * @param {Function} base\n * @param {Object} [properties]\n */\nfunction inherit(child, base, properties) {\n var baseP = base.prototype,\n childP;\n\n childP = child.prototype = Object.create(baseP);\n childP.constructor = child;\n childP._super = baseP;\n\n if (properties) {\n extend(childP, properties);\n }\n}\n\n/**\n * simple function bind\n * @param {Function} fn\n * @param {Object} context\n * @returns {Function}\n */\nfunction bindFn(fn, context) {\n return function boundFn() {\n return fn.apply(context, arguments);\n };\n}\n\n/**\n * let a boolean value also be a function that must return a boolean\n * this first item in args will be used as the context\n * @param {Boolean|Function} val\n * @param {Array} [args]\n * @returns {Boolean}\n */\nfunction boolOrFn(val, args) {\n if (typeof val == TYPE_FUNCTION) {\n return val.apply(args ? args[0] || undefined : undefined, args);\n }\n return val;\n}\n\n/**\n * use the val2 when val1 is undefined\n * @param {*} val1\n * @param {*} val2\n * @returns {*}\n */\nfunction ifUndefined(val1, val2) {\n return (val1 === undefined) ? val2 : val1;\n}\n\n/**\n * addEventListener with multiple events at once\n * @param {EventTarget} target\n * @param {String} types\n * @param {Function} handler\n */\nfunction addEventListeners(target, types, handler) {\n each(splitStr(types), function(type) {\n target.addEventListener(type, handler, false);\n });\n}\n\n/**\n * removeEventListener with multiple events at once\n * @param {EventTarget} target\n * @param {String} types\n * @param {Function} handler\n */\nfunction removeEventListeners(target, types, handler) {\n each(splitStr(types), function(type) {\n target.removeEventListener(type, handler, false);\n });\n}\n\n/**\n * find if a node is in the given parent\n * @method hasParent\n * @param {HTMLElement} node\n * @param {HTMLElement} parent\n * @return {Boolean} found\n */\nfunction hasParent(node, parent) {\n while (node) {\n if (node == parent) {\n return true;\n }\n node = node.parentNode;\n }\n return false;\n}\n\n/**\n * small indexOf wrapper\n * @param {String} str\n * @param {String} find\n * @returns {Boolean} found\n */\nfunction inStr(str, find) {\n return str.indexOf(find) > -1;\n}\n\n/**\n * split string on whitespace\n * @param {String} str\n * @returns {Array} words\n */\nfunction splitStr(str) {\n return str.trim().split(/\\s+/g);\n}\n\n/**\n * find if a array contains the object using indexOf or a simple polyFill\n * @param {Array} src\n * @param {String} find\n * @param {String} [findByKey]\n * @return {Boolean|Number} false when not found, or the index\n */\nfunction inArray(src, find, findByKey) {\n if (src.indexOf && !findByKey) {\n return src.indexOf(find);\n } else {\n var i = 0;\n while (i < src.length) {\n if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {\n return i;\n }\n i++;\n }\n return -1;\n }\n}\n\n/**\n * convert array-like objects to real arrays\n * @param {Object} obj\n * @returns {Array}\n */\nfunction toArray(obj) {\n return Array.prototype.slice.call(obj, 0);\n}\n\n/**\n * unique array with objects based on a key (like 'id') or just by the array's value\n * @param {Array} src [{id:1},{id:2},{id:1}]\n * @param {String} [key]\n * @param {Boolean} [sort=False]\n * @returns {Array} [{id:1},{id:2}]\n */\nfunction uniqueArray(src, key, sort) {\n var results = [];\n var values = [];\n var i = 0;\n\n while (i < src.length) {\n var val = key ? src[i][key] : src[i];\n if (inArray(values, val) < 0) {\n results.push(src[i]);\n }\n values[i] = val;\n i++;\n }\n\n if (sort) {\n if (!key) {\n results = results.sort();\n } else {\n results = results.sort(function sortUniqueArray(a, b) {\n return a[key] > b[key];\n });\n }\n }\n\n return results;\n}\n\n/**\n * get the prefixed property\n * @param {Object} obj\n * @param {String} property\n * @returns {String|Undefined} prefixed\n */\nfunction prefixed(obj, property) {\n var prefix, prop;\n var camelProp = property[0].toUpperCase() + property.slice(1);\n\n var i = 0;\n while (i < VENDOR_PREFIXES.length) {\n prefix = VENDOR_PREFIXES[i];\n prop = (prefix) ? prefix + camelProp : property;\n\n if (prop in obj) {\n return prop;\n }\n i++;\n }\n return undefined;\n}\n\n/**\n * get a unique id\n * @returns {number} uniqueId\n */\nvar _uniqueId = 1;\nfunction uniqueId() {\n return _uniqueId++;\n}\n\n/**\n * get the window object of an element\n * @param {HTMLElement} element\n * @returns {DocumentView|Window}\n */\nfunction getWindowForElement(element) {\n var doc = element.ownerDocument;\n return (doc.defaultView || doc.parentWindow);\n}\n\nvar MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;\n\nvar SUPPORT_TOUCH = ('ontouchstart' in window);\nvar SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;\nvar SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);\n\nvar INPUT_TYPE_TOUCH = 'touch';\nvar INPUT_TYPE_PEN = 'pen';\nvar INPUT_TYPE_MOUSE = 'mouse';\nvar INPUT_TYPE_KINECT = 'kinect';\n\nvar COMPUTE_INTERVAL = 25;\n\nvar INPUT_START = 1;\nvar INPUT_MOVE = 2;\nvar INPUT_END = 4;\nvar INPUT_CANCEL = 8;\n\nvar DIRECTION_NONE = 1;\nvar DIRECTION_LEFT = 2;\nvar DIRECTION_RIGHT = 4;\nvar DIRECTION_UP = 8;\nvar DIRECTION_DOWN = 16;\n\nvar DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;\nvar DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;\nvar DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;\n\nvar PROPS_XY = ['x', 'y'];\nvar PROPS_CLIENT_XY = ['clientX', 'clientY'];\n\n/**\n * create new input type manager\n * @param {Manager} manager\n * @param {Function} callback\n * @returns {Input}\n * @constructor\n */\nfunction Input(manager, callback) {\n var self = this;\n this.manager = manager;\n this.callback = callback;\n this.element = manager.element;\n this.target = manager.options.inputTarget;\n\n // smaller wrapper around the handler, for the scope and the enabled state of the manager,\n // so when disabled the input events are completely bypassed.\n this.domHandler = function(ev) {\n if (boolOrFn(manager.options.enable, [manager])) {\n self.handler(ev);\n }\n };\n\n this.init();\n\n}\n\nInput.prototype = {\n /**\n * should handle the inputEvent data and trigger the callback\n * @virtual\n */\n handler: function() { },\n\n /**\n * bind the events\n */\n init: function() {\n this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);\n this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);\n this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);\n },\n\n /**\n * unbind the events\n */\n destroy: function() {\n this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);\n this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);\n this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);\n }\n};\n\n/**\n * create new input type manager\n * called by the Manager constructor\n * @param {Hammer} manager\n * @returns {Input}\n */\nfunction createInputInstance(manager) {\n var Type;\n var inputClass = manager.options.inputClass;\n\n if (inputClass) {\n Type = inputClass;\n } else if (SUPPORT_POINTER_EVENTS) {\n Type = PointerEventInput;\n } else if (SUPPORT_ONLY_TOUCH) {\n Type = TouchInput;\n } else if (!SUPPORT_TOUCH) {\n Type = MouseInput;\n } else {\n Type = TouchMouseInput;\n }\n return new (Type)(manager, inputHandler);\n}\n\n/**\n * handle input events\n * @param {Manager} manager\n * @param {String} eventType\n * @param {Object} input\n */\nfunction inputHandler(manager, eventType, input) {\n var pointersLen = input.pointers.length;\n var changedPointersLen = input.changedPointers.length;\n var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));\n var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));\n\n input.isFirst = !!isFirst;\n input.isFinal = !!isFinal;\n\n if (isFirst) {\n manager.session = {};\n }\n\n // source event is the normalized value of the domEvents\n // like 'touchstart, mouseup, pointerdown'\n input.eventType = eventType;\n\n // compute scale, rotation etc\n computeInputData(manager, input);\n\n // emit secret event\n manager.emit('hammer.input', input);\n\n manager.recognize(input);\n manager.session.prevInput = input;\n}\n\n/**\n * extend the data with some usable properties like scale, rotate, velocity etc\n * @param {Object} manager\n * @param {Object} input\n */\nfunction computeInputData(manager, input) {\n var session = manager.session;\n var pointers = input.pointers;\n var pointersLength = pointers.length;\n\n // store the first input to calculate the distance and direction\n if (!session.firstInput) {\n session.firstInput = simpleCloneInputData(input);\n }\n\n // to compute scale and rotation we need to store the multiple touches\n if (pointersLength > 1 && !session.firstMultiple) {\n session.firstMultiple = simpleCloneInputData(input);\n } else if (pointersLength === 1) {\n session.firstMultiple = false;\n }\n\n var firstInput = session.firstInput;\n var firstMultiple = session.firstMultiple;\n var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;\n\n var center = input.center = getCenter(pointers);\n input.timeStamp = now();\n input.deltaTime = input.timeStamp - firstInput.timeStamp;\n\n input.angle = getAngle(offsetCenter, center);\n input.distance = getDistance(offsetCenter, center);\n\n computeDeltaXY(session, input);\n input.offsetDirection = getDirection(input.deltaX, input.deltaY);\n\n input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;\n input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;\n\n computeIntervalInputData(session, input);\n\n // find the correct target\n var target = manager.element;\n if (hasParent(input.srcEvent.target, target)) {\n target = input.srcEvent.target;\n }\n input.target = target;\n}\n\nfunction computeDeltaXY(session, input) {\n var center = input.center;\n var offset = session.offsetDelta || {};\n var prevDelta = session.prevDelta || {};\n var prevInput = session.prevInput || {};\n\n if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {\n prevDelta = session.prevDelta = {\n x: prevInput.deltaX || 0,\n y: prevInput.deltaY || 0\n };\n\n offset = session.offsetDelta = {\n x: center.x,\n y: center.y\n };\n }\n\n input.deltaX = prevDelta.x + (center.x - offset.x);\n input.deltaY = prevDelta.y + (center.y - offset.y);\n}\n\n/**\n * velocity is calculated every x ms\n * @param {Object} session\n * @param {Object} input\n */\nfunction computeIntervalInputData(session, input) {\n var last = session.lastInterval || input,\n deltaTime = input.timeStamp - last.timeStamp,\n velocity, velocityX, velocityY, direction;\n\n if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {\n var deltaX = last.deltaX - input.deltaX;\n var deltaY = last.deltaY - input.deltaY;\n\n var v = getVelocity(deltaTime, deltaX, deltaY);\n velocityX = v.x;\n velocityY = v.y;\n velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;\n direction = getDirection(deltaX, deltaY);\n\n session.lastInterval = input;\n } else {\n // use latest velocity info if it doesn't overtake a minimum period\n velocity = last.velocity;\n velocityX = last.velocityX;\n velocityY = last.velocityY;\n direction = last.direction;\n }\n\n input.velocity = velocity;\n input.velocityX = velocityX;\n input.velocityY = velocityY;\n input.direction = direction;\n}\n\n/**\n * create a simple clone from the input used for storage of firstInput and firstMultiple\n * @param {Object} input\n * @returns {Object} clonedInputData\n */\nfunction simpleCloneInputData(input) {\n // make a simple copy of the pointers because we will get a reference if we don't\n // we only need clientXY for the calculations\n var pointers = [];\n var i = 0;\n while (i < input.pointers.length) {\n pointers[i] = {\n clientX: round(input.pointers[i].clientX),\n clientY: round(input.pointers[i].clientY)\n };\n i++;\n }\n\n return {\n timeStamp: now(),\n pointers: pointers,\n center: getCenter(pointers),\n deltaX: input.deltaX,\n deltaY: input.deltaY\n };\n}\n\n/**\n * get the center of all the pointers\n * @param {Array} pointers\n * @return {Object} center contains `x` and `y` properties\n */\nfunction getCenter(pointers) {\n var pointersLength = pointers.length;\n\n // no need to loop when only one touch\n if (pointersLength === 1) {\n return {\n x: round(pointers[0].clientX),\n y: round(pointers[0].clientY)\n };\n }\n\n var x = 0, y = 0, i = 0;\n while (i < pointersLength) {\n x += pointers[i].clientX;\n y += pointers[i].clientY;\n i++;\n }\n\n return {\n x: round(x / pointersLength),\n y: round(y / pointersLength)\n };\n}\n\n/**\n * calculate the velocity between two points. unit is in px per ms.\n * @param {Number} deltaTime\n * @param {Number} x\n * @param {Number} y\n * @return {Object} velocity `x` and `y`\n */\nfunction getVelocity(deltaTime, x, y) {\n return {\n x: x / deltaTime || 0,\n y: y / deltaTime || 0\n };\n}\n\n/**\n * get the direction between two points\n * @param {Number} x\n * @param {Number} y\n * @return {Number} direction\n */\nfunction getDirection(x, y) {\n if (x === y) {\n return DIRECTION_NONE;\n }\n\n if (abs(x) >= abs(y)) {\n return x > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;\n }\n return y > 0 ? DIRECTION_UP : DIRECTION_DOWN;\n}\n\n/**\n * calculate the absolute distance between two points\n * @param {Object} p1 {x, y}\n * @param {Object} p2 {x, y}\n * @param {Array} [props] containing x and y keys\n * @return {Number} distance\n */\nfunction getDistance(p1, p2, props) {\n if (!props) {\n props = PROPS_XY;\n }\n var x = p2[props[0]] - p1[props[0]],\n y = p2[props[1]] - p1[props[1]];\n\n return Math.sqrt((x * x) + (y * y));\n}\n\n/**\n * calculate the angle between two coordinates\n * @param {Object} p1\n * @param {Object} p2\n * @param {Array} [props] containing x and y keys\n * @return {Number} angle\n */\nfunction getAngle(p1, p2, props) {\n if (!props) {\n props = PROPS_XY;\n }\n var x = p2[props[0]] - p1[props[0]],\n y = p2[props[1]] - p1[props[1]];\n return Math.atan2(y, x) * 180 / Math.PI;\n}\n\n/**\n * calculate the rotation degrees between two pointersets\n * @param {Array} start array of pointers\n * @param {Array} end array of pointers\n * @return {Number} rotation\n */\nfunction getRotation(start, end) {\n return getAngle(end[1], end[0], PROPS_CLIENT_XY) - getAngle(start[1], start[0], PROPS_CLIENT_XY);\n}\n\n/**\n * calculate the scale factor between two pointersets\n * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out\n * @param {Array} start array of pointers\n * @param {Array} end array of pointers\n * @return {Number} scale\n */\nfunction getScale(start, end) {\n return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);\n}\n\nvar MOUSE_INPUT_MAP = {\n mousedown: INPUT_START,\n mousemove: INPUT_MOVE,\n mouseup: INPUT_END\n};\n\nvar MOUSE_ELEMENT_EVENTS = 'mousedown';\nvar MOUSE_WINDOW_EVENTS = 'mousemove mouseup';\n\n/**\n * Mouse events input\n * @constructor\n * @extends Input\n */\nfunction MouseInput() {\n this.evEl = MOUSE_ELEMENT_EVENTS;\n this.evWin = MOUSE_WINDOW_EVENTS;\n\n this.allow = true; // used by Input.TouchMouse to disable mouse events\n this.pressed = false; // mousedown state\n\n Input.apply(this, arguments);\n}\n\ninherit(MouseInput, Input, {\n /**\n * handle mouse events\n * @param {Object} ev\n */\n handler: function MEhandler(ev) {\n var eventType = MOUSE_INPUT_MAP[ev.type];\n\n // on start we want to have the left mouse button down\n if (eventType & INPUT_START && ev.button === 0) {\n this.pressed = true;\n }\n\n if (eventType & INPUT_MOVE && ev.which !== 1) {\n eventType = INPUT_END;\n }\n\n // mouse must be down, and mouse events are allowed (see the TouchMouse input)\n if (!this.pressed || !this.allow) {\n return;\n }\n\n if (eventType & INPUT_END) {\n this.pressed = false;\n }\n\n this.callback(this.manager, eventType, {\n pointers: [ev],\n changedPointers: [ev],\n pointerType: INPUT_TYPE_MOUSE,\n srcEvent: ev\n });\n }\n});\n\nvar POINTER_INPUT_MAP = {\n pointerdown: INPUT_START,\n pointermove: INPUT_MOVE,\n pointerup: INPUT_END,\n pointercancel: INPUT_CANCEL,\n pointerout: INPUT_CANCEL\n};\n\n// in IE10 the pointer types is defined as an enum\nvar IE10_POINTER_TYPE_ENUM = {\n 2: INPUT_TYPE_TOUCH,\n 3: INPUT_TYPE_PEN,\n 4: INPUT_TYPE_MOUSE,\n 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816\n};\n\nvar POINTER_ELEMENT_EVENTS = 'pointerdown';\nvar POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';\n\n// IE10 has prefixed support, and case-sensitive\nif (window.MSPointerEvent) {\n POINTER_ELEMENT_EVENTS = 'MSPointerDown';\n POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';\n}\n\n/**\n * Pointer events input\n * @constructor\n * @extends Input\n */\nfunction PointerEventInput() {\n this.evEl = POINTER_ELEMENT_EVENTS;\n this.evWin = POINTER_WINDOW_EVENTS;\n\n Input.apply(this, arguments);\n\n this.store = (this.manager.session.pointerEvents = []);\n}\n\ninherit(PointerEventInput, Input, {\n /**\n * handle mouse events\n * @param {Object} ev\n */\n handler: function PEhandler(ev) {\n var store = this.store;\n var removePointer = false;\n\n var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');\n var eventType = POINTER_INPUT_MAP[eventTypeNormalized];\n var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;\n\n var isTouch = (pointerType == INPUT_TYPE_TOUCH);\n\n // get index of the event in the store\n var storeIndex = inArray(store, ev.pointerId, 'pointerId');\n\n // start and mouse must be down\n if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {\n if (storeIndex < 0) {\n store.push(ev);\n storeIndex = store.length - 1;\n }\n } else if (eventType & (INPUT_END | INPUT_CANCEL)) {\n removePointer = true;\n }\n\n // it not found, so the pointer hasn't been down (so it's probably a hover)\n if (storeIndex < 0) {\n return;\n }\n\n // update the event in the store\n store[storeIndex] = ev;\n\n this.callback(this.manager, eventType, {\n pointers: store,\n changedPointers: [ev],\n pointerType: pointerType,\n srcEvent: ev\n });\n\n if (removePointer) {\n // remove from the store\n store.splice(storeIndex, 1);\n }\n }\n});\n\nvar SINGLE_TOUCH_INPUT_MAP = {\n touchstart: INPUT_START,\n touchmove: INPUT_MOVE,\n touchend: INPUT_END,\n touchcancel: INPUT_CANCEL\n};\n\nvar SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';\nvar SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';\n\n/**\n * Touch events input\n * @constructor\n * @extends Input\n */\nfunction SingleTouchInput() {\n this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;\n this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;\n this.started = false;\n\n Input.apply(this, arguments);\n}\n\ninherit(SingleTouchInput, Input, {\n handler: function TEhandler(ev) {\n var type = SINGLE_TOUCH_INPUT_MAP[ev.type];\n\n // should we handle the touch events?\n if (type === INPUT_START) {\n this.started = true;\n }\n\n if (!this.started) {\n return;\n }\n\n var touches = normalizeSingleTouches.call(this, ev, type);\n\n // when done, reset the started state\n if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {\n this.started = false;\n }\n\n this.callback(this.manager, type, {\n pointers: touches[0],\n changedPointers: touches[1],\n pointerType: INPUT_TYPE_TOUCH,\n srcEvent: ev\n });\n }\n});\n\n/**\n * @this {TouchInput}\n * @param {Object} ev\n * @param {Number} type flag\n * @returns {undefined|Array} [all, changed]\n */\nfunction normalizeSingleTouches(ev, type) {\n var all = toArray(ev.touches);\n var changed = toArray(ev.changedTouches);\n\n if (type & (INPUT_END | INPUT_CANCEL)) {\n all = uniqueArray(all.concat(changed), 'identifier', true);\n }\n\n return [all, changed];\n}\n\nvar TOUCH_INPUT_MAP = {\n touchstart: INPUT_START,\n touchmove: INPUT_MOVE,\n touchend: INPUT_END,\n touchcancel: INPUT_CANCEL\n};\n\nvar TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';\n\n/**\n * Multi-user touch events input\n * @constructor\n * @extends Input\n */\nfunction TouchInput() {\n this.evTarget = TOUCH_TARGET_EVENTS;\n this.targetIds = {};\n\n Input.apply(this, arguments);\n}\n\ninherit(TouchInput, Input, {\n handler: function MTEhandler(ev) {\n var type = TOUCH_INPUT_MAP[ev.type];\n var touches = getTouches.call(this, ev, type);\n if (!touches) {\n return;\n }\n\n this.callback(this.manager, type, {\n pointers: touches[0],\n changedPointers: touches[1],\n pointerType: INPUT_TYPE_TOUCH,\n srcEvent: ev\n });\n }\n});\n\n/**\n * @this {TouchInput}\n * @param {Object} ev\n * @param {Number} type flag\n * @returns {undefined|Array} [all, changed]\n */\nfunction getTouches(ev, type) {\n var allTouches = toArray(ev.touches);\n var targetIds = this.targetIds;\n\n // when there is only one touch, the process can be simplified\n if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {\n targetIds[allTouches[0].identifier] = true;\n return [allTouches, allTouches];\n }\n\n var i,\n targetTouches,\n changedTouches = toArray(ev.changedTouches),\n changedTargetTouches = [],\n target = this.target;\n\n // get target touches from touches\n targetTouches = allTouches.filter(function(touch) {\n return hasParent(touch.target, target);\n });\n\n // collect touches\n if (type === INPUT_START) {\n i = 0;\n while (i < targetTouches.length) {\n targetIds[targetTouches[i].identifier] = true;\n i++;\n }\n }\n\n // filter changed touches to only contain touches that exist in the collected target ids\n i = 0;\n while (i < changedTouches.length) {\n if (targetIds[changedTouches[i].identifier]) {\n changedTargetTouches.push(changedTouches[i]);\n }\n\n // cleanup removed touches\n if (type & (INPUT_END | INPUT_CANCEL)) {\n delete targetIds[changedTouches[i].identifier];\n }\n i++;\n }\n\n if (!changedTargetTouches.length) {\n return;\n }\n\n return [\n // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'\n uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),\n changedTargetTouches\n ];\n}\n\n/**\n * Combined touch and mouse input\n *\n * Touch has a higher priority then mouse, and while touching no mouse events are allowed.\n * This because touch devices also emit mouse events while doing a touch.\n *\n * @constructor\n * @extends Input\n */\nfunction TouchMouseInput() {\n Input.apply(this, arguments);\n\n var handler = bindFn(this.handler, this);\n this.touch = new TouchInput(this.manager, handler);\n this.mouse = new MouseInput(this.manager, handler);\n}\n\ninherit(TouchMouseInput, Input, {\n /**\n * handle mouse and touch events\n * @param {Hammer} manager\n * @param {String} inputEvent\n * @param {Object} inputData\n */\n handler: function TMEhandler(manager, inputEvent, inputData) {\n var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),\n isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);\n\n // when we're in a touch event, so block all upcoming mouse events\n // most mobile browser also emit mouseevents, right after touchstart\n if (isTouch) {\n this.mouse.allow = false;\n } else if (isMouse && !this.mouse.allow) {\n return;\n }\n\n // reset the allowMouse when we're done\n if (inputEvent & (INPUT_END | INPUT_CANCEL)) {\n this.mouse.allow = true;\n }\n\n this.callback(manager, inputEvent, inputData);\n },\n\n /**\n * remove the event listeners\n */\n destroy: function destroy() {\n this.touch.destroy();\n this.mouse.destroy();\n }\n});\n\nvar PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');\nvar NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;\n\n// magical touchAction value\nvar TOUCH_ACTION_COMPUTE = 'compute';\nvar TOUCH_ACTION_AUTO = 'auto';\nvar TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented\nvar TOUCH_ACTION_NONE = 'none';\nvar TOUCH_ACTION_PAN_X = 'pan-x';\nvar TOUCH_ACTION_PAN_Y = 'pan-y';\n\n/**\n * Touch Action\n * sets the touchAction property or uses the js alternative\n * @param {Manager} manager\n * @param {String} value\n * @constructor\n */\nfunction TouchAction(manager, value) {\n this.manager = manager;\n this.set(value);\n}\n\nTouchAction.prototype = {\n /**\n * set the touchAction value on the element or enable the polyfill\n * @param {String} value\n */\n set: function(value) {\n // find out the touch-action by the event handlers\n if (value == TOUCH_ACTION_COMPUTE) {\n value = this.compute();\n }\n\n if (NATIVE_TOUCH_ACTION) {\n this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;\n }\n this.actions = value.toLowerCase().trim();\n },\n\n /**\n * just re-set the touchAction value\n */\n update: function() {\n this.set(this.manager.options.touchAction);\n },\n\n /**\n * compute the value for the touchAction property based on the recognizer's settings\n * @returns {String} value\n */\n compute: function() {\n var actions = [];\n each(this.manager.recognizers, function(recognizer) {\n if (boolOrFn(recognizer.options.enable, [recognizer])) {\n actions = actions.concat(recognizer.getTouchAction());\n }\n });\n return cleanTouchActions(actions.join(' '));\n },\n\n /**\n * this method is called on each input cycle and provides the preventing of the browser behavior\n * @param {Object} input\n */\n preventDefaults: function(input) {\n // not needed with native support for the touchAction property\n if (NATIVE_TOUCH_ACTION) {\n return;\n }\n\n var srcEvent = input.srcEvent;\n var direction = input.offsetDirection;\n\n // if the touch action did prevented once this session\n if (this.manager.session.prevented) {\n srcEvent.preventDefault();\n return;\n }\n\n var actions = this.actions;\n var hasNone = inStr(actions, TOUCH_ACTION_NONE);\n var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);\n var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);\n\n if (hasNone ||\n (hasPanY && direction & DIRECTION_HORIZONTAL) ||\n (hasPanX && direction & DIRECTION_VERTICAL)) {\n return this.preventSrc(srcEvent);\n }\n },\n\n /**\n * call preventDefault to prevent the browser's default behavior (scrolling in most cases)\n * @param {Object} srcEvent\n */\n preventSrc: function(srcEvent) {\n this.manager.session.prevented = true;\n srcEvent.preventDefault();\n }\n};\n\n/**\n * when the touchActions are collected they are not a valid value, so we need to clean things up. *\n * @param {String} actions\n * @returns {*}\n */\nfunction cleanTouchActions(actions) {\n // none\n if (inStr(actions, TOUCH_ACTION_NONE)) {\n return TOUCH_ACTION_NONE;\n }\n\n var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);\n var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);\n\n // pan-x and pan-y can be combined\n if (hasPanX && hasPanY) {\n return TOUCH_ACTION_PAN_X + ' ' + TOUCH_ACTION_PAN_Y;\n }\n\n // pan-x OR pan-y\n if (hasPanX || hasPanY) {\n return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;\n }\n\n // manipulation\n if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {\n return TOUCH_ACTION_MANIPULATION;\n }\n\n return TOUCH_ACTION_AUTO;\n}\n\n/**\n * Recognizer flow explained; *\n * All recognizers have the initial state of POSSIBLE when a input session starts.\n * The definition of a input session is from the first input until the last input, with all it's movement in it. *\n * Example session for mouse-input: mousedown -> mousemove -> mouseup\n *\n * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed\n * which determines with state it should be.\n *\n * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to\n * POSSIBLE to give it another change on the next cycle.\n *\n * Possible\n * |\n * +-----+---------------+\n * | |\n * +-----+-----+ |\n * | | |\n * Failed Cancelled |\n * +-------+------+\n * | |\n * Recognized Began\n * |\n * Changed\n * |\n * Ended/Recognized\n */\nvar STATE_POSSIBLE = 1;\nvar STATE_BEGAN = 2;\nvar STATE_CHANGED = 4;\nvar STATE_ENDED = 8;\nvar STATE_RECOGNIZED = STATE_ENDED;\nvar STATE_CANCELLED = 16;\nvar STATE_FAILED = 32;\n\n/**\n * Recognizer\n * Every recognizer needs to extend from this class.\n * @constructor\n * @param {Object} options\n */\nfunction Recognizer(options) {\n this.id = uniqueId();\n\n this.manager = null;\n this.options = merge(options || {}, this.defaults);\n\n // default is enable true\n this.options.enable = ifUndefined(this.options.enable, true);\n\n this.state = STATE_POSSIBLE;\n\n this.simultaneous = {};\n this.requireFail = [];\n}\n\nRecognizer.prototype = {\n /**\n * @virtual\n * @type {Object}\n */\n defaults: {},\n\n /**\n * set options\n * @param {Object} options\n * @return {Recognizer}\n */\n set: function(options) {\n extend(this.options, options);\n\n // also update the touchAction, in case something changed about the directions/enabled state\n this.manager && this.manager.touchAction.update();\n return this;\n },\n\n /**\n * recognize simultaneous with an other recognizer.\n * @param {Recognizer} otherRecognizer\n * @returns {Recognizer} this\n */\n recognizeWith: function(otherRecognizer) {\n if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {\n return this;\n }\n\n var simultaneous = this.simultaneous;\n otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);\n if (!simultaneous[otherRecognizer.id]) {\n simultaneous[otherRecognizer.id] = otherRecognizer;\n otherRecognizer.recognizeWith(this);\n }\n return this;\n },\n\n /**\n * drop the simultaneous link. it doesnt remove the link on the other recognizer.\n * @param {Recognizer} otherRecognizer\n * @returns {Recognizer} this\n */\n dropRecognizeWith: function(otherRecognizer) {\n if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {\n return this;\n }\n\n otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);\n delete this.simultaneous[otherRecognizer.id];\n return this;\n },\n\n /**\n * recognizer can only run when an other is failing\n * @param {Recognizer} otherRecognizer\n * @returns {Recognizer} this\n */\n requireFailure: function(otherRecognizer) {\n if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {\n return this;\n }\n\n var requireFail = this.requireFail;\n otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);\n if (inArray(requireFail, otherRecognizer) === -1) {\n requireFail.push(otherRecognizer);\n otherRecognizer.requireFailure(this);\n }\n return this;\n },\n\n /**\n * drop the requireFailure link. it does not remove the link on the other recognizer.\n * @param {Recognizer} otherRecognizer\n * @returns {Recognizer} this\n */\n dropRequireFailure: function(otherRecognizer) {\n if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {\n return this;\n }\n\n otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);\n var index = inArray(this.requireFail, otherRecognizer);\n if (index > -1) {\n this.requireFail.splice(index, 1);\n }\n return this;\n },\n\n /**\n * has require failures boolean\n * @returns {boolean}\n */\n hasRequireFailures: function() {\n return this.requireFail.length > 0;\n },\n\n /**\n * if the recognizer can recognize simultaneous with an other recognizer\n * @param {Recognizer} otherRecognizer\n * @returns {Boolean}\n */\n canRecognizeWith: function(otherRecognizer) {\n return !!this.simultaneous[otherRecognizer.id];\n },\n\n /**\n * You should use `tryEmit` instead of `emit` directly to check\n * that all the needed recognizers has failed before emitting.\n * @param {Object} input\n */\n emit: function(input) {\n var self = this;\n var state = this.state;\n\n function emit(withState) {\n self.manager.emit(self.options.event + (withState ? stateStr(state) : ''), input);\n }\n\n // 'panstart' and 'panmove'\n if (state < STATE_ENDED) {\n emit(true);\n }\n\n emit(); // simple 'eventName' events\n\n // panend and pancancel\n if (state >= STATE_ENDED) {\n emit(true);\n }\n },\n\n /**\n * Check that all the require failure recognizers has failed,\n * if true, it emits a gesture event,\n * otherwise, setup the state to FAILED.\n * @param {Object} input\n */\n tryEmit: function(input) {\n if (this.canEmit()) {\n return this.emit(input);\n }\n // it's failing anyway\n this.state = STATE_FAILED;\n },\n\n /**\n * can we emit?\n * @returns {boolean}\n */\n canEmit: function() {\n var i = 0;\n while (i < this.requireFail.length) {\n if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {\n return false;\n }\n i++;\n }\n return true;\n },\n\n /**\n * update the recognizer\n * @param {Object} inputData\n */\n recognize: function(inputData) {\n // make a new copy of the inputData\n // so we can change the inputData without messing up the other recognizers\n var inputDataClone = extend({}, inputData);\n\n // is is enabled and allow recognizing?\n if (!boolOrFn(this.options.enable, [this, inputDataClone])) {\n this.reset();\n this.state = STATE_FAILED;\n return;\n }\n\n // reset when we've reached the end\n if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {\n this.state = STATE_POSSIBLE;\n }\n\n this.state = this.process(inputDataClone);\n\n // the recognizer has recognized a gesture\n // so trigger an event\n if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {\n this.tryEmit(inputDataClone);\n }\n },\n\n /**\n * return the state of the recognizer\n * the actual recognizing happens in this method\n * @virtual\n * @param {Object} inputData\n * @returns {Const} STATE\n */\n process: function(inputData) { }, // jshint ignore:line\n\n /**\n * return the preferred touch-action\n * @virtual\n * @returns {Array}\n */\n getTouchAction: function() { },\n\n /**\n * called when the gesture isn't allowed to recognize\n * like when another is being recognized or it is disabled\n * @virtual\n */\n reset: function() { }\n};\n\n/**\n * get a usable string, used as event postfix\n * @param {Const} state\n * @returns {String} state\n */\nfunction stateStr(state) {\n if (state & STATE_CANCELLED) {\n return 'cancel';\n } else if (state & STATE_ENDED) {\n return 'end';\n } else if (state & STATE_CHANGED) {\n return 'move';\n } else if (state & STATE_BEGAN) {\n return 'start';\n }\n return '';\n}\n\n/**\n * direction cons to string\n * @param {Const} direction\n * @returns {String}\n */\nfunction directionStr(direction) {\n if (direction == DIRECTION_DOWN) {\n return 'down';\n } else if (direction == DIRECTION_UP) {\n return 'up';\n } else if (direction == DIRECTION_LEFT) {\n return 'left';\n } else if (direction == DIRECTION_RIGHT) {\n return 'right';\n }\n return '';\n}\n\n/**\n * get a recognizer by name if it is bound to a manager\n * @param {Recognizer|String} otherRecognizer\n * @param {Recognizer} recognizer\n * @returns {Recognizer}\n */\nfunction getRecognizerByNameIfManager(otherRecognizer, recognizer) {\n var manager = recognizer.manager;\n if (manager) {\n return manager.get(otherRecognizer);\n }\n return otherRecognizer;\n}\n\n/**\n * This recognizer is just used as a base for the simple attribute recognizers.\n * @constructor\n * @extends Recognizer\n */\nfunction AttrRecognizer() {\n Recognizer.apply(this, arguments);\n}\n\ninherit(AttrRecognizer, Recognizer, {\n /**\n * @namespace\n * @memberof AttrRecognizer\n */\n defaults: {\n /**\n * @type {Number}\n * @default 1\n */\n pointers: 1\n },\n\n /**\n * Used to check if it the recognizer receives valid input, like input.distance > 10.\n * @memberof AttrRecognizer\n * @param {Object} input\n * @returns {Boolean} recognized\n */\n attrTest: function(input) {\n var optionPointers = this.options.pointers;\n return optionPointers === 0 || input.pointers.length === optionPointers;\n },\n\n /**\n * Process the input and return the state for the recognizer\n * @memberof AttrRecognizer\n * @param {Object} input\n * @returns {*} State\n */\n process: function(input) {\n var state = this.state;\n var eventType = input.eventType;\n\n var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);\n var isValid = this.attrTest(input);\n\n // on cancel input and we've recognized before, return STATE_CANCELLED\n if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {\n return state | STATE_CANCELLED;\n } else if (isRecognized || isValid) {\n if (eventType & INPUT_END) {\n return state | STATE_ENDED;\n } else if (!(state & STATE_BEGAN)) {\n return STATE_BEGAN;\n }\n return state | STATE_CHANGED;\n }\n return STATE_FAILED;\n }\n});\n\n/**\n * Pan\n * Recognized when the pointer is down and moved in the allowed direction.\n * @constructor\n * @extends AttrRecognizer\n */\nfunction PanRecognizer() {\n AttrRecognizer.apply(this, arguments);\n\n this.pX = null;\n this.pY = null;\n}\n\ninherit(PanRecognizer, AttrRecognizer, {\n /**\n * @namespace\n * @memberof PanRecognizer\n */\n defaults: {\n event: 'pan',\n threshold: 10,\n pointers: 1,\n direction: DIRECTION_ALL\n },\n\n getTouchAction: function() {\n var direction = this.options.direction;\n var actions = [];\n if (direction & DIRECTION_HORIZONTAL) {\n actions.push(TOUCH_ACTION_PAN_Y);\n }\n if (direction & DIRECTION_VERTICAL) {\n actions.push(TOUCH_ACTION_PAN_X);\n }\n return actions;\n },\n\n directionTest: function(input) {\n var options = this.options;\n var hasMoved = true;\n var distance = input.distance;\n var direction = input.direction;\n var x = input.deltaX;\n var y = input.deltaY;\n\n // lock to axis?\n if (!(direction & options.direction)) {\n if (options.direction & DIRECTION_HORIZONTAL) {\n direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;\n hasMoved = x != this.pX;\n distance = Math.abs(input.deltaX);\n } else {\n direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;\n hasMoved = y != this.pY;\n distance = Math.abs(input.deltaY);\n }\n }\n input.direction = direction;\n return hasMoved && distance > options.threshold && direction & options.direction;\n },\n\n attrTest: function(input) {\n return AttrRecognizer.prototype.attrTest.call(this, input) &&\n (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));\n },\n\n emit: function(input) {\n this.pX = input.deltaX;\n this.pY = input.deltaY;\n\n var direction = directionStr(input.direction);\n if (direction) {\n this.manager.emit(this.options.event + direction, input);\n }\n\n this._super.emit.call(this, input);\n }\n});\n\n/**\n * Pinch\n * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).\n * @constructor\n * @extends AttrRecognizer\n */\nfunction PinchRecognizer() {\n AttrRecognizer.apply(this, arguments);\n}\n\ninherit(PinchRecognizer, AttrRecognizer, {\n /**\n * @namespace\n * @memberof PinchRecognizer\n */\n defaults: {\n event: 'pinch',\n threshold: 0,\n pointers: 2\n },\n\n getTouchAction: function() {\n return [TOUCH_ACTION_NONE];\n },\n\n attrTest: function(input) {\n return this._super.attrTest.call(this, input) &&\n (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);\n },\n\n emit: function(input) {\n this._super.emit.call(this, input);\n if (input.scale !== 1) {\n var inOut = input.scale < 1 ? 'in' : 'out';\n this.manager.emit(this.options.event + inOut, input);\n }\n }\n});\n\n/**\n * Press\n * Recognized when the pointer is down for x ms without any movement.\n * @constructor\n * @extends Recognizer\n */\nfunction PressRecognizer() {\n Recognizer.apply(this, arguments);\n\n this._timer = null;\n this._input = null;\n}\n\ninherit(PressRecognizer, Recognizer, {\n /**\n * @namespace\n * @memberof PressRecognizer\n */\n defaults: {\n event: 'press',\n pointers: 1,\n time: 500, // minimal time of the pointer to be pressed\n threshold: 5 // a minimal movement is ok, but keep it low\n },\n\n getTouchAction: function() {\n return [TOUCH_ACTION_AUTO];\n },\n\n process: function(input) {\n var options = this.options;\n var validPointers = input.pointers.length === options.pointers;\n var validMovement = input.distance < options.threshold;\n var validTime = input.deltaTime > options.time;\n\n this._input = input;\n\n // we only allow little movement\n // and we've reached an end event, so a tap is possible\n if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {\n this.reset();\n } else if (input.eventType & INPUT_START) {\n this.reset();\n this._timer = setTimeoutContext(function() {\n this.state = STATE_RECOGNIZED;\n this.tryEmit();\n }, options.time, this);\n } else if (input.eventType & INPUT_END) {\n return STATE_RECOGNIZED;\n }\n return STATE_FAILED;\n },\n\n reset: function() {\n clearTimeout(this._timer);\n },\n\n emit: function(input) {\n if (this.state !== STATE_RECOGNIZED) {\n return;\n }\n\n if (input && (input.eventType & INPUT_END)) {\n this.manager.emit(this.options.event + 'up', input);\n } else {\n this._input.timeStamp = now();\n this.manager.emit(this.options.event, this._input);\n }\n }\n});\n\n/**\n * Rotate\n * Recognized when two or more pointer are moving in a circular motion.\n * @constructor\n * @extends AttrRecognizer\n */\nfunction RotateRecognizer() {\n AttrRecognizer.apply(this, arguments);\n}\n\ninherit(RotateRecognizer, AttrRecognizer, {\n /**\n * @namespace\n * @memberof RotateRecognizer\n */\n defaults: {\n event: 'rotate',\n threshold: 0,\n pointers: 2\n },\n\n getTouchAction: function() {\n return [TOUCH_ACTION_NONE];\n },\n\n attrTest: function(input) {\n return this._super.attrTest.call(this, input) &&\n (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);\n }\n});\n\n/**\n * Swipe\n * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.\n * @constructor\n * @extends AttrRecognizer\n */\nfunction SwipeRecognizer() {\n AttrRecognizer.apply(this, arguments);\n}\n\ninherit(SwipeRecognizer, AttrRecognizer, {\n /**\n * @namespace\n * @memberof SwipeRecognizer\n */\n defaults: {\n event: 'swipe',\n threshold: 10,\n velocity: 0.65,\n direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,\n pointers: 1\n },\n\n getTouchAction: function() {\n return PanRecognizer.prototype.getTouchAction.call(this);\n },\n\n attrTest: function(input) {\n var direction = this.options.direction;\n var velocity;\n\n if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {\n velocity = input.velocity;\n } else if (direction & DIRECTION_HORIZONTAL) {\n velocity = input.velocityX;\n } else if (direction & DIRECTION_VERTICAL) {\n velocity = input.velocityY;\n }\n\n return this._super.attrTest.call(this, input) &&\n direction & input.direction &&\n input.distance > this.options.threshold &&\n abs(velocity) > this.options.velocity && input.eventType & INPUT_END;\n },\n\n emit: function(input) {\n var direction = directionStr(input.direction);\n if (direction) {\n this.manager.emit(this.options.event + direction, input);\n }\n\n this.manager.emit(this.options.event, input);\n }\n});\n\n/**\n * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur\n * between the given interval and position. The delay option can be used to recognize multi-taps without firing\n * a single tap.\n *\n * The eventData from the emitted event contains the property `tapCount`, which contains the amount of\n * multi-taps being recognized.\n * @constructor\n * @extends Recognizer\n */\nfunction TapRecognizer() {\n Recognizer.apply(this, arguments);\n\n // previous time and center,\n // used for tap counting\n this.pTime = false;\n this.pCenter = false;\n\n this._timer = null;\n this._input = null;\n this.count = 0;\n}\n\ninherit(TapRecognizer, Recognizer, {\n /**\n * @namespace\n * @memberof PinchRecognizer\n */\n defaults: {\n event: 'tap',\n pointers: 1,\n taps: 1,\n interval: 300, // max time between the multi-tap taps\n time: 250, // max time of the pointer to be down (like finger on the screen)\n threshold: 2, // a minimal movement is ok, but keep it low\n posThreshold: 10 // a multi-tap can be a bit off the initial position\n },\n\n getTouchAction: function() {\n return [TOUCH_ACTION_MANIPULATION];\n },\n\n process: function(input) {\n var options = this.options;\n\n var validPointers = input.pointers.length === options.pointers;\n var validMovement = input.distance < options.threshold;\n var validTouchTime = input.deltaTime < options.time;\n\n this.reset();\n\n if ((input.eventType & INPUT_START) && (this.count === 0)) {\n return this.failTimeout();\n }\n\n // we only allow little movement\n // and we've reached an end event, so a tap is possible\n if (validMovement && validTouchTime && validPointers) {\n if (input.eventType != INPUT_END) {\n return this.failTimeout();\n }\n\n var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;\n var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;\n\n this.pTime = input.timeStamp;\n this.pCenter = input.center;\n\n if (!validMultiTap || !validInterval) {\n this.count = 1;\n } else {\n this.count += 1;\n }\n\n this._input = input;\n\n // if tap count matches we have recognized it,\n // else it has began recognizing...\n var tapCount = this.count % options.taps;\n if (tapCount === 0) {\n // no failing requirements, immediately trigger the tap event\n // or wait as long as the multitap interval to trigger\n if (!this.hasRequireFailures()) {\n return STATE_RECOGNIZED;\n } else {\n this._timer = setTimeoutContext(function() {\n this.state = STATE_RECOGNIZED;\n this.tryEmit();\n }, options.interval, this);\n return STATE_BEGAN;\n }\n }\n }\n return STATE_FAILED;\n },\n\n failTimeout: function() {\n this._timer = setTimeoutContext(function() {\n this.state = STATE_FAILED;\n }, this.options.interval, this);\n return STATE_FAILED;\n },\n\n reset: function() {\n clearTimeout(this._timer);\n },\n\n emit: function() {\n if (this.state == STATE_RECOGNIZED ) {\n this._input.tapCount = this.count;\n this.manager.emit(this.options.event, this._input);\n }\n }\n});\n\n/**\n * Simple way to create an manager with a default set of recognizers.\n * @param {HTMLElement} element\n * @param {Object} [options]\n * @constructor\n */\nfunction Hammer(element, options) {\n options = options || {};\n options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);\n return new Manager(element, options);\n}\n\n/**\n * @const {string}\n */\nHammer.VERSION = '2.0.4';\n\n/**\n * default settings\n * @namespace\n */\nHammer.defaults = {\n /**\n * set if DOM events are being triggered.\n * But this is slower and unused by simple implementations, so disabled by default.\n * @type {Boolean}\n * @default false\n */\n domEvents: false,\n\n /**\n * The value for the touchAction property/fallback.\n * When set to `compute` it will magically set the correct value based on the added recognizers.\n * @type {String}\n * @default compute\n */\n touchAction: TOUCH_ACTION_COMPUTE,\n\n /**\n * @type {Boolean}\n * @default true\n */\n enable: true,\n\n /**\n * EXPERIMENTAL FEATURE -- can be removed/changed\n * Change the parent input target element.\n * If Null, then it is being set the to main element.\n * @type {Null|EventTarget}\n * @default null\n */\n inputTarget: null,\n\n /**\n * force an input class\n * @type {Null|Function}\n * @default null\n */\n inputClass: null,\n\n /**\n * Default recognizer setup when calling `Hammer()`\n * When creating a new Manager these will be skipped.\n * @type {Array}\n */\n preset: [\n // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]\n [RotateRecognizer, { enable: false }],\n [PinchRecognizer, { enable: false }, ['rotate']],\n [SwipeRecognizer,{ direction: DIRECTION_HORIZONTAL }],\n [PanRecognizer, { direction: DIRECTION_HORIZONTAL }, ['swipe']],\n [TapRecognizer],\n [TapRecognizer, { event: 'doubletap', taps: 2 }, ['tap']],\n [PressRecognizer]\n ],\n\n /**\n * Some CSS properties can be used to improve the working of Hammer.\n * Add them to this method and they will be set when creating a new Manager.\n * @namespace\n */\n cssProps: {\n /**\n * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.\n * @type {String}\n * @default 'none'\n */\n userSelect: 'none',\n\n /**\n * Disable the Windows Phone grippers when pressing an element.\n * @type {String}\n * @default 'none'\n */\n touchSelect: 'none',\n\n /**\n * Disables the default callout shown when you touch and hold a touch target.\n * On iOS, when you touch and hold a touch target such as a link, Safari displays\n * a callout containing information about the link. This property allows you to disable that callout.\n * @type {String}\n * @default 'none'\n */\n touchCallout: 'none',\n\n /**\n * Specifies whether zooming is enabled. Used by IE10>\n * @type {String}\n * @default 'none'\n */\n contentZooming: 'none',\n\n /**\n * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.\n * @type {String}\n * @default 'none'\n */\n userDrag: 'none',\n\n /**\n * Overrides the highlight color shown when the user taps a link or a JavaScript\n * clickable element in iOS. This property obeys the alpha value, if specified.\n * @type {String}\n * @default 'rgba(0,0,0,0)'\n */\n tapHighlightColor: 'rgba(0,0,0,0)'\n }\n};\n\nvar STOP = 1;\nvar FORCED_STOP = 2;\n\n/**\n * Manager\n * @param {HTMLElement} element\n * @param {Object} [options]\n * @constructor\n */\nfunction Manager(element, options) {\n options = options || {};\n\n this.options = merge(options, Hammer.defaults);\n this.options.inputTarget = this.options.inputTarget || element;\n\n this.handlers = {};\n this.session = {};\n this.recognizers = [];\n\n this.element = element;\n this.input = createInputInstance(this);\n this.touchAction = new TouchAction(this, this.options.touchAction);\n\n toggleCssProps(this, true);\n\n each(options.recognizers, function(item) {\n var recognizer = this.add(new (item[0])(item[1]));\n item[2] && recognizer.recognizeWith(item[2]);\n item[3] && recognizer.requireFailure(item[3]);\n }, this);\n}\n\nManager.prototype = {\n /**\n * set options\n * @param {Object} options\n * @returns {Manager}\n */\n set: function(options) {\n extend(this.options, options);\n\n // Options that need a little more setup\n if (options.touchAction) {\n this.touchAction.update();\n }\n if (options.inputTarget) {\n // Clean up existing event listeners and reinitialize\n this.input.destroy();\n this.input.target = options.inputTarget;\n this.input.init();\n }\n return this;\n },\n\n /**\n * stop recognizing for this session.\n * This session will be discarded, when a new [input]start event is fired.\n * When forced, the recognizer cycle is stopped immediately.\n * @param {Boolean} [force]\n */\n stop: function(force) {\n this.session.stopped = force ? FORCED_STOP : STOP;\n },\n\n /**\n * run the recognizers!\n * called by the inputHandler function on every movement of the pointers (touches)\n * it walks through all the recognizers and tries to detect the gesture that is being made\n * @param {Object} inputData\n */\n recognize: function(inputData) {\n var session = this.session;\n if (session.stopped) {\n return;\n }\n\n // run the touch-action polyfill\n this.touchAction.preventDefaults(inputData);\n\n var recognizer;\n var recognizers = this.recognizers;\n\n // this holds the recognizer that is being recognized.\n // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED\n // if no recognizer is detecting a thing, it is set to `null`\n var curRecognizer = session.curRecognizer;\n\n // reset when the last recognizer is recognized\n // or when we're in a new session\n if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {\n curRecognizer = session.curRecognizer = null;\n }\n\n var i = 0;\n while (i < recognizers.length) {\n recognizer = recognizers[i];\n\n // find out if we are allowed try to recognize the input for this one.\n // 1. allow if the session is NOT forced stopped (see the .stop() method)\n // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one\n // that is being recognized.\n // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.\n // this can be setup with the `recognizeWith()` method on the recognizer.\n if (session.stopped !== FORCED_STOP && ( // 1\n !curRecognizer || recognizer == curRecognizer || // 2\n recognizer.canRecognizeWith(curRecognizer))) { // 3\n recognizer.recognize(inputData);\n } else {\n recognizer.reset();\n }\n\n // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the\n // current active recognizer. but only if we don't already have an active recognizer\n if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {\n curRecognizer = session.curRecognizer = recognizer;\n }\n i++;\n }\n },\n\n /**\n * get a recognizer by its event name.\n * @param {Recognizer|String} recognizer\n * @returns {Recognizer|Null}\n */\n get: function(recognizer) {\n if (recognizer instanceof Recognizer) {\n return recognizer;\n }\n\n var recognizers = this.recognizers;\n for (var i = 0; i < recognizers.length; i++) {\n if (recognizers[i].options.event == recognizer) {\n return recognizers[i];\n }\n }\n return null;\n },\n\n /**\n * add a recognizer to the manager\n * existing recognizers with the same event name will be removed\n * @param {Recognizer} recognizer\n * @returns {Recognizer|Manager}\n */\n add: function(recognizer) {\n if (invokeArrayArg(recognizer, 'add', this)) {\n return this;\n }\n\n // remove existing\n var existing = this.get(recognizer.options.event);\n if (existing) {\n this.remove(existing);\n }\n\n this.recognizers.push(recognizer);\n recognizer.manager = this;\n\n this.touchAction.update();\n return recognizer;\n },\n\n /**\n * remove a recognizer by name or instance\n * @param {Recognizer|String} recognizer\n * @returns {Manager}\n */\n remove: function(recognizer) {\n if (invokeArrayArg(recognizer, 'remove', this)) {\n return this;\n }\n\n var recognizers = this.recognizers;\n recognizer = this.get(recognizer);\n recognizers.splice(inArray(recognizers, recognizer), 1);\n\n this.touchAction.update();\n return this;\n },\n\n /**\n * bind event\n * @param {String} events\n * @param {Function} handler\n * @returns {EventEmitter} this\n */\n on: function(events, handler) {\n var handlers = this.handlers;\n each(splitStr(events), function(event) {\n handlers[event] = handlers[event] || [];\n handlers[event].push(handler);\n });\n return this;\n },\n\n /**\n * unbind event, leave emit blank to remove all handlers\n * @param {String} events\n * @param {Function} [handler]\n * @returns {EventEmitter} this\n */\n off: function(events, handler) {\n var handlers = this.handlers;\n each(splitStr(events), function(event) {\n if (!handler) {\n delete handlers[event];\n } else {\n handlers[event].splice(inArray(handlers[event], handler), 1);\n }\n });\n return this;\n },\n\n /**\n * emit event to the listeners\n * @param {String} event\n * @param {Object} data\n */\n emit: function(event, data) {\n // we also want to trigger dom events\n if (this.options.domEvents) {\n triggerDomEvent(event, data);\n }\n\n // no handlers, so skip it all\n var handlers = this.handlers[event] && this.handlers[event].slice();\n if (!handlers || !handlers.length) {\n return;\n }\n\n data.type = event;\n data.preventDefault = function() {\n data.srcEvent.preventDefault();\n };\n\n var i = 0;\n while (i < handlers.length) {\n handlers[i](data);\n i++;\n }\n },\n\n /**\n * destroy the manager and unbinds all events\n * it doesn't unbind dom events, that is the user own responsibility\n */\n destroy: function() {\n this.element && toggleCssProps(this, false);\n\n this.handlers = {};\n this.session = {};\n this.input.destroy();\n this.element = null;\n }\n};\n\n/**\n * add/remove the css properties as defined in manager.options.cssProps\n * @param {Manager} manager\n * @param {Boolean} add\n */\nfunction toggleCssProps(manager, add) {\n var element = manager.element;\n each(manager.options.cssProps, function(value, name) {\n element.style[prefixed(element.style, name)] = add ? value : '';\n });\n}\n\n/**\n * trigger dom event\n * @param {String} event\n * @param {Object} data\n */\nfunction triggerDomEvent(event, data) {\n var gestureEvent = document.createEvent('Event');\n gestureEvent.initEvent(event, true, true);\n gestureEvent.gesture = data;\n data.target.dispatchEvent(gestureEvent);\n}\n\nextend(Hammer, {\n INPUT_START: INPUT_START,\n INPUT_MOVE: INPUT_MOVE,\n INPUT_END: INPUT_END,\n INPUT_CANCEL: INPUT_CANCEL,\n\n STATE_POSSIBLE: STATE_POSSIBLE,\n STATE_BEGAN: STATE_BEGAN,\n STATE_CHANGED: STATE_CHANGED,\n STATE_ENDED: STATE_ENDED,\n STATE_RECOGNIZED: STATE_RECOGNIZED,\n STATE_CANCELLED: STATE_CANCELLED,\n STATE_FAILED: STATE_FAILED,\n\n DIRECTION_NONE: DIRECTION_NONE,\n DIRECTION_LEFT: DIRECTION_LEFT,\n DIRECTION_RIGHT: DIRECTION_RIGHT,\n DIRECTION_UP: DIRECTION_UP,\n DIRECTION_DOWN: DIRECTION_DOWN,\n DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,\n DIRECTION_VERTICAL: DIRECTION_VERTICAL,\n DIRECTION_ALL: DIRECTION_ALL,\n\n Manager: Manager,\n Input: Input,\n TouchAction: TouchAction,\n\n TouchInput: TouchInput,\n MouseInput: MouseInput,\n PointerEventInput: PointerEventInput,\n TouchMouseInput: TouchMouseInput,\n SingleTouchInput: SingleTouchInput,\n\n Recognizer: Recognizer,\n AttrRecognizer: AttrRecognizer,\n Tap: TapRecognizer,\n Pan: PanRecognizer,\n Swipe: SwipeRecognizer,\n Pinch: PinchRecognizer,\n Rotate: RotateRecognizer,\n Press: PressRecognizer,\n\n on: addEventListeners,\n off: removeEventListeners,\n each: each,\n merge: merge,\n extend: extend,\n inherit: inherit,\n bindFn: bindFn,\n prefixed: prefixed\n});\n\nif (typeof define == TYPE_FUNCTION && define.amd) {\n define('hammerjs',[],function() {\n return Hammer;\n });\n} else if (typeof module != 'undefined' && module.exports) {\n module.exports = Hammer;\n} else {\n window[exportName] = Hammer;\n}\n\n})(window, document, 'Hammer');\n\n","// Backbone.js 1.1.2\n\n// (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n// Backbone may be freely distributed under the MIT license.\n// For all details and documentation:\n// http://backbonejs.org\n\n(function(root, factory) {\n\n // Set up Backbone appropriately for the environment. Start with AMD.\n if (typeof define === 'function' && define.amd) {\n define('backbone',['underscore', 'jquery', 'exports'], function(_, $, exports) {\n // Export global even in AMD case in case this script is loaded with\n // others that may still expect a global Backbone.\n root.Backbone = factory(root, exports, _, $);\n });\n\n // Next for Node.js or CommonJS. jQuery may not be needed as a module.\n } else if (typeof exports !== 'undefined') {\n var _ = require('underscore');\n factory(root, exports, _);\n\n // Finally, as a browser global.\n } else {\n root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));\n }\n\n}(this, function(root, Backbone, _, $) {\n\n // Initial Setup\n // -------------\n\n // Save the previous value of the `Backbone` variable, so that it can be\n // restored later on, if `noConflict` is used.\n var previousBackbone = root.Backbone;\n\n // Create local references to array methods we'll want to use later.\n var array = [];\n var push = array.push;\n var slice = array.slice;\n var splice = array.splice;\n\n // Current version of the library. Keep in sync with `package.json`.\n Backbone.VERSION = '1.1.2';\n\n // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns\n // the `$` variable.\n Backbone.$ = $;\n\n // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable\n // to its previous owner. Returns a reference to this Backbone object.\n Backbone.noConflict = function() {\n root.Backbone = previousBackbone;\n return this;\n };\n\n // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option\n // will fake `\"PATCH\"`, `\"PUT\"` and `\"DELETE\"` requests via the `_method` parameter and\n // set a `X-Http-Method-Override` header.\n Backbone.emulateHTTP = false;\n\n // Turn on `emulateJSON` to support legacy servers that can't deal with direct\n // `application/json` requests ... will encode the body as\n // `application/x-www-form-urlencoded` instead and will send the model in a\n // form param named `model`.\n Backbone.emulateJSON = false;\n\n // Backbone.Events\n // ---------------\n\n // A module that can be mixed in to *any object* in order to provide it with\n // custom events. You may bind with `on` or remove with `off` callback\n // functions to an event; `trigger`-ing an event fires all callbacks in\n // succession.\n //\n // var object = {};\n // _.extend(object, Backbone.Events);\n // object.on('expand', function(){ alert('expanded'); });\n // object.trigger('expand');\n //\n var Events = Backbone.Events = {\n\n // Bind an event to a `callback` function. Passing `\"all\"` will bind\n // the callback to all events fired.\n on: function(name, callback, context) {\n if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;\n this._events || (this._events = {});\n var events = this._events[name] || (this._events[name] = []);\n events.push({callback: callback, context: context, ctx: context || this});\n return this;\n },\n\n // Bind an event to only be triggered a single time. After the first time\n // the callback is invoked, it will be removed.\n once: function(name, callback, context) {\n if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;\n var self = this;\n var once = _.once(function() {\n self.off(name, once);\n callback.apply(this, arguments);\n });\n once._callback = callback;\n return this.on(name, once, context);\n },\n\n // Remove one or many callbacks. If `context` is null, removes all\n // callbacks with that function. If `callback` is null, removes all\n // callbacks for the event. If `name` is null, removes all bound\n // callbacks for all events.\n off: function(name, callback, context) {\n var retain, ev, events, names, i, l, j, k;\n if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;\n if (!name && !callback && !context) {\n this._events = void 0;\n return this;\n }\n names = name ? [name] : _.keys(this._events);\n for (i = 0, l = names.length; i < l; i++) {\n name = names[i];\n if (events = this._events[name]) {\n this._events[name] = retain = [];\n if (callback || context) {\n for (j = 0, k = events.length; j < k; j++) {\n ev = events[j];\n if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||\n (context && context !== ev.context)) {\n retain.push(ev);\n }\n }\n }\n if (!retain.length) delete this._events[name];\n }\n }\n\n return this;\n },\n\n // Trigger one or many events, firing all bound callbacks. Callbacks are\n // passed the same arguments as `trigger` is, apart from the event name\n // (unless you're listening on `\"all\"`, which will cause your callback to\n // receive the true name of the event as the first argument).\n trigger: function(name) {\n if (!this._events) return this;\n var args = slice.call(arguments, 1);\n if (!eventsApi(this, 'trigger', name, args)) return this;\n var events = this._events[name];\n var allEvents = this._events.all;\n if (events) triggerEvents(events, args);\n if (allEvents) triggerEvents(allEvents, arguments);\n return this;\n },\n\n // Tell this object to stop listening to either specific events ... or\n // to every object it's currently listening to.\n stopListening: function(obj, name, callback) {\n var listeningTo = this._listeningTo;\n if (!listeningTo) return this;\n var remove = !name && !callback;\n if (!callback && typeof name === 'object') callback = this;\n if (obj) (listeningTo = {})[obj._listenId] = obj;\n for (var id in listeningTo) {\n obj = listeningTo[id];\n obj.off(name, callback, this);\n if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];\n }\n return this;\n }\n\n };\n\n // Regular expression used to split event strings.\n var eventSplitter = /\\s+/;\n\n // Implement fancy features of the Events API such as multiple event\n // names `\"change blur\"` and jQuery-style event maps `{change: action}`\n // in terms of the existing API.\n var eventsApi = function(obj, action, name, rest) {\n if (!name) return true;\n\n // Handle event maps.\n if (typeof name === 'object') {\n for (var key in name) {\n obj[action].apply(obj, [key, name[key]].concat(rest));\n }\n return false;\n }\n\n // Handle space separated event names.\n if (eventSplitter.test(name)) {\n var names = name.split(eventSplitter);\n for (var i = 0, l = names.length; i < l; i++) {\n obj[action].apply(obj, [names[i]].concat(rest));\n }\n return false;\n }\n\n return true;\n };\n\n // A difficult-to-believe, but optimized internal dispatch function for\n // triggering events. Tries to keep the usual cases speedy (most internal\n // Backbone events have 3 arguments).\n var triggerEvents = function(events, args) {\n var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];\n switch (args.length) {\n case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;\n case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;\n case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;\n case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;\n default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;\n }\n };\n\n var listenMethods = {listenTo: 'on', listenToOnce: 'once'};\n\n // Inversion-of-control versions of `on` and `once`. Tell *this* object to\n // listen to an event in another object ... keeping track of what it's\n // listening to.\n _.each(listenMethods, function(implementation, method) {\n Events[method] = function(obj, name, callback) {\n var listeningTo = this._listeningTo || (this._listeningTo = {});\n var id = obj._listenId || (obj._listenId = _.uniqueId('l'));\n listeningTo[id] = obj;\n if (!callback && typeof name === 'object') callback = this;\n obj[implementation](name, callback, this);\n return this;\n };\n });\n\n // Aliases for backwards compatibility.\n Events.bind = Events.on;\n Events.unbind = Events.off;\n\n // Allow the `Backbone` object to serve as a global event bus, for folks who\n // want global \"pubsub\" in a convenient place.\n _.extend(Backbone, Events);\n\n // Backbone.Model\n // --------------\n\n // Backbone **Models** are the basic data object in the framework --\n // frequently representing a row in a table in a database on your server.\n // A discrete chunk of data and a bunch of useful, related methods for\n // performing computations and transformations on that data.\n\n // Create a new model with the specified attributes. A client id (`cid`)\n // is automatically generated and assigned for you.\n var Model = Backbone.Model = function(attributes, options) {\n var attrs = attributes || {};\n options || (options = {});\n this.cid = _.uniqueId('c');\n this.attributes = {};\n if (options.collection) this.collection = options.collection;\n if (options.parse) attrs = this.parse(attrs, options) || {};\n attrs = _.defaults({}, attrs, _.result(this, 'defaults'));\n this.set(attrs, options);\n this.changed = {};\n this.initialize.apply(this, arguments);\n };\n\n // Attach all inheritable methods to the Model prototype.\n _.extend(Model.prototype, Events, {\n\n // A hash of attributes whose current and previous value differ.\n changed: null,\n\n // The value returned during the last failed validation.\n validationError: null,\n\n // The default name for the JSON `id` attribute is `\"id\"`. MongoDB and\n // CouchDB users may want to set this to `\"_id\"`.\n idAttribute: 'id',\n\n // Initialize is an empty function by default. Override it with your own\n // initialization logic.\n initialize: function(){},\n\n // Return a copy of the model's `attributes` object.\n toJSON: function(options) {\n return _.clone(this.attributes);\n },\n\n // Proxy `Backbone.sync` by default -- but override this if you need\n // custom syncing semantics for *this* particular model.\n sync: function() {\n return Backbone.sync.apply(this, arguments);\n },\n\n // Get the value of an attribute.\n get: function(attr) {\n return this.attributes[attr];\n },\n\n // Get the HTML-escaped value of an attribute.\n escape: function(attr) {\n return _.escape(this.get(attr));\n },\n\n // Returns `true` if the attribute contains a value that is not null\n // or undefined.\n has: function(attr) {\n return this.get(attr) != null;\n },\n\n // Set a hash of model attributes on the object, firing `\"change\"`. This is\n // the core primitive operation of a model, updating the data and notifying\n // anyone who needs to know about the change in state. The heart of the beast.\n set: function(key, val, options) {\n var attr, attrs, unset, changes, silent, changing, prev, current;\n if (key == null) return this;\n\n // Handle both `\"key\", value` and `{key: value}` -style arguments.\n if (typeof key === 'object') {\n attrs = key;\n options = val;\n } else {\n (attrs = {})[key] = val;\n }\n\n options || (options = {});\n\n // Run validation.\n if (!this._validate(attrs, options)) return false;\n\n // Extract attributes and options.\n unset = options.unset;\n silent = options.silent;\n changes = [];\n changing = this._changing;\n this._changing = true;\n\n if (!changing) {\n this._previousAttributes = _.clone(this.attributes);\n this.changed = {};\n }\n current = this.attributes, prev = this._previousAttributes;\n\n // Check for changes of `id`.\n if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];\n\n // For each `set` attribute, update or delete the current value.\n for (attr in attrs) {\n val = attrs[attr];\n if (!_.isEqual(current[attr], val)) changes.push(attr);\n if (!_.isEqual(prev[attr], val)) {\n this.changed[attr] = val;\n } else {\n delete this.changed[attr];\n }\n unset ? delete current[attr] : current[attr] = val;\n }\n\n // Trigger all relevant attribute changes.\n if (!silent) {\n if (changes.length) this._pending = options;\n for (var i = 0, l = changes.length; i < l; i++) {\n this.trigger('change:' + changes[i], this, current[changes[i]], options);\n }\n }\n\n // You might be wondering why there's a `while` loop here. Changes can\n // be recursively nested within `\"change\"` events.\n if (changing) return this;\n if (!silent) {\n while (this._pending) {\n options = this._pending;\n this._pending = false;\n this.trigger('change', this, options);\n }\n }\n this._pending = false;\n this._changing = false;\n return this;\n },\n\n // Remove an attribute from the model, firing `\"change\"`. `unset` is a noop\n // if the attribute doesn't exist.\n unset: function(attr, options) {\n return this.set(attr, void 0, _.extend({}, options, {unset: true}));\n },\n\n // Clear all attributes on the model, firing `\"change\"`.\n clear: function(options) {\n var attrs = {};\n for (var key in this.attributes) attrs[key] = void 0;\n return this.set(attrs, _.extend({}, options, {unset: true}));\n },\n\n // Determine if the model has changed since the last `\"change\"` event.\n // If you specify an attribute name, determine if that attribute has changed.\n hasChanged: function(attr) {\n if (attr == null) return !_.isEmpty(this.changed);\n return _.has(this.changed, attr);\n },\n\n // Return an object containing all the attributes that have changed, or\n // false if there are no changed attributes. Useful for determining what\n // parts of a view need to be updated and/or what attributes need to be\n // persisted to the server. Unset attributes will be set to undefined.\n // You can also pass an attributes object to diff against the model,\n // determining if there *would be* a change.\n changedAttributes: function(diff) {\n if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;\n var val, changed = false;\n var old = this._changing ? this._previousAttributes : this.attributes;\n for (var attr in diff) {\n if (_.isEqual(old[attr], (val = diff[attr]))) continue;\n (changed || (changed = {}))[attr] = val;\n }\n return changed;\n },\n\n // Get the previous value of an attribute, recorded at the time the last\n // `\"change\"` event was fired.\n previous: function(attr) {\n if (attr == null || !this._previousAttributes) return null;\n return this._previousAttributes[attr];\n },\n\n // Get all of the attributes of the model at the time of the previous\n // `\"change\"` event.\n previousAttributes: function() {\n return _.clone(this._previousAttributes);\n },\n\n // Fetch the model from the server. If the server's representation of the\n // model differs from its current attributes, they will be overridden,\n // triggering a `\"change\"` event.\n fetch: function(options) {\n options = options ? _.clone(options) : {};\n if (options.parse === void 0) options.parse = true;\n var model = this;\n var success = options.success;\n options.success = function(resp) {\n if (!model.set(model.parse(resp, options), options)) return false;\n if (success) success(model, resp, options);\n model.trigger('sync', model, resp, options);\n };\n wrapError(this, options);\n return this.sync('read', this, options);\n },\n\n // Set a hash of model attributes, and sync the model to the server.\n // If the server returns an attributes hash that differs, the model's\n // state will be `set` again.\n save: function(key, val, options) {\n var attrs, method, xhr, attributes = this.attributes;\n\n // Handle both `\"key\", value` and `{key: value}` -style arguments.\n if (key == null || typeof key === 'object') {\n attrs = key;\n options = val;\n } else {\n (attrs = {})[key] = val;\n }\n\n options = _.extend({validate: true}, options);\n\n // If we're not waiting and attributes exist, save acts as\n // `set(attr).save(null, opts)` with validation. Otherwise, check if\n // the model will be valid when the attributes, if any, are set.\n if (attrs && !options.wait) {\n if (!this.set(attrs, options)) return false;\n } else {\n if (!this._validate(attrs, options)) return false;\n }\n\n // Set temporary attributes if `{wait: true}`.\n if (attrs && options.wait) {\n this.attributes = _.extend({}, attributes, attrs);\n }\n\n // After a successful server-side save, the client is (optionally)\n // updated with the server-side state.\n if (options.parse === void 0) options.parse = true;\n var model = this;\n var success = options.success;\n options.success = function(resp) {\n // Ensure attributes are restored during synchronous saves.\n model.attributes = attributes;\n var serverAttrs = model.parse(resp, options);\n if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);\n if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {\n return false;\n }\n if (success) success(model, resp, options);\n model.trigger('sync', model, resp, options);\n };\n wrapError(this, options);\n\n method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');\n if (method === 'patch') options.attrs = attrs;\n xhr = this.sync(method, this, options);\n\n // Restore attributes.\n if (attrs && options.wait) this.attributes = attributes;\n\n return xhr;\n },\n\n // Destroy this model on the server if it was already persisted.\n // Optimistically removes the model from its collection, if it has one.\n // If `wait: true` is passed, waits for the server to respond before removal.\n destroy: function(options) {\n options = options ? _.clone(options) : {};\n var model = this;\n var success = options.success;\n\n var destroy = function() {\n model.trigger('destroy', model, model.collection, options);\n };\n\n options.success = function(resp) {\n if (options.wait || model.isNew()) destroy();\n if (success) success(model, resp, options);\n if (!model.isNew()) model.trigger('sync', model, resp, options);\n };\n\n if (this.isNew()) {\n options.success();\n return false;\n }\n wrapError(this, options);\n\n var xhr = this.sync('delete', this, options);\n if (!options.wait) destroy();\n return xhr;\n },\n\n // Default URL for the model's representation on the server -- if you're\n // using Backbone's restful methods, override this to change the endpoint\n // that will be called.\n url: function() {\n var base =\n _.result(this, 'urlRoot') ||\n _.result(this.collection, 'url') ||\n urlError();\n if (this.isNew()) return base;\n return base.replace(/([^\\/])$/, '$1/') + encodeURIComponent(this.id);\n },\n\n // **parse** converts a response into the hash of attributes to be `set` on\n // the model. The default implementation is just to pass the response along.\n parse: function(resp, options) {\n return resp;\n },\n\n // Create a new model with identical attributes to this one.\n clone: function() {\n return new this.constructor(this.attributes);\n },\n\n // A model is new if it has never been saved to the server, and lacks an id.\n isNew: function() {\n return !this.has(this.idAttribute);\n },\n\n // Check if the model is currently in a valid state.\n isValid: function(options) {\n return this._validate({}, _.extend(options || {}, { validate: true }));\n },\n\n // Run validation against the next complete set of model attributes,\n // returning `true` if all is well. Otherwise, fire an `\"invalid\"` event.\n _validate: function(attrs, options) {\n if (!options.validate || !this.validate) return true;\n attrs = _.extend({}, this.attributes, attrs);\n var error = this.validationError = this.validate(attrs, options) || null;\n if (!error) return true;\n this.trigger('invalid', this, error, _.extend(options, {validationError: error}));\n return false;\n }\n\n });\n\n // Underscore methods that we want to implement on the Model.\n var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];\n\n // Mix in each Underscore method as a proxy to `Model#attributes`.\n _.each(modelMethods, function(method) {\n Model.prototype[method] = function() {\n var args = slice.call(arguments);\n args.unshift(this.attributes);\n return _[method].apply(_, args);\n };\n });\n\n // Backbone.Collection\n // -------------------\n\n // If models tend to represent a single row of data, a Backbone Collection is\n // more analagous to a table full of data ... or a small slice or page of that\n // table, or a collection of rows that belong together for a particular reason\n // -- all of the messages in this particular folder, all of the documents\n // belonging to this particular author, and so on. Collections maintain\n // indexes of their models, both in order, and for lookup by `id`.\n\n // Create a new **Collection**, perhaps to contain a specific type of `model`.\n // If a `comparator` is specified, the Collection will maintain\n // its models in sort order, as they're added and removed.\n var Collection = Backbone.Collection = function(models, options) {\n options || (options = {});\n if (options.model) this.model = options.model;\n if (options.comparator !== void 0) this.comparator = options.comparator;\n this._reset();\n this.initialize.apply(this, arguments);\n if (models) this.reset(models, _.extend({silent: true}, options));\n };\n\n // Default options for `Collection#set`.\n var setOptions = {add: true, remove: true, merge: true};\n var addOptions = {add: true, remove: false};\n\n // Define the Collection's inheritable methods.\n _.extend(Collection.prototype, Events, {\n\n // The default model for a collection is just a **Backbone.Model**.\n // This should be overridden in most cases.\n model: Model,\n\n // Initialize is an empty function by default. Override it with your own\n // initialization logic.\n initialize: function(){},\n\n // The JSON representation of a Collection is an array of the\n // models' attributes.\n toJSON: function(options) {\n return this.map(function(model){ return model.toJSON(options); });\n },\n\n // Proxy `Backbone.sync` by default.\n sync: function() {\n return Backbone.sync.apply(this, arguments);\n },\n\n // Add a model, or list of models to the set.\n add: function(models, options) {\n return this.set(models, _.extend({merge: false}, options, addOptions));\n },\n\n // Remove a model, or a list of models from the set.\n remove: function(models, options) {\n var singular = !_.isArray(models);\n models = singular ? [models] : _.clone(models);\n options || (options = {});\n var i, l, index, model;\n for (i = 0, l = models.length; i < l; i++) {\n model = models[i] = this.get(models[i]);\n if (!model) continue;\n delete this._byId[model.id];\n delete this._byId[model.cid];\n index = this.indexOf(model);\n this.models.splice(index, 1);\n this.length--;\n if (!options.silent) {\n options.index = index;\n model.trigger('remove', model, this, options);\n }\n this._removeReference(model, options);\n }\n return singular ? models[0] : models;\n },\n\n // Update a collection by `set`-ing a new list of models, adding new ones,\n // removing models that are no longer present, and merging models that\n // already exist in the collection, as necessary. Similar to **Model#set**,\n // the core operation for updating the data contained by the collection.\n set: function(models, options) {\n options = _.defaults({}, options, setOptions);\n if (options.parse) models = this.parse(models, options);\n var singular = !_.isArray(models);\n models = singular ? (models ? [models] : []) : _.clone(models);\n var i, l, id, model, attrs, existing, sort;\n var at = options.at;\n var targetModel = this.model;\n var sortable = this.comparator && (at == null) && options.sort !== false;\n var sortAttr = _.isString(this.comparator) ? this.comparator : null;\n var toAdd = [], toRemove = [], modelMap = {};\n var add = options.add, merge = options.merge, remove = options.remove;\n var order = !sortable && add && remove ? [] : false;\n\n // Turn bare objects into model references, and prevent invalid models\n // from being added.\n for (i = 0, l = models.length; i < l; i++) {\n attrs = models[i] || {};\n if (attrs instanceof Model) {\n id = model = attrs;\n } else {\n id = attrs[targetModel.prototype.idAttribute || 'id'];\n }\n\n // If a duplicate is found, prevent it from being added and\n // optionally merge it into the existing model.\n if (existing = this.get(id)) {\n if (remove) modelMap[existing.cid] = true;\n if (merge) {\n attrs = attrs === model ? model.attributes : attrs;\n if (options.parse) attrs = existing.parse(attrs, options);\n existing.set(attrs, options);\n if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;\n }\n models[i] = existing;\n\n // If this is a new, valid model, push it to the `toAdd` list.\n } else if (add) {\n model = models[i] = this._prepareModel(attrs, options);\n if (!model) continue;\n toAdd.push(model);\n this._addReference(model, options);\n }\n\n // Do not add multiple models with the same `id`.\n model = existing || model;\n if (order && (model.isNew() || !modelMap[model.id])) order.push(model);\n modelMap[model.id] = true;\n }\n\n // Remove nonexistent models if appropriate.\n if (remove) {\n for (i = 0, l = this.length; i < l; ++i) {\n if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);\n }\n if (toRemove.length) this.remove(toRemove, options);\n }\n\n // See if sorting is needed, update `length` and splice in new models.\n if (toAdd.length || (order && order.length)) {\n if (sortable) sort = true;\n this.length += toAdd.length;\n if (at != null) {\n for (i = 0, l = toAdd.length; i < l; i++) {\n this.models.splice(at + i, 0, toAdd[i]);\n }\n } else {\n if (order) this.models.length = 0;\n var orderedModels = order || toAdd;\n for (i = 0, l = orderedModels.length; i < l; i++) {\n this.models.push(orderedModels[i]);\n }\n }\n }\n\n // Silently sort the collection if appropriate.\n if (sort) this.sort({silent: true});\n\n // Unless silenced, it's time to fire all appropriate add/sort events.\n if (!options.silent) {\n for (i = 0, l = toAdd.length; i < l; i++) {\n (model = toAdd[i]).trigger('add', model, this, options);\n }\n if (sort || (order && order.length)) this.trigger('sort', this, options);\n }\n\n // Return the added (or merged) model (or models).\n return singular ? models[0] : models;\n },\n\n // When you have more items than you want to add or remove individually,\n // you can reset the entire set with a new list of models, without firing\n // any granular `add` or `remove` events. Fires `reset` when finished.\n // Useful for bulk operations and optimizations.\n reset: function(models, options) {\n options || (options = {});\n for (var i = 0, l = this.models.length; i < l; i++) {\n this._removeReference(this.models[i], options);\n }\n options.previousModels = this.models;\n this._reset();\n models = this.add(models, _.extend({silent: true}, options));\n if (!options.silent) this.trigger('reset', this, options);\n return models;\n },\n\n // Add a model to the end of the collection.\n push: function(model, options) {\n return this.add(model, _.extend({at: this.length}, options));\n },\n\n // Remove a model from the end of the collection.\n pop: function(options) {\n var model = this.at(this.length - 1);\n this.remove(model, options);\n return model;\n },\n\n // Add a model to the beginning of the collection.\n unshift: function(model, options) {\n return this.add(model, _.extend({at: 0}, options));\n },\n\n // Remove a model from the beginning of the collection.\n shift: function(options) {\n var model = this.at(0);\n this.remove(model, options);\n return model;\n },\n\n // Slice out a sub-array of models from the collection.\n slice: function() {\n return slice.apply(this.models, arguments);\n },\n\n // Get a model from the set by id.\n get: function(obj) {\n if (obj == null) return void 0;\n return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid];\n },\n\n // Get the model at the given index.\n at: function(index) {\n return this.models[index];\n },\n\n // Return models with matching attributes. Useful for simple cases of\n // `filter`.\n where: function(attrs, first) {\n if (_.isEmpty(attrs)) return first ? void 0 : [];\n return this[first ? 'find' : 'filter'](function(model) {\n for (var key in attrs) {\n if (attrs[key] !== model.get(key)) return false;\n }\n return true;\n });\n },\n\n // Return the first model with matching attributes. Useful for simple cases\n // of `find`.\n findWhere: function(attrs) {\n return this.where(attrs, true);\n },\n\n // Force the collection to re-sort itself. You don't need to call this under\n // normal circumstances, as the set will maintain sort order as each item\n // is added.\n sort: function(options) {\n if (!this.comparator) throw new Error('Cannot sort a set without a comparator');\n options || (options = {});\n\n // Run sort based on type of `comparator`.\n if (_.isString(this.comparator) || this.comparator.length === 1) {\n this.models = this.sortBy(this.comparator, this);\n } else {\n this.models.sort(_.bind(this.comparator, this));\n }\n\n if (!options.silent) this.trigger('sort', this, options);\n return this;\n },\n\n // Pluck an attribute from each model in the collection.\n pluck: function(attr) {\n return _.invoke(this.models, 'get', attr);\n },\n\n // Fetch the default set of models for this collection, resetting the\n // collection when they arrive. If `reset: true` is passed, the response\n // data will be passed through the `reset` method instead of `set`.\n fetch: function(options) {\n options = options ? _.clone(options) : {};\n if (options.parse === void 0) options.parse = true;\n var success = options.success;\n var collection = this;\n options.success = function(resp) {\n var method = options.reset ? 'reset' : 'set';\n collection[method](resp, options);\n if (success) success(collection, resp, options);\n collection.trigger('sync', collection, resp, options);\n };\n wrapError(this, options);\n return this.sync('read', this, options);\n },\n\n // Create a new instance of a model in this collection. Add the model to the\n // collection immediately, unless `wait: true` is passed, in which case we\n // wait for the server to agree.\n create: function(model, options) {\n options = options ? _.clone(options) : {};\n if (!(model = this._prepareModel(model, options))) return false;\n if (!options.wait) this.add(model, options);\n var collection = this;\n var success = options.success;\n options.success = function(model, resp) {\n if (options.wait) collection.add(model, options);\n if (success) success(model, resp, options);\n };\n model.save(null, options);\n return model;\n },\n\n // **parse** converts a response into a list of models to be added to the\n // collection. The default implementation is just to pass it through.\n parse: function(resp, options) {\n return resp;\n },\n\n // Create a new collection with an identical list of models as this one.\n clone: function() {\n return new this.constructor(this.models);\n },\n\n // Private method to reset all internal state. Called when the collection\n // is first initialized or reset.\n _reset: function() {\n this.length = 0;\n this.models = [];\n this._byId = {};\n },\n\n // Prepare a hash of attributes (or other model) to be added to this\n // collection.\n _prepareModel: function(attrs, options) {\n if (attrs instanceof Model) return attrs;\n options = options ? _.clone(options) : {};\n options.collection = this;\n var model = new this.model(attrs, options);\n if (!model.validationError) return model;\n this.trigger('invalid', this, model.validationError, options);\n return false;\n },\n\n // Internal method to create a model's ties to a collection.\n _addReference: function(model, options) {\n this._byId[model.cid] = model;\n if (model.id != null) this._byId[model.id] = model;\n if (!model.collection) model.collection = this;\n model.on('all', this._onModelEvent, this);\n },\n\n // Internal method to sever a model's ties to a collection.\n _removeReference: function(model, options) {\n if (this === model.collection) delete model.collection;\n model.off('all', this._onModelEvent, this);\n },\n\n // Internal method called every time a model in the set fires an event.\n // Sets need to update their indexes when models change ids. All other\n // events simply proxy through. \"add\" and \"remove\" events that originate\n // in other collections are ignored.\n _onModelEvent: function(event, model, collection, options) {\n if ((event === 'add' || event === 'remove') && collection !== this) return;\n if (event === 'destroy') this.remove(model, options);\n if (model && event === 'change:' + model.idAttribute) {\n delete this._byId[model.previous(model.idAttribute)];\n if (model.id != null) this._byId[model.id] = model;\n }\n this.trigger.apply(this, arguments);\n }\n\n });\n\n // Underscore methods that we want to implement on the Collection.\n // 90% of the core usefulness of Backbone Collections is actually implemented\n // right here:\n var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',\n 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',\n 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',\n 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',\n 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',\n 'lastIndexOf', 'isEmpty', 'chain', 'sample'];\n\n // Mix in each Underscore method as a proxy to `Collection#models`.\n _.each(methods, function(method) {\n Collection.prototype[method] = function() {\n var args = slice.call(arguments);\n args.unshift(this.models);\n return _[method].apply(_, args);\n };\n });\n\n // Underscore methods that take a property name as an argument.\n var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];\n\n // Use attributes instead of properties.\n _.each(attributeMethods, function(method) {\n Collection.prototype[method] = function(value, context) {\n var iterator = _.isFunction(value) ? value : function(model) {\n return model.get(value);\n };\n return _[method](this.models, iterator, context);\n };\n });\n\n // Backbone.View\n // -------------\n\n // Backbone Views are almost more convention than they are actual code. A View\n // is simply a JavaScript object that represents a logical chunk of UI in the\n // DOM. This might be a single item, an entire list, a sidebar or panel, or\n // even the surrounding frame which wraps your whole app. Defining a chunk of\n // UI as a **View** allows you to define your DOM events declaratively, without\n // having to worry about render order ... and makes it easy for the view to\n // react to specific changes in the state of your models.\n\n // Creating a Backbone.View creates its initial element outside of the DOM,\n // if an existing element is not provided...\n var View = Backbone.View = function(options) {\n this.cid = _.uniqueId('view');\n options || (options = {});\n _.extend(this, _.pick(options, viewOptions));\n this._ensureElement();\n this.initialize.apply(this, arguments);\n this.delegateEvents();\n };\n\n // Cached regex to split keys for `delegate`.\n var delegateEventSplitter = /^(\\S+)\\s*(.*)$/;\n\n // List of view options to be merged as properties.\n var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];\n\n // Set up all inheritable **Backbone.View** properties and methods.\n _.extend(View.prototype, Events, {\n\n // The default `tagName` of a View's element is `\"div\"`.\n tagName: 'div',\n\n // jQuery delegate for element lookup, scoped to DOM elements within the\n // current view. This should be preferred to global lookups where possible.\n $: function(selector) {\n return this.$el.find(selector);\n },\n\n // Initialize is an empty function by default. Override it with your own\n // initialization logic.\n initialize: function(){},\n\n // **render** is the core function that your view should override, in order\n // to populate its element (`this.el`), with the appropriate HTML. The\n // convention is for **render** to always return `this`.\n render: function() {\n return this;\n },\n\n // Remove this view by taking the element out of the DOM, and removing any\n // applicable Backbone.Events listeners.\n remove: function() {\n this.$el.remove();\n this.stopListening();\n return this;\n },\n\n // Change the view's element (`this.el` property), including event\n // re-delegation.\n setElement: function(element, delegate) {\n if (this.$el) this.undelegateEvents();\n this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);\n this.el = this.$el[0];\n if (delegate !== false) this.delegateEvents();\n return this;\n },\n\n // Set callbacks, where `this.events` is a hash of\n //\n // *{\"event selector\": \"callback\"}*\n //\n // {\n // 'mousedown .title': 'edit',\n // 'click .button': 'save',\n // 'click .open': function(e) { ... }\n // }\n //\n // pairs. Callbacks will be bound to the view, with `this` set properly.\n // Uses event delegation for efficiency.\n // Omitting the selector binds the event to `this.el`.\n // This only works for delegate-able events: not `focus`, `blur`, and\n // not `change`, `submit`, and `reset` in Internet Explorer.\n delegateEvents: function(events) {\n if (!(events || (events = _.result(this, 'events')))) return this;\n this.undelegateEvents();\n for (var key in events) {\n var method = events[key];\n if (!_.isFunction(method)) method = this[events[key]];\n if (!method) continue;\n\n var match = key.match(delegateEventSplitter);\n var eventName = match[1], selector = match[2];\n method = _.bind(method, this);\n eventName += '.delegateEvents' + this.cid;\n if (selector === '') {\n this.$el.on(eventName, method);\n } else {\n this.$el.on(eventName, selector, method);\n }\n }\n return this;\n },\n\n // Clears all callbacks previously bound to the view with `delegateEvents`.\n // You usually don't need to use this, but may wish to if you have multiple\n // Backbone views attached to the same DOM element.\n undelegateEvents: function() {\n this.$el.off('.delegateEvents' + this.cid);\n return this;\n },\n\n // Ensure that the View has a DOM element to render into.\n // If `this.el` is a string, pass it through `$()`, take the first\n // matching element, and re-assign it to `el`. Otherwise, create\n // an element from the `id`, `className` and `tagName` properties.\n _ensureElement: function() {\n if (!this.el) {\n var attrs = _.extend({}, _.result(this, 'attributes'));\n if (this.id) attrs.id = _.result(this, 'id');\n if (this.className) attrs['class'] = _.result(this, 'className');\n var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);\n this.setElement($el, false);\n } else {\n this.setElement(_.result(this, 'el'), false);\n }\n }\n\n });\n\n // Backbone.sync\n // -------------\n\n // Override this function to change the manner in which Backbone persists\n // models to the server. You will be passed the type of request, and the\n // model in question. By default, makes a RESTful Ajax request\n // to the model's `url()`. Some possible customizations could be:\n //\n // * Use `setTimeout` to batch rapid-fire updates into a single request.\n // * Send up the models as XML instead of JSON.\n // * Persist models via WebSockets instead of Ajax.\n //\n // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests\n // as `POST`, with a `_method` parameter containing the true HTTP method,\n // as well as all requests with the body as `application/x-www-form-urlencoded`\n // instead of `application/json` with the model in a param named `model`.\n // Useful when interfacing with server-side languages like **PHP** that make\n // it difficult to read the body of `PUT` requests.\n Backbone.sync = function(method, model, options) {\n var type = methodMap[method];\n\n // Default options, unless specified.\n _.defaults(options || (options = {}), {\n emulateHTTP: Backbone.emulateHTTP,\n emulateJSON: Backbone.emulateJSON\n });\n\n // Default JSON-request options.\n var params = {type: type, dataType: 'json'};\n\n // Ensure that we have a URL.\n if (!options.url) {\n params.url = _.result(model, 'url') || urlError();\n }\n\n // Ensure that we have the appropriate request data.\n if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {\n params.contentType = 'application/json';\n params.data = JSON.stringify(options.attrs || model.toJSON(options));\n }\n\n // For older servers, emulate JSON by encoding the request into an HTML-form.\n if (options.emulateJSON) {\n params.contentType = 'application/x-www-form-urlencoded';\n params.data = params.data ? {model: params.data} : {};\n }\n\n // For older servers, emulate HTTP by mimicking the HTTP method with `_method`\n // And an `X-HTTP-Method-Override` header.\n if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {\n params.type = 'POST';\n if (options.emulateJSON) params.data._method = type;\n var beforeSend = options.beforeSend;\n options.beforeSend = function(xhr) {\n xhr.setRequestHeader('X-HTTP-Method-Override', type);\n if (beforeSend) return beforeSend.apply(this, arguments);\n };\n }\n\n // Don't process data on a non-GET request.\n if (params.type !== 'GET' && !options.emulateJSON) {\n params.processData = false;\n }\n\n // If we're sending a `PATCH` request, and we're in an old Internet Explorer\n // that still has ActiveX enabled by default, override jQuery to use that\n // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.\n if (params.type === 'PATCH' && noXhrPatch) {\n params.xhr = function() {\n return new ActiveXObject(\"Microsoft.XMLHTTP\");\n };\n }\n\n // Make the request, allowing the user to override any Ajax options.\n var xhr = options.xhr = Backbone.ajax(_.extend(params, options));\n model.trigger('request', model, xhr, options);\n return xhr;\n };\n\n var noXhrPatch =\n typeof window !== 'undefined' && !!window.ActiveXObject &&\n !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);\n\n // Map from CRUD to HTTP for our default `Backbone.sync` implementation.\n var methodMap = {\n 'create': 'POST',\n 'update': 'PUT',\n 'patch': 'PATCH',\n 'delete': 'DELETE',\n 'read': 'GET'\n };\n\n // Set the default implementation of `Backbone.ajax` to proxy through to `$`.\n // Override this if you'd like to use a different library.\n Backbone.ajax = function() {\n return Backbone.$.ajax.apply(Backbone.$, arguments);\n };\n\n // Backbone.Router\n // ---------------\n\n // Routers map faux-URLs to actions, and fire events when routes are\n // matched. Creating a new one sets its `routes` hash, if not set statically.\n var Router = Backbone.Router = function(options) {\n options || (options = {});\n if (options.routes) this.routes = options.routes;\n this._bindRoutes();\n this.initialize.apply(this, arguments);\n };\n\n // Cached regular expressions for matching named param parts and splatted\n // parts of route strings.\n var optionalParam = /\\((.*?)\\)/g;\n var namedParam = /(\\(\\?)?:\\w+/g;\n var splatParam = /\\*\\w+/g;\n var escapeRegExp = /[\\-{}\\[\\]+?.,\\\\\\^$|#\\s]/g;\n\n // Set up all inheritable **Backbone.Router** properties and methods.\n _.extend(Router.prototype, Events, {\n\n // Initialize is an empty function by default. Override it with your own\n // initialization logic.\n initialize: function(){},\n\n // Manually bind a single named route to a callback. For example:\n //\n // this.route('search/:query/p:num', 'search', function(query, num) {\n // ...\n // });\n //\n route: function(route, name, callback) {\n if (!_.isRegExp(route)) route = this._routeToRegExp(route);\n if (_.isFunction(name)) {\n callback = name;\n name = '';\n }\n if (!callback) callback = this[name];\n var router = this;\n Backbone.history.route(route, function(fragment) {\n var args = router._extractParameters(route, fragment);\n router.execute(callback, args);\n router.trigger.apply(router, ['route:' + name].concat(args));\n router.trigger('route', name, args);\n Backbone.history.trigger('route', router, name, args);\n });\n return this;\n },\n\n // Execute a route handler with the provided parameters. This is an\n // excellent place to do pre-route setup or post-route cleanup.\n execute: function(callback, args) {\n if (callback) callback.apply(this, args);\n },\n\n // Simple proxy to `Backbone.history` to save a fragment into the history.\n navigate: function(fragment, options) {\n Backbone.history.navigate(fragment, options);\n return this;\n },\n\n // Bind all defined routes to `Backbone.history`. We have to reverse the\n // order of the routes here to support behavior where the most general\n // routes can be defined at the bottom of the route map.\n _bindRoutes: function() {\n if (!this.routes) return;\n this.routes = _.result(this, 'routes');\n var route, routes = _.keys(this.routes);\n while ((route = routes.pop()) != null) {\n this.route(route, this.routes[route]);\n }\n },\n\n // Convert a route string into a regular expression, suitable for matching\n // against the current location hash.\n _routeToRegExp: function(route) {\n route = route.replace(escapeRegExp, '\\\\$&')\n .replace(optionalParam, '(?:$1)?')\n .replace(namedParam, function(match, optional) {\n return optional ? match : '([^/?]+)';\n })\n .replace(splatParam, '([^?]*?)');\n return new RegExp('^' + route + '(?:\\\\?([\\\\s\\\\S]*))?$');\n },\n\n // Given a route, and a URL fragment that it matches, return the array of\n // extracted decoded parameters. Empty or unmatched parameters will be\n // treated as `null` to normalize cross-browser behavior.\n _extractParameters: function(route, fragment) {\n var params = route.exec(fragment).slice(1);\n return _.map(params, function(param, i) {\n // Don't decode the search params.\n if (i === params.length - 1) return param || null;\n return param ? decodeURIComponent(param) : null;\n });\n }\n\n });\n\n // Backbone.History\n // ----------------\n\n // Handles cross-browser history management, based on either\n // [pushState](http://diveintohtml5.info/history.html) and real URLs, or\n // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)\n // and URL fragments. If the browser supports neither (old IE, natch),\n // falls back to polling.\n var History = Backbone.History = function() {\n this.handlers = [];\n _.bindAll(this, 'checkUrl');\n\n // Ensure that `History` can be used outside of the browser.\n if (typeof window !== 'undefined') {\n this.location = window.location;\n this.history = window.history;\n }\n };\n\n // Cached regex for stripping a leading hash/slash and trailing space.\n var routeStripper = /^[#\\/]|\\s+$/g;\n\n // Cached regex for stripping leading and trailing slashes.\n var rootStripper = /^\\/+|\\/+$/g;\n\n // Cached regex for detecting MSIE.\n var isExplorer = /msie [\\w.]+/;\n\n // Cached regex for removing a trailing slash.\n var trailingSlash = /\\/$/;\n\n // Cached regex for stripping urls of hash.\n var pathStripper = /#.*$/;\n\n // Has the history handling already been started?\n History.started = false;\n\n // Set up all inheritable **Backbone.History** properties and methods.\n _.extend(History.prototype, Events, {\n\n // The default interval to poll for hash changes, if necessary, is\n // twenty times a second.\n interval: 50,\n\n // Are we at the app root?\n atRoot: function() {\n return this.location.pathname.replace(/[^\\/]$/, '$&/') === this.root;\n },\n\n // Gets the true hash value. Cannot use location.hash directly due to bug\n // in Firefox where location.hash will always be decoded.\n getHash: function(window) {\n var match = (window || this).location.href.match(/#(.*)$/);\n return match ? match[1] : '';\n },\n\n // Get the cross-browser normalized URL fragment, either from the URL,\n // the hash, or the override.\n getFragment: function(fragment, forcePushState) {\n if (fragment == null) {\n if (this._hasPushState || !this._wantsHashChange || forcePushState) {\n fragment = decodeURI(this.location.pathname + this.location.search);\n var root = this.root.replace(trailingSlash, '');\n if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);\n } else {\n fragment = this.getHash();\n }\n }\n return fragment.replace(routeStripper, '');\n },\n\n // Start the hash change handling, returning `true` if the current URL matches\n // an existing route, and `false` otherwise.\n start: function(options) {\n if (History.started) throw new Error(\"Backbone.history has already been started\");\n History.started = true;\n\n // Figure out the initial configuration. Do we need an iframe?\n // Is pushState desired ... is it available?\n this.options = _.extend({root: '/'}, this.options, options);\n this.root = this.options.root;\n this._wantsHashChange = this.options.hashChange !== false;\n this._wantsPushState = !!this.options.pushState;\n this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);\n var fragment = this.getFragment();\n var docMode = document.documentMode;\n var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));\n\n // Normalize root to always include a leading and trailing slash.\n this.root = ('/' + this.root + '/').replace(rootStripper, '/');\n\n if (oldIE && this._wantsHashChange) {\n var frame = Backbone.$('
\\n\\n