//
    //  Initialization
    //

    void Awake()
    {
        if (!avatar)
        {
            avatar = gameObject;
        }

        animator = avatar.GetComponent <Animator>();

        // Get animator state machine behaviors (allows us to get animator events)
        AvatarGestureStateBehavior[] behaviors = animator.GetBehaviours <AvatarGestureStateBehavior>();
        foreach (var behavior in behaviors)
        {
            if (behavior.layerName == ANIM_RARM_LAYERNAME)
            {
                rarmStateBehavior = behavior;
            }
            else if (behavior.layerName == ANIM_LARM_LAYERNAME)
            {
                larmStateBehavior = behavior;
            }
            else if (behavior.layerName == ANIM_HEAD_LAYERNAME)
            {
                headStateBehavior = behavior;
            }
        }

        Debug.Assert(rarmStateBehavior != null && larmStateBehavior != null);

        // Attach event handlers to state machine behavior
        rarmStateBehavior.AnimationStart += StateMachineBehavior_AnimationStart;
        rarmStateBehavior.AnimationEnd   += StateMachineBehavior_AnimationEnd;

        larmStateBehavior.AnimationStart += StateMachineBehavior_AnimationStart;
        larmStateBehavior.AnimationEnd   += StateMachineBehavior_AnimationEnd;

        headStateBehavior.AnimationStart += StateMachineBehavior_AnimationStart;
        headStateBehavior.AnimationEnd   += StateMachineBehavior_AnimationEnd;

        // Default to RArm
        currentStateBehavior =
            rarmStateBehavior;             // TODO -- could elect to dynamically subscribe/unsubscribe to behaviors as needed instead of checking them each time
    }
    /// <summary>
    /// Makes the avatar perform the specified gesture.
    /// </summary>
    /// <param name="gesture">A predefined AvatarGesture.</param>
    /// <param name="callback">Function to call when the gesture completes</param>
    public void PerformGesture(AvatarGesture gesture, Action <AvatarGesture> callback = null)
    {
        if (gesture == null)
        {
            Debug.LogError("No gesture specified!");
            return;
        }

        //////////////////////////////////////////////
        // Get trigger names based on handedness

        string anim_gestureid_name;
        string anim_trigger_name;

        if (gesture.BodyPart == AvatarGesture.Body.LeftArm)
        {
            anim_gestureid_name = ANIM_LARM_GESTUREID;
            anim_trigger_name   = ANIM_LARM_TRIGGER;

            currentStateBehavior = larmStateBehavior;
        }
        else if (gesture.BodyPart == AvatarGesture.Body.RightArm)
        {
            anim_gestureid_name = ANIM_RARM_GESTUREID;
            anim_trigger_name   = ANIM_RARM_TRIGGER;

            currentStateBehavior = rarmStateBehavior;
        }
        else
        {
            anim_gestureid_name = ANIM_HEAD_GESTUREID;
            anim_trigger_name   = ANIM_HEAD_TRIGGER;

            currentStateBehavior = headStateBehavior;
        }

        //////////////////////////////////////////////
        // Trigger the gesture

        animator.SetInteger(anim_gestureid_name, gesture.Id);
        animator.SetTrigger(anim_trigger_name);

        CurrentGesture = gesture;

        //////////////////////////////////////////////
        // Callback upon completion

        if (callback != null)
        {
            // Cache currentStateBehavior
            AvatarGestureStateBehavior behavior = currentStateBehavior;

            // Create a one-shot event handler that calls the callback function
            AvatarGestureStateBehavior.StateMachineEventHandler eventHandler = null;
            eventHandler = delegate(object sender) {
                behavior.AnimationEnd -= eventHandler;                 // Unsubscribe; one-shot
                callback(gesture);
            };
            behavior.AnimationEnd += eventHandler;             // Subscribe
        }
    }