Python maya.cmds.xform() Examples

The following are 30 code examples of maya.cmds.xform(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module maya.cmds , or try the search function .
Example #1
Source File: shortcuts.py    From cmt with MIT License 7 votes vote down vote up
def vector_to(source=None, target=None):
    """Calculate the distance between two nodes

    :param source: First node
    :param target: Second node
    :return: MVector (API2)
    """
    if source is None or target is None:
        # Default to selection
        selection = cmds.ls(sl=True, type='transform')
        if len(selection) != 2:
            raise RuntimeError('Select 2 transforms.')
        source, target = selection

    pos1 = cmds.xform(source, query=True, worldSpace=True, translation=True)
    pos2 = cmds.xform(target, query=True, worldSpace=True, translation=True)

    source = OpenMaya2.MPoint(pos1[0], pos1[1], pos1[2])
    target = OpenMaya2.MPoint(pos2[0], pos2[1], pos2[2])
    return target - source 
Example #2
Source File: common.py    From cmt with MIT License 6 votes vote down vote up
def place_pole_vector(start, mid, end, pole_vector, offset):
    """Place a pole vector along the plane of the 2 bone ik

    :param start: Start joint
    :param mid: Mid joint
    :param end: End joint
    :param pole_vector: Pole vector transform
    :param offset: Scalar offset from the mid joint
    """
    v1 = OpenMaya.MVector(cmds.xform(start, q=True, ws=True, t=True))
    v2 = OpenMaya.MVector(cmds.xform(mid, q=True, ws=True, t=True))
    v3 = OpenMaya.MVector(cmds.xform(end, q=True, ws=True, t=True))

    e1 = (v3 - v1).normal()
    e2 = v2 - v1
    v = v1 + e1 * (e1 * e2)
    pos = v2 + (v2 - v).normal() * offset
    cmds.xform(pole_vector, ws=True, t=list(pos)) 
Example #3
Source File: shortcuts.py    From cmt with MIT License 6 votes vote down vote up
def distance(node1=None, node2=None):
    """Calculate the distance between two nodes

    :param node1: First node
    :param node2: Second node
    :return: The distance
    """
    if node1 is None or node2 is None:
        # Default to selection
        selection = cmds.ls(sl=True, type='transform')
        if len(selection) != 2:
            raise RuntimeError('Select 2 transforms.')
        node1, node2 = selection

    pos1 = cmds.xform(node1, query=True, worldSpace=True, translation=True)
    pos2 = cmds.xform(node2, query=True, worldSpace=True, translation=True)

    pos1 = OpenMaya.MPoint(pos1[0], pos1[1], pos1[2])
    pos2 = OpenMaya.MPoint(pos2[0], pos2[1], pos2[2])
    return pos1.distanceTo(pos2) 
Example #4
Source File: dpControls.py    From dpAutoRigSystem with GNU General Public License v2.0 6 votes vote down vote up
def shapeSizeSetup(self, transformNode, *args):
        """ Find shapes, create a cluster deformer to all and set the pivot to transform pivot.
            Returns the created cluster.
        """
        clusterHandle = None
        childShapeList = cmds.listRelatives(transformNode, shapes=True, children=True)
    #    print "Child length {0}".format(len(childShapeList))
        if childShapeList:
            thisNamespace = childShapeList[0].split(":")[0]
            cmds.namespace(set=thisNamespace, force=True)
            clusterName = transformNode.split(":")[1]+"_ShapeSizeCH"
            clusterHandle = cmds.cluster(childShapeList, name=clusterName)[1]
            cmds.setAttr(clusterHandle+".visibility", 0)
            cmds.xform(clusterHandle, scalePivot=(0, 0, 0), worldSpace=True)
            cmds.namespace(set=":")
        else:
            print "There are not children shape to create shapeSize setup of:", transformNode
        return clusterHandle 
Example #5
Source File: transform.py    From SISideBar with MIT License 6 votes vote down vote up
def reset_actor():
    from . import sisidebar_sub
    sel = cmds.ls(sl=True, l=True)
    joints = cmds.ls(sl=True, l=True, type='joint')
    if not joints:
        joints = []
    for s in sel:
        if cmds.nodeType(s) == 'KTG_ModelRoot':
            child_joints = cmds.ls(cmds.listRelatives(s, ad=True, f=True), l=True, type='joint')
            if child_joints:
                joints += child_joints
    if not sel:
        joints = cmds.ls(l=True, type='joint')
    for j in joints:
        con_info = cmds.connectionInfo(j+'.bindPose', dfs=True)
        if not con_info:
            continue
        con_info = con_info[0]
        bind_info = con_info.replace('world', 'xform')
        pose = cmds.getAttr(bind_info)
        cmds.xform(j, m=pose)
    sisidebar_sub.get_matrix() 
Example #6
Source File: common.py    From cmt with MIT License 6 votes vote down vote up
def align(node, target, axis, world_up):
    """Align an axis of one node to another using offsetParentMatrix.

    :param node: Node to align
    :param target: Node to align to
    :param axis: Local axis to match
    :param world_up: World up axis
    """
    axis = OpenMaya.MVector(axis)
    world_up = OpenMaya.MVector(world_up)
    tm = OpenMaya.MMatrix(cmds.getAttr("{}.worldMatrix[0]".format(target)))
    world_axis = axis * tm
    world_z = world_axis ^ world_up
    world_up = world_z ^ world_axis
    t = cmds.xform(node, q=True, ws=True, t=True)
    x = list(world_axis) + [0.0]
    y = list(world_up) + [0.0]
    z = list(world_z) + [0.0]
    t = [t[0], t[1], t[2], 1.0]
    m = OpenMaya.MMatrix(*[x + y + z + t])
    parent = cmds.listRelatives(node, parent=True, path=True)
    if parent:
        p = OpenMaya.MMatrix(cmds.getAttr("{}.worldInverseMatrix[0]".format(parent[0])))
        m *= p
    cmds.setAttr("{}.offsetParentMatrix".format(node), list(m), type="matrix") 
Example #7
Source File: orientjoints.py    From cmt with MIT License 6 votes vote down vote up
def create_arrow(jointName):
    curve = cmds.curve(
        name="%s_ForwardDirection" % jointName,
        degree=1,
        point=[
            (-1, 0, 0),
            (-1, 2, 0),
            (-2, 2, 0),
            (0, 4, 0),
            (2, 2, 0),
            (1, 2, 0),
            (1, 0, 0),
            (-1, 0, 0),
        ],
    )
    group = cmds.group()
    cmds.xform(objectSpace=True, pivots=(0, 0, 0))
    jointScale = cmds.jointDisplayScale(query=True)
    jointRadius = cmds.getAttr("%s.radius" % jointName)
    jointScale *= jointRadius
    cmds.xform(scale=(jointScale, jointScale, jointScale))

    return group 
Example #8
Source File: mayaSphere3.py    From tutorials with MIT License 5 votes vote down vote up
def getScale(self):
        return cmds.xform(self.name, query=True, scale=True) 
Example #9
Source File: BlendTransforms.py    From BlendTransforms with The Unlicense 5 votes vote down vote up
def BT_Setup(set = None):
    
    if not set:
        return False

    transforms = cmds.listConnections(set +'.dagSetMembers')
    if not transforms:
        return False

    if not cmds.attributeQuery('Blend_Node', n = set, ex = True):
        cmds.addAttr(set, ln = 'Blend_Node', k = False, h = True, dt = 'string')
    else:
        return False

    btNode = cmds.createNode("BlendTransforms")
    cmds.setAttr(set +'.Blend_Node', btNode, type = "string")

    for i in range(0, len(transforms)):
        baseMatrix = cmds.xform(transforms[i], q = True, m = True)
        baseScale = cmds.getAttr(transforms[i] +'.scale')[0]
        baseRotOffset = [0.0, 0.0, 0.0]

        if cmds.objectType(transforms[i], isType = 'joint'):
            baseRotOffset = cmds.getAttr(transforms[i] +'.jointOrient')[0]

        btAttr = 'transforms[' +str(i) +'].baseMatrix'
        btScaleAttr = 'transforms[' +str(i) +'].baseScale'
        btRotOffsetAttr = 'transforms[' +str(i) +'].baseRotOffset'

        BT_MatrixValuesToNode(values = baseMatrix, node = btNode, attr = btAttr)
        BT_Double3ValuesToNode(values = baseScale, node = btNode, attr = btScaleAttr)
        BT_Double3ValuesToNode(values = baseRotOffset, node = btNode, attr = btRotOffsetAttr)
        BT_ConnectOutputs(index = i, node = btNode, transform = transforms[i])

    return True 
Example #10
Source File: dm2skin.py    From dm2skin with The Unlicense 5 votes vote down vote up
def dm2skin_getVertexPositionsOverRange(mesh, startFrame=0, endFrame=1):
    """Gets a list of lists of vertex positions for the given mesh. One list for
    each frame between startFrame and endFrame."""
    numVerts = cmds.polyEvaluate(mesh, v=True)
    resultList = []
    for i in range(startFrame, endFrame + 1):
        tempList = []
        cmds.currentTime(i)
        for j in range(0, numVerts):
            tempPos = cmds.xform(mesh + '.vtx[' + str(j) + ']', q=True, ws=True, t=True)
            tempList.append(np.array([tempPos[0], tempPos[1], tempPos[2]]))
        resultList.append(tempList)
    return resultList 
Example #11
Source File: dm2skin.py    From dm2skin with The Unlicense 5 votes vote down vote up
def dm2skin_getVertexLocationList(mesh, frame=0):
    """Gets a list of vertex locations on the given frame."""
    numVerts = cmds.polyEvaluate(mesh, v=True)
    resultList = []
    cmds.currentTime(frame)
    for v in range(0, numVerts):
        pos = cmds.xform(mesh + '.vtx[' + str(v) + ']', q=True, ws=True, t=True)
        resultList.append(np.array([pos[0], pos[1], pos[2], 1.0]))
    return resultList 
Example #12
Source File: dm2skin.py    From dm2skin with The Unlicense 5 votes vote down vote up
def dm2skin_getNeighbouringJoints(joint, vertexString=None, cluster=None, influences=3):
    """This gets a list of nearby joints in the skin cluster to joint up to
    the number of influences. These will be the ones we use in our minimization
    later"""

    if not cmds.objExists(joint):
        return False
    if influences < 3:
        return False
    if not cluster:
        return False

    clusterJoints = cmds.skinCluster(cluster, q=True, inf=True)

    pos1 = cmds.xform(vertexString, q=True, ws=True, t=True)

    parentJoint = cmds.listRelatives(joint, parent=True)

    subtract = 1
    # add the main joint
    resultList = [joint]
    # i've found it works best to always include the parent
    if parentJoint and parentJoint in clusterJoints:
        resultList.insert(0, parentJoint[0])
        subtract = 2

    # for the rest of the available influences get a list of nearby joints in space
    measureList = []
    for measureJnt in clusterJoints:
        if measureJnt not in resultList:
            jntPos2 = cmds.xform(measureJnt, q=True, ws=True, t=True)
            #this just gets the length of the vector between the two joints
            dist = math.sqrt(reduce(lambda x, y: x + y, [math.pow(jntPos2[i] - pos1[i], 2) for i in range(len(pos1))]))
            measureList.append((measureJnt, dist))

    # sort the list in ascending order so we get the closest joints first
    measureList.sort(key=lambda dist: dist[1])
    ascendingList = [entry[0] for entry in measureList[0:influences - subtract]]
    return resultList + ascendingList 
Example #13
Source File: test_Bindings.py    From mGui with MIT License 5 votes vote down vote up
def test_cmds_accessor_get(self):
        cmds.file(new=True, f=True)
        test_obj, _ = cmds.polyCube()
        cmds.xform(test_obj, rotation=(10, 10, 10))
        ac = bindings.CmdsAccessor(test_obj, 'r')
        assert ac.pull() == [(10, 10, 10)] 
Example #14
Source File: mayaSphere4.py    From tutorials with MIT License 5 votes vote down vote up
def getRotation(self):
        return cmds.xform(self.name, query=True, rotation=True) 
Example #15
Source File: mayaSphere4.py    From tutorials with MIT License 5 votes vote down vote up
def getScale(self):
        return cmds.xform(self.name, query=True, scale=True) 
Example #16
Source File: mayaGeom.py    From tutorials with MIT License 5 votes vote down vote up
def getTranslation(self):
        return cmds.xform(self.name, query=True, translation=True) 
Example #17
Source File: mayaSphere3.py    From tutorials with MIT License 5 votes vote down vote up
def getRotation(self):
        return cmds.xform(self.name, query=True, rotation=True) 
Example #18
Source File: BlendTransforms.py    From BlendTransforms with The Unlicense 5 votes vote down vote up
def BT_Setup(set = None):
    
    if not set:
        return False

    transforms = cmds.listConnections(set +'.dagSetMembers')
    if not transforms:
        return False

    if not cmds.attributeQuery('Blend_Node', n = set, ex = True):
        cmds.addAttr(set, ln = 'Blend_Node', k = False, h = True, dt = 'string')
    else:
        return False

    btNode = cmds.createNode("BlendTransforms")
    cmds.setAttr(set +'.Blend_Node', btNode, type = "string")

    for i in range(0, len(transforms)):
        baseMatrix = cmds.xform(transforms[i], q = True, m = True)
        baseScale = cmds.getAttr(transforms[i] +'.scale')[0]
        baseRotOffset = [0.0, 0.0, 0.0]

        if cmds.objectType(transforms[i], isType = 'joint'):
            baseRotOffset = cmds.getAttr(transforms[i] +'.jointOrient')[0]

        btAttr = 'transforms[' +str(i) +'].baseMatrix'
        btScaleAttr = 'transforms[' +str(i) +'].baseScale'
        btRotOffsetAttr = 'transforms[' +str(i) +'].baseRotOffset'

        BT_MatrixValuesToNode(values = baseMatrix, node = btNode, attr = btAttr)
        BT_Double3ValuesToNode(values = baseScale, node = btNode, attr = btScaleAttr)
        BT_Double3ValuesToNode(values = baseRotOffset, node = btNode, attr = btRotOffsetAttr)
        BT_ConnectOutputs(index = i, node = btNode, transform = transforms[i])

    return True 
Example #19
Source File: math.py    From video2mocap with MIT License 5 votes vote down vote up
def distance_between(node1, node2):
    """
    Get the distance between two transform nodes in world space.

    :param str node1:
    :param str node2:
    :return: Distance between
    :rtype: float
    """
    point1 = OpenMaya.MVector(cmds.xform(node1, q=True, ws=True, t=True))
    point2 = OpenMaya.MVector(cmds.xform(node2, q=True, ws=True, t=True))

    return (point1 - point2).length() 
Example #20
Source File: skeleton.py    From video2mocap with MIT License 5 votes vote down vote up
def position_skeleton(skeleton_data, gen):
    """
    Position the skeleton using the data that is stored in the Skeleton
    Generator node. The joint ids are sorted and looped to make sure the
    positions get set in the correct order. Unfortunately this is not correct
    and the head is processed before the neck. This means this function will
    have to be ran twice to ensure the currect stance position of the
    skeleton.

    :param dict skeleton_data:
    :param str gen:
    """
    for _id in sorted(HIK_ID_MAPPER.keys()):
        attribute = HIK_ID_MAPPER.get(_id)
        joint = skeleton_data.get(HIK_MAPPER.get(attribute))

        # position joint
        translate = cmds.getAttr("{}.{}T".format(gen, attribute))[0]
        rotate = cmds.getAttr("{}.{}R".format(gen, attribute))[0]
        scale = cmds.getAttr("{}.{}S".format(gen, attribute))[0]

        cmds.xform(
            joint,
            worldSpace=True,
            translation=translate,
            rotation=rotate,
            scale=scale
        ) 
Example #21
Source File: common.py    From cmt with MIT License 5 votes vote down vote up
def snap_to_orientation(node, snap_to):
    r = cmds.xform(snap_to, q=True, ws=True, ro=True)
    cmds.xform(node, ws=True, ro=r) 
Example #22
Source File: common.py    From cmt with MIT License 5 votes vote down vote up
def snap_to_position(node, snap_to):
    pos = cmds.xform(snap_to, q=True, ws=True, t=True)
    cmds.xform(node, ws=True, t=pos) 
Example #23
Source File: spaceswitch.py    From cmt with MIT License 5 votes vote down vote up
def switch_space(node, attribute, space, create_keys=False):
    """Seamlessly switch between spaces

    :param node: Node to switch
    :param attribute: Space switching attribute on node
    :param space: Space index in the space attribute
    :param create_keys: True to create switching keys
    """
    m = cmds.xform(node, q=True, ws=True, m=True)
    cmds.setAttr("{}.{}".format(node, attribute), space)
    cmds.xform(node, ws=True, m=m) 
Example #24
Source File: orientjoints.py    From cmt with MIT License 5 votes vote down vote up
def create_orient_manipulator(joint, material):
    joint_scale = cmds.jointDisplayScale(query=True)
    joint_radius = cmds.getAttr("{0}.radius".format(joint))
    radius = joint_scale * joint_radius
    children = cmds.listRelatives(joint, children=True, path=True)
    if children:
        p1 = cmds.xform(joint, q=True, ws=True, t=True)
        p1 = OpenMaya.MPoint(*p1)
        p2 = cmds.xform(children[0], q=True, ws=True, t=True)
        p2 = OpenMaya.MPoint(*p2)
        radius = p1.distanceTo(p2)
    arrow_cvs = [
        [-1, 0, 0],
        [-1, 2, 0],
        [-2, 2, 0],
        [0, 4, 0],
        [2, 2, 0],
        [1, 2, 0],
        [1, 0, 0],
        [-1, 0, 0],
    ]
    arrow_cvs = [[x[0] * radius, x[1] * radius, x[2] * radius] for x in arrow_cvs]
    shape = cmds.curve(name="{0}_zForward".format(joint), degree=1, point=arrow_cvs)
    # shape = cmds.sphere(n='{0}_zForward'.format(joint), p=(0, 0, 0), ax=(0, 0, -1), ssw=0, esw=180, r=radius, d=3, ut=0, tol=0.01, s=8, nsp=4, ch=0)[0]
    # cmds.setAttr('{0}.sz'.format(shape), 0)
    # cmds.select(shape)
    # cmds.hyperShade(assign=material)
    group = cmds.createNode("transform", name="{0}_grp".format(shape))
    cmds.parent(shape, group)
    cmds.makeIdentity(shape, apply=True)
    cmds.addAttr(shape, longName=MESSAGE_ATTRIBUTE, attributeType="message")
    cmds.connectAttr(
        "{0}.message".format(joint), "{0}.{1}".format(shape, MESSAGE_ATTRIBUTE)
    )
    for attr in ["tx", "ty", "tz", "ry", "rz", "v"]:
        cmds.setAttr("{0}.{1}".format(shape, attr), lock=True, keyable=False)
    return group, shape 
Example #25
Source File: orientjoints.py    From cmt with MIT License 5 votes vote down vote up
def get_position(node):
    p = cmds.xform(node, q=True, ws=True, t=True)
    return OpenMaya.MPoint(p) 
Example #26
Source File: BlendTransforms.py    From BlendTransforms with The Unlicense 5 votes vote down vote up
def BT_Setup(set = None):
    
    if not set:
        return False

    transforms = cmds.listConnections(set +'.dagSetMembers')
    if not transforms:
        return False

    if not cmds.attributeQuery('Blend_Node', n = set, ex = True):
        cmds.addAttr(set, ln = 'Blend_Node', k = False, h = True, dt = 'string')
    else:
        return False

    btNode = cmds.createNode("BlendTransforms")
    cmds.setAttr(set +'.Blend_Node', btNode, type = "string")

    for i in range(0, len(transforms)):
        baseMatrix = cmds.xform(transforms[i], q = True, m = True)
        baseScale = cmds.getAttr(transforms[i] +'.scale')[0]
        baseRotOffset = [0.0, 0.0, 0.0]

        if cmds.objectType(transforms[i], isType = 'joint'):
            baseRotOffset = cmds.getAttr(transforms[i] +'.jointOrient')[0]

        btAttr = 'transforms[' +str(i) +'].baseMatrix'
        btScaleAttr = 'transforms[' +str(i) +'].baseScale'
        btRotOffsetAttr = 'transforms[' +str(i) +'].baseRotOffset'

        BT_MatrixValuesToNode(values = baseMatrix, node = btNode, attr = btAttr)
        BT_Double3ValuesToNode(values = baseScale, node = btNode, attr = btScaleAttr)
        BT_Double3ValuesToNode(values = baseRotOffset, node = btNode, attr = btRotOffsetAttr)
        BT_ConnectOutputs(index = i, node = btNode, transform = transforms[i])

    return True 
Example #27
Source File: control.py    From cmt with MIT License 5 votes vote down vote up
def rotate_components(rx, ry, rz, nodes=None):
    """Rotate the given nodes' components the given number of degrees about each axis.

    :param rx: Degrees around x.
    :param ry: Degrees around y.
    :param rz: Degrees around z.
    :param nodes: Optional list of curves.
    """
    if nodes is None:
        nodes = cmds.ls(sl=True) or []
    for node in nodes:
        pivot = cmds.xform(node, q=True, rp=True, ws=True)
        cmds.rotate(
            rx, ry, rz, "{0}.cv[*]".format(node), r=True, p=pivot, os=True, fo=True
        ) 
Example #28
Source File: BlendTransforms.py    From BlendTransforms with The Unlicense 5 votes vote down vote up
def BT_Setup(set = None):
    
    if not set:
        return False

    transforms = cmds.listConnections(set +'.dagSetMembers')
    if not transforms:
        return False

    if not cmds.attributeQuery('Blend_Node', n = set, ex = True):
        cmds.addAttr(set, ln = 'Blend_Node', k = False, h = True, dt = 'string')
    else:
        return False

    btNode = cmds.createNode("BlendTransforms")
    cmds.setAttr(set +'.Blend_Node', btNode, type = "string")

    for i in range(0, len(transforms)):
        baseMatrix = cmds.xform(transforms[i], q = True, m = True)
        baseScale = cmds.getAttr(transforms[i] +'.scale')[0]
        baseRotOffset = [0.0, 0.0, 0.0]

        if cmds.objectType(transforms[i], isType = 'joint'):
            baseRotOffset = cmds.getAttr(transforms[i] +'.jointOrient')[0]

        btAttr = 'transforms[' +str(i) +'].baseMatrix'
        btScaleAttr = 'transforms[' +str(i) +'].baseScale'
        btRotOffsetAttr = 'transforms[' +str(i) +'].baseRotOffset'

        BT_MatrixValuesToNode(values = baseMatrix, node = btNode, attr = btAttr)
        BT_Double3ValuesToNode(values = baseScale, node = btNode, attr = btScaleAttr)
        BT_Double3ValuesToNode(values = baseRotOffset, node = btNode, attr = btRotOffsetAttr)
        BT_ConnectOutputs(index = i, node = btNode, transform = transforms[i])

    return True 
Example #29
Source File: ml_softWeights.py    From ml_tools with MIT License 5 votes vote down vote up
def softSelectionClusterWeights(*args):

    sel = mc.ls(sl=True, o=True)

    if not sel:
        raise RuntimeError('Please select some vertices.')

    weights = getSoftSelectionWeights()

    if not weights:
        raise RuntimeError('Please select some vertices.')

    #get manipulator position for pivot
    mc.setToolTo('Move')
    moveMode = mc.manipMoveContext('Move', query=True, mode=True)
    mc.manipMoveContext('Move', edit=True, mode=0)
    position = mc.manipMoveContext('Move', query=True, position=True)
    mc.manipMoveContext('Move', edit=True, mode=moveMode)

    clusterNode, clusterHandle = mc.cluster(sel[0])

    for vert in mc.ls(sel[0]+'.vtx[*]', fl=True, l=True):
        weight = 0.0
        if vert in weights.keys():
            weight = weights[vert]
        mc.percent(clusterNode, vert, v=weight)

    #set cluster pivot
    mc.xform(clusterHandle, a=True, ws=True, piv=(position[0], position[1], position[2]))
    clusterShape = mc.listRelatives(clusterHandle, c=True, s=True)
    mc.setAttr(clusterShape[0] + '.origin', position[0], position[1], position[2]) 
Example #30
Source File: sqStickyLipsSetup.py    From dpAutoRigSystem with GNU General Public License v2.0 5 votes vote down vote up
def sqCheckCurveDirection(self, thisCurve, *args):
        posMinX = cmds.xform(thisCurve+".cv[0]", query=True, worldSpace=True, translation=True)[0]
        posMaxX = cmds.xform(thisCurve+".cv["+str(self.curveLenght-1)+"]", query=True, worldSpace=True, translation=True)[0]
        if posMinX > posMaxX:
            cmds.reverseCurve(thisCurve, constructionHistory=False, replaceOriginal=True)