docs: function(e, timeStamp) {
      if (timeStamp instanceof Date) {
        timeStamp = timeStamp.valueOf();
      }
      if (typeof timeStamp !== "number") {
        timeStamp = Date.now();
      }
  
      var self = this;
  
      // Ignore event when tracking is not enabled (no touchstart event on element)
      // This is required as this listener ('touchmove') sits on the document and not on the element itself.
      if (!self.__isTracking) {
        return;
      }
  
      // Not touching anymore (when two finger hit the screen there are two touch end events)
      self.__isTracking = false;
  
      // Be sure to reset the dragging flag now. Here we also detect whether
      // the finger has moved fast enough to switch into a deceleration animation.
      if (self.__isDragging) {
  
        // Reset dragging flag
        self.__isDragging = false;
  
        // Start deceleration
        // Verify that the last move detected was in some relevant time frame
        if (self.__isSingleTouch && self.options.animating && (timeStamp - self.__lastTouchMove) <= 100) {
  
          // Then figure out what the scroll position was about 100ms ago
          var positions = self.__positions;
          var endPos = positions.length - 1;
          var startPos = endPos;
  
          // Move pointer to position measured 100ms ago
          for (var i = endPos; i > 0 && positions[i] > (self.__lastTouchMove - 100); i -= 3) {
            startPos = i;
          }
  
          // If start and stop position is identical in a 100ms timeframe,
          // we cannot compute any useful deceleration.
          if (startPos !== endPos) {
  
            // Compute relative movement between these two points
            var timeOffset = positions[endPos] - positions[startPos];
            var movedLeft = self.__scrollLeft - positions[startPos - 2];
            var movedTop = self.__scrollTop - positions[startPos - 1];
  
            // Based on 50ms compute the movement to apply for each render step
            self.__decelerationVelocityX = movedLeft / timeOffset * (1000 / 60);
            self.__decelerationVelocityY = movedTop / timeOffset * (1000 / 60);
  
            // How much velocity is required to start the deceleration
            var minVelocityToStartDeceleration = self.options.paging || self.options.snapping ? self.options.decelVelocityThresholdPaging : self.options.decelVelocityThreshold;
  
            // Verify that we have enough velocity to start deceleration
            if (Math.abs(self.__decelerationVelocityX) > minVelocityToStartDeceleration || Math.abs(self.__decelerationVelocityY) > minVelocityToStartDeceleration) {
  
              // Deactivate pull-to-refresh when decelerating
              if (!self.__refreshActive) {
                self.__startDeceleration(timeStamp);
              }
            }
          } else {
            self.__scrollingComplete();
          }
        } else if ((timeStamp - self.__lastTouchMove) > 100) {
          self.__scrollingComplete();
        }
  
      } else if (self.__decStopped) {
        // the deceleration was stopped
        // user flicked the scroll fast, and stop dragging, then did a touchstart to stop the srolling
        // tell the touchend event code to do nothing, we don't want to actually send a click
        e.isTapHandled = true;
        self.__decStopped = false;
      }
  
      // If this was a slower move it is per default non decelerated, but this
      // still means that we want snap back to the bounds which is done here.
      // This is placed outside the condition above to improve edge case stability
      // e.g. touchend fired without enabled dragging. This should normally do not
      // have modified the scroll positions or even showed the scrollbars though.
      if (!self.__isDecelerating) {
  
        if (self.__refreshActive && self.__refreshStart) {
  
          // Use publish instead of scrollTo to allow scrolling to out of boundary position
          // We don't need to normalize scrollLeft, zoomLevel, etc. here because we only y-scrolling when pull-to-refresh is enabled
          self.__publish(self.__scrollLeft, -self.__refreshHeight, self.__zoomLevel, true);
  
          var d = new Date();
          self.refreshStartTime = d.getTime();
  
          if (self.__refreshStart) {
            self.__refreshStart();
          }
          // for iOS-ey style scrolling
          if (!ionic.Platform.isAndroid())self.__startDeceleration();
        } else {
  
          if (self.__interruptedAnimation || self.__isDragging) {
            self.__scrollingComplete();
          }
          self.scrollTo(self.__scrollLeft, self.__scrollTop, true, self.__zoomLevel);
  
          // Directly signalize deactivation (nothing todo on refresh?)
          if (self.__refreshActive) {
  
            self.__refreshActive = false;
            if (self.__refreshDeactivate) {
              self.__refreshDeactivate();
            }
  
          }
        }
      }
  
      // Fully cleanup list
      self.__positions.length = 0;
  
    }