def add_sine_attributes(obj, sine_prefix='sine', tick_source_attr='time1.outTime', hide_unkeyable=True, add_absolute_output=False, nice_name_prefix=True):
    ' \n    Create Sine function without using third-party plugins or expressions\n    \n            Parameters:\n                obj (string): Name of the object\n                sine (string): Prefix given to the name of the attributes (default is "sine")\n                tick_source_attr (string): Name of the attribute used as the source for time. It uses the default "time1" node if nothing else is specified\n                hide_unkeyable (bool): Hides the tick and output attributes\n                add_absolute_output (bool): Also creates an output version that gives only positive numbers much like the abs() expression\n\n            Returns:\n                sine_output_attrs (list): A string with the name of the object and the name of the sine output attribute. E.g. "pSphere1.sineOutput"\n                                          In case an absolute output is added, it will be the second object in the list. E.g. ["pSphere1.sineOutput", "pSphere1.sineAbsOutput"]\n                                          If add_absolute_output is False the second attribute is None\n    '
    required_plugin = 'quatNodes'
    if (not cmds.pluginInfo(required_plugin, q=True, loaded=True)):
        cmds.loadPlugin(required_plugin, qt=False)
    influence_suffix = 'Time'
    amplitude_suffix = 'Amplitude'
    frequency_suffix = 'Frequency'
    offset_suffix = 'Offset'
    output_suffix = 'Output'
    tick_suffix = 'Tick'
    abs_suffix = 'AbsOutput'
    influence_attr = (sine_prefix + influence_suffix)
    amplitude_attr = (sine_prefix + amplitude_suffix)
    frequency_attr = (sine_prefix + frequency_suffix)
    offset_attr = (sine_prefix + offset_suffix)
    output_attr = (sine_prefix + output_suffix)
    tick_attr = (sine_prefix + tick_suffix)
    abs_attr = (sine_prefix + abs_suffix)
    mdl_node = cmds.createNode('multDoubleLinear', name=(obj + '_multDoubleLiner'))
    quat_node = cmds.createNode('eulerToQuat', name=(obj + '_eulerToQuat'))
    multiply_node = cmds.createNode('multiplyDivide', name=(obj + '_amplitude_multiply'))
    sum_node = cmds.createNode('plusMinusAverage', name=(obj + '_offset_sum'))
    influence_multiply_node = cmds.createNode('multiplyDivide', name=(obj + '_influence_multiply'))
    if nice_name_prefix:
        cmds.addAttr(obj, ln=influence_attr, at='double', k=True, maxValue=1, minValue=0)
        cmds.addAttr(obj, ln=amplitude_attr, at='double', k=True)
        cmds.addAttr(obj, ln=frequency_attr, at='double', k=True)
        cmds.addAttr(obj, ln=offset_attr, at='double', k=True)
        cmds.addAttr(obj, ln=tick_attr, at='double', k=True)
        cmds.addAttr(obj, ln=output_attr, at='double', k=True)
        if add_absolute_output:
            cmds.addAttr(obj, ln=abs_attr, at='double', k=True)
    else:
        cmds.addAttr(obj, ln=influence_attr, at='double', k=True, maxValue=1, minValue=0, nn=influence_suffix)
        cmds.addAttr(obj, ln=amplitude_attr, at='double', k=True, nn=amplitude_suffix)
        cmds.addAttr(obj, ln=frequency_attr, at='double', k=True, nn=frequency_suffix)
        cmds.addAttr(obj, ln=offset_attr, at='double', k=True, nn=offset_suffix)
        cmds.addAttr(obj, ln=tick_attr, at='double', k=True, nn=tick_suffix)
        cmds.addAttr(obj, ln=output_attr, at='double', k=True, nn=output_suffix)
        if add_absolute_output:
            cmds.addAttr(obj, ln=abs_attr, at='double', k=True, nn=re.sub('(\\w)([A-Z])', '\\1 \\2', abs_suffix))
    cmds.setAttr(((obj + '.') + influence_attr), 1)
    cmds.setAttr(((obj + '.') + amplitude_attr), 1)
    cmds.setAttr(((obj + '.') + frequency_attr), 10)
    if hide_unkeyable:
        cmds.setAttr(((obj + '.') + tick_attr), k=False)
        cmds.setAttr(((obj + '.') + output_attr), k=False)
    if (add_absolute_output and hide_unkeyable):
        cmds.setAttr(((obj + '.') + abs_attr), k=False)
    cmds.connectAttr(tick_source_attr, (influence_multiply_node + '.input1X'))
    cmds.connectAttr((influence_multiply_node + '.outputX'), ((obj + '.') + tick_attr))
    cmds.connectAttr(((obj + '.') + influence_attr), (influence_multiply_node + '.input2X'))
    cmds.connectAttr(((obj + '.') + amplitude_attr), (multiply_node + '.input2X'))
    cmds.connectAttr(((obj + '.') + frequency_attr), (mdl_node + '.input1'))
    cmds.connectAttr(((obj + '.') + tick_attr), (mdl_node + '.input2'))
    cmds.connectAttr(((obj + '.') + offset_attr), (sum_node + '.input1D[0]'))
    cmds.connectAttr((mdl_node + '.output'), (quat_node + '.inputRotateX'))
    cmds.connectAttr((quat_node + '.outputQuatX'), (multiply_node + '.input1X'))
    cmds.connectAttr((multiply_node + '.outputX'), (sum_node + '.input1D[1]'))
    cmds.connectAttr((sum_node + '.output1D'), ((obj + '.') + output_attr))
    if add_absolute_output:
        squared_node = cmds.createNode('multiplyDivide', name=(obj + '_abs_squared'))
        reverse_squared_node = cmds.createNode('multiplyDivide', name=(obj + '_reverseAbs_multiply'))
        cmds.setAttr((squared_node + '.operation'), 3)
        cmds.setAttr((reverse_squared_node + '.operation'), 3)
        cmds.setAttr((squared_node + '.input2X'), 2)
        cmds.setAttr((reverse_squared_node + '.input2X'), 0.5)
        cmds.connectAttr(((obj + '.') + output_attr), (squared_node + '.input1X'))
        cmds.connectAttr((squared_node + '.outputX'), (reverse_squared_node + '.input1X'))
        cmds.connectAttr((reverse_squared_node + '.outputX'), ((obj + '.') + abs_attr))
        return [((obj + '.') + output_attr), ((obj + '.') + abs_attr)]
    else:
        return [((obj + '.') + output_attr), None]
Create Sine function without using third-party plugins or expressions

        Parameters:
            obj (string): Name of the object
            sine (string): Prefix given to the name of the attributes (default is "sine")
            tick_source_attr (string): Name of the attribute used as the source for time. It uses the default "time1" node if nothing else is specified
            hide_unkeyable (bool): Hides the tick and output attributes
            add_absolute_output (bool): Also creates an output version that gives only positive numbers much like the abs() expression

        Returns:
            sine_output_attrs (list): A string with the name of the object and the name of the sine output attribute. E.g. "pSphere1.sineOutput"
                                      In case an absolute output is added, it will be the second object in the list. E.g. ["pSphere1.sineOutput", "pSphere1.sineAbsOutput"]
                                      If add_absolute_output is False the second attribute is None
def add_sine_attributes(obj, sine_prefix='sine', tick_source_attr='time1.outTime', hide_unkeyable=True, add_absolute_output=False, nice_name_prefix=True):
    ' \n    Create Sine function without using third-party plugins or expressions\n    \n            Parameters:\n                obj (string): Name of the object\n                sine (string): Prefix given to the name of the attributes (default is "sine")\n                tick_source_attr (string): Name of the attribute used as the source for time. It uses the default "time1" node if nothing else is specified\n                hide_unkeyable (bool): Hides the tick and output attributes\n                add_absolute_output (bool): Also creates an output version that gives only positive numbers much like the abs() expression\n\n            Returns:\n                sine_output_attrs (list): A string with the name of the object and the name of the sine output attribute. E.g. "pSphere1.sineOutput"\n                                          In case an absolute output is added, it will be the second object in the list. E.g. ["pSphere1.sineOutput", "pSphere1.sineAbsOutput"]\n                                          If add_absolute_output is False the second attribute is None\n    '
    required_plugin = 'quatNodes'
    if (not cmds.pluginInfo(required_plugin, q=True, loaded=True)):
        cmds.loadPlugin(required_plugin, qt=False)
    influence_suffix = 'Time'
    amplitude_suffix = 'Amplitude'
    frequency_suffix = 'Frequency'
    offset_suffix = 'Offset'
    output_suffix = 'Output'
    tick_suffix = 'Tick'
    abs_suffix = 'AbsOutput'
    influence_attr = (sine_prefix + influence_suffix)
    amplitude_attr = (sine_prefix + amplitude_suffix)
    frequency_attr = (sine_prefix + frequency_suffix)
    offset_attr = (sine_prefix + offset_suffix)
    output_attr = (sine_prefix + output_suffix)
    tick_attr = (sine_prefix + tick_suffix)
    abs_attr = (sine_prefix + abs_suffix)
    mdl_node = cmds.createNode('multDoubleLinear', name=(obj + '_multDoubleLiner'))
    quat_node = cmds.createNode('eulerToQuat', name=(obj + '_eulerToQuat'))
    multiply_node = cmds.createNode('multiplyDivide', name=(obj + '_amplitude_multiply'))
    sum_node = cmds.createNode('plusMinusAverage', name=(obj + '_offset_sum'))
    influence_multiply_node = cmds.createNode('multiplyDivide', name=(obj + '_influence_multiply'))
    if nice_name_prefix:
        cmds.addAttr(obj, ln=influence_attr, at='double', k=True, maxValue=1, minValue=0)
        cmds.addAttr(obj, ln=amplitude_attr, at='double', k=True)
        cmds.addAttr(obj, ln=frequency_attr, at='double', k=True)
        cmds.addAttr(obj, ln=offset_attr, at='double', k=True)
        cmds.addAttr(obj, ln=tick_attr, at='double', k=True)
        cmds.addAttr(obj, ln=output_attr, at='double', k=True)
        if add_absolute_output:
            cmds.addAttr(obj, ln=abs_attr, at='double', k=True)
    else:
        cmds.addAttr(obj, ln=influence_attr, at='double', k=True, maxValue=1, minValue=0, nn=influence_suffix)
        cmds.addAttr(obj, ln=amplitude_attr, at='double', k=True, nn=amplitude_suffix)
        cmds.addAttr(obj, ln=frequency_attr, at='double', k=True, nn=frequency_suffix)
        cmds.addAttr(obj, ln=offset_attr, at='double', k=True, nn=offset_suffix)
        cmds.addAttr(obj, ln=tick_attr, at='double', k=True, nn=tick_suffix)
        cmds.addAttr(obj, ln=output_attr, at='double', k=True, nn=output_suffix)
        if add_absolute_output:
            cmds.addAttr(obj, ln=abs_attr, at='double', k=True, nn=re.sub('(\\w)([A-Z])', '\\1 \\2', abs_suffix))
    cmds.setAttr(((obj + '.') + influence_attr), 1)
    cmds.setAttr(((obj + '.') + amplitude_attr), 1)
    cmds.setAttr(((obj + '.') + frequency_attr), 10)
    if hide_unkeyable:
        cmds.setAttr(((obj + '.') + tick_attr), k=False)
        cmds.setAttr(((obj + '.') + output_attr), k=False)
    if (add_absolute_output and hide_unkeyable):
        cmds.setAttr(((obj + '.') + abs_attr), k=False)
    cmds.connectAttr(tick_source_attr, (influence_multiply_node + '.input1X'))
    cmds.connectAttr((influence_multiply_node + '.outputX'), ((obj + '.') + tick_attr))
    cmds.connectAttr(((obj + '.') + influence_attr), (influence_multiply_node + '.input2X'))
    cmds.connectAttr(((obj + '.') + amplitude_attr), (multiply_node + '.input2X'))
    cmds.connectAttr(((obj + '.') + frequency_attr), (mdl_node + '.input1'))
    cmds.connectAttr(((obj + '.') + tick_attr), (mdl_node + '.input2'))
    cmds.connectAttr(((obj + '.') + offset_attr), (sum_node + '.input1D[0]'))
    cmds.connectAttr((mdl_node + '.output'), (quat_node + '.inputRotateX'))
    cmds.connectAttr((quat_node + '.outputQuatX'), (multiply_node + '.input1X'))
    cmds.connectAttr((multiply_node + '.outputX'), (sum_node + '.input1D[1]'))
    cmds.connectAttr((sum_node + '.output1D'), ((obj + '.') + output_attr))
    if add_absolute_output:
        squared_node = cmds.createNode('multiplyDivide', name=(obj + '_abs_squared'))
        reverse_squared_node = cmds.createNode('multiplyDivide', name=(obj + '_reverseAbs_multiply'))
        cmds.setAttr((squared_node + '.operation'), 3)
        cmds.setAttr((reverse_squared_node + '.operation'), 3)
        cmds.setAttr((squared_node + '.input2X'), 2)
        cmds.setAttr((reverse_squared_node + '.input2X'), 0.5)
        cmds.connectAttr(((obj + '.') + output_attr), (squared_node + '.input1X'))
        cmds.connectAttr((squared_node + '.outputX'), (reverse_squared_node + '.input1X'))
        cmds.connectAttr((reverse_squared_node + '.outputX'), ((obj + '.') + abs_attr))
        return [((obj + '.') + output_attr), ((obj + '.') + abs_attr)]
    else:
        return [((obj + '.') + output_attr), None]