_recognizerHandler(e) {
        const changedTouches = e.changedTouches || e.originalEvent.changedTouches;
        this.actives.update(e, changedTouches);

        if (this.getDocumentActives().length() > 2) {
            this.clear();
            return;
        }

        if (e.type === TOUCH_START) {
            if (this.actives.length() <= 2) {
                this.currentATouch = this.actives.first() || null;
                if (this.actives.length() > 1) {
                    this.currentBTouch = this.actives.nth(1) || null;
                }
            } else {
                this.clear();
            }

            if (this.currentATouch !== null && this.currentBTouch === null) {
                this.started = (e.timeStamp || e.originalEvent.timeStamp);
            } else if (this.currentATouch !== null && this.currentBTouch !== null) {
                this.maybeStart(e);
            }
        } else if (e.type === TOUCH_END || e.type === TOUCH_CANCEL) {
            if (this.currentATouch === null || this.currentBTouch === null) {
                this.clear();
                return;
            }

            if (this.actives.length() <= 1 && !this.checkDelta(changedTouches)) {
                return;
            } else if (this.actives.length() > 1 || this.getDocumentActives().length() > 1) {
                this.clear();
                return;
            }

            if (this.actives.length() !== 0) {
                return;
            }

            const elapsed = (e.timeStamp || e.originalEvent.timeStamp) - this.started;
            if (elapsed > 20 && elapsed < TAP_TIME) {
                this.handler.call(e.currentTarget, this.currentATouch, this.currentBTouch);
            }
            this.clear();
        } else if (e.type === TOUCH_MOVE) {
            if (this.getDocumentActives().length() > 2) {
                this.clear();
            }
        }
    }
    _recognizerHandler(e) {
        const changedTouches = e.changedTouches || e.originalEvent.changedTouches;
        this.actives.update(e, changedTouches);

        if (this.getDocumentActives().length() > 1) {
            this.clear();
            return;
        }

        if (e.type === TOUCH_START) {
            this.currentTouch = this.actives.first();
        } else if (e.type === TOUCH_END || e.type === TOUCH_CANCEL) {
            if (this.actives.length() > 0) {
                this.clear();
            } else {
                this.end(e, this.currentTouch);
            }
        } else if (e.type === TOUCH_MOVE) {
            if (!this.actives.contains(this.currentTouch) ||
                this.actives.length() > 1 ||
                this.getDocumentActives().length() > 1) {
                this.clear();
                return;
            }

            const touch = changedTouches[0];
            const yDelta = Math.abs(touch.clientY - this.currentTouch.clientY);
            const xDelta = Math.abs(touch.clientX - this.currentTouch.clientX);

            if (this.committed === UNCOMMITTED) {
                if (yDelta > 10 && yDelta > xDelta) {
                    this.committed = VERTICAL;
                } else if (xDelta > 10 && xDelta > yDelta) {
                    this.committed = HORIZONTAL;
                }

                if (this.committed === this.dimension) {
                    this.currentTouch = touch;
                    this.startHandler.call(e.currentTarget, new GestureObject(e, touch));
                }
            } else if (this.committed === this.dimension) {
                this.currentTouch = touch;
                const g = new GestureObject(e, touch);
                this.moveHandler.call(e.currentTarget, g);
            }
        }
    }
    _recognizerHandler(e) {
        const {changedTouches} = e;
        const now = e.timeStamp;
        this.actives.update(e, changedTouches);

        if (this.getDocumentActives().length() > 2) {
            this.clear();
            return;
        }

        if (e.type === TOUCH_START) {
            if (this.actives.length() === 1) {
                this.currentATouch = this.actives.first();
                this.startAX = this.currentATouch.clientX;
                this.lastAX = this.startAX;
                this.lastAY = this.currentATouch.clientY;
                this.startTime = now;
            } else if (this.actives.length() === 2 && this.currentATouch !== null) {
                this.startTime = now;
                this.currentBTouch = this.actives.nth(1);
                this.startBX = this.currentBTouch.clientX;
                this.lastBX = this.startBX;
                this.lastBY = this.currentBTouch.clientY;
                if (this.lastAX !== -1 &&
                    (Math.abs(this.lastAX - this.lastBX) > 150 &&
                        Math.abs(this.lastAY - this.lastBY) > 150)) {
                    this.clear();
                }
            } else {
                this.clear();
            }
        } else if (e.type === TOUCH_END || e.type === TOUCH_CANCEL) {
            if (this.currentATouch === null || this.currentBTouch === null) return;
            for (let i = 0; i < changedTouches.length; ++i) {
                const touch = changedTouches[i];
                if (touch.identifier === this.currentATouch.identifier) {
                    this.lastAX = touch.clientX;
                } else if (touch.identifier === this.currentBTouch.identifier) {
                    this.lastBX = touch.clientX;
                }
            }
            if (this.actives.length() === 0) {
                this.checkCompletion(now - this.startTime);
            }
        } else if (e.type === TOUCH_MOVE) {
            if (this.getDocumentActives().length() > 2) {
                this.clear();
                return;
            }
            if (this.currentATouch !== null || this.currentBTouch !== null) {

                for (let i = 0; i < changedTouches.length; ++i) {
                    const touch = changedTouches[i];

                    if (this.currentATouch !== null && touch.identifier === this.currentATouch.identifier) {
                        this.lastAX = touch.clientX;
                        this.lastAY = touch.clientY;
                    } else if (this.currentBTouch !== null && touch.identifier === this.currentBTouch.identifier) {
                        this.lastBX = touch.clientX;
                        this.lastBY = touch.clientY;
                    }
                }

                if (this.lastAX !== -1 && this.lastBX !== -1 &&
                    (Math.abs(this.lastAX - this.lastBX) > 150 &&
                     Math.abs(this.lastAY - this.lastBY) > 150)) {
                    this.clear();
                }
            }
        }
    }