PageSourceSearch

https://www.foreverhorsecrazy.com/files/theme/plugins.js

js foreverhorsecrazy.com collected 2026-10-07 11:35:22 UTC 68,187 bytes, 2,471 lines download raw bytes

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

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.