PageSourceSearch

https://www.timjbradley.com/files/theme/plugin.js?1643661899

js timjbradley.com collected 2026-09-30 20:24:26 UTC 89,704 bytes, 2,907 lines download raw bytes

vendor: 19,335 bytes, lines 1-705
1
2/*! Hammer.JS - v2.0.4 - 2014-09-28
3 * http://hammerjs.github.io/
4 *
5 * Copyright (c) 2014 Jorik Tangelder;
6 * Licensed under the MIT license */
7(function(window, document, exportName, undefined) {
8    'use strict';
9  
10  var VENDOR_PREFIXES = ['', 'webkit', 'moz', 'MS', 'ms', 'o'];
11  var TEST_ELEMENT = document.createElement('div');
12  
13  var TYPE_FUNCTION = 'function';
14  
15  var round = Math.round;
16  var abs = Math.abs;
17  var now = Date.now;
18  
19  /**
20   * set a timeout with a given scope
21   * @param {Function} fn
22   * @param {Number} timeout
23   * @param {Object} context
24   * @returns {number}
25   */
26  function setTimeoutContext(fn, timeout, context) {
27      return setTimeout(bindFn(fn, context), timeout);
28  }
29  
30  /**
31   * if the argument is an array, we want to execute the fn on each entry
32   * if it aint an array we don't want to do a thing.
33   * this is used by all the methods that accept a single and array argument.
34   * @param {*|Array} arg
35   * @param {String} fn
36   * @param {Object} [context]
37   * @returns {Boolean}
38   */
39  function invokeArrayArg(arg, fn, context) {
40      if (Array.isArray(arg)) {
41          each(arg, context[fn], context);
42          return true;
43      }
44      return false;
45  }
46  
47  /**
48   * walk objects and arrays
49   * @param {Object} obj
50   * @param {Function} iterator
51   * @param {Object} context
52   */
53  function each(obj, iterator, context) {
54      var i;
55  
56      if (!obj) {
57          return;
58      }
59  
60      if (obj.forEach) {
61          obj.forEach(iterator, context);
62      } else if (obj.length !== undefined) {
63          i = 0;
64          while (i < obj.length) {
65              iterator.call(context, obj[i], i, obj);
66              i++;
67          }
68      } else {
69          for (i in obj) {
70              obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
71          }
72      }
73  }
74  
75  /**
76   * extend object.
77   * means that properties in dest will be overwritten by the ones in src.
78   * @param {Object} dest
79   * @param {Object} src
80   * @param {Boolean} [merge]
81   * @returns {Object} dest
82   */
83  function extend(dest, src, merge) {
84      var keys = Object.keys(src);
85      var i = 0;
86      while (i < keys.length) {
87          if (!merge || (merge && dest[keys[i]] === undefined)) {
88              dest[keys[i]] = src[keys[i]];
89          }
90          i++;
91      }
92      return dest;
93  }
94  
95  /**
96   * merge the values from src in the dest.
97   * means that properties that exist in dest will not be overwritten by src
98   * @param {Object} dest
99   * @param {Object} src
100   * @returns {Object} dest
101   */
102  function merge(dest, src) {
103      return extend(dest, src, true);
104  }
105  
106  /**
107   * simple class inheritance
108   * @param {Function} child
109   * @param {Function} base
110   * @param {Object} [properties]
111   */
112  function inherit(child, base, properties) {
113      var baseP = base.prototype,
114          childP;
115  
116      childP = child.prototype = Object.create(baseP);
117      childP.constructor = child;
118      childP._super = baseP;
119  
120      if (properties) {
121          extend(childP, properties);
122      }
123  }
124  
125  /**
126   * simple function bind
127   * @param {Function} fn
128   * @param {Object} context
129   * @returns {Function}
130   */
131  function bindFn(fn, context) {
132      return function boundFn() {
133          return fn.apply(context, arguments);
134      };
135  }
136  
137  /**
138   * let a boolean value also be a function that must return a boolean
139   * this first item in args will be used as the context
140   * @param {Boolean|Function} val
141   * @param {Array} [args]
142   * @returns {Boolean}
143   */
144  function boolOrFn(val, args) {
145      if (typeof val == TYPE_FUNCTION) {
146          return val.apply(args ? args[0] || undefined : undefined, args);
147      }
148      return val;
149  }
150  
151  /**
152   * use the val2 when val1 is undefined
153   * @param {*} val1
154   * @param {*} val2
155   * @returns {*}
156   */
157  function ifUndefined(val1, val2) {
158      return (val1 === undefined) ? val2 : val1;
159  }
160  
161  /**
162   * addEventListener with multiple events at once
163   * @param {EventTarget} target
164   * @param {String} types
165   * @param {Function} handler
166   */
167  function addEventListeners(target, types, handler) {
168      each(splitStr(types), function(type) {
169          target.addEventListener(type, handler, false);
170      });
171  }
172  
173  /**
174   * removeEventListener with multiple events at once
175   * @param {EventTarget} target
176   * @param {String} types
177   * @param {Function} handler
178   */
179  function removeEventListeners(target, types, handler) {
180      each(splitStr(types), function(type) {
181          target.removeEventListener(type, handler, false);
182      });
183  }
184  
185  /**
186   * find if a node is in the given parent
187   * @method hasParent
188   * @param {HTMLElement} node
189   * @param {HTMLElement} parent
190   * @return {Boolean} found
191   */
192  function hasParent(node, parent) {
193      while (node) {
194          if (node == parent) {
195              return true;
196          }
197          node = node.parentNode;
198      }
199      return false;
200  }
201  
202  /**
203   * small indexOf wrapper
204   * @param {String} str
205   * @param {String} find
206   * @returns {Boolean} found
207   */
208  function inStr(str, find) {
209      return str.indexOf(find) > -1;
210  }
211  
212  /**
213   * split string on whitespace
214   * @param {String} str
215   * @returns {Array} words
216   */
217  function splitStr(str) {
218      return str.trim().split(/\s+/g);
219  }
220  
221  /**
222   * find if a array contains the object using indexOf or a simple polyFill
223   * @param {Array} src
224   * @param {String} find
225   * @param {String} [findByKey]
226   * @return {Boolean|Number} false when not found, or the index
227   */
228  function inArray(src, find, findByKey) {
229      if (src.indexOf && !findByKey) {
230          return src.indexOf(find);
231      } else {
232          var i = 0;
233          while (i < src.length) {
234              if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
235                  return i;
236              }
237              i++;
238          }
239          return -1;
240      }
241  }
242  
243  /**
244   * convert array-like objects to real arrays
245   * @param {Object} obj
246   * @returns {Array}
247   */
248  function toArray(obj) {
249      return Array.prototype.slice.call(obj, 0);
250  }
251  
252  /**
253   * unique array with objects based on a key (like 'id') or just by the array's value
254   * @param {Array} src [{id:1},{id:2},{id:1}]
255   * @param {String} [key]
256   * @param {Boolean} [sort=False]
257   * @returns {Array} [{id:1},{id:2}]
258   */
259  function uniqueArray(src, key, sort) {
260      var results = [];
261      var values = [];
262      var i = 0;
263  
264      while (i < src.length) {
265          var val = key ? src[i][key] : src[i];
266          if (inArray(values, val) < 0) {
267              results.push(src[i]);
268          }
269          values[i] = val;
270          i++;
271      }
272  
273      if (sort) {
274          if (!key) {
275              results = results.sort();
276          } else {
277              results = results.sort(function sortUniqueArray(a, b) {
278                  return a[key] > b[key];
279              });
280          }
281      }
282  
283      return results;
284  }
285  
286  /**
287   * get the prefixed property
288   * @param {Object} obj
289   * @param {String} property
290   * @returns {String|Undefined} prefixed
291   */
292  function prefixed(obj, property) {
293      var prefix, prop;
294      var camelProp = property[0].toUpperCase() + property.slice(1);
295  
296      var i = 0;
297      while (i < VENDOR_PREFIXES.length) {
298          prefix = VENDOR_PREFIXES[i];
299          prop = (prefix) ? prefix + camelProp : property;
300  
301          if (prop in obj) {
302              return prop;
303          }
304          i++;
305      }
306      return undefined;
307  }
308  
309  /**
310   * get a unique id
311   * @returns {number} uniqueId
312   */
313  var _uniqueId = 1;
314  function uniqueId() {
315      return _uniqueId++;
316  }
317  
318  /**
319   * get the window object of an element
320   * @param {HTMLElement} element
321   * @returns {DocumentView|Window}
322   */
323  function getWindowForElement(element) {
324      var doc = element.ownerDocument;
325      return (doc.defaultView || doc.parentWindow);
326  }
327  
328  var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
329  
330  var SUPPORT_TOUCH = ('ontouchstart' in window);
331  var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;
332  var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
333  
334  var INPUT_TYPE_TOUCH = 'touch';
335  var INPUT_TYPE_PEN = 'pen';
336  var INPUT_TYPE_MOUSE = 'mouse';
337  var INPUT_TYPE_KINECT = 'kinect';
338  
339  var COMPUTE_INTERVAL = 25;
340  
341  var INPUT_START = 1;
342  var INPUT_MOVE = 2;
343  var INPUT_END = 4;
344  var INPUT_CANCEL = 8;
345  
346  var DIRECTION_NONE = 1;
347  var DIRECTION_LEFT = 2;
348  var DIRECTION_RIGHT = 4;
349  var DIRECTION_UP = 8;
350  var DIRECTION_DOWN = 16;
351  
352  var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
353  var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
354  var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
355  
356  var PROPS_XY = ['x', 'y'];
357  var PROPS_CLIENT_XY = ['clientX', 'clientY'];
358  
359  /**
360   * create new input type manager
361   * @param {Manager} manager
362   * @param {Function} callback
363   * @returns {Input}
364   * @constructor
365   */
366  function Input(manager, callback) {
367      var self = this;
368      this.manager = manager;
369      this.callback = callback;
370      this.element = manager.element;
371      this.target = manager.options.inputTarget;
372  
373      // smaller wrapper around the handler, for the scope and the enabled state of the manager,
374      // so when disabled the input events are completely bypassed.
375      this.domHandler = function(ev) {
376          if (boolOrFn(manager.options.enable, [manager])) {
377              self.handler(ev);
378          }
379      };
380  
381      this.init();
382  
383  }
384  
385  Input.prototype = {
386      /**
387       * should handle the inputEvent data and trigger the callback
388       * @virtual
389       */
390      handler: function() { },
391  
392      /**
393       * bind the events
394       */
395      init: function() {
396          this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
397          this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
398          this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
399      },
400  
401      /**
402       * unbind the events
403       */
404      destroy: function() {
405          this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
406          this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
407          this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
408      }
409  };
410  
411  /**
412   * create new input type manager
413   * called by the Manager constructor
414   * @param {Hammer} manager
415   * @returns {Input}
416   */
417  function createInputInstance(manager) {
418      var Type;
419      var inputClass = manager.options.inputClass;
420  
421      if (inputClass) {
422          Type = inputClass;
423      } else if (SUPPORT_POINTER_EVENTS) {
424          Type = PointerEventInput;
425      } else if (SUPPORT_ONLY_TOUCH) {
426          Type = TouchInput;
427      } else if (!SUPPORT_TOUCH) {
428          Type = MouseInput;
429      } else {
430          Type = TouchMouseInput;
431      }
432      return new (Type)(manager, inputHandler);
433  }
434  
435  /**
436   * handle input events
437   * @param {Manager} manager
438   * @param {String} eventType
439   * @param {Object} input
440   */
441  function inputHandler(manager, eventType, input) {
442      var pointersLen = input.pointers.length;
443      var changedPointersLen = input.changedPointers.length;
444      var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
445      var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
446  
447      input.isFirst = !!isFirst;
448      input.isFinal = !!isFinal;
449  
450      if (isFirst) {
451          manager.session = {};
452      }
453  
454      // source event is the normalized value of the domEvents
455      // like 'touchstart, mouseup, pointerdown'
456      input.eventType = eventType;
457  
458      // compute scale, rotation etc
459      computeInputData(manager, input);
460  
461      // emit secret event
462      manager.emit('hammer.input', input);
463  
464      manager.recognize(input);
465      manager.session.prevInput = input;
466  }
467  
468  /**
469   * extend the data with some usable properties like scale, rotate, velocity etc
470   * @param {Object} manager
471   * @param {Object} input
472   */
473  function computeInputData(manager, input) {
474      var session = manager.session;
475      var pointers = input.pointers;
476      var pointersLength = pointers.length;
477  
478      // store the first input to calculate the distance and direction
479      if (!session.firstInput) {
480          session.firstInput = simpleCloneInputData(input);
481      }
482  
483      // to compute scale and rotation we need to store the multiple touches
484      if (pointersLength > 1 && !session.firstMultiple) {
485          session.firstMultiple = simpleCloneInputData(input);
486      } else if (pointersLength === 1) {
487          session.firstMultiple = false;
488      }
489  
490      var firstInput = session.firstInput;
491      var firstMultiple = session.firstMultiple;
492      var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
493  
494      var center = input.center = getCenter(pointers);
495      input.timeStamp = now();
496      input.deltaTime = input.timeStamp - firstInput.timeStamp;
497  
498      input.angle = getAngle(offsetCenter, center);
499      input.distance = getDistance(offsetCenter, center);
500  
501      computeDeltaXY(session, input);
502      input.offsetDirection = getDirection(input.deltaX, input.deltaY);
503  
504      input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
505      input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
506  
507      computeIntervalInputData(session, input);
508  
509      // find the correct target
510      var target = manager.element;
511      if (hasParent(input.srcEvent.target, target)) {
512          target = input.srcEvent.target;
513      }
514      input.target = target;
515  }
516  
517  function computeDeltaXY(session, input) {
518      var center = input.center;
519      var offset = session.offsetDelta || {};
520      var prevDelta = session.prevDelta || {};
521      var prevInput = session.prevInput || {};
522  
523      if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
524          prevDelta = session.prevDelta = {
525              x: prevInput.deltaX || 0,
526              y: prevInput.deltaY || 0
527          };
528  
529          offset = session.offsetDelta = {
530              x: center.x,
531              y: center.y
532          };
533      }
534  
535      input.deltaX = prevDelta.x + (center.x - offset.x);
536      input.deltaY = prevDelta.y + (center.y - offset.y);
537  }
538  
539  /**
540   * velocity is calculated every x ms
541   * @param {Object} session
542   * @param {Object} input
543   */
544  function computeIntervalInputData(session, input) {
545      var last = session.lastInterval || input,
546          deltaTime = input.timeStamp - last.timeStamp,
547          velocity, velocityX, velocityY, direction;
548  
549      if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
550          var deltaX = last.deltaX - input.deltaX;
551          var deltaY = last.deltaY - input.deltaY;
552  
553          var v = getVelocity(deltaTime, deltaX, deltaY);
554          velocityX = v.x;
555          velocityY = v.y;
556          velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
557          direction = getDirection(deltaX, deltaY);
558  
559          session.lastInterval = input;
560      } else {
561          // use latest velocity info if it doesn't overtake a minimum period
562          velocity = last.velocity;
563          velocityX = last.velocityX;
564          velocityY = last.velocityY;
565          direction = last.direction;
566      }
567  
568      input.velocity = velocity;
569      input.velocityX = velocityX;
570      input.velocityY = velocityY;
571      input.direction = direction;
572  }
573  
574  /**
575   * create a simple clone from the input used for storage of firstInput and firstMultiple
576   * @param {Object} input
577   * @returns {Object} clonedInputData
578   */
579  function simpleCloneInputData(input) {
580      // make a simple copy of the pointers because we will get a reference if we don't
581      // we only need clientXY for the calculations
582      var pointers = [];
583      var i = 0;
584      while (i < input.pointers.length) {
585          pointers[i] = {
586              clientX: round(input.pointers[i].clientX),
587              clientY: round(input.pointers[i].clientY)
588          };
589          i++;
590      }
591  
592      return {
593          timeStamp: now(),
594          pointers: pointers,
595          center: getCenter(pointers),
596          deltaX: input.deltaX,
597          deltaY: input.deltaY
598      };
599  }
600  
601  /**
602   * get the center of all the pointers
603   * @param {Array} pointers
604   * @return {Object} center contains `x` and `y` properties
605   */
606  function getCenter(pointers) {
607      var pointersLength = pointers.length;
608  
609      // no need to loop when only one touch
610      if (pointersLength === 1) {
611          return {
612              x: round(pointers[0].clientX),
613              y: round(pointers[0].clientY)
614          };
615      }
616  
617      var x = 0, y = 0, i = 0;
618      while (i < pointersLength) {
619          x += pointers[i].clientX;
620          y += pointers[i].clientY;
621          i++;
622      }
623  
624      return {
625          x: round(x / pointersLength),
626          y: round(y / pointersLength)
627      };
628  }
629  
630  /**
631   * calculate the velocity between two points. unit is in px per ms.
632   * @param {Number} deltaTime
633   * @param {Number} x
634   * @param {Number} y
635   * @return {Object} velocity `x` and `y`
636   */
637  function getVelocity(deltaTime, x, y) {
638      return {
639          x: x / deltaTime || 0,
640          y: y / deltaTime || 0
641      };
642  }
643  
644  /**
645   * get the direction between two points
646   * @param {Number} x
647   * @param {Number} y
648   * @return {Number} direction
649   */
650  function getDirection(x, y) {
651      if (x === y) {
652          return DIRECTION_NONE;
653      }
654  
655      if (abs(x) >= abs(y)) {
656          return x > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
657      }
658      return y > 0 ? DIRECTION_UP : DIRECTION_DOWN;
659  }
660  
661  /**
662   * calculate the absolute distance between two points
663   * @param {Object} p1 {x, y}
664   * @param {Object} p2 {x, y}
665   * @param {Array} [props] containing x and y keys
666   * @return {Number} distance
667   */
668  function getDistance(p1, p2, props) {
669      if (!props) {
670          props = PROPS_XY;
671      }
672      var x = p2[props[0]] - p1[props[0]],
673          y = p2[props[1]] - p1[props[1]];
674  
675      return Math.sqrt((x * x) + (y * y));
676  }
677  
678  /**
679   * calculate the angle between two coordinates
680   * @param {Object} p1
681   * @param {Object} p2
682   * @param {Array} [props] containing x and y keys
683   * @return {Number} angle
684   */
685  function getAngle(p1, p2, props) {
686      if (!props) {
687          props = PROPS_XY;
688      }
689      var x = p2[props[0]] - p1[props[0]],
690          y = p2[props[1]] - p1[props[1]];
691      return Math.atan2(y, x) * 180 / Math.PI;
692  }
693  
694  /**
695   * calculate the rotation degrees between two pointersets
696   * @param {Array} start array of pointers
697   * @param {Array} end array of pointers
698   * @return {Number} rotation
699   */
700  function getRotation(start, end) {
701      return getAngle(end[1], end[0], PROPS_CLIENT_XY) - getAngle(start[1], start[0], PROPS_CLIENT_XY);
702  }
703  
704  /**
705   * calculate the scale factor between two pointersets
vendor: 21,256 bytes, lines 706-1413
706   * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
707   * @param {Array} start array of pointers
708   * @param {Array} end array of pointers
709   * @return {Number} scale
710   */
711  function getScale(start, end) {
712      return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
713  }
714  
715  var MOUSE_INPUT_MAP = {
716      mousedown: INPUT_START,
717      mousemove: INPUT_MOVE,
718      mouseup: INPUT_END
719  };
720  
721  var MOUSE_ELEMENT_EVENTS = 'mousedown';
722  var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
723  
724  /**
725   * Mouse events input
726   * @constructor
727   * @extends Input
728   */
729  function MouseInput() {
730      this.evEl = MOUSE_ELEMENT_EVENTS;
731      this.evWin = MOUSE_WINDOW_EVENTS;
732  
733      this.allow = true; // used by Input.TouchMouse to disable mouse events
734      this.pressed = false; // mousedown state
735  
736      Input.apply(this, arguments);
737  }
738  
739  inherit(MouseInput, Input, {
740      /**
741       * handle mouse events
742       * @param {Object} ev
743       */
744      handler: function MEhandler(ev) {
745          var eventType = MOUSE_INPUT_MAP[ev.type];
746  
747          // on start we want to have the left mouse button down
748          if (eventType & INPUT_START && ev.button === 0) {
749              this.pressed = true;
750          }
751  
752          if (eventType & INPUT_MOVE && ev.which !== 1) {
753              eventType = INPUT_END;
754          }
755  
756          // mouse must be down, and mouse events are allowed (see the TouchMouse input)
757          if (!this.pressed || !this.allow) {
758              return;
759          }
760  
761          if (eventType & INPUT_END) {
762              this.pressed = false;
763          }
764  
765          this.callback(this.manager, eventType, {
766              pointers: [ev],
767              changedPointers: [ev],
768              pointerType: INPUT_TYPE_MOUSE,
769              srcEvent: ev
770          });
771      }
772  });
773  
774  var POINTER_INPUT_MAP = {
775      pointerdown: INPUT_START,
776      pointermove: INPUT_MOVE,
777      pointerup: INPUT_END,
778      pointercancel: INPUT_CANCEL,
779      pointerout: INPUT_CANCEL
780  };
781  
782  // in IE10 the pointer types is defined as an enum
783  var IE10_POINTER_TYPE_ENUM = {
784      2: INPUT_TYPE_TOUCH,
785      3: INPUT_TYPE_PEN,
786      4: INPUT_TYPE_MOUSE,
787      5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
788  };
789  
790  var POINTER_ELEMENT_EVENTS = 'pointerdown';
791  var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
792  
793  // IE10 has prefixed support, and case-sensitive
794  if (window.MSPointerEvent) {
795      POINTER_ELEMENT_EVENTS = 'MSPointerDown';
796      POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
797  }
798  
799  /**
800   * Pointer events input
801   * @constructor
802   * @extends Input
803   */
804  function PointerEventInput() {
805      this.evEl = POINTER_ELEMENT_EVENTS;
806      this.evWin = POINTER_WINDOW_EVENTS;
807  
808      Input.apply(this, arguments);
809  
810      this.store = (this.manager.session.pointerEvents = []);
811  }
812  
813  inherit(PointerEventInput, Input, {
814      /**
815       * handle mouse events
816       * @param {Object} ev
817       */
818      handler: function PEhandler(ev) {
819          var store = this.store;
820          var removePointer = false;
821  
822          var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
823          var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
824          var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
825  
826          var isTouch = (pointerType == INPUT_TYPE_TOUCH);
827  
828          // get index of the event in the store
829          var storeIndex = inArray(store, ev.pointerId, 'pointerId');
830  
831          // start and mouse must be down
832          if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
833              if (storeIndex < 0) {
834                  store.push(ev);
835                  storeIndex = store.length - 1;
836              }
837          } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
838              removePointer = true;
839          }
840  
841          // it not found, so the pointer hasn't been down (so it's probably a hover)
842          if (storeIndex < 0) {
843              return;
844          }
845  
846          // update the event in the store
847          store[storeIndex] = ev;
848  
849          this.callback(this.manager, eventType, {
850              pointers: store,
851              changedPointers: [ev],
852              pointerType: pointerType,
853              srcEvent: ev
854          });
855  
856          if (removePointer) {
857              // remove from the store
858              store.splice(storeIndex, 1);
859          }
860      }
861  });
862  
863  var SINGLE_TOUCH_INPUT_MAP = {
864      touchstart: INPUT_START,
865      touchmove: INPUT_MOVE,
866      touchend: INPUT_END,
867      touchcancel: INPUT_CANCEL
868  };
869  
870  var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
871  var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
872  
873  /**
874   * Touch events input
875   * @constructor
876   * @extends Input
877   */
878  function SingleTouchInput() {
879      this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
880      this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
881      this.started = false;
882  
883      Input.apply(this, arguments);
884  }
885  
886  inherit(SingleTouchInput, Input, {
887      handler: function TEhandler(ev) {
888          var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
889  
890          // should we handle the touch events?
891          if (type === INPUT_START) {
892              this.started = true;
893          }
894  
895          if (!this.started) {
896              return;
897          }
898  
899          var touches = normalizeSingleTouches.call(this, ev, type);
900  
901          // when done, reset the started state
902          if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
903              this.started = false;
904          }
905  
906          this.callback(this.manager, type, {
907              pointers: touches[0],
908              changedPointers: touches[1],
909              pointerType: INPUT_TYPE_TOUCH,
910              srcEvent: ev
911          });
912      }
913  });
914  
915  /**
916   * @this {TouchInput}
917   * @param {Object} ev
918   * @param {Number} type flag
919   * @returns {undefined|Array} [all, changed]
920   */
921  function normalizeSingleTouches(ev, type) {
922      var all = toArray(ev.touches);
923      var changed = toArray(ev.changedTouches);
924  
925      if (type & (INPUT_END | INPUT_CANCEL)) {
926          all = uniqueArray(all.concat(changed), 'identifier', true);
927      }
928  
929      return [all, changed];
930  }
931  
932  var TOUCH_INPUT_MAP = {
933      touchstart: INPUT_START,
934      touchmove: INPUT_MOVE,
935      touchend: INPUT_END,
936      touchcancel: INPUT_CANCEL
937  };
938  
939  var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
940  
941  /**
942   * Multi-user touch events input
943   * @constructor
944   * @extends Input
945   */
946  function TouchInput() {
947      this.evTarget = TOUCH_TARGET_EVENTS;
948      this.targetIds = {};
949  
950      Input.apply(this, arguments);
951  }
952  
953  inherit(TouchInput, Input, {
954      handler: function MTEhandler(ev) {
955          var type = TOUCH_INPUT_MAP[ev.type];
956          var touches = getTouches.call(this, ev, type);
957          if (!touches) {
958              return;
959          }
960  
961          this.callback(this.manager, type, {
962              pointers: touches[0],
963              changedPointers: touches[1],
964              pointerType: INPUT_TYPE_TOUCH,
965              srcEvent: ev
966          });
967      }
968  });
969  
970  /**
971   * @this {TouchInput}
972   * @param {Object} ev
973   * @param {Number} type flag
974   * @returns {undefined|Array} [all, changed]
975   */
976  function getTouches(ev, type) {
977      var allTouches = toArray(ev.touches);
978      var targetIds = this.targetIds;
979  
980      // when there is only one touch, the process can be simplified
981      if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
982          targetIds[allTouches[0].identifier] = true;
983          return [allTouches, allTouches];
984      }
985  
986      var i,
987          targetTouches,
988          changedTouches = toArray(ev.changedTouches),
989          changedTargetTouches = [],
990          target = this.target;
991  
992      // get target touches from touches
993      targetTouches = allTouches.filter(function(touch) {
994          return hasParent(touch.target, target);
995      });
996  
997      // collect touches
998      if (type === INPUT_START) {
999          i = 0;
1000          while (i < targetTouches.length) {
1001              targetIds[targetTouches[i].identifier] = true;
1002              i++;
1003          }
1004      }
1005  
1006      // filter changed touches to only contain touches that exist in the collected target ids
1007      i = 0;
1008      while (i < changedTouches.length) {
1009          if (targetIds[changedTouches[i].identifier]) {
1010              changedTargetTouches.push(changedTouches[i]);
1011          }
1012  
1013          // cleanup removed touches
1014          if (type & (INPUT_END | INPUT_CANCEL)) {
1015              delete targetIds[changedTouches[i].identifier];
1016          }
1017          i++;
1018      }
1019  
1020      if (!changedTargetTouches.length) {
1021          return;
1022      }
1023  
1024      return [
1025          // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
1026          uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
1027          changedTargetTouches
1028      ];
1029  }
1030  
1031  /**
1032   * Combined touch and mouse input
1033   *
1034   * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
1035   * This because touch devices also emit mouse events while doing a touch.
1036   *
1037   * @constructor
1038   * @extends Input
1039   */
1040  function TouchMouseInput() {
1041      Input.apply(this, arguments);
1042  
1043      var handler = bindFn(this.handler, this);
1044      this.touch = new TouchInput(this.manager, handler);
1045      this.mouse = new MouseInput(this.manager, handler);
1046  }
1047  
1048  inherit(TouchMouseInput, Input, {
1049      /**
1050       * handle mouse and touch events
1051       * @param {Hammer} manager
1052       * @param {String} inputEvent
1053       * @param {Object} inputData
1054       */
1055      handler: function TMEhandler(manager, inputEvent, inputData) {
1056          var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
1057              isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
1058  
1059          // when we're in a touch event, so  block all upcoming mouse events
1060          // most mobile browser also emit mouseevents, right after touchstart
1061          if (isTouch) {
1062              this.mouse.allow = false;
1063          } else if (isMouse && !this.mouse.allow) {
1064              return;
1065          }
1066  
1067          // reset the allowMouse when we're done
1068          if (inputEvent & (INPUT_END | INPUT_CANCEL)) {
1069              this.mouse.allow = true;
1070          }
1071  
1072          this.callback(manager, inputEvent, inputData);
1073      },
1074  
1075      /**
1076       * remove the event listeners
1077       */
1078      destroy: function destroy() {
1079          this.touch.destroy();
1080          this.mouse.destroy();
1081      }
1082  });
1083  
1084  var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
1085  var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
1086  
1087  // magical touchAction value
1088  var TOUCH_ACTION_COMPUTE = 'compute';
1089  var TOUCH_ACTION_AUTO = 'auto';
1090  var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
1091  var TOUCH_ACTION_NONE = 'none';
1092  var TOUCH_ACTION_PAN_X = 'pan-x';
1093  var TOUCH_ACTION_PAN_Y = 'pan-y';
1094  
1095  /**
1096   * Touch Action
1097   * sets the touchAction property or uses the js alternative
1098   * @param {Manager} manager
1099   * @param {String} value
1100   * @constructor
1101   */
1102  function TouchAction(manager, value) {
1103      this.manager = manager;
1104      this.set(value);
1105  }
1106  
1107  TouchAction.prototype = {
1108      /**
1109       * set the touchAction value on the element or enable the polyfill
1110       * @param {String} value
1111       */
1112      set: function(value) {
1113          // find out the touch-action by the event handlers
1114          if (value == TOUCH_ACTION_COMPUTE) {
1115              value = this.compute();
1116          }
1117  
1118          if (NATIVE_TOUCH_ACTION) {
1119              this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
1120          }
1121          this.actions = value.toLowerCase().trim();
1122      },
1123  
1124      /**
1125       * just re-set the touchAction value
1126       */
1127      update: function() {
1128          this.set(this.manager.options.touchAction);
1129      },
1130  
1131      /**
1132       * compute the value for the touchAction property based on the recognizer's settings
1133       * @returns {String} value
1134       */
1135      compute: function() {
1136          var actions = [];
1137          each(this.manager.recognizers, function(recognizer) {
1138              if (boolOrFn(recognizer.options.enable, [recognizer])) {
1139                  actions = actions.concat(recognizer.getTouchAction());
1140              }
1141          });
1142          return cleanTouchActions(actions.join(' '));
1143      },
1144  
1145      /**
1146       * this method is called on each input cycle and provides the preventing of the browser behavior
1147       * @param {Object} input
1148       */
1149      preventDefaults: function(input) {
1150          // not needed with native support for the touchAction property
1151          if (NATIVE_TOUCH_ACTION) {
1152              return;
1153          }
1154  
1155          var srcEvent = input.srcEvent;
1156          var direction = input.offsetDirection;
1157  
1158          // if the touch action did prevented once this session
1159          if (this.manager.session.prevented) {
1160              srcEvent.preventDefault();
1161              return;
1162          }
1163  
1164          var actions = this.actions;
1165          var hasNone = inStr(actions, TOUCH_ACTION_NONE);
1166          var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
1167          var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
1168  
1169          if (hasNone ||
1170              (hasPanY && direction & DIRECTION_HORIZONTAL) ||
1171              (hasPanX && direction & DIRECTION_VERTICAL)) {
1172              return this.preventSrc(srcEvent);
1173          }
1174      },
1175  
1176      /**
1177       * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
1178       * @param {Object} srcEvent
1179       */
1180      preventSrc: function(srcEvent) {
1181          this.manager.session.prevented = true;
1182          srcEvent.preventDefault();
1183      }
1184  };
1185  
1186  /**
1187   * when the touchActions are collected they are not a valid value, so we need to clean things up. *
1188   * @param {String} actions
1189   * @returns {*}
1190   */
1191  function cleanTouchActions(actions) {
1192      // none
1193      if (inStr(actions, TOUCH_ACTION_NONE)) {
1194          return TOUCH_ACTION_NONE;
1195      }
1196  
1197      var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
1198      var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
1199  
1200      // pan-x and pan-y can be combined
1201      if (hasPanX && hasPanY) {
1202          return TOUCH_ACTION_PAN_X + ' ' + TOUCH_ACTION_PAN_Y;
1203      }
1204  
1205      // pan-x OR pan-y
1206      if (hasPanX || hasPanY) {
1207          return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
1208      }
1209  
1210      // manipulation
1211      if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
1212          return TOUCH_ACTION_MANIPULATION;
1213      }
1214  
1215      return TOUCH_ACTION_AUTO;
1216  }
1217  
1218  /**
1219   * Recognizer flow explained; *
1220   * All recognizers have the initial state of POSSIBLE when a input session starts.
1221   * The definition of a input session is from the first input until the last input, with all it's movement in it. *
1222   * Example session for mouse-input: mousedown -> mousemove -> mouseup
1223   *
1224   * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
1225   * which determines with state it should be.
1226   *
1227   * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
1228   * POSSIBLE to give it another change on the next cycle.
1229   *
1230   *               Possible
1231   *                  |
1232   *            +-----+---------------+
1233   *            |                     |
1234   *      +-----+-----+               |
1235   *      |           |               |
1236   *   Failed      Cancelled          |
1237   *                          +-------+------+
1238   *                          |              |
1239   *                      Recognized       Began
1240   *                                         |
1241   *                                      Changed
1242   *                                         |
1243   *                                  Ended/Recognized
1244   */
1245  var STATE_POSSIBLE = 1;
1246  var STATE_BEGAN = 2;
1247  var STATE_CHANGED = 4;
1248  var STATE_ENDED = 8;
1249  var STATE_RECOGNIZED = STATE_ENDED;
1250  var STATE_CANCELLED = 16;
1251  var STATE_FAILED = 32;
1252  
1253  /**
1254   * Recognizer
1255   * Every recognizer needs to extend from this class.
1256   * @constructor
1257   * @param {Object} options
1258   */
1259  function Recognizer(options) {
1260      this.id = uniqueId();
1261  
1262      this.manager = null;
1263      this.options = merge(options || {}, this.defaults);
1264  
1265      // default is enable true
1266      this.options.enable = ifUndefined(this.options.enable, true);
1267  
1268      this.state = STATE_POSSIBLE;
1269  
1270      this.simultaneous = {};
1271      this.requireFail = [];
1272  }
1273  
1274  Recognizer.prototype = {
1275      /**
1276       * @virtual
1277       * @type {Object}
1278       */
1279      defaults: {},
1280  
1281      /**
1282       * set options
1283       * @param {Object} options
1284       * @return {Recognizer}
1285       */
1286      set: function(options) {
1287          extend(this.options, options);
1288  
1289          // also update the touchAction, in case something changed about the directions/enabled state
1290          this.manager && this.manager.touchAction.update();
1291          return this;
1292      },
1293  
1294      /**
1295       * recognize simultaneous with an other recognizer.
1296       * @param {Recognizer} otherRecognizer
1297       * @returns {Recognizer} this
1298       */
1299      recognizeWith: function(otherRecognizer) {
1300          if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
1301              return this;
1302          }
1303  
1304          var simultaneous = this.simultaneous;
1305          otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1306          if (!simultaneous[otherRecognizer.id]) {
1307              simultaneous[otherRecognizer.id] = otherRecognizer;
1308              otherRecognizer.recognizeWith(this);
1309          }
1310          return this;
1311      },
1312  
1313      /**
1314       * drop the simultaneous link. it doesnt remove the link on the other recognizer.
1315       * @param {Recognizer} otherRecognizer
1316       * @returns {Recognizer} this
1317       */
1318      dropRecognizeWith: function(otherRecognizer) {
1319          if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
1320              return this;
1321          }
1322  
1323          otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1324          delete this.simultaneous[otherRecognizer.id];
1325          return this;
1326      },
1327  
1328      /**
1329       * recognizer can only run when an other is failing
1330       * @param {Recognizer} otherRecognizer
1331       * @returns {Recognizer} this
1332       */
1333      requireFailure: function(otherRecognizer) {
1334          if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
1335              return this;
1336          }
1337  
1338          var requireFail = this.requireFail;
1339          otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1340          if (inArray(requireFail, otherRecognizer) === -1) {
1341              requireFail.push(otherRecognizer);
1342              otherRecognizer.requireFailure(this);
1343          }
1344          return this;
1345      },
1346  
1347      /**
1348       * drop the requireFailure link. it does not remove the link on the other recognizer.
1349       * @param {Recognizer} otherRecognizer
1350       * @returns {Recognizer} this
1351       */
1352      dropRequireFailure: function(otherRecognizer) {
1353          if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
1354              return this;
1355          }
1356  
1357          otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1358          var index = inArray(this.requireFail, otherRecognizer);
1359          if (index > -1) {
1360              this.requireFail.splice(index, 1);
1361          }
1362          return this;
1363      },
1364  
1365      /**
1366       * has require failures boolean
1367       * @returns {boolean}
1368       */
1369      hasRequireFailures: function() {
1370          return this.requireFail.length > 0;
1371      },
1372  
1373      /**
1374       * if the recognizer can recognize simultaneous with an other recognizer
1375       * @param {Recognizer} otherRecognizer
1376       * @returns {Boolean}
1377       */
1378      canRecognizeWith: function(otherRecognizer) {
1379          return !!this.simultaneous[otherRecognizer.id];
1380      },
1381  
1382      /**
1383       * You should use `tryEmit` instead of `emit` directly to check
1384       * that all the needed recognizers has failed before emitting.
1385       * @param {Object} input
1386       */
1387      emit: function(input) {
1388          var self = this;
1389          var state = this.state;
1390  
1391          function emit(withState) {
1392              self.manager.emit(self.options.event + (withState ? stateStr(state) : ''), input);
1393          }
1394  
1395          // 'panstart' and 'panmove'
1396          if (state < STATE_ENDED) {
1397              emit(true);
1398          }
1399  
1400          emit(); // simple 'eventName' events
1401  
1402          // panend and pancancel
1403          if (state >= STATE_ENDED) {
1404              emit(true);
1405          }
1406      },
1407  
1408      /**
1409       * Check that all the require failure recognizers has failed,
1410       * if true, it emits a gesture event,
1411       * otherwise, setup the state to FAILED.
1412       * @param {Object} input
1413       */
vendor: 7,768 bytes, lines 1414-1682
1414      tryEmit: function(input) {
1415          if (this.canEmit()) {
1416              return this.emit(input);
1417          }
1418          // it's failing anyway
1419          this.state = STATE_FAILED;
1420      },
1421  
1422      /**
1423       * can we emit?
1424       * @returns {boolean}
1425       */
1426      canEmit: function() {
1427          var i = 0;
1428          while (i < this.requireFail.length) {
1429              if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
1430                  return false;
1431              }
1432              i++;
1433          }
1434          return true;
1435      },
1436  
1437      /**
1438       * update the recognizer
1439       * @param {Object} inputData
1440       */
1441      recognize: function(inputData) {
1442          // make a new copy of the inputData
1443          // so we can change the inputData without messing up the other recognizers
1444          var inputDataClone = extend({}, inputData);
1445  
1446          // is is enabled and allow recognizing?
1447          if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
1448              this.reset();
1449              this.state = STATE_FAILED;
1450              return;
1451          }
1452  
1453          // reset when we've reached the end
1454          if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
1455              this.state = STATE_POSSIBLE;
1456          }
1457  
1458          this.state = this.process(inputDataClone);
1459  
1460          // the recognizer has recognized a gesture
1461          // so trigger an event
1462          if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
1463              this.tryEmit(inputDataClone);
1464          }
1465      },
1466  
1467      /**
1468       * return the state of the recognizer
1469       * the actual recognizing happens in this method
1470       * @virtual
1471       * @param {Object} inputData
1472       * @returns {Const} STATE
1473       */
1474      process: function(inputData) { }, // jshint ignore:line
1475  
1476      /**
1477       * return the preferred touch-action
1478       * @virtual
1479       * @returns {Array}
1480       */
1481      getTouchAction: function() { },
1482  
1483      /**
1484       * called when the gesture isn't allowed to recognize
1485       * like when another is being recognized or it is disabled
1486       * @virtual
1487       */
1488      reset: function() { }
1489  };
1490  
1491  /**
1492   * get a usable string, used as event postfix
1493   * @param {Const} state
1494   * @returns {String} state
1495   */
1496  function stateStr(state) {
1497      if (state & STATE_CANCELLED) {
1498          return 'cancel';
1499      } else if (state & STATE_ENDED) {
1500          return 'end';
1501      } else if (state & STATE_CHANGED) {
1502          return 'move';
1503      } else if (state & STATE_BEGAN) {
1504          return 'start';
1505      }
1506      return '';
1507  }
1508  
1509  /**
1510   * direction cons to string
1511   * @param {Const} direction
1512   * @returns {String}
1513   */
1514  function directionStr(direction) {
1515      if (direction == DIRECTION_DOWN) {
1516          return 'down';
1517      } else if (direction == DIRECTION_UP) {
1518          return 'up';
1519      } else if (direction == DIRECTION_LEFT) {
1520          return 'left';
1521      } else if (direction == DIRECTION_RIGHT) {
1522          return 'right';
1523      }
1524      return '';
1525  }
1526  
1527  /**
1528   * get a recognizer by name if it is bound to a manager
1529   * @param {Recognizer|String} otherRecognizer
1530   * @param {Recognizer} recognizer
1531   * @returns {Recognizer}
1532   */
1533  function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
1534      var manager = recognizer.manager;
1535      if (manager) {
1536          return manager.get(otherRecognizer);
1537      }
1538      return otherRecognizer;
1539  }
1540  
1541  /**
1542   * This recognizer is just used as a base for the simple attribute recognizers.
1543   * @constructor
1544   * @extends Recognizer
1545   */
1546  function AttrRecognizer() {
1547      Recognizer.apply(this, arguments);
1548  }
1549  
1550  inherit(AttrRecognizer, Recognizer, {
1551      /**
1552       * @namespace
1553       * @memberof AttrRecognizer
1554       */
1555      defaults: {
1556          /**
1557           * @type {Number}
1558           * @default 1
1559           */
1560          pointers: 1
1561      },
1562  
1563      /**
1564       * Used to check if it the recognizer receives valid input, like input.distance > 10.
1565       * @memberof AttrRecognizer
1566       * @param {Object} input
1567       * @returns {Boolean} recognized
1568       */
1569      attrTest: function(input) {
1570          var optionPointers = this.options.pointers;
1571          return optionPointers === 0 || input.pointers.length === optionPointers;
1572      },
1573  
1574      /**
1575       * Process the input and return the state for the recognizer
1576       * @memberof AttrRecognizer
1577       * @param {Object} input
1578       * @returns {*} State
1579       */
1580      process: function(input) {
1581          var state = this.state;
1582          var eventType = input.eventType;
1583  
1584          var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
1585          var isValid = this.attrTest(input);
1586  
1587          // on cancel input and we've recognized before, return STATE_CANCELLED
1588          if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
1589              return state | STATE_CANCELLED;
1590          } else if (isRecognized || isValid) {
1591              if (eventType & INPUT_END) {
1592                  return state | STATE_ENDED;
1593              } else if (!(state & STATE_BEGAN)) {
1594                  return STATE_BEGAN;
1595              }
1596              return state | STATE_CHANGED;
1597          }
1598          return STATE_FAILED;
1599      }
1600  });
1601  
1602  /**
1603   * Pan
1604   * Recognized when the pointer is down and moved in the allowed direction.
1605   * @constructor
1606   * @extends AttrRecognizer
1607   */
1608  function PanRecognizer() {
1609      AttrRecognizer.apply(this, arguments);
1610  
1611      this.pX = null;
1612      this.pY = null;
1613  }
1614  
1615  inherit(PanRecognizer, AttrRecognizer, {
1616      /**
1617       * @namespace
1618       * @memberof PanRecognizer
1619       */
1620      defaults: {
1621          event: 'pan',
1622          threshold: 10,
1623          pointers: 1,
1624          direction: DIRECTION_ALL
1625      },
1626  
1627      getTouchAction: function() {
1628          var direction = this.options.direction;
1629          var actions = [];
1630          if (direction & DIRECTION_HORIZONTAL) {
1631              actions.push(TOUCH_ACTION_PAN_Y);
1632          }
1633          if (direction & DIRECTION_VERTICAL) {
1634              actions.push(TOUCH_ACTION_PAN_X);
1635          }
1636          return actions;
1637      },
1638  
1639      directionTest: function(input) {
1640          var options = this.options;
1641          var hasMoved = true;
1642          var distance = input.distance;
1643          var direction = input.direction;
1644          var x = input.deltaX;
1645          var y = input.deltaY;
1646  
1647          // lock to axis?
1648          if (!(direction & options.direction)) {
1649              if (options.direction & DIRECTION_HORIZONTAL) {
1650                  direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
1651                  hasMoved = x != this.pX;
1652                  distance = Math.abs(input.deltaX);
1653              } else {
1654                  direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
1655                  hasMoved = y != this.pY;
1656                  distance = Math.abs(input.deltaY);
1657              }
1658          }
1659          input.direction = direction;
1660          return hasMoved && distance > options.threshold && direction & options.direction;
1661      },
1662  
1663      attrTest: function(input) {
1664          return AttrRecognizer.prototype.attrTest.call(this, input) &&
1665              (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
1666      },
1667  
1668      emit: function(input) {
1669          this.pX = input.deltaX;
1670          this.pY = input.deltaY;
1671  
1672          var direction = directionStr(input.direction);
1673          if (direction) {
1674              this.manager.emit(this.options.event + direction, input);
1675          }
1676  
1677          this._super.emit.call(this, input);
1678      }
1679  });
1680  
1681  /**
1682   * Pinch
1683   * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
1684   * @constructor
1685   * @extends AttrRecognizer
1686   */
1687  function PinchRecognizer() {
1688      AttrRecognizer.apply(this, arguments);
1689  }
1690  
1691  inherit(PinchRecognizer, AttrRecognizer, {
1692      /**
1693       * @namespace
1694       * @memberof PinchRecognizer
1695       */
1696      defaults: {
1697          event: 'pinch',
1698          threshold: 0,
1699          pointers: 2
1700      },
1701  
1702      getTouchAction: function() {
1703          return [TOUCH_ACTION_NONE];
1704      },
1705  
1706      attrTest: function(input) {
1707          return this._super.attrTest.call(this, input) &&
1708              (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
1709      },
1710  
1711      emit: function(input) {
1712          this._super.emit.call(this, input);
1713          if (input.scale !== 1) {
1714              var inOut = input.scale < 1 ? 'in' : 'out';
1715              this.manager.emit(this.options.event + inOut, input);
1716          }
1717      }
1718  });
1719  
1720  /**
1721   * Press
vendor: 6,553 bytes, lines 1722-1938
1722   * Recognized when the pointer is down for x ms without any movement.
1723   * @constructor
1724   * @extends Recognizer
1725   */
1726  function PressRecognizer() {
1727      Recognizer.apply(this, arguments);
1728  
1729      this._timer = null;
1730      this._input = null;
1731  }
1732  
1733  inherit(PressRecognizer, Recognizer, {
1734      /**
1735       * @namespace
1736       * @memberof PressRecognizer
1737       */
1738      defaults: {
1739          event: 'press',
1740          pointers: 1,
1741          time: 500, // minimal time of the pointer to be pressed
1742          threshold: 5 // a minimal movement is ok, but keep it low
1743      },
1744  
1745      getTouchAction: function() {
1746          return [TOUCH_ACTION_AUTO];
1747      },
1748  
1749      process: function(input) {
1750          var options = this.options;
1751          var validPointers = input.pointers.length === options.pointers;
1752          var validMovement = input.distance < options.threshold;
1753          var validTime = input.deltaTime > options.time;
1754  
1755          this._input = input;
1756  
1757          // we only allow little movement
1758          // and we've reached an end event, so a tap is possible
1759          if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
1760              this.reset();
1761          } else if (input.eventType & INPUT_START) {
1762              this.reset();
1763              this._timer = setTimeoutContext(function() {
1764                  this.state = STATE_RECOGNIZED;
1765                  this.tryEmit();
1766              }, options.time, this);
1767          } else if (input.eventType & INPUT_END) {
1768              return STATE_RECOGNIZED;
1769          }
1770          return STATE_FAILED;
1771      },
1772  
1773      reset: function() {
1774          clearTimeout(this._timer);
1775      },
1776  
1777      emit: function(input) {
1778          if (this.state !== STATE_RECOGNIZED) {
1779              return;
1780          }
1781  
1782          if (input && (input.eventType & INPUT_END)) {
1783              this.manager.emit(this.options.event + 'up', input);
1784          } else {
1785              this._input.timeStamp = now();
1786              this.manager.emit(this.options.event, this._input);
1787          }
1788      }
1789  });
1790  
1791  /**
1792   * Rotate
1793   * Recognized when two or more pointer are moving in a circular motion.
1794   * @constructor
1795   * @extends AttrRecognizer
1796   */
1797  function RotateRecognizer() {
1798      AttrRecognizer.apply(this, arguments);
1799  }
1800  
1801  inherit(RotateRecognizer, AttrRecognizer, {
1802      /**
1803       * @namespace
1804       * @memberof RotateRecognizer
1805       */
1806      defaults: {
1807          event: 'rotate',
1808          threshold: 0,
1809          pointers: 2
1810      },
1811  
1812      getTouchAction: function() {
1813          return [TOUCH_ACTION_NONE];
1814      },
1815  
1816      attrTest: function(input) {
1817          return this._super.attrTest.call(this, input) &&
1818              (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
1819      }
1820  });
1821  
1822  /**
1823   * Swipe
1824   * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
1825   * @constructor
1826   * @extends AttrRecognizer
1827   */
1828  function SwipeRecognizer() {
1829      AttrRecognizer.apply(this, arguments);
1830  }
1831  
1832  inherit(SwipeRecognizer, AttrRecognizer, {
1833      /**
1834       * @namespace
1835       * @memberof SwipeRecognizer
1836       */
1837      defaults: {
1838          event: 'swipe',
1839          threshold: 10,
1840          velocity: 0.65,
1841          direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
1842          pointers: 1
1843      },
1844  
1845      getTouchAction: function() {
1846          return PanRecognizer.prototype.getTouchAction.call(this);
1847      },
1848  
1849      attrTest: function(input) {
1850          var direction = this.options.direction;
1851          var velocity;
1852  
1853          if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
1854              velocity = input.velocity;
1855          } else if (direction & DIRECTION_HORIZONTAL) {
1856              velocity = input.velocityX;
1857          } else if (direction & DIRECTION_VERTICAL) {
1858              velocity = input.velocityY;
1859          }
1860  
1861          return this._super.attrTest.call(this, input) &&
1862              direction & input.direction &&
1863              input.distance > this.options.threshold &&
1864              abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
1865      },
1866  
1867      emit: function(input) {
1868          var direction = directionStr(input.direction);
1869          if (direction) {
1870              this.manager.emit(this.options.event + direction, input);
1871          }
1872  
1873          this.manager.emit(this.options.event, input);
1874      }
1875  });
1876  
1877  /**
1878   * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
1879   * between the given interval and position. The delay option can be used to recognize multi-taps without firing
1880   * a single tap.
1881   *
1882   * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
1883   * multi-taps being recognized.
1884   * @constructor
1885   * @extends Recognizer
1886   */
1887  function TapRecognizer() {
1888      Recognizer.apply(this, arguments);
1889  
1890      // previous time and center,
1891      // used for tap counting
1892      this.pTime = false;
1893      this.pCenter = false;
1894  
1895      this._timer = null;
1896      this._input = null;
1897      this.count = 0;
1898  }
1899  
1900  inherit(TapRecognizer, Recognizer, {
1901      /**
1902       * @namespace
1903       * @memberof PinchRecognizer
1904       */
1905      defaults: {
1906          event: 'tap',
1907          pointers: 1,
1908          taps: 1,
1909          interval: 300, // max time between the multi-tap taps
1910          time: 250, // max time of the pointer to be down (like finger on the screen)
1911          threshold: 2, // a minimal movement is ok, but keep it low
1912          posThreshold: 10 // a multi-tap can be a bit off the initial position
1913      },
1914  
1915      getTouchAction: function() {
1916          return [TOUCH_ACTION_MANIPULATION];
1917      },
1918  
1919      process: function(input) {
1920          var options = this.options;
1921  
1922          var validPointers = input.pointers.length === options.pointers;
1923          var validMovement = input.distance < options.threshold;
1924          var validTouchTime = input.deltaTime < options.time;
1925  
1926          this.reset();
1927  
1928          if ((input.eventType & INPUT_START) && (this.count === 0)) {
1929              return this.failTimeout();
1930          }
1931  
1932          // we only allow little movement
1933          // and we've reached an end event, so a tap is possible
1934          if (validMovement && validTouchTime && validPointers) {
1935              if (input.eventType != INPUT_END) {
1936                  return this.failTimeout();
1937              }
1938  
vendor: 10,800 bytes, lines 1939-2260
1939              var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
1940              var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
1941  
1942              this.pTime = input.timeStamp;
1943              this.pCenter = input.center;
1944  
1945              if (!validMultiTap || !validInterval) {
1946                  this.count = 1;
1947              } else {
1948                  this.count += 1;
1949              }
1950  
1951              this._input = input;
1952  
1953              // if tap count matches we have recognized it,
1954              // else it has began recognizing...
1955              var tapCount = this.count % options.taps;
1956              if (tapCount === 0) {
1957                  // no failing requirements, immediately trigger the tap event
1958                  // or wait as long as the multitap interval to trigger
1959                  if (!this.hasRequireFailures()) {
1960                      return STATE_RECOGNIZED;
1961                  } else {
1962                      this._timer = setTimeoutContext(function() {
1963                          this.state = STATE_RECOGNIZED;
1964                          this.tryEmit();
1965                      }, options.interval, this);
1966                      return STATE_BEGAN;
1967                  }
1968              }
1969          }
1970          return STATE_FAILED;
1971      },
1972  
1973      failTimeout: function() {
1974          this._timer = setTimeoutContext(function() {
1975              this.state = STATE_FAILED;
1976          }, this.options.interval, this);
1977          return STATE_FAILED;
1978      },
1979  
1980      reset: function() {
1981          clearTimeout(this._timer);
1982      },
1983  
1984      emit: function() {
1985          if (this.state == STATE_RECOGNIZED ) {
1986              this._input.tapCount = this.count;
1987              this.manager.emit(this.options.event, this._input);
1988          }
1989      }
1990  });
1991  
1992  /**
1993   * Simple way to create an manager with a default set of recognizers.
1994   * @param {HTMLElement} element
1995   * @param {Object} [options]
1996   * @constructor
1997   */
1998  function Hammer(element, options) {
1999      options = options || {};
2000      options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
2001      return new Manager(element, options);
2002  }
2003  
2004  /**
2005   * @const {string}
2006   */
2007  Hammer.VERSION = '2.0.4';
2008  
2009  /**
2010   * default settings
2011   * @namespace
2012   */
2013  Hammer.defaults = {
2014      /**
2015       * set if DOM events are being triggered.
2016       * But this is slower and unused by simple implementations, so disabled by default.
2017       * @type {Boolean}
2018       * @default false
2019       */
2020      domEvents: false,
2021  
2022      /**
2023       * The value for the touchAction property/fallback.
2024       * When set to `compute` it will magically set the correct value based on the added recognizers.
2025       * @type {String}
2026       * @default compute
2027       */
2028      touchAction: TOUCH_ACTION_COMPUTE,
2029  
2030      /**
2031       * @type {Boolean}
2032       * @default true
2033       */
2034      enable: true,
2035  
2036      /**
2037       * EXPERIMENTAL FEATURE -- can be removed/changed
2038       * Change the parent input target element.
2039       * If Null, then it is being set the to main element.
2040       * @type {Null|EventTarget}
2041       * @default null
2042       */
2043      inputTarget: null,
2044  
2045      /**
2046       * force an input class
2047       * @type {Null|Function}
2048       * @default null
2049       */
2050      inputClass: null,
2051  
2052      /**
2053       * Default recognizer setup when calling `Hammer()`
2054       * When creating a new Manager these will be skipped.
2055       * @type {Array}
2056       */
2057      preset: [
2058          // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
2059          [RotateRecognizer, { enable: false }],
2060          [PinchRecognizer, { enable: false }, ['rotate']],
2061          [SwipeRecognizer,{ direction: DIRECTION_HORIZONTAL }],
2062          [PanRecognizer, { direction: DIRECTION_HORIZONTAL }, ['swipe']],
2063          [TapRecognizer],
2064          [TapRecognizer, { event: 'doubletap', taps: 2 }, ['tap']],
2065          [PressRecognizer]
2066      ],
2067  
2068      /**
2069       * Some CSS properties can be used to improve the working of Hammer.
2070       * Add them to this method and they will be set when creating a new Manager.
2071       * @namespace
2072       */
2073      cssProps: {
2074          /**
2075           * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
2076           * @type {String}
2077           * @default 'none'
2078           */
2079          userSelect: 'none',
2080  
2081          /**
2082           * Disable the Windows Phone grippers when pressing an element.
2083           * @type {String}
2084           * @default 'none'
2085           */
2086          touchSelect: 'none',
2087  
2088          /**
2089           * Disables the default callout shown when you touch and hold a touch target.
2090           * On iOS, when you touch and hold a touch target such as a link, Safari displays
2091           * a callout containing information about the link. This property allows you to disable that callout.
2092           * @type {String}
2093           * @default 'none'
2094           */
2095          touchCallout: 'none',
2096  
2097          /**
2098           * Specifies whether zooming is enabled. Used by IE10>
2099           * @type {String}
2100           * @default 'none'
2101           */
2102          contentZooming: 'none',
2103  
2104          /**
2105           * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
2106           * @type {String}
2107           * @default 'none'
2108           */
2109          userDrag: 'none',
2110  
2111          /**
2112           * Overrides the highlight color shown when the user taps a link or a JavaScript
2113           * clickable element in iOS. This property obeys the alpha value, if specified.
2114           * @type {String}
2115           * @default 'rgba(0,0,0,0)'
2116           */
2117          tapHighlightColor: 'rgba(0,0,0,0)'
2118      }
2119  };
2120  
2121  var STOP = 1;
2122  var FORCED_STOP = 2;
2123  
2124  /**
2125   * Manager
2126   * @param {HTMLElement} element
2127   * @param {Object} [options]
2128   * @constructor
2129   */
2130  function Manager(element, options) {
2131      options = options || {};
2132  
2133      this.options = merge(options, Hammer.defaults);
2134      this.options.inputTarget = this.options.inputTarget || element;
2135  
2136      this.handlers = {};
2137      this.session = {};
2138      this.recognizers = [];
2139  
2140      this.element = element;
2141      this.input = createInputInstance(this);
2142      this.touchAction = new TouchAction(this, this.options.touchAction);
2143  
2144      toggleCssProps(this, true);
2145  
2146      each(options.recognizers, function(item) {
2147          var recognizer = this.add(new (item[0])(item[1]));
2148          item[2] && recognizer.recognizeWith(item[2]);
2149          item[3] && recognizer.requireFailure(item[3]);
2150      }, this);
2151  }
2152  
2153  Manager.prototype = {
2154      /**
2155       * set options
2156       * @param {Object} options
2157       * @returns {Manager}
2158       */
2159      set: function(options) {
2160          extend(this.options, options);
2161  
2162          // Options that need a little more setup
2163          if (options.touchAction) {
2164              this.touchAction.update();
2165          }
2166          if (options.inputTarget) {
2167              // Clean up existing event listeners and reinitialize
2168              this.input.destroy();
2169              this.input.target = options.inputTarget;
2170              this.input.init();
2171          }
2172          return this;
2173      },
2174  
2175      /**
2176       * stop recognizing for this session.
2177       * This session will be discarded, when a new [input]start event is fired.
2178       * When forced, the recognizer cycle is stopped immediately.
2179       * @param {Boolean} [force]
2180       */
2181      stop: function(force) {
2182          this.session.stopped = force ? FORCED_STOP : STOP;
2183      },
2184  
2185      /**
2186       * run the recognizers!
2187       * called by the inputHandler function on every movement of the pointers (touches)
2188       * it walks through all the recognizers and tries to detect the gesture that is being made
2189       * @param {Object} inputData
2190       */
2191      recognize: function(inputData) {
2192          var session = this.session;
2193          if (session.stopped) {
2194              return;
2195          }
2196  
2197          // run the touch-action polyfill
2198          this.touchAction.preventDefaults(inputData);
2199  
2200          var recognizer;
2201          var recognizers = this.recognizers;
2202  
2203          // this holds the recognizer that is being recognized.
2204          // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
2205          // if no recognizer is detecting a thing, it is set to `null`
2206          var curRecognizer = session.curRecognizer;
2207  
2208          // reset when the last recognizer is recognized
2209          // or when we're in a new session
2210          if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
2211              curRecognizer = session.curRecognizer = null;
2212          }
2213  
2214          var i = 0;
2215          while (i < recognizers.length) {
2216              recognizer = recognizers[i];
2217  
2218              // find out if we are allowed try to recognize the input for this one.
2219              // 1.   allow if the session is NOT forced stopped (see the .stop() method)
2220              // 2.   allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
2221              //      that is being recognized.
2222              // 3.   allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
2223              //      this can be setup with the `recognizeWith()` method on the recognizer.
2224              if (session.stopped !== FORCED_STOP && ( // 1
2225                      !curRecognizer || recognizer == curRecognizer || // 2
2226                      recognizer.canRecognizeWith(curRecognizer))) { // 3
2227                  recognizer.recognize(inputData);
2228              } else {
2229                  recognizer.reset();
2230              }
2231  
2232              // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
2233              // current active recognizer. but only if we don't already have an active recognizer
2234              if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
2235                  curRecognizer = session.curRecognizer = recognizer;
2236              }
2237              i++;
2238          }
2239      },
2240  
2241      /**
2242       * get a recognizer by its event name.
2243       * @param {Recognizer|String} recognizer
2244       * @returns {Recognizer|Null}
2245       */
2246      get: function(recognizer) {
2247          if (recognizer instanceof Recognizer) {
2248              return recognizer;
2249          }
2250  
2251          var recognizers = this.recognizers;
2252          for (var i = 0; i < recognizers.length; i++) {
2253              if (recognizers[i].options.event == recognizer) {
2254                  return recognizers[i];
2255              }
2256          }
2257          return null;
2258      },
2259  
2260      /**
2261       * add a recognizer to the manager
2262       * existing recognizers with the same event name will be removed
2263       * @param {Recognizer} recognizer
2264       * @returns {Recognizer|Manager}
2265       */
2266      add: function(recognizer) {
2267          if (invokeArrayArg(recognizer, 'add', this)) {
2268              return this;
2269          }
2270  
2271          // remove existing
2272          var existing = this.get(recognizer.options.event);
2273          if (existing) {
2274              this.remove(existing);
2275          }
2276  
2277          this.recognizers.push(recognizer);
2278          recognizer.manager = this;
2279  
2280          this.touchAction.update();
2281          return recognizer;
2282      },
2283  
2284      /**
2285       * remove a recognizer by name or instance
2286       * @param {Recognizer|String} recognizer
2287       * @returns {Manager}
2288       */
2289      remove: function(recognizer) {
2290          if (invokeArrayArg(recognizer, 'remove', this)) {
2291              return this;
2292          }
2293  
2294          var recognizers = this.recognizers;
2295          recognizer = this.get(recognizer);
2296          recognizers.splice(inArray(recognizers, recognizer), 1);
2297  
2298          this.touchAction.update();
2299          return this;
2300      },
2301  
2302      /**
2303       * bind event
2304       * @param {String} events
2305       * @param {Function} handler
2306       * @returns {EventEmitter} this
2307       */
2308      on: function(events, handler) {
2309          var handlers = this.handlers;
2310          each(splitStr(events), function(event) {
2311              handlers[event] = handlers[event] || [];
2312              handlers[event].push(handler);
2313          });
2314          return this;
2315      },
2316  
2317      /**
2318       * unbind event, leave emit blank to remove all handlers
2319       * @param {String} events
2320       * @param {Function} [handler]
2321       * @returns {EventEmitter} this
2322       */
2323      off: function(events, handler) {
2324          var handlers = this.handlers;
2325          each(splitStr(events), function(event) {
2326              if (!handler) {
2327                  delete handlers[event];
2328              } else {
2329                  handlers[event].splice(inArray(handlers[event], handler), 1);
2330              }
2331          });
2332          return this;
2333      },
2334  
2335      /**
2336       * emit event to the listeners
2337       * @param {String} event
2338       * @param {Object} data
2339       */
2340      emit: function(event, data) {
2341          // we also want to trigger dom events
2342          if (this.options.domEvents) {
2343              triggerDomEvent(event, data);
2344          }
2345  
2346          // no handlers, so skip it all
2347          var handlers = this.handlers[event] && this.handlers[event].slice();
2348          if (!handlers || !handlers.length) {
2349              return;
2350          }
2351  
2352          data.type = event;
2353          data.preventDefault = function() {
2354              data.srcEvent.preventDefault();
2355          };
2356  
2357          var i = 0;
2358          while (i < handlers.length) {
2359              handlers[i](data);
2360              i++;
2361          }
2362      },
2363  
2364      /**
2365       * destroy the manager and unbinds all events
2366       * it doesn't unbind dom events, that is the user own responsibility
2367       */
2368      destroy: function() {
2369          this.element && toggleCssProps(this, false);
2370  
2371          this.handlers = {};
2372          this.session = {};
2373          this.input.destroy();
2374          this.element = null;
2375      }
2376  };
2377  
2378  /**
2379   * add/remove the css properties as defined in manager.options.cssProps
2380   * @param {Manager} manager
2381   * @param {Boolean} add
2382   */
2383  function toggleCssProps(manager, add) {
2384      var element = manager.element;
2385      each(manager.options.cssProps, function(value, name) {
2386          element.style[prefixed(element.style, name)] = add ? value : '';
2387      });
2388  }
2389  
2390  /**
2391   * trigger dom event
2392   * @param {String} event
2393   * @param {Object} data
2394   */
2395  function triggerDomEvent(event, data) {
2396      var gestureEvent = document.createEvent('Event');
2397      gestureEvent.initEvent(event, true, true);
2398      gestureEvent.gesture = data;
2399      data.target.dispatchEvent(gestureEvent);
2400  }
2401  
2402  extend(Hammer, {
2403      INPUT_START: INPUT_START,
2404      INPUT_MOVE: INPUT_MOVE,
2405      INPUT_END: INPUT_END,
2406      INPUT_CANCEL: INPUT_CANCEL,
2407  
2408      STATE_POSSIBLE: STATE_POSSIBLE,
2409      STATE_BEGAN: STATE_BEGAN,
2410      STATE_CHANGED: STATE_CHANGED,
2411      STATE_ENDED: STATE_ENDED,
2412      STATE_RECOGNIZED: STATE_RECOGNIZED,
2413      STATE_CANCELLED: STATE_CANCELLED,
2414      STATE_FAILED: STATE_FAILED,
2415  
2416      DIRECTION_NONE: DIRECTION_NONE,
2417      DIRECTION_LEFT: DIRECTION_LEFT,
2418      DIRECTION_RIGHT: DIRECTION_RIGHT,
2419      DIRECTION_UP: DIRECTION_UP,
2420      DIRECTION_DOWN: DIRECTION_DOWN,
2421      DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
2422      DIRECTION_VERTICAL: DIRECTION_VERTICAL,
2423      DIRECTION_ALL: DIRECTION_ALL,
2424  
2425      Manager: Manager,
2426      Input: Input,
2427      TouchAction: TouchAction,
2428  
2429      TouchInput: TouchInput,
2430      MouseInput: MouseInput,
2431      PointerEventInput: PointerEventInput,
2432      TouchMouseInput: TouchMouseInput,
2433      SingleTouchInput: SingleTouchInput,
2434  
2435      Recognizer: Recognizer,
2436      AttrRecognizer: AttrRecognizer,
2437      Tap: TapRecognizer,
2438      Pan: PanRecognizer,
2439      Swipe: SwipeRecognizer,
2440      Pinch: PinchRecognizer,
2441      Rotate: RotateRecognizer,
2442      Press: PressRecognizer,
2443  
2444      on: addEventListeners,
2445      off: removeEventListeners,
2446      each: each,
2447      merge: merge,
2448      extend: extend,
2449      inherit: inherit,
2450      bindFn: bindFn,
2451      prefixed: prefixed
2452  });
2453  
2454  if (typeof module != 'undefined' && module.exports) {
2455      module.exports = Hammer;
2456  } else {
2457      window[exportName] = Hammer;
2458  }
2459  
2460  })(window, document, 'Hammer');
2461  
2462
2463// Generated by CoffeeScript 1.6.2
2464/*!
2465jQuery Waypoints - v2.0.5
2466Copyright (c) 2011-2014 Caleb Troughton
2467Licensed under the MIT license.
2468https://github.com/imakewebthings/jquery-waypoints/blob/master/licenses.txt
2469*/
2470(function() {
2471    var t = [].indexOf || function(t) {
2472        for (var e = 0, n = this.length; e < n; e++) {
2473            if (e in this && this[e] === t)
2474                return e
2475        }
2476        return -1
2477    }, e = [].slice;
2478    (function(t, e) {
2479        return e(t.jQuery, t)
2480    })(window, function(n, r) {
2481        var i, o, l, s, f, u, c, a, h, d, p, y, v, w, g, m;
2482        i = n(r);
2483        a = t.call(r, "ontouchstart") >= 0;
2484        s = {horizontal: {},vertical: {}};
2485        f = 1;
2486        c = {};
2487        u = "waypoints-context-id";
2488        p = "resize.waypoints";
2489        y = "scroll.waypoints";
2490        v = 1;
2491        w = "waypoints-waypoint-ids";
vendor: 10,935 bytes, lines 2492-2749
2492        g = "waypoint";
2493        m = "waypoints";
2494        o = function() {
2495            function t(t) {
2496                var e = this;
2497                this.$element = t;
2498                this.element = t[0];
2499                this.didResize = false;
2500                this.didScroll = false;
2501                this.id = "context" + f++;
2502                this.oldScroll = {x: t.scrollLeft(),y: t.scrollTop()};
2503                this.waypoints = {horizontal: {},vertical: {}};
2504                this.element[u] = this.id;
2505                c[this.id] = this;
2506                t.bind(y, function() {
2507                    var t;
2508                    if (!(e.didScroll || a)) {
2509                        e.didScroll = true;
2510                        t = function() {
2511                            e.doScroll();
2512                            return e.didScroll = false
2513                        };
2514                        return r.setTimeout(t, n[m].settings.scrollThrottle)
2515                    }
2516                });
2517                t.bind(p, function() {
2518                    var t;
2519                    if (!e.didResize) {
2520                        e.didResize = true;
2521                        t = function() {
2522                            n[m]("refresh");
2523                            return e.didResize = false
2524                        };
2525                        return r.setTimeout(t, n[m].settings.resizeThrottle)
2526                    }
2527                })
2528            }
2529            t.prototype.doScroll = function() {
2530                var t, e = this;
2531                t = {horizontal: {newScroll: this.$element.scrollLeft(),oldScroll: this.oldScroll.x,forward: "right",backward: "left"},vertical: {newScroll: this.$element.scrollTop(),oldScroll: this.oldScroll.y,forward: "down",backward: "up"}};
2532                if (a && (!t.vertical.oldScroll || !t.vertical.newScroll)) {
2533                    n[m]("refresh")
2534                }
2535                n.each(t, function(t, r) {
2536                    var i, o, l;
2537                    l = [];
2538                    o = r.newScroll > r.oldScroll;
2539                    i = o ? r.forward : r.backward;
2540                    n.each(e.waypoints[t], function(t, e) {
2541                        var n, i;
2542                        if (r.oldScroll < (n = e.offset) && n <= r.newScroll) {
2543                            return l.push(e)
2544                        } else if (r.newScroll < (i = e.offset) && i <= r.oldScroll) {
2545                            return l.push(e)
2546                        }
2547                    });
2548                    l.sort(function(t, e) {
2549                        return t.offset - e.offset
2550                    });
2551                    if (!o) {
2552                        l.reverse()
2553                    }
2554                    return n.each(l, function(t, e) {
2555                        if (e.options.continuous || t === l.length - 1) {
2556                            return e.trigger([i])
2557                        }
2558                    })
2559                });
2560                return this.oldScroll = {x: t.horizontal.newScroll,y: t.vertical.newScroll}
2561            };
2562            t.prototype.refresh = function() {
2563                var t, e, r, i = this;
2564                r = n.isWindow(this.element);
2565                e = this.$element.offset();
2566                this.doScroll();
2567                t = {horizontal: {contextOffset: r ? 0 : e.left,contextScroll: r ? 0 : this.oldScroll.x,contextDimension: this.$element.width(),oldScroll: this.oldScroll.x,forward: "right",backward: "left",offsetProp: "left"},vertical: {contextOffset: r ? 0 : e.top,contextScroll: r ? 0 : this.oldScroll.y,contextDimension: r ? n[m]("viewportHeight") : this.$element.height(),oldScroll: this.oldScroll.y,forward: "down",backward: "up",offsetProp: "top"}};
2568                return n.each(t, function(t, e) {
2569                    return n.each(i.waypoints[t], function(t, r) {
2570                        var i, o, l, s, f;
2571                        i = r.options.offset;
2572                        l = r.offset;
2573                        o = n.isWindow(r.element) ? 0 : r.$element.offset()[e.offsetProp];
2574                        if (n.isFunction(i)) {
2575                            i = i.apply(r.element)
2576                        } else if (typeof i === "string") {
2577                            i = parseFloat(i);
2578                            if (r.options.offset.indexOf("%") > -1) {
2579                                i = Math.ceil(e.contextDimension * i / 100)
2580                            }
2581                        }
2582                        r.offset = o - e.contextOffset + e.contextScroll - i;
2583                        if (r.options.onlyOnScroll && l != null || !r.enabled) {
2584                            return
2585                        }
2586                        if (l !== null && l < (s = e.oldScroll) && s <= r.offset) {
2587                            return r.trigger([e.backward])
2588                        } else if (l !== null && l > (f = e.oldScroll) && f >= r.offset) {
2589                            return r.trigger([e.forward])
2590                        } else if (l === null && e.oldScroll >= r.offset) {
2591                            return r.trigger([e.forward])
2592                        }
2593                    })
2594                })
2595            };
2596            t.prototype.checkEmpty = function() {
2597                if (n.isEmptyObject(this.waypoints.horizontal) && n.isEmptyObject(this.waypoints.vertical)) {
2598                    this.$element.unbind([p, y].join(" "));
2599                    return delete c[this.id]
2600                }
2601            };
2602            return t
2603        }();
2604        l = function() {
2605            function t(t, e, r) {
2606                var i, o;
2607                if (r.offset === "bottom-in-view") {
2608                    r.offset = function() {
2609                        var t;
2610                        t = n[m]("viewportHeight");
2611                        if (!n.isWindow(e.element)) {
2612                            t = e.$element.height()
2613                        }
2614                        return t - n(this).outerHeight()
2615                    }
2616                }
2617                this.$element = t;
2618                this.element = t[0];
2619                this.axis = r.horizontal ? "horizontal" : "vertical";
2620                this.callback = r.handler;
2621                this.context = e;
2622                this.enabled = r.enabled;
2623                this.id = "waypoints" + v++;
2624                this.offset = null;
2625                this.options = r;
2626                e.waypoints[this.axis][this.id] = this;
2627                s[this.axis][this.id] = this;
2628                i = (o = this.element[w]) != null ? o : [];
2629                i.push(this.id);
2630                this.element[w] = i
2631            }
2632            t.prototype.trigger = function(t) {
2633                if (!this.enabled) {
2634                    return
2635                }
2636                if (this.callback != null) {
2637                    this.callback.apply(this.element, t)
2638                }
2639                if (this.options.triggerOnce) {
2640                    return this.destroy()
2641                }
2642            };
2643            t.prototype.disable = function() {
2644                return this.enabled = false
2645            };
2646            t.prototype.enable = function() {
2647                this.context.refresh();
2648                return this.enabled = true
2649            };
2650            t.prototype.destroy = function() {
2651                delete s[this.axis][this.id];
2652                delete this.context.waypoints[this.axis][this.id];
2653                return this.context.checkEmpty()
2654            };
2655            t.getWaypointsByElement = function(t) {
2656                var e, r;
2657                r = t[w];
2658                if (!r) {
2659                    return []
2660                }
2661                e = n.extend({}, s.horizontal, s.vertical);
2662                return n.map(r, function(t) {
2663                    return e[t]
2664                })
2665            };
2666            return t
2667        }();
2668        d = {init: function(t, e) {
2669                var r;
2670                e = n.extend({}, n.fn[g].defaults, e);
2671                if ((r = e.handler) == null) {
2672                    e.handler = t
2673                }
2674                this.each(function() {
2675                    var t, r, i, s;
2676                    t = n(this);
2677                    i = (s = e.context) != null ? s : n.fn[g].defaults.context;
2678                    if (!n.isWindow(i)) {
2679                        i = t.closest(i)
2680                    }
2681                    i = n(i);
2682                    r = c[i[0][u]];
2683                    if (!r) {
2684                        r = new o(i)
2685                    }
2686                    return new l(t, r, e)
2687                });
2688                n[m]("refresh");
2689                return this
2690            },disable: function() {
2691                return d._invoke.call(this, "disable")
2692            },enable: function() {
2693                return d._invoke.call(this, "enable")
2694            },destroy: function() {
2695                return d._invoke.call(this, "destroy")
2696            },prev: function(t, e) {
2697                return d._traverse.call(this, t, e, function(t, e, n) {
2698                    if (e > 0) {
2699                        return t.push(n[e - 1])
2700                    }
2701                })
2702            },next: function(t, e) {
2703                return d._traverse.call(this, t, e, function(t, e, n) {
2704                    if (e < n.length - 1) {
2705                        return t.push(n[e + 1])
2706                    }
2707                })
2708            },_traverse: function(t, e, i) {
2709                var o, l;
2710                if (t == null) {
2711                    t = "vertical"
2712                }
2713                if (e == null) {
2714                    e = r
2715                }
2716                l = h.aggregate(e);
2717                o = [];
2718                this.each(function() {
2719                    var e;
2720                    e = n.inArray(this, l[t]);
2721                    return i(o, e, l[t])
2722                });
2723                return this.pushStack(o)
2724            },_invoke: function(t) {
2725                this.each(function() {
2726                    var e;
2727                    e = l.getWaypointsByElement(this);
2728                    return n.each(e, function(e, n) {
2729                        n[t]();
2730                        return true
2731                    })
2732                });
2733                return this
2734            }};
2735        n.fn[g] = function() {
2736            var t, r;
2737            r = arguments[0], t = 2 <= arguments.length ? e.call(arguments, 1) : [];
2738            if (d[r]) {
2739                return d[r].apply(this, t)
2740            } else if (n.isFunction(r)) {
2741                return d.init.apply(this, arguments)
2742            } else if (n.isPlainObject(r)) {
2743                return d.init.apply(this, [null, r])
2744            } else if (!r) {
2745                return n.error("jQuery Waypoints needs a callback function or handler option.")
2746            } else {
2747                return n.error("The " + r + " method does not exist in jQuery Waypoints.")
2748            }
2749        };
2750        n.fn[g].defaults = {context: r,continuous: true,enabled: true,horizontal: false,offset: 0,triggerOnce: false};
2751        h = {refresh: function() {
2752                return n.each(c, function(t, e) {
2753                    return e.refresh()
2754                })
2755            },viewportHeight: function() {
2756                var t;
2757                return (t = r.innerHeight) != null ? t : i.height()
2758            },aggregate: function(t) {
2759                var e, r, i;
2760                e = s;
2761                if (t) {
2762                    e = (i = c[n(t)[0][u]]) != null ? i.waypoints : void 0
2763                }
2764                if (!e) {
2765                    return []
2766                }
2767                r = {horizontal: [],vertical: []};
2768                n.each(r, function(t, i) {
2769                    n.each(e[t], function(t, e) {
2770                        return i.push(e)
2771                    });
2772                    i.sort(function(t, e) {
2773                        return t.offset - e.offset
2774                    });
2775                    r[t] = n.map(i, function(t) {
2776                        return t.element
2777                    });
2778                    return r[t] = n.unique(r[t])
2779                });
2780                return r
2781            },above: function(t) {
2782                if (t == null) {
2783                    t = r
2784                }
2785                return h._filter(t, "vertical", function(t, e) {
2786                    return e.offset <= t.oldScroll.y
2787                })
2788            },below: function(t) {
2789                if (t == null) {
2790                    t = r
2791                }
2792                return h._filter(t, "vertical", function(t, e) {
2793                    return e.offset > t.oldScroll.y
2794                })
2795            },left: function(t) {
2796                if (t == null) {
2797                    t = r
2798                }
2799                return h._filter(t, "horizontal", function(t, e) {
2800                    return e.offset <= t.oldScroll.x
2801                })
2802            },right: function(t) {
2803                if (t == null) {
2804                    t = r
2805                }
2806                return h._filter(t, "horizontal", function(t, e) {
2807                    return e.offset > t.oldScroll.x
2808                })
2809            },enable: function() {
2810                return h._invoke("enable")
2811            },disable: function() {
2812                return h._invoke("disable")
2813            },destroy: function() {
2814                return h._invoke("destroy")
2815            },extendFn: function(t, e) {
2816                return d[t] = e
2817            },_invoke: function(t) {
2818                var e;
2819                e = n.extend({}, s.vertical, s.horizontal);
2820                return n.each(e, function(e, n) {
2821                    n[t]();
2822                    return true
2823                })
2824            },_filter: function(t, e, r) {
2825                var i, o;
2826                i = c[n(t)[0][u]];
2827                if (!i) {
2828                    return []
2829                }
2830                o = [];
2831                n.each(i.waypoints[e], function(t, e) {
2832                    if (r(i, e)) {
2833                        return o.push(e)
2834                    }
2835                });
2836                o.sort(function(t, e) {
2837                    return t.offset - e.offset
2838                });
2839                return n.map(o, function(t) {
2840                    return t.element
2841                })
2842            }};
2843        n[m] = function() {
2844            var t, n;
2845            n = arguments[0], t = 2 <= arguments.length ? e.call(arguments, 1) : [];
2846            if (h[n]) {
2847                return h[n].apply(null, t)
2848            } else {
2849                return h.aggregate.call(null, n)
2850            }
2851        };
2852        n[m].settings = {resizeThrottle: 100,scrollThrottle: 30};
2853        return i.on("load.waypoints", function() {
2854            return n[m]("refresh")
2855        })
2856    })
2857}).call(this);
2858
2859// Generated by CoffeeScript 1.6.2
2860/*
2861Sticky Elements Shortcut for jQuery Waypoints - v2.0.5
2862Copyright (c) 2011-2014 Caleb Troughton
2863Licensed under the MIT license.
2864https://github.com/imakewebthings/jquery-waypoints/blob/master/licenses.txt
2865*/
2866(function() {
2867    (function(t, n) {
2868        return n(t.jQuery)
2869    })(window, function(t) {
2870        var n, i;
2871        n = {wrapper: '<div class="sticky-wrapper" />',stuckClass: "stuck",direction: "down right"};
2872        i = function(t, n) {
2873            var i;
2874            t.wrap(n.wrapper);
2875            i = t.parent();
2876            return i.data("isWaypointStickyWrapper", true)
2877        };
2878        t.waypoints("extendFn", "sticky", function(r) {
2879            var e, a, s;
2880            a = t.extend({}, t.fn.waypoint.defaults, n, r);
2881            e = i(this, a);
2882            s = a.handler;
2883            a.handler = function(n) {
2884                var i, r;
2885                i = t(this).children(":first");
2886                r = a.direction.indexOf(n) !== -1;
2887                i.toggleClass(a.stuckClass, r);
2888                e.height(r ? i.outerHeight() : "");
2889                if (s != null) {
2890                    return s.call(this, n)
2891                }
2892            };
2893            e.waypoint(a);
2894            return this.data("stuckClass", a.stuckClass)
2895        });
2896        return t.waypoints("extendFn", "unsticky", function() {
2897            var t;
2898            t = this.parent();
2899            if (!t.data("isWaypointStickyWrapper")) {
2900                return this
2901            }
2902            t.waypoint("destroy");
2903            this.unwrap();
2904            return this.removeClass(this.data("stuckClass"))
2905        })
2906    })
2907}).call(this);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.