text: /**
   * this holds the last move event,
   * used to fix empty touchend issue
   * see the onTouch event for an explanation
   * @type {Object}
   */
  var last_move_event = null;
  
  
  /**
   * when the mouse is hold down, this is true
   * @type {Boolean}
   */
  var enable_detect = false;
  
  
  /**
   * when touch events have been fired, this is true
   * @type {Boolean}
   */
  var touch_triggered = false;
  
  
  Hammer.event = {
    /**
     * simple addEventListener
     * @param   {HTMLElement}   element
     * @param   {String}        type
     * @param   {Function}      handler
     */
    bindDom: function(element, type, handler) {
      var types = type.split(' ');
      Hammer.utils.each(types, function(type){
        element.addEventListener(type, handler, false);
      });
    },
  
  
    /**
     * simple removeEventListener
     * @param   {HTMLElement}   element
     * @param   {String}        type
     * @param   {Function}      handler
     */
    unbindDom: function(element, type, handler) {
      var types = type.split(' ');
      Hammer.utils.each(types, function(type){
        element.removeEventListener(type, handler, false);
      });
    },
  
  
    /**
     * touch events with mouse fallback
     * @param   {HTMLElement}   element
     * @param   {String}        eventType        like Hammer.EVENT_MOVE
     * @param   {Function}      handler
     */
    onTouch: function onTouch(element, eventType, handler) {
      var self = this;
  
      var fn = function bindDomOnTouch(ev) {
        var sourceEventType = ev.type.toLowerCase();
  
        // onmouseup, but when touchend has been fired we do nothing.
        // this is for touchdevices which also fire a mouseup on touchend
        if(sourceEventType.match(/mouse/) && touch_triggered) {
          return;
        }
  
        // mousebutton must be down or a touch event
        else if(sourceEventType.match(/touch/) ||   // touch events are always on screen
          sourceEventType.match(/pointerdown/) || // pointerevents touch
          (sourceEventType.match(/mouse/) && ev.which === 1)   // mouse is pressed
          ) {
          enable_detect = true;
        }
  
        // mouse isn't pressed
        else if(sourceEventType.match(/mouse/) && !ev.which) {
          enable_detect = false;
        }
  
  
        // we are in a touch event, set the touch triggered bool to true,
        // this for the conflicts that may occur on ios and android
        if(sourceEventType.match(/touch|pointer/)) {
          touch_triggered = true;
        }
  
        // count the total touches on the screen
        var count_touches = 0;
  
        // when touch has been triggered in this detection session
        // and we are now handling a mouse event, we stop that to prevent conflicts
        if(enable_detect) {
          // update pointerevent
          if(Hammer.HAS_POINTEREVENTS && eventType != Hammer.EVENT_END) {
            count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);
          }
          // touch
          else if(sourceEventType.match(/touch/)) {
            count_touches = ev.touches.length;
          }
          // mouse
          else if(!touch_triggered) {
            count_touches = sourceEventType.match(/up/) ? 0 : 1;
          }
  
          // if we are in a end event, but when we remove one touch and
          // we still have enough, set eventType to move
          if(count_touches > 0 && eventType == Hammer.EVENT_END) {
            eventType = Hammer.EVENT_MOVE;
          }
          // no touches, force the end event
          else if(!count_touches) {
            eventType = Hammer.EVENT_END;
          }
  
          // store the last move event
          if(count_touches || last_move_event === null) {
            last_move_event = ev;
          }
  
          // trigger the handler
          handler.call(Hammer.detection, self.collectEventData(element, eventType, self.getTouchList(last_move_event, eventType), ev));
  
          // remove pointerevent from list
          if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) {
            count_touches = Hammer.PointerEvent.updatePointer(eventType, ev);
          }
        }
  
        // on the end we reset everything
        if(!count_touches) {
          last_move_event = null;
          enable_detect = false;
          touch_triggered = false;
          Hammer.PointerEvent.reset();
        }
      };
  
      this.bindDom(element, Hammer.EVENT_TYPES[eventType], fn);
  
      // return the bound function to be able to unbind it later
      return fn;
      },
  
  
    /**
     * we have different events for each device/browser
     * determine what we need and set them in the Hammer.EVENT_TYPES constant
     */
    determineEventTypes: function determineEventTypes() {
      // determine the eventtype we want to set
      var types;
  
      // pointerEvents magic
      if(Hammer.HAS_POINTEREVENTS) {
        types = Hammer.PointerEvent.getEvents();
      }
      // on Android, iOS, blackberry, windows mobile we dont want any mouseevents
      else if(Hammer.NO_MOUSEEVENTS) {
        types = [
          'touchstart',
          'touchmove',
          'touchend touchcancel'];
      }
      // for non pointer events browsers and mixed browsers,
      // like chrome on windows8 touch laptop
      else {
        types = [
          'touchstart mousedown',
          'touchmove mousemove',
          'touchend touchcancel mouseup'];
      }
  
      Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0];
      Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1];
      Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2];
    },
  
  
    /**
     * create touchlist depending on the event
     * @param   {Object}    ev
     * @param   {String}    eventType   used by the fakemultitouch plugin
     */
    getTouchList: function getTouchList(ev/*, eventType*/) {
      // get the fake pointerEvent touchlist
      if(Hammer.HAS_POINTEREVENTS) {
        return Hammer.PointerEvent.getTouchList();
      }
      // get the touchlist
      else if(ev.touches) {
        return ev.touches;
      }
      // make fake touchlist from mouse position
      else {
        ev.identifier = 1;
        return [ev];
      }
    },
  
  
    /**
     * collect event data for Hammer js
     * @param   {HTMLElement}   element
     * @param   {String}        eventType        like Hammer.EVENT_MOVE
     * @param   {Object}        eventData
     */
    collectEventData: function collectEventData(element, eventType, touches, ev) {
      // find out pointerType
      var pointerType = Hammer.POINTER_TOUCH;
      if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) {
        pointerType = Hammer.POINTER_MOUSE;
      }
  
      return {
        center     : Hammer.utils.getCenter(touches),
        timeStamp  : new Date().getTime(),
        target     : ev.target,
        touches    : touches,
        eventType  : eventType,
        pointerType: pointerType,
        srcEvent   : ev,
  
        /**
         * prevent the browser default actions
         * mostly used to disable scrolling of the browser
         */
        preventDefault: function() {
          if(this.srcEvent.preventManipulation) {
            this.srcEvent.preventManipulation();
          }
  
          if(this.srcEvent.preventDefault) {
            this.srcEvent.preventDefault();
          }
        },
  
        /**
         * stop bubbling the event up to its parents
         */
        stopPropagation: function() {
          this.srcEvent.stopPropagation();
        },
  
        /**
         * immediately stop gesture detection
         * might be useful after a swipe was detected
         * @return {*}
         */
        stopDetect: function() {
          return Hammer.detection.stopDetect();
        }
      };
    }
  };