text:
import maya.cmds as cmds
import maya.api.OpenMaya as apiOpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import json
import os
import math
import sys
import re
import struct
from collections import OrderedDict
from copy import deepcopy
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx

######################################################
# PluginFunctions
######################################################
class PluginFunctions():

	######################################################
	# getAllNodesOfType
	######################################################
	@staticmethod
	def getAllNodesOfType(typeId):
		list = cmds.ls( type='transform', long=True )
		result = []
		for node in list:
			# find type attribute
			sphAttr = cmds.listAttr(node, string="SPH_Type")
			if sphAttr != None:
				sphtype = cmds.getAttr(node + ".SPH_Type")
				if typeId == sphtype:
					result.append(node)
		return result

	######################################################
	# getShape
	######################################################
	@staticmethod
	def getShape(nodeName):
		return cmds.listRelatives(nodeName, shapes=True, type="shape")

	######################################################
	# get quaternion of a transform node
	######################################################
	@staticmethod
	def getQuaternion(node):
		sel_list = apiOpenMaya.MSelectionList()
		sel_list.add(node)
		obj = sel_list.getDependNode(0)
		xform = apiOpenMaya.MFnTransform(obj)
		quat = xform.rotation(asQuaternion=True)
		quat.normalizeIt()
		return quat

	######################################################
	# get axis,angle of a transform node
	######################################################
	@staticmethod
	def getAxisAngle(node):
		sel_list = apiOpenMaya.MSelectionList()
		sel_list.add(node)
		obj = sel_list.getDependNode(0)
		xform = apiOpenMaya.MFnTransform(obj)
		quat = xform.rotation(asQuaternion=True)
		quat.normalizeIt()
		aa = quat.asAxisAngle()
		return ([aa[0][0], aa[0][1], aa[0][2]], aa[1])

	@staticmethod
	def createFloatAttr(longName, shortName, defaultValue, softMin, softMax, minValue=0, maxValue=1000000):
		nAttr = OpenMaya.MFnNumericAttribute()
		newAttr = nAttr.create( longName, shortName, OpenMaya.MFnNumericData.kFloat, defaultValue )
		nAttr.setStorable(1)
		nAttr.setMin(minValue)
		nAttr.setMax(maxValue)
		nAttr.setSoftMin(softMin)
		nAttr.setSoftMax(softMax)
		return newAttr

	@staticmethod
	def createIntAttr(longName, shortName, defaultValue, softMin, softMax, minValue=0, maxValue=1000000):
		nAttr = OpenMaya.MFnNumericAttribute()
		newAttr = nAttr.create( longName, shortName, OpenMaya.MFnNumericData.kInt, defaultValue )
		nAttr.setStorable(1)
		nAttr.setMin(minValue)
		nAttr.setMax(maxValue)
		nAttr.setSoftMin(softMin)
		nAttr.setSoftMax(softMax)
		return newAttr

	@staticmethod
	def createBoolAttr(longName, shortName, defaultValue):
		nAttr = OpenMaya.MFnNumericAttribute()
		newAttr = nAttr.create( longName, shortName, OpenMaya.MFnNumericData.kBoolean, defaultValue )
		nAttr.setStorable(1)
		return newAttr

	@staticmethod
	def createVec3Attr(longName, shortName, defaultValue):
		nAttr = OpenMaya.MFnNumericAttribute()
		newAttr = nAttr.create( longName, shortName, OpenMaya.MFnNumericData.k3Float )
		nAttr.setDefault(defaultValue[0], defaultValue[1], defaultValue[2])
		nAttr.setStorable(1)
		return newAttr

	@staticmethod
	def createColorAttr(longName, shortName, defaultValue):
		nAttr = OpenMaya.MFnNumericAttribute()
		newAttr = nAttr.createColor( longName, shortName )
		nAttr.setDefault(defaultValue[0], defaultValue[1], defaultValue[2])
		nAttr.setStorable(1)
		return newAttr

	@staticmethod
	def createVec3iAttr(longName, shortName, defaultValue):
		nAttr = OpenMaya.MFnNumericAttribute()
		newAttr = nAttr.create( longName, shortName, OpenMaya.MFnNumericData.k3Int )
		nAttr.setDefault(defaultValue[0], defaultValue[1], defaultValue[2])
		nAttr.setStorable(1)
		return newAttr

	@staticmethod
	def createEnumAttr(longName, shortName, defaultValue, enumList):
		eAttr = OpenMaya.MFnEnumAttribute()
		newAttr = eAttr.create( longName, shortName, defaultValue)
		i=0
		for item in enumList:
			eAttr.addField(item, i)
			i+=1
		eAttr.setStorable(1)
		return newAttr

	@staticmethod
	def createStringAttr(longName, shortName, defaultValue):
		nAttr = OpenMaya.MFnTypedAttribute()
		sData = OpenMaya.MFnStringData()
		default = sData.create(defaultValue)
		newAttr = nAttr.create( longName, shortName, OpenMaya.MFnData.kString, default )
		nAttr.setStorable(1)
		return newAttr

	######################################################
	# createBoolParam
	######################################################
	@staticmethod
	def createBoolParam(name, label, description, defaultValue):
		param = {
				"type": "bool",
				"name": name,
				"label": label,
				"description": description,
				"default": defaultValue,
				"value": defaultValue,
				"ctrlId": None
			}
		return param

	######################################################
	# createFloatParam
	######################################################
	@staticmethod
	def createFloatParam(name, label, description, defaultValue, minValue, maxValue, fieldMin=0, fieldMax=1000000):
		param = {
				"type": "float",
				"name": name,
				"label": label,
				"description": description,
				"default": defaultValue,
				"value": defaultValue,
				"min": minValue,
				"max": maxValue,
				"fieldMin": fieldMin,
				"fieldMax": fieldMax,
				"ctrlId": None
			}
		return param

	######################################################
	# createVec3Param
	######################################################
	@staticmethod
	def createVec3Param(name, label, description, defaultValue):
		param = {
				"type": "vec3",
				"name": name,
				"label": label,
				"description": description,
				"default": defaultValue,
				"value": defaultValue,
				"ctrlId": None
			}
		return param

	######################################################
	# createColorParam
	######################################################
	@staticmethod
	def createColorParam(name, label, description, defaultValue):
		param = {
				"type": "color",
				"name": name,
				"label": label,
				"description": description,
				"default": defaultValue,
				"value": defaultValue,
				"ctrlId": None
			}
		return param

	######################################################
	# createVec3iParam
	######################################################
	@staticmethod
	def createVec3iParam(name, label, description, defaultValue):
		param = {
				"type": "vec3i",
				"name": name,
				"label": label,
				"description": description,
				"default": defaultValue,
				"value": defaultValue,
				"ctrlId": None
			}
		return param

	######################################################
	# createIntParam
	######################################################
	@staticmethod
	def createIntParam(name, label, description, defaultValue, minValue, maxValue, fieldMin=0, fieldMax=1000000):
		param = {
				"type": "int",
				"name": name,
				"label": label,
				"description": description,
				"default": defaultValue,
				"value": defaultValue,
				"min": minValue,
				"max": maxValue,
				"fieldMin": fieldMin,
				"fieldMax": fieldMax,
				"ctrlId": None
			}
		return param

	######################################################
	# createStringParam
	######################################################
	@staticmethod
	def createStringParam(name, label, description, defaultValue):
		param = {
				"type": "string",
				"name": name,
				"label": label,
				"description": description,
				"default": defaultValue,
				"value": defaultValue,
				"ctrlId": None
			}
		return param

	######################################################
	# createEnumParam
	######################################################
	@staticmethod
	def createEnumParam(name, label, description, defaultValue, enumList):
		param = {
				"type": "enum",
				"name": name,
				"label": label,
				"description": description,
				"default": defaultValue,
				"value": defaultValue,
				"enumList": enumList,
				"ctrlId": None
			}
		return param

	######################################################
	# getSelectedTransforms
	# get all selected transform nodes recursively
	######################################################
	@staticmethod
	def getSelectedTransforms():
		list = cmds.ls( selection=True, type='transform', long=True )
		transformNodes = []
		for item in list:
			transformNodes.append(item)
			children = cmds.listRelatives(item, ad=True, type="transform")
			if children == None:
				continue
			for child in children:
				transformNodes.append(child)
		return transformNodes

######################################################
# createCircularEmitter
######################################################
class createCircularEmitterCmd(OpenMayaMPx.MPxCommand):
	s_name = "createCircularEmitter"

	def __init__(self):
		OpenMayaMPx.MPxCommand.__init__(self)

	@staticmethod
	def creator():
		return createCircularEmitterCmd()

	def doIt(self, args):
		self.redoIt()

	def redoIt(self):
		self.cyl = cmds.polyCylinder(name="CircularEmitter", r=1, h=0.2, sx=20, sy=1, sz=1, ax=[1,0,0], rcp=0, cuv=3, ch=1)
		cmds.delete(ch=True)
		node = self.cyl[0]
		cmds.delete(node + ".f[40:59]")

		cmds.scale(0.5, 0.5, 0.5, self.cyl[0])

		# set type
		cmds.addAttr(node, longName="SPH_Type", niceName="type",dt="string", hidden=True)
		cmds.setAttr((node + '.SPH_Type'), "CircularEmitter", type="string")

		# velocity
		cmds.addAttr(node, longName="SPH_velocity", niceName="velocity", at="float");
		cmds.setAttr((node + '.SPH_velocity'), 1.0)

		# start time
		cmds.addAttr(node, longName="SPH_startTime", niceName="start time", at="float");
		cmds.setAttr((node + '.SPH_startTime'), 0.0)

		# velocity
		cmds.addAttr(node, longName="SPH_endTime", niceName="end time", at="float");
		cmds.setAttr((node + '.SPH_endTime'), 100000.0)

		# fluid id
		cmds.addAttr(node, longName="SPH_fluidId", niceName="Fluid id", dt="string")
		cmds.setAttr((node + '.SPH_fluidId'), "Fluid", type="string")

	def undoIt(self):
		pass

	def isUndoable(self):
		return True

######################################################
# RectangularEmitter
######################################################
class createRectangularEmitterCmd(OpenMayaMPx.MPxCommand):
	s_name = "createRectangularEmitter"

	def __init__(self):
		OpenMayaMPx.MPxCommand.__init__(self)

	@staticmethod
	def creator():
		return createRectangularEmitterCmd()

	def doIt(self, args):
		self.redoIt()

	def redoIt(self):
		self.cube = cmds.polyCube(name="RectangularEmitter", w=0.2, h=1, d=1, sx=1, sy=1, sz=1, ch=1)
		cmds.delete(ch=True)
		node = self.cube[0]
		cmds.delete(node + ".f[4]")

		# set type
		cmds.addAttr(node, longName="SPH_Type", niceName="type",dt="string", hidden=True)
		cmds.setAttr((node + '.SPH_Type'), "RectangularEmitter", type="string")

		# velocity
		cmds.addAttr(node, longName="SPH_velocity", niceName="velocity", at="float");
		cmds.setAttr((node + '.SPH_velocity'), 1.0)

		# start time
		cmds.addAttr(node, longName="SPH_startTime", niceName="start time", at="float");
		cmds.setAttr((node + '.SPH_startTime'), 0.0)

		# velocity
		cmds.addAttr(node, longName="SPH_endTime", niceName="end time", at="float");
		cmds.setAttr((node + '.SPH_endTime'), 100000.0)

		# fluid id
		cmds.addAttr(node, longName="SPH_fluidId", niceName="Fluid id", dt="string")
		cmds.setAttr((node + '.SPH_fluidId'), "Fluid", type="string")

	def undoIt(self):
		pass

	def isUndoable(self):
		return True

######################################################
# AnimationField
######################################################
class createAnimationFieldCmd(OpenMayaMPx.MPxCommand):
	s_name = "createAnimationField"
	s_shortTypeFlag = '-s'
	s_longTypeFlag = '-shape'

	def __init__(self):
		OpenMayaMPx.MPxCommand.__init__(self)

	@staticmethod
	def syntaxCreator():
		syntax = OpenMaya.MSyntax()

		syntax.addFlag( createAnimationFieldCmd.s_shortTypeFlag, createAnimationFieldCmd.s_longTypeFlag, OpenMaya.MSyntax.kLong )

		return syntax

	@staticmethod
	def creator():
		return createAnimationFieldCmd()

	def doIt(self, args):
		argData = OpenMaya.MArgParser( self.syntax(), args )
		self.shapeType = 0
		if argData.isFlagSet( createAnimationFieldCmd.s_shortTypeFlag ):
			self.shapeType = argData.flagArgumentInt(createAnimationFieldCmd.s_shortTypeFlag, 0)
		self.redoIt()

	def redoIt(self):
		poly = ""
		if self.shapeType == 1:
			poly = cmds.polySphere(name="AnimationField", r=1, sx=20, sy=20, ax=[0,1,0], cuv=2, ch=1)
			cmds.expression(s=poly[0] + ".scaleY=" + poly[0] + ".scaleZ=" + poly[0] + ".scaleX;", o=poly[0])
		elif self.shapeType == 2:
			poly = cmds.polyCylinder(name="AnimationField", r=1, h=1, sx=20, sy=1, ax=[1,0,0], cuv=3, rcp=0, ch=1)
			cmds.expression(s=poly[0] + ".scaleZ=" + poly[0] + ".scaleY;", o=poly[0])
		else:
			poly = cmds.polyCube(name="AnimationField", w=1, h=1, d=1, sx=1, sy=1, sz=1, ch=1)
		cmds.delete(ch=True)
		node = poly[0]

		# set type
		cmds.addAttr(node, longName="SPH_shapeType", niceName="shape type", at="long", hidden=True)
		cmds.setAttr((node + '.SPH_shapeType'), self.shapeType)

		# set type
		cmds.addAttr(node, longName="SPH_Type", niceName="type",dt="string", hidden=True)
		cmds.setAttr((node + '.SPH_Type'), "AnimationField", type="string")

		# set particle field
		cmds.addAttr(node, longName="SPH_particleField", niceName="paricle field",dt="string")
		cmds.setAttr((node + '.SPH_particleField'), "velocity", type="string")

		# set expression
		cmds.addAttr(node, longName="SPH_expressionX", niceName="expression - x",dt="string")
		cmds.setAttr((node + '.SPH_expressionX'), "", type="string")

		cmds.addAttr(node, longName="SPH_expressionY", niceName="expression - y",dt="string")
		cmds.setAttr((node + '.SPH_expressionY'), "", type="string")

		cmds.addAttr(node, longName="SPH_expressionZ", niceName="expression - z",dt="string")
		cmds.setAttr((node + '.SPH_expressionZ'), "", type="string")

	def undoIt(self):
		pass

	def isUndoable(self):
		return True

######################################################
# convertToFluid
#
# Converts a list of transform nodes to fluid models.
# Only nodes with a shape are converted.
######################################################
class convertToFluidCmd(OpenMayaMPx.MPxCommand):
	s_name = "convertToFluid"

	def __init__(self):
		OpenMayaMPx.MPxCommand.__init__(self)

	@staticmethod
	def creator():
		return convertToFluidCmd()

	def doIt(self, args):
		self.redoIt()

	def redoIt(self):
		nodes = PluginFunctions.getSelectedTransforms()
		self.convertToFluid(nodes)

	def convertToFluid(self, nodes):
		for node in nodes:
			shapeNode = PluginFunctions.getShape(node)
			if shapeNode != None:
				lst = cmds.listRelatives(node, children=True, type='SPHFluidNode'  )
				if (lst == None):
					cmds.createNode("SPHFluidNode", name="SPH_Fluid", parent=node)
				else:
					print("The node " + node + " is already an SPH fluid.")

######################################################
# convertToRigidBody
#
# Converts a list of transform nodes to rigid bodies.
# Only nodes with a shape are converted.
######################################################
class convertToRigidBodiesCmd(OpenMayaMPx.MPxCommand):
	s_name = "convertToRigidBodies"

	def __init__(self):
		OpenMayaMPx.MPxCommand.__init__(self)

	@staticmethod
	def creator():
		return convertToRigidBodiesCmd()

	def doIt(self, args):
		self.redoIt()

	def redoIt(self):
		nodes = PluginFunctions.getSelectedTransforms()
		self.convertToRigidBody(nodes)

	def convertToRigidBody(self, nodes):
		for node in nodes:
			shapeNode = PluginFunctions.getShape(node)
			if shapeNode != None:
				lst = cmds.listRelatives(node, children=True, type='SPHRigidBodyNode'  )
				if (lst == None):
					cmds.createNode("SPHRigidBodyNode", name="SPH_Rigid_Body", parent=node)
				else:
					print("The node " + node + " is already an SPH rigid body.")

######################################################
# saveModel
######################################################
class saveModelCmd(OpenMayaMPx.MPxCommand):
	s_name = "saveModel"

	def __init__(self):
		OpenMayaMPx.MPxCommand.__init__(self)

	@staticmethod
	def creator():
		return saveModelCmd()

	def doIt(self, args):
		self.redoIt()

	def redoIt(self):
		sphConfigList = cmds.ls( type='SPHConfigurationNode', long=True )
		if len(sphConfigList) == 0:
			cmds.warning("Not saved since no SPH configuration node was found.")
			return

		if not cmds.pluginInfo("objExport", query=True, loaded=True):
			cmds.loadPlugin("objExport")

		fileName = cmds.fileDialog2(ff="*.json", fm=0, dir="")
		scenePath = os.path.dirname(fileName[0])

		scene=self.generateScene(scenePath)
		if scene == None:
			return

		f = open(fileName[0], 'w')
		json_str = json.dumps(scene, sort_keys=True,indent=4, separators=(',', ': '))
		f.write(json_str)
		f.close()

	def isUndoable(self):
		return False

	######################################################
	# openFluidIdDialog
	######################################################
	def openFluidIdDialog(self):
		sphConfigList = cmds.ls( type='SPHConfigurationNode', long=False )

		cmds.columnLayout( adjustableColumn=True, columnOffset=["both", 10], rowSpacing=10, columnAlign="center" )

		cmds.textScrollList("SPHFluidIdList", numberOfRows=8, allowMultiSelection=False,
				append=sphConfigList,
				selectItem=sphConfigList[0], showIndexedItem=1)
		cmds.rowLayout(numberOfColumns=2)
		cmds.button("Ok", c='cmds.layoutDialog( dismiss="Ok " + cmds.textScrollList("SPHFluidIdList",q=True,selectItem=True)[0]  )' )
		cmds.button("Cancel", c='cmds.layoutDialog( dismiss="Cancel" )')

	######################################################
	# generate scene
	######################################################
	def generateScene(self, scenePath):
		scene = OrderedDict()
		scene['FluidModels'] = []
		scene['RigidBodies'] = []
		scene['Emitters'] = []
		scene['AnimationFields'] = []
		scene['Materials'] = []
		scene['Configuration'] = OrderedDict()

		sphConfigList = cmds.ls( type='SPHConfigurationNode', long=True )
		sphConfig = ""
		if len(sphConfigList) == 0:
			cmds.warning("Not saved since no SPH configuration node was found.")
			return None
		elif len(sphConfigList) > 1:
			sphConfig = sphConfigList[0]
			res = cmds.layoutDialog(ui=self.openFluidIdDialog)
			if res == "Cancel":
				return None
			else:
				sphConfig = res[3:]
		else:
			sphConfig = sphConfigList[0]

			#cmds.warning("More than one SPH configuration node was found using " + sphConfigList[0] + ".")

		attributes = cmds.listAttr(sphConfig, string="SPH_*", sn=False)

		for attr in attributes:
			if cmds.getAttr(sphConfig + "." + attr, type=True) == "float3":
				value = cmds.getAttr(sphConfig + "." + attr)[0]
			elif cmds.getAttr(sphConfig + "." + attr, type=True) == "long3":
				value = cmds.getAttr(sphConfig + "." + attr)[0]
			else:
				value = cmds.getAttr(sphConfig + "." + attr)

			# avoid to write child attributes
			parent = cmds.attributeQuery( attr, node=sphConfig, listParent=True )
			if parent == None:
				scene["Configuration"][attr[4:]] = value

		fluidConfigList = cmds.ls( type='SPHFluidConfigurationNode', long=False )
		if len(fluidConfigList) == 0:
			cmds.warning("Not saved since no fluid material node was found.")
			return

		for fluid in fluidConfigList:
			attributes = cmds.listAttr(fluid, string="SPH_*", sn=False)
			mat = OrderedDict()
			mat['id'] = fluid
			for attr in attributes:
				if cmds.getAttr(fluid + "." + attr, type=True) == "float3":
					value = cmds.getAttr(fluid + "." + attr)[0]
				elif cmds.getAttr(fluid + "." + attr, type=True) == "long3":
					value = cmds.getAttr(fluid + "." + attr)[0]
				else:
					value = cmds.getAttr(fluid + "." + attr)
				mat[attr[4:]] = value
			scene["Materials"].append(mat)

		rigidBodyList = cmds.ls( type='SPHRigidBodyNode', long=False )
		for rb in rigidBodyList:
			self.addRigidBody(scene, rb, scenePath)

		fluidList = cmds.ls( type='SPHFluidNode', long=False )
		for fluid in fluidList:
			self.addFluid(scene, fluid, scenePath)

		emitters = PluginFunctions.getAllNodesOfType("RectangularEmitter")
		for emitter in emitters:
			self.addRectangularEmitter(sphConfig, scene, emitter, scenePath)

		emitters = PluginFunctions.getAllNodesOfType("CircularEmitter")
		for emitter in emitters:
			self.addCircularEmitter(sphConfig, scene, emitter, scenePath)

		animFields = PluginFunctions.getAllNodesOfType("AnimationField")
		for animField in animFields:
			self.addAnimationField(sphConfig, scene, animField, scenePath)

		return scene

	######################################################
	# getCurrentParticleRadius
	######################################################
	def getCurrentParticleRadius(self, sphConfig):
		return cmds.getAttr(sphConfig + ".particleRadius")

	######################################################
	# add rigid bodies
	######################################################
	def addRigidBody(self, scene, rbNode, scenePath):

		# export geometry
		tr = cmds.listRelatives( rbNode, allParents=True )
		cmds.select(tr, replace=True)

		# export geometry
		polyTri = cmds.polyTriangulate()
		name = cmds.ls( selection=True, type='transform', long=False )[0]
		fileName = os.path.join(scenePath, "rb_" + name + ".obj")
		cmds.file(fileName, force=True, options="groups=0;ptgroups=0;materials=0;smoothing=0;normals=0", pr=True, exportSelected=True, type="OBJexport")
		cmds.delete(polyTri)

		attributes = cmds.listAttr(rbNode, string="SPH_*", sn=False)
		rb = OrderedDict()
		for attr in attributes:
			if cmds.getAttr(rbNode + "." + attr, type=True) == "float3":
				value = cmds.getAttr(rbNode + "." + attr)[0]
			elif cmds.getAttr(rbNode + "." + attr, type=True) == "long3":
				value = cmds.getAttr(rbNode + "." + attr)[0]
			else:
				value = cmds.getAttr(rbNode + "." + attr)

			# avoid to write child attributes
			parent = cmds.attributeQuery( attr, node=rbNode, listParent=True )
			if parent == None:
				rb[attr[4:]] = value

		rb['translation'] = [0,0,0]
		rb['rotationaxis'] = [1,0,0]
		rb['rotationangle'] = 0.0
		rb['scale'] = [1,1,1]
		rb['geometryFile'] = "rb_" + name + ".obj"

		scene['RigidBodies'].append(rb)

		#color = cmds.getAttr(rbNode + ".SPH_color")[0]
		#color = color + (1.0,)

	######################################################
	# add fluid
	######################################################
	def addFluid(self, scene, fluidNode, scenePath):

		# export geometry
		tr = cmds.listRelatives( fluidNode, allParents=True )
		cmds.select(tr, replace=True)

		particleFile = cmds.getAttr(fluidNode + ".particleFile")
		name = ""
		if (particleFile == ""):
			polyTri = cmds.polyTriangulate()
			name = cmds.ls( selection=True, type='transform', long=False )[0]
			fileName = os.path.join(scenePath, "fluid_" + name + ".obj")
			cmds.file(fileName, force=True, options="groups=0;ptgroups=0;materials=0;smoothing=0;normals=0", pr=True, exportSelected=True, type="OBJexport")
			cmds.delete(polyTri)

		attributes = cmds.listAttr(fluidNode, string="SPH_*", sn=False)
		fluid = OrderedDict()
		for attr in attributes:
			if cmds.getAttr(fluidNode + "." + attr, type=True) == "float3":
				value = cmds.getAttr(fluidNode + "." + attr)[0]
			elif cmds.getAttr(fluidNode + "." + attr, type=True) == "long3":
				value = cmds.getAttr(fluidNode + "." + attr)[0]
			else:
				value = cmds.getAttr(fluidNode + "." + attr)

			# avoid to write child attributes
			parent = cmds.attributeQuery( attr, node=fluidNode, listParent=True )
			if parent == None:
				fluid[attr[4:]] = value

		if (particleFile == ""):
			fluid['particleFile'] = "fluid_" + name + ".obj"
		fluid['translation'] = [0,0,0]
		fluid['rotationaxis'] = [1,0,0]
		fluid['rotationangle'] = 0.0
		fluid['scale'] = [1,1,1]

		scene['FluidModels'].append(fluid)

	######################################################
	# add rectangular emitter
	######################################################
	def addRectangularEmitter(self, sphConfig, scene, node, scenePath):

		t = cmds.xform(node, query=True, t=True, ws=True)
		s = cmds.xform(node, query=True, s=True, ws=True)

		# get particleRadius
		radius = self.getCurrentParticleRadius(sphConfig)
		diam = 2.0 * radius
		s[1] -= 2.0*diam
		s[2] -= 2.0*diam

		axisAngle = PluginFunctions.getAxisAngle(node)

		startTime = cmds.getAttr(node + ".SPH_startTime")
		endTime = cmds.getAttr(node + ".SPH_endTime")
		velocity = cmds.getAttr(node + ".SPH_velocity")
		id = cmds.getAttr(node + ".SPH_fluidId")
		emitter = {
				'id': id,
				'width': int(s[2]/diam),
				'height': int(s[1]/diam),
				'translation': t,
				'rotationAxis': axisAngle[0],
				'rotationAngle': axisAngle[1],
				'emitStartTime': startTime,
				'emitEndTime': endTime,
				'velocity' : velocity,
				'type' : 0
			}

		scene['Emitters'].append(emitter)

	######################################################
	# add circular emitter
	######################################################
	def addCircularEmitter(self, sphConfig, scene, node, scenePath):

		t = cmds.xform(node, query=True, t=True, ws=True)
		s = cmds.xform(node, query=True, s=True, ws=True)

		# get particleRadius
		radius = self.getCurrentParticleRadius(sphConfig)
		s[1] -= 2.0*radius

		axisAngle = PluginFunctions.getAxisAngle(node)

		startTime = cmds.getAttr(node + ".SPH_startTime")
		endTime = cmds.getAttr(node + ".SPH_endTime")
		velocity = cmds.getAttr(node + ".SPH_velocity")
		id = cmds.getAttr(node + ".SPH_fluidId")
		emitter = {
				'id': id,
				'width': int(s[1]/radius),
				'translation': t,
				'rotationAxis': axisAngle[0],
				'rotationAngle': axisAngle[1],
				'emitStartTime': startTime,
				'emitEndTime': endTime,
				'velocity' : velocity,
				'type' : 1
			}

		scene['Emitters'].append(emitter)

	######################################################
	# add animation field
	######################################################
	def addAnimationField(self, sphConfig, scene, node, scenePath):

		t = cmds.xform(node, query=True, t=True, ws=True)
		s = cmds.xform(node, query=True, s=True, ws=True)
		axisAngle = PluginFunctions.getAxisAngle(node)

		particleField = cmds.getAttr(node + ".SPH_particleField")
		shapeType = cmds.getAttr(node + ".SPH_shapeType")
		expression_x = cmds.getAttr(node + ".SPH_expressionX")
		expression_y = cmds.getAttr(node + ".SPH_expressionY")
		expression_z = cmds.getAttr(node + ".SPH_expressionZ")

		animField = {
				'particleField': particleField,
				'translation': t,
				'rotationAxis': axisAngle[0],
				'rotationAngle': axisAngle[1],
				'scale': s,
				'shapeType': shapeType,
				'expression_x' : expression_x,
				'expression_y' : expression_y,
				'expression_z' : expression_z
			}

		scene['AnimationFields'].append(animField)

def addAttributesToSPHNode(node):
	# add attributes
	for key in node.sphParameters:
		params = node.sphParameters[key]
		for param in params:
			paramType = param["type"]
			paramName = param["name"]
			paramLabel = param["label"]
			if paramType == "bool":
				attr = PluginFunctions.createBoolAttr("SPH_" + paramName, paramName, param["value"])
				node.addAttribute( attr )
			elif paramType == "float":
				attr = PluginFunctions.createFloatAttr("SPH_" + paramName, paramName, param["value"], param["min"], param["max"], param["fieldMin"], param["fieldMax"])
				node.addAttribute( attr )
			elif paramType == "int":
				attr = PluginFunctions.createIntAttr("SPH_" + paramName, paramName, param["value"], param["min"], param["max"], param["fieldMin"], param["fieldMax"])
				node.addAttribute( attr )
			elif paramType == "vec3":
				attr = PluginFunctions.createVec3Attr("SPH_" + paramName, paramName, param["value"])
				node.addAttribute( attr )
			elif paramType == "color":
				attr = PluginFunctions.createColorAttr("SPH_" + paramName, paramName, param["value"])
				node.addAttribute( attr )
			elif paramType == "vec3i":
				attr = PluginFunctions.createVec3iAttr("SPH_" + paramName, paramName, param["value"])
				node.addAttribute( attr )
			elif paramType == "enum":
				attr = PluginFunctions.createEnumAttr("SPH_" + paramName, paramName, param["value"], param["enumList"])
				node.addAttribute( attr )
			elif paramType == "string":
				attr = PluginFunctions.createStringAttr("SPH_" + paramName, paramName, param["value"])
				node.addAttribute( attr )

# Node definition
class SPHConfigurationNode(OpenMayaMPx.MPxLocatorNode):
	kPluginNodeId = OpenMaya.MTypeId(0x90000)
	kPluginNodeTypeName = "SPHConfigurationNode"

	# class variables
	input = OpenMaya.MObject()
	dataAttr = OpenMaya.MObject()
	sphParameters = OrderedDict()

	def __init__(self):
		OpenMayaMPx.MPxLocatorNode.__init__(self)

	def postConstructor(self):
		OpenMayaMPx.MPxLocatorNode.postConstructor(self)

	# initializer
	@staticmethod
	def initialize():
		SPHConfigurationNode.initParameters()
		addAttributesToSPHNode(SPHConfigurationNode)

	# creator
	@staticmethod
	def creator():
		return OpenMayaMPx.asMPxPtr( SPHConfigurationNode() )

	def compute(self,plug,dataBlock):
		# if ( plug == SPHConfigurationNode.output ):
				# dataHandle = dataBlock.inputValue( SPHConfigurationNode.input )

				# inputFloat = dataHandle.asFloat()
				# result = math.sin( inputFloat ) * 10.0
				# outputHandle = dataBlock.outputValue( SPHConfigurationNode.output )
				# outputHandle.setFloat( result )
				# dataBlock.setClean( plug )

		return OpenMaya.kUnknownParameter

	######################################################
	# initParameters
	######################################################
	@staticmethod
	def initParameters():
		SPHConfigurationNode.sphParameters["General"] = [
			PluginFunctions.createBoolParam("pause", "Pause", "Pause simulation after loading.", True),
			PluginFunctions.createFloatParam("timeStepSize", "Time step size", "Time step size", 0.001, 0.00001, 1.0),
			PluginFunctions.createFloatParam("pauseAt", "Pause simulation at", "Pause simulation at the given time. When the value is negative, the simulation is not paused.", -1, -1, 100, -1),
			PluginFunctions.createFloatParam("stopAt", "Stop simulation at", "Stop simulation at the given time. When the value is negative, the simulation is not stopped.", -1, -1, 100, -1)
		]
		SPHConfigurationNode.sphParameters["Visualization"] = [
			PluginFunctions.createVec3Param("cameraPosition", "Camera position", "Initial position of the camera.", [0.0,3.0,8.0]),
			PluginFunctions.createVec3Param("cameraLookat", "Camera lookat", "Lookat point of the camera.", [0.0,0.0,0.0]),
			PluginFunctions.createIntParam("numberOfStepsPerRenderUpdate", "# time steps / update", "Number of simulation steps per rendered frame.", 4, 1, 100),
			PluginFunctions.createEnumParam("renderWalls", "Render walls", "Make walls visible/invisible.", 4, ["None", "Particles (all)", "Particles (no walls)", "Geometry (all)", "Geometry (no walls)"]),
		]
		SPHConfigurationNode.sphParameters["Export"] = [
			PluginFunctions.createBoolParam("enablePartioExport", "Partio export", "Enable/disable partio export.", False),
			PluginFunctions.createBoolParam("enableRigidBodyExport", "Rigid body export", "Enable/disable rigid body export.", False),
			PluginFunctions.createBoolParam("enableVTKExport", "VTK export", "Enable/disable VTK export.", False),
			PluginFunctions.createBoolParam("enableRigidBodyVTKExport", "Rigid body VTK export", "Enable/disable rigid body VTK export.", False),
			PluginFunctions.createFloatParam("dataExportFPS", "Export FPS", "Frame rate of particle export.", 25, 0.1, 1000),
			PluginFunctions.createStringParam("particleAttributes", "Export attributes", "Attributes that are exported in the particle files (except id and position).", "velocity"),
			PluginFunctions.createBoolParam("enableStateExport", "State export", "Enable/disable simulation state export.", False),
			PluginFunctions.createFloatParam("stateExportFPS", "State export FPS", "Frame rate of state export.", 1, 0.1, 1000)
		]
		SPHConfigurationNode.sphParameters["Simulation"] = [
			PluginFunctions.createBoolParam("sim2D", "2D simulation", "2D/3D simulation.", False),
			PluginFunctions.createBoolParam("enableZSort", "Enable z-sort", "Enable z-sort to improve cache hits.", True),
			PluginFunctions.createFloatParam("particleRadius", "Particle radius", "Radius of the fluid particles.", 0.025, 0.0001, 1000.0, 0),
			PluginFunctions.createVec3Param("gravitation", "Gravitation", "Vector to define the gravitational acceleration.", [0,-9.81,0]),
			PluginFunctions.createEnumParam("simulationMethod", "Simulation method", "Simulation method.", 4, ["WCSPH", "PCISPH", "PBF", "IISPH", "DFSPH", "Projective Fluids"]),
			PluginFunctions.createIntParam("maxIterations", "Max. iterations", "Maximal number of iterations of the pressure solver.", 100, 1, 1000, 1),
			PluginFunctions.createFloatParam("maxError", "Max. density error(%)", "Maximal density error (%).", 0.01, 1.0e-6, 1.0, 0),
			PluginFunctions.createEnumParam("boundaryHandlingMethod", "Boundary handling method", "Boundary handling method.", 2, ["Akinci et al. 2012", "Koschier and Bender 2017", "Bender et al. 2019"])

		]
		SPHConfigurationNode.sphParameters["CFL"] = [
			PluginFunctions.createEnumParam("cflMethod", "CFL - method", "CFL method used for adaptive time stepping.", 1, ["None", "CFL", "CFL - iterations"]),
			PluginFunctions.createFloatParam("cflFactor", "CFL - factor", "Factor to scale the CFL time step size.", 0.5, 1e-6, 10.0, 0),
			PluginFunctions.createFloatParam("cflMinTimeStepSize", "CFL - min. time step size", "Min. time step size.", 0.0001, 1e-7, 1.0, 0),
			PluginFunctions.createFloatParam("cflMaxTimeStepSize", "CFL - max. time step size", "Max. time step size.", 0.005, 1e-6, 1.0, 0)
		]
		SPHConfigurationNode.sphParameters["Kernel"] = [
			PluginFunctions.createEnumParam("kernel", "Kernel", "Kernel function used in the SPH model (in 2D use only cubic or Wendland).", 4, ["Cubic spline", "Wendland quintic C2", "Poly6", "Spiky", "Precomputed cubic spline"]),
			PluginFunctions.createEnumParam("gradKernel", "Gradient of kernel", "Gradient of the kernel function used in the SPH model (in 2D use only cubic or Wendland).", 4, ["Cubic spline", "Wendland quintic C2", "Poly6", "Spiky", "Precomputed cubic spline"])
		]
		SPHConfigurationNode.sphParameters["WCSPH"] = [
			PluginFunctions.createFloatParam("stiffness", "Stiffness", "Stiffness coefficient of EOS.", 10000, 0, 500000),
			PluginFunctions.createFloatParam("exponent", "Exponent (gamma)", "Exponent of EOS.", 7.0, 1.0e-6, 10.0, 0)
		]
		SPHConfigurationNode.sphParameters["PBF"] = [
			PluginFunctions.createEnumParam("velocityUpdateMethod", "Velocity update method", "Method for the velocity integration.", 0, ["First Order Update", "Second Order Update"])
		]
		SPHConfigurationNode.sphParameters["DFSPH"] = [
			PluginFunctions.createIntParam("maxIterationsV", "Max. iterations (divergence)", "Maximal number of iterations of the divergence solver.", 100, 1, 1000, 1),
			PluginFunctions.createFloatParam("maxErrorV", "Max. divergence error(%)", "Maximal divergence error (%).", 0.01, 1.0e-6, 1.0, 0),
			PluginFunctions.createBoolParam("enableDivergenceSolver", "Enable divergence solver", "Turn divergence solver on/off.", True)
		]
		SPHConfigurationNode.sphParameters["Projective Fluids"] = [
			PluginFunctions.createFloatParam("stiffnessPF", "Stiffness", "Stiffness coefficient.", 50000, 0, 500000)
		]

# Node definition
class SPHFluidConfigurationNode(OpenMayaMPx.MPxLocatorNode):
	kPluginNodeId = OpenMaya.MTypeId(0x90001)
	kPluginNodeTypeName = "SPHFluidConfigurationNode"

	# class variables
	input = OpenMaya.MObject()
	dataAttr = OpenMaya.MObject()
	sphParameters = OrderedDict()

	def __init__(self):
		OpenMayaMPx.MPxLocatorNode.__init__(self)

	# initializer
	@staticmethod
	def initialize():
		SPHFluidConfigurationNode.initParameters()
		addAttributesToSPHNode(SPHFluidConfigurationNode)

	# creator
	@staticmethod
	def creator():
		return OpenMayaMPx.asMPxPtr( SPHFluidConfigurationNode() )

	######################################################
	# initParameters
	######################################################
	@staticmethod
	def initParameters():
		SPHFluidConfigurationNode.sphParameters["Simulation"] = [
			PluginFunctions.createFloatParam("density0", "Rest density", "Rest density of the fluid.", 1000.0, 0.1, 10000.0)
		]
		SPHFluidConfigurationNode.sphParameters["Visualization"] = [
			PluginFunctions.createStringParam("colorField", "Color field", "Choose vector or scalar field for particle coloring.", "velocity"),
			PluginFunctions.createEnumParam("colorMapType", "Color map type", "Selection of a color map for coloring the scalar/vector field.", 1, ["None", "Jet", "Plasma"]),
			PluginFunctions.createFloatParam("renderMinValue", "Min. value", "Minimal value used for color-coding the color field in the rendering process.", 0, -1000, 1000, -1000000),
			PluginFunctions.createFloatParam("renderMaxValue", "Max. value", "Maximal value used for color-coding the color field in the rendering process.", 5, -1000, 1000, -1000000)
		]
		SPHFluidConfigurationNode.sphParameters["Emitters"] = [
			PluginFunctions.createIntParam("maxEmitterParticles", "Max. number of emitted particles", "Maximum number of emitted particles", 10000, 1, 10000000, 0, 100000000),
			PluginFunctions.createBoolParam("emitterReuseParticles", "Reuse particles", "Reuse particles if they are outside of the bounding box defined by emitterBoxMin, emitterBoxMaRex.", False),
			PluginFunctions.createVec3Param("emitterBoxMin", "Emitter box min.", "Minimum coordinates of an axis-aligned box (used in combination with emitterReuseParticles).", [0.0,0.0,0.0]),
			PluginFunctions.createVec3Param("emitterBoxMax", "Emitter box max.", "Maximum coordinates of an axis-aligned box (used in combination with emitterReuseParticles).", [1.0,1.0,1.0])
		]
		SPHFluidConfigurationNode.sphParameters["Viscosity"] = [
			PluginFunctions.createEnumParam("viscosityMethod", "Viscosity", "Method to compute viscosity forces.", 1, ["None", "Standard", "XSPH", "Bender and Koschier 2017", "Peer et al. 2015", "Peer et al. 2016", "Takahashi et al. 2015 (improved)", "Weiler et al. 2018"]),
			PluginFunctions.createFloatParam("viscosity", "Viscosity coefficient", "Coefficient for the viscosity force computation.", 0.01, 0, 1000, 0),
			PluginFunctions.createIntParam("viscoMaxIter", "Max. iterations (visco)", "(Implicit solvers) Max. iterations of the viscosity solver.", 100, 1, 1000),
			PluginFunctions.createFloatParam("viscoMaxError", "Max. visco error", "(Implicit solvers) Max. error of the viscosity solver.", 0.01, 1e-6, 1, 0),
			PluginFunctions.createIntParam("viscoMaxIterOmega", "Max. iterations (vorticity diffusion)", "(Peer et al. 2016) Max. iterations of the vorticity diffusion solver.", 100, 1, 1000),
			PluginFunctions.createFloatParam("viscoMaxErrorOmega", "Max. vorticity diffusion error", "(Peer et al. 2016) Max. error of the vorticity diffusion solver.", 0.01, 1e-6, 1, 0),
			PluginFunctions.createFloatParam("viscosityBoundary", "Viscosity coefficient (Boundary)", "Coefficient for the viscosity force computation at the boundary.", 0.0, 0, 1000, 0)
		]
		SPHFluidConfigurationNode.sphParameters["Vorticity"] = [
			PluginFunctions.createEnumParam("vorticityMethod", "Vorticity method", "Method to compute vorticity forces.", 0, ["None", "Micropolar model", "Vorticity confinement"]),
			PluginFunctions.createFloatParam("vorticity", "Vorticity coefficient", "Coefficient for the vorticity force computation.", 0.01, 0, 10.0, 0),
			PluginFunctions.createFloatParam("viscosityOmega", "Angular viscosity coefficient", "Viscosity coefficient for the angular velocity field.", 0.1, 0, 10.0, 0),
			PluginFunctions.createFloatParam("inertiaInverse", "Inertia inverse", "Inverse microinertia used in the micropolar model.", 0.5, 0, 10.0, 0)
		]
		SPHFluidConfigurationNode.sphParameters["Drag force"] = [
			PluginFunctions.createEnumParam("dragMethod", "Drag method", "Method to compute drag forces.", 0, ["None", "Macklin et al. 2014", "Gissler et al. 2017"]),
			PluginFunctions.createFloatParam("drag", "Drag coefficient", "Coefficient for the drag force computation.", 0.01, 0, 100.0, 0)
		]
		SPHFluidConfigurationNode.sphParameters["Surface tension"] = [
			PluginFunctions.createEnumParam("surfaceTensionMethod", "Surface tension method", "Method to compute surface tension forces.", 0, ["None", "Becker & Teschner 2007", "Akinci et al. 2013", "He et al. 2014"]),
			PluginFunctions.createFloatParam("surfaceTension", "Surface tension coefficient", "Coefficient for the surface tension computation.", 0.05, 0, 100.0, 0)
		]
		SPHFluidConfigurationNode.sphParameters["Elasticity"] = [
			PluginFunctions.createEnumParam("elasticityMethod", "Elasticity method", "Method to compute elastic forces.", 0, ["None", "Becker et al. 2009", "Peer et al. 2018"]),
			PluginFunctions.createFloatParam("youngsModulus", "Young's modulus", "Stiffness of the elastic material.", 100000.0, 0, 1000.0, 0),
			PluginFunctions.createFloatParam("poissonsRatio", "Poisson's ratio", "Ratio of transversal expansion and axial compression.", 0.3, -0.9999, 0.4999, -0.9999),
			PluginFunctions.createIntParam("elasticityMaxIter", "Max. iterations (elasticity)", "(Implicit solvers) Max. iterations of the elasticity solver.", 100, 1, 1000),
			PluginFunctions.createFloatParam("elasticityMaxError", "Max. elasticity error", "(Implicit solvers) Max. error of the elasticity solver.", 0.0001, 1e-6, 1, 0),
			PluginFunctions.createFloatParam("alpha", "Zero-energy modes suppression", "Coefficent for zero-energy modes suppression method.", 0.0, 0, 10000.0, 0)
		]

class SPHFluidNode(OpenMayaMPx.MPxLocatorNode):
	kPluginNodeId = OpenMaya.MTypeId(0x90002)
	kPluginNodeTypeName = "SPHFluidNode"

	# class variables
	input = OpenMaya.MObject()
	dataAttr = OpenMaya.MObject()
	sphParameters = OrderedDict()

	def __init__(self):
		OpenMayaMPx.MPxLocatorNode.__init__(self)

	def postConstructor(self):
		OpenMayaMPx.MPxLocatorNode.postConstructor(self)

	# initializer
	@staticmethod
	def initialize():
		SPHFluidNode.initParameters()
		addAttributesToSPHNode(SPHFluidNode)

	# creator
	@staticmethod
	def creator():
		return OpenMayaMPx.asMPxPtr( SPHFluidNode() )

	def compute(self,plug,dataBlock):
		# if ( plug == SPHFluidNode.output ):
				# dataHandle = dataBlock.inputValue( SPHFluidNode.input )

				# inputFloat = dataHandle.asFloat()
				# result = math.sin( inputFloat ) * 10.0
				# outputHandle = dataBlock.outputValue( SPHFluidNode.output )
				# outputHandle.setFloat( result )
				# dataBlock.setClean( plug )

		return OpenMaya.kUnknownParameter

	######################################################
	# initParameters
	######################################################
	@staticmethod
	def initParameters():
		SPHFluidNode.sphParameters["General"] = [
			PluginFunctions.createStringParam("id", "Fluid id", "Id of the fluid material.", "Fluid"),
			PluginFunctions.createVec3Param("initialVelocity", "Initial velocity", "Initial velocity of the fluid.", [0.0,0.0,0.0]),
			PluginFunctions.createVec3Param("initialAngularVelocity", "Initial angular velocity", "Initial angular velocity of the fluid.", [0.0,0.0,0.0]),
			PluginFunctions.createVec3iParam("resolutionSDF", "SDF resolution", "Resolution of the SDF.", [20,20,20]),
			PluginFunctions.createBoolParam("invert", "Invert SDF", "Invert the SDF, flips inside/outside.", False),
			PluginFunctions.createEnumParam("denseMode", "Dense mode", "Sampling mode.", 0, ["Regular", "Almost dense", "Dense"]),
			PluginFunctions.createStringParam("particleFile", "Particle sampling file", "Particle sampling file.", ""),
		]

class SPHRigidBodyNode(OpenMayaMPx.MPxLocatorNode):
	kPluginNodeId = OpenMaya.MTypeId(0x90003)
	kPluginNodeTypeName = "SPHRigidBodyNode"

	# class variables
	input = OpenMaya.MObject()
	dataAttr = OpenMaya.MObject()
	sphParameters = OrderedDict()

	def __init__(self):
		OpenMayaMPx.MPxLocatorNode.__init__(self)

	def postConstructor(self):
		OpenMayaMPx.MPxLocatorNode.postConstructor(self)

	# initializer
	@staticmethod
	def initialize():
		SPHRigidBodyNode.initParameters()
		addAttributesToSPHNode(SPHRigidBodyNode)

	# creator
	@staticmethod
	def creator():
		return OpenMayaMPx.asMPxPtr( SPHRigidBodyNode() )

	def compute(self,plug,dataBlock):
		# if ( plug == SPHRigidBodyNode.output ):
				# dataHandle = dataBlock.inputValue( SPHRigidBodyNode.input )

				# inputFloat = dataHandle.asFloat()
				# result = math.sin( inputFloat ) * 10.0
				# outputHandle = dataBlock.outputValue( SPHRigidBodyNode.output )
				# outputHandle.setFloat( result )
				# dataBlock.setClean( plug )

		return OpenMaya.kUnknownParameter

	######################################################
	# initParameters
	######################################################
	@staticmethod
	def initParameters():
		SPHRigidBodyNode.sphParameters["General"] = [
			PluginFunctions.createBoolParam("isDynamic", "Dynamic", "Defines if the body is static or dynamic.", False),
			PluginFunctions.createBoolParam("isWall", "Wall", "Defines if this is a wall. Walls are typically not rendered. This is the only difference.", False),
			PluginFunctions.createColorParam("color", "Color", "Color of the body", [0.2, 0.2, 0.2]),
			PluginFunctions.createFloatParam("density", "Density", "Rest density of the body.", 1000.0, 0, 100000.0, 0),
			PluginFunctions.createVec3iParam("mapResolution", "Map resolution", "Resolution of the volume/density map.", [20,20,20]),
			PluginFunctions.createBoolParam("mapInvert", "Invert map", "Invert the volume/density map, flips inside/outside.", False),
			PluginFunctions.createFloatParam("mapThickness", "Map thickness", "Thickness of the map.", 0.0, 0, 100.0, 0),
			PluginFunctions.createVec3iParam("resolutionSDF", "SDF resolution", "Resolution of the SDF.", [20,20,20]),
			PluginFunctions.createBoolParam("invert", "Invert SDF", "Invert the SDF, flips inside/outside.", False),
			PluginFunctions.createEnumParam("samplingMode", "Sampling mode", "Sampling mode.", 0, ["Poisson disk sanmpling", "Regular triangle sampling"]),
		]

######################################################
# loadRigidBodies
#
# load rigid body data that was exported by
# a SPH simulation
######################################################
class loadRigidBodiesCmd(OpenMayaMPx.MPxCommand):
	s_name = "loadRigidBodies"

	def __init__(self):
		OpenMayaMPx.MPxCommand.__init__(self)

	@staticmethod
	def creator():
		return loadRigidBodiesCmd()

	def doIt(self, args):
		self.addedNodes = []
		self.firstFileName = cmds.fileDialog2(ff="*.bin", fm=1, dir="")[0]
		indexlist = re.findall(r'\d+', self.firstFileName)
		if len(indexlist) == 0:
			cmds.warning("No frame index found in file name.")
			return

		self.firstFrame = int(indexlist[-1])
		self.redoIt()

	def redoIt(self):
		self.loadRigidBodies()

	def loadRigidBodies(self):

		folderName = os.path.dirname(self.firstFileName)
		frameNumber = self.firstFrame
		firstFile = open(self.firstFileName, 'rb')

		# read number of bodies
		bytes = firstFile.read()
		firstFile.close()

		(numBodies,), bytes = struct.unpack('i', bytes[:4]), bytes[4:]

		objFiles = []
		transformNodes = []
		for i in range(0, numBodies):
			# determine length of file name string
			(strLength,), bytes = struct.unpack('i', bytes[:4]), bytes[4:]

			# read file name
			objFile, bytes = bytes[:strLength], bytes[strLength:]

			# Check for duplicates and create instances
			if objFile in objFiles:
				idx = objFiles.index(objFile)
				newNodes = cmds.duplicate(transformNodes[idx], instanceLeaf= True)
				transformNodes.append(newNodes[0])
				self.addedNodes.append(newNodes)
			else:
				objFileName = os.path.join(folderName, objFile)
				newNodes = cmds.file(objFileName, i=True, rnn=True, type="OBJ", options="mo=1")

				transformNodes.append(newNodes[0])
				objFiles.append(objFile)
				self.addedNodes.append(newNodes)

			# Read scaling factors in first file
			(sx,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
			(sy,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
			(sz,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]

			cmds.scale(sx, sy, sz, transformNodes[i])

			(isWall,), bytes = struct.unpack('?', bytes[:1]), bytes[1:]
			(colr,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
			(colg,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
			(colb,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
			(cola,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]

			if isWall:
				cmds.setAttr((transformNodes[i] + '.visibility'), 0)

			cmds.setKeyframe(transformNodes[i], at="s", t=1)
			if frameNumber > 1:
				cmds.setKeyframe(transformNodes[i], at="visibility", t=1, value=0)
				if not isWall:
					cmds.setKeyframe(transformNodes[i], at="visibility", t=frameNumber, value=1)

		# load transformations
		for i in range(0, numBodies):
			# Read translation in first file
			(x,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
			(y,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
			(z,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]

			# Read rotation in first file
			r = []
			for j in range(0,9):
				(value,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
				r.append(value)

			cmds.xform(transformNodes[i], p=True, m=[r[0],r[1],r[2],0,r[3],r[4],r[5],0,r[6],r[7],r[8],0,x,y,z,1])
			cmds.setKeyframe(transformNodes[i], at="t", t=frameNumber)
			cmds.setKeyframe(transformNodes[i], at="r", t=frameNumber)

		# read other files
		idx = self.firstFileName.rfind(str(frameNumber))
		l = len(str(frameNumber))
		chk = True
		while chk:
			frameNumber += 1
			fileName = str(self.firstFileName[0:idx]) + str(frameNumber) + str(self.firstFileName[idx+l:])
			chk = os.path.exists(fileName)
			if chk:
				f = open(fileName, 'rb')
				bytes = f.read()
				f.close()

				# load transformations
				for i in range(0, numBodies):
					# Read translation in file
					(x,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
					(y,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
					(z,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]

					# Read rotation in file
					r = []
					for j in range(0,9):
						(value,), bytes = struct.unpack('f', bytes[:4]), bytes[4:]
						r.append(value)

					cmds.xform(transformNodes[i], p=True, m=[r[0],r[1],r[2],0,r[3],r[4],r[5],0,r[6],r[7],r[8],0,x,y,z,1])
					cmds.setKeyframe(transformNodes[i], at="t", t=frameNumber)
					cmds.setKeyframe(transformNodes[i], at="r", t=frameNumber)

		cmds.currentTime(1)

	def undoIt(self):
		for node in self.addedNodes:
			cmds.delete(node)

	def isUndoable(self):
		return True

######################################################
# createSPHMenu
######################################################
def createSPHMenu():
	global menuId
	menuId = cmds.menu( label='SPlisHSPlasH', p="MayaWindow" )
	cmds.menuItem(divider=True, dividerLabel="Scene generating")

	cmds.menuItem( label='Add scene configuration',command=
		'if "SPH_Config" not in cmds.ls( type="transform"):\n' +
		'	cmds.createNode("transform", name="SPH_Config")\n' +
		'cmds.createNode("SPHConfigurationNode", name="Configuration", parent="SPH_Config")')

	cmds.menuItem( label='Add fluid material',command=
		'if "SPH_Fluid_Material" not in cmds.ls( type="transform"):\n' +
		'	cmds.createNode("transform", name="SPH_Fluid_Material")\n' +
		'cmds.createNode("SPHFluidConfigurationNode", name="Fluid", parent="SPH_Fluid_Material")')

	cmds.menuItem(divider=True)
	cmds.menuItem( label='Convert selection to fluid',command='cmds.convertToFluid()' )
	cmds.menuItem( label='Convert selection to rigid bodies',command='cmds.convertToRigidBodies()' )
	cmds.menuItem(divider=True)
	cmds.menuItem( label='Create rectangular emitter',command='cmds.createRectangularEmitter()' )
	cmds.menuItem( label='Create circular emitter',command='cmds.createCircularEmitter()' )
	cmds.menuItem(divider=True)
	cmds.menuItem( label='Create box animation field',command='cmds.createAnimationField(s=0)' )
	cmds.menuItem( label='Create sphere animation field',command='cmds.createAnimationField(s=1)' )
	cmds.menuItem( label='Create cylinder animation field',command='cmds.createAnimationField(s=2)' )
	cmds.menuItem(divider=True)
	cmds.menuItem( label='Save scene',command='cmds.saveModel()' )
	cmds.menuItem(divider=True, dividerLabel="Import")
	cmds.menuItem( label='Load rigid body data',command='cmds.loadRigidBodies()' )

######################################################
# deleteSPHMenu
######################################################
def deleteSPHMenu():
	global menuId
	cmds.deleteUI(menuId)
	return

# Initialize the script plug-in
def initializePlugin(mobject):
	global settingsWinId
	global fluidWinId
	global menuId
	global fluidIds
	global sphParameters
	global fluidParameters

	mplugin = OpenMayaMPx.MFnPlugin(mobject, "SPlisHSPlasH", "1.0", "Any")

	settingsWinId = ""
	fluidWinId = ""
	menuId = ""
	fluidIds = ["Fluid"]

	try:
		mplugin.registerNode( SPHConfigurationNode.kPluginNodeTypeName, SPHConfigurationNode.kPluginNodeId, SPHConfigurationNode.creator, SPHConfigurationNode.initialize, OpenMayaMPx.MPxNode.kLocatorNode )
		mplugin.registerNode( SPHFluidConfigurationNode.kPluginNodeTypeName, SPHFluidConfigurationNode.kPluginNodeId, SPHFluidConfigurationNode.creator, SPHFluidConfigurationNode.initialize, OpenMayaMPx.MPxNode.kLocatorNode )
		mplugin.registerNode( SPHFluidNode.kPluginNodeTypeName, SPHFluidNode.kPluginNodeId, SPHFluidNode.creator, SPHFluidNode.initialize, OpenMayaMPx.MPxNode.kLocatorNode )
		mplugin.registerNode( SPHRigidBodyNode.kPluginNodeTypeName, SPHRigidBodyNode.kPluginNodeId, SPHRigidBodyNode.creator, SPHRigidBodyNode.initialize, OpenMayaMPx.MPxNode.kLocatorNode )

		mplugin.registerCommand(createRectangularEmitterCmd.s_name, createRectangularEmitterCmd.creator)
		mplugin.registerCommand(createCircularEmitterCmd.s_name, createCircularEmitterCmd.creator)
		mplugin.registerCommand(saveModelCmd.s_name, saveModelCmd.creator)
		mplugin.registerCommand(convertToFluidCmd.s_name, convertToFluidCmd.creator)
		mplugin.registerCommand(convertToRigidBodiesCmd.s_name, convertToRigidBodiesCmd.creator)
		mplugin.registerCommand(createAnimationFieldCmd.s_name, createAnimationFieldCmd.creator, createAnimationFieldCmd.syntaxCreator)
		mplugin.registerCommand(loadRigidBodiesCmd.s_name, loadRigidBodiesCmd.creator)

	except:
		sys.stderr.write( "Failed to register nodes." )
		raise

	createSPHMenu()

# Uninitialize the script plug-in
def uninitializePlugin(mobject):
	mplugin = OpenMayaMPx.MFnPlugin(mobject)
	deleteSPHMenu()

	try:
		mplugin.deregisterCommand(createRectangularEmitterCmd.s_name)
		mplugin.deregisterCommand(createCircularEmitterCmd.s_name)
		mplugin.deregisterCommand(saveModelCmd.s_name)
		mplugin.deregisterCommand(convertToFluidCmd.s_name)
		mplugin.deregisterCommand(convertToRigidBodiesCmd.s_name)
		mplugin.deregisterCommand(createAnimationFieldCmd.s_name)
		mplugin.deregisterCommand(loadRigidBodiesCmd.s_name)

		mplugin.deregisterNode( SPHRigidBodyNode.kPluginNodeId )
		mplugin.deregisterNode( SPHFluidNode.kPluginNodeId )
		mplugin.deregisterNode( SPHFluidConfigurationNode.kPluginNodeId )
		mplugin.deregisterNode( SPHConfigurationNode.kPluginNodeId )
	except:
		sys.stderr.write( "Failed to deregister node")
		raise


text:
static PyObject *x11_getpowhash(PyObject *self, PyObject *args)
{
    char *output;
    PyObject *value;
#if PY_MAJOR_VERSION >= 3
    PyBytesObject *input;
#else
    PyStringObject *input;
#endif
    if (!PyArg_ParseTuple(args, "S", &input))
        return NULL;
    Py_INCREF(input);
    output = PyMem_Malloc(32);

#if PY_MAJOR_VERSION >= 3
    x11_hash((char *)PyBytes_AsString((PyObject*) input), output);
#else
    x11_hash((char *)PyString_AsString((PyObject*) input), output);
#endif
    Py_DECREF(input);
#if PY_MAJOR_VERSION >= 3
    value = Py_BuildValue("y#", output, 32);
#else
    value = Py_BuildValue("s#", output, 32);
#endif
    PyMem_Free(output);
    return value;
}

static PyMethodDef X11Methods[] = {
    { "getPoWHash", x11_getpowhash, METH_VARARGS, "Returns the proof of work hash using x11 hash" },
    { NULL, NULL, 0, NULL }
};

#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef X11Module = {
    PyModuleDef_HEAD_INIT,
    "x11_hash",
    "...",
    -1,
    X11Methods
};

PyMODINIT_FUNC PyInit_x11_hash(void) {
    return PyModule_Create(&X11Module);
}

#else

PyMODINIT_FUNC initx11_hash(void) {
    (void) Py_InitModule("x11_hash", X11Methods);
}
#endif

redpajama_set_name: RedPajamaGithub


text:
'use strict';

var gulp = require('gulp'),
    fs = require('fs'),
    $ = require('gulp-load-plugins')();
$.mainBowerFiles = require('main-bower-files');
$.del = require('del');

var globalConf = require('./config');

var paths = {
    app: 'app/',
    test: 'test/',
    front: 'public/',
    images: 'public/assets/images/',
    fonts: 'public/assets/fonts/',
    fixtures: 'fixtures/',
    upload_fixtures: 'fixtures/upload/',
    dist: 'www/',
    views_dist: 'views'
};

// compress image and copy its
gulp.task('images', function () {
  return gulp.src(paths.images + '**/*')
    .pipe($.imagemin())
    .pipe(gulp.dest(paths.dist + 'assets/images/'));
});

// Copy fonts
gulp.task('fonts', function () {
  return gulp.src(
      $.mainBowerFiles({filter: '**/*.{eot,svg,ttf,woff}'})
      .concat(paths.fonts)
    )
    .pipe($.flatten())
    .pipe(gulp.dest(paths.dist + 'fonts/'));
});

// Copy favicon
gulp.task('misc', function () {
  return gulp.src(paths.front + '**/favicon.*')
    .pipe(gulp.dest(paths.dist));
});

// Load Fixture
gulp.task('fixtures', function () {
    gulp.src(paths.fixtures + 'upload/**/*')
        .pipe(gulp.dest(globalConf.upload_dir));

   fs.readdir(__dirname + '/' + paths.fixtures, function(err, names){
       names.forEach(function(name) {
           if (!fs.statSync(__dirname + '/' + paths.fixtures + name).isDirectory()) {
               require('./'+ paths.fixtures + name);
           }
       });
   });
});

// Load template
gulp.task('scripts', function () {
    gulp.src($.mainBowerFiles({filter: '**/*.js'}))
        .pipe($.uglify())
        .pipe($.concat('vendor.js'))
        .pipe(gulp.dest(paths.dist+ 'scripts/'));

    gulp.src(concat(paths.front + '**/*.js'))
        .pipe($.uglify())
        .pipe($.concat('vendor.js'))
        .pipe(gulp.dest(paths.dist+ 'scripts/'));
});

// Compile js
gulp.task('scripts', function () {
    gulp.src($.mainBowerFiles({filter: '**/*.js'}))
        .pipe($.uglify())
        .pipe($.concat('vendor.js'))
        .pipe(gulp.dest(paths.dist+ 'scripts/'));

    gulp.src(paths.front + '**/*.js')
        .pipe($.uglify())
        .pipe($.concat('app.js'))
        .pipe(gulp.dest(paths.dist+ 'scripts/'));
});

// Compile js
gulp.task('scripts-dev', function () {
    gulp.src($.mainBowerFiles({filter: '**/*.js'}))
        .pipe($.concat('vendor.js'))
        .pipe(gulp.dest(paths.dist+ 'scripts/'));

    gulp.src(paths.front + '**/*.js')
        .pipe($.concat('app.js'))
        .pipe(gulp.dest(paths.dist+ 'scripts/'));
});

// compile scss
gulp.task('styles', function () {

    gulp.src($.mainBowerFiles({filter: '**/*.css' }))
        .pipe($.concat('vendor.css'))
        .pipe(gulp.dest(paths.dist+ 'styles/'));

    gulp.src(paths.front + '*.scss')
        .pipe($.sass())
        .pipe($.concat('app.css'))
        .pipe(gulp.dest(paths.dist+ 'styles/'));
});

// run the mocha test
gulp.task('mocha', function () {
    $.env({
        vars: {
            NODE_ENV: 'TEST',
            PORT: 3001
        }
    });
    return gulp
        .src( [paths.test + '**/*.js'], {read: false})
        .pipe($.coverage.instrument({
            pattern: [paths.app + '**/*.js']
        }))
        .pipe($.mocha({bail: false}))
        .pipe($.coverage.gather())
        .pipe($.coverage.format())
        .pipe(gulp.dest('reports'))
         .once('error', function () {
        })
    ;
});

// run hints
gulp.task('jshint', ['mocha'], function () {
  return gulp.src([paths.app + '**/*.js', paths.front + '**/*.js' ])
    .pipe($.jshint())
    .pipe($.jshint.reporter('jshint-stylish'))
    .pipe($.jshint.reporter('fail'));
});

// Launch the server with node and reload it everytime a file change
gulp.task('serve', ['watch'], function() {
    $.nodemon({
        script: paths.app + "index.js",
        env: {
            NODE_ENV: 'DEV',
            PORT: '3000'
        }
    });
});

// clean the dest file
gulp.task('clean', function (done) {
  $.del([paths.dist +'*', '!' + globalConf.upload_dir, paths.views_dist], done);
});

// Watch for rebuild
gulp.task('watch', ['build'], function(){
    gulp.watch(paths.images + '**/*', ['images']);
    gulp.watch(paths.fonts + '**/*', ['fonts']);
    gulp.watch(paths.front + '**/favicon.*', ['misc']);
    gulp.watch(paths.front + '**/*.js', ['scripts-dev']);
    gulp.watch('bower_components/**/*.js', ['scripts-dev']);
    gulp.watch(paths.front + '**/*css', ['styles']);
    gulp.watch('bower_components/**/*scss', ['styles']);
});

// watch for launch test
gulp.task('watch-test', ['build'], function(){
    gulp.watch([paths.fonts + '**/*.js', paths.app + '**/*.js', paths.test + '**/*.js'], ['test']);
});

gulp.task('test', ['jshint', 'mocha']);
gulp.task('build', ['images', 'fonts', 'misc', 'scripts', 'styles']);
gulp.task('install-dev', ['build', 'fixtures', 'scripts-dev', 'styles']);
gulp.task('install', ['build', 'fixtures']);


text:
package org.openehealth.ipf.commons.ihe.xds.core.metadata;

import org.openehealth.ipf.commons.ihe.xds.core.validate.ValidationMessage;
import org.openehealth.ipf.commons.ihe.xds.core.validate.XDSMetaDataException;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;
/**
 * Lists all possible types of associations between two documents.
 *
 * @author Jens Riemschneider
 */
@XmlType(name = "AssociationType")
@XmlEnum()
public enum AssociationType {
    /** An entry that is appended to another one. */
    @XmlEnumValue("APND") APPEND("APND", "urn:ihe:iti:2007:AssociationType:APND"),
    /** An entry that replaced another one. */
    @XmlEnumValue("RPLC") REPLACE("RPLC", "urn:ihe:iti:2007:AssociationType:RPLC"),
    /** An entry that transforms another one. */
    @XmlEnumValue("XFRM") TRANSFORM("XFRM", "urn:ihe:iti:2007:AssociationType:XFRM"),
    /** An entry that transforms and replaces another one. */
    @XmlEnumValue("XFRM_RPLC") TRANSFORM_AND_REPLACE("XFRM_RPLC", "urn:ihe:iti:2007:AssociationType:XFRM_RPLC"),
    /** An entry that is a member of another one. */
    @XmlEnumValue("HasMember") HAS_MEMBER("HasMember", "urn:oasis:names:tc:ebxml-regrep:AssociationType:HasMember"),
    /** An entry that represents a signature of another one. */
    @XmlEnumValue("signs") SIGNS("signs", "urn:ihe:iti:2007:AssociationType:signs"),
    /** An entry that represents a link to the On-Demand DocumentEntry. */
    @XmlEnumValue("IsSnapshotOf") IS_SNAPSHOT_OF("IsSnapshotOf", "urn:ihe:iti:2010:AssociationType:IsSnapshotOf"),
    /** An entry that represents an association for update availability status trigger. */
    @XmlEnumValue("UpdateAvailabilityStatus") UPDATE_AVAILABILITY_STATUS("UpdateAvailabilityStatus", "urn:ihe:iti:2010:AssociationType:UpdateAvailabilityStatus"),
    /** An entry that represents an association for submit association trigger. */
    @XmlEnumValue("SubmitAssociation") SUBMIT_ASSOCIATION("SubmitAssociation", "urn:ihe:iti:2010:AssociationType:SubmitAssociation");

    private final String opcode21;
    private final String opcode30;

    AssociationType(String opcode21, String opcode30) {
        this.opcode21 = opcode21;
        this.opcode30 = opcode30;
    }

    /**
     * @return a string representation in ebXML 2.1.
     */
    public String getOpcode21() {
        return opcode21;
    }

    /**
     * @return a string representation in ebXML 3.0.
     */
    public String getOpcode30() {
        return opcode30;
    }

    /**
     * null-safe version of {@link #getOpcode21()}.
     * @param type
     *          the type for which to get the opcode. Can be null.
     * @return the opcode or null if type was null.
     */
    public static String getOpcode21(AssociationType type) {
        return type != null ? type.getOpcode21() : null;
    }

    /**
     * null-safe version of {@link #getOpcode30()}.
     * @param type
     *          the type for which to get the opcode. Can be null.
     * @return the opcode or null if type was null.
     */
    public static String getOpcode30(AssociationType type) {
        return type != null ? type.getOpcode30() : null;
    }

    /**
     * Returns the association type that is represented by the given opcode.
     *

     * This method looks up the opcode via the ebXML 2.1 representations.
     * @param opcode
     *          the string representation. Can be null.
     * @return the association type or null if the opcode was null.
     */
    public static AssociationType valueOfOpcode21(String opcode) {
        if (opcode == null) {
            return null;
        }

        for (var type : AssociationType.values()) {
            if (opcode.equals(type.getOpcode21())) {
                return type;
            }
        }

        throw new XDSMetaDataException(ValidationMessage.INVALID_ASSOCIATION_TYPE);
    }

    /**
     * Returns the association type that is represented by the given opcode.
     *

     * This method looks up the opcode via the ebXML 3.0 representations.
     * @param opcode
     *          the string representation. Can be null.
     * @return the association type or null if the opcode was null.
     */
    public static AssociationType valueOfOpcode30(String opcode) {
        if (opcode == null) {
            return null;
        }

        for (var type : AssociationType.values()) {
            if (opcode.equals(type.getOpcode30())) {
                return type;
            }
        }

        throw new XDSMetaDataException(ValidationMessage.INVALID_ASSOCIATION_TYPE);
    }

    /**
     * @return true if the association contains a replacement.
     */
    public boolean isReplace() {
        return this == REPLACE || this == TRANSFORM_AND_REPLACE;
    }
}


text:
using System.Runtime.InteropServices;
using EcsRx.Components;

namespace EcsRx.Examples.ExampleApps.Playground.Components
{
    [StructLayout(LayoutKind.Sequential)]
    public struct StructComponent2 : IComponent
    {
        public byte IsTrue;
        public int Value;
    }
}


text:
SYNONYM

#### According to
The Catalogue of Life, 3rd January 2011

#### Published in
Bot. Mag. 80: t. 4801. 1854

#### Original name
null

### Remarks
null


text:
{\vfill
{\bigskip \centerline{\it \copyright \ \number\year \
David Backus, Chase Coleman, and Spencer Lyon @ NYU Stern}%
}}


text:
package com.blinkbox.books.search.ingester

import akka.actor.{ ActorRef, ActorSystem, Props, Status }
import akka.testkit.{ ImplicitSender, TestActorRef, TestKit }
import com.blinkbox.books.messaging._
import com.blinkbox.books.test.MockitoSyrup
import java.io.IOException
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Matchers._
import org.mockito.Mockito._
import org.mockito.verification.VerificationMode
import org.scalatest.BeforeAndAfter
import org.scalatest.FlatSpecLike
import org.scalatest.StreamlinedXmlEquality
import org.scalatest.junit.JUnitRunner
import org.xml.sax.SAXException
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.io.Source
import scala.util.Success
import scala.util.Failure
import scala.xml.XML

@RunWith(classOf[JUnitRunner])
class BookMetadataTransformerTest extends TestKit(ActorSystem("test-system")) with ImplicitSender
  with FlatSpecLike with BeforeAndAfter with MockitoSyrup with StreamlinedXmlEquality {

  "A book data processor" should "pass on transformed book distribute message" in new TestFixture {

    handler ! event("/example.book.xml")

    expectMsgType[Status.Success]

    checkSuccessfulResult("/example.book.out.xml")
    checkNoFailures()
  }

  it should "pass on transformed book undistribute message" in new TestFixture {

    handler ! event("/example.undistribute.xml")

    expectMsgType[Status.Success]

    checkSuccessfulResult("/example.undistribute.out.xml")
    checkNoFailures()
  }

  it should "pass on transformed price data message" in new TestFixture {
    handler ! event("/example.price.xml")

    expectMsgType[Status.Success]

    checkSuccessfulResult("/example.price.out.xml")
    checkNoFailures()
  }

  it should "pass on message to error handler for invalid incoming XML" in new TestFixture {

    val invalidEvent = Event.xml("This is not valid XML", EventHeader.apply("test"))
    handler ! invalidEvent

    // Should successfully complete processing of this message (i.e. not retry).
    expectMsgType[Status.Success]
    checkFailure[SAXException](invalidEvent)
  }

  it should "retry in case of a temporary error from its output" in new TestFixture {
    // Force a temporary exception to happen when passing on output command to Solr.
    val tempException = new IOException("Test exception")
    when(output.handleUpdate(anyString))
      .thenReturn(Future.failed(tempException))
      .thenReturn(Future.failed(tempException))
      .thenReturn(Future.successful(()))

    handler ! event("/example.book.xml")

    expectMsgType[Status.Success]

    checkSuccessfulResult("/example.book.out.xml", attempts = times(3))
    checkNoFailures()
  }

  it should "pass in message to error handler for non-temporary errors from its output" in new TestFixture {
    val unrecoverableError = new IllegalArgumentException("Test unrecoverable error")
    when(output.handleUpdate(anyString))
      .thenReturn(Future.failed(unrecoverableError))

    val inputEvent = event("/example.book.xml")
    handler ! inputEvent

    // Should successfully complete processing of this message (i.e. not retry).
    expectMsgType[Status.Success]
    verify(errorHandler).handleError(inputEvent, unrecoverableError)
  }

  trait TestFixture {

    val retryInterval = 100.millis

    // Define mocks and initialise them with default behaviour.
    val output = mock[SolrApi]
    val errorHandler = mock[ErrorHandler]

    doReturn(Future.successful(())).when(errorHandler).handleError(any[Event], any[Throwable])
    doReturn(Future.successful(())).when(output).handleUpdate(anyString)

    // The actor under test.
    val handler = TestActorRef(Props(new BookMetadataTransformer(output, errorHandler, retryInterval)))

    /** Create input event. */
    def event(inputFilename: String) = Event.xml(fileToString(inputFilename), EventHeader.apply("test"))

    /** Check that the event was processed successfully by checking the various outputs. */
    def checkSuccessfulResult(expectedFilename: String, attempts: VerificationMode = times(1)) = {
      val outputCaptor = ArgumentCaptor.forClass(classOf[String])
      verify(output, attempts).handleUpdate(outputCaptor.capture)

      val expectedXml = XML.loadString(fileToString(expectedFilename))
      val producedXml = XML.loadString(outputCaptor.getValue)
      assert(expectedXml === producedXml)
    }

    def fileToString(inputFilename: String): String = {
      val input = getClass.getResourceAsStream(inputFilename)
      assert(input != null, s"Couldn't find test input $inputFilename")
      Source.fromInputStream(input).mkString
    }

    def checkNoFailures() = verify(errorHandler, times(0)).handleError(any[Event], any[Throwable])

    /** Check that event processing failed and was treated correctly. */
    def checkFailure[T <: Throwable](event: Event)(implicit manifest: Manifest[T]) {
      // Check no output was given.
      verify(output, times(0)).handleUpdate(anyString)

      // Check event was passed on to error handler, along with the expected exception.
      val expectedExceptionClass = manifest.runtimeClass.asInstanceOf[Class[T]]
      verify(errorHandler).handleError(eql(event), isA(expectedExceptionClass))
    }

  }

}


text:
$(function () {

    $('#RelatorioVendas_data_inicial, #RelatorioVendas_data_final').mask('99/99/9999 99:99:99');

    $('.uncollapse').on('click', function () {
        $(this).closest('div').find('[data-action="collapse"]').trigger('click');
    });

    new Tokens('#RelatorioVendas_clientes', {
        url: window.protocol + window._parent + 'carrinho/clientes',
        type: 'post',
        names: ['id_cliente'],
        show: 'nome',
        cantReapeatComparison: ['id_cliente'],
        nothingMessage: 'Nenhum resultado encontrado.',
        load: clientes.data,
        remote: function (data, token) {
            token.process(data.data);
        }
    });

    new Tokens('#RelatorioVendas_bairros', {
        url: window.protocol + window._parent + 'relatorio-vendas/bairros',
        type: 'post',
        names: ['id_bairro'],
        show: 'nome',
        cantReapeatComparison: ['id_bairro'],
        nothingMessage: 'Nenhum resultado encontrado.',
        load: bairros.data,
        remote: function (data, token) {
            token.process(data.data);
        }
    });

    new Tokens('#RelatorioVendas_produtos', {
        url: window.protocol + window._parent + 'pedidos/produtos',
        type: 'post',
        names: ['id_produto'],
        show: 'nome',
        cantReapeatComparison: ['id_produto'],
        nothingMessage: 'Nenhum resultado encontrado.',
        load: produtos.data,
        remote: function (data, token) {
            token.process(data.data);
        }
    });

    new Tokens('#RelatorioVendas_status', {
        url: window.protocol + window._parent + 'relatorio-vendas/status',
        type: 'post',
        names: ['id_status'],
        show: 'nome',
        cantReapeatComparison: ['id_status'],
        nothingMessage: 'Nenhum resultado encontrado.',
        load: _status.data,
        remote: function (data, token) {
            token.process(data.data);
        }
    });

    if (typeof tojs !== 'undefined') {

        $('#full_valor h5').html('Foram vendidos R$ ' + tojs.valor + ' entre as datas ' + tojs.inicial + ' e ' + tojs.final + '');
        $('#full_quantidade h5').html(tojs.quantidade + ' produtos vendidos entre as datas ' + tojs.inicial + ' e ' + tojs.final + '');
        $('#full_lucro h5').html('O lucro total foi de R$ ' + tojs.custo + ' entre as datas ' + tojs.inicial + ' e ' + tojs.final + '');

        var fc = true;
        for (var i in tojs.produtos_valor) {
            var now = tojs.produtos_valor[i];
            var tr = $('

');
            if (fc === true) tr.addClass('bg-success-400');
            fc = false;
            tr.append('' + now['nome'] + '	');
            tr.append('' + now['quantidade'] + '	');
            tr.append('R$ ' + now['valor'] + '	');
            $('#resumo_produtos_valor tbody').append(tr);
        }

        fc = true;
        for (i in tojs.produtos_quantidade) {
            now = tojs.produtos_quantidade[i];
            tr = $('

');
            if (fc === true) tr.addClass('bg-success-400');
            fc = false;
            tr.append('' + now['nome'] + '	');
            tr.append('' + now['quantidade'] + '	');
            tr.append('R$ ' + now['valor'] + '	');
            $('#resumo_produtos_quantidade tbody').append(tr);
        }

        fc = true;
        for (i in tojs.sellers) {
            now = tojs.sellers[i];
            tr = $('

');
            if (fc === true) tr.addClass('bg-success-400');
            fc = false;
            tr.append('' + now['nome'] + '	');
            tr.append('' + now['quantidade'] + '	');
            tr.append('R$ ' + now['valor'] + '	');
            $('#resumo_vendedores tbody').append(tr);
        }

        fc = true;
        for (i in tojs.acheters) {
            now = tojs.acheters[i];
            tr = $('

');
            if (fc === true) tr.addClass('bg-success-400');
            fc = false;
            tr.append('' + now['nome'] + '	');
            tr.append('' + now['quantidade'] + '	');
            tr.append('R$ ' + now['valor'] + '	');
            $('#resumo_clientes tbody').append(tr);
        }
    }

});


text:
function [HDI,varargout] = GetHDIMu(PostMu,a,GridStructure)
% Get a High density Interval with a specified amplitude 1-a for the population mean
% for instance, if a= 0.05, the 95% HDI is provided (for internal
% consistency with Frequentist confidence intervals)
%
%
% Copyright 2015, Giancarlo Valente, Maastricht University

if a > 1 || a < 0
    error('the second parameter should be a percentage (between 0 and 1)');
end
mu      = GridStructure.mu;

[PostSort,idx]  = sort(PostMu);
CS              = cumsum(PostSort);
[~,idx1]        = find(CS> a,1,'first');
PostHeightHDI   = PostMu(idx(idx1));

ValInHDI        = false(size(mu));
ValInHDI(PostMu   > PostHeightHDI) = 1;

if  ~ValInHDI(1)
    LowerValue  = find(ValInHDI,1,'first');
else
    LowerValue = 1;
end

if  ~ValInHDI(end)
    HigherValue  = find(ValInHDI,1,'last');
else
    HigherValue = numel(mu);
end

HDI = mu([LowerValue HigherValue]);
% if needed, also the indices can be given as output
if nargout >= 2
    varargout{1} = [LowerValue HigherValue];
end


text:
require 'yaml'
require 'equalizer'
require 'memoizable'
require 'ice_nine'

module MutantSpec
  class Warning
    def self.assert_no_warnings
      return if EXTRACTOR.warnings.empty?

      fail UnexpectedWarnings, EXTRACTOR.warnings.to_a
    end

    class UnexpectedWarnings < StandardError
      MSG = 'Unexpected warnings: %s'.freeze

      def initialize(warnings)
        super(MSG % warnings.join("\n"))
      end
    end

    class Extractor < DelegateClass(IO)
      PATTERN = /\A(?:.+):(?:\d+): warning: (?:.+)\n\z/.freeze

      include Equalizer.new(:whitelist, :seen, :io), Memoizable

      def initialize(io, whitelist)
        @whitelist = whitelist
        @seen      = Set.new
        @io        = io

        super(io)
      end

      def write(message)
        return super if PATTERN !~ message

        add(message.chomp)

        self
      end

      def warnings
        seen.dup
      end
      memoize :warnings

    private

      def add(warning)
        return if whitelist.any?(&warning.public_method(:end_with?))

        seen << warning
      end

      attr_reader :whitelist, :seen, :io
    end

    warnings  = Pathname.new(__dir__).join('warnings.yml').freeze
    whitelist = IceNine.deep_freeze(YAML.load(warnings.read))

    EXTRACTOR = Extractor.new(STDERR, whitelist)
  end
end


text:
#ifndef encodeInputDecoder_h
#define  encodeInputDecoder_h

#include "decodeinput.h"
#include "encodeinput.h"

#include <Yami.h>
#include <map>

using namespace YamiMediaCodec;

class MyRawImage;
class EncodeInputDecoder : public  EncodeInput {
public:
    EncodeInputDecoder(DecodeInput* input);
    ~EncodeInputDecoder();
    virtual bool init(const char* inputFileName, uint32_t fourcc, int width, int height);
    virtual bool getOneFrameInput(VideoFrameRawData &inputBuffer);
    virtual bool recycleOneFrameInput(VideoFrameRawData &inputBuffer);
    virtual bool isEOS();
private:
    bool decodeOneFrame();
    DecodeInput* m_input;
    IVideoDecoder* m_decoder;
    bool m_isEOS;

    typedef std::map<uint32_t, SharedPtr<MyRawImage> > ImageMap;

    ImageMap m_images;
    uint32_t m_id;
    DISALLOW_COPY_AND_ASSIGN(EncodeInputDecoder);
};
#endif


text:
/**
  @module ember-data
*/

import { PromiseArray } from "ember-data/system/promise_proxies";
var get = Ember.get;
var set = Ember.set;

/**
  A record array is an array that contains records of a certain type. The record
  array materializes records as needed when they are retrieved for the first
  time. You should not create record arrays yourself. Instead, an instance of
  `DS.RecordArray` or its subclasses will be returned by your application's store
  in response to queries.

  @class RecordArray
  @namespace DS
  @extends Ember.ArrayProxy
  @uses Ember.Evented
*/

export default Ember.ArrayProxy.extend(Ember.Evented, {
  /**
    The model type contained by this record array.

    @property type
    @type DS.Model
  */
  type: null,

  /**
    The array of client ids backing the record array. When a
    record is requested from the record array, the record
    for the client id at the same index is materialized, if
    necessary, by the store.

    @property content
    @private
    @type Ember.Array
  */
  content: null,

  /**
    The flag to signal a `RecordArray` is currently loading data.

    Example

    ```javascript
    var people = store.all('person');
    people.get('isLoaded'); // true
    ```

    @property isLoaded
    @type Boolean
  */
  isLoaded: false,
  /**
    The flag to signal a `RecordArray` is currently loading data.

    Example

    ```javascript
    var people = store.all('person');
    people.get('isUpdating'); // false
    people.update();
    people.get('isUpdating'); // true
    ```

    @property isUpdating
    @type Boolean
  */
  isUpdating: false,

  /**
    The store that created this record array.

    @property store
    @private
    @type DS.Store
  */
  store: null,

  /**
    Retrieves an object from the content by index.

    @method objectAtContent
    @private
    @param {Number} index
    @return {DS.Model} record
  */
  objectAtContent: function(index) {
    var content = get(this, 'content');

    return content.objectAt(index);
  },

  /**
    Used to get the latest version of all of the records in this array
    from the adapter.

    Example

    ```javascript
    var people = store.all('person');
    people.get('isUpdating'); // false
    people.update();
    people.get('isUpdating'); // true
    ```

    @method update
  */
  update: function() {
    if (get(this, 'isUpdating')) { return; }

    var store = get(this, 'store');
    var type = get(this, 'type');

    return store.fetchAll(type, this);
  },

  /**
    Adds a record to the `RecordArray` without duplicates

    @method addRecord
    @private
    @param {DS.Model} record
    @param {DS.Model} an optional index to insert at
  */
  addRecord: function(record, idx) {
    var content = get(this, 'content');
    if (idx === undefined) {
      content.addObject(record);
    } else if (!content.contains(record)) {
      content.insertAt(idx, record);
    }
  },

  _pushRecord: function(record) {
    get(this, 'content').pushObject(record);
  },

  /**
    Adds a record to the `RecordArray`, but allows duplicates

    @deprecated
    @method pushRecord
    @private
    @param {DS.Model} record
  */
  pushRecord: function(record) {
    Ember.deprecate('Usage of `recordArray.pushRecord` is deprecated, use `recordArray.addObject` instead');
    this._pushRecord(record);
  },
  /**
    Removes a record to the `RecordArray`.

    @method removeRecord
    @private
    @param {DS.Model} record
  */
  removeRecord: function(record) {
    get(this, 'content').removeObject(record);
  },

  /**
    Saves all of the records in the `RecordArray`.

    Example

    ```javascript
    var messages = store.all('message');
    messages.forEach(function(message) {
      message.set('hasBeenSeen', true);
    });
    messages.save();
    ```

    @method save
    @return {DS.PromiseArray} promise
  */
  save: function() {
    var recordArray = this;
    var promiseLabel = "DS: RecordArray#save " + get(this, 'type');
    var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) {
      return recordArray;
    }, null, "DS: RecordArray#save return RecordArray");

    return PromiseArray.create({ promise: promise });
  },

  _dissociateFromOwnRecords: function() {
    var array = this;

    this.forEach(function(record) {
      var recordArrays = record._recordArrays;

      if (recordArrays) {
        recordArrays.delete(array);
      }
    });
  },

  /**
    @method _unregisterFromManager
    @private
  */
  _unregisterFromManager: function() {
    var manager = get(this, 'manager');
    //We will stop needing this stupid if statement soon, once manyArray are refactored to not be RecordArrays
    if (manager) {
      manager.unregisterFilteredRecordArray(this);
    }
  },

  willDestroy: function() {
    this._unregisterFromManager();
    this._dissociateFromOwnRecords();
    set(this, 'content', undefined);
    this._super.apply(this, arguments);
  }
});


text:
package com.planet_ink.coffee_mud.Commands;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.Abilities.interfaces.*;
import com.planet_ink.coffee_mud.Areas.interfaces.*;
import com.planet_ink.coffee_mud.Behaviors.interfaces.*;
import com.planet_ink.coffee_mud.CharClasses.interfaces.*;
import com.planet_ink.coffee_mud.Commands.interfaces.*;
import com.planet_ink.coffee_mud.Common.interfaces.*;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;

import java.util.*;

@SuppressWarnings("unchecked")
public class Practice extends StdCommand
{
	public Practice(){}

	private String[] access={"PRACTICE","PRAC"};
	public String[] getAccessWords(){return access;}
	public boolean execute(MOB mob, Vector commands, int metaFlags)
		throws java.io.IOException
	{
		if(commands.size()<2)
		{
			mob.tell("You have "+mob.getPractices()+" practice points.  Enter HELP PRACTICE for more information.");
			return false;
		}
		commands.removeElementAt(0);

		MOB teacher=null;
		if(commands.size()>1)
		{
			teacher=mob.location().fetchInhabitant((String)commands.lastElement());
			if(teacher!=null) commands.removeElementAt(commands.size()-1);
		}

		String abilityName=CMParms.combine(commands,0);

		if(teacher==null)
		for(int i=0;i<mob.location().numInhabitants();i++)
		{
			MOB possTeach=mob.location().fetchInhabitant(i);
			if((possTeach!=null)&&(possTeach.findAbility(abilityName)!=null)&&(possTeach!=mob))
			{
				teacher=possTeach;
				break;
			}
		}

		if((teacher==null)||(!CMLib.flags().canBeSeenBy(teacher,mob)))
		{
			mob.tell("That person doesn't seem to be here.");
			return false;
		}

		Ability myAbility=mob.findAbility(abilityName);
		if(myAbility==null)
		{
			mob.tell("You don't seem to know "+abilityName+".");
			return false;
		}
		if(!myAbility.savable())
		{
			mob.tell(abilityName+" cannot be practiced, as it is a native skill.");
			return false;
		}

		Ability teacherAbility=mob.findAbility(abilityName);
		if(teacherAbility==null)
		{
			mob.tell(teacher.name()+" doesn't seem to know "+abilityName+".");
			return false;
		}

		if(!teacherAbility.canBeTaughtBy(teacher,mob))
			return false;
		if(!teacherAbility.canBePracticedBy(teacher,mob))
			return false;
		CMMsg msg=CMClass.getMsg(teacher,mob,null,CMMsg.MSG_SPEAK,null);
		if(!mob.location().okMessage(mob,msg))
			return false;
		msg=CMClass.getMsg(teacher,mob,null,CMMsg.MSG_NOISYMOVEMENT,"<S-NAME> practice(s) '"+myAbility.name()+"' with <T-NAMESELF>.");
		if(!mob.location().okMessage(mob,msg))
			return false;
		teacherAbility.practice(teacher,mob);
		mob.location().send(mob,msg);
		return false;
	}
    public double combatActionsCost(MOB mob, Vector cmds){return CMath.div(CMProps.getIntVar(CMProps.SYSTEMI_DEFCOMCMDTIME),100.0);}
    public double actionsCost(MOB mob, Vector cmds){return CMath.div(CMProps.getIntVar(CMProps.SYSTEMI_DEFCMDTIME),100.0);}
	public boolean canBeOrdered(){return false;}

}


text:
---
layout: post
title: "Polymer 1.x Cheat Sheet"
category: posts
---

<style>
.highlight .err {
  color: inherit;
  background-color: inherit;
}
.highlight .s1, .highlight .s {
  color: #336699;
  background: inherit;
}
pre {
  margin-bottom: 30px;
}
pre, code {
  background: #f4f6f8;
}
p > code, li > code {
  font-weight: bold;
}
pre {
  border-bottom: solid 1px #CFD8DC;
}
</style>

This is a cheat sheet for the [Polymer 1.x](https://www.polymer-project.org/1.0/) library.
It helps you write Web Components, which are pretty 🔥🔥🔥. If you're interested in the
Polymer 2.0 cheat sheet, it's [here](https://meowni.ca/posts/polymer-2-cheatsheet/). If you think something
is missing from this page, [tell me](https://twitter.com/intent/tweet?original_referer=https%3A%2F%2Fmeowni.ca%2F&ref_src=twsrc%5Etfw&text=@notwaldorf%20Polymer%20cheat%20sheet%20feature%20request:) about it!

* TOC
{:toc}

## Defining an element

Docs: [registering an element](https://www.polymer-project.org/1.0/docs/devguide/registering-elements), [behaviours](https://www.polymer-project.org/1.0/docs/devguide/registering-elements#prototype-mixins), [shared style modules](https://www.polymer-project.org/1.0/docs/devguide/styling#style-modules)

```html
<dom-module id="element-name">
  <template>
    <!-- Use one of these style declarations, but not both -->
    <!-- Use this if you don't want to include a shared style -->
    <style></style>
    <!-- Use this if you want to include a shared style -->
    <style include="some-style-module-name"></style>
  </template>
  <script>
    Polymer({
      is: 'element-name',
      // All of these are optional. Only keep the ones you need.
      behaviors: [],
      observers: [],
      listeners: {},
      hostAttributes: {},
      properties: {}
    });
  </script>
</dom-module>
```

## Defining a behaviour

Docs: [behaviours](https://www.polymer-project.org/1.0/docs/devguide/behaviors).

Defining a behavior to share implementation between different elements:

```html
<script>
  MyNamespace.MyFancyBehaviorImpl = {
    // Code that you want common to elements, such
    // as behaviours, methods, etc.
  }

  MyNamespace.MyFancyBehavior = [
    MyFancyBehaviorImpl,
    /* You can add other behaviours here */
  ];
</script>
```

Using the behavior in an element:

```html
<dom-module id="element-name">
  <template>
    <!-- ... -->
  </template>
  <script>
    Polymer({
      is: 'element-name',
      behaviors: [MyNamespace.MyCustomButtonBehavior]
      /* ... */
    });
  </script>
</dom-module>
```

## Lifecycle methods

Docs: [lifecycle callbacks](https://www.polymer-project.org/1.0/docs/devguide/registering-elements#lifecycle-callbacks).

```js
Polymer({
  registered: function() {},
  created: function() {},
  ready: function() {},
  attached: function() {},
  detached: function() {}
});
```

There's an `attributeChanged` callback as well, but that's very rarely used.

## Data binding
Docs: [data binding](https://www.polymer-project.org/1.0/docs/devguide/data-binding),
[attribute binding](https://www.polymer-project.org/1.0/docs/devguide/data-binding#attribute-binding),
[binding to array items](https://www.polymer-project.org/1.0/docs/devguide/data-binding#bind-array-item),
[computed bindings](https://www.polymer-project.org/1.0/docs/devguide/data-binding#annotated-computed).

Don't forget: Polymer [camel-cases](https://www.polymer-project.org/1.0/docs/devguide/properties#property-name-mapping) properties, so if in JavaScript you use `myProperty`,
in HTML you would use `my-property`.

**One way** binding: when `myProperty` changes, `theirProperty` gets updated:

```html
<some-element their-property="[[myProperty]]"></some-element>
```

**Two way** binding: when `myProperty` changes, `theirProperty` gets updated,
and vice versa:

```html
{% raw %}<some-element their-property="{{myProperty}}"></some-element>{% endraw %}
```

**Attribute binding**: when `myProperty` is `true`, the element is hidden; when it's
`false`, the element is visible:

```html
<some-element hidden$="[[myProperty]]"></some-element>
```

**Computed binding**: binding to the `class` attribute will recompile styles when
`myProperty` changes:

```html
<some-element class$="[[_computeSomething(myProperty)]]"></some-element>

_computeSomething: function(prop) {
  return prop ? 'a-class-name' : 'another-class-name';
}
```

## Observers

Docs: [observers](https://www.polymer-project.org/1.0/docs/devguide/observers),
[multi-property observers](https://www.polymer-project.org/1.0/docs/devguide/observers#multi-property-observers),
[observing array mutations](https://www.polymer-project.org/1.0/docs/devguide/observers#array-observation).

Adding an `observer` in the `properties` block lets you observe changes in the
value of a property:

```js
properties: {
  myProperty: {
    observer: '_myPropertyChanged'
  }
},

// The second argument is optional, and gives you the
// previous value of the property, before the update:
_myPropertyChanged: function(value, /*oldValue */) {
  //...
}
```

In the `observers` block:

```js
observers: [
  '_doSomething(myProperty)',
  '_multiPropertyObserver(myProperty, anotherProperty)',
  '_observerForASubProperty(user.name)',
  // Below, items can be an array or an object:'
  '_observerForABunchOfSubPaths(items.*)'
]
```

## Listeners
Docs: [event listeners](https://www.polymer-project.org/1.0/docs/devguide/events#event-listeners),
[imperative listeners](https://www.polymer-project.org/1.0/docs/devguide/events#imperative-listeners).

```js
listeners: {
  'click': '_onClick',
  'input': '_onInput',
  'something-changed': '_onSomethingChanged'
}
```

## Properties block

Docs: [declared properties](https://www.polymer-project.org/1.0/docs/devguide/properties),
[object/array properties](https://www.polymer-project.org/1.0/docs/devguide/properties#configuring-object-and-array-properties),
[read-only properties](https://www.polymer-project.org/1.0/docs/devguide/properties#read-only),
[computed properties](https://www.polymer-project.org/1.0/docs/devguide/observers#define-a-computed-property).

There are all the possible things you can use in the `properties`
block. Don't just use all of them because you can; some (like `reflectToAttribute`
  and `notify`) can have performance implications.

```js
properties: {
  basic: {
    type: Boolean | Number | String | Array | Object,

    // Value can be one of the types above, eg:
    value: true,

    // For an Array or Object, you must return it from a function
    // (otherwise the array will be defined on the prototype
    // and not the instance):
    value: function() { return ['cheese', 'pepperoni', 'more-cheese'] },

    reflectToAttribute: true | false,
    readOnly: true | false,
    notify: true | false
  },

  // Computed properties are essentially read-only, and can only be
  // updated when their dependencies change.
  basicComputedProperty: {
    computed: '_someFunction(myProperty, anotherProperty)'
  }
}
```

## Observing added and removed children

Docs: [DOM distribution](https://www.polymer-project.org/1.0/docs/devguide/local-dom#dom-distribution),
[observe nodes](https://www.polymer-project.org/1.0/docs/devguide/local-dom#observe-nodes).

If you have a content node for distribution:

```html
<template>
  <slot id="distributed"></slot>
</template>
```
And you want to be notified when nodes have been added/removed:

```js
attached: function() {
  this._observer =
    Polymer.dom(this.$.distributed).observeNodes(function(info) {
    // info is {addedNodes: [...], removedNodes: [...]}
  });
},
detached: function() {
  Polymer.dom(this.$.distributed).unobserveNodes(this._observer);
}
```

## Style modules
Docs: [shared style modules](https://www.polymer-project.org/1.0/docs/devguide/styling#style-modules).

Defining styles that will be shared across different elements, in a file called
`my-shared-styles.html` (for example):

```html
<dom-module id="my-shared-styles">
  <template>
    <style>
      .red { color: red; }
      /* Custom property defined in the global scope */
      html {
        --the-best-red: #e91e63;
      }
    </style>
  </template>
</dom-module>
```

Include the shared style in a custom element:

```html
<link rel="import" href="my-shared-styles.html">
<dom-module id="element-name">
  <template>
    <style include="my-shared-styles">
      /* Other styles in here */
    </style>
  </template>
  <script>
    Polymer({ is: 'element-name' });
  </script>
</dom-module>
```

Include the shared style in the main document:

```html
<html>
<head>
  <link rel="import" href="my-shared-styles.html">
  <style is="custom-style" include="my-shared-styles">
    /* Other styles in here */
  </style>
</head>
<body>...</body>
</html>
```

## Styling with custom properties and mixins

Docs: [styling](https://www.polymer-project.org/1.0/docs/devguide/styling),
[CSS properties](https://www.polymer-project.org/1.0/docs/devguide/styling#custom-css-properties),
[CSS mixins](https://www.polymer-project.org/1.0/docs/devguide/styling#custom-css-mixins),
[shim limitations](https://www.polymer-project.org/1.0/docs/devguide/styling#custom-properties-shim-limitations)

Note that the examples below depend on browser support for custom properties.
For how to use the shim (spoilers: it's `<style is="custom-style">`) and its limitations,
check the docs linked above.

Defining a custom property:

```css
html /* or :host, or :root etc. */{
  --my-custom-radius: 5px;
}
```

Using a custom property:

```css
.my-image {
  border-radius: var(--my-custom-radius);
}
```

Using a custom property with a fallback:

```css
.my-image {
  border-radius: var(--my-custom-radius, 3px);
}
```

Using a custom property with a custom property fallback:

```css
.my-image {
  border-radius: var(--my-custom-radius, var(--my-fallback));
}
```

Defining a mixin:

```css
some-custom-element {
  --my-custom-mixin: {
    border-radius: 5px;
  };
}
```

Using a mixin:

```css
.my-image {
  @apply --my-custom-mixin;
}
```

## Binding helper elements

Docs: [dom-repeat](https://www.polymer-project.org/1.0/docs/api/dom-repeat),
[dom-bind](https://www.polymer-project.org/1.0/docs/api/dom-bind),
[dom-if](https://www.polymer-project.org/1.0/docs/api/dom-if)

`dom-repeat` stamps and binds a template for each item in an array:

```html
{% raw %}<template is="dom-repeat" items="{{employees}}">
  <div>First name: <span>{{item.first}}</span></div>
  <div>Last name: <span>{{item.last}}</span></div>
</template>{% endraw %}
```

`dom-bind` stamps itself into the main document and adds a binding scope:

```html
{% raw %}<html>
<body>
  <template is="dom-bind">
    <paper-input value="{{myText}}"></paper-input>
    <span>You typed: [[myText]]</span>
  </template>
</body>
<html>{% endraw %}
```

`dom-if` stamps itself conditionally based on a property's value:

```html
{% raw %}<template is="dom-if" if="{{myProperty}}">
  <span>This content will appear when myProperty is truthy.</span>
</template>{% endraw %}
```