protected virtual void UpdateGesture(T gesture, FingerGestures.IFingerList touches)
    {
        if (gesture.State == GestureRecognitionState.Ready)
        {
            return;
        }

        if (gesture.State == GestureRecognitionState.Started)
        {
            gesture.State = GestureRecognitionState.InProgress;
        }

        switch (gesture.State)
        {
        case GestureRecognitionState.InProgress:
        {
            GestureRecognitionState newState = OnRecognize(gesture, touches);

            if (newState == GestureRecognitionState.FailAndRetry)
            {
                // special case for MultiTap when the Nth tap in the sequence is performed out of the tolerance radius,
                //  fail the gesture and immeditaly reattempt a Begin() on it using current touch data

                // this will trigger the fail event
                gesture.State = GestureRecognitionState.Failed;

                // save the clusterId we're currently assigned to (reset will clear it)
                int clusterId = gesture.ClusterId;

                // reset gesture state
                Reset(gesture);

                // attempt to restart recognition right away with current touch data
                if (CanBegin(gesture, touches))
                {
                    Begin(gesture, clusterId, touches);
                }
            }
            else
            {
                if (newState == GestureRecognitionState.InProgress)
                {
                    gesture.PickSelection(Raycaster);
                }

                gesture.State = newState;
            }
        }
        break;

        case GestureRecognitionState.Recognized:     // Ended
        case GestureRecognitionState.Failed:
        {
            // release the fingers right away so another recognizer can use them, even though this one isn't reset yet
            if (gesture.PreviousState != gesture.State)          // only do this the first time we enter this state
            {
                ReleaseFingers(gesture);
            }

            // check if we should reset the gesture now
            if (ResetMode == GestureResetMode.NextFrame || (ResetMode == GestureResetMode.EndOfTouchSequence && touches.Count == 0))
            {
                Reset(gesture);
            }
        }
        break;

        default:
            Debug.LogError(this + " - Unhandled state: " + gesture.State + ". Failing gesture.");
            gesture.State = GestureRecognitionState.Failed;
            break;
        }
    }
    protected virtual void UpdateGesture(T gesture, TouchManager.IFingerList touches)
    {
        if (gesture.State == GestureRecognitionState.Ready)
        {
            return;
        }
        if (gesture.State == GestureRecognitionState.Started)
        {
            gesture.State = GestureRecognitionState.InProgress;
        }

        switch (gesture.State)
        {
        case GestureRecognitionState.InProgress:
        {
            GestureRecognitionState newState = OnRecognize(gesture, touches);
            if (newState == GestureRecognitionState.FailAndRetry)
            {
                gesture.State = GestureRecognitionState.Failed;
                int clusterId = gesture.ClusterId;
                Reset(gesture);
                if (CanBegin(gesture, touches))
                {
                    Begin(gesture, clusterId, touches);
                }
            }
            else
            {
                gesture.State = newState;
            }
        }
        break;

        case GestureRecognitionState.Recognized:
        case GestureRecognitionState.Failed:
        {
            if (ResetMode == GestureResetMode.NextFrame || (ResetMode == GestureResetMode.EndOfTouchSequence && touches.Count == 0))
            {
                if ("OnEasyGesture" == gesture.Recognizer.EventMessageName)
                {
                    if (GestureRecognitionState.Failed == gesture.State)
                    {
                        gesture.HintFlag = HintType.RFailure;
                        RaiseHintEvent(gesture);
                    }
                    else
                    {
                        if (SkillCategory.kNone != gesture.SkillTags)
                        {
                            gesture.HintFlag = HintType.RSucceed;
                            RaiseHintEvent(gesture);
                        }
                    }
                }

                if (touches.Count == 0)
                {
                    Reset(gesture, false);
                    Refresh(gesture);
                }
                else
                {
                    Reset(gesture, true);
                }
            }
        }
        break;

        default:
            Debug.LogError("UpdateGesture Failing");
            gesture.State = GestureRecognitionState.Failed;
            break;
        }
    }