def compute(self, plug, dataBlock):
        """Compute the upper arm's elevation angle as well as the orientation for the first twist joint in the shoulder."""
        if (plug == AM_ShoulderConstraintNode.rotate or plug == AM_ShoulderConstraintNode.angle):
            # ----------------------------------------------------------------
            # Get the incoming data
            # ----------------------------------------------------------------
            # the constrained node's rotateOrder attribute
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.rotateOrder)
            eRotateOrder = dataHandle.asShort()
            # angular offset for the raised orientation
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.raisedAngleOffset)
            dRaisedAngleOffset = dataHandle.asDouble()
            dRaisedAngleOffset = math.radians(dRaisedAngleOffset)
            # axis pointing down the length of the upper arm
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.shoulderAim)
            vShoulderForward = (dataHandle.asVector()).normal()
            # axis pointing to the character's front
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.shoulderFront)
            vShoulderRight = (dataHandle.asVector()).normal()
            # axis pointing to the character's the head
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.spineAim)
            vSpineForward = (dataHandle.asVector()).normal()
            # axis pointing to the character's front
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.spineFront)
            vSpineUp = (dataHandle.asVector()).normal()
            # the rotatePivot attribute of the upper arm
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.shoulderPivot)
            vShoulderPivot = dataHandle.asVector()
            # the rotatePivot attribute of the spine
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.spinePivot)
            vSpinePivot = dataHandle.asVector()
            # the jointOrient attribute (Euler XYZ offset) of the constrained node
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.jointOrient)
            vJointOrient = dataHandle.asVector()
            eJointOrient = OM.MEulerRotation(math.radians(vJointOrient.x), math.radians(vJointOrient.y),
                                             math.radians(vJointOrient.z), 0)
            qJointOrient = eJointOrient.asQuaternion()
            qJointOrient.conjugateIt()
            # the spine's worldMatrix attribute
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.spine)
            mSpine = dataHandle.asMatrix()
            mSpine = OM.MTransformationMatrix(mSpine)
            qSpine = mSpine.rotation()
            # the shoulder's worldMatrix attribute
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.shoulder)
            mShoulder = dataHandle.asMatrix()
            mShoulder = OM.MTransformationMatrix(mShoulder)
            qShoulder = mShoulder.rotation()
            # the constrained node's parentInverseMatrix attribute
            dataHandle = dataBlock.inputValue(AM_ShoulderConstraintNode.parentInverseMatrix)
            mParent = dataHandle.asMatrix()
            mParent = OM.MTransformationMatrix(mParent)
            qParent = mParent.rotation()

            # ----------------------------------------------------------------
            # Orthonormalize provided axes for the shoulder and spine
            # ----------------------------------------------------------------
            vShoulderUp = OM.MVector(vShoulderForward ^ vShoulderRight).normal()
            vShoulderRight = vShoulderUp ^ vShoulderForward
            vSpineRight = OM.MVector(vSpineUp ^ vSpineForward).normal()
            vSpineUp = vSpineForward ^ vSpineRight

            # ----------------------------------------------------------------
            # Determine the side of the body the shoulder is on: right is negative, left is positive
            # (assumes that the shoulder's pivot point will never cross over the spine object's central axis)
            # ----------------------------------------------------------------
            mSpine.addTranslation(-vSpinePivot, OM.MSpace.kObject)
            mShoulder.addTranslation(-vShoulderPivot, OM.MSpace.kObject)
            vSpinePosition = mSpine.getTranslation(OM.MSpace.kWorld)
            vShoulderPosition = mShoulder.getTranslation(OM.MSpace.kWorld)
            dBodySideScalar = cmp((vSpinePosition - vShoulderPosition) * vSpineRight.rotateBy(qSpine), 0.0)

            # ----------------------------------------------------------------
            # Define each of the target up-vectors corresponding to different elevations in spine space
            # ----------------------------------------------------------------
            # target up vector at rest
            vRest = vSpineForward * -dBodySideScalar
            # target up vector when lowered
            vLowered = -(vSpineForward ^ vSpineUp)
            # target up vector when raised
            vRaised = -vSpineRight.rotateBy(OM.MQuaternion(dRaisedAngleOffset, vSpineForward * -dBodySideScalar))

            # ----------------------------------------------------------------
            # Interpolate the target up-vector
            # ----------------------------------------------------------------
            # rotate the spine and shoulder vectors into their respective spaces to get the current elevation angle
            vSpineForwardRotated = vSpineForward.rotateBy(qSpine)
            vShoulderForwardRotated = vShoulderForward.rotateBy(qShoulder)
            dAngle = math.degrees(math.pi - vSpineForwardRotated.angle(vShoulderForwardRotated))

            # interpolate the up-vector based on the shoulder's angle of elevation
            dDot = vSpineForwardRotated * vShoulderForwardRotated
            vTargetUp = OM.MVector()
            if (dDot < 0):
                vTargetUp = vRest + (vLowered - vRest) - -dDot
            else:
                vTargetUp = vRest + (vRaised - vRest) * dDot

            # rotate the target up-vector into world space
            vTargetUp = vTargetUp.rotateBy(qSpine).normal()

            # ----------------------------------------------------------------
            # Compute the local orientation for the constrained node
            # ----------------------------------------------------------------
            # orthonormalize target axes and get target normal orientation for constrained object
            vTargetRight = vTargetUp ^ vShoulderForwardRotated
            vTargetUp = vShoulderForwardRotated ^ vTargetRight
            mList = [vTargetRight.x, vTargetRight.y, vTargetRight.z, 0.0,
                     vTargetUp.x, vTargetUp.y, vTargetUp.z, 0.0,
                     vShoulderForwardRotated.x, vShoulderForwardRotated.y, vShoulderForwardRotated.z, 0.0,
                     0.0, 0.0, 0.0, 1.0]
            mTarget = OM.MMatrix()
            OM.MScriptUtil.createMatrixFromList(mList, mTarget)
            qTarget = OM.MQuaternion(OM.MTransformationMatrix(mTarget).rotation())

            # get offset orientation of the constrained object (from z-forward, y-up)
            mList = [vShoulderRight.x, vShoulderRight.y, vShoulderRight.z, 0.0,
                     vShoulderUp.x, vShoulderUp.y, vShoulderUp.z, 0.0,
                     vShoulderForward.x, vShoulderForward.y, vShoulderForward.z, 0.0,
                     0.0, 0.0, 0.0, 1.0]
            mFromNormal = OM.MMatrix()
            OM.MScriptUtil.createMatrixFromList(mList, mFromNormal)
            qFromNormal = OM.MQuaternion(OM.MTransformationMatrix(mFromNormal).rotation())
            if (qFromNormal.w > 0.0):
                qFromNormal.invertIt()

            # composite final quaternion to get local-space value
            qFinal = OM.MQuaternion(qFromNormal * qTarget * qParent * qJointOrient)

            # output as Euler angles for the constrained node
            eFinal = qFinal.asEulerRotation()
            eFinal.reorderIt(eRotateOrder)

            # ----------------------------------------------------------------
            # Set the outgoing plugs
            # ----------------------------------------------------------------
            outputHandle = dataBlock.outputValue(AM_ShoulderConstraintNode.rotate)
            outputHandle.set3Double(math.degrees(eFinal.x), math.degrees(eFinal.y), math.degrees(eFinal.z))
            outputHandle = dataBlock.outputValue(AM_ShoulderConstraintNode.angle)
            outputHandle.setDouble(dAngle)
            dataBlock.setClean(plug)

        else:
            return OM.kUnknownParameter
dataset/ETHPy150Open CountZer0/PipelineConstructionSet/maya/plugins/2014/win64/AM_ShoulderConstraint.py/AM_ShoulderConstraintNode.compute/operator `*` -> `-`