Below is a list of 99% of all functions of puppetshop.
(Note that this is an auto-generated file, so some formatting issues may exist)
(Not all functions are meant to be used by 3rd parties developing scripts or plugins)

You should always try to use the functions in the 'Puppet' interface, such as 'puppet.GetRoot' etc.
(No other functions in other interfaces are garantueed to work the same in future versions of puppetshop.)



Functions_Puppet.ms
puppet.getPuppetNodes riggedOnly:true =
 
	# Description  	:	gets all puppet nodes in the scene
	# Parameters 	: 	<boolean>		riggedOnly			:			if true, returns only puppet that have been rigged
	# Returns    	: 	array of puppet nodes
	
puppet.getRoot puppetNode includeGOD:true =
 
	# Description  : 	Finds the root node of a (rigged) puppet
	# Parameters   : 	<node>		puppetNode		:		puppet Node
						<boolean>	includeGOD		:		if true, the GOD node (if exists) will be returned as root node, 
															if false, then the first child of the GOD node is considered the root and returned.
	# Returns      : node
	
puppet.getHierarchyNodes puppetNode =
 
	# Description  : 	Gets all nodes of a puppet that where in the original hierarchy (nodes that should be exported)
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
	# Returns      : 	Array of nodes (unsorted)
	# Note		   :	You generally do not need this function. You should get the root of a puppet and then gets it's children and so on to
						get all the nodes of a hierarchy. That way you get them in correct hierarchical order.
						This function will return_ all to-be-exported nodes, but not in hierarchical order.
						This function is also pretty slow, so use it only once to grab all nodes in your SDK plugin
	
puppet.getAnimationNodes puppetNode =
 
	# Description  : 	Gets all animation nodes
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
	# Returns      : 	Array of nodes
	# Note		   :	Animation nodes are the control nodes in the skeleton the animators uses to animate the character.
						These nodes may or may not get exported, it depends on how the rig is setup.
						For example, the footCtrl that drives the IK on a leg, is not exported, because the game engine usually only requires the
						leg bones themselves to be exported. (However you are free to export the IK nodes if you need them)
	
puppet.getPuppetParent puppetNode anode =
 
	# Description  : 	Gets parent of a puppetshop node
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<node>		anode		:		Node to find parent of.
	# Returns      : 	parent node or undefined
	
puppet.getPuppetChildren puppetNode anode =
 
	# Description  : 	Gets children of a puppetshop node
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<node>		anode		:		Node to find children of.
	# Returns      : 	array of children
	
puppet.setHierarchyLevel puppetNode num =
 
	# Description  : 	Set the hierarchy to a certain level
	# Parameters   : 	<node>		puppetNode		:		puppet Node
						<integer>	num				:		set the hierarchy level
	# Returns      : true if succesful, false if not (which likely means the hierarchyLevel provided does not exist)
	
puppet.getNodeByClass puppetNode anode nodeClass =
 
	# Description  : 	Gets all nodes of a certain class
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<node>		anode		:		Node where to start search (usually root).
						<class>		nodeClass	:		class of ndoe you are trying to find, for example: puppetShop_head
	# Returns      : 	array of nodes of the specified class
	
puppet.setClipEditMode puppetNode bool setRange:true =
 
	# Description  : 	Switches puppet into cutscene mode or out of cutscene mode (clip edit mode)
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<boolean>	bool		:		true or false
						<boolean>	setRange	:		if true, we also update the max animationrange
	# Returns      : 	ok
	# Note		   :	If modify panel is open, it will not redraw the UI...
	
puppet.setCacheMode puppetNode bool =
 
	# Description  : 	Switches puppet into cache mode or out of cache mode
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<boolean>	bool		:		true or false
	# Returns      : 	ok
	
puppet.getMode puppetNode =
 
	# Description  : 	gets current 'mode' of puppet (timeline/animation or clip editting or cache or graph)
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
	# Returns      : 	integer
	
puppet.setActiveAnimation puppetNode ind animName:undefined =
 
	# Description  : 	Switches to the correct timeline (automatically detects if timeline exists.
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<integer>	ind			:		index of the animation you wish to switch to
						<string>	animName	:		you may also provide an animation instead of an index.
	# Returns      : 	ok
	# Example	   :	puppet.setActiveAnimation $'Bob_World' 2
	
puppet.setActiveAnimationByName puppetNode animName =
 
	# Description  : 	Switches to the correct timeline by name (automatically detects if timeline exists.
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<string>	animName	:		animation name
	# Returns      : 	ok
	# Example	   :	puppet.setActiveAnimationByName $'Bob_World' "MyAnim"
	
puppet.createNewAttributeModifier puppetNode targetNode blockString rolloutString strName =
 
	# Description  : 	Creates a new modifiers that hold animatable (timeline compatible) parameters.
	# Parameters   : 	<node>			puppetNode	:		PuppetNode of the character we are working on
						<node>			targetNode	:		the node that will get the modifier applied
						<string>		blockString	:		Additional parameter block items you want to insert
						<string>		rolloutString:		Additional rollout items you want to insert
						<string>		strName		:		Name of rollout
	# Returns      : 	ok
	# Note		   :	You would use this function to add a puppet attribute modifier to a custom animation node that you want to give
						timeline compatible custom attributes.
						
						Make sure (!) the targetNode was added to the custom anim list before running this function on it
	
puppet.getActiveAnimationName puppetNode =
 
	# Description  : 	returns the active animation name
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
	# Returns      : 	string, (or false if no active animation could be found for PS 1.x characters)
	
puppet.addAnimation puppetNode animName sFrame eFrame =
 
	# Description  : 	Adds new timeline/animation clip
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<string>	animName	:		name of animation you want to add
						<integer>	sFrame		:		Start frame of new animation
						<integer>	eFrame		:		End frame of new animation
	# Returns      : 	true
	
puppet.setBasePose puppetNode frm animOn:on setSlider:true =
 
	# Description  : 	resets the basePose of the character at frm
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<integer>	frm			:		frame number at which to set the basePose.
						<on/off>	animOn		:		animate on or off.
	# Returns      : 	ok
	
puppet.getAnimInfo puppetNode ind =
 
	# Description  : 	get animation info
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<integer>	ind			:		frame number at which to set the basePose.
	# Returns      : 	array #(active, name, startTime, endTime, params, checked)
	
puppet.getAnimCount puppetNode =
 
	# Description  : 	returns number of animations
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
	# Returns      : 	integer
	
puppet.getAnimIndex puppetNode animName =
 
	# Description  : 	returns index of animation
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<string>	animName		:		name of animation
	# Returns      : 	integer
	
puppet.getClipData pNode animName animIndex =
 
	# Description  	: 	Returns the Data for a single clip on a puppet
	# Parameters 	: 	
						<node>		pNode		:		puppetNode
						<string>	animName	:		name of animation we want info of
						<integer>	animIndex	:		index of animation in the animation list
	# Returns    	: 	array #( #(track, start, end, #(time, blendval, time, blendval, ...)), #(...) )
	# Note			:	This is used to be able to get the information where and how often a clip is used on a puppet, and what its blend values are
						Useful for cutscenes.
	
puppet.getNodeExposure aNode =
 
	# Description  : 	returns wheter a node should be shown in UI or not
	# Parameters   : 	<node>		anode		:		 anode (only garantueed for puppetShop nodes)
	# Returns      : 	true if node should be visible, false if it should be hidden from custom UI's
	
puppet.addAnimNode puppetNode node quiet:false =
 
	# Description  : 	Adds new node to custom anim node list
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<node>		node		:		node you want to add to custom anim list
						<boolean>	quiet		:		if true, don't pop up warning messages.
	# Returns      : 	true or false
	
puppet.addHierarchyNode puppetNode node parent:undefined =
 
	# Description  : 	Adds new node to custom hierarchy node list
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<node>		node		:		node you want to add to custom hierarchy list
						<node>		parent		:		hierarchy parent node
	# Returns      : 	true or false
	
puppet.delAnimNode puppetNode node =
 
	# Description  : 	deletes node from custom anim node list
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<node>		node		:		node you want to delete from the list
	# Returns      : 	ok
	
puppet.delHierarchyNode puppetNode node =
 
	# Description  : 	deletes node from custom hierarchy node list
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<node>		node		:		node you want to delete from the list
	# Returns      : 	ok
	
puppet.linkPuppetNode puppetNode parent =
 
	# Description  : 	allows you to link the puppetNode to another node
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<node>		parent		:		node that you want to be the new parent of the puppetNode
	# Returns      : 	true
	
puppet.deleteNode anode =
 
	# Description  : 	delete nodes (from a puppet) without getting the 'deleted part of rig' message
	# Parameters   : 	<node>		anode	:		node to delete (can be a puppetshop class node or any other max node)
	# Returns      : 	true
	
puppet.renameNode anode newName =
 
	# Description  : 	renames a node in the puppet rig without geting the rename warning
	# Parameters   : 	<node>		anode	:		node to rename (can be a puppetshop class node or any other max node)
	# Parameters   : 	<string>	newName	:		new name for node
	# Returns      : 	true
	
puppet.getPuppetName puppetNode =
 
	# Description  : 	returns name of character
	# Parameters   : 	<node>		puppetNode	:		puppetNode
	# Returns      : 	string
	# Note		   :	This basically strips off the "_World" from the puppetNode name
	
puppet.getAllNodesOfPuppet puppetNode includeHierarchy:false =
 
	# Description  : 	returns all ndoes belonging to the puppet
	# Parameters   : 	<node>		puppetNode			:		puppetNode
						<boolean>	includeHierarchy	:		if true, includes custom hierarchy nodes too (caution, this might include things like skinned mesh that you might not want to delete)
	# Returns      : 	ok
	
puppet.extractPuppet puppetNode extractProxy:true transferTwist:true transferUserProps:true =
 
	# Description  : 	extracts a new un-rigged puppet from a rigged one
	# Parameters   : 	<node>		puppetNode	:		puppetNode
	# Returns      : 	new created puppetNode (unrigged)
	
puppet.deletePuppet puppetNode =
 
	# Description  : 	deletes entire puppet, node that custom added hierarchy nodes will be left in the scene as they could be skins.
	# Parameters   : 	<node>		puppetNode	:		puppetNode
	# Returns      : 	ok
	
puppet.isActivePart anode animIndex =
 
	# Description  : 	checks if a node is set to be exported or not (animator can decide this per animation clip)
	# Parameters   : 	<node>		anode		:		a node you are about to export (hierarchy node)
						<integer>	animIndex	:		the index of the animation you are exporting
	# Returns      : 	true or false
	# Note		   :	If a node does not have the ability to be switched on or off (for example some sort of custom node) the default return_ value will be true
	
puppet.batchAnimSave puppetNode dir all:true=
 
	# Description  : 	Saves animations of puppet to disk
	# Parameters   : 	<node>		puppetNode	:		puppetNode
						<string>	dir			:		path name of directory to save to
						<boolean>	all			:		if true, save all animations, if false, saves only the 'checked' animations
	# Returns      : 	ok
	
puppet.batchAnimLoad puppetNode dir sframe:1 zeroLayers:true =
 
	# Description  : 	load animations from disk onto puppet
	# Parameters   : 	<node>		puppetNode	:		puppetNode
						<string>	dir			:		path name of directory to save to
						<integer>	sframe		:		start frame for all animations
						<boolean>	zeroLayers	:		wheter to zero and bracket existing layers or not, Usually you won't have any and true is fine.
	# Returns      : 	ok
	# NOTE		   :	See the function "saveAnimNodeList" below for details on batch loading only certain nodes
	
puppet.saveAnimNodeList puppetNode file =
 
	# Description  : 	saves animation node list to disk. This can be useful in-combination with batch saving and loading
						Two files can be provided for batch saving and loading: to.pnl and from.pnl
						The lists should contain the animation nodes of the source puppet (from) and the target puppet (to) in the right order
						These two lists allow you to only batch-load certain nodes that were saved (in case of rig changes)
						The name and extension must be as mentioned above.
	# Parameters   : 	<node>		puppetNode	:		puppetNode
						<string>	file		:		path name of file to save node list to
	# Returns      : 	ok
	
puppet.batchExportToBVH puppetNode folder human:true all:true =
 
	# Description  : 	export human mocap
	# Parameters   : 	<node>		puppetNode	:		puppetNode
						<string>	folder		:		path name of folder to export to. I.e.: "c:\\myfolder"
						<boolean>	human		:		if true, uses the specialised human exporter. If false uses the creature exporter
						<boolean>	all			:		if false uses checked animations only
	# Returns      : 	ok
	# Note		   :	Be sure to reset any custom added constraint at base frame
						I.e.: with animate on at time -1 leftHandCtrl.modifiers["Puppet Attributes"].custom_attributes.constrain_ = 0.0
	
puppet.batchImportHumanBVH puppetNode folder config:4 =
 
	# Description  : 	export human mocap
	# Parameters   : 	<node>		puppetNode	:		puppetNode
						<string>	folder		:		path name of folder to export to. I.e.: "c:\\myfolder"
						<integer>	config		:		how to import mocap, for example default 4 means: fk-blend arms and IK legs (see dropdownlist in UI)
	# Returns      : 	ok
	# Note		   :	Must be HUMAN!
	
puppet.renamePuppet puppetNode newName =
 
	# Description  : 	sets a new name for a puppet
	# Parameters   : 	<node>		puppetNode	:		puppetNode
						<string>	newName		:		new name for puppet
	# Returns      : 	ok
	
puppet.setLocalRotation anode x y z =
 
	# Description  : 	sets local rotation on a node with euler values specified
	# Parameters   : 	<node>		anode	:		node to set TM of
						<integer>	x		:		wanted local x rotation
						<integer>	y		:		wanted local y rotation
						<integer>	z		:		wanted local z rotation
	# Returns      : 	local rotation (this values goes into $.rotation.controller.value)
	
puppet.printSkeleton puppetNode puppetRoot =
 
	# Description  : 	Example code of how to export hierarchy of a puppet
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<node>		puppetRoot			:		root of a puppet (first node of a puppet's skeleton)
	# Returns      : 	ok (prints stuff to listener)
	
puppet.printAllPuppets =
 
	# Description  : 	Example code of how to export hierarchy of a puppet
	# Parameters   : 	
	# Returns      : 	ok (prints stuff to listener)
	

Classes.ms
ps_classes.godnode =
 
	# Description  : Creates a class Face object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.puppetHelper =
 
	# Description  : pivot Spheres are placed to allow to user to custom place pivot points
	# Parameters   : 
	# Returns      : ok
	
ps_classes.puppetShoulderTwist =
 
	# Description  : Node that visualizes the range of motion for shoulder twist bones.
	# Parameters   : 
	# Returns      : ok
	
ps_classes.mocapNode =
 
	# Description  : Creates a mocap bone
	# Parameters   : 
	# Returns      : ok
	
ps_classes.markerNode =
 
	# Description  : Creates a marker
	# Parameters   : 
	# Returns      : ok
	
ps_classes.ctrlNode =
 
	# Description  : Creates a class CTRL object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.FKSphere =
 
	# Description  : A half sphere for fk control
	# Parameters   : 
	# Returns      : ok
	
ps_classes.pivotSphere =
 
	# Description  : pivot Spheres are placed to allow to user to custom place pivot points
	# Parameters   : 
	# Returns      : ok
	
ps_classes.pivotHolder =
 
	# Description  : Creates a Rectangle that will act as the floor for a foot or hand (location of pivots)
	# Parameters   : 
	# Returns      : ok
	
ps_classes.digitHUB =
 
	# Description  : Creates a node (foot or hand) that holds digits (fingers or toes)
	# Parameters   : 
	# Returns      : ok
	
ps_classes.fknode =
 
	# Description  : Creates a class fk object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.facenode =
 
	# Description  : Creates a class Face object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.twistnode =
 
	# Description  : Creates a class twist object. 
					 Twist nodes are used for better mesh deformation between joints (like shoulder area)
	# Parameters   : 
	# Returns      : ok
	
ps_classes.twistnoderoot =
 
	# Description  : Creates a class twist root object. 
					 Twist nodes are used for better mesh deformation between joints (like shoulder area)
	# Parameters   : 
	# Returns      : ok
	
ps_classes.spinenode =
 
	# Description  : Creates a class spine object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.spineroot =
 
	# Description  : Creates a class spine root object. 
					 A root object is the first object of a chain (I.e. first bone in a spine, or upper leg in a chain of leg bones)
	# Parameters   : 
	# Returns      : ok
	
ps_classes.tailnode =
 
	# Description  : Creates a class tail object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.tailroot =
 
	# Description  : Creates a class tail root object. 
					 A root object is the first object of a chain (I.e. first bone in a spine, or upper leg in a chain of leg bones)
	# Parameters   : 
	# Returns      : ok
	
ps_classes.necknode =
 
	# Description  : Creates a class neck object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.neckroot =
 
	# Description  : Creates a class neck root object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.headnode =
 
	# Description  : Creates a class head object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.digitnode =
 
	# Description  : Creates a digit node (finger or toes)
	# Parameters   : 
	# Returns      : ok
	
ps_classes.leg =
 
	# Description  : Creates a class leg object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.legroot =
 
	# Description  : Creates a class leg root object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.arm =
 
	# Description  : Creates a class arm object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.armroot =
 
	# Description  : Creates a class arm root object
	# Parameters   : 
	# Returns      : ok
	
ps_classes.puppetNode =
 
	# Description  : Creates the puppet node from which you build your character
	# Parameters   : 
	# Returns      : ok
	

Clip_Editor.ms
c_ps_timeSlider .setTimeSliderBitmap =
 
	# Description  	: 	Creates a bitmap for the timeSlider
	# Parameters 	: 	
	# Returns    	: 	bitmap
	
c_ps_timeSlider .setSliderLabel timeSlider_bmp lbl thisTime:undefined =
 
	# Description  	: 	sets correct text and position for timeslider label
	# Parameters 	: 				timeSlider	:		timeSlider bitmap
							<label>			lbl			:		timeSlider label
							<integer<		thisTime	:		use provided time instead of currenttime
	# Returns    	: 	ok
	# Note			:	Currently there is not support for displaying tick-times.
	
c_ps_timeSlider .updateTimeSliderValues =
 
	# Description  	: 	updates values needed for updateTimeSlider
	# Parameters 	: 	
	# Returns    	: 	ok
	
c_ps_timeSlider .setSliderPos timeSlider_bmp lbl cursorPos timeIndicator =
 
	# Description  	: 	sets position of timeslider bitmap
	# Parameters 	: 				timeSlider	:		timeSlider bitmap
							<label>			lbl			:		timeSlider label
							<point2>		cursorPos	:		position of cursor
							<bitmap>		timeIndicator:		timeIndicator of clip editor
	# Returns    	: 	ok
	
c_ps_timeSlider .updateTimeSlider timeSlider_bmp lbl timeIndicator =
 
	# Description  	: 	updates the timeslider
	# Parameters 	: 				timeSlider	:		timeSlider bitmap
							<label>			lbl			:		timeSlider label
	# Returns    	: 	ok
	
c_ps_timeSlider .ps_animChange timeSlider_bmp lbl timeIndicator =
 
	# Description  	: 	redraws timeslider due to animationRange changes
	# Parameters 	: 	
	# Returns    	: 	ok
	# Note			:	
	
c_ps_timeSlider .ps_playAnim clipEditor playTimerStatus:undefined =
 
	# Description  	: 	toggle play anim
	# Parameters 	: 	<boolean>		playTimerStatus		:	normally this function behaves as a toggle, but you can force it to adopt a value by supplying this parameter. Note that you give it the oppesite of what you want the outcome to be (since it will toggle)
	# Returns    	: 	ok
	# Note			:	
	
c_ps_timeSlider .addKeyRollout modal:true =
 
	# Description  	: 	redraws timeslider due to animationRange changes
	# Parameters 	: 	
	# Returns    	: 	ok
	# Note			:	
	
c_ps_clipEditor .drawText track_bmp trackID:1 =
 
	# Description  	: 	Draws text to clip editor
	# Parameters 	: 	
	# Returns    	: 	ok
	
c_ps_clipEditor .getSingleClipData pNode animName animIndex =
 
	# Description  	: 	Returns the Data for a single clip on a puppet
	# Parameters 	: 	
						<node>		pNode		:		puppetNode
						<string>	animName	:		name of animation we want info of
						<integer>	animIndex	:		index of animation in the animation list
	# Returns    	: 	array #( #(track, start, end, #(time, blendval, time, blendval, ...)), #(...) )
	# Note			:	This is used to be able to get the information where and how often a clip is used on a puppet, and what its blend values are
						Useful for cutscenes.
	
c_ps_clipEditor .drawRow track_bmp rowNum pNode color:rowColor trackID:1 clip_Array:undefined =
 
	# Description  	: 	Draws a single row
	# Parameters 	: 	
	# Returns    	: 	ok
	
c_ps_clipEditor .getClipHit updateColor:false =
 
	# Description  	: 	Determines what was 'hit' when the lmbutton was clicked onto the dialog
	# Parameters 	: 	<boolean>	updateColor		:	wheter to update the clipcolor UI. true for left-click but should be false for right-clicks
	# Returns    	: 	ok
	
c_ps_clipEditor .getHit clipDialog updateColor:true =
 
	# Description  	: 	Determines what was 'hit' when the lmbutton was clicked onto the dialog
	# Parameters 	: 	<boolean>	updateColor		:	wheter to update the clipcolor UI. true for left-click but should be false for right-clicks
	# Returns    	: 	ok
	
c_ps_clipEditor .refresh track1_bmp track2_bmp clip_Array:undefined =
 
	# Description  	: 	refresh the clip editor
	# Parameters 	: 	
	# Returns    	: 	ok
	
c_ps_clipEditor .refreshLists clipEditRol =
 
	# Description  	: 	refreshes the 2 dropdownlists to only show puppets in clipEditor mode
	# Parameters 	: 	
	# Returns    	: 	ok
	
c_ps_clipEditor .dockSlider clipEditRol eWidth eHeight =
 
	# Description  	: 	docks the timeslider
	# Parameters 	: 	
	# Returns    	: 	ok
	# Note			:	
	
c_ps_clipEditor .bakeClipArray nodesToDisable:#() nodesToEnable:#() =
 
	# Description  	: 	puts clipArray back into controllers
	# Parameters 	: 	
	# Returns    	: 	ok
	
c_ps_clipEditor .updateClipArray pos keepEnd:undefined resetSlice:undefined resetScale:undefined customColor:undefined =
 
	# Description  	: 	updates the clipArray (i.e. when scale, move, etc)
	# Parameters 	: 	
						<point3>		pos				:		supply position of mouse, for udpates that don't care about the mouse (i.e. keepEnd) supply [0,0,0]
						<boolean>		keepEnd			:		if supplied, set the keepEnd value to this, if undefined, we do not update it.
						<boolean>		resetSlice		:		if supplied, reset the start and end slice back to 0.
						<boolean>		resetScale		:		if supplied, reset scale to 1.0
						<color>			customColor		:		if supplied we set this color as the new clip color
	# Returns    	: 	ok
	

Functions_.ms
ps_func.controllerLocked state =
 
	# Description  	: locks / unlocks controller from being overwritable
	# Parameters 	: 
						<boolean>		state		:	true if controllers should NOT be over-writeable, false if they should be
	# Returns    	: the previous state, this is returned so that functions that change the state can restore the state when done
	# Note			: see also 'return_' which always switches this flag back to true
	
ps_func.isPuppetProperty obj propStr =
 
	# Description  	: checks if a property exists on an object. Unlike isProperty for max, this does not cause exceptions in 3dsmax debug
	# Parameters 	: 
						<node>		obj		:	node to check property of (can be modifier, structure, maxobject etc.)
						<string>	propStr	:	property we are looking for
	# Returns    	: true or false
	
ps_func.roundto val n =
 
	# Description  :	Rounds of values
	# Parameters   : 
						float		val		:		float we wish to round
						integer		n		:		how many digits past the dot we want
	# Returns      : 	rounded float
	
ps_func.isUnEven num =
 
	# Description  :	checks wheter a number is even of uneven
	# Parameters   : 
						integer		num		:		integer we wish to check
	# Returns      : 	ok
	# Note		   : 	copied from mocap
	
ps_func.easeInOut val t1:3.0 t2:2.0 =
 
	# Description  :	hermite function for ease-in and out
	# Parameters   : 	float		val		:	value to convert
						float		t2		:	in-tangent, to adjust curve
						float		t2		:	out-tangent
	# Returns      : 	float
	# Note		   : val needs to be 0 to 1
	
ps_func.replaceString str src trg =
 
	# Description  	: returns the characters name
	# Parameters 	: 
						<string>		str		:		entire string
						<string>		src		:		piece of string we are going to replace
						<string>		trg		:		piece of string we are replacing src with
	# Returns    	: ok
	# NOTE			: 
	
ps_func.getBaseClass anode super:false =
 
	# Description  	: returns base class of objects, and respects xrefs
	# Parameters 	: 
						<node>			anode	:		node to get baseclass of
						<boolean>		super	:		if true, we get the superclassof instead
	# Returns    	: class
	# Note			:	ISPROPERTY should NEVER be run on controllers, it will eventually crash max.
	
ps_func.posRotCloseEnough p1 p2 limit:0.01 useW:false =
 
	# Description  : checks to see if 2 point3's or two quats are 'close enough' to being the same
	# Parameters   : 	<Point3 / Quat>		p1
						<Point3 / Quat>		p2
						<float>				limit		:		threshhold
	# Returns      : ok
 	
ps_func.resetStretchTM childArray =
 
	# Description  	: resets stretch in bones and compensates by changing the length value for the bone
	# Parameters 	: 
	# Returns    	: ok
	
ps_func.getCharName puppetNode =
 
	# Description  	: returns the characters name
	# Parameters 	: 
	# Returns    	: ok
	# NOTE			: 
	
ps_func.keyStripper cont range keyArray:undefined keyValuesArray:undefined keyTimesArray:undefined closeEnough:false =
 
	# Description  : Just a quick and dirty key stripper to strip out very obvious keys with the same values
	# Parameters   : 
					 <controller>		cont			:		the controller you want to strip
					 <interval>			range			:		the time range you want to strip for
					 <array>			keyArray		:		optional, you may feed it an array directly instead of using a controller (you can leave controller undefined)
					 <array>			keyValuesArray	:		optional, feed it the array of values and times directly instead of the key array
					 <boolean>			closeEnough		:		if true, do a 'close enough comparision'. Currently only work on floats!
	# Returns	   : array that is stripped of key values
	# Note		   : 1. If your controller is XYZ, make sure you feed it the seperate X, Y and Z controllers
					 2. This may not strip 100% of the keys that could be stripped
					 3. When feeding keyValuesArray we sue to make keyArray not undefined, make it #() instead so that doDelete is set to false
	
ps_func.canSetKeys cont =
 
	# Description  	: checks if a controller is keyable
	# Parameters 	: 
						<controller>		cont		:	controller to add key to
	# Returns    	: true or false
	
ps_func.addKey cont t tangentFix:false =
 
	# Description  	: adds a key to a controller if the key doesn't already exist.
	# Parameters 	: 
						<controller>		cont		:	controller to add key to
						<integer>			t			:	time
						<boolean>			tangentFix	:	if true and we added a first or last key, then fix the tangent so that the curve stays the same
	# Returns    	: ok
	# NOTE			: 
	
ps_func.convKey cont t type:#custom ignore:#(#step) =
 
	# Description  	: converts a key (if exists) to a differen tangent type
	# Parameters 	: 
						<controller>		cont		:		controller to convert keys of
						<integer>			t			:		time to convert keys at
						<name>				type		:		type of tangent you want to convert to
						<array>				ignore		:		types of tangents NOT to convert. #step is default because of animatable pivot.
	# Returns    	: ok
	
ps_func.unParent aNodes =
 
	# Description  	: unParents the animation Nodes provided and returns the original parents.
	# Parameters 	: 
	# Returns    	: ok
	
ps_func.reParent aNodes parentArray =
 
	# Description  	: restores Parents the animation Nodes provided
	# Parameters 	: 
	# Returns    	: ok
	
ps_func.setTimelineControllerNames puppetNode tInd:undefined =
 
	# Description  : Sets the timeline name on all controllers
	# Parameters   : 
	# Returns      : ok
	
ps_func.getLayerName puppetNode ind tInd:undefined =
 
	# Description  : gets the name of a layer
	# Parameters   : 
	# Returns      : string
	
ps_func.setLayerName puppetNode txt ind tInd:undefined =
 
	# Description  : sets the name of a layer
	# Parameters   : 
	# Returns      : ok
	
ps_func.getSubanimName subanim =
 
	# Description  	: returns name of subAnim
	# Parameters 	: 
	# Returns    	: return_ string
	
ps_func.getLayerCont puppetNode returnList:false type:1 thisLayer:undefined instance:false tInd:undefined =
 
	# Description  	: returns the active layer controller
	# Parameters 	: 	<node>		puppetNode		:	puppetNode (or any animatable node)
						<boolean>	returnList		:	if false, we return_ the active layer controller. If true, we return_ the layers-list controller itself
						<integer>	type			:	1 == position, 2 == rotation
						<integer>	thisLayer		:	if specified, we use this layer indexd to find the controller and not look for active controller ourself
						<boolean>	instance		:	if false, we make a copy of the controller. If true, means we are working directly on the controller, thus no need for using setLayerCont. This can be slower in complex rigs.
						<integer>	tInd			:	index of timeline
	# Returns    	: (copy of) a controller
	# NOTE			: puppetNode can really be any animatable node
	
ps_func.setLayerCont puppetNode cont type:1 subType:0 thisLayer:undefined setList:false instance:true tInd:undefined =
 
	# Description  	: set the active layer controller
	# Parameters 	: 	<node>			puppetNode		:	puppetNode (or any animatable node)
						<controller>	Cont			:	the controller to set
						<integer>		type			:	1 == position, 2 == rotation
						<integer>		subtype			:	if not 0, means we are dealing with a float list
						<integer>		thisLayer		:	if specified, we use this layer indexd to find the controller and not look for active controller ourself
						<boolean>		setList			:	if true, we set the layer controller itself, instead of one of it's sub controllers
						<boolean>		instance		:	if false, we make a copy of the controller.
						<integer>	tInd				:	index of timeline
	# Returns    	: ok
	# NOTE			: puppetNode can really be any animatable node
	
ps_func.getAttributeTimeLineCont ca returnList:false instance:false =
 
	# Description  	: returns the active attribute timeline controller
	# Parameters 	: 	<attribute_controller>	ca				:	attribute that holds the controller we are after. I.e.: puppetCa.syncPivX_.controller
						<boolean>				returnList		:	If true, we return_ the timeline-list controller itself
						<boolean>				instance		:	if false, we make a copy of the controller. If true, we are working directly on the controller, thus no need to use 'setAttributeTimeLineCont'. This can be slower.
	# Returns    	: (copy of) a controller
	# NOTE			: 
	
ps_func.setAttributeTimeLineCont ca cont setList:false instance:true =
 
	# Description  	: set the active layer controller
	# Parameters 	: 	<attribute>		ca				:	attribute to set
						<controller>	Cont			:	the controller to set
						<boolean>		setList			:	if true, we set the list controller itself, instead of one of it's sub controllers
						<boolean>		instance		:	if false, we make a copy of the controller.
	# Returns    	: ok
	# NOTE			: 
	
ps_func.setMulCurveActive puppetNode layer =
 
	# Description  :	sets multiplier curve to active
	# Parameters   : 	
						<node>		puppetNode	: 	puppet node
	# Returns      : 	ok
	
ps_func.addMulCurve puppetNode layer =
 
	# Description  :	adds multiplier curve to layer
	# Parameters   : 	
						<node>		puppetNode	: 	puppet node
	# Returns      : 	ok
	
ps_func.delMulCurve puppetNode layer =
 
	# Description  :	removed multiplier curve from layer
	# Parameters   : 	
						<node>		puppetNode	: 	puppet node
	# Returns      : 	ok
	
ps_func.fixWindups anode layer s_frame e_frame =
 
	# Description  :	Fixed 'windup' rotations. (Rotations bigger then 360)
	# Parameters   : 	
						<node>		anode		: 	node to work on
						<integer>	layer		:	which layer to work on
						<integer>	s_frame		:	start frame
						<integer>	e_frame		:	end frame
	# Returns      : 	ok
	
ps_func.tcbFlipFix inCont =
 
	# Description  	:	Makes quat2 take the closest route to quat1
	# Parameters   	: 	
	# Returns     	: 	ok
	# Note			: 
	
ps_func.makeClosest quat1 quat2 =
 
	# Description  	:	Makes quat2 take the closest route to quat1
	# Parameters   	: 	
	# Returns     	: 	ok
	# Note			: 
	
ps_func.makeLinearClosest anode thetime theLayer:undefined cont:undefined setCont:true instance:false =
 
	# Description  	:	Makes quat2 take the closest route to quat1, for linear controllers
	# Parameters   	: 	
						<node>			anode			:	node to work on
						<integer>		thetime			:	time to fix rotation at
						<integer>		theLayer		:	force it to use this layer instead of active one
						<controller>	cont			: 	force it to use this controller isntead of finding it
						<boolean>		setCont			:	if true, we set the controller, if false we do not (might be set later by other function)
						<boolean>		instance		:	wheter to copy or instance the rotation controller
	# Returns     	: 	ok
	# Note			: 	Max's default linear controller does not have a build in fix for quat closest values, thus we have to do it ourselves
	
ps_func.getPuppetNodes riggedOnly:true =
 
	# Description  	:	gets all puppet nodes in the scene
	# Parameters 	: 
	# Returns    	: 	array of puppet nodes
	
ps_func.getSkinnedMeshes =
 
	# Description  	:	gets all skinned meshes in the scene
	# Parameters 	: 
	# Returns    	: 	array of meshes with skin modifier
	
ps_func.delayedGC cnt light:false =
 
	# Description  	:	Makes quat2 take the closest route to quat1
	# Parameters   	: 	
	# Returns     	: 	ok
	# Note			: 
	
ps_func.customNodePreDelete n =
 
	# Description  	: Gets called during the deletion of a custom added node. Custom nodes are nodes added by the user after the rig was complete.
	# Parameters 	: 
	# Returns    	: ok
	# NOTE			: 
	
ps_func.PuppetRigPostDeleteCallback =
 
	# Description  	:	deletes nodes of a rig
	# Parameters   	: 	
	# Returns     	: 	ok
	# Note			: 
	
ps_func.PuppetRigPreDeleteCallback =
 
	# Description  	:	checks if the deleted node belongs to a puppetshop rig, 
						if so, then it adds the rig nodes to a list of nodes to be deleted
	# Parameters   	: 	
	# Returns     	: 	ok
	# Note			: 
	
ps_func.cleanUpRig Nodes =
 
	# Description  	: Checks if bones have been deleted and cleans up any children and parents
	# Parameters 	: <array>		Nodes		:	search through these objects
	# Returns    	: ok
	# NOTE			: 
						This is the heart of the beast. It's relatively delicate system (so be careful if you change anything in here)
						It is 'delicate' because maxscript was never really designed to deal with these types of situations, so we had to jump 
						though a few hoops to get it to work properly and stable.
						When an object gets deleted, we get some information send to us by the callback on the puppetnode.
						We then search though all objects in  (usually all objects in the max scene) to check if they are involved in the deletion.
						An object is 'involved' when either itself or any of it's parents got deleted.
						We then proceed to delete the rest of it's chain.
						I.e. If the lower leg gets deleted, we delete the upperleg, and all children of the lower leg, so that no nodes of this leg
						stay behind in the max scene.
	
ps_func.delayFunction delayTime fString =
 
	# Description  :	opens up a rollout with a timer that launches commands
	# Parameters   : 
						<integer>		delayTimer		:		time in miliseconds
						<string>		fString			:		function string to execute
	# Returns      : 	ok
	# Note		   :	Right now you can only have one rollout open at once, but we can change this if we need to...
	
ps_func.nodePostDelete resetDeleteInProgress:false =
 
	# Description  	: Gets called when a node has been deleted
	# Parameters 	: 
	# Returns    	: ok
	# NOTE			: 
	
ps_func.nodePreDelete =
 
	# Description  	: Gets called during the deletion of a node
	# Parameters 	: 
	# Returns    	: ok
	# NOTE			: 

						If the cleanUpRig function is the heart of the beast, then this must be the brains (equally important and delicate).
						During the deletion of a node we store some vital information that the cleanUpRig function needs to have to function properly
						We figure out which node it was that got deleted, and track down it's chain parent.
						This information is stored in a few global parameters that get used by the cleanUpRig function.
	
ps_func.resize_puppet puppetNode scaleAmount theChildren:undefined =
 
	# Description  	: 	changes the size of a puppet by changing the length etc of all nodes
	# Parameters 	: 
						<node>		puppetNode			:		Puppet node that we are resizing
	# Returns    	: ok
	# NOTE			: 
	
ps_func.mirrorMatrix axis flip tm:(matrix3 1) pivotTm:(matrix3 1) =
 
	# Description  	: 	Mirror transform Matrix
	# Parameters 	: 
						<string>		axis		:		axis to mirror over
						<string>		flip		:		axis to flip
						<matrix3>		tm			:		transform matrix to mirror
						<matrix3>		pivotTM		:		transform matrix to mirror around
	# Returns    	: ok
	# NOTE			: For axis and flip pick one of the following:
						[-1,1,1]  -- reflect in YZ plane (x)
						[1,-1,1]  -- reflect in ZX plane (y)
						[1,1,-1]  -- reflect in XY plane (z)
	
ps_func.mirror_pose_fn sourceTransform sourceNode targetNode centerNode theMap:undefined =
 
	# Description  : Mirrors a node
	# Parameters   :  <matrix3>		sourceTransform 	:	transform we copied from source node
					 <node>			sourceNode			:	source node
					 <node>			targetNode 			:	node we are going to paste the mirrored transform to


					 <node>			centerNode 			:	Node we are mirroring around
					 <point3>		theMap				:	this vector tells our mirror function how it is suppose to mirror the object 	# Returns      : ok
	
ps_func.scale_limb whichLimb =
 
	# Description  	: 	changes the length of a limb and moves it's children
	# Parameters 	: 
						<node>		whichLimb		:		The limb we are changing the length of
	# Returns    	: ok
	# NOTE			: 
	
ps_func.insertBone whichLimb =
 
	# Description  	: 	Inserts an extra bone
	# Parameters 	: 
						<node>		whichLimb		:		any node in a chain (we will find the chain parent in this function)
	# Returns    	: ok
	# NOTE			: new bones always get inserted at the end of the chain of same class bones as whichlimb.
	
ps_func.removeBone whichLimb =
 
	# Description  	: 	Removes a bone
	# Parameters 	: 
						<node>		whichLimb		:		any node in a chain (we will find the chain parent in this function)
	# Returns    	: ok
	# NOTE			: We always remove the last bone in the chain of same class bones as whichlimb
	
ps_func.createControlLine puppetNode objFrom objTo useFromCenter:true col:undefined =
 
	# Description  : Creates a Line going from one object to another
	# Parameters   :  <obj> 		objFrom    		:		Control Cube
					 <obj> 		objTo  			:		Target Node
					 <boolean>	useFromCenter	:		if true, use the center for the objFrom object. If false, use transform.pos
					 <color>	col				:		specifies a specific color to use for the spline, if undefined color will be the frozen color
	# Returns      : spline node
	
ps_func.Swivel_dif vec1_Pre vec2_Pre vec1_Post vec2_Post vec3 =
 
	# Description  : calculates swivel difference
	# Parameters   :  <point3>	vec1_Pre			:		Shoulder - hand
					 <point3>	vec2_Pre			:		elbow - shoulder
					 <point3>	vec1_Post			:		Shoulder - hand
					 <point3>	vec2_Post			:		elbow - shoulder
					 <point3>	vec3				:		elbow - hand

	# Returns      : angle in degrees
	# Note		   : To calculate the difference in swivel angle after relinking the ik chain, you store two vectors before you make any changes,
					 then store the two vectors after all changes have been made and this fuction will return_ the difference in swivelangle,

					 which you can then add to the existing swivelangle to correct any problems.
					 
					 I've seen some fairly minor differences still, so don't think this is completely accurate, but haven't seen any big problems.
					 Might need to find a more accurate way to calculate the swivel angle.
	
ps_func.Callback_SortDuplicateNodeArrayByHandles v1 v2 =
 
	# Description  	: callback for PickDuplicateNode and GetDuplicateNodeIndex
	# Parameters 	: <entry> 
	# Returns     	: 

	
ps_func.PickDuplicateNode strNodeName index:1 puppetCnt:1 =
 
	# Description  	: Picks node by ascending handle order.
	# Parameters 	:	 	 node name, 
							<index> default is 1
	# Returns     	: array of nodes
	
ps_func.GetDuplicateNodeIndex objNode =
 
	# Description  	: Returns node index by ascending handle
	# Parameters 	: <node> object to test
	# Returns     	:  index
	
ps_func.GetPuppetsByNameCount puppetNode =
 
	# Description  	: Returns number of puppets of a certain name in scene

	# Parameters 	: 	<node>		puppetNode		:		puppetNode
	# Returns     	: integer
	
ps_func.applyFilter puppetNode filter nodeArray filter_options whichLayer s_frame e_frame =
 
	# Description  : applies a filter to nodes
	# Parameters   : 
						<node>			puppetNode		:		puppet node
						<string>		filter			:		which filter we are going to apply
						<array>			nodeArray		:		Array of nodes to apply filter to.
						<array>			filter_options	:		Array of filter options, since each filter could need different options, this is a array that changes from filter to filter
						<integer>		whichLayer		:		the layer we are applying the filter too
						<integer>		s_frame			:		start frame to start applying filter
						<integer>		e_frame			:		last frame to apply filter to.
	# Returns      : ok
	
ps_func.setConstraintFilters puppetNode src targ filt agentRoot barRol:undefined =
 
	# Description  : Creates all constraints specified. Src are the animatable nodes in the rig, targ are the mocap bones.
	# Parameters   : 
						<node>			puppetNode		:		puppet node
						<array>			src				:		Array of src nodes names (strings)		-- nodes to be constraint
						<array>			targ			:		Array of target nodes names (strings)	-- nodes we are constraining to
						<array>			filt			:		list of filters to apply (strings)
						<node>			agentRoot		:		root node of mocap agent (as there can be multiple)
						<progressbar>	barRol			:		rollout that holds the progressbar
	# Returns      : ok
	
ps_func.setPivotTangents ca frm:currenttime tType:"step" =
 
	# Description  : reset pivot keys to step tangents
	# Parameters   : 
						<integer>			frm			:	time to reset pivot at
						<custom attribute>	ca			:	custom attribute that holds the pivot keys.
						<name>				tType		:	tangent type
	# Returns      : ok
	
ps_func.initFoot ca frm:currenttime =
 
	# Description  	: initialises foot settings
	# Parameters 	: 
						<attribute>		ca		:		attribute that holds the pivot
	# Returns    	: ok
	
ps_func.movePivot ca minPos:undefined frm:undefined setTangents:true =
 
	# Description  	: moves pivot
	# Parameters 	: 
						<attribute>		ca				:		attribute that holds the pivot
						<boolean>		setTangents		:		if true, we set the tangents to step. This only needs to happen the last time move pivot is called, nto while interactively placing the pivot
	# Returns    	: ok
	
ps_func.snapPiv ca acceptHold:true frm:currenttime =
 
	# Description  	: snap pivot to a location (i.e. ankle)
	# Parameters 	: 
						<attribute>		ca		:		attribute that holds the pivot
	# Returns    	: ok
	
ps_func.pivStateChange ca state =
 
	# Description  	: when user clicks the pivot checkbox
	# Parameters 	: 
						<attribute>		ca		:		attribute that holds the pivot
						<boolean>		state	:		state of the pivot checkbox
	# Returns    	: ok
	
ps_func.pivTick ca =
 
	# Description  	: timer ticking while changing pivot
	# Parameters 	: 
						<attribute>		ca		:		attribute that holds the pivot
	# Returns    	: ok
	
ps_func.reset_pivot ca frm:currenttime =
 
	# Description  : reset pivot attributes to 0
	# Parameters   : 
						<integer>	frm		:	time to reset pivot at
						<custom attribute>	ca		:	custom attribute that holds the pivot keys.
	# Returns      : ok
	
ps_func.keyPivot ca frm:currenttime =
 
	# Description  : reset pivot attributes to 0
	# Parameters   : 
						<integer>	frm		:	time to reset pivot at
						<custom attribute>	ca		:	custom attribute that holds the pivot keys.
	# Returns      : ok
	
ps_func.snapToIK ca partID askToes:true firstNodeIndex:2 snapPos:false doRange:keyboard.SHIFTPressed quiet:false =
 
	# Description  : snaps FK legs to IK legs / spline (tail)
	# Parameters   : 
						<attribute>		ca		:	custom attribute
						<integer>		partID	:	number that identifies what bodypart we are working on
						<boolean>		askToes	:	if true ask to snap toes as well, useful since this function is also used by spline
						<integer>		firstNodeIndex	:	default is 2 because first fk node for legs is break-off node, but not for spline
						<boolean>		snapPos	:	if true, also snap position
						<boolean>		doRange	:	if true, convert for entire animation range
						<boolean>		quiet	:	if true, no messageboxes
	# Returns      : ok
	
ps_func.snapToFK ca partID useSwivelTarget:true doRange:keyboard.SHIFTPressed quiet:false =
 
	# Description  : snaps IK legs to FK legs
	# Parameters   : 
						<attribute>		ca		:	custom attribute
						<integer>		partID	:	number that identifies what bodypart we are working on
						<boolean>		useSwivelTarget:	true, uses swivel target, false uses angle spinner
						<boolean>		doRange	:	if true, convert for entire animation range
						<boolean>		quiet	:	if true, no messageboxes
	# Returns      : ok
	# Note		   :	There are two options. A leg with swivel target and one with swivel spinner.
						For the one with target we find 3 fk nodes and figure out which direction the swivel node should go.
						For the one with the swivel spinner we do almost the same thing accept we set an angle instead.
	
ps_func.getKeysInInterval kAr timeInterval =
 
	# Description  : Gets keys within a certain interval range
	# Parameters   : 	<array>			kAr				:		Array of keys
 						<interval>		timeInterval	:		time Interval to get keys of
	# Returns      : Array of key times
	
ps_func.getMultiplierCurve puppetNode layer:1 =
 
	# Description  : Finds the multiplier curve on a controller
	# Parameters   : 	<node>			puppetnode	:	puppetNode
	# Returns      : Multiplier_curve.controller
	
ps_func.getEaseCurve puppetNode returnSubAnim:false acTimeLine:undefined =
 
	# Description  : Finds the ease curve on a controller
	# Parameters   : 	<node>			puppetnode		:	puppetNode
						<boolean>		returnSubAnim	:	if true, return_ subAnim instead of controller. This is sometimes needed because the controller returns values in ticks or sometime (when curve editor has been opened)
						<integer>		acTimeLine		:	what timeline to get the easeCurve from
	# Returns      : ease_curve.controller
	
ps_func.checkForEaseCurve cont =
 
	# Description  : checks to see if an ease curve exists on a controller
	# Parameters   : 	<controller>	cont			:		controller that had the keys and that has a ease_curve applied
	# Returns      : 0 if no curves are found, 1 or higher if curves are found
	
ps_func.adjustKeyTimesForEase puppetNode keyTimes =
 
	# Description  : adjusts key times to compensate for ease_curve (so that they ease_curve effect is baked into key-times)
	# Parameters   : 	
						<array>			keyTimes		:		Array of keys times
	# Returns      : new Array of key times
	# Example: myKeys = ps_func.adjustKeyTimesForEase puppetNode kCont myKeys
	
ps_func.setORT cont type:#constant =
 
	# Description  : Sets out of ranges curves (important before resetting basePose , or create keys anywhere outside of the current animator loop)
	# Parameters   : 	<controller>		cont		:		controller to reset
						<name>				type		:		what to set the curves too
	# Returns      : ok
	
ps_func.collapseTime puppetNode nodeArray ca keyToKey:true bakeCA:false bakeWeight:true bakeMul:true toggleOnly:false =
 
	# Description  : collapses ease_curve effect into keys
	# Parameters   : 	<array>			nodeArray				:		Nodes to bake
						<array>			ca						:		attribute controllers
						<boolean>		keyToKey				:		if true, we only collapse where keys in either layer exist, if false, we key-per-frame
						<boolean>		bakeCA					:		if true, we also bake the custom attributes.
						<boolean>		toggleOnly				:		if true, we do not bake, but only toggle the easeCurve on/off
	# Returns      : ok
	# Note		   : We also need to bake attributes and weight/mul curves.
					 We also hijack this function to endable/disable timecurves
	
ps_func.resetPose nodeArray frm:0 noWarnings:false dontResetPuppetnode:false forceAbsoluteZero:false resetPos:true resetRot:true keyOnly:false resetORT:true resetScale:true activeLayerOnly:false addKey:true =
 
	# Description  : Resets transforms for certain nodes
	# Parameters   : 	<array>		nodeArray			:		Array of nodes
						<integer>	frm					:		time at which to reset the transform
						<boolean>	noWarnings			:		true will suspend any warnings
						<boolean>	dontResetPuppetnode :		if true, we do not reset any objects of class puppetNode
						<boolean>	forceAbsoluteZero	:		if true, make sure the values inside the xyz floats are zero.
						<boolean>	resetPos			:		if true, reset position
						<boolean>	resetRot			:		if true, reset rotation
						<boolean>	keyOnly				:		if true, we don't put a value of zero, instead we put the existing value (is more like bracket but then all layers).
						<boolean>	activeLayerOnly		:		if true, only zeros the active layer
						<boolean>	addKey				:		if true, use 'addKey' (which always sets a key, no matter if animate button is on or not)
	# Returns      : ok
	
ps_func.reSyncEaseCurve puppetNode =
 
	# Description  : reSync easeCurve_ to puppet for older characters (bugfix)
	# Parameters   : 
	# Returns      : ok
	
ps_func.debugCollapseLayer puppetNode nodeArray activeLayer bstart:animationrange.start.frame bend:animationrange.end.frame =
 
	# Description  : debug collapse
	# Parameters   : 	<array>			nodeArray				:		Nodes to bake
						<integer>		activeLayer				:		Layer to collapse
	# Returns      : ok
	
ps_func.collapseLayer puppetNode nodeArray activeLayer targetLayer:undefined bstart:animationrange.start.frame bend:animationrange.end.frame bakeTM:#() bFrame:undefined dontResetPuppetnode:false keyToKey:true respectLocks:true subtractPreviousLayers:false skipInstanceCurve:false TCBFlipFix:false wipePnode:false counterScalePos:false =
 
	# Description  : collapses one layer onto another
	# Parameters   : 	<array>			nodeArray				:		Nodes to bake
						<integer>		activeLayer				:		Layer to collapse
						<integer>		targetLayer				:		layer to collapse to
						<bstart>		float					:		start time to bake
						<bend>			float					:		end time
						<string>		bakeTM					:		which controllers to bake (PR - pos and rot, R - rot only etc.)
						<integer>		bFrame					:		baseFrame, to reset basePose
						<boolean>		subtractPreviousLayers	:		if true, we subtract the values of the all layers when pasting back, if false then we only subtract the base pose values. Used to import mocap relative to previous layer
						<boolean>		dontResetPuppetnode		:		if true, we do not reset the pose on puppetnodes
						<boolean>		keyToKey				:		if true, we only collapse where keys in either layer exist, if false, we key-per-frame
						<boolean>		respectLocks			:		if true, we respect the transform locks
						<boolean>		skipInstanceCurve		:		if true, we do not re-instance ease and mul curves. This useful when the layer that is collapsed is going to be deleted right away, i.e. mocap import and collapse layer.
						<boolean>		TCBFlipFix				:		if true, use TCB rotation flip fix, good for mocap, not good for collapsing bezier curves.
						<boolean>		wipePnode				:		if true, wipes the keys of the puppetNode, used for baking 'in-place' animation
						<boolean>		counterScalePos			:		if true, adjust position to counter scaling on puppetNode (this allows IK and Root to stay in the same position as it was before scaling)
	# Returns      : ok
	
ps_func.SetRelativeTM puppetNode nodes sTime eTime =
 
	# Description  : not really used, but this is example code how to set transform value relative to parent, even if constraints are used
	# Parameters   : 	
						<array>		nodes			:		Nodes to be copied
						<integer>	sTime			:		Frame to copy
						<integer>	eTime			:		Frame to copy too
	# Returns      : ok
	
ps_func.pasteRelativePose centerNode nodes sTime eTime respectLocks:true =
 
	# Description  : pastes relative pose
	# Parameters   : 	<node>		centerNode		:		Node the is the center of the pose (generally first child of puppetNode)
						<array>		nodes			:		Nodes to be copied
						<integer>	sTime			:		Frame to copy
						<integer>	eTime			:		Frame to copy too
						<boolean>	respectLocks	:		if true, it uses the transform locks to determine what to copy/paste
	# Returns      : ok
	# Note		   : Not sure if rotation constraints also need to use the exception code, for now it appears they do not...
					 We have to paste the pose a few times (pastePoseAmount) because unfortunatly our hierarchy can be so custom, that parents, children and constraints not always get copied in the right order
	
ps_func.setRigCallbacks nodeWithID setLayerDraw:true =
 
	# Description  : sets the proper callbacks for a rigged puppet
	# Parameters   : 	<node>			:		nodeWithID		:		Node that has the HUBID, ususally puppetTool modifier
						<boolean>		:		setLayerDraw	:		wheter to set the callbacks for layer info drawing (should NOT be set during rigging a new puppet!)
	# Returns      : ok
	
ps_func.changeEvalToAddLayer puppetNode aNodes setBool =
 
	# Description  : enables/disables controller evaluation when animations are used in clip editor and we add a layer
	# Parameters   : 
	# Returns      : ok
	
ps_func.instanceWeightControllers puppetNode aNodes layer forceUpdate:false tInd:undefined =
 
	# Description  	: instances all weight controllers to the puppetNode
	# Parameters 	: 	<boolean>		forceUpdate			:	if true, we refresh the puppet_controller no matter if it already existed (used by addAnimNodes)
						<integer>		tInd				:	index of timeline
	# Returns    	: 
	
ps_func.reFreshEaseControllerCurve theCurve sFrame:0 eFrame:100 centerKey:false =
 
	# Description  	: reFreshes keys on ease curve
	# Parameters 	: 
	# Returns    	: ok
	# Note			: 
	
ps_func.reFreshMultiplierControllerCurve theCurve sFrame:0 eFrame:100 =
 
	# Description  	: reFreshes keys on multiplier curve
	# Parameters 	: 
	# Returns    	: ok
	# Note			: 
	
ps_func.deleteEaseControllers puppetNode aNodes layer tm:true weightMul:true ca:true =
 
	# Description  	: removes all Ease controllers
	# Parameters 	: 
						<boolean>		tm			:		remove ease_curve of pos and rot				-- these options exist so that collapseLayer can delete the ease_curve only of the weight and mul curve
						<boolean>		weightMul	:		remove ease_curve of weight and mul_curve
						<boolean>		ca			:		remove ease_curve of attributes
	# Returns    	: ok
	
ps_func.delEaseCurves puppetNode delFromAnimNodes:true =
 
	# Description  :	removes ease curves from all layers
	# Parameters   : 	
						<node>		puppetNode				: 	puppet node
						<boolean>	deleteFromAnimNodes		:	if true, we delete the ease from anim Nodes, this should always happen, unless layer count is zero.
	# Returns      : 	ok
	
ps_func.reSyncCAEaseCurves puppetNode cas =
 
	# Description  :	fixes a bug in the attribute timelines and resyncs proper ease curve per timeline
	# Parameters   : 	
						<node>		puppetNode				: 	puppet node
						<attribute>	cas						:	attribute controllers
	# Returns      : 	ok
	
ps_func.instanceEaseControllers puppetNode aNodes layer refreshCurve:false tm:true weightMul:true ca:true =
 
	# Description  	: instances Ease controllers on all nodes and layers of puppet
	# Parameters 	: 
						<boolean>		tm			:		remove ease_curve of pos and rot				-- these options exist so that collapseLayer can delete the ease_curve only of the weight and mul curve
						<boolean>		weightMul	:		remove ease_curve of weight and mul_curve
						<boolean>		ca			:		remove ease_curve of attributes
						<boolean>		refreshCurve:		if true, we refresh the ease_curve to sync with timeline framerange.
	# Returns    	: ok
	# Note			: position and rotation curves are also instanced, so the same curve applies to rotation and position
					  Also, we need to apply the same curve on the custom attributes
	
ps_func.deleteMultiplierControllers puppetNode aNodes layer =
 
	# Description  	: removes all Multiplier controllers of a layer
	# Parameters 	: 
						<integer>		layer		:		which layer to work on
	# Returns    	: ok
	
ps_func.instanceMultiplierControllers puppetNode aNodes layer refreshCurve:false =
 
	# Description  	: instances all Multiplier controllers to the puppetNode
	# Parameters 	: 
						<integer>		layer		:		which layer to work on
						<boolean>		refreshCurve:		if true, we refresh the mul_curve to sync with timeline framerange.
	# Returns    	: ok
	# Note			: we do not apply multiplier curves onto attributes or weight controllers, however each layer can have a new multiplier curve
	
ps_func.instanceManager puppetNode aNodes layer iw:true ie:true im:true refreshMul:false refreshEase:false =
 
	# Description  	: Handles instancing for controllers. I.e. when animation is loaded, instanced controllers need to be restored.
	# Parameters 	: 					refreshMul/ease		:		if true, refresh the curve to match timeline frameRange.
	# Returns    	: ok
	# Note			: 	if clips are used, having the ps_changeEvaluating off for the clip controller would crash because updates would not happen correctly.
						So, we have to temporarly enable the evaluating of the clip controller here and disable it when we are done.
	
ps_func.ps_updateTimeRange =
 
	# Description  	: Updates the value in the time spinners, controlled by timechangecallback
	# Parameters 	: 
	# Returns    	: 
	
ps_func.getPoseNodes myNodes puppetRoot:undefined =
 
	# Description  : gets Nodes used in poses
	# Parameters   :  <array>		myNodes		:		nodes to search, usually hierarchyNodes
					 <node>			puppetRoot	:		if supplied, we check to see if any of the nodes is the puppetRoot and make sure we add it too.
	# Returns      : array of nodes
	
ps_func.getAnimNodesOfPoseNode pNode c =
 
	# Description  : gets the animatable nodes that belong to a poseNode
	# Parameters   : 				pNode	:		puppetNode
							<node>		c		:		node to search, usually a HUB, but can also be a digitHolder
	# Returns      : array of nodes
	

Functions_02.ms
ps_func2.isContInstanced cont layer =
 
	# Description  : Checks if a animation controller is instanced.
	# Parameters   : 
						<controller>		cont	:		must be list controller
	# Returns      : true if instanced, false if not
	
ps_func2.isLocked puppetNode layer =
 
	# Description  : Checks if a layer is locked
	# Parameters   : 
	# Returns      : true if locked
	
ps_func2.getPNodeFromMod mod =
 
	# Description  : finds node that is dependent on puppet tools modifier (used for floating rollouts)
	# Parameters   : 
						<modifier>		mod	:		puppet tools modifier (this)
	# Returns      : node
	# Note		   : We asume that only one puppetNode is a dependent node on the modifier, which should be true
	
ps_func2.renamePuppet puppetNode newName =
 
	# Description  : Renames a puppet
	# Parameters   : 
						<node>		puppetNode	:		puppet to rename
						<string>	newName		:		new name for puppet
	# Returns      : ok
	
ps_func2.makeLayerUnique puppetNode animNodes tInd layIndex =
 
	# Description  : makes layer unique if it's instanced
	# Parameters   : 	<node>		puppetNode		:		puppet node
						<array>		animNodes		:		all animation nodes in puppet
						<integer>	tInd			:		which timeline (index)
						<integer>	layIndex		:		index of layer to change
	# Returns      : ok
	
ps_func2.addNullToPuppet puppetNode anode =
 
	# Description  : add nulls to puppet, so it can get deleted when the puppet does
	# Parameters   : 
						<node>			puppetNode		:		puppet node
						<node>			anode			:		node to add
	# Returns      : ok
	
ps_func2.delKeysTime cont range =
 
	# Description  : delete keys of a controller for time range
	# Parameters   :  <controller>		cont	:		must be list controller
	# Returns      : ok
	
ps_func2.swapKeys source target range =
 
	# Description  : swap keys within a time range
	# Parameters   : 
						<controller>		source	:		source controller
						<controller>		target	:		target controller
						<interval>			range	:		time to swap keys for, keys otuside of range are left alone
	# Returns      : ok
	# Note		   : Both controllers must be the same class and must support keys directly (so XYZ controller must provide the indivual float controllers)
	
ps_func2.getDigitNodes aNodes ca rotMethod flip =
 
	# Description  : gathers the proper digit nodes for rotateDigit function
	# Parameters   : 
						<array>			aNodes		:		array of nodes (current selection of nodes)
						<attribute>		ca			:		custom attribute
						<integer>		rotMethod	:		1==bend, 2==splay
						<boolean>		flip		:		if true, splay and bend are flipped
	# Returns      : array of nodes
	
ps_func2.rotateDigits digitNodes rotMethod val PrevVal flip =
 
	# Description  : Rotates a selection of digits around certain axis
	# Parameters   : 
						<array>			digitNodes		:		array of nodes to be rotated
						<integer>		rotMethod		:		1==bend, 2==splay
						<float>			val				:		slider value
						<float>			PrevVal			:		previous slider value
						<boolean>		flip			:		if true, splay and bend are flipped
	# Returns      : 
	
ps_func2.faceNormal P1 P2 P3 =
 
	# Description  : gets normal from face.
	# Parameters   : 
						<node>			p1,p2,p3		:		3 nodes that make up the face
	# Returns      : matrix3
	
ps_func2.setMarkerFilters puppetNode pupNames markerNames filt offsets agentRoot AdjustBoneLength:false =
 
	# Description  : Creates all constraints specified for attacking rig to markers.
	# Parameters   : 
						<node>			puppetNode		:		puppet node
						<array>			pupNames		:		Array of puppet node names				-- nodes to be constraint
						<array>			markerNames		:		Array of marker node names (strings)	-- nodes we are constraining to
						<array>			filt			:		list of filters to apply (strings)
						<array>			offsets			:		Array of rotation offset (difference between bone and plane in default pose)
						<node>			agentRoot		:		root node of marker agent (as there can be multiple)
						<boolean>		AdjustBoneLength:		if true, adjust bone lengths to markers
	# Returns      : ok
	
ps_func2.setClipEditMode puppetNode bool setRange:true =
 
	# Description  : 	Switches puppet into cutscene mode or out of cutscene mode (clip edit mode)
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<boolean>	bool		:		true or false
						<boolean>	setRange	:		if true, we also update the max animationrange
	# Returns      : 	ok
	# Note		   :	If modify panel is open, it will not redraw the UI...
	
ps_func2.getClipcount puppetNode =
 
	# Description  : returns number of clips used in clipEditor (all tracks combined)
	# Parameters   : 
	# Returns      : integer
	
ps_func2.addAnimLayerPostRig puppetNode each quiet:false =
 
	# Description  : adds animation layers to a node after the rig was done (used by add custom anim nodes)
	# Parameters   : 
	# Returns      : ok
	
ps_func2.addnodeToCustomAnimList puppetNode nodesToReallyAdd linkToPnode:true =
 
	# Description  : adds node to custom anim node list (used by add custom anim nodes)
	# Parameters   : 
	# Returns      : ok
	
ps_func2.addnodeToCustomHierarchyList puppetNode nodeToAdd linkToNode:undefined =
 
	# Description  : adds node to custom hierarchy node list
	# Parameters   : 
	# Returns      : true or false
	
ps_func2.delNodeFromCustomAnimList puppetNode node index:unsupplied =
 
	# Description  : deletes a node from custom anim node list
	# Parameters   : 	<node>		puppetNode		:		puppetNode that holds the node in the custom animation node list
						<node>		node			:		node to remove from the list
						<integer>	index			:		if you don't know the node, but you know the index in the list, you may supply the index instead
															puppetNode must be selected and modify panel must be open to use index
	# Returns      : ok
	
ps_func2.delNodeFromCustomHierList puppetNode node index:unsupplied =
 
	# Description  : deletes a node from custom hier node list
	# Parameters   : 	<node>		puppetNode		:		puppetNode that holds the node in the custom hierarchy node list
						<node>		node			:		node to remove from the list
						<integer>	index			:		if you don't know the node, but you know the index in the list, you may supply the index instead
															puppetNode must be selected and modify panel must be open to use index
	# Returns      : ok
	
ps_func2.sortNodesForPose nodes =
 
	# Description  : sort nodes (semi hierarchical) for copying/ pasting / mirroring a pose
	# Parameters   : 
	# Returns      : sorted array
	# NOTE		   : This may also re-organize the puppetnode (and root node) so they are no longer garantueed to be at element 1 and 2
					 Keep that in mind for functions that need them at those elements!
	
ps_func2.copyRelativePose puppetNode centerNode nodes sTime buffer:undefined copyAttributes:true doSort:true doGC:true =
 
	# Description  : pastes relative pose
	# Parameters   : 	<node>		centerNode		:		Node the is the center of the pose (generally first child of puppetNode)
						<array>		nodes			:		Nodes to be copied
						<integer>	sTime			:		Frame to copy
						<modifier>	buffer			:		location of buffer (arrays) to store pose in
						<boolean>	copyAttributes	:		copy attributes, which should always be true, except when doing the subtract pose.
						<boolean>	doSort			:		if true, make an attempt to sort nodes by constraints
						<boolean>	doGC			:		if false, don't do GC
	# Returns      : ok
	# Note		   : Not sure if rotation constraints also need to use the exception code, for now it appears they do not...
					 We have to paste the pose a few times (pastePoseAmount) because unfortunatly our hierarchy can be so custom, that parents, children and constraints not always get copied in the right order
	
ps_func2.pasteRelativePose puppetNode nodes eTime respectLocks:true absolute:false pasteCA:true buffer:undefined dontSetPNodeRoot:false pastePoseAmount:5 dontSetPNode:false doGC:true useCopiedNodes:false =
 
	# Description  : pastes relative pose
	# Parameters   : 	
						<array>		nodes			:		Nodes to be copied, don't think this is used, but left in the function. It grab the nodes from buffer
						<integer>	eTime			:		Frame to paste too
						<boolean>	respectLocks	:		if true, it uses the transform locks to determine what to copy/paste
						<boolean>	absolute		:		if true, we copy a pose absolute, meaning we match the puppetNode and root to the pose before pasting.
						<boolean>	pasteCA			:		if true, paste attribute values
						<modifier>	buffer			:		location of buffer (arrays) to store pose in
						<boolean>	dontSetPNodeRoot:		if true, we do not set the puppetNode and Root transform. Used by In-place reset position of puppetNode
						<integer>	pastePoseAmount	:		paste threshold, because we cannot garantuee that the parents are always set before children, due to constraints.
						<boolean>	dontSetPNode	:		see above, rootRotOnly
						<boolean>	doGC			:		if false, don't do GC
						<boolean>	useCopiedNodes	:		if true, use the nodes as copied into the buffer, if false, use the provided 'nodes' array. This options is used by puppet_pose copy/paste
	# Returns      : ok
	# Note		   : Not sure if rotation constraints also need to use the exception code, for now it appears they do not...
					 We have to paste the pose a few times (pastePoseAmount) because unfortunatly our hierarchy can be so custom, that parents, children and constraints not always get copied in the right order
	
ps_func2.mirrorPose puppetNode iNodes eTime respectLocks:true pasteCA:true buffer:undefined quiet:false doSort:true pastePoseAmount:2 rotOnly:false doGC:true =
 
	# Description  : mirrors a pose
	# Parameters   : 	
						<array>		iNodes			:		Nodes to mirror to
						<integer>	eTime			:		Frame to paste too
						<boolean>	respectLocks	:		if true, it uses the transform locks to determine what to copy/paste
						<boolean>	pasteCA			:		if true, paste attribute values
						<modifier>	buffer			:		location of buffer (arrays) to store pose in
						<boolean>	quiet			:		if true, no messageboxes
						<boolean>	doSort			:		if true, attempts to sort nodes by hierarchy
						<integer>	pastePoseAmount	:		paste threshold, because we cannot garantuee that the parents are always set before children, due to constraints.
						<boolean>	rotOnly			:		if true, only mirror rotation no matter what the locks say. This can be useful to mirror fingers where you first want to mirror the rotation of the hand with 'rotOnly:true'
						<boolean>	doGC			:		if false, don't do GC
	# Returns      : ok
	# Note		   : Puppetshop_Helpers classes are ignored from mirroring at this time due to break-nodes moving the leg (see code below)
	
ps_func2.subtractPose puppetNode root_node nodes eTime respectLocks:true buffer:undefined subBasePose:true range:undefined =
 
	# Description  : substract a pose from a layer
	# Parameters   : 	
						<array>		nodes			:		Nodes to be copied
						<integer>	eTime			:		Frame to substract too
						<boolean>	respectLocks	:		if true, it uses the transform locks to determine what to copy/paste
						<modifier>	buffer			:		location of buffer (arrays) to store pose in
						<boolean>	subBasePose		:		if true, substract basePose
	# Returns      : ok
	
ps_func2.deletePuppet pNode =
 
	# Description  : substract a pose from a layer
	# Parameters   : 	
						<node>		pNode			:		puppetNode
	# Returns      : ok
	
ps_func2.checkForPuppetTrackview ignoreOpen:false =
 
	# Description  : Checks if the puppet trackview is open or not
	# Parameters   : 
	# Returns      : true if found, false if not
	
ps_func2.bakeSpineBones pNode spineNode puppetCont =
 
	# Description  : Bakes bend into spine bones and resets bend Ctrl
	# Parameters   : 
	# Returns      : ok
	
ps_func2.delLayerName puppetNode ind =
 
	# Description  : deletes the name of a layer
	# Parameters   : 
	# Returns      : ok
	
ps_func2.getActiveListController cont =
 
	# Description  : gets the active list controller out of nested list controllers
	# Parameters   : 	<controller>	cont		:	controller to start search with (position, rotation or scale)
	# Returns      : active list controller
	# Note		   : 
						1. Does not search puppet_float_lists (XYZ controller with lists on individual floats)
						2. is used to replace some code in controllerFunctions.ms in stdPlugs
	
ps_func2.getNestedPuppetControllers cont pConts:undefined =
 
	# Description  : gets all nested puppet controller from a controller (list)
	# Parameters   : 
	# Returns      : array of puppet_controllers
	
ps_func2.setActiveAnimation puppetNode ind animName:undefined setRange:true suspendRefresh:false gbc:true =
 
	# Description  : 	Switches to the correct timeline (automatically detects if timeline exists).
	# Parameters   : 	<node>		puppetNode	:		PuppetNode of the character we are working on
						<integer>	ind			:		index of the animation you wish to switch to
						<string>	animName	:		you may also provide an animation instead of an index.
						<boolean>	setRange	:		if true, update max timerange
						<boolean>	suspendRefresh:		if true, UI is not updated in setTimeLine function
						<boolean>	gbc			:		if true, setTimeline will do a garbage collection
	# Returns      : 	true is succesful, false if not
	
ps_func2.addClipLayersCAs clipCAs isClip:true =
 
	# Description  : Adds proper clip/track layer setup to rig attributes
	# Parameters   : 	<boolean>		isClip		:		if true the attributes are fed as clip controller, if false, they are fed as lists
	# Returns      : ok
	
ps_func2.addClipLayers puppetNode =
 
	# Description  : Adds proper clip/track layer setup to rig
	# Parameters   : 
	# Returns      : ok
	
ps_func2.addClip puppetNode row tInd =
 
	# Description  : adds clip to rig
	# Parameters   : 	
						<integer>		row			:		which row (we have 1-3 controllers in the list controller which act as different tracks or rows)
						<integer>		tInd		:		index of timeline clip we are adding
	# Returns      : ok
	
ps_func2.delClip puppetNode row clipInd =
 
	# Description  : delete clip from rig
	# Parameters   : 	
						<integer>		row			:		which row (we have 1-3 controllers in the list controller which act as different tracks or rows)
						<integer>		clipInd		:		index of clip we are deleting
	# Returns      : ok
	
ps_func2.clipDataToControllers puppetNode row offset scale clipIndex keepEnd sliceStart sliceEnd animIndex clipColor aNodes:undefined clipCas:undefined nodesToDisable:#() nodesToEnable:#() =
 
	# Description  	: 	takes the existing clipArray and dumps the info back into all controllers.
	# Parameters 	: 	
						Most parameters are indentified in the code below
	# Returns    	: 	ok
	
ps_func2.bakeClipSolution puppetNode sframe eframe quiet:false =
 
	# Description  : bake clip edit solution back to a keyed animation
	# Parameters   : 
						<node>		puppetNode	:		puppetNode of the character you want to bake
						<integer>	sframe		:		first frame of baking region
						<integer>	eframe		:		last frame to bake
						<boolean>	quiet		:		if true, no messageboxes will pop-up
	# Returns      : ok
	
ps_func2.getSelectedClipIndices clipArray t =
 
	# Description  : returns the selected clips indices
	# Parameters   : 	<array>		clipArray		:		array that has the clipEditor data
						<integer>	t				:		track ID (1 or 2)
	# Returns      : array:  #( #(row, clipIndex), #(row, clipIndex), ...  )
	
ps_func2.fixToe toe quiet:false =
 
	# Description  : Fixes old toes to stop instancing scale controller to prevent some save lock-ups
	# Parameters   : 	
						<node>			toe				:	toe node
	# Returns      : ok
	
ps_func2.PuppetPostFileOpen =
 
	# Description  : post file open callback function
	# Parameters   : 
	# Returns      : ok
	
ps_func2.distancePoint3 vec vec2 =
 
	# Description  : distance between 2 point3s
	# Parameters   : 	<point3>		vec		:	position A
						<point3>		vec2	:	position B
	# Returns      : float
	# Note		   : This is slower then calling the MXS 'distance' function
	
ps_func2.pointInSphere posSphere radius posPoint =
 
	# Description  : test if a point is in a sphere
	# Parameters   : 	<point3>		posSphere		:	position of sphere
						<float>			radius			:	radius of sphere
						<point3>		posPoint		:	position of point
	# Returns      : true or false
	
ps_func2.closestPointOnSphere posSphere radius posPoint sphereTM =
 
	# Description  : closestPointOnSphere
	# Parameters   : 	<point3>		posSphere		:	position of sphere
						<float>			radius			:	radius of sphere
						<point3>		posPoint		:	position of point
						<Matrix3>		sphereTM		:	transform of sphere
	# Returns      : point3
	
ps_func2.capsuleStartAndEnd capsule parTM:(matrix3 1)=
 
	# Description  : get start and end position from max geometry capsule
	# Parameters   : 	<node>		capsule		:	max geometry capsule
						<matrix3>	parTM		:	relative to TM
	# Returns      : #(start, end)
	
ps_func2.distancePointToLine A B C =
 
	# Description  : measure distance between a point and a line
	# Parameters   : 	<point3>		A		:	Line st