← Back to team overview

yade-dev team mailing list archive

[Merge] lp:yade/0.60 into lp:yade

 

Çağdaş GÜRBÜZ has proposed merging lp:yade/0.60 into lp:yade.

Requested reviews:
  Yade packagers (yade-pkg)

For more details, see:
https://code.launchpad.net/~yade-dev/yade/0.60/+merge/195351
-- 
The attached diff has been truncated due to its size.
https://code.launchpad.net/~yade-dev/yade/0.60/+merge/195351
Your team Yade developers is subscribed to branch lp:yade.
=== added file '.bzrignore'
--- .bzrignore	1970-01-01 00:00:00 +0000
+++ .bzrignore	2013-11-15 08:22:02 +0000
@@ -0,0 +1,31 @@
+tags
+scons.current-profile
+scons.profile-*
+.project
+yade.1
+debian/changelog
+debian/control
+doc/epydoc
+
+doc/sphinx/WallStresses
+doc/sphinx/_build/
+doc/sphinx/_publications.bib
+doc/sphinx/abc.xml
+doc/sphinx/modules.rst
+doc/sphinx/publications.rst
+doc/sphinx/references.rst
+doc/sphinx/yade.eudoxos.rst
+doc/sphinx/yade.export.rst
+doc/sphinx/yade.linterpolation.rst
+doc/sphinx/yade.log.rst
+doc/sphinx/yade.pack.rst
+doc/sphinx/yade.plot.rst
+doc/sphinx/yade.post2d.rst
+doc/sphinx/yade.qt.rst
+doc/sphinx/yade.timing.rst
+doc/sphinx/yade.utils.rst
+doc/sphinx/yade.wrapper.rst
+doc/sphinx/yade.ymport.rst
+.kdev4/yade.kdev4
+yade.kdev4
+

=== added directory '.kdev4'
=== added file '.kdev4/yade.kdev4'
--- .kdev4/yade.kdev4	1970-01-01 00:00:00 +0000
+++ .kdev4/yade.kdev4	2013-11-15 08:22:02 +0000
@@ -0,0 +1,31 @@
+[Buildset]
+BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00\x08\x00y\x00a\x00d\x00e)
+
+[Launch]
+Launch Configurations=Launch Configuration 0
+
+[Launch][Launch Configuration 0]
+Configured Launch Modes=execute
+Configured Launchers=nativeAppLauncher
+Name=yade-debug
+Type=Native Application
+
+[Launch][Launch Configuration 0][Data]
+Arguments=\s/home/3S-LAB/bchareyre/yade/yade-test-kdev/bin/yade-true-true --debug -j 1  /home/3S-LAB/bchareyre2/yade/yade-test-kdev/yade/scripts/test/chained-cylinder-spring.py
+Debugger Shell=
+Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x00)
+Dependency Action=Nothing
+Display Demangle Names=true
+Display Static Members=false
+EnvironmentGroup=default
+Executable=python
+GDB Path=gdb
+Remote GDB Config Script=
+Remote GDB Run Script=
+Remote GDB Shell Script=
+Try Setting Breakpoints On Loading Libraries=true
+Working Directory=
+isExecutable=true
+[MakeBuilder]
+Make Binary=scons
+Number Of Jobs=3

=== added file 'AUTHORS'
--- AUTHORS	1970-01-01 00:00:00 +0000
+++ AUTHORS	2013-11-15 08:22:02 +0000
@@ -0,0 +1,26 @@
+svn blame lines count as of r.1683
+find -iname "*[hc]pp" -exec svn blame {} \; | awk '{print $2}' | sort | uniq -c | sort -rn
+
+38752 Vaclav Smilauer      <eudoxos@xxxxxxxxxxxxxxx>    
+33887 Janek Kozicki        <cosurgi@xxxxxxxxxxxxxxx>    
+11962 Bruno Chareyre       <chareyre@xxxxxxxxxxxxxxx>   
+10446 Olivier Galizzi      <galizzi@xxxxxxxxxxxxxxx>    
+ 4448 Sergei Dorofeenko    <sega@xxxxxxxxxxxxxxx>       
+ 3787 Vincent Richefeu     <richefeu@xxxxxxxxxxxxxxx>   
+ 3360 Jerome Duriez        <jduriez@xxxxxxxxxxxxxxx>    
+  835 Jean-François Jerier <jfjerier@xxxxxxxxxxxxxxx>   
+  201 Feng Chen            <fchen3@xxxxxxxxxxxxxxx>     
+    0 Thibault Lhermitte   <lhermitte@xxxxxxxxxxxxxxx>  
+    0 Luc Sibille          <lucsibille@xxxxxxxxxxxxxxx> 
+    0 Lionel Favier        <lfavier@xxxxxxxxxxxxxxx>    
+    0 Artur R. Czechowski  <arturcz@xxxxxxxxxxxxxxx>    
+    0 Andrzej Oszer        <przewdnik@xxxxxxxxxxxxxxx>  
+
+
+To produce a signature for some specific file, use this command:
+
+svn blame core/MetaBody.hpp | awk '{print $2}' | sort | uniq -c | \
+sort -rn | awk '{print $2}' | \
+xargs -n 1 -I person fgrep person AUTHORS | \
+sed -e 's/ *[0-9]* \(.*\)/* (C) \1                 */'
+

=== added file 'ChangeLog'
--- ChangeLog	1970-01-01 00:00:00 +0000
+++ ChangeLog	2013-11-15 08:22:02 +0000
@@ -0,0 +1,1604 @@
+NOTE: this changelog is no longer maintained as of 8/2009,
+go to http://bazaar.launchpad.net/~yade-dev/yade/trunk/changes
+for complete history or use bzr log on your local checkout/branch.
+
+---
+
+2008-08-20 Janek Kozicki <cosurgi@xxxxxxxxx> revision 1480
+
+	* ChangeLog: New ChangeLog format. Please use this format in your
+	entries (I don't like updating ChangeLog once per year with 240
+	revisions ;)). New ChangeLog format is:
+
+	* path/File, or list of files: summary of modifications. But please
+	keep ChangeLog short (svn log is for details), if you modify 100 files
+	together, don't list all of them. Be prudent.
+
+
+WARNING: the ChangeLog update below is sloppy, because it was done by single
+person (Janek) in few hours, by examining 'svn log' output of 240 commits(!!).
+All entries above this one are supposed to be much better in quality. Because
+they will be written by the people who are authors of those changes.
+
+2008-08-19  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1475
+	
+	* pkg/dem/Engine/StandAloneEngine/GlobalStiffnessCounter.cpp: Fix
+	physical action index.
+
+	* SConstruct: Kill building threads if the master thread is interrupted
+	in multi-builds (profile=a,b)
+
+	* gui/py/PythonUI_rc.py, core/yade.cpp: Do not propagate exception to c++
+	-> crash if there is python exception in the script being run from
+	command-line. Just print traceback and drop to the python console
+	(unless stop after execution specified)
+
+	* gui/py/PuthonUI.cpp: Fix GUI "crash" when trying to run python
+	console without terminal (running by clicking an icon, for example):
+	if no $TERM, run non-interactively
+
+	* core/yade.cpp: Select QtGUI over PythonUI if no $TERM set
+
+
+2008-08-16  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1470
+
+	* NormalShearInteractions.cpp: Added new (abstract) classes:
+	NormalInteraction (with kn (normal) sitffness) and
+	NormalShearInteraction (additionally, with ks (shear) stiffness). They
+	are used by GlobalStiffnessCounter.
+
+	* pkg/common/DataClass/InteractionPhysics/SimpleElasticInteraction.cpp:
+	Removed SimpleElasticInteraction, since it it basically
+	NormalInteraction, and changed all code to reflect that.
+
+	* pkg/dem/Engine/StandAloneEngine/GlobalStiffnessCounter.cpp: Changed
+	GlobalStiffnessCounter to work with the NormalShearInteraction class,
+	since it provides an abdstract interface and will be useful with more
+	classes than just ElasticContactInteraction.
+
+
+2008-08-14 Janek Kozicki <cosurgi@xxxxxxxxx> revision 1469
+
+	* pkg/mass-spring/PreProcessor/HangingCloth.cpp
+	* pkg/fem/PreProcessor/FEMBeam.cpp: use NDEBUG to detect optimized
+	builds in FEMBeam and HangingCloth
+
+
+2008-08-14  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1468
+
+	* core/Omega.cpp: Remove draw mutex when loading simulation introduced
+	a few days ago (may throw boost::lock_error under some conditions)
+
+	* core/yade.cpp: Restore default signal handlers before exit from
+	main; set SEGV handler to nullHandler since on i386 we (on lenny
+	consistently) get crashes in some log4cxx destructor.
+
+
+2008-08-12  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1463
+
+	* gui/qt3/YadeQtMainWindow.cpp
+	* gui/qt3/SimulationController.cpp: Fix refresh period: use it for
+	regular GL rendering as well
+
+	* gui/qt3/QtFileGenerator.cpp: Make "open automatically" open
+	generated simulation even if a simulation is already loaded.
+	Fix crashes (on some machines) the close() was emitted 2�for
+	QtFileGenerato
+
+	* gui/py/PythonUI_rc.py: Fix error with newer ipython coming from the
+	fact that sys.argv wasn't defined in the embedded python env.
+
+
+2008-07-30  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1455-1449
+
+	* lib/miniWm3/Wm3Math.cpp:  DECREASED Mathr::ZERO_TOLERANCE to 1e-20
+	so that we don't get identity quaternions for small rotation in
+	ToAxisAngle (!!)
+
+	* gui/tq3/GLViewer.cpp: Add glue for GLViewer, currently may crash,
+	probably concurrency issues there
+
+	* scripts/make-release.sh: Add script for making release
+
+
+2008-07-17  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1432
+
+	* core/MetaBody.cpp: Multiple display parameters (i.e. QGLViewer
+	config and OpenGLRenderingEngine config) are stored in Metabody.
+
+	* core/MetaBody.cpp: stopAtIteration moved to MetaBody so that it is
+	saved and reloaded (MetaBody::recover hack is gone)
+
+	* lib/serialization/IOFormatManager.cpp: Add the ability to load from
+	stream and save to stream to IOFormatManager (afterwards, I discovered
+	there were actually_identical_ functions loadArchive and saveArchive;
+	those were deleted since unused elsewhere)
+
+	* gui/qt3/GLViewer.cpp: GLViewer can now load and save state from/to
+	string
+
+	* gui/qt3/GLViewer.cpp: in GLViewer, keys 7,8,9 load display config
+	#0,1,2 and Alt-{7,8,9} saves current view to #0,1,2. Those are saved
+	in MetaBody. BUG: after loading such config, the QtGUI-generated
+	OpenGLRenderingEngine config dialog doesn't work anymore (probably
+	some issue with archives, not sure).
+
+	* lib/serialization-qt/FundamentalHandler.tpp: Hopefully all
+	xml-parser-offensive characters are escaped at string serialization,
+	and unescaped at deserialization. We use standard SGML escapes (newline=&br;
+	tab=&tab; <=&lt;) and so on now. This allows one to save
+	XML-as-string in the xml itself (used for DisplayParameters).
+
+	* gui/qt3/GLViewer.cpp: GLViewer now properly saves what XYZ planes
+	are displayed (using custom DOM element)
+
+	* extra/Brefcom.cpp: Some fixes in Brefcom, more to come.
+
+
+2008-07-10  Sergei Dorofeenko <dorofeenko@xxxxxxxxx> revision 1419
+
+	* core/FiltrEngine.cpp: FiltrEngine is a base engine for a scene
+	filtration before visualization (both for a player and for a
+	controller). The filtration is activated through GUI (now only for
+	SimulationPlayer).
+
+	* pkg/common/Engine/FiltrEngine/ColorizedLayerFilter.cpp: allocates
+	with colour a layer of bodies
+
+	* pkg/common/Engine/FiltrEngine/ColorizedVelocityFilter.cpp: allocates
+	with colour a velocity of bodies
+
+
+2008-06-29  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1405
+
+	* gui/qt3/SimulationController.cpp
+	* gui/qt3/GLViewer.cpp: Implemented clipping planes in the GL viewer
+	and GL renderer
+
+	* gui/qt3/GLViewer.cpp: Moving body is now consistent with mouse
+	bindings for moving scene
+
+
+2008-05-10  Sergei Dorofeenko <dorofeenko@xxxxxxxxx> revision 1347
+
+	* pkg/dem/PreProcessor/STLImporterTest.cpp: Main commit: import a
+	geometry of walls from a STL file.
+
+
+2008-03-30  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1290
+
+	* cmdGui.cpp: allow saving spheres (format like small.sdec.xyz) from python
+
+	* PositionOrientationRecorder.cpp can optionally record RGB color of each
+	body as well now
+
+	* GLSimulationPlayerviewer.cpp: SimulationPlayer now can change colors
+	of bodies, if the .rgb file exists
+
+	* Brefcom.cpp: Bunch of fixes if brefcom, in UniaxialStrainControlledTest
+
+	* Omega.cpp, MetaBody.cpp: dt moved from Omega to MetaBody for good;
+	this allows preprocessor to set timestep that will be used when the
+	simulation is loaded.
+
+
+2008-03-25  Sergei Dorofeenko <dorofeenko@xxxxxxxxx> revision 1285
+
+	* SimpleViscoelastic*.cpp: Add linear viscoelastic contact model
+
+
+2008-03-22  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1281-1283
+
+	* extra/Brefcom.cpp: Include fracture strain calibration routines in brefcom.
+		- Add BrecomDamageColorizer - changes colora ccording to average
+		cohesive interactions the body has.
+		- Delete non-cohesive interactions from inside BrefcomLaw when
+		spheres become distant.
+		- Documentation updates.
+
+	* gui/qt3/GLSimulationPlayerviewer.cpp: Resurredced and un-crapped
+	simulation player (for making videos). Updated howto is
+	http://yade.wikia.com/wiki/New:Making_videos#Using_Simulation_Player_with_svn.3E1281
+
+	* pkg/common/engine/DeuxExMachina/CentralGravityEngine.cpp: 
+	* pkg/common/engine/DeuxExMachina/PositionOrientationRecorder.cpp:
+	Added some comments to didactical CentralGravityEngine and to
+	PositionOrientationRecorder.
+
+	1. MAJOR improvements of the python wrappers (constructors take attributes etc.)
+
+	2. FIRST proof-of-implementation simulation completely created in python:
+	scripts/simple-scene.py. This file will be commented abundantly shortly.
+
+	3. Add default values to some bool params so that there is no serializer error
+	if they are uninitialized.
+
+	4. Add aabbEnlargeFactor to InteractingSphere2AABB�(should be added to
+	InteractingBox2AABB as well?) (not tested yet)
+
+	5. rename InteractionDetectionFactor to interactinDetectionFactor
+
+	6. Serialization now registers only attributes that have not yet been
+	registered (there were problems with python because of that: at first save,
+	attributes were duplicated and the xml file was less readble, although
+	loadable)
+
+	7. Scan .tpp and .ipp for c++ tags as well
+
+	8. Some documentation.
+
+
+2008-08-18 Janek Kozicki <cosurgi@xxxxxxxxx> revision 1280
+
+	* CohesiveFrictionalContactLaw.cpp: added Moment Law
+
+	* ForceEngine.cpp: now works on subscribedBodies
+
+	* MomentEngine.cpp: new engine added
+
+	* KnownFundamentalsHandler.tpp: it wasn't compiling if you tried to
+	save quaternions to file. Basically change the case of function calls: x();
+	into X();
+
+
+2008-03-13  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1274
+
+	* lib/QGLViewer/* : BIG - Moved latest upstream qglviewer to our tree. If
+	you REALLY need to use the packaged version, let me know. As of now,
+	there is no way to do that.
+
+	* gui/qt3/* : BIG: Removed many (unfunctional) parts of the qt3 GUI,
+	in the view of qt4 migration which will probably not happen. Maybe I
+	removed too much (simulation player -- does it work?!), let me know in
+	that case.
+
+
+2008-03-03  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1270-1273
+
+	* scripts/default-test.py: Test suite for all preprocessors
+	
+	* scripts/default-test.py: handles crashing simulations gracefully (by
+	executing them in a subprocess)
+
+	* GlobalStiffnessCounter.cpp: Added assumeElasticSpheres attribute to
+	GlobalStiffnessCounter; if set to false, dynamic_casts are used to
+	properly determine type of contact between spheres (used in USCTGen
+	now)
+
+	* yade.cpp: Debugger now dumps backtrace without interruption and
+	exits immediately (core is still dumped)
+
+	* cmdGui.cpp: now exports yade binary name (to allow spawning
+	subprocesses)
+
+	* Omega.cpp: retains original argc and argv from the command line.
+
+	* PersistentSAPCollider.cpp: Remove NaN's in PersistentSAPCollider for
+	bodies that don't have bounding box: use zero-size degenerate box at
+	its position instead. (fixes warning when running ClumpTestGen)
+
+	* SConstruct: Remove check for scientific python from scons as we
+	don't use it now.
+
+
+2008-02-27 Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> revision 1268
+
+	* NewtonsDampedLaw.cpp : new engine.
+		The result is exactly the same as with :
+		- CundallNonViscousForceDamping
+		- CundallNonViscousMomentumDamping
+		- NewtonsForceLaw
+		- NewtonsMomentumLaw
+		- LeapFrogPositionIntegrator
+		- LeapFrogOrientationIntegrator
+
+	But this engine is faster because it uses less loops and less dispatching. 
+ 
+	Requirements :
+		- All dynamic bodies must have physical parameters of type (or inheriting from) BodyMacroParameters
+		- Physical actions must include forces and moments
+
+
+2008-02-15 Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> revision 1237
+
+	* yade.cpp: conditional compilation in order to compile with boost 1.33
+
+	* TriaxialTest.cpp: instanciation of a SimpleElasticRelationship 
+	object before adding it to engines (to avoid a crash). Va�v please, 
+	what is going on here?
+
+	* TriaxialCompressionEngine.cpp: 
+		- 0.5 factor in front of UnbalancedForce equation
+		- small fixes in default values
+		- timestep, unbalancedForce, and "Compression started" is displayed 
+		again during triaxial test run
+
+
+2008-02-13  Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1246
+
+	* yade.cpp: Preliminary recovery of simulation accross runs (try
+	sending SIGHUP to yade)
+
+	* cmdGui.cpp: Python wrapper for body parameters.
+
+	* Omega.cpp: Allow Omega to stop at predefined iteration number (for
+	regression tests, I work on that ;-) )
+
+
+2008-08-20 Janek Kozicki <cosurgi@xxxxxxxxx> revision 1480
+
+	* CundallNonViscousMomentumDamping.cpp: Fix FUNCTOR2D mistake
+	
+	* qt3 files: make it compile with python2.4 and qt3 (which sucks)
+
+	* NOTE: python-scientific requires boost 1.34
+
+
+2008-01-24 Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1243
+	* MetaEngine.cpp: Remove MetaEngine, inherit MetaDispatchingEngine
+	directly
+
+	* TriaxialStressEngine.cpp: Fix unbalanced force reporting (thanks for
+	complaining, Bruno)
+
+	* EngineUnit.cpp: EngineUnits now declare their types with FUNCTOR1D(.) or
+	FUNCTOR2D(.,.) macros, dispatchers will ask for their types
+	automagically. Old syntax still supported, once all engines have those
+	types declared, it will be obsoleted and removed (like
+	e->add("InteractingSphere","InteractingSphere","InteractingSphere2InteractingSphere4SpheresContactGeometry");
+	Shop and USCTGen usethe new syntax now.
+
+	* BrefcomLaw.cpp: Brefcom law passes some rudimentary tests and appears to work
+	(normal force and damage for now; we miss shear force and blocked
+	rotations)
+
+	* BrefcomContact.cpp: Brefcom contact can be drawn with opengl, damage signified by color.
+
+	* cmdGui.cpp: Updated Python wrapper.
+
+
+2008-01-24 Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1242
+	1. BIG update of python wrappers - enagines can be created, added,
+	modified from python now. Examples will be provided very soon.
+
+	2. fix plugin loader for multi-plugins: YADE_PLUGIN() macro should be
+	used in all plugins, otherwise due to linking symbol overrides a
+	multi-plugin will shadow classes in the plugin actually being loaded
+	(better solution?!)
+
+	3. Add experimental BREakable Frictional COhesive Moment-blocking
+	material (brefcom for short), not yet fully done.
+
+	4. PersistentSAPCollider now can be parametrized to permit distant
+	contacts (is not the default, though), incorporating Bruno's changes
+	in DistantPersistentSAPCollider
+
+	5. Uniaxial strain-controlled test (USCT), a quite simple
+	implementation. Used primarily for brefcom testing now.
+
+	6. Fix SConstruct so that it is backward-compatible with python2.4
+
+
+2008-01-27 Janek Kozicki <cosurgi@xxxxxxxxx> revision 1240
+	* LatticeExample.cpp: Use lattice model for simulation of concrete
+	with steel fibres reinforcement.
+	* SConstruct: SConstruct is now working on debian etch,
+	* Doxyfile: exclude multimethods in Doxyfile
+
+
+2008-01-24 Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1239
+	* SConstruct: Default scons to latest snapshot (should be a bit faster)
+	* SConstruct: Don't autocreate plugin path entries for paths that are not installed
+	* TriaxialStressEngine: Turn TriaxialStressEngine into state machine, while preserving the
+	possibility of changing some values by hand in .xml. (should be
+	tested).
+	* Doxyfile: Exclude Loki:: from doxygen docs.
+
+
+2007-06-30 Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1237
+	* Tetra.cpp, TetraTestGen.cpp: 
+		- Tetrahedron fixes (intersections are ;correct now, but
+		interaction still wrong - crashes??!)
+		- Correct formulas for 4hedron inertia, testcase passes
+	* trunk/SConscruct: Fix scons to work with versions > .97 (no syntax errors;
+	didn't try if it compiles
+	* SimulationController.cpp:
+		- Switch to fixed timestep when timestep is being changed by
+		user in the qt3 ui
+		- Change default timestep to 1e-8, should prevent weidness
+		onthe first run.
+
+
+2007-07-26 Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> revision 1230
+	* Cohesive* files: 
+	1. New contact law and related classes :
+	CohesiveFrictionalContactLaw. It will be the most general
+	contac law in Yade soon probably (TODO : include rotational
+	effects like MomentRotation law).
+	2. New Stress-Strain recorder : TriaxialStateRecorder,
+	autodetect the TrixialCompressionEngine of a MetaBody and
+	write the  parameters from it in a text file.
+	3. TriaxialCompressionEngine and TriaxialStressController are
+	modified in order to compute stress and strain on demand.
+
+
+2007-07-11 Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> revision 1224
+	* CohesiveFrictionalContactLaw.cpp CohesiveTriaxialTest.cpp,
+	Cohesive* files: This commit contains new classes in order to simulate
+	cohesive interactions with transient interactions.  The new
+	SAPCollider does set IsReal=false at each time step, neither do the
+	Sphere2Sphere4Distant... engine. The user must set isReal=false in
+	another engine (here the CohesiveFrictionalContactLaw engine) in order
+	to have the interactions removed from the DistantPersistentSAPCollider
+	list.  All new engines are used in the CohesiveTriaxialTest.
+
+
+2007-06-30 Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1216
+	* yade.spec: .spec file for fedora
+	* ScrewGen.cpp: Add screw example (this is really my personal one...)
+	* Shop.cpp: Fix Shop::tetra (tetra interacting geometry still
+	incorrect or incorrectly drawn... why???)
+	* yade.cpp: Remove python finalization, boost should take care of that.
+	* DynLibManager: Possibly fix plugin loader bug (first plugin after
+	one with yadePluginClasses "inherits" them unless it has its own
+	yadePluginClasses defined).
+
+
+2007-06-22 Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> revision 1215
+	* TriaxialCompressionEngine, GlobalStiffnessTimeStepper, TriaxialTest:
+		- TriaxialTest now includes a recorder to write stress history to a file.
+		- safety factor is set to a smaller value in the timestepper as
+		the computed value was still a bit too large in some cases.
+		- UnbalancedForce is defined in TriaxialCompressionEngine() to
+		avoid errors when loading a xml.
+
+2007-06-27 Vaclav Smilauer <eudoxos@xxxxxxxx> revision 1214
+	* FundamentalHandler: Don't warn on amd64 about limited type range in
+	comparison.
+
+
+2007-06-22 Bruno Chareyre <bruno.chareyre@xxxxxxxxxxx> revision 1213
+	* TriaxialCompressionEngine: UnbalancedForce member data was not
+	defined in the constructor of TriaxialCompressionEngine, it was
+	causing a crash when loading a TriaxialTest.xml.
+
+
+2007-06-21 Janek Kozicki <cosurgi@xxxxxxxxx> revision 1212
+	* ChangeLog: update
+
+
+r.1209 (Vaclav)
+  1. SCons will download new version of itself if older thatn 0.96.93 and will proxy all calls to it transparently (hopefully)
+  1a. Fix argv[0] for scons proxy.
+  2. Revamped python wrappers, now all attributes are settable as dicionary entries in respective instances from python
+  3. added example of python script that generates and runs BoxStack
+  4. Do not #define DEBUG, since it is used in log4cxx (as log4cxx::Levels::DEBUG). YADE_DEBUG is used everywhere. If you ever get weird errors about that, #undef DEBUG after including qt3 headers.
+  5. Some code cleanups.
+
+r.1206 (Vaclav)
+  1. rename ThreadWorker::message() to ThreadWorker::getStatus, ThreadWorker::setMessage() to ThreadWorker::setStatus (and private ThreadWorker::m_message to m_status)
+  2. add public: std::string FileGenerator::message that holds exit value description
+  3. FileGenerator::generate returns now bool (if the generation was successful); description in ::message
+  4. Adapted all generators and UIs for the above changes (except NullGUI - is that needed?)
+  5. Adjust other components for FileGenerator changes. Add wrapper for preprocessor in python.
+
+r.1204 (Vaclav)
+  - frontend cleanups, eperimental python console ui.
+  - Convenience functions for serialization - experimental.
+  - fix qualifiers in constructor of AttrAccess
+
+r.1200 (Janek)
+  - update yade icon, by Vaclav's suggestion (the red spheres are not so vividly red, so looks a bit better)
+  - scons will create the installation directory if it doesn't exist
+  - incorporated Bruno's fixes into 0.11 release
+
+r.1199 (Bruno)
+  - Modified definition of the interpenetration for box-spheres interractions. The previous definition was inconsistent.
+  - Some changes in the computation of critical timestep so that the triaxial samples do not explode when dt is set to the automatic value. The change mostly affects the first steps of a simulation. Now, dt is computed at each timestep during the first steps, whatever the value of the user-defined variable "timeStepUpdateInterval", until a relevant value is found.
+  - Cosmetic changes in TriaxialTest.
+  - Initial zoom in the simulation player is set to 2. 
+
+r.1192 (Janek)
+  - FileGenerators try to set the timestep when TimeStepper is not used. But it
+    is still not working when simulation is running during the generation. This
+    means, that 'dt' should not be in Omega, but inside a simulation itself. At
+    last there is a clear answer for this dilemma.
+  - fixed some crashing of HangingCloth
+  - fixed warnings in capillary law.
+
+r.1186 (Vaclav)
+  - Fix scons to handle boost.*-mt well, some other cleanups.
+  - remove hardcoded linkage with boost libs from SConscript files
+  - Modify debian builds so that making source packages for release versions work as well.
+
+r.1182 (Bruno)
+  - Add files related to capillary law.
+
+r.1181 (Janek)
+  - introduced Body::id_t(ype) so that bodies are not numbered as an int, but as a Body::id_t
+  - added center 'scene button' on first tab of simulation controller
+
+r.1180 (Vaclav)
+  - Correct 'all' value for features
+  - Clump improvements
+  - If RELEASE file exists, get yade version from there, instead of from svn.
+  - Remove wildmagic-dev from debian deps.
+  - fixed qt3 detection (used deprecated qapp.h header instead of qapplication.h).
+
+r.1174 (Janek)
+  - timestepper is set correctly when loading file in GUI (I hope!) - no need to reload second time
+  - FileGenerator does not open SimulationController if it already exists
+
+r.1174 (mixed)
+  - don't exclude lattice with miniWm3 
+  - merge lattice from Janek's PhD
+  - SConscript uses md5sum instead of timestamp.
+  - fixed crash in SDECLinkedSpheres example
+  - fixed RotatingBox and BoxStack examples - and accidental mistake in SAPCollider
+  - Add 'features' option to scons, which can enable/disable python and log4cxx at compile-time (extensible)
+
+
+r.1165 (Janek)
+  - updated Icon
+  - updated ChangeLog
+  - moved some obsolete scripts to doc/removed
+  - preparing for release 
+
+r.1162 (Vaclav)
+  - Make compilation proper when python is not found (no errors, just disable what should be disabled).
+
+r.1161 (Vaclav)
+  1. remove vector<Vector3r> from tetrahedra code, replace simply by Vector3r[4]
+  2. implement 4h-4h intersection peroperly, without relying on wm3. Compiles, not tested for correctness at all.
+
+r.1160 (Vaclav)
+  1. Some type fixes (signed vs. unsigned). The Body ID mess needs to be cleaned up!!!
+  2. More tetrahedron stuff; will not compile for now, though.
+  3. Icon update ;-)
+
+r.1159 (Vaclav)
+  1. gdbCrashBatch moved to Omega (was emptry when a different thread thatn the main one crashed?!)
+  2. Shop generates tetrahedra properly now, including dispatchers
+  3. Tetrahedra rendering and linking fixed
+  4. Added an icon to the main window (not serious ;-) )
+  5. commented out STUPID_DLL overflowing loader 
+  6. log4cxx has level set to INFO by default (was DEBUG, lot of garbage on screen)
+
+r.1158 (Vaclav)
+  1. Remove cyclic plugin loading forever (undefined STUPID_DLL)
+  2. Tetrahedron has vector<Vector3r> v instead of Vector3r v1,v2,v3,v4; (fem will probably not compile because of this for now - will be fixed)
+  3. Added experimental tetra class & friends.
+
+r.1155 (Vaclav)  
+  1. PythonRecorder runs optimized byte-compiled expression, optionally translated to machine-code by psyco
+  2. Serialization lib now properly escapes and unescapes XML-unfriendly charcters (\n,\t,<,>,",\\)->(\\n,\\t,\[,\],\',\\\\)
+
+r.1154 (Vaclav)  
+  - Merged the scons-layout branch to trunk.
+  - tree is flattened, scons is the only compilation method,
+  - qmake stuff removed completely
+  - added debian/rules for packaging
+  - added miniWm3 (does not need to depend on Wm3Foundation, just recommended). We plan to stop using wm3 anyway....
+
+r.1087 (Vaclav)
+  - Doxygen settings from yade-flat imported. New file tracking removed elements.
+  - dynamic_pointer_cast replaced by YADE_PTR_CAST as appropriate. It must be defined on compiler command-line (-DYADE_PTR_CAST=dynamic_pointer_cast or -DYADE_PTR_CAST=static_pointer_cast). Scons builds get this automatically.  
+  - dynamic_cast replaced by YADE_CAST where appropriate: i.e. the result of the cast is not checked to verify whether the conversion was successful as condition for further flow branching. The consequence is that you have to #define YADE_CAST in CXXFLAGS by hand as either dynamic_cast (original version) or static_cast (for optimized builds) when using make.
+  - Scons will do that automatically for you. It is the highest time you switch to scons ;-).
+  - SCons cleanup. Now supports buildPrefix (defaults to '..') so that build is completely separate from sources.
+
+r.1082 (Vaclav)
+  1. Cleanup of clump includes
+  2. Scons now puts buildDir include directory first so that it shadows eventually installed versions
+  3. jobs=x added to scons, like -j3, but is saved accross runs
+  4. Archive modifications (shuffling includes around) so that compiling with recent g++ (4.1) works - was preprocessor problem.
+  - Attempt to access interactions from Python, commeted out for the moment. May disappear later. Not used anywhere. Do not use.
+
+r.1079 (Vaclav)
+  Python fixes:
+  1. load pyade.py from path given by PREFIX and POSTFIX (we really need to define that somewhere in a unified manner: not by using BOOST_PP_STRINGIZE everywhere! - config.hpp...?)
+  2. velocity and angularVelocity are vectors now (returned only the x component by mistake)
+
+r.1078 (Vaclav)
+  1. Debugging mode now #defines YADE_DEBUG in addition to DEBUG, which seems to be #undef'ed by some header. Lazy to trace down.
+  2. Removed #ifdef DEBUG messages from dynlib &co (now under #if 0); use LOG_TRACE if you need those messages
+  3. Signal handler now handles SIGSEGV (segmentation fault) and SIGABRT (failed assertions, among other) in debugging mode: gdb is run, attached to the current process and backtrace of all threads is printed. 
+
+r.1077 (Vaclav)
+  1. Clump member velocities are calculated in ClumpMemberMover. This may create problems since velocity will always be lagged by one iteration. 
+  2. removed cyclic dependency of Clump and Shop.
+
+r.1076 (Vaclav)
+  1. renamed Chagelog to ChangeLog, will be generated autmatically from svn chamgelog
+  2. removed waf script (wscript), not used
+  3. scons now installs everything with '-version-postfix' appended, like yade-svn1072-debug
+  4. scons builds different variants (version and postfix) in separate directories
+
+r.1075 (Vaclav)
+  Many extensive changes:
+  1. HIGHLEVEL_CLUMPS removed, as if it were defined always. Minor things to do with clumps are calculating member velocities at every iteration and figuring out if CundallNonViscousDamping works differently than for standalone bodies.
+  2. signal handles if linked with python so that ^C works as expected.
+  3. Fixes in the Shop code.
+  4. scons builds should support even separate headers for different postfixes.
+
+r.1074 (Vaclav)
+  1. OK, the floats floating around for colors drove me nuts, so I replace all of that garbage by doubles. Since for one particular case (glMaterialv) the corresponding function taking double (glMaterialdv) is not defined in mesa (and perhaps not in most other gl libs), for that one the argument was converted explicitly.
+  2. New Shop class, that defines static methods for easy things, along with a dictionary of default parameters for some useful stuff: like getting a rootbody with reasonable set of actors, sphere body, box body. That's all for the moment. Add your own stuff. Filegenerators may shrink considerably this way.
+  3. Clump::subBodies renamed to Clump::members, Clump::moveSubBodies to Clump::moveMembers, ClumpSubBodyMover to ClumpMemberMover - to be consistent with Body::isClumpMember. Clump still not moved to DEM, that will wait till later - at the moment, QGLViewer depends on Clump (for moving clump when selected and moved with mouse).
+  - There may be some borken things here, do not use this revision for anything.
+
+r.1073 (Vaclav)
+  1. Scons changes, node enumeration gotten rid of, now uses proper Install in SConscript's. Should eliminate scons version problems we've had.
+  2. Some new make targets: for repetitive compilation (with -j2) and first personalizaed target: eudoxos.
+  3. Selecting clump member in GLViewer now selects the whole clump; it is moved and redrawn as well (only with HIGHLEVEL_CLUMPS).
+  4. An attempts at escaping special characters beforce XML serialization (\",\n,\t,\\), doesn't work - commented out.
+  5. Project files cleaned from nonexistent include directories.
+
+r.1072 (Bruno)
+  - Minor changes in the computation of the critical timestep.
+
+r.1070 (Bruno)
+  A lot of small changes in triaxial classes, impossible to comment all of them; but note that :
+  - TriaxialCompressionEngine can compress a sample to a dense isotropic state (either by moving walls or increasing the size of the spheres),
+  - then change the confining pressure if needed (for running tests with different confining pressure on the same sample),
+  - then start a triaxial compression test at constant zz strain rate and constant xx and yy stress (when the sample is considered stable based on StabilityCriterion).
+  - The transitions between the different phases are (in principle) very smooth.
+  note also that the contact laws are now defined using SimpleElasticLaw.
+
+r.1069 (Bruno)
+  - A simple definition of contact stiffness based on E and nu :
+     kn = E*size of sphere (so that apparent stiffness will be independent of size)
+     ks = nu*kn
+
+r.1067 (Vaclav)
+  1. selection in the renderer are now saved in Omega::selectedBodies (GUI to that list is in the future yet)
+  2. PythonRecorder now supports retrieving selected bodies; it redirects stdout to file if specified.
+  3. pyade now required scientific python to be installed - this permits to do vector and quaternion arithmetics in python. General cleanup.
+  4. pyadeDummy.py module added - for testing pyade without yade
+
+r.1066 (Vaclav)
+  1. Clump code cleanup
+  2. Python may now be embedded in yade: (i) SConscruct checks for it and #defines YADE_PYTHON if present. (ii) main sets up the interpreter. One disadvantage is that Python runs in its own thread, so pressing ^C during simulation doesn't quit yade (^\ still works).
+  3. New class PythonRecorder that evaluates arbitrary expression when activated.
+  4. Pyade interface that makes it possible to retrieve some values from yade in Python. For example, you can now record body #5 z-velocity and z-angularVelocity every 10 iterations by setting PythonRecorder::expression="if (S.i%10==0): print B[5].v[2],B[5].w[2]". Retrievable attributes are documented in the source (or the Doxygen documentation).
+  - The python stuff is not very logically still in yade-extra/clump, which has become my playground. Once it matures and someone want it, it may move. Let me know it you find it useful.
+
+
+r.1065 (Vaclav)
+  1. Clump code is not (hopefully) correct physically - translational, rotational and potential energies give constant sum over time (more or less)
+  2. ClumpTestGen generates a useful scenario of standalone sphere, {1,2,3,4}-sphere clump.
+  3. Inertia calculation fallback for cases with NaNs from EigenDecomposition.
+  4. acceleration and angularAcceleration reset after every position update for clump.
+  5. Body::{isClump,isClumpMember,isStandalone} added.
+  6. Gravity engine skips clump members (applied to the whole clump only).
+  - Perhaps in the next commit, I will remove the #ifdef HIGHLEVEL_CLUMPS. Someone protesting?
+
+r.1064 (Vaclav)
+  1. Fixes in the clump code
+  2. InteractionGeometryMetaEngine doesn't crash if a body doesn't have interactingGeometry (like Clump)
+  3. Fixes in the collider, related to the clump code
+  4. ClumpSubBodyMover is now a DeuxExMachina
+  5. discovered bug in Wm3::Matrix3::EigenDecomposition
+  6. ClumpTestGen generates a usable testcase (either a random one, or with one-sphere clump and an equivalent sphere) for testing purposes. Parameters etc. are physically wrong, but at least there are no crashes.
+  7. ClumpTestGen temporarily sets rootBody in Omega so that Body::byId is usable
+
+r.1063 (Vaclav)
+  1. Clump::subBodies are now a std::map<Body::id_t,Se3r>, subSe3s removed.
+  2. Sample clump generator ClumpTestGen written; works, but yade crashes because of dispatchers being setup incorrectly.
+  3. Omega::setRootBody added so that rootBody can be temporarily set during filegeneration, which is necessary for Body::byId.
+
+r.1062  (Bruno)
+  - Squared distances are now compared instead of simple distances (faster) to decide if two grains are in contact.
+  - In addition, InteractionDetectionFactor is added as member data. The default value is 1, a value greater than one will allow the geometry of contacts to be created as soon as the distance is less than Factor*SumOfRadii. Usefull for interactions at longer distances (like capillary effects).
+
+r.1061  (Bruno)
+  - The damping equations are reverted to their original expressions, with independant damping of each DOF. It looks like the convergence to equilibrium is faster with these equation
+
+r.1060  (Vaclav)
+  1. Clump code completed, but totally untested so far.
+  2. Added target 'doc' to Makefile that runs doxygen
+  3. New tracing macro TRWM3QUAT for quaternions
+
+r.1059  
+  - a more prominent warning when PREFIX was not defined during compilation
+  - ThreePointBending does not crash when there is not file to load
+  - some fiddling with lattice
+
+r.1058  (Vaclav)
+  1. provide Doxyfile, running "cd yade-doc; doxygen" will produce html reference documentation
+  2. initial (non-functional) implementation of high-level clumps, along with some cleanup of the changes done elsewhere
+  3. erskine now can be given scons variables (namely, $PREFIX) that will be unexpanded in generated SConscript's
+  4. SConscruct #defines HIGHLEVEL_CLUMPS, since other people probably don't use scons (yet)
+  5. New method Body::byId, new typedef Body::id_t, new constant Body::ID_NONE (jailed in HIGHLEVEL_CLUMPS for now, that will be removed sooner or later)
+
+r.1057
+  - Prepare framework for "high-level clumps". Everything is withing #ifdef HIGHLEVEL_CLUMPS, hence shouldn't change anything unless compiled with that option (don't try at the moment, it doesn't work). More information at http://beta.arcig.cz/~eudoxos/phd/index.cgi/YaDe/HighLevelClumps .
+
+r.1056
+  IMPORTANT: In this commit I have added a third parameter to GLDrawInteractingGeometryFunctor, which means that all GLDrawInteracting* classes had to be changed. If you have your own classes that draw interacting geometry you must modify them as well. The extra paramater added is 'bool wireFrame'. I think it will be useful :)
+  - also I made two separate 'bool' flags in the display settings to set wireframe for body and for interactions.
+  - the interaction for linked spheres is drawn in two colors: red for compression, blue for tension.
+  - some lattice improvements, like drawing of fracture surface in 3D.
+
+r.1055 (Vaclav)
+  - Simulation may be (which is the default) loaded after generation automatically now.
+
+r.1054
+  - in GLViewer new keys: 'o' and 'p' to change the field of view. Useful for changing the perspective.
+  - GLDrawSphere now plots a wireframe sphere very nicely: a circle facing the camera. Look very neat when combined with drawn interactions
+  - I have changed the flag names in OpenGLRenderingEngine. Maybe this look better, what do you think?
+  - I added a ThreePointBending. It can load spheres from some other simulation, put two supports and a moving piston. So we get a beam bending. It works in such a way, that first we generate an assembly of compacted spheres using Bruno's triaxial compression, with the dimensions of desired beam. Then load them into ThreePointBending, and we can bend a beam. It uses a linked spheres with unfinished formulas from Jean Patrick Plassiard, so it is rather unfinished... just like SDECLinkedSpheres example...  
+
+r.1053
+  - In this commit I made Interactions drawable by GLDraw*, and I added three example GLDraws for Interactions:
+  - GLDrawClosestFeatures - it is a very simple GLDraw - just plots the vector of two overlapping bodies, the closest feature. A body displaced by it, will stop overlapping with the other body.
+  - GLDrawSimpleElasticInteraction - it prints a "kn" of the interaction. It may be useful if someone wants to PRINT data on the screen about interactions.
+  - GLDrawSpheresContactGeometry - this is most interesting, it draws a box between two interacting spheres, and it's size corresponds to the force between them. With it it is simple to see how the force paths.  It uses only a normal force, not shear force
+    IMPORTANT: this is a fairly big change: *EVERY* class that inherits from
+    InteractionPhysics or InteractionGeometry had to be modified:
+    1. write constructor in .hpp file
+    2. write REGISTER_CLASS_INDEX(this class,its base class); macro in .hpp file
+    3. write createIndex(); call inside constructor in .cpp file
+  For example look into AABB.hpp AABB.cpp to see how it must look like.
+  - If you want to import some of your classess, you must make those modifications to your interaction classes.
+
+r.1052
+  - added GeometricalModelForceColorizer. It is another hacky Engine that I have added (along with Quadrilaterals). I did it, because I wanted to see spheres colored according to force acting on them. This is a hack because the GLDraw mechanism is currently very limited, and has to be extended to allow things like this. So currently it works, but not in a way it should be done.  GLDraw* changes are coming ... soon :) 
+  - BTW: it could be done better, currently looking at those colors can give you apoplexy
+
+r.1051 (Bruno)
+  - IsotropicCompressionEngine removed from SVN.
+  - TriaxialTest do the same thing (i.e. isot. compression) better, and do more.
+
+r.1050  
+  - OpenGLRenderingEngine didn't draw Body when it's groupMask was 0
+  - some changes in lattice.
+
+r.1048  (Vaclav)
+  1. Fixed Omega::scanPlugins so that it loads plugins that were linked without -rpath for their dependencies. Everything is in #ifdef STUPID_DLL
+  2. Removed again IsotropicCompressionTest since needed headers are missing. Bruno, please add them back (they were removed in the 1045 commit.) and then enable IsotropicCompressionTest in yade-packages/yade-package-dem/src/PreProcessor/PreProcessor.pro again.  
+
+r.1047  (Vaclav)
+  1. Include IsotropicCompressionTest in dem's preprocessors project so that it gets compiled
+  2. Improve erskine to indent SConscripts in a nice way
+
+r.1044  (Vaclav)
+  - Fix build process for older versions of scons that break if there is a target that has no sources. Added a dummy empty file to the loki library to do that, modified project file. Do not forget to delete yade-libs/yade-lib-loki before running scons again to regenerate SConscript files.
+  - Plugin loader now handles multi-class plugins, provided that they define "char* yadePluginClasses[]" symbol containing list of class names (sentinel=NULL) that the plugin contains. Regular one-class-per-file plugins work normally.
+  - Something like yadePluginClasses should be (in the future) extended to hold more module information (classes, module version, author, perhaps license, URL, required yade version, pointers to documentation etc.).
+  - Microchanges: fix rpath quoting, fix ctags indexing non-c++ files (local bug? --language=c++ would make all files (including .o, for example), being indexed.
+
+r.1041  
+  - QtFileGenerator remembers save file name (so it is not always ../data/scene.xml), this was done in previous commit. A small bugfix here
+  - maximum delay between display updates is now 10 minutes (600000 miliseconds)
+  - BIN format did not support std::pair, I had to fix it, because I needed that. But we are switching to boost::serialization in near future, anyway. 
+  - added NodeRecorder (records average position of selected nodes), BeamRecorder (records stress in x and y direction in a selected section) and MovingSupport (a sliding support - transfers only one DOF acorss it) to lattice.
+  - replaced std::vector with std::list in few places in lattice. There where add/remove was more often, and random access was not needed.
+
+r.1040
+  - FileGenerator shows generation time, and saving time
+  - FileGenerator saves output file name (it was always fixed at
+    "../data/scene.xml") and serialization dynlib (BIN / XML) so currently ../data/scene.xml is just a default value. But saving a filegenerator remembers target output file.
+  - To make it work I had to add a line FileGenerator::registerAttributes(); in all FileGenerator-s (so it is a call to the base class, so it can register file name and serialization dynlib.
+  - also, to make it work I had to make a dirty HACK in  yade-lib-serialization-qt. I don't feel much guilt, because it is already decided that we will scrap yade's serialization and switch to boost::serialization. Then this hack will disappear.
+  - SimulationController will not reopen a file, when closed and opened. That was a bit annoying when last file loaded was big.
+  - some fixes in MarchingCube
+  - Lattice can display its own aggregates using marching cubes. Like with Quadrilaterals, I had to make a hasck to get it to work. And it again proves that GLDraw* mechanisms need improvement. I had to add a global variable in Omega, to transmit parameters between user input and the GLDrawer. The parameters are changed inside GLViewer, which is a hack too. I had to do this now, because there is no way to parametrise GLDrawers from user interface.  ( GLDrawLatticeSetGeometry ) 
+  - MeasurePoisson improvement, LatticeExample can now generate using Delaunay, 
+
+r.1036
+  - FileGenerator reports how long the generation took
+  - yade.cpp takes PREFIX and POSTFIX as #define /some/path , without "
+  - small change to lattice generation method
+  - Makefile cleans after scons
+  - small SConstruct changes
+
+r.1033  (Vaclav)
+  - Scons accepts additional POSTFIX parameter, which will alter installation so that PREFIX/{bin,lib}/yade becomes PREFIX/{bin,lib}/yadePOSTFIX (similar to EXTRAVERSION of Linux). Further, configuration files will be searched for in ~/.yadePOSTFIX instead of ~/.yade. Unfortunately, headers installed in PREFIX will still be overwritten by newer version, even with different POSTFIX, since most files do something like #include<yade/...>. This is meant to ease simultaneous installations of different variants of yade. To achieve full independence, PREFIX and POSTFIX should be different. Note that you don't need to set LD_LIBRARY_PATH, since scons uses linker's -rpath option (hint: man ld). If someone has better solution, please let me know.  
+  - Along the same line, I replace the annoying first run configuration (and annoying way of adding plugin directories) by simply writing config file with sane default values if none is present. The user is noticed of that.
+  - Finally, when SimulationController is launched, the stop button callback is called - Bruno, can you confirm, that the first simulation is now OK?
+
+r.1032  (Vaclav)
+  - Iterations/sec display added to simulation controller (someone more sensible may redesign the layout in the future). Line ending changed from CRLF to CR. 
+  - SCons update, please use it and report any problems to yade-dev or yade-users. Thanks.
+  - Quick fix for recently discovered segfault. Wondering why it didn't surface before. Valgrind still complains about PhysicalActionVectorVectorIterator::increment using an unitialized value, but that may be unrelated (probably is) to this one.
+  - Massive update of scons, which I now recommend for building. It has some autodetection support as well.
+  - Please report any bugs (?) / RFEs to me. Brief instruction are given in INSTALL.
+  - Exceptions from the FileGenerator thread are now properly caught; it means for example that if you pass an invalid classname in createActors, yade will tell you what class it wasn't able to construct instead of hanging infinitely.
+
+r.1025  (Vaclav)
+  - Bastardized wm3 library ejected from the tree. From now on, you need to install wm3 separately. Will update README shortly on how to proceed. Basically, add  "-I/usr/local/include/wm3" to CXXFLAGS if you use qmake. Includes and linking was adjusted in c++ and .pro files.
+  - DOUBLE_PRECISION removed in favor of SINGLE_PRECISION. Therefore, the default is to define Reals as doubles now. SINGLE_PRECISION will be removed very soon anyway.
+  - Removed yade-lib-algorithms, since it is not used. Once someone needs it, it can be found in svn history.
+  - Created yade-lib-base, that for now contains
+   1. Logging.hpp: moved from yade-core to avoid circular dependency),
+   2. yadeWm3.hpp: typedefs for Vector3r Vecrtor3<Real>, definition of Real. This header will be removed soon, since it will not be needed.
+   3. yadeWm3Extra.hpp: things that were added to the bastardized wm3, like a few operators and functions. You almost certainly want to include it in your code if you get undefined references (and link with yade-lib-base).
+  - Omega now reports undefined symbols demangled.
+
+r.1020  (Vaclav)
+  1. Two sets of files were named StiffnessMatrixTimeStepper, of which the other one was in directory Global StiffnessTimestepper. Since it was not used (not compiled by default), I renamed the second set to match the directory name. If it breaks something, let me know.
+  2. Updated the scons script, scons now compiles yade completely, including header installation. It is yet to be tuned to be lot more fast, but works fine already.
+  3. Cleaning up messages at startup, (almost) everything is piped through the LOG_* stuff.
+  4. Included sample logging.conf.sample file, log4cxx is amazingly flexible and easy to use. Give it a try!
+  5. Lot of debugging since after the last change of allowing regular files to be plugin-loaded, yade would try to load garbage (like the file foobar.baz transformed to libbar.so and the like) giving spurious errors. Everything should work properly now, you can have whatever you like in the plugins directories. It will not even crash on short files (amazing fragility...).
+  6. Removed the message from ResultantForceEngine constructor, to not to pollute the console every time. Dtto for StiffnessMatrixTimeStepper.
+  7. Added one ; in yade.cpp that broke compilation without LOG4CXX. The non-log4cxx macros are now enclosed within {} just as their log4cxx counter parts. This should eliminate the need for separately building both configurations.
+
+r.1018  (Vaclav)
+  1. Allow running simulation from commandline by using the -S switch (in QtGUI only for the moment).
+  2. Embryonal form of some logging framework (logging.hpp), that is perfectly usable as of now. it is disabled by default, see logging.hpp for more information on how to use it.
+  3. Scripts to build yade with scons (works here), which should make repetitive and parallel building faster/more reliable. Note that scons build uses the log4cxx framework by default.
+  4. Some random and mostly commented-out changes in the library loader I needed for debugging my installation. Most importantly however, yade will also load files that are _not_ symlinks (which was not the case until now).
+  5. Changing boost path corectness checker to "native", so that we don't crash on non-ms-dos filenames.
+
+r.1016  (Bruno)
+  - Engines are now compiled in a different order, with DeusExMachinas compiled last. The full DEM package has been compiled successfully after thuis change.
+  - same thing to be done probably for the MyTetrahedron stuff as some headers can't be found when you "make clean" + "make" from yade-package-dem directory
+  - Matrix3 patch from Vaclav
+
+r.1014
+  - removed invMass and invInertia. Removed special handling for division by zero. mass shouldn't be zero anyway.
+  - I checked simulation results, by comparing positionoritntation_* files, before and after the change. There was a difference in the two or three last digits. 1.234567890123xxx  <- x are different numbers oh well. Perhaps this version is more precise, because in fact there is one multiplication less during the calculations.
+
+r.1013  (Bruno)
+  - Modifications in the equations of "non-viscous" damping. The equations are now as defined by Cundall.
+
+r.1011 (*)
+  - Added drawMask to OpenGLRenderingEngine, it is now possible to see only bodies that have a certain groupMask
+  - Added Quadrilateral, but it is in fact a hack, that makes it possible to see the evolution of strain field. It is much simpler to add something as a component of OpenGLRenderingEngine (the drawing loop) than as a component of engines (the calculation loop). This fact is a string indication that design of OpenGLRenderingEngine is much better than design of Metabody->engines. And so engines must be eliminated to simplify their use. Whole process will get automated.
+  - So currently we have a Quadrilateral that is not really a Quadrilateral, but just a quick hack to see evolution of strain field. The real solution will be to change the data structure. And this solution is coming ;) (ut don't know when) 
+  - Anyway, adding it, gave me a lot of thoughts about the current design of data.  I won't leave this unfixed, this would be too bad :>
+
+r.1010
+  - 'C' key centers scene on selected body
+  - 'D' sets the 'isDynamic' flag of selected body. (select it twice to unset this flag).
+  - Finally 3D lattice works with torsion and bending. There is bending stiffness, and torsion stiffness.
+  - flag that allows one to enable/disable calculating of torsion in lattice
+  - LatticeExample FileGenerator can now generate a 3D tetrahedral regular grid. (before there was only orthogonal grid)
+
+r.1008
+  - Omega throws when loading bad simulation file
+  - NullGUI allows one to call a FileGenerator
+  - Lattice 3D is working with bending stiffness. Now I must add torsional stiffness.
+  - also renamed: ./yade-scripts/renameClassFirst volatileInteractions transientInteractions
+  - added GLDrawStateFunctor. So now it is possible to see bodies' velocity, acceleration, angularVelocity, angularAcceleration. And other State attributes of a body.
+  - renaming: ElasticContactParameters ElasticContactInteraction
+
+r.1000
+  - Some cleaning, involving changing variable names, like Body::interactingGeometry. Which caused almost all the files to be modified.
+  - And most imporatntly added a primitive example of doing calculations with tetrahedrons. It is for educational purposes about how to add new stuff to yade. Later I will have to come back to this commit, and extract from it a useful example for the manual.
+  - This example is for V�av �milauer, because he wants to write a complete simulation with tetrahedrons. So this is a starting point.
+
+r.995
+  - Finally deleted swiftpp and qhull. Now we have less license problems. There is still license problem with math library, though.
+  - Tetrahedrons are currently not working, just crashing (because swiftpp was removed).
+  - SDECTriaxialTest is deleted, because it was never done, in fact.
+
+r.995
+  - more improvements in ThreadRunner, ThreadWorker::~ThreadWorker and SimulationController
+  - fiddling with lattice: angle between beams is now calculated in 3D not 2D, with tracking of positive/negative angle. So the angle is between -180 and 180 deg, while arcus cosinus can only give a result between 0 and 180 degrees.
+
+r.994
+  - Graphics display can be now synchronized with the calculation without problems, and without blocking GUI 
+  - FileGenerator now does not block whole GUI when generating. And can be stopped if function generate() calls somewhere in the loops:
+        if(shouldTerminate()) return "";
+  - an example how to use the progrss bar, and messages is inside SDECSpheresPlane generator, and LatticeExample. Other generators cannot be stopped with "Stop" button.
+  - ranaming SimulationRunner -> ThreadRunner ; SimulationFlow -> ThreadWorker
+
+r.989
+  - it is possible to select (shift click) and 'm'ove bodies in the simulation view window a dirty implementation. Needs major refactoring.
+  - the "display" tab now offers the ability to set 'display refresh rate' in [ms] so it's like the priority of draw.
+  - deleted yade-lib-time, and using boost::posix_time instead
+
+r.983
+  - better DynLib error reporting
+  - new Lattice, only 2D
+  - triaxial test from Bruno
+  - deleted unused QGLThread
+
+r.979
+  - updated INSTALL file (before release).
+  - also updated Changelog in previous commit.
+
+
+r.978
+  - SimulationController is now updating iterations/time and sets time step correctly.
+  - some small changes in filegenerators, so they by default will generate something interesting.
+  - FileDialog now reports "Cancel" button correctly.
+
+r.974 version 0.10.0
+  - added SimulationRunner, that can start/stop or perform singleLoop of simulation in separate thread.
+  - Maybe some signal capability will be added to SimulationRunner, so that something can be notified when singleLoop is finished during calculations.
+
+r.972
+  - GLSimulationPlayerviewer - change of function call, because qglviewer 2.2 has changed a function name: added compilation flag: QGLVIEWER20
+  - OpenGLRenderingEngine - latest version of libglut3d requires to call glutInit(): added compilation flags: NO_GLUTINIT
+
+r.970
+  - Threadable class has been removed:
+  - when yade is idle 0% of CPU is consumed by the display,
+  - when simulation is ran it is in separate thread, second processor (if present) is drawing on the screen,
+  - with two processors theoretically QtGUI should have speed equal to NullGUI,
+  - drawing on the screen is not synchronized, so some bodies are from previous iteration, some are from next iteration (later there will be an option to turn synchronization ON - it will slow down computations a bit)
+  - This implementation is stil not 100% tested, please report if there are any problems. Especially if there is a segfault on exit. Press enter in each graphical view to start/stop updating it.
+
+r.960
+  - 'cancel' when loading filegenerator is not crashing now
+  - started non-local model for lattice
+  - hopefully 2d lattice beams are now okay.
+  - middle button in 3d view is now "PAN" command, not "ZOOM" as it used to be. It's more similar to AutoCAD
+  - 'yade -h' will now display compilation flags (currently only DOUBLE_PRECISION - how about adding long double ;) ?)
+
+r.957
+  - added function Quaternion::power(RealType)
+  - lattice bending works now in 2d (X-Y plane), using angles. not vectors or quaternions. I will do 3d later.
+
+r.956
+  - fixed serious bug in bool BodyRedirectionVector::erase(unsigned int);
+  - added function bool exists() const; to BodyContainer
+  - graphical display now has reversed meaning of scrollwheel, so it is now similar to behaviour of blender and autocad
+  - SDECLinkedSpheres is working after some (surprise!) quick hack. That part is still waiting for total rewrite.
+  - big improvements in lattice model. beam bending works (but not always) with axis+angle notation. maybe with quaternions it will be better. There is a problem that shows itself when using regular triangular grid.
+
+r.955 version 0.9.8
+  - NullGUI displays help when called without arguments
+  - fixed serious problem in OpenGLRenderingEngine's constructor - there were hardoced plugin names. now the list is built dynamically
+  - configurable path to preferences, not forcing users to use ~/.yade/
+  - QtGUI is now saving the configuration of RenderingEngine, so for example background color is remembered now.
+  - 'Load' and 'Save' in FileGenerator works
+  - added yadeVersionName to Omega - so that all plugins can query it to correcly display version, which is set by main(), and general cleaning of the mess in main(), yade.cpp
+  - fixed handling of pointer to simulationController in YadeQtMainWindow.cpp
+  - lattice model based on rods works great
+  - add a FIXME in XMLFormatManager, beginDesrialization : rootBody can load FileGenerator, because is not checking names
+
+r.954 version 0.9.7
+  - NullGUI can save to binary format
+  - graphical windows GLViewer displays a grid with cell size exacly 1 meter or 1 cm (depending on the model size) previously that grid had some random size, which was totally useless
+  - added DisplacementEngine derived from DeuxExMachina - is like translation, but without velocity - purely kinematic displacement.
+  - disorder parameters in FileGenerators SDECSpheresPlane and LatticeExample are now Vector3r, so that we can specify different randomness in each direction. This is useful for flat 2D simulations
+  - major improvements to lattice model (rod model is working)
+
+r.953 version 0.9.6
+  - binary serialization for yade
+  - fixed one bug in BINFormatManager
+  - fixed saving ElasticContactParameters and SpheresContactGeometry, so that after loading the simulation is not going crazy
+  - removed GLAPI and GLAPIENTRY from OpenGLWrapper
+  - XMLSaxParser is now better at counting lines
+
+r.951 version 0.9.5
+  - can save simulation from simulation controller
+  - can change background color of the simulation displayed
+
+r.950
+  - QtEngineEditor is not working - doesn't detect correctly StandAloneEngines
+  - there was a collision between PersistentSAPCollider and PersistentSAPCollider from yade-extra, renamed second one to PersistentAloneSAPCollider
+
+r.949 version 0.9.4
+  - added: StandAloneEngine.hpp, InteractionSolver.hpp, DataRecorder.hpp, BroadInteractor.hpp - to have a nicer and easier to navigate class diagram
+  - fixed drawing of bounding volumes inside rootBody
+
+r.948 version 0.9.3
+  - MetaBody::actors -> engines
+  - GLDrawInteractionBox -> GLDrawInteractingBox
+  - GLDrawInteractionGeometryFunctor -> GLDrawInteractingGeometryFunctor
+  - GLDrawInteractionSphere -> GLDrawInteractingSphere
+  - GLDrawInteractionGeometrySet -> GLDrawMetaInteractingGeometry
+  - ErrorTolerantContactModel -> ErrorTolerantContact
+  - AABox2Sphere4ClosestFeatures -> AAInteractingBox2InteractingSphere4ClosestFeatures
+  - Box2Box4ClosestFeatures -> InteractingBox2InteractingBox4ClosestFeatures
+  - Box2Sphere4ClosestFeatures -> InteractingBox2InteractingSphere4ClosestFeatures
+  - Box2Sphere4ErrorTolerant -> InteractingBox2InteractingSphere4ErrorTolerantContact
+  - Box2Sphere4MacroMicroContactGeometry -> InteractingBox2InteractingSphere4SpheresContactGeometry
+  - Sphere2Sphere4ClosestFeatures -> InteractingSphere2InteractingSphere4ClosestFeatures
+  - Sphere2Sphere4ErrorTolerant -> InteractingSphere2InteractingSphere4ErrorTolerantContact
+  - Sphere2Sphere4MacroMicroContactGeometry -> InteractingSphere2InteractingSphere4SpheresContactGeometry
+  - Box2AABB -> InteractingBox2AABB
+  - Sphere2AABB -> InteractingSphere2AABB
+
+r.938 version 0.9.2
+  - added SDECMovingWall FileGenerator contributed by Andreas Plesch.
+  - cleaned all .cpp files. they are all now less cluttered and easier/shorter to read.
+  - So I have started compiling it on windows, and I stopped on the problem that linker cannot link serialization with factory.
+
+
+r.917 version 0.9.1
+  - SimulationPlayer - can play recorded position/orientation data
+  - QtSimulationPlayer
+  - SphericalDEMSimulator - a separate version of DEM calculations without all "yade burden" to make speed comparisons
+
+r.914
+  - new version of docs, checked by my sister.
+
+r.904 yade-core version 0.9.0
+  - split of packages done. Now each package can be developed separately and has own version numbers.
+  - Initial version numbers are choosen arbitrally to reflect their advancement state.
+  - huge improvement in Makefile. 'make compile_install' and yade is ready to release to the wild world.
+  - some class renamed to better reflect their functions,
+  - some cleaning,
+  - Simulation loop editing through GUI starts to work,
+  - added REGSITER_BASE_CLASS_NAME, so we can build class tree on runtime (used by simulation loop GUI),
+  - removed all references from Serialization stuff to yade-lib-multimethod as they are totally unrelated,
+  - plugins of yade containers are now using ::iterator, just like STL !
+  - Tetrahedron Discrete Model, and Lattice Discrete Model start to work, but not good enough to increment a major revision number.
+  - FEM, DEM, Mass Spring and Rigid Body are working good.
+
+ yade-core                                      version 0.9.0
+ yade-libs:         
+        yade-lib-algorithms                     version 0.1.0
+        yade-lib-computational-geometry         version 0.5.0
+        yade-lib-factory                        version 1.0.0
+        yade-lib-loki                           version 0.9.5  because is different than Loki
+        yade-lib-multimethods                   version 1.0.0
+        yade-lib-opengl                         version 0.5.0
+        yade-lib-qhull                          version 1.0.0
+        yade-lib-serialization                  version 1.0.0
+        yade-lib-serialization-qt               version 0.8.0  because is not serializing containers
+        yade-lib-serialization-xml              version 1.0.0
+        yade-lib-swiftpp                        version 1.0.0
+        yade-lib-threads                        version 0.3.0  because is not supporting multithreaded calculations
+        yade-lib-time                           version 0.5.0
+        yade-lib-wm3-math                       version 0.7.0
+ yade-guis:         
+        yade-gui-qt                             version 0.7.0
+ yade-packages:         
+        yade-package-common                     version 0.9.0
+        yade-package-dem                        version 0.9.0
+        yade-package-fem                        version 0.7.0
+        yade-package-lattice                    version 0.3.0
+        yade-package-mass-spring                version 0.9.0
+        yade-package-realtime-rigidbody         version 0.9.0
+
+r.890
+  preparing for release.
+
+r.845
+  renaming:
+  XMLManager -> XMLFormatManager
+  IOManager  -> IOFormatManager
+  MacroMicroContactGeometry -> SpheresContactGeometry
+  SDECTimeStepper -> ElasticCriterionTimeStepper
+  InteractionDescriptionSet2AABB -> MetaInteractingGeometry2AABB
+
+r.832 (*)
+  huge improvement in Makefile. now the mechanism of make is ready to release yade to the wild world.
+
+r.821
+  Simulation loop editing is now working. There are still some random crashes to fix and for now it is not possible to load a simulation loop.
+
+r.818 (*) (fix article)
+  Removed unused classes.
+  D    yade-core/src/InteractionSolver.cpp
+  D    yade-core/src/InteractionSolver.hpp
+  D    yade-core/src/BroadInteractor.cpp
+  D    yade-core/src/BroadInteractor.hpp
+  D    yade-core/projects/kdevelop/yade/InteractionSolver.cpp
+  D    yade-core/projects/kdevelop/yade/BroadInteractor.cpp
+  M    yade-core/projects/kdevelop/yade/yade.pro
+  D    yade-core/projects/kdevelop/yade/InteractionSolver.hpp
+  D    yade-core/projects/kdevelop/yade/BroadInteractor.hpp
+
+
+r.817
+  added REGSITER_BASE_CLASS_NAME, so we can build class tree on runtime.
+
+r.815
+  Improvements in QtEngineEditor. Now it is almost possible to create graphically a simultation loop.Now I have to make something to set parameter of MetaEngines.
+
+r.812 (*)
+  Better design : added class related to MetaEngine. Removed all references to Serialization stuff into yade-lib-multimethod. They are now into newly added classes.
+
+r.809 (*)
+  plugin containers for yade use ::iterator, just like STL !
+
+r.808
+  I have introduced iterators for all types of containers in order to remove the dirty gotoFirst, gotoNext, hasNext and notAtEnd methods. Now it looks like more like STL iterators. It is compiling but unfortunately it is segfaulting at runtime, probably some problems in ++,* operators.
+
+r.804
+  Better YadeQtMainWindow. Now menus are displayed in menu bar in the same order they are added in the program. Added preferences for QtGUI. Now it remembers size and position and exit. Now it is possible to choose time step from GUI.
+
+r.801 (*) version 0.8.7
+  tagging v.0.8.7
+  - second redesign of directory tree finished.
+  - yade-core is clean
+  - yade-empties contain templates for whole packages.
+  - New yade-empty-package which is simpler than previous one.
+  - Makefiles install correctly.
+  - Yade is now compiling with separate libraries projects
+
+
+r.758
+  yade-core is clean
+
+r.754
+  yade-empties contain templates for whole packages.
+
+r.748
+  New yade-empty-package which is simpler than previous one. Makefiles install correctly. Yade is now compiling with separate libraries projects
+
+r.746
+  fixed all #include paths, started Makefiles
+
+r.732
+  second directory tree redesign started. much better now.
+
+r.714 (*) version 0.8.6
+  tagging v.0.8.6
+  - All those extra environment variables are no longer needed. Currently only LD_LIBRARY_PATH is used by dlopen. Dunno how to remove it.
+  - added user manual to doc/, without pictures, and still a draft.
+  - Small change so that yade is compiling with qglviewer 2.0
+  - Updates in Omega : now foreach plugins we store if it is indexable, factorable or serializable.
+  - Improved GUI for code generation : Data class, engine and dispatching engine works. No stuff is done for generation of kdevelop projects.
+
+
+r.709 (*)
+  All those extra environment variables are no longer needed. Currently only LD_LIBRARY_PATH is used by dlopen. Dunno how to remove it.
+
+r.708
+  Small change so that yade is compiling with qglviewer 2.0
+
+r.705
+  Updates in Omega : now foreach plugins we store if it is indexable, factorable or serializable. Improved GUI for code generation : Data class, engine and dispatching engine works. No stuff is done for generation of kdevelop projects.
+
+r.701
+  Added some functions into yade-lib-computational-geometry. Started to and graphical interface for buliding simulation loop and initializer list
+
+r.700 (*) version 0.8.5
+  tagging v.0.8.5
+  - Lattice works with rods, but dirty, of course - as always when something is implemented for the first time :>
+
+r.691 (*)
+  Added some dynlibs for handling swept sphere volume.
+
+r.690
+  To make yade deserialization working I had to modify PointerHandler.tpp around line 90. Basically I just replaced a dynamic_cast by a reinterpret_cast. We have to find why dynamic_cast is not working anymore.
+
+r.688 (*) version 0.8.4
+  tagging v.0.8.4
+  - Added new file generator Funnel and TetrahedronsTest (*)
+  - Added new InteractingGeometry PolyhedralSweptSphere (*)
+  - Added new NarrowInteractionGeometryEngine SwiftPolyhedronProximityModeler that will use SWIFT++ library and PolyhedralSweptSphere (*)
+  - Added EngineUnit Tetrahedron2PolyhedralSweptSphere and Box2PolyhedralSweptSphere that will build InteractingGeometry
+
+r.687 (*)
+  Lets consider here that splitting is done. (but almost)
+
+r.686
+  Added MarchingCube algorithm into yade-lib-computationnal-geometry
+  Created lib yade-lib-algorithms were to gather algorithms of different type : for now there is only a PerlinNoise algorithm, but we can put here sorting algorithm ...
+
+r.684
+  Added libraries swift++ and qhull.
+  Modified scripts so that they work with .h and .c files. improved documentation
+
+r.680
+  SimpleSpringLaw renamed to FrictionLessElasticContactLaw.
+
+r.671
+  Renaming:
+  PhysicalActionEngineUnit -> PhysicalActionDamperUnit, PhysicalActionApplierUnit
+  Added class Preferences that contains directory to dynlibs.
+  Modification of library yade-lib-factory so that it is using multiple directories to look for requested dynlib
+
+r.669 version 0.8.3
+  tagging v.0.8.3
+  - Splitted ElasticContactLaw into 2 : ElasticContactLaw and ElasticCohesiveLaw.
+  - Autocollision for hanging cloth is working without hack.
+
+r.668
+  Removing all references to libraries Interactions, Body and Engine that no longer exist. Yade should now compile.
+
+r.639
+  renamed ActionParameter to PhysicalAction
+
+r.637 version 0.8.2
+  tagging v.0.8.2
+  - new directory structure almost splitted, we start to have packages. 
+  - Yade is now compiling on the first try.
+  - removed initialization in constructor of bodyContainer, InteractionContainer ... because now container are in plugins and so compiled after yade itself.
+  - Changed name Dispatcher/funtor to MetaEngine/EngineUnit
+
+r.562 version 0.8.1
+  tagging v.0.8.1
+  - we have made a great yade-empty directory structure. This is a design for future split of yade into several packages.
+
+r.554
+  Renaming classes. First draft of documentation.
+
+r.512
+  Added layout and scrollview to QTGUI
+
+r.510 (*)
+  better openGL tetrahedron display. created empty directories for splitting to packages.
+
+r.486 version 0.8.0
+  tagging v.0.8.0
+  - FEM works!
+
+r.482
+  FEM is half done - generation works. and other stuff. Only Constitutive Law for FEM is empty - waiting to be written. But there is a compilation problem we have to compile twice now, because of linker errors in fem loader.
+
+r.481
+  ComplexBody has now actors and initializers, and thanks to that FEMSetTextLoaderFunctor is working. loading terrain from VRML file will work in a similar way that FEMSetTextLoaderFunctor
+
+r.480 version 0.7.5
+  tagging v.0.7.5
+  - Quite stable version used for course (teaching how to use yade) with Frederic, Emmanuel and Julien.
+
+r.470
+  FEMBeam loads the file correctly
+
+r.469
+  renamed:
+  SDECParameters -> BodyMacroParameters
+  SDECContactGeometry -> MacroMicroContactGeometry, and all functors
+  SDECMacroMicroElasticRelationships -> MacroMicroElasticRelationships
+  SDECContactPhysics -> ElasticContactParameters
+  SDECLaw -> ElasticContactLaw
+  added epmty classes:
+  FEMTetrahedronParameters
+  FEMSetParameters
+  FEMSet2MarchingCubes
+  LatticeSet2MarchingCubes
+  MarchingCubes
+  FEMSetTextLoaderFunctor
+
+r.458
+  ActionParameterInitializer and ActionParameterReset, LeapFrogOrientationIntegratorFunctor and LeapFrogPositionIntegratorFunctor, ForceCondition GravityCondition RotationCondition TranslationCondition
+
+r.450
+  separating gravity to GravityForceFunctor
+
+r.444 version 0.7.4
+  tagging v.0.7.4
+  - version used for training with Julien, Frederic, and Luc
+
+r.441
+  renaming:
+  DynamicEngine -> ConsitutiveLaw
+  KinematicEngine -> KinematicMotion
+  ApplyActionForce2Particle -> NewtonsForceLaw
+  ApplyActionMomentum2RigidBody -> NewtonsMomentumLaw
+
+r.435
+  fixed stupid and embarassing error when calculating sphere volume. All physical results are totally different now. comparing results again with SDEC.
+
+r.434
+  Body::group changed into Body::groupMask (so bodies can belong to many groups - max. 16 groups, because we have 16 bits here). added fem.beam, so that we can start with FEM
+
+r.432
+  started lattice model. Generation works.
+
+r.430
+  Splitted leapfrog integrator into two parts (position and orientation)
+
+r.427
+  internal shearing angle is added, and yade is ready to compare results with
+  sdec, although force recorder is little dirty, because it is releasing the big ball
+
+r.426 version 0.7.3
+  tagging v.0.7.3
+  - RotatingBox example with spheres and boxes inside is working quite good - with SimpleSpringDynamicEngine.
+  - BoxStack example is working quite good. meybe it should be renamed to WallImpact.
+  - the real name for damping is: Cundall Non Viscous Local Damping.
+  - TimeStepper is working quite nice, and now - even SDECLinkedSpheres example is stable.
+  - SDECParameters is now holding shearingAngle, young modulus and posions ratio - as it should. 
+  - timestepper is working good with that. All examples filegenerators exept FEM are working!
+
+r.419
+  added ActionReset - it is not inside SDECDynamicEngine - because for cloth example we have two/three engines, so they can't do a reset - because they will delete results from other engine
+  also changed arguments to InteractionGeometryFunctor - from shared_ptr<Interaction>& to const shared_ptr<Interaction>&, because InteractionContainer is returning cont reference. So by passing this const& - we avoid making extra copy of shared_ptr so it is faster - lot of files were changed.
+  I also started separating computation of InteractionGeometry and InteractionPhysics for permanent links. Currently this calculation is inside SDECDynamicEngine ! it is very bad, and must be moved outside, because for lattice model I want to make those calculations in a clean way - outside of dynamic engine. To do that I had to modify dispatcher - so now dispatcher is doing two loops - one over permanentInteractions and second over interactions. So this dirty part of deleting duplicated interactions was moved from SDECDynamicEngine to InteractionGeometryDispatcher. It is still dirty and must be solved, but now it is dirty outside of dynamic engine, so it is possible to work on dynamic engine in a clean way.
+
+r.417 version 0.7.2
+  tagging v.0.7.2
+  - damping is separated from SDECDynamicEngine and works, strange is that ActionDampingDispatcher and ActionApplyDispatcher are exactly the same! so they should be merged into one dispatcher. maybe Action2BodyPhysicalParametersDispatcher
+
+r.416 version 0.7.1
+  tagging v.0.7.1
+  - I have done some general cleaning - removed unnecessary constructors, deleted unused postProcessAttributes, etc..
+  - FunctorWrapper is Serializable, now - because we want Dispatcher to work with serialization, so that Functors can get extra arguments from .xml
+
+r.413
+  FunctorWrapper is Serializable, now - because we want Dispatcher to work with serialization, so that Functors can get extra arguments from .xml
+
+r.410
+  finished all renaming. update of GeometricalModel for cloth is working
+
+r.407
+  OK/Cancel works now in file selection dialog, 
+  ActionForce2RigidBody was deleted, because ActionForce2Particle does the same job 
+  now I'm starting to work on updating GeometricalModel of Mesh2D, so that cloth will be displayed properly
+
+r.406
+  I have done some general cleaning - removed unnecessary constructors, deleted unused postProcessAttributes, etc.. and I have discovered that when class has no virtual destructor then dunamic_cast fails! I wanted to remove all unused destructor, and then all dynamic_cast were failing. So instead I added virtual destructor everywhere :)
+
+r.399
+  We have now: ( <- means 'aggregates' )
+  Interaction <- InteractionGeometry
+  Interaction <- InteractionPhysics
+  Body <- BodyPhysicalParameters
+  Body <- BoundingVolume
+  Body <- GeometricalModel
+  Body <- InteractionDescription
+
+r.395
+  lots of class renaming. openGL improvement, Loki stored in single place.
+
+r.379 version 0.7.0
+  tagging v.0.7.0
+  - To add BodyPhysicalParameter the OpenGLDispatchers have been added. This greatly separates display from numerics.
+  -  MassSpring cloth is now working : but we still have to update geometricalModel. Created TimeIntegratorFunctor and Dispatcher. BallisticDynamicEngine is now LeapFrogIntegrator
+  
+
+r.374
+  MassSpring cloth is now working : but we still have to update geometricalModel. Created TimeIntegratorFunctor and Dispatcher. BallisticDynamicEngine is now LeapFrogIntegrator
+
+r.373
+  To add BodyPhysicalParameter the OpenGLDispatchers have been added. This greatly separates display from numerics.
+
+r.368
+  Added BodyPhysics class and moved all type of bodies into subdirectory, BodyPhysics
+
+r.367 version 0.6.8
+  tagging v.0.6.8
+  - Added single step button in QtGUI
+  - Better SpheresPlanes FileGenerator
+  - HangingCloth is working again but it is designed using Yade framework
+
+r.366
+  HangingCloth is working again but it is designed adhering to Yade framework.
+
+r.355
+  InteractionPhysicsDispatcher starts to works. But we have to make BodyPhysics
+
+r.352 (*) (****) version 0.6.7
+  tagging v.0.6.7
+  - small change in ActionDispatcher.cpp, is faster, but if Action was holding body's id it is possible that it can be faster result: 107 seconds is faster compared to 111 seconds
+  - tere are a lot of places where we can do improvement like this. if we do code change like here - in every possible places - yade can gain a lot of speed.
+  - basically I've discovered that every temporary variable of type shared_ptr<> costs 3 seconds, so we should avoid creating them and instead pass them around by references - whenever possible. 
+  - And very iportant to note is that this speed improvement is possible ONLY because we have introduced Action, which is more generic! without this class it would be impossible to get faster. So it means that good generic code allows faster code - at least sometimes - as we have example if this here. The same was with containers - introducing containers made code slower, but it made possible to make improvements in other places (because containers increased genericity) and as a result the code got faster.
+
+r.351
+  renamed CollisionFunctor to InteractionFunctor
+
+r.345 version 0.6.6
+  tagging v.0.6.6
+  - possibly faster DynLibDispatcher, 
+  - I was also trying to fix problem that Singleton is not deleted at end, but finally I made only some improvement, but it is still not fixed.
+
+r.344
+  some optimizations by using references. Multimethods now support inheritance in Indexable objects, I had to modify in Indexable class:
+  #define REGISTER_CLASS_INDEX(SomeClass,BaseClass)
+
+r.342 version 0.6.5
+  tagging v.0.6.5
+  - containers return references (no temporary objects are created)
+
+r.340 version 0.6.4
+  tagging v.0.6.4
+  - ActionContainer, without creating new pointers everytime.
+
+r.339 version 0.6.3
+  tagging v.0.6.3
+  - ActionContainer->reset() - faster code.
+  - benchmark tests.
+
+r.338 version 0.6.2
+  tagging v.0.6.2
+  - ActionDispatcher is working
+  - dispatcher for creating actions need createIndex() in constructor of all Actions
+  - Added classes: Action, ActionVecVec, ActionContainer, ActionForce, ActionMomentum, etc.. but they are empty. And it is compiling
+
+r.337
+  ActionDispatcher is working
+
+r.334
+  dispatcher for creating actions need createIndex() in constructor of all Actions
+
+r.330
+  Added classes: Action, ActionVecVec, ActionContainer, ActionForce, ActionMomentum, etc.. but they are empty. And it is compiling
+
+r.323
+  Added Action, ActionContainer, SDECLinearContactModel, PhysicalInteractor. We started redesign to introduce Action which are the response of a DynamicEngine to an Interaction and acts on body.
+
+r.315 version 0.6.1
+  tagging v.0.6.1
+  - versioon used for benchmark checks
+  - small fixes.
+  - Real used everywhere instead of floar or double.
+
+r.312 (*)
+  now Real is used everywhere instead of double or float. Specify with compilation flag #define DOUBLE_PRECISION, whether you want float or double.
+
+r.307
+  splitting InteractionModel to InteractionGeometry and InteractionPhysics
+
+r.303
+  iterating containers in done with: gotoFirst, gotoNext, notAtEnd gotoFirstPotential, gotoNextPotential, notAtEndPotential.
+
+r.300 version 0.6.0
+  tagging v.0.6.0
+  - moment rotation law added, mess inside SDECDynamicEngine (three enegines in one!)
+  - Serialization now supports almost all std, boost and Loki containers and more
+  - math classes are separate from serialization, and done with templates (but with wild-magic license)
+  - for storing Bodies and Interactions we now use polymorphic classes InteractionContainer and BodyContainer
+  - yade uses threads now, but still not fully stable
+  - switch at compile time to select float/double precision of calculation
+  - displayed objects are now casting really cool shadows
+  - some examples are not updated, and therefor not working. it is guaranteed that SDECBenchmark8k will always work.
+  - BoundingVolume optimized for each kind of GeometricalModel makes computation almost twice faster
+  - new very generic MultiMethods are added, allowing multivirtual call with extra parameters, and easy code reuse
+
+r.298
+  new very generic MultiMethods are added, allowing multivirtual call with extra parameters, and easy code reuse
+
+r.291
+  better handling of threads, but still not fully stable
+
+r.254 version 0.5.2
+  tagging v.0.5.2
+  - Finished rearranging subdirectories. Now we have directory extensions (we can rename it,
+  - if there is a better name), and ClassFactory is in toolbox/Libraries,
+  - yade is now compiling (and works) with g++ 3.3,
+  - all .xml examples except ErrorTolerant, are now working,
+  - Improved version of QtGUIGenerator. Now boolean are represented by
+  - checkboxes instead of linedits,
+  - Better handling of start,stop and reload simulation. Thread now terminate
+  - when associated window is closed,
+  - NullGUI is now saving results during computations. Those results can be opened with QtGUI and we can see what is computed.
+  - added filegenerator that can import data files from SDEC,
+  - Boxes are now casting shadows,
+  - Better handling of thread into GUI.
+  - is compiling with double.
+
+r.245
+  BoundingVolume now can be used to center scene for display
+
+r.232 version 0.5.1
+  tagging v.0.5.1
+  - small fixes, little faster
+
+r.227 version 0.5.0
+  tagging v.0.5.0
+  - Bounding volume are now both indexalbe and a GeometricalModel,
+  - BoundingVolume update is now done in an actor,
+  - Improved version of GLWindowManager library,
+  - BoundingVolume optimized for each kind of GeometricalModel makes computation almost twice faster
+
+r.225
+  some examples are not updated, and therefore not working. it is guaranteed that SDECBenchmark8k will always work.
+
+r.223 version 0.4.8
+  tagging v.0.4.8
+  - scripts are checking all Environement Variables - more safety,
+  - fixed missing is_base_and_derived in Indexable.hpp,
+  - Much better version of Thread library and multithreaded QGLViewer,
+  - Reenabling GUI updater thread,
+  - Now we use InteractionHashMap by default because InteractionVecSet is not ready yet,
+  - Added RenderingEngines,
+  - OpenGLWrapper 50% done  - and #DOUBLE_PRECISION works! (float/double),
+  - Shadows are working
+  - SDECCollision.xml and SDECTetrahedronWithLinks.xml work for dt=0.003,
+  - comparing results with older versions.
+  
+r.219
+  displayed objects are now casting really cool shadows
+
+r.209
+  switch at compile time to select float/double precision of calculation
+
+r.196 version 0.4.7
+  tagging v.0.4.7
+  - Improved thread management. Multiple views are now working,
+  - Improved GUI.
+  - scripts that allow easy switching between relative paths and paths in environemnt YADE*PATH variables
+  - XMLManager writes pointers in a shorter way, with _className_
+  - NullGUI works - for benchmars of Vector3 not in Serializable, etc..
+
+r.182
+  yade uses threads now, but still not fully stable
+
+r.184 version 0.4.6
+  tagging version 0.4.6
+  - New SimulationController is now working
+  - Started moving simulation loop from glViewer to a specific thread
+  - InteractionContainer and BodyContainer integration completed. but container classes quality/speed is not good (and tested) yet
+  - InteractionVecSet and BodyVector done.
+  - Added ThreadSynchronizer. Yade is now working with external simulation loop
+  - FIXED threading on multi-processor machine (not real multiprocessor, just hyper threading...)
+  - rename BodyVector to BodyRedirectionVector
+  
+r.180
+  for storing Bodies and Interactions we now use polymorphic classes InteractionContainer and BodyContainer
+
+r.175 version 0.4.5
+  tagging 0.4.5
+  - Add QtFileGenerator, for automatic file generation with Qt GUI (not completely working yet)
+  - QtGuiGenerator and QtFileGenerator are now working
+  - BodyContainer starts to work
+  - All Qt libraries are now in one library.
+  - Created new qt controller for simulation and new opengl library
+
+r.168 version 0.4.4
+  tagging v.0.4.4
+  InteractionContainer starts working
+
+r.165 version 0.4.3
+  tagging v.0.4.3
+  praparing for InteractionContainer. small fixes
+
+r.155 version 0.4.2
+  tagging v.0.4.2
+  - better serialization for math stuff.
+
+r.154 
+  math classes are separate from serialization, and done with templates (but with wild-magic license)
+
+r.147 version 0.4.1
+  tagging v.0.4.1
+  - Serialization now supports almost all STL containers from std namespace, boost and Loki containers and more
+  - comparing resluts with older revisions.
+
+r.140
+  Serialization now supports almost all STL containers from std namespace, boost and Loki containers and more
+
+r.129 version 0.4.0
+  moment rotation law added,
+  - unit tests of SDEC with r.90 (checking results correctness)
+  - LPC solver for ErrorTolerant computations
+
+r.127
+  LPC solver for ErrorTolerant computations
+
+r.122
+  moment rotation law added, mess inside SDECDynamicEngine (three enegines in one!)
+
+r.112 version 0.3.1
+  tagging v.0.3.1
+  - added NullGUI, so commandline computation is possible
+
+r.108
+  started ErrorTolerant DynamicEngine
+
+r.90 version 0.3.0
+  tagging v.0.3.0
+  - SDEC (DEM) added and works with contact law
+
+r.83
+  SDECDynamicEngine starts to work with SDEC contact law
+
+r.80
+  simple example for SDEC added
+
+r.76
+  Serialization uses boost::spirit
+
+r.74 version 0.2.0
+  tagging v.0.2.0 with working cloth, rotatingbox and falling boxes. before adding SDEC
+  - ClassFactory is now reusable
+  
+r.56
+  ClassFactory is now reusable
+
+r.40
+  setDebug, setRelease scripts added
+
+r.30
+  cloth simulation added
+
+r.26 version 0.1.1
+  tagging version v.0.1.1 after adding multimethods and before adding Cloth
+
+r.17
+  first try at multimethods, added class Indexable, and multimethods are used for collision
+
+r.6 version 0.1.0
+  tagging v.0.1.0
+  - initial yade version imported (after 6 months of work by Olivier alone)
+  - tagging this version before adding multimethods
+  - Rigid Body example works
+  
+r.1
+  rigid body example works
+

=== renamed file 'ChangeLog' => 'ChangeLog.moved'
=== added file 'INSTALL'
--- INSTALL	1970-01-01 00:00:00 +0000
+++ INSTALL	2013-11-15 08:22:02 +0000
@@ -0,0 +1,78 @@
+
+Authoritative source: http://yade.wikia.com/wiki/Installation, this file may be out-fo-date.
+
+Release sources
+===============
+Go to http://yade.wikia.com/wiki/Installation for up-to-date sources.
+
+Latest SVN snapshot
+===================
+If you want to look at the latest yade version from Launchpad, 
+you can download it using one of the ways shown below:
+
+	bzr checkout lp:yade
+
+
+Which one of those above will work depends on your network and firewall
+configuration.
+
+Prequisities
+============
+All libraries listed below must be installed with development headers. It's
+better to install them using your linux's distribution package management
+system, instead of downloading directly from the website.
+
+    * boost library >=1.34 with components: date-time, filesystem, thread, regex, algorithm, foreach
+    * qt3 library, including multithreading (-mt) component
+    * freeglut3 / libglut3 development files
+    * g++
+    * sqlite3
+    * scons build system 
+
+optionally:
+
+    * Ctags
+    * Doxygen
+    * wildmagic 3.11 - only if you want Delaunay triangulation support in lattice model
+    * log4cxx - extensive logging support and debugging
+    * python-dev, python-scientific, python-matplotlib, python-numpy - for python scripting interface
+	 * gdb
+
+Installation
+============
+
+Run this command from inside yade-0.12/ directory to install yade as a local
+user without root privileages:
+
+	scons PREFIX=/home/username/YADE optimize=1
+
+(If you have a machine that you are the only user on, you can instead change
+permission on /usr/local 
+	
+	sudo chown username: /usr/local
+
+	scons optimize=1
+
+and still use default paths without special priviledges).
+
+Scons takes many options, see scons -h or http://yade.wikia.com/wiki/Installation_details#Scons_options for details.
+
+Distribution-specific instructions
+==================================
+(http://yade.wikia.com/wiki/Installation_of_yade_on_debian_or_kubuntu,
+http://yade.wikia.com/wiki/Installation_of_yade_on_fedora,
+http://yade.wikia.com/wiki/Installation_of_yade_on_gentoo is more detailed)
+
+Debian/Ubuntu
+-------------
+Install dependencies (9.04, Jaunty):
+
+sudo aptitude install scons libqt3-mt-dev qt3-dev-tools freeglut3-dev \  
+libboost-date-time-dev libboost-filesystem-dev libboost-thread-dev \  
+libboost-regex-dev fakeroot dpkg-dev build-essential g++ \  
+libboost-iostreams-dev liblog4cxx10-dev python-dev libboost-python-dev ipython \  
+python-matplotlib libsqlite3-dev python-numeric python-tk gnuplot doxygen python-pygraphviz
+
+
+Then run scons as per above.
+

=== renamed file 'INSTALL' => 'INSTALL.moved'
=== added file 'LICENSE'
--- LICENSE	1970-01-01 00:00:00 +0000
+++ LICENSE	2013-11-15 08:22:02 +0000
@@ -0,0 +1,346 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+13. As a special exception, you have permission to link this program
+with the CGAL library and distribute executables, as long as you
+follow the requirements of the GNU GPL in regard to all of the
+software in the executable aside from CGAL.
+

=== renamed file 'LICENSE' => 'LICENSE.moved'
=== added file 'NEWS'
--- NEWS	1970-01-01 00:00:00 +0000
+++ NEWS	2013-11-15 08:22:02 +0000
@@ -0,0 +1,174 @@
+vim:syntax=changelog
+
+2009-04-20 Václav Šmilauer <eudoxos@xxxxxxxx> revision around bzr2150
+
+	* RELEASE: 0.5
+		- https://launchpad.net/yade/+milestone/0.5
+
+	* overall:
+		- yade main is now a python script, the c++ part is imported
+		- many classes renamed for the sake of consistency, while mostly keeping backward compatibility for scripts
+		- all classes (deriving from Serializable) are automatically exposed in python via automatically constructed wrappers, with full attribute access (https://bugs.launchpad.net/yade/+bug/544857)
+		- lot of old code removed (to be found in attic/)
+
+	* functionality:
+		- separated State and (possibly shared) Material for bodies
+		- InsertionSortCollider handles both periodic and aperiodic simulations now
+		- Cell can undergo arbitrary linear transformation during simulation
+		- VTKRecorder saves to VTK-compatible XML files; allows one to use Paraview for post-processing
+		- NewtonIntegrator features integration of rotation of non-spherical bodies
+		- callback functionality for interaction and body loop (InteractionDispatchers and NewtonIntegrator) (not yet fully done)
+		- body and interaction containers devirtualized (https://blueprints.launchpad.net/yade/+spec/devirtualize-containers)
+
+	* documentation:
+		- New website https://www.yade-dem.org
+		- Sphinx documentation https://www.yade-dem.org/sphinx/, containing both hand-written and automatically generated documentation
+		- All classes and attributes visible from python are documented now
+		- Drop doxygen documentation
+
+
+2009-08-31 Václav Šmilauer <eudoxos@xxxxxxxx> revision around bzr1740
+
+	* RELEASE: 0.20.0
+
+	* overall: 
+		- fix many crashers, including synchronization with openGL, GUI and python
+		- generate documentation for both python and c++ classes/functions automatically (http://yade.wikia.com/wiki/Reference_documentation)
+		- move away from SVN repository at berlios.de to bzr at http://www.launchpad.net/yade; bug tracking and other launchpad features are being used; mailing lists migrated to launchpad
+
+	* functionality enhancements (apart from performance-oriented changes):
+		- Facets (arbitrary triangulation elements) interacting with spheres, allowing to triangulate any surface
+		- support for GTS-compatible triangulated surfaces both as predicates and facet-triangulated simulation elements
+		- non-incremental sphere-sphere and sphere-facet contact geometry classes (Dem3DofGeom)
+		- ConstitutiveLawDispatcher, for having multiple constitutive laws operating on different interactions
+		- schedule to run multiple jobs at time, with different parameters (yade-multi, http://yade.wikia.com/wiki/ScriptParametricStudy)
+		- added PhysicalParameters::blockedDOFs
+		- periodic boundary conditions
+		- interaction logic cleaned up
+		- sphere packing generators (orthogonal, hexagonal, loose random, triaxially compacted; periodic coming soon)
+		- geometry predicates to clip packing, including boolean operations on predicates
+		- infrastructure for regression tests
+
+	* performance:
+		- consistent openMP support throughout the code (InteractionDispatchers, NewtonsDampedLaw, BexContainer) (http://yade.wikia.com/wiki/Performance_Tuning#openMP)
+		- InsertionSortCollider (PersistentSAPCollide removed) (http://yade.wikia.com/wiki/Colliders_performace)
+		- InteractionDispatchers that reduce number of loops over interactions to one (http://yade.wikia.com/wiki/Performance_Tuning#InteractionDispatchers)
+		- new fast container for interactions (InteractionVecMap) (http://yade.wikia.com/wiki/Performance_Tuning#Containers)
+		- caching dispatchers, avoiding repetitive multivirtual call resolution (http://yade.wikia.com/wiki/Performance_Tuning#Dispatcher_cache)
+		- runtime profiling information (http://yade.wikia.com/wiki/Speed_profiling_using_TimingInfo_and_TimingDeltas_classes)
+		- avoid running collision detection at every step (http://yade.wikia.com/wiki/Insertion_Sort_Collider_Stride)
+		- vector and quaternion classes are wrapped in python automatically (faster, avoids hand-written wrappers)
+		- removed many python proxy classes, resulting in big speedup of python (e.g. 40 × for some operations)
+
+	* building:
+		- yade can be optionally with one single plugin containing all packages. Speeds up full compilation considerably and reduces binary size several times.
+		- files in pkg/* are picked up automatically by the build system, including linking flags
+		- do not install headers, only plugins
+		- fix debian-package builds and document the procedure (http://yade.wikia.com/wiki/DebianPackages), special package for docs
+		- fix all (or most) compile-time warnings
+		- create new top-level py/ directory for python
+
+	* python:
+		- use natural syntax for class instance construction with attributes
+		- run telnet server to make yade accessible while running (from localhost only)
+		- save any python variables within the XML file, which will be resurrected next time (utils.saveVars, utils.loadVars)
+		- support saving simulation to memory temporarily
+		- functions from creating video from simulation (via snapshots, either during simulation or in the player)
+
+	* Documentation:
+		- Structurized content added http://yade.wikia.com/wiki/Structurized_content
+		- FAQ start to implement http://yade.wikia.com/wiki/FAQ
+
+
+2008-08-20 Janek Kozicki <cosurgi@xxxxxxxxx> revision 1579
+
+	* RELEASE: 0.12.1
+	
+		- several python interface improvements
+		- add code for plotting histogram of interaction directions
+		- added buttons for looking from different directions
+		- new contact algorithm for facets
+		- added python script for making videos
+		- added a TCP server on port 9000 with python console in it
+		- new dependency on python-numpy package, which allows faster math in python
+		- added a script for parametric studies
+
+
+2008-08-20 Janek Kozicki <cosurgi@xxxxxxxxx> revision 1486
+
+	* RELEASE: 0.12
+
+	* User interface:
+
+		- Refactored Qt3 interface: MDI with simulation running
+		  asynchronously, with python console
+
+		- Python wrapper and console with the ability to control most
+		  simulation aspects (including creating simulations,
+		  modifying, inspecting, running, recording data), some parts
+		  of the UI (setting view, configuring renderer); see
+		  scripts/simple-scene.py to get started
+		  (http://yade.wikia.com/wiki/SimpleSceneTutorial)
+
+		- Much enhanced simulation recorder and player, saving
+		  optionally to a single file (sqlite database), the ability to
+		  create video from simulation with one command (may be done
+		  offscreen as well): scripts/simple-scene-player.py,
+		  http://yade.wikia.com/wiki/New:Making_videos
+
+	* Graphical Viewer:
+
+		- up to 3 clipping planes in the GLViewer, can be manipulated,
+		  bound to each other, activated/deactivated
+
+		- saving view to view configurations inside MetaBody (Alt+7 --
+		  Alt+9), can be loaded later (from python as well)
+
+		- displacement and rotation scaling in GLViewer, using
+		  PhysicalParameters::refSe3
+
+	* Simulation features:
+
+		- New moment rotation law, fully tested and working
+
+		- All simulation aspects (dt, iteration, virtual time) are now
+		  inside MetaBody, i.e. are restored exactly as they were from
+		  .xml
+
+		- Much improved triaxial test
+
+		- Lattice model can now simulate concrete with steel fibres
+	
+	* New, experimental features:
+
+		- Selectively block any of 6 DOFs ( translation and rotation)
+		  for individual bodies (PhysicalParameters::blockedDOFs - not
+		  documented, not conveniently accessible from python
+		  yet)
+
+		- Plotting interface based on pylab see example in
+		  scripts/simple-scene-graph.py
+
+		- Sega's facets and vertices with stl import (for example
+		  import shapes from blender)
+	
+	* Serialization:
+
+		- Transparent support for compressed .xml.gz and .xml.bz2
+		  files; dropped support for binary format
+
+		- The (de)serializer now (un)escapes all control characters,
+		  using the &charname; format, arbitrary string values can be
+		  de/serialized now, including parentheses, quotations marks,
+		  newlines, tabs, <>.
+
+	* Compilation / Development:
+
+		- Compilation profiles allow separate option sets for scons;
+		  simultaneous compilation of multiple profiles is supported
+		  via the profile=a,b,c
+		
+		- QGLViewer source is now in our tree, no need to install it
+		  separately
+
+

=== renamed file 'NEWS' => 'NEWS.moved'
=== added file 'RELEASE'
--- RELEASE	1970-01-01 00:00:00 +0000
+++ RELEASE	2013-11-15 08:22:02 +0000
@@ -0,0 +1,1 @@
+0.60.3

=== added file 'SConscript'
--- SConscript	1970-01-01 00:00:00 +0000
+++ SConscript	2013-11-15 08:22:02 +0000
@@ -0,0 +1,5 @@
+Import('*')
+
+import yadeSCons
+yadeSCons.buildPluginLibs(env,env['buildPlugs'])
+SConscript(dirs=['core','lib']+[d for d in ('extra','py','gui') if d not in env['exclude']],duplicate=0)

=== added file 'SConscript-mono'
--- SConscript-mono	1970-01-01 00:00:00 +0000
+++ SConscript-mono	2013-11-15 08:22:02 +0000
@@ -0,0 +1,101 @@
+# vim: syntax=python
+Import('*')
+
+
+srcs=[] # list of single source files that will be compiled in chunks based on chunkSize
+extraSrcs=[] # list of _chunks_ (list/tuple) of sources that will be compiled separately
+pyMods=[] # list of symbolic links that will point to the resulting library; their sources must be specified in srcs/extraSrcs
+libs=[]
+
+### core
+
+pyMain='$PREFIX/bin/yade$SUFFIX'
+env['PLUGINDIR']='$PREFIX/lib/yade$SUFFIX'
+main=env.ScanReplace('core/main/main.py.in')
+batch=env.ScanReplace('core/main/yade-batch.in')
+env.AlwaysBuild(main)
+env.AlwaysBuild(batch)
+env.InstallAs(pyMain,main)
+env.InstallAs(pyMain+'-batch',batch)
+env.AddPostAction(pyMain,Chmod(pyMain,0755))
+env.AddPostAction(pyMain+'-batch',Chmod(pyMain+'-batch',0755))
+
+extraSrcs+=[['core/'+f for f in ['Body.cpp','BodyContainer.cpp','Bound.cpp','Cell.cpp','PartialEngine.cpp','Engine.cpp','FileGenerator.cpp','FrontEnd.cpp','Interaction.cpp','InteractionContainer.cpp','GroupRelationData.cpp','Material.cpp','Scene.cpp','Dispatcher.cpp','Omega.cpp','Shape.cpp','SimulationFlow.cpp','State.cpp','ThreadRunner.cpp','ThreadWorker.cpp','TimeStepper.cpp','corePlugins.cpp','main/pyboot.cpp']]]
+pyMods+=['boot']
+
+# libs
+srcs+=['lib/'+f for f in ['base/Math.cpp','factory/ClassFactory.cpp','factory/DynLibManager.cpp','multimethods/Indexable.cpp','serialization/Serializable.cpp','pyutil/gil.cpp']]
+if 'opengl' in env['features']:
+	srcs+=['lib/opengl/GLUtils.cpp']
+	libs+=['GL','GLU','glut']
+if 'cgal' in env['features']:
+	extraSrcs+=[['lib/'+f for f in Split('triangulation/KinematicLocalisationAnalyser.cpp triangulation/Operations.cpp triangulation/RegularTriangulation.cpp triangulation/Timer.cpp triangulation/basicVTKwritter.cpp triangulation/FlowBoundingSphere.cpp triangulation/Deformation.cpp triangulation/Empilement.cpp triangulation/stdafx.cpp triangulation/Tenseur3.cpp triangulation/Tesselation.cpp triangulation/TriaxialState.cpp')]]
+
+# py
+if 'gts' in env['features']:
+	extraSrcs+=['py/'+f for f in ('3rd-party/pygts-0.3.1/cleanup.c','3rd-party/pygts-0.3.1/edge.c','3rd-party/pygts-0.3.1/face.c','3rd-party/pygts-0.3.1/object.c','3rd-party/pygts-0.3.1/point.c','3rd-party/pygts-0.3.1/pygts.c','3rd-party/pygts-0.3.1/segment.c','3rd-party/pygts-0.3.1/surface.c','3rd-party/pygts-0.3.1/triangle.c','3rd-party/pygts-0.3.1/vertex.c')]
+	pyMods+=['../gts/_gts']
+	env.Install('$PLUGINDIR/py/gts',[env.File('py/3rd-party/pygts-0.3.1/__init__.py'),env.File('py/3rd-party/pygts-0.3.1/pygts.py')])
+
+pyMods+=['../miniEigen','WeightedAverage2d','log','_utils','_packPredicates','_packSpheres','_packObb','wrapper','_customConverters','_eudoxos','_packSpherePadder']
+srcs+=['py/mathWrap/miniEigen.cpp','py/WeightedAverage2d.cpp','py/_eudoxos.cpp','py/log.cpp','py/_utils.cpp','py/pack/_packPredicates.cpp','py/pack/_packSpheres.cpp','py/pack/_packObb.cpp','py/wrapper/yadeWrapper.cpp','py/wrapper/customConverters.cpp']
+extraSrcs+=[ ['py/pack/_packSpherePadder.cpp','py/pack/SpherePadder/SpherePadder.cpp','py/pack/SpherePadder/TetraMesh.cpp','py/pack/SpherePadder/CellPartition.cpp']+(['py/pack/SpherePadder/SpherePackingTriangulation.cpp'] if 'cgal' in env['features'] else []) ]
+
+env.Install('$PLUGINDIR/py/yade',[
+	env.AlwaysBuild(env.ScanReplace('py/__init__.py.in')),
+	env.AlwaysBuild(env.ScanReplace('py/config.py.in'))
+	]
+	+[env.File('py/'+f) for f in  ['utils.py','ymport.py','export.py','eudoxos.py','plot.py','params.py','linterpolation.py','timing.py','pack/pack.py','remote.py','system.py','export.py','post2d.py','runtime.py','manpage.py','_extraDocs.py',]]
+)
+env.Install('$PLUGINDIR/py/yade/tests',[env.File('__init__.py','py/tests'),env.File('wrapper.py','py/tests'),env.File('omega.py','py/tests')
+])
+
+env.Install('$PLUGINDIR/py',[
+	env.File('mtTkinter.py','py/3rd-party/mtTkinter-0.3'),
+])
+
+# gui
+if 'qt4' in env['features']:
+	env.Install('$PLUGINDIR/py/yade/qt',[env.File('gui/'+f) for f in ['qt4/img_rc.py','qt4/ui_controller.py','qt4/SerializableEditor.py','qt4/Inspector.py','qt4/__init__.py',]])
+	env.Command('gui/qt4/img_rc.py','gui/qt4/img.qrc','pyrcc4 -o $buildDir/gui/qt4/img_rc.py gui/qt4/img.qrc')
+	env.Command('gui/qt4/ui_controller.py','gui/qt4/controller.ui','pyuic4 -o $buildDir/gui/qt4/ui_controller.py gui/qt4/controller.ui')
+	srcs+=['gui/qt4/GLViewer.cpp','gui/qt4/_GLViewer.cpp','gui/qt4/OpenGLManager.cpp']
+	pyMods+=['qt/_GLViewer']
+	libs+=[env['QGLVIEWER_LIB']]
+
+# pkg
+pluginsSrcs=[p.src for p in env['buildPlugs'].values()]
+srcs+=pluginsSrcs
+
+# building itself
+env['LIBS']=env['LIBS']+libs
+import os.path
+
+def makeChunk(chunk,srcs,baseDir=None):
+	if not baseDir: baseDir=env['buildDir']
+	chunk2=baseDir+'/'+chunk
+	f=open(chunk2,'w')
+	for s in srcs: f.write('#include<%s>\n'%os.path.abspath(env['topLevelDir']+'/'+s))
+	return chunk2
+	
+
+extraChunks=[(ff if isinstance(ff,str) else makeChunk('chunk%02d.%s'%(i,ff[0].split('.')[-1]),ff)) for i,ff in enumerate(extraSrcs)]
+#import pprint; pprint.pprint(extraSrcs)
+chunkSize=env['chunkSize']
+if chunkSize>1:
+	srcsChunks=[srcs[chunkSize*i:chunkSize*(i+1)] for i in range(0,1+len(srcs)/chunkSize)]
+	env.Install('$PLUGINDIR',env.SharedLibrary('yade',[makeChunk('yade%02d.cpp'%i,chunkSrcs) for i,chunkSrcs in enumerate(srcsChunks)]+extraChunks))
+elif chunkSize==1:
+	env.Install('$PLUGINDIR',env.SharedLibrary('yade',srcs+extraChunks))
+else: # chunkSize<=0
+	env.Install('$PLUGINDIR',env.SharedLibrary('yade',[makeChunk('yade.cpp',srcs)]+extraChunks))
+
+yadeSo=env.subst('$PLUGINDIR/libyade.so')
+import os, os.path
+for m in pyMods:
+	mm=env.subst('$PLUGINDIR/py/yade/'+m+'.so')
+	d=os.path.dirname(mm);
+	if not os.path.exists(d): os.makedirs(d)
+	relpath=os.path.relpath(yadeSo,d)
+	env.Command(mm,yadeSo,'ln -s -f "%s" "%s"'%(relpath,mm))
+

=== added file 'SConstruct'
--- SConstruct	1970-01-01 00:00:00 +0000
+++ SConstruct	2013-11-15 08:22:02 +0000
@@ -0,0 +1,627 @@
+#!/usr/bin/scons
+# coding: UTF-8
+# vim:syntax=python:
+
+#
+# This is the master build file for scons (http://www.scons.org). It is experimental, though it build very well for me. Prequisities for running are having scons installed (debian & family: package scons)
+#
+# Type "scons -h" for yade-specific options and "scons -H" for scons' options. Note that yade options will be remembered (saved in scons.config) so that you need to specify them only for the first time. Like this, for example:
+#
+#	scons -j2 brief=1 debug=0 optimize=1 profile=1 exclude=extra,lattice,snow
+#
+# Next time, you can simply run "scons" or "scons -j4" (for 4-parallel builds) to rebuild targets that need it. IF YOU NEED TO READ CODE IN THIS FILE, SOMETHING IS BROKEN AND YOU SHOULD REALLY TELL ME.
+#
+# Scons will do preparatory steps (generating SConscript files from .pro files, creating local include directory and symlinking all headers from there, ...), compile files and install them.
+#
+# To clean the build, run `scons -c'. Please note that it will also _uninstall_ yade from $PREFIX!
+#
+# TODO:
+#  1. [REMOVED] [DONE] retrieve target list and append install targets dynamically;
+#  2. [DONE] configuration and option handling.
+#  3. Have build.log with commands and all output...
+#
+# And as usually, clean up the code, get rid of workarounds and hacks etc.
+import os,os.path,string,re,sys,shutil
+import SCons
+# SCons version numbers are needed a few times
+# rewritten for python2.4
+ver=[str(x) for x in SCons.__version__.split('.')]
+for i in range(0,len(ver)):
+	def any2num(x):
+		if x in ('0123456789'): return x
+		else: return '0'
+	ver[i]="".join([any2num(x) for x in ver[i]])
+	if len(ver[i])>2: ver[i]=ver[i][0:2]+"."+ver[i][2:]
+sconsVersion=10000*float(ver[0])
+if len(ver)>1: sconsVersion+=100*float(ver[1])
+if len(ver)>2: sconsVersion+=float(ver[2])
+# print sconsVersion
+#
+
+##########################################################################################
+########## PROXY TO NEWER SCONS (DOWNLOADED IF NEEDED) ###################################
+##########################################################################################
+#print sconsVersion
+if sconsVersion<9806.0 and not os.environ.has_key('NO_SCONS_GET_RECENT'):
+	# sconsVersion<10200.0 
+	# tgzParams=("http://dfn.dl.sourceforge.net/sourceforge/scons/scons-local-1.2.0.d20090223.tar.gz","/scons-local-1.2.0.d20090223";)
+	tgzParams=("http://heanet.dl.sourceforge.net/sourceforge/scons/scons-local-1.0.0.tar.gz","/scons-local-1.0.0";)
+	newPrefix="./scons-local";
+	newUrl,newDir=tgzParams[0],newPrefix+"/"+tgzParams[1]
+	if not os.path.exists(newDir):
+		print "Scons version too old, downloading new version. All subsequent calls will be proxied to the new version transparently."
+		import urllib,tarfile
+		(filename,headers)=urllib.urlretrieve(newUrl)
+		print filename,"\n",headers
+		tar=tarfile.open(filename, "r:gz")
+		for tarinfo in tar: tar.extract(tarinfo,newPrefix)
+		print "Done extracting scons to",newDir
+		assert(os.path.exists(newDir))
+	if os.path.exists(newDir):
+		Exit(os.execv(newPrefix+"/scons.py",[newPrefix+'/scons.py']+sys.argv[1:]))
+
+##########################################################################################
+############# OPTIONS ####################################################################
+##########################################################################################
+
+### hardy compatibility (may be removed at some later point probably)
+### used only when building debian package, since at that point auto download of newer scons is disabled
+if 'Variables' not in dir():
+	Variables=Options
+	BoolVariable,ListVariable,EnumVariable=BoolOption,ListOption,EnumOption
+
+env=Environment(tools=['default','scanreplace'],toolpath=['scripts'])
+profileFile='scons.current-profile'
+env['sourceRoot']=os.getcwd()
+
+profOpts=Variables(profileFile)
+profOpts.Add(('profile','Config profile to use (predefined: default or ""); append ! to use it but not save for next build (in scons.current-profile)','default'))
+profOpts.Update(env)
+# multiple profiles - run them all at the same time
+# take care not to save current profile for those parallel builds
+if env['profile']=='': env['profile']='default'
+# save the profile only if the last char is not !
+saveProfile=True
+if env['profile'][-1]=='!': env['profile'],noSaveProfile=env['profile'][:-1],False
+if saveProfile: profOpts.Save(profileFile,env)
+
+if env['profile']=='': env['profile']='default'
+optsFile='scons.profile-'+env['profile']
+profile=env['profile']
+print '@@@ Using profile',profile,'('+optsFile+') @@@'
+
+opts=Variables(optsFile)
+## compatibility hack again
+if 'AddVariables' not in dir(opts): opts.AddVariables=opts.AddOptions
+
+def colonSplit(x): return x.split(':')
+
+#
+# The convention now is, that
+#  1. CAPITALIZED options are
+#   (a) notorious shell variables (they correspons most the time to SCons environment options of the same name - like CPPPATH)
+#   (b) c preprocessor macros available to the program source (like PREFIX and SUFFIX)
+#  2. lowercase options influence the building process, compiler options and the like.
+#
+
+
+opts.AddVariables(
+	### OLD: use PathOption with PathOption.PathIsDirCreate, but that doesn't exist in 0.96.1!
+	('PREFIX','Install path prefix','/usr/local'),
+	('runtimePREFIX','Runtime path prefix; DO NOT USE, inteded for packaging only.',None),
+	('variant','Build variant, will be suffixed to all files, along with version.','' if profile=='default' else '-'+profile,None,lambda x:x),
+	BoolVariable('debug', 'Enable debugging information',0),
+	BoolVariable('gprof','Enable profiling information for gprof',0),
+	('optimize','Turn on optimizations (-1, 0 or 1); negative value sets optimization based on debugging: not optimize with debugging and vice versa.',-1,None,int),
+	ListVariable('exclude','Yade components that will not be built','none',names=['gui','extra','common','dem','lattice','snow']),
+	EnumVariable('PGO','Whether to "gen"erate or "use" Profile-Guided Optimization','',['','gen','use'],{'no':'','0':'','false':''},1),
+	ListVariable('features','Optional features that are turned on','log4cxx,opengl,gts,openmp,vtk',names=['opengl','log4cxx','cgal','openmp','gts','vtk','python','gl2ps','devirt-functors','qt4','never_use_this_one']),
+	('jobs','Number of jobs to run at the same time (same as -j, but saved)',2,None,int),
+	#('extraModules', 'Extra directories with their own SConscript files (must be in-tree) (whitespace separated)',None,None,Split),
+	('buildPrefix','Where to create build-[version][variant] directory for intermediary files','..'),
+	('hotPlugins','Files (without the .cpp extension) that will be compiled separately even in the monolithic build (use for those that you modify frequently); comma-separated.',''),
+	('chunkSize','Maximum files to compile in one translation unit when building plugins. (unlimited if <= 0, per-file linkage is used if 1)',7,None,int),
+	('version','Yade version (if not specified, guess will be attempted)',None),
+	('realVersion','Revision (usually bzr revision); guessed automatically unless specified',None),
+	('CPPPATH', 'Additional paths for the C preprocessor (colon-separated)','/usr/include/vtk-5.0:/usr/include/vtk-5.2:/usr/include/vtk-5.4:/usr/include/vtk-5.6:/usr/include/eigen2:/usr/include/vtk'), # hardy has vtk-5.0
+	('LIBPATH','Additional paths for the linker (colon-separated)',None),
+	('libstdcxx','Specify libstdc++ location by hand (opened dynamically at startup), usually not needed',None),
+	('QT4CXX','Specify a different compiler for files including qt4; this is necessary for older qt version (<=4.7) which don\'t compile with clang',None),
+	('QT4DIR','Directory where Qt4 is installed','/usr/share/qt4'),
+	('PATH','Path (not imported automatically from the shell) (colon-separated)',None),
+	('CXX','The c++ compiler','g++'),
+	('CXXFLAGS','Additional compiler flags for compilation (like -march=core2).',None,None,Split),
+	('march','Architecture to use with -march=... when optimizing','native',None,None),
+	BoolVariable('mono','[experimental] Build only one shared library and make all other files (python objects, for instance) only be symlinks.',0),
+	('execCheck','Name of the main script that should be installed; if the current one differs, an erro is raised (do not use directly, only intended for --rebuild',None),
+	('defThreads','Default number of OpenMP threads to run with, unless overridden with -j. Keep unset (negative) to default to using all cores.',-1),
+	#('SHLINK','Linker for shared objects','g++'),
+	('SHCCFLAGS','Additional compiler flags for linking (for plugins).',None,None,Split),
+	BoolVariable('QUAD_PRECISION','typedef Real as long double (=quad)',0),
+	BoolVariable('brief',"Don't show commands being run, only what files are being compiled/linked/installed",True),
+)
+opts.Update(env)
+
+if str(env['features'])=='all':
+	print 'ERROR: using "features=all" is illegal, since it breaks feature detection at runtime (SCons limitation). Write out all features separated by commas instead. Sorry.'
+	Exit(1)
+
+if saveProfile: opts.Save(optsFile,env)
+# fix expansion in python substitution by assigning the right value if not specified
+if not env.has_key('runtimePREFIX') or not env['runtimePREFIX']: env['runtimePREFIX']=env['PREFIX']
+# set optimization based on debug, if required
+if env['optimize']<0: env['optimize']=not env['debug']
+
+# handle colon-separated lists:
+for k in ('CPPPATH','LIBPATH','QTDIR','PATH'):
+	if env.has_key(k):
+		env[k]=colonSplit(env[k])
+
+# do not propagate PATH from outside, to ensure identical builds on different machines
+#env.Append(ENV={'PATH':['/usr/local/bin','/bin','/usr/bin']})
+# ccache needs $HOME to be set, also CCACHE_PREFIX if used; colorgcc needs $TERM; distcc wants DISTCC_HOSTS
+# fakeroot needs FAKEROOTKEY and LD_PRELOAD
+propagatedEnvVars=['HOME','TERM','DISTCC_HOSTS','LD_PRELOAD','FAKEROOTKEY','LD_LIBRARY_PATH','CCACHE_PREFIX']
+for v in propagatedEnvVars:
+	if os.environ.has_key(v): env.Append(ENV={v:os.environ[v]})
+if env.has_key('PATH'): env.Append(ENV={'PATH':env['PATH']})
+
+# get number of jobs from DEB_BUILD_OPTIONS if defined
+# see http://www.de.debian.org/doc/debian-policy/ch-source.html#s-debianrules-options
+if os.environ.has_key('DEB_BUILD_OPTIONS'):
+	for opt in os.environ['DEB_BUILD_OPTIONS'].split():
+		if opt.startswith('parallel='):
+			j=opt.split('=')[1].split(',')[0] # there was a case of 5, in hardy...
+			print "Setting number of jobs (using DEB_BUILD_OPTIONS) to `%s'"%j
+			env['jobs']=int(j)
+
+
+
+if sconsVersion>9700: opts.FormatOptionHelpText=lambda env,opt,help,default,actual,alias: "%10s: %5s [%s] (%s)\n"%(opt,actual,default,help)
+else: opts.FormatOptionHelpText=lambda env,opt,help,default,actual: "%10s: %5s [%s] (%s)\n"%(opt,actual,default,help)
+Help(opts.GenerateHelpText(env))
+
+###########################################
+################# BUILD DIRECTORY #########
+###########################################
+import yadeSCons
+## ALL generated stuff should go here - therefore we must determine it very early!!
+if not env.has_key('realVersion') or not env['realVersion']: env['realVersion']=yadeSCons.getRealVersion() or 'unknown' # unknown if nothing returned
+if not env.has_key('version'): env['version']=env['realVersion']
+
+env['SUFFIX']='-'+env['version']+env['variant']
+env['SUFFIX_DBG']=env['SUFFIX']+('' if not env['debug'] else '/dbg')
+env['LIBDIR']='$PREFIX/lib/yade$SUFFIX_DBG'
+print "Yade version is `%s' (%s), installed files will be suffixed with `%s'."%(env['version'],env['realVersion'],env['SUFFIX'])
+buildDir=os.path.abspath(env.subst('$buildPrefix/build$SUFFIX_DBG'))
+print "All intermediary files will be in `%s'."%env.subst(buildDir)
+env['buildDir']=buildDir
+# these MUST be first so that builddir's headers are read before any locally installed ones
+buildInc='$buildDir/include'
+env.Append(CPPPATH=[buildInc])
+
+env.SConsignFile(buildDir+'/scons-signatures')
+
+##########################################################################################
+############# SHORTCUT TARGETS ###########################################################
+##########################################################################################
+
+if len(sys.argv)>1 and ('clean' in sys.argv) or ('tags' in sys.argv) or ('doc' in sys.argv):
+	if 'clean' in sys.argv:
+		if os.path.exists(buildDir):
+			print "Cleaning: %s."%buildDir; shutil.rmtree(buildDir)
+		else: print "Nothing to clean: %s."%buildDir
+		sys.argv.remove('clean')
+	if 'tags' in sys.argv:
+		cmd="ctags -R --extra=+q --fields=+n --exclude='.*' --exclude=attic --exclude=doc --exclude=scons-local --exclude=include --exclude=lib/triangulation --exclude=debian --exclude='*.so' --exclude='*.s' --exclude='*.ii' --langmap=c++:+.inl,c++:+.tpp,c++:+.ipp"
+		print cmd; os.system(cmd)
+		sys.argv.remove('tags')
+	if 'doc' in sys.argv:
+		raise RuntimeError("'doc' argument not supported by scons now")
+	#	cmd="cd doc; doxygen Doxyfile"
+	#	print cmd; os.system(cmd)
+	#	sys.argv.remove('doc')
+	# still something on the command line? Ignore, but warn about that
+	if len(sys.argv)>1: print "!!! WARNING: Shortcuts (clean,tags,doc) cannot be mixed with regular targets or options; ignoring:\n"+''.join(["!!!\t"+a+"\n" for a in sys.argv[1:]])
+	# bail out
+	Exit(0)
+
+
+##########################################################################################
+############# CONFIGURATION ##############################################################
+##########################################################################################
+
+# ensure non-None
+env.Append(CPPPATH='',LIBPATH='',LIBS='',CXXFLAGS='',SHCCFLAGS='')
+
+if 0:
+	def CheckQt(context, qtdirs):
+		"Attempts to localize qt3 installation in given qtdirs. Sets necessary variables if found and returns True; otherwise returns False."
+		# make sure they exist and save them for restoring if a test fails
+		origs={'LIBS':context.env['LIBS'],'LIBPATH':context.env['LIBPATH'],'CPPPATH':context.env['CPPPATH']}
+		qtdirs=qtdirs[0].split()
+		for qtdir in qtdirs:
+			context.Message( 'Checking for qt-mt in '+qtdir+'... ' )
+			context.env['QTDIR']=qtdir
+			context.env.Append(LIBS='qt-mt',LIBPATH=qtdir+'/lib',CPPPATH=qtdir+'/include' )
+			ret=context.TryLink('#include<qapplication.h>\nint main(int argc, char **argv){QApplication qapp(argc, argv);return 0;}\n','.cpp')
+			context.Result(ret)
+			if not ret:
+				for k in origs.keys(): context.env[k]=origs[k]
+			else:
+				return ret
+		return False
+
+
+def CheckCXX(context):
+	context.Message('Checking whether c++ compiler "%s" works...'%env['CXX'])
+	ret=context.TryLink('#include<iostream>\nint main(int argc, char**argv){std::cerr<<std::endl;return 0;}\n','.cpp')
+	context.Result(ret)
+	return ret
+def CheckLibStdCxx(context):
+	context.Message('Finding libstdc++ library... ')
+	if context.env.has_key('libstdcxx') and context.env['libstdcxx']:
+		l=context.env['libstdcxx']
+		context.Result(l+' (specified by the user)')
+		return l
+	ret=os.popen(context.env['CXX']+' -print-file-name=libstdc++.so.6').readlines()[0][:-1]
+	if ret[0]!='/':
+		context.Result('Relative path "%s" was given by compiler %s, must specify libstdcxx=.. explicitly.'%(ret,context.env['CXX']))
+		Exit(1)
+	ret=os.path.abspath(ret) # removes .. in the path returned by g++
+	context.env['libstdcxx']=ret
+	context.Result(ret)
+	return ret
+
+def CheckPython(context):
+	"Checks for functional python/c API. Sets variables if OK and returns true; otherwise returns false."
+	origs={'LIBS':context.env['LIBS'],'LIBPATH':context.env['LIBPATH'],'CPPPATH':context.env['CPPPATH'],'LINKFLAGS':context.env['LINKFLAGS']}
+	context.Message('Checking for Python development files... ')
+	try:
+		#FIXME: once caught, exception disappears along with the actual message of what happened...
+		import distutils.sysconfig as ds
+		context.env.Append(CPPPATH=ds.get_python_inc(),LIBS=ds.get_config_var('LIBS').split() if ds.get_config_var('LIBS') else None)
+		context.env.Append(LINKFLAGS=ds.get_config_var('LINKFORSHARED').split()+ds.get_config_var('BLDLIBRARY').split())
+		ret=context.TryLink('#include<Python.h>\nint main(int argc, char **argv){Py_Initialize(); Py_Finalize();}\n','.cpp')
+		if not ret: raise RuntimeError
+	except (ImportError,RuntimeError,ds.DistutilsPlatformError):
+		for k in origs.keys(): context.env[k]=origs[k]
+		context.Result('error')
+		return False
+	context.Result('ok'); return True
+
+def CheckBoost(context):
+	context.Message('Checking boost libraries... ')
+	libs=[
+		('boost_system','boost/system/error_code.hpp','boost::system::error_code();',False),
+		('boost_thread','boost/thread/thread.hpp','boost::thread();',True),
+		('boost_date_time','boost/date_time/posix_time/posix_time.hpp','boost::posix_time::time_duration();',True),
+		('boost_filesystem','boost/filesystem/path.hpp','boost::filesystem::path();',True),
+		('boost_iostreams','boost/iostreams/device/file.hpp','boost::iostreams::file_sink("");',True),
+		('boost_regex','boost/regex.hpp','boost::regex("");',True),
+		('boost_serialization','boost/archive/archive_exception.hpp','try{} catch (const boost::archive::archive_exception& e) {};',True),
+		('boost_program_options','boost/program_options.hpp','boost::program_options::options_description o;',True),
+		('boost_python','boost/python.hpp','boost::python::scope();',True),
+	]
+	failed=[]
+	def checkLib_maybeMT(lib,header,func):
+		for LIB in (lib,lib+'-mt'):
+			LIBS=env['LIBS'][:]; context.env.Append(LIBS=[LIB])
+			if context.TryLink('#include<'+header+'>\nint main(void){'+func+';}','.cpp'): return True
+			env['LIBS']=LIBS
+		return False
+	for lib,header,func,mandatory in libs:
+		ok=checkLib_maybeMT(lib,header,func)
+		if not ok and mandatory: failed.append(lib)
+	if failed: context.Result('Failures: '+', '.join(failed)); return False
+	context.Result('all ok'); return True
+
+def CheckPythonModules(context):
+	context.Message("Checking for required python modules... ")
+	mods=[('IPython','ipython'),('numpy','python-numpy'),('matplotlib','python-matplotlib'),('Xlib','python-xlib')]
+	if 'qt4' in context.env['features']: mods.append(('PyQt4.QtGui','python-qt4'))
+	failed=[]
+	for m,pkg in mods:
+		try:
+			exec("import %s"%m)
+		except ImportError:
+			failed.append(m+' (package %s)'%pkg)
+	if failed: context.Result('Failures: '+', '.join(failed)); return False
+	context.Result('all ok'); return True
+
+	
+
+if not env.GetOption('clean'):
+	conf=env.Configure(custom_tests={'CheckLibStdCxx':CheckLibStdCxx,'CheckCXX':CheckCXX,'CheckBoost':CheckBoost,'CheckPython':CheckPython,'CheckPythonModules':CheckPythonModules}, # 'CheckQt':CheckQt
+		conf_dir='$buildDir/.sconf_temp',log_file='$buildDir/config.log'
+	)
+	ok=True
+	ok&=conf.CheckCXX()
+	if not ok:
+			print "\nYour compiler is broken, no point in continuing. See `%s' for what went wrong and use the CXX/CXXFLAGS parameters to change your compiler."%(buildDir+'/config.log')
+			Exit(1)
+	conf.CheckLibStdCxx()
+	ok&=conf.CheckLibWithHeader('pthread','pthread.h','c','pthread_exit(NULL);',autoadd=1)
+	ok&=(conf.CheckPython() and conf.CheckCXXHeader(['Python.h','numpy/ndarrayobject.h'],'<>'))
+	ok&=conf.CheckPythonModules()
+	ok&=conf.CheckBoost()
+	env['haveForeach']=conf.CheckCXXHeader('boost/foreach.hpp','<>')
+	if not env['haveForeach']: print "(OK, local version will be used instead)"
+	ok&=conf.CheckCXXHeader('Eigen/Core')
+	ok&=conf.CheckCXXHeader('loki/NullType.h')
+	# for installable stript's shebang ( http://en.wikipedia.org/wiki/Shebang_(Unix) )
+	env['pyExecutable']=sys.executable
+
+	if not ok:
+		print "\nOne of the essential libraries above was not found, unable to continue.\n\nCheck `%s' for possible causes, note that there are options that you may need to customize:\n\n"%(buildDir+'/config.log')+opts.GenerateHelpText(env)
+		Exit(1)
+	def featureNotOK(featureName,note=None):
+		print "\nERROR: Unable to compile with optional feature `%s'.\n\nIf you are sure, remove it from features (scons features=featureOne,featureTwo for example) and build again."%featureName
+		if note: print "Note:",note
+		Exit(1)
+	# check "optional" libs
+	if 'opengl' in env['features']:
+		ok=conf.CheckLibWithHeader('glut','GL/glut.h','c++','glutGetModifiers();',autoadd=1)
+		# TODO ok=True for darwin platform where openGL (and glut) is native
+		if not ok: featureNotOK('opengl')
+		if 'qt4' in env['features']:
+			env['ENV']['PKG_CONFIG_PATH']='/usr/bin/pkg-config'
+			env.Tool('qt4')
+			env.EnableQt4Modules(['QtGui','QtCore','QtXml','QtOpenGL'])
+			if not conf.TryAction(env.Action('pyrcc4'),'','qrc'): featureNotOK('qt4','The pyrcc4 program is not operational (package pyqt4-dev-tools)')
+			if not conf.TryAction(env.Action('pyuic4'),'','ui'): featureNotOK('qt4','The pyuic4 program is not operational (package pyqt4-dev-tools)')
+			if conf.CheckLibWithHeader(['qglviewer-qt4'],'QGLViewer/qglviewer.h','c++','QGLViewer();',autoadd=1):
+				env['QGLVIEWER_LIB']='qglviewer-qt4'
+			elif conf.CheckLibWithHeader(['libQGLViewer'],'QGLViewer/qglviewer.h','c++','QGLViewer();',autoadd=1):
+				env['QGLVIEWER_LIB']='libQGLViewer'
+			else: featureNotOK('qt4','Building with Qt4 implies the QGLViewer library installed (package libqglviewer-qt4-dev package in debian/ubuntu, libQGLViewer in RPM-based distributions)')
+	if 'vtk' in env['features']:
+		ok=conf.CheckLibWithHeader(['vtkCommon'],'vtkInstantiator.h','c++','vtkInstantiator::New();',autoadd=1)
+		env.Append(LIBS=['vtkHybrid','vtkFiltering','vtkRendering','vtkIO','vtkexoIIc','vtkParallel','vtkGraphics','vtkverdict','vtkImaging','vtkftgl','vtkDICOMParser','vtkmetaio','vtksqlite'])
+		if not ok: featureNotOK('vtk',note="Installer can`t find vtk-library. Be sure you have it installed (usually, libvtk5-dev package). Or you might have to add VTK header directory (e.g. /usr/include/vtk-5.4) to CPPPATH.")
+	if 'gts' in env['features']:
+		env.ParseConfig('pkg-config gts --cflags --libs');
+		ok=conf.CheckLibWithHeader('gts','gts.h','c++','gts_object_class();',autoadd=1)
+		env.Append(CPPDEFINES='PYGTS_HAS_NUMPY')
+		if not ok: featureNotOK('gts')
+	if 'log4cxx' in env['features']:
+		ok=conf.CheckLibWithHeader('log4cxx','log4cxx/logger.h','c++','log4cxx::Logger::getLogger("");',autoadd=1)
+		if not ok: featureNotOK('log4cxx')
+	if 'gl2ps' in env['features']:
+		ok=conf.CheckLibWithHeader('gl2ps','gl2ps.h','c','gl2psEndPage();',autoadd=1)
+		if not ok: featureNotOK('gl2ps')
+	if 'cgal' in env['features']:
+		ok=conf.CheckLibWithHeader('CGAL','CGAL/Exact_predicates_inexact_constructions_kernel.h','c++','CGAL::Exact_predicates_inexact_constructions_kernel::Point_3();')
+		env.Append(CXXFLAGS='-frounding-math') # required by cgal, otherwise we get assertion failure at startup
+		if not ok: featureNotOK('cgal')
+	if not env['mono']: env.Append(LIBS='yade-support')
+
+	env.Append(CPPDEFINES=['YADE_'+f.upper().replace('-','_') for f in env['features']])
+
+	env=conf.Finish()
+
+	if os.path.exists('../brefcom-mm.hh'):
+		print "Will use full CPM model in ../brefcom-mm.hh"
+		env.Append(CPPDEFINES='YADE_CPM_FULL_MODEL_AVAILABLE')
+
+##########################################################################################
+############# BUILDING ###################################################################
+##########################################################################################
+
+### SCONS OPTIMIZATIONS
+SCons.Defaults.DefaultEnvironment(tools = [])
+env.Decider('MD5-timestamp')
+env.SetOption('max_drift',5) # cache md5sums of files older than 5 seconds
+SetOption('implicit_cache',0) # cache #include files etc.
+env.SourceCode(".",None) # skip dotted directories
+SetOption('num_jobs',env['jobs'])
+
+### SHOWING OUTPUT
+if env['brief']:
+	## http://www.scons.org/wiki/HidingCommandLinesInOutput
+	env.Replace(CXXCOMSTR='C ${SOURCES}', # → ${TARGET.file}')
+		CCOMSTR='C ${SOURCES}',
+		SHCXXCOMSTR='C ${SOURCES}', 
+		SHCCCOMSTR='C ${SOURCES}', 
+		SHLINKCOMSTR='L ${TARGET.file}',
+		LINKCOMSTR='L ${TARGET.file}',
+		INSTALLSTR='> $TARGET',
+		QT_UICCOMSTR='U ${SOURCES}',
+		QT_MOCCOMSTR='M ${SOURCES}',
+		QT4_UICCOMSTR='U ${SOURCES}',
+		QT_MOCFROMHCOMSTR='M ${SOURCES}',
+		QT_MOCFROMCXXCOMSTR='M ${SOURCES}',
+		)
+else:
+	env.Replace(INSTALLSTR='cp -f ${SOURCE} ${TARGET}')
+
+### DIRECTORIES
+## PREFIX must be absolute path. Why?!
+env['PREFIX']=os.path.abspath(env['PREFIX'])
+
+libDirs=('extra','gui','lib','py','plugins')
+# where are we going to be installed... pkg/dem becomes pkg-dem
+instLibDirs=[os.path.join('$LIBDIR',x) for x in libDirs]
+## runtime library search directories; there can be up to 2 levels of libs, so we do in in quite a crude way here:
+## FIXME: use syntax as shown here: http://www.scons.org/wiki/UsingOrigin
+relLibDirs=['../'+x for x in libDirs]+['../../'+x for x in libDirs]+[env.subst('../lib/yade$SUFFIX_DBG/lib')]
+runtimeLibDirs=[env.Literal('\\$$ORIGIN/'+x) for x in relLibDirs]
+
+### PREPROCESSOR FLAGS
+if env['QUAD_PRECISION']: env.Append(CPPDEFINES='QUAD_PRECISION')
+
+### COMPILER
+if env['debug']: env.Append(CXXFLAGS='-ggdb2',CPPDEFINES=['YADE_DEBUG'])
+if 'openmp' in env['features']: env.Append(CXXFLAGS='-fopenmp',LIBS='gomp',CPPDEFINES='YADE_OPENMP')
+if env['optimize']:
+	# NDEBUG is used in /usr/include/assert.h: when defined, asserts() are no-ops
+	env.Append(CXXFLAGS=['-O3'],CPPDEFINES=[('YADE_CAST','static_cast'),('YADE_PTR_CAST','static_pointer_cast'),'NDEBUG'])
+	# do not state architecture if not provided
+	# used for debian packages, where 'native' would generate instructions outside the package architecture
+	# (such as SSE instructions on i386 builds, if the builder supports them)
+	if env.has_key('march') and env['march']: env.Append(CXXFLAGS=['-march=%s'%env['march']]),
+else:
+	env.Append(CPPDEFINES=[('YADE_CAST','dynamic_cast'),('YADE_PTR_CAST','dynamic_pointer_cast')])
+
+if env['gprof']: env.Append(CXXFLAGS=['-pg'],LINKFLAGS=['-pg'],SHLINKFLAGS=['-pg'])
+env.Prepend(CXXFLAGS=['-pipe','-Wall'])
+
+if env['PGO']=='gen': env.Append(CXXFLAGS=['-fprofile-generate'],LINKFLAGS=['-fprofile-generate'])
+if env['PGO']=='use': env.Append(CXXFLAGS=['-fprofile-use'],LINKFLAGS=['-fprofile-use'])
+
+if 'clang' in env['CXX']:
+	print 'Looks like we use clang, adding some flags to avoid warning flood.'
+	env.Append(CXXFLAGS=['-Wno-unused-variable','-Wno-mismatched-tags','-Wno-constant-logical-operand','-Qunused-arguments','-Wno-empty-body'])
+	if 'openmp' in env['features']: print 'WARNING: building with clang and OpenMP feature, expect compilation errors!'
+	if env['march']: print 'WARNING: specifying march with clang\'s might lead to crash at startup (if so, recompile with march= )!'
+
+
+### LINKER
+## libs for all plugins
+if not env['mono']:
+	env.Append(LIBS=[],SHLINKFLAGS=['-rdynamic'])
+	env.Append(LINKFLAGS=['-rdynamic','-Wl,-z,origin'])
+
+if not env['debug']: env.Append(SHLINKFLAGS=['-W,--strip-all'])
+
+# makes dynamic library loading easier (no LD_LIBRARY_PATH) and perhaps faster
+env.Append(RPATH=runtimeLibDirs)
+# find already compiled but not yet installed libraries for linking
+env.Append(LIBPATH=instLibDirs) # this is if we link to libs that are installed, which is the case now
+
+
+def relpath(pf,pt):
+	"""Returns relative path from pf (path from) to pt (path to) as string.
+	Last component of pf MUST be filename, not directory name. It can be empty, though. Legal pf's: 'dir1/dir2/something.cc', 'dir1/dir2/'. Illegal: 'dir1/dir2'."""
+	from os.path import sep,join,abspath,split
+	apfl=abspath(split(pf)[0]).split(sep); aptl=abspath(pt).split(sep); i=0
+	while apfl[i]==aptl[i] and i<min(len(apfl),len(aptl))-1: i+=1
+	return sep.join(['..' for j in range(0,len(apfl)-i)]+aptl[i:])
+
+# 1. symlink all headers to buildDir/include before the actual build
+# 2. (unused now) instruct scons to install (not symlink) all headers to the right place as well
+# 3. set the "install" target as default (if scons is called without any arguments), which triggers build in turn
+# Should be cleaned up.
+
+if not env.GetOption('clean'):
+	# how to make that executed automatically??! For now, run always.
+	#env.AddPreAction(installAlias,installHeaders)
+	from os.path import join,split,isabs,isdir,exists,lexists,islink,isfile,sep
+	#installHeaders() # install to buildDir always
+	#if 0: # do not install headers
+	#	installHeaders(env.subst('$PREFIX')) # install to $PREFIX if specifically requested: like "scons /usr/local/include"
+
+	yadeInc=join(buildDir,'include/yade')
+	if not os.path.exists(yadeInc): os.makedirs(yadeInc)
+	import glob
+	for p in ['core','extra']+glob.glob('lib/*')+glob.glob('pkg/*')+glob.glob('gui'):
+		link=yadeInc+'/'+p.replace('/','-')
+		if os.path.isdir(p) and not os.path.exists(link):
+			if lexists(link): os.remove(link) # dangling symlink
+			os.symlink(relpath(link,p),link)
+	boostDir=buildDir+'/include/boost'
+	if not exists(boostDir): os.makedirs(boostDir)
+	def mkSymlink(link,target):
+		if not exists(link):
+			if lexists(link): os.remove(link) # remove dangling symlink
+			os.symlink(relpath(link,target),link)
+	if not env['haveForeach']:
+		mkSymlink(boostDir+'/foreach.hpp','extra/foreach.hpp_local')
+	#mkSymlink(boostDir+'/python','py/3rd-party/boost-python-indexing-suite-v2-noSymlinkHeaders')
+	mkSymlink(buildDir+'/include/indexing_suite','py/3rd-party/boost-python-indexing-suite-v2-noSymlinkHeaders')
+	mkSymlink(boostDir+'/math','extra/floating_point_utilities_v3/boost/math')
+	env.Default(env.Alias('install',['$PREFIX/bin','$PREFIX/lib'])) # build and install everything that should go to instDirs, which are $PREFIX/{bin,lib} (uses scons' Install)
+
+env.Export('env');
+
+######
+### combining builder
+#####
+# since paths are aboslute, sometime they are not picked up
+# hack it away by writing the combined files into a text file
+# and when it changes, force rebuild of all combined files
+# changes to $buildDir/combined-files are cheked at the end of 
+# the SConscript file
+import md5
+combinedFiles=env.subst('$buildDir/combined-files')
+
+if os.path.exists(combinedFiles):
+	combinedFilesMd5=md5.md5(file(combinedFiles).read()).hexdigest()
+	os.remove(combinedFiles)
+else:
+	combinedFilesMd5=None
+
+# http://www.scons.org/wiki/CombineBuilder
+import SCons.Action
+import SCons.Builder
+def combiner_build(target, source, env):
+	"""generate a file, that's including all sources"""
+	out=""
+	for src in source: out+="#include \"%s\"\n"%src.abspath
+	open(str(target[0]),'w').write(out)
+	env.AlwaysBuild(target[0])
+	return 0
+def CombineWrapper(target,source):
+	open(combinedFiles,'a').write(env.subst(target)+': '+' '.join([env.subst(s) for s in source])+'\n')
+	return env.Combine(target,source)
+env.CombineWrapper=CombineWrapper
+	
+env.Append(BUILDERS = {'Combine': env.Builder(action = SCons.Action.Action(combiner_build, "> $TARGET"),target_factory = env.fs.File,)})
+
+import yadeSCons
+allPlugs=yadeSCons.scanAllPlugins(None,feats=env['features'])
+buildPlugs=yadeSCons.getWantedPlugins(allPlugs,env['exclude'],env['features'],env['chunkSize'],env['hotPlugins'].split(','))
+def linkPlugins(plugins):
+	"""Given list of plugins we need to link to, return list of real libraries that we should link to."""
+	ret=set()
+	for p in plugins:
+		if not buildPlugs.has_key(p):
+			raise RuntimeError("Plugin %s is required (backtrace shows where), but will not be built!"%p)
+		ret.add(buildPlugs[p].obj)
+	return ['core','yade-support']+list(ret)
+
+env['linkPlugins']=linkPlugins
+env['buildPlugs']=buildPlugs
+
+if env['mono']:
+	env['topLevelDir']=os.path.abspath(os.getcwd())
+	env.SConscript('SConscript-mono',variant_dir=buildDir,duplicate=0)
+
+else:
+	# read top-level SConscript file. It is used only so that variant_dir is set. This file reads all necessary SConscripts
+	env.SConscript(dirs=['.'],variant_dir=buildDir,duplicate=0)
+
+#################################################################################
+## remove plugins that are in the target dir but will not be installed now
+## only when installing without requesting special path (we would have no way
+## to know what should be installed overall.
+if not COMMAND_LINE_TARGETS:
+	toInstall=set([str(node) for node in env.FindInstalledFiles()])
+	for root,dirs,files in os.walk(env.subst('$LIBDIR')):
+		# do not go inside the debug directly, plugins are different there
+		for f in files:
+			# skip debug files, if in the non-debug build
+			if not env['debug'] and '/dbg/' in root: continue
+			#print 'Considering',f
+			ff=os.path.join(root,f)
+			# do not delete python-optimized files and symbolic links (lib_gts__python-module.so, for instance)
+			if ff not in toInstall and not ff.endswith('.pyo') and not ff.endswith('.pyc') and not os.path.islink(ff) and not os.path.basename(ff).startswith('.nfs'):
+				print "Deleting extra plugin", ff
+				os.remove(ff)
+
+#################################################################################
+#### DOCUMENTATION
+# must be explicitly requested to be installed, e.g.:
+#    scons /usr/local/share/doc
+env.Install('$PREFIX/share/doc/yade$SUFFIX-doc/',['examples','scripts','doc'])
+
+
+### check if combinedFiles is different; if so, force rebuild of all of them
+if os.path.exists(combinedFiles) and combinedFilesMd5!=md5.md5(open(combinedFiles).read()).hexdigest():
+	print 'Rebuilding combined files, since the md5 has changed.'
+	combs=[l.split(':')[0] for l in open(combinedFiles)]
+	for c in combs:
+		env.AlwaysBuild(c)
+		env.Default(c)
+
+#Progress('.', interval=100, file=sys.stderr)

=== added file 'VERSION'
--- VERSION	1970-01-01 00:00:00 +0000
+++ VERSION	2013-11-15 08:22:02 +0000
@@ -0,0 +1,1 @@
+0.60.3

=== added file 'Yade.kdevelop'
--- Yade.kdevelop	1970-01-01 00:00:00 +0000
+++ Yade.kdevelop	2013-11-15 08:22:02 +0000
@@ -0,0 +1,229 @@
+<?xml version = '1.0'?>
+<kdevelop>
+  <general>
+    <author>Vaclav Smilauer</author>
+    <email>eudoxos@xxxxxxxx</email>
+    <version>$VERSION$</version>
+    <projectmanagement>KDevCustomProject</projectmanagement>
+    <primarylanguage>C++</primarylanguage>
+    <ignoreparts/>
+    <projectname>Yade</projectname>
+    <projectdirectory>.</projectdirectory>
+    <absoluteprojectpath>false</absoluteprojectpath>
+    <description></description>
+    <defaultencoding></defaultencoding>
+    <versioncontrol/>
+  </general>
+  <kdevcustomproject>
+    <run>
+      <mainprogram>/usr/bin/python</mainprogram>
+      <directoryradio>executable</directoryradio>
+      <programargs>/home/chia/yade/inst/bin/yade-r2446</programargs>
+      <globaldebugarguments>/home/chia/yade/inst/bin/yade-r2446-dbg</globaldebugarguments>
+      <globalcwd>/tmp</globalcwd>
+      <useglobalprogram>false</useglobalprogram>
+      <terminal>true</terminal>
+      <autocompile>true</autocompile>
+      <autoinstall>true</autoinstall>
+      <autokdesu>false</autokdesu>
+      <envvars/>
+    </run>
+    <build>
+      <buildtool>make</buildtool>
+      <builddir></builddir>
+    </build>
+    <make>
+      <abortonerror>false</abortonerror>
+      <numberofjobs>4</numberofjobs>
+      <prio>0</prio>
+      <dontact>false</dontact>
+      <makebin>scons</makebin>
+      <defaulttarget></defaulttarget>
+      <makeoptions></makeoptions>
+      <selectedenvironment>default</selectedenvironment>
+      <environments>
+        <default>
+          <envvar value="localhost/1 192.168.27.125/2 192.168.27.91/1 192.168.23.204/2 192.168.27.201/2 192.168.27.118/2 194.254.65.169/2" name="DISTCC_HOSTS" />
+        </default>
+      </environments>
+    </make>
+    <filetypes>
+      <filetype>*.java</filetype>
+      <filetype>*.h</filetype>
+      <filetype>*.H</filetype>
+      <filetype>*.hh</filetype>
+      <filetype>*.hxx</filetype>
+      <filetype>*.hpp</filetype>
+      <filetype>*.c</filetype>
+      <filetype>*.C</filetype>
+      <filetype>*.cc</filetype>
+      <filetype>*.cpp</filetype>
+      <filetype>*.c++</filetype>
+      <filetype>*.cxx</filetype>
+      <filetype>Makefile</filetype>
+      <filetype>CMakeLists.txt</filetype>
+    </filetypes>
+    <blacklist/>
+    <other>
+      <prio>0</prio>
+      <otherbin>scons</otherbin>
+      <defaulttarget></defaulttarget>
+      <otheroptions></otheroptions>
+      <selectedenvironment>default</selectedenvironment>
+      <environments>
+        <default/>
+      </environments>
+    </other>
+  </kdevcustomproject>
+  <kdevdebugger>
+    <general>
+      <dbgshell></dbgshell>
+      <gdbpath></gdbpath>
+      <configGdbScript></configGdbScript>
+      <runShellScript></runShellScript>
+      <runGdbScript></runGdbScript>
+      <breakonloadinglibs>true</breakonloadinglibs>
+      <separatetty>false</separatetty>
+      <floatingtoolbar>false</floatingtoolbar>
+      <raiseGDBOnStart>false</raiseGDBOnStart>
+    </general>
+    <display>
+      <staticmembers>true</staticmembers>
+      <demanglenames>true</demanglenames>
+      <outputradix>10</outputradix>
+    </display>
+  </kdevdebugger>
+  <kdevdoctreeview>
+    <ignoretocs>
+      <toc>ada</toc>
+      <toc>ada_bugs_gcc</toc>
+      <toc>bash</toc>
+      <toc>bash_bugs</toc>
+      <toc>clanlib</toc>
+      <toc>fortran_bugs_gcc</toc>
+      <toc>gnome1</toc>
+      <toc>gnustep</toc>
+      <toc>gtk</toc>
+      <toc>gtk_bugs</toc>
+      <toc>haskell</toc>
+      <toc>haskell_bugs_ghc</toc>
+      <toc>java_bugs_gcc</toc>
+      <toc>java_bugs_sun</toc>
+      <toc>kde2book</toc>
+      <toc>opengl</toc>
+      <toc>pascal_bugs_fp</toc>
+      <toc>php</toc>
+      <toc>php_bugs</toc>
+      <toc>perl</toc>
+      <toc>perl_bugs</toc>
+      <toc>python</toc>
+      <toc>python_bugs</toc>
+      <toc>qt-kdev3</toc>
+      <toc>ruby</toc>
+      <toc>ruby_bugs</toc>
+      <toc>sdl</toc>
+      <toc>sw</toc>
+      <toc>w3c-dom-level2-html</toc>
+      <toc>w3c-svg</toc>
+      <toc>w3c-uaag10</toc>
+      <toc>wxwidgets_bugs</toc>
+    </ignoretocs>
+    <ignoreqt_xml>
+      <toc>Guide to the Qt Translation Tools</toc>
+      <toc>Qt Assistant Manual</toc>
+      <toc>Qt Designer Manual</toc>
+      <toc>Qt Reference Documentation</toc>
+      <toc>qmake User Guide</toc>
+    </ignoreqt_xml>
+    <ignoredoxygen>
+      <toc>KDE Libraries (Doxygen)</toc>
+    </ignoredoxygen>
+  </kdevdoctreeview>
+  <kdevfilecreate>
+    <filetypes/>
+    <useglobaltypes>
+      <type ext="ui" />
+      <type ext="cpp" />
+    </useglobaltypes>
+  </kdevfilecreate>
+  <kdevcppsupport>
+    <qt>
+      <used>false</used>
+      <version>3</version>
+      <includestyle>3</includestyle>
+      <root>/usr/share/qt3</root>
+      <designerintegration>EmbeddedKDevDesigner</designerintegration>
+      <qmake>/usr/bin/qmake-qt3</qmake>
+      <designer>/usr/bin/designer</designer>
+      <designerpluginpaths/>
+    </qt>
+    <codecompletion>
+      <automaticCodeCompletion>false</automaticCodeCompletion>
+      <automaticArgumentsHint>true</automaticArgumentsHint>
+      <automaticHeaderCompletion>true</automaticHeaderCompletion>
+      <codeCompletionDelay>250</codeCompletionDelay>
+      <argumentsHintDelay>400</argumentsHintDelay>
+      <headerCompletionDelay>250</headerCompletionDelay>
+      <showOnlyAccessibleItems>false</showOnlyAccessibleItems>
+      <completionBoxItemOrder>0</completionBoxItemOrder>
+      <howEvaluationContextMenu>true</howEvaluationContextMenu>
+      <showCommentWithArgumentHint>true</showCommentWithArgumentHint>
+      <statusBarTypeEvaluation>false</statusBarTypeEvaluation>
+      <namespaceAliases>std=_GLIBCXX_STD;__gnu_cxx=std</namespaceAliases>
+      <processPrimaryTypes>true</processPrimaryTypes>
+      <processFunctionArguments>false</processFunctionArguments>
+      <preProcessAllHeaders>false</preProcessAllHeaders>
+      <parseMissingHeaders>false</parseMissingHeaders>
+      <resolveIncludePaths>true</resolveIncludePaths>
+      <alwaysParseInBackground>true</alwaysParseInBackground>
+      <usePermanentCaching>true</usePermanentCaching>
+      <alwaysIncludeNamespaces>false</alwaysIncludeNamespaces>
+      <includePaths>.;</includePaths>
+      <parseMissingHeadersExperimental>false</parseMissingHeadersExperimental>
+      <resolveIncludePathsUsingMakeExperimental>false</resolveIncludePathsUsingMakeExperimental>
+    </codecompletion>
+    <creategettersetter>
+      <prefixGet></prefixGet>
+      <prefixSet>set</prefixSet>
+      <prefixVariable>m_,_</prefixVariable>
+      <parameterName>theValue</parameterName>
+      <inlineGet>true</inlineGet>
+      <inlineSet>true</inlineSet>
+    </creategettersetter>
+    <splitheadersource>
+      <enabled>false</enabled>
+      <synchronize>true</synchronize>
+      <orientation>Vertical</orientation>
+    </splitheadersource>
+    <references/>
+  </kdevcppsupport>
+  <cppsupportpart>
+    <filetemplates>
+      <interfacesuffix>.hpp</interfacesuffix>
+      <implementationsuffix>.cpp</implementationsuffix>
+    </filetemplates>
+  </cppsupportpart>
+  <kdevdocumentation>
+    <projectdoc>
+      <docsystem></docsystem>
+      <docurl></docurl>
+      <usermanualurl></usermanualurl>
+    </projectdoc>
+  </kdevdocumentation>
+  <kdevfileview>
+    <groups>
+      <hidenonprojectfiles>false</hidenonprojectfiles>
+      <hidenonlocation>false</hidenonlocation>
+    </groups>
+    <tree>
+      <hidepatterns>*.o,*.lo,CVS</hidepatterns>
+      <hidenonprojectfiles>false</hidenonprojectfiles>
+      <showvcsfields>false</showvcsfields>
+    </tree>
+  </kdevfileview>
+  <ctagspart>
+    <customArguments>-R --extra=+q --fields=+n --exclude='.*' --exclude=attic --exclude=doc --exclude=scons-local --exclude=include --exclude=lib/triangulation --exclude=debian --exclude='*.so' --exclude='*.s' --exclude='*.ii' --langmap=c++:+.inl,c++:+.tpp,c++:+.ipp</customArguments>
+    <activeTagsFiles/>
+    <customTagfilePath>/home/chia/yade/src/r2446/tags</customTagfilePath>
+  </ctagspart>
+</kdevelop>

=== added directory 'core'
=== renamed directory 'core' => 'core.moved'
=== added file 'core/Body.cpp'
--- core/Body.cpp	1970-01-01 00:00:00 +0000
+++ core/Body.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,23 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include "Body.hpp"
+
+#include <limits>
+#include "Scene.hpp"
+#include "Omega.hpp"
+
+//! This could be -1 if id_t is re-typedef'ed as `int'
+const Body::id_t Body::ID_NONE=Body::id_t(-1);
+
+const shared_ptr<Body>& Body::byId(Body::id_t _id, Scene* rb){return (*((rb?rb:Omega::instance().getScene().get())->bodies))[_id];}
+const shared_ptr<Body>& Body::byId(Body::id_t _id, shared_ptr<Scene> rb){return (*(rb->bodies))[_id];}
+
+

=== added file 'core/Body.hpp'
--- core/Body.hpp	1970-01-01 00:00:00 +0000
+++ core/Body.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,93 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+#pragma once
+
+#include<iostream>
+#include"Shape.hpp"
+#include"Bound.hpp"
+#include"State.hpp"
+#include"Material.hpp"
+
+#include<yade/lib-base/Math.hpp>
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-multimethods/Indexable.hpp>
+
+class Scene;
+
+class Body: public Serializable{
+	public:
+		typedef int id_t;
+		// bits for Body::flags
+		enum { FLAG_DYNAMIC=1, FLAG_BOUNDED=2, FLAG_ASPHERICAL=4 }; /* add powers of 2 as needed */
+		//! symbolic constant for body that doesn't exist.
+		static const Body::id_t ID_NONE;
+		//! get Body pointer given its id. 
+		static const shared_ptr<Body>& byId(Body::id_t _id,Scene* rb=NULL);
+		static const shared_ptr<Body>& byId(Body::id_t _id,shared_ptr<Scene> rb);
+
+		
+		//! Whether this Body is a Clump.
+		//! @note The following is always true: \code (Body::isClump() XOR Body::isClumpMember() XOR Body::isStandalone()) \endcode
+		bool isClump() const {return clumpId!=ID_NONE && id==clumpId;}
+		//! Whether this Body is member of a Clump.
+		bool isClumpMember() const {return clumpId!=ID_NONE && id!=clumpId;}
+		//! Whether this body is standalone (neither Clump, nor member of a Clump)
+		bool isStandalone() const {return clumpId==ID_NONE;}
+
+		//! Whether this body has all DOFs blocked
+		// inline accessors
+		// logic: http://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit-in-c
+		bool isDynamic() const {return flags & FLAG_DYNAMIC; }
+		void setDynamic(bool d){ if(d) flags|=FLAG_DYNAMIC; else flags&=~(FLAG_DYNAMIC); }
+		bool isBounded() const {return flags & FLAG_BOUNDED; }
+		void setBounded(bool d){ if(d) flags|=FLAG_BOUNDED; else flags&=~(FLAG_BOUNDED); }
+		bool isAspherical() const {return flags & FLAG_ASPHERICAL; }
+		void setAspherical(bool d){ if(d) flags|=FLAG_ASPHERICAL; else flags&=~(FLAG_ASPHERICAL); }
+
+		/*! Hook for clump to update position of members when user-forced reposition and redraw (through GUI) occurs.
+		 * This is useful only in cases when engines that do that in every iteration are not active - i.e. when the simulation is paused.
+		 * (otherwise, GLViewer would depend on Clump and therefore Clump would have to go to core...) */
+		virtual void userForcedDisplacementRedrawHook(){return;}
+
+		Body::id_t getId() const {return id;};
+
+		int getGroupMask() {return groupMask; };
+		bool maskOk(int mask){return (mask==0 || (groupMask&mask));}
+
+		// only BodyContainer can set the id of a body
+		friend class BodyContainer;
+
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Body,Serializable,"A particle, basic element of simulation; interacts with other bodies.",
+		((Body::id_t,id,Body::ID_NONE,Attr::readonly,"Unique id of this body."))
+
+		((int,groupMask,1,,"Bitmask for determining interactions."))
+		((int,flags,FLAG_DYNAMIC|FLAG_BOUNDED,Attr::readonly,"Bits of various body-related flags. *Do not access directly*. In c++, use isDynamic/setDynamic, isBounded/setBounded. In python, use :yref:`Body.dynamic` and :yref:`Body.bounded`."))
+
+		((shared_ptr<Material>,material,,,":yref:`Material` instance associated with this body."))
+		((shared_ptr<State>,state,new State,,"Physical :yref:`state<State>`."))
+		((shared_ptr<Shape>,shape,,,"Geometrical :yref:`Shape`."))
+		((shared_ptr<Bound>,bound,,,":yref:`Bound`, approximating volume for the purposes of collision detection."))
+
+		((int,clumpId,Body::ID_NONE,Attr::readonly,"Id of clump this body makes part of; invalid number if not part of clump; see :yref:`Body::isStandalone`, :yref:`Body::isClump`, :yref:`Body::isClumpMember` properties. \n\n This property is not meant to be modified directly from Python, use :yref:`O.bodies.appendClumped<BodyContainer.appendClumped>` instead.")),
+		/* ctor */,
+		/* py */
+		//
+		.def_readwrite("mat",&Body::material,"Shorthand for :yref:`Body::material`")
+		.add_property("isDynamic",&Body::isDynamic,&Body::setDynamic,"Deprecated synonym for :yref:`Body::dynamic` |ydeprecated|")
+		.add_property("dynamic",&Body::isDynamic,&Body::setDynamic,"Whether this body will be moved by forces. (In c++, use ``Body::isDynamic``/``Body::setDynamic``) :ydefault:`true`")
+		.add_property("bounded",&Body::isBounded,&Body::setBounded,"Whether this body should have :yref:`Body.bound` created. Note that bodies without a :yref:`bound <Body.bound>` do not participate in collision detection. (In c++, use ``Body::isBounded``/``Body::setBounded``) :ydefault:`true`")
+		.add_property("aspherical",&Body::isAspherical,&Body::setAspherical,"Whether this body has different inertia along principal axes; :yref:`NewtonIntegrator` makes use of this flag to call rotation integration routine for aspherical bodies, which is more expensive. :ydefault:`false`")
+		.def_readwrite("mask",&Body::groupMask,"Shorthand for :yref:`Body::groupMask`")
+		.add_property("isStandalone",&Body::isStandalone,"True if this body is neither clump, nor clump member; false otherwise.")
+		.add_property("isClumpMember",&Body::isClumpMember,"True if this body is clump member, false otherwise.")
+		.add_property("isClump",&Body::isClump,"True if this body is clump itself, false otherwise.");
+	);
+};
+REGISTER_SERIALIZABLE(Body);

=== added file 'core/BodyContainer.cpp'
--- core/BodyContainer.cpp	1970-01-01 00:00:00 +0000
+++ core/BodyContainer.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,27 @@
+// 2010 © Václav Šmilauer <eudoxos@xxxxxxxx>
+
+#include<yade/core/BodyContainer.hpp>
+#include<yade/core/Body.hpp>
+
+unsigned int BodyContainer::findFreeId(){
+	unsigned int max=body.size();
+	for(; lowestFree<max; lowestFree++){
+		if(!(bool)body[lowestFree]) return lowestFree;
+	}
+	return body.size();
+}
+
+unsigned int BodyContainer::insert(shared_ptr<Body>& b){
+	Body::id_t newId=findFreeId();
+	return insert(b,newId);
+}
+
+unsigned int BodyContainer::insert(shared_ptr<Body>& b, unsigned int id){
+	assert(id>=0);
+	if((size_t)id>=body.size()) body.resize(id+1);
+	b->id=id;
+	body[id]=b;
+	return id;
+}
+
+BodyContainer::~BodyContainer(){}

=== added file 'core/BodyContainer.hpp'
--- core/BodyContainer.hpp	1970-01-01 00:00:00 +0000
+++ core/BodyContainer.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,53 @@
+// 2004 © Olivier Galizzi <olivier.galizzi@xxxxxxx>
+// 2004 © Janek Kozicki <cosurgi@xxxxxxxxxx>
+// 2010 © Václav Šmilauer <eudoxos@xxxxxxxx>
+
+#pragma once
+
+#include<yade/lib-serialization/Serializable.hpp>
+
+#include<boost/foreach.hpp>
+#ifndef FOREACH
+#  define FOREACH BOOST_FOREACH
+#endif
+
+class Body;
+
+/*
+Container of bodies implemented as flat std::vector. It handles body removal and
+intelligently reallocates free ids for newly added ones.
+
+Any alternative implementation should use the same API.
+*/
+class BodyContainer: public Serializable{
+	private:
+		typedef std::vector<shared_ptr<Body> > ContainerT;
+		std::vector<shared_ptr<Body> > body;
+		unsigned int lowestFree;
+		unsigned int findFreeId();
+	public:
+		typedef ContainerT::iterator iterator;
+		typedef ContainerT::const_iterator const_iterator;
+
+		BodyContainer(): lowestFree(0){}
+		virtual ~BodyContainer();
+		unsigned int insert(shared_ptr<Body>&);
+		unsigned int insert(shared_ptr<Body>& b, unsigned int id);
+	
+		// mimick some STL api
+		void clear(){ body.clear(); lowestFree=0; }
+		iterator begin() { return body.begin(); }
+		iterator end() { return body.end(); }
+		const_iterator begin() const { return body.begin(); }
+		const_iterator end() const { return body.end(); }
+		unsigned int size() const { return body.size(); }
+		shared_ptr<Body>& operator[](unsigned int id){ return body[id];}
+		const shared_ptr<Body>& operator[](unsigned int id) const { return body[id]; }
+
+		bool exists(unsigned int id) const { return (id>=0) && ((size_t)id<body.size()) && ((bool)body[id]); }
+		bool erase(unsigned int id){ if(!exists(id)) return false; lowestFree=min(lowestFree,id); body[id]=shared_ptr<Body>(); return true; }
+
+		REGISTER_CLASS_AND_BASE(BodyContainer,Serializable);
+		REGISTER_ATTRIBUTES(Serializable,(body));
+};
+REGISTER_SERIALIZABLE(BodyContainer);

=== added file 'core/Bound.cpp'
--- core/Bound.cpp	1970-01-01 00:00:00 +0000
+++ core/Bound.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,12 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include "Bound.hpp"
+
+
+

=== added file 'core/Bound.hpp'
--- core/Bound.hpp	1970-01-01 00:00:00 +0000
+++ core/Bound.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,37 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+#pragma once
+
+#include<yade/lib-base/Math.hpp>
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-multimethods/Indexable.hpp>
+#include<yade/core/Dispatcher.hpp>
+
+/*! Interface for approximate body locations in space
+
+	Note: the min and max members refer to shear coordinates, in periodic
+	and sheared space, not cartesian coordinates in the physical space.
+
+*/
+
+class Bound: public Serializable, public Indexable{
+	public:
+	YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(Bound,Serializable,"Object bounding part of space taken by associated body; might be larger, used to optimalize collision detection",
+		((Vector3r,color,Vector3r(1,1,1),,"Color for rendering this object"))
+		((Vector3r,min,Vector3r(NaN,NaN,NaN),(Attr::noSave | Attr::readonly),"Lower corner of box containing this bound (and the :yref:`Body` as well)"))
+		((Vector3r,max,Vector3r(NaN,NaN,NaN),(Attr::noSave | Attr::readonly),"Lower corner of box containing this bound (and the :yref:`Body` as well)"))
+		,
+		/*deprec*/ ((diffuseColor,color,"For consistency with Shape.color")),
+		/* init */,
+		/* ctor*/,
+		/*py*/
+		YADE_PY_TOPINDEXABLE(Bound)
+	);
+	REGISTER_INDEX_COUNTER(Bound);
+};
+REGISTER_SERIALIZABLE(Bound);

=== added file 'core/Cell.cpp'
--- core/Cell.cpp	1970-01-01 00:00:00 +0000
+++ core/Cell.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,49 @@
+
+#include<yade/core/Cell.hpp>
+
+void Cell::integrateAndUpdate(Real dt){
+	//incremental displacement gradient
+	_trsfInc=dt*velGrad;
+	// total transformation; M = (Id+G).M = F.M
+	trsf+=_trsfInc*trsf;
+	// Hsize will contain colums with transformed base vectors FIXME : no need to initialize all the time, even if it doesn't hurt, it doesn't make sense.
+	Hsize=Matrix3r::Zero(); Hsize(0,0)=refSize[0]; Hsize(1,1)=refSize[1]; Hsize(2,2)=refSize[2]; // later with eigen: Hsize=Matrix::Zero(); Hsize.diagonal=refSize;
+	Hsize=trsf*Hsize;
+	// lengths of transformed cell vectors, skew cosines
+	Matrix3r Hnorm; // normalized transformed base vectors
+	for(int i=0; i<3; i++){
+		Vector3r base(Hsize.col(i));
+		_size[i]=base.norm(); base/=_size[i]; //base is normalized now
+		// was: Hnorm.SetColumn(i,base);
+		// with eigen: Hnorm.col(i)=base;
+		// temporarily 2way for compat
+		Hnorm(0,i)=base[0]; Hnorm(1,i)=base[1]; Hnorm(2,i)=base[2];
+	};
+	//cerr<<"Hsize="<<endl<<Hsize(0,0)<<" "<<Hsize(0,1)<<" "<<Hsize(0,2)<<endl<<Hsize(1,0)<<" "<<Hsize(1,1)<<" "<<Hsize(1,2)<<endl<<Hsize(2,0)<<" "<<Hsize(2,1)<<" "<<Hsize(2,2)<<endl;
+	// skew cosines
+	for(int i=0; i<3; i++){
+		int i1=(i+1)%3, i2=(i+2)%3;
+		// sin between axes is cos of skew
+		_cos[i]=(Hnorm.col(i1).cross(Hnorm.col(i2))).squaredNorm();
+	}
+	// pure shear trsf: ones on diagonal
+	_shearTrsf=Hnorm;
+	//cerr<<"shearTrsf="<<endl<<_shearTrsf(0,0)<<" "<<_shearTrsf(0,1)<<" "<<_shearTrsf(0,2)<<endl<<_shearTrsf(1,0)<<" "<<_shearTrsf(1,1)<<" "<<_shearTrsf(1,2)<<endl<<_shearTrsf(2,0)<<" "<<_shearTrsf(2,1)<<" "<<_shearTrsf(2,2)<<endl;
+	// pure unshear transformation
+	_unshearTrsf=_shearTrsf.inverse();
+	// some parts can branch depending on presence/absence of shear
+	_hasShear=(trsf(0,1)!=0 || trsf(0,2)!=0 || trsf(1,0)!=0 || trsf(1,2)!=0 || trsf(2,0)!=0 || trsf(2,1)!=0);
+	// OpenGL shear matrix (used frequently)
+	fillGlShearTrsfMatrix(_glShearTrsfMatrix);
+
+	if(!(homoDeform==HOMO_NONE || homoDeform==HOMO_POS || homoDeform==HOMO_VEL || homoDeform==HOMO_VEL_2ND)) throw std::invalid_argument("Cell.homoDeform must be in {0,1,2,3}.");
+}
+
+void Cell::fillGlShearTrsfMatrix(double m[16]){
+	m[0]=_shearTrsf(0,0); m[4]=_shearTrsf(0,1); m[8]=_shearTrsf(0,2); m[12]=0;
+	m[1]=_shearTrsf(1,0); m[5]=_shearTrsf(1,1); m[9]=_shearTrsf(1,2); m[13]=0;
+	m[2]=_shearTrsf(2,0); m[6]=_shearTrsf(2,1); m[10]=_shearTrsf(2,2);m[14]=0;
+	m[3]=0;               m[7]=0;               m[11]=0;              m[15]=1;
+}
+
+

=== added file 'core/Cell.hpp'
--- core/Cell.hpp	1970-01-01 00:00:00 +0000
+++ core/Cell.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,129 @@
+// 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
+
+/*! Periodic cell parameters and routines. Usually instantiated as Scene::cell.
+
+The Cell has reference box configuration (*refSize*) which is transformed (using *trsf*) to the current parallelepiped configuration. Using notation from http://en.wikipedia.org/wiki/Finite_strain_theory:
+
+* Vector3r *refSize* is undeformed cell size (box)
+* Matrix3r *trsf* is "deformation gradient tensor" F (written as matrix) 
+* Matrix3r *velGrad* is …
+
+The transformation has normal part and rotation/shear part. the shearPt, unshearPt, getShearTrsf etc functions refer to both shear and rotation.
+
+*/
+
+#pragma once
+
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-base/Math.hpp>
+
+class Cell: public Serializable{
+	public:
+	//! Get current size (refSize × normal strain)
+	const Vector3r& getSize() const { return _size; }
+	//! Return copy of the current size (used only by the python wrapper)
+	Vector3r getSize_copy() const { return _size; }
+	//! return vector of consines of skew angle in yz, xz, xy planes between respective transformed base vectors
+	const Vector3r& getCos() const {return _cos;}
+	//! transformation matrix applying pure shear&rotation (scaling removed)
+	const Matrix3r& getShearTrsf() const { return _shearTrsf; }
+	//! inverse of getShearTrsfMatrix().
+	const Matrix3r& getUnshearTrsf() const {return _unshearTrsf;}
+	//! transformation increment matrix applying arbitrary field (remove if not used in NewtonIntegrator!)
+	// const Matrix3r& getTrsfInc() const { return _trsfInc; }
+	
+	/*! return pointer to column-major OpenGL 4x4 matrix applying pure shear. This matrix is suitable as argument for glMultMatrixd.
+
+	Note: the order of OpenGL transoformations matters; for instance, if you draw sheared wire box of size *size*,
+	centered at *center*, the order is:
+
+		1. translation: glTranslatev(center);
+		3. shearing: glMultMatrixd(scene->cell->getGlShearTrsfMatrix());
+		2. scaling: glScalev(size);
+		4. draw: glutWireCube(1);
+	
+	See also http://www.songho.ca/opengl/gl_transform.html#matrix .
+	*/
+	const double* getGlShearTrsfMatrix() const { return _glShearTrsfMatrix; }
+	//! Whether any shear (non-diagonal) component of the strain matrix is nonzero.
+	bool hasShear() const {return _hasShear; }
+
+	// caches; private
+	private:
+		Matrix3r _trsfInc;
+		Vector3r _size, _cos;
+		bool _hasShear;
+		Matrix3r _shearTrsf, _unshearTrsf;
+		double _glShearTrsfMatrix[16];
+		void fillGlShearTrsfMatrix(double m[16]);
+	public:
+
+	//! "integrate" velGrad, update cached values used by public getter
+	void integrateAndUpdate(Real dt);
+	/*! Return point inside periodic cell, even if shear is applied */
+	Vector3r wrapShearedPt(const Vector3r& pt) const { return shearPt(wrapPt(unshearPt(pt))); }
+	/*! Return point inside periodic cell, even if shear is applied; store cell coordinates in period. */
+	Vector3r wrapShearedPt(const Vector3r& pt, Vector3i& period) const { return shearPt(wrapPt(unshearPt(pt),period)); }
+	/*! Apply inverse shear on point; to put it inside (unsheared) periodic cell, apply wrapPt on the returned value. */
+	Vector3r unshearPt(const Vector3r& pt) const { return _unshearTrsf*pt; }
+	//! Apply shear on point. 
+	Vector3r shearPt(const Vector3r& pt) const { return _shearTrsf*pt; }
+	/*! Wrap point to inside the periodic cell; don't compute number of periods wrapped */
+	Vector3r wrapPt(const Vector3r& pt) const {
+		Vector3r ret; for(int i=0;i<3;i++) ret[i]=wrapNum(pt[i],_size[i]); return ret;
+	}
+	/*! Wrap point to inside the periodic cell; period will contain by how many cells it was wrapped. */
+	Vector3r wrapPt(const Vector3r& pt, Vector3i& period) const {
+		Vector3r ret; for(int i=0; i<3; i++){ ret[i]=wrapNum(pt[i],_size[i],period[i]); } return ret;
+	}
+	/*! Wrap number to interval 0…sz */
+	static Real wrapNum(const Real& x, const Real& sz) {
+		Real norm=x/sz; return (norm-floor(norm))*sz;
+	}
+	/*! Wrap number to interval 0…sz; store how many intervals were wrapped in period */
+	static Real wrapNum(const Real& x, const Real& sz, int& period) {
+		Real norm=x/sz; period=(int)floor(norm); return (norm-period)*sz;
+	}
+
+	// relative position and velocity for interaction accross multiple cells
+	Vector3r intrShiftPos(const Vector3i& cellDist) const { return Hsize*cellDist.cast<Real>(); }
+	Vector3r intrShiftVel(const Vector3i& cellDist) const { if(homoDeform==HOMO_VEL || homoDeform==HOMO_VEL_2ND) return velGrad*Hsize*cellDist.cast<Real>(); return Vector3r::Zero(); }
+	// return body velocity while taking away mean field velocity (coming from velGrad) if the mean field velocity is applied on velocity
+	Vector3r bodyFluctuationVel(const Vector3r& pos, const Vector3r& vel) const { if(homoDeform==HOMO_VEL || homoDeform==HOMO_VEL_2ND) return (vel-velGrad*pos); return vel; }
+
+	Vector3r getRefSize() const { return refSize; }
+	void setRefSize(const Vector3r& s){ refSize=s; integrateAndUpdate(0); }
+	Matrix3r getTrsf() const { return trsf; }
+	void setTrsf(const Matrix3r& m){ trsf=m; integrateAndUpdate(0); }
+	// return current cell volume
+	Real getVolume() const { return Hsize.determinant(); }
+
+	void postLoad(Cell&){ integrateAndUpdate(0); }
+
+	// to resolve overloads
+	Vector3r wrapShearedPt_py(const Vector3r& pt) const { return wrapShearedPt(pt);}
+	Vector3r wrapPt_py(const Vector3r& pt) const { return wrapPt(pt);}
+
+	enum { HOMO_NONE=0, HOMO_POS=1, HOMO_VEL=2, HOMO_VEL_2ND=3 };
+	
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Cell,Serializable,"Parameters of periodic boundary conditions. Only applies if O.isPeriodic==True.",
+		((Vector3r,refSize,Vector3r(1,1,1),Attr::triggerPostLoad,"Reference size of the cell."))
+		((Matrix3r,trsf,Matrix3r::Identity(),Attr::triggerPostLoad,"Current transformation matrix of the cell."))
+		((Matrix3r,velGrad,Matrix3r::Zero(),,"Velocity gradient of the transformation; used in NewtonIntegrator."))
+		((Matrix3r,prevVelGrad,Matrix3r::Zero(),Attr::readonly,"Velocity gradient in the previous step."))
+		((Matrix3r,Hsize,Matrix3r::Zero(),Attr::readonly,"The current cell size (one column per box edge), computed from *refSize* and *trsf* |yupdate|"))
+		((int,homoDeform,3,Attr::triggerPostLoad,"Deform (:yref:`velGrad<Cell.velGrad>`) the cell homothetically, by adjusting positions or velocities of particles. The values have the following meaning: 0: no homothetic deformation, 1: set absolute particle positions directly (when ``velGrad`` is non-zero), but without changing their velocity, 2: adjust particle velocity (only when ``velGrad`` changed) with Δv_i=Δ ∇v x_i. 3: as 2, but include a 2nd order term in addition -- the derivative of 1 (convective term in the velocity update).")),
+		/*ctor*/ integrateAndUpdate(0),
+		/*py*/
+		.def_readonly("size",&Cell::getSize_copy,"Current size of the cell, i.e. lengths of 3 cell lateral vectors after applying current trsf. Update automatically at every step.")
+		.add_property("volume",&Cell::getVolume,"Current volume of the cell.")
+		// debugging only
+		.def("wrap",&Cell::wrapShearedPt_py,"Transform an arbitrary point into a point in the reference cell")
+		.def("unshearPt",&Cell::unshearPt,"Apply inverse shear on the point (removes skew+rot of the cell)")
+		.def("shearPt",&Cell::shearPt,"Apply shear (cell skew+rot) on the point")
+		.def("wrapPt",&Cell::wrapPt_py,"Wrap point inside the reference cell, assuming the cell has no skew+rot.")
+		.def_readonly("shearTrsf",&Cell::_shearTrsf,"Current skew+rot transformation (no resize)")
+		.def_readonly("unshearTrsf",&Cell::_shearTrsf,"Inverse of the current skew+rot transformation (no resize)")
+	);
+};
+REGISTER_SERIALIZABLE(Cell);

=== added file 'core/Dispatcher.cpp'
--- core/Dispatcher.cpp	1970-01-01 00:00:00 +0000
+++ core/Dispatcher.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,18 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+
+#include<yade/core/Functor.hpp>
+Functor::~Functor(){}; // vtable
+
+#include "Dispatcher.hpp"
+#include<algorithm>
+#include<vector>
+
+
+Dispatcher::~Dispatcher(){}

=== added file 'core/Dispatcher.hpp'
--- core/Dispatcher.hpp	1970-01-01 00:00:00 +0000
+++ core/Dispatcher.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,230 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include<boost/lexical_cast.hpp>
+
+#include<yade/core/Engine.hpp>
+#include<yade/core/Functor.hpp>
+#include<yade/core/Omega.hpp>
+#include<yade/lib-multimethods/DynLibDispatcher.hpp>
+
+#include<boost/preprocessor/cat.hpp>
+
+// real base class for all dispatchers (the other one are templates)
+class Dispatcher: public Engine{
+	public:
+	// these functions look to be completely unused...?
+	virtual string getFunctorType() { throw; };
+	virtual int getDimension() { throw; };
+	virtual string getBaseClassType(unsigned int ) { throw; };
+	//
+	virtual ~Dispatcher();
+	YADE_CLASS_BASE_DOC(Dispatcher,Engine,"Engine dispatching control to its associated functors, based on types of argument it receives. This abstract base class provides no functionality in itself.")
+};
+REGISTER_SERIALIZABLE(Dispatcher);
+
+/* Each real dispatcher derives from Dispatcher1D or Dispatcher2D (both templates), which in turn derive from Dispatcher (an Engine) and DynLibDispatcher (the dispatch logic).
+Because we need literal functor and class names for registration in python, we provide macro that creates the real dispatcher class with everything needed.
+*/
+
+#define _YADE_DISPATCHER1D_FUNCTOR_ADD(FunctorT,f) virtual void addFunctor(shared_ptr<FunctorT> f){ add1DEntry(f->get1DFunctorType1(),f); }
+#define _YADE_DISPATCHER2D_FUNCTOR_ADD(FunctorT,f) virtual void addFunctor(shared_ptr<FunctorT> f){ add2DEntry(f->get2DFunctorType1(),f->get2DFunctorType2(),f); }
+
+#define _YADE_DIM_DISPATCHER_FUNCTOR_DOC_ATTRS_CTOR_PY(Dim,DispatcherT,FunctorT,doc,attrs,ctor,py) \
+	typedef FunctorT FunctorType; \
+	void updateScenePtr(){ FOREACH(shared_ptr<FunctorT> f, functors){ f->scene=scene; }} \
+	void postLoad(DispatcherT&){ clearMatrix(); FOREACH(shared_ptr<FunctorT> f, functors) add(static_pointer_cast<FunctorT>(f)); } \
+	virtual void add(FunctorT* f){ add(shared_ptr<FunctorT>(f)); } \
+	virtual void add(shared_ptr<FunctorT> f){ bool dupe=false; string fn=f->getClassName(); FOREACH(const shared_ptr<FunctorT>& f, functors) { if(fn==f->getClassName()) dupe=true; } if(!dupe) functors.push_back(f); addFunctor(f); } \
+	BOOST_PP_CAT(_YADE_DISPATCHER,BOOST_PP_CAT(Dim,D_FUNCTOR_ADD))(FunctorT,f) \
+	boost::python::list functors_get(void) const { boost::python::list ret; FOREACH(const shared_ptr<FunctorT>& f, functors){ ret.append(f); } return ret; } \
+	void functors_set(const vector<shared_ptr<FunctorT> >& ff){ functors.clear(); FOREACH(const shared_ptr<FunctorT>& f, ff) add(f); postLoad(*this); } \
+	void pyHandleCustomCtorArgs(python::tuple& t, python::dict& d){ if(python::len(t)==0)return; if(python::len(t)!=1) throw invalid_argument("Exactly one list of " BOOST_PP_STRINGIZE(FunctorT) " must be given."); typedef std::vector<shared_ptr<FunctorT> > vecF; vecF vf=boost::python::extract<vecF>(t[0])(); functors_set(vf); t=python::tuple(); } \
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(DispatcherT,Dispatcher,"Dispatcher calling :yref:`functors<" BOOST_PP_STRINGIZE(FunctorT) ">` based on received argument type(s).\n\n" doc, \
+		((vector<shared_ptr<FunctorT> >,functors,,,"Functors active in the dispatch mechanism [overridden below].")) /*additional attrs*/ attrs, \
+		/*ctor*/ ctor, /*py*/ py .add_property("functors",&DispatcherT::functors_get,&DispatcherT::functors_set,"Functors associated with this dispatcher." " :yattrtype:`vector<shared_ptr<" BOOST_PP_STRINGIZE(FunctorT) "> >` ") \
+		.def("dispMatrix",&DispatcherT::dump,python::arg("names")=true,"Return dictionary with contents of the dispatch matrix.").def("dispFunctor",&DispatcherT::getFunctor,"Return functor that would be dispatched for given argument(s); None if no dispatch; ambiguous dispatch throws."); \
+	)
+
+#define YADE_DISPATCHER1D_FUNCTOR_DOC_ATTRS_CTOR_PY(DispatcherT,FunctorT,doc,attrs,ctor,py) _YADE_DIM_DISPATCHER_FUNCTOR_DOC_ATTRS_CTOR_PY(1,DispatcherT,FunctorT,doc,attrs,ctor,py)
+#define YADE_DISPATCHER2D_FUNCTOR_DOC_ATTRS_CTOR_PY(DispatcherT,FunctorT,doc,attrs,ctor,py) _YADE_DIM_DISPATCHER_FUNCTOR_DOC_ATTRS_CTOR_PY(2,DispatcherT,FunctorT,doc,attrs,ctor,py)
+
+// HELPER FUNCTIONS
+
+/*! Function returning class name (as string) for given index and topIndexable (top-level indexable, such as Shape, Material and so on)
+This function exists solely for debugging, is quite slow: it has to traverse all classes and ask for inheritance information.
+It should be used primarily to convert indices to names in Dispatcher::dictDispatchMatrix?D; since it relies on Omega for RTTI,
+this code could not be in Dispatcher itself.
+s*/
+template<class topIndexable>
+std::string Dispatcher_indexToClassName(int idx){
+	scoped_ptr<topIndexable> top(new topIndexable);
+	std::string topName=top->getClassName();
+	typedef std::pair<string,DynlibDescriptor> classItemType;
+	FOREACH(classItemType clss, Omega::instance().getDynlibsDescriptor()){
+		if(Omega::instance().isInheritingFrom_recursive(clss.first,topName) || clss.first==topName){
+			// create instance, to ask for index
+			shared_ptr<topIndexable> inst=dynamic_pointer_cast<topIndexable>(ClassFactory::instance().createShared(clss.first));
+			assert(inst);
+			if(inst->getClassIndex()<0 && inst->getClassName()!=top->getClassName()){
+				throw logic_error("Class "+inst->getClassName()+" didn't use REGISTER_CLASS_INDEX("+inst->getClassName()+","+top->getClassName()+") and/or forgot to call createIndex() in the ctor. [[ Please fix that! ]]");
+			}
+			if(inst->getClassIndex()==idx) return clss.first;
+		}
+	}
+	throw runtime_error("No class with index "+boost::lexical_cast<string>(idx)+" found (top-level indexable is "+topName+")");
+}
+
+//! Return class index of given indexable
+template<typename TopIndexable>
+int Indexable_getClassIndex(const shared_ptr<TopIndexable> i){return i->getClassIndex();}
+
+//! Return sequence (hierarchy) of class indices of given indexable; optionally convert to names
+template<typename TopIndexable>
+python::list Indexable_getClassIndices(const shared_ptr<TopIndexable> i, bool convertToNames){
+	int depth=1; python::list ret; int idx0=i->getClassIndex();
+	if(convertToNames) ret.append(Dispatcher_indexToClassName<TopIndexable>(idx0));
+	else ret.append(idx0);
+	if(idx0<0) return ret; // don't continue and call getBaseClassIndex(), since we are at the top already
+	while(true){
+		int idx=i->getBaseClassIndex(depth++);
+		if(convertToNames) ret.append(Dispatcher_indexToClassName<TopIndexable>(idx));
+		else ret.append(idx);
+		if(idx<0) return ret;
+	}
+}
+
+
+
+//! Return functors of this dispatcher, as list of functors of appropriate type
+template<typename DispatcherT>
+std::vector<shared_ptr<typename DispatcherT::functorType> > Dispatcher_functors_get(shared_ptr<DispatcherT> self){
+	std::vector<shared_ptr<typename DispatcherT::functorType> > ret;
+	FOREACH(const shared_ptr<Functor>& functor, self->functors){ shared_ptr<typename DispatcherT::functorType> functorRightType(dynamic_pointer_cast<typename DispatcherT::functorType>(functor)); if(!functorRightType) throw logic_error("Internal error: Dispatcher of type "+self->getClassName()+" did not contain Functor of the required type "+typeid(typename DispatcherT::functorType).name()+"?"); ret.push_back(functorRightType); }
+	return ret;
+}
+
+template<typename DispatcherT>
+void Dispatcher_functors_set(shared_ptr<DispatcherT> self, std::vector<shared_ptr<typename DispatcherT::functorType> > functors){
+	self->clear();
+	FOREACH(const shared_ptr<typename DispatcherT::functorType>& item, functors) self->add(item);
+}
+
+// Dispatcher is not a template, hence converting this into a real constructor would be complicated; keep it separated, at least for now...
+//! Create dispatcher of given type, with functors given as list in argument
+template<typename DispatcherT>
+shared_ptr<DispatcherT> Dispatcher_ctor_list(const std::vector<shared_ptr<typename DispatcherT::functorType> >& functors){
+	shared_ptr<DispatcherT> instance(new DispatcherT);
+	Dispatcher_functors_set<DispatcherT>(instance,functors);
+	return instance;
+}
+
+
+
+template
+<
+	class FunctorType,
+	bool autoSymmetry=true
+>
+class Dispatcher1D : public Dispatcher,
+				public DynLibDispatcher
+				<	  TYPELIST_1(typename FunctorType::DispatchType1)		// base classes for dispatch
+					, FunctorType		// class that provides multivirtual call
+					, typename FunctorType::ReturnType		// return type
+					, typename FunctorType::ArgumentTypes
+					, autoSymmetry
+				>
+{
+
+	public :
+		typedef typename FunctorType::DispatchType1 baseClass;
+		typedef baseClass argType1;
+		typedef FunctorType functorType;
+		typedef DynLibDispatcher<TYPELIST_1(baseClass),FunctorType,typename FunctorType::ReturnType,typename FunctorType::ArgumentTypes,autoSymmetry> dispatcherBase;
+
+		shared_ptr<FunctorType> getFunctor(shared_ptr<baseClass> arg){ return dispatcherBase::getExecutor(arg); }
+		python::dict dump(bool convertIndicesToNames){
+			python::dict ret;
+			FOREACH(const DynLibDispatcher_Item1D& item, dispatcherBase::dataDispatchMatrix1D()){
+				if(convertIndicesToNames){
+					string arg1=Dispatcher_indexToClassName<argType1>(item.ix1);
+					ret[python::make_tuple(arg1)]=item.functorName;
+				} else ret[python::make_tuple(item.ix1)]=item.functorName;
+			}
+			return ret;
+		}
+
+		int getDimension() { return 1; }
+	
+		virtual string getFunctorType(){
+			shared_ptr<FunctorType> eu(new FunctorType);
+			return eu->getClassName();
+		}
+
+		virtual string getBaseClassType(unsigned int i){
+			if (i==0) { shared_ptr<baseClass> bc(new baseClass); return bc->getClassName(); }
+			else return "";
+		}
+
+
+	public:
+	REGISTER_ATTRIBUTES(Dispatcher,);
+	REGISTER_CLASS_AND_BASE(Dispatcher1D,Dispatcher DynLibDispatcher);
+};
+
+
+template
+<
+	class FunctorType,
+	bool autoSymmetry=true
+>
+class Dispatcher2D : public Dispatcher,
+				public DynLibDispatcher
+				<	  TYPELIST_2(typename FunctorType::DispatchType1,typename FunctorType::DispatchType2) // base classes for dispatch
+					, FunctorType			// class that provides multivirtual call
+					, typename FunctorType::ReturnType    // return type
+					, typename FunctorType::ArgumentTypes // argument of engine unit
+					, autoSymmetry
+				>
+{
+	public :
+		typedef typename FunctorType::DispatchType1 baseClass1; typedef typename FunctorType::DispatchType2 baseClass2;
+		typedef baseClass1 argType1;
+		typedef baseClass2 argType2;
+		typedef FunctorType functorType;
+		typedef DynLibDispatcher<TYPELIST_2(baseClass1,baseClass2),FunctorType,typename FunctorType::ReturnType,typename FunctorType::ArgumentTypes,autoSymmetry> dispatcherBase;
+		shared_ptr<FunctorType> getFunctor(shared_ptr<baseClass1> arg1, shared_ptr<baseClass2> arg2){ return dispatcherBase::getExecutor(arg1,arg2); }
+		python::dict dump(bool convertIndicesToNames){
+			python::dict ret;
+			FOREACH(const DynLibDispatcher_Item2D& item, dispatcherBase::dataDispatchMatrix2D()){
+				if(convertIndicesToNames){
+					string arg1=Dispatcher_indexToClassName<argType1>(item.ix1), arg2=Dispatcher_indexToClassName<argType2>(item.ix2);
+					ret[python::make_tuple(arg1,arg2)]=item.functorName;
+				} else ret[python::make_tuple(item.ix1,item.ix2)]=item.functorName;
+			}
+			return ret;
+		}
+
+		virtual int getDimension() { return 2; }
+
+		virtual string getFunctorType(){
+			shared_ptr<FunctorType> eu(new FunctorType);
+			return eu->getClassName();
+		}
+		virtual string getBaseClassType(unsigned int i){
+			if (i==0){ shared_ptr<baseClass1> bc(new baseClass1); return bc->getClassName(); }
+			else if (i==1){ shared_ptr<baseClass2> bc(new baseClass2); return bc->getClassName();}
+			else return "";
+		}
+	public:
+	REGISTER_ATTRIBUTES(Dispatcher,);
+	REGISTER_CLASS_AND_BASE(Dispatcher2D,Dispatcher DynLibDispatcher);
+};
+

=== added file 'core/DisplayParameters.hpp'
--- core/DisplayParameters.hpp	1970-01-01 00:00:00 +0000
+++ core/DisplayParameters.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,27 @@
+#pragma once
+ 
+/* Class for storing set of display parameters.
+ *
+ * The interface sort of emulates map string->string (which is not handled by yade-serialization).
+ *
+ * The "keys" (called displayTypes) are intended to be "OpenGLRenderer" or "GLViewer" (and perhaps other).
+ * The "values" are intended to be XML representation of display parameters, obtained either by yade-serialization
+ * with OpenGLRenderer and saveStateToStream with QGLViewer (and GLViewer).
+ *
+ */
+
+class DisplayParameters: public Serializable{
+	private:
+		std::vector<std::string> values;
+		std::vector<std::string> displayTypes;
+	public:
+		//! Get value of given display type and put it in string& value and return true; if there is no such display type, return false.
+		bool getValue(std::string displayType, std::string& value){assert(values.size()==displayTypes.size()); vector<string>::iterator I=std::find(displayTypes.begin(),displayTypes.end(),displayType); if(I==displayTypes.end()) return false; value=values[std::distance(displayTypes.begin(),I)]; return true;}
+		//! Set value of given display type; if such display type exists, it is overwritten, otherwise a new one is created.
+		void setValue(std::string displayType, std::string value){assert(values.size()==displayTypes.size()); vector<string>::iterator I=std::find(displayTypes.begin(),displayTypes.end(),displayType); if(I==displayTypes.end()){displayTypes.push_back(displayType); values.push_back(value);} else {values[std::distance(displayTypes.begin(),I)]=value;};}
+	DisplayParameters(){}
+	virtual ~DisplayParameters(){}
+	REGISTER_ATTRIBUTES(Serializable,(displayTypes)(values));
+	REGISTER_CLASS_AND_BASE(DisplayParameters,Serializable);
+};
+REGISTER_SERIALIZABLE(DisplayParameters);

=== added file 'core/EnergyTracker.hpp'
--- core/EnergyTracker.hpp	1970-01-01 00:00:00 +0000
+++ core/EnergyTracker.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,65 @@
+#pragma once
+#include<boost/python.hpp>
+#include<boost/foreach.hpp>
+#include<string>
+#include<yade/lib-base/openmp-accu.hpp>
+#include<yade/lib-serialization/Serializable.hpp>
+
+#ifndef FOREACH
+	#define FOREACH BOOST_FOREACH
+#endif
+
+namespace py=boost::python;
+
+class EnergyTracker: public Serializable{
+	public:
+	~EnergyTracker();
+	void findId(const std::string& name, int& id, bool reset=false, bool newIfNotFound=true){
+		if(id>0) return; // the caller should have checked this already
+		if(names.count(name)) id=names[name];
+		else if(newIfNotFound) {
+			#ifdef YADE_OPENMP
+				#pragma omp critical
+			#endif
+				{ energies.resize(energies.size()+1); id=energies.size()-1; resetStep.resize(id+1); resetStep[id]=reset; names[name]=id; assert(id<(int)energies.size()); assert(id>=0); }
+		}
+	}
+	// set value of the accumulator; note: must NOT be called from parallel sections!
+	void set(const Real& val, const std::string& name, int &id){
+		if(id<0) findId(name,id,/* do not reset value that is set directly */ false);
+		energies.set(id,val);
+	}
+	// add value to the accumulator; safely called from parallel sections
+	void add(const Real& val, const std::string& name, int &id, bool reset=false){
+		if(id<0) findId(name,id,reset);
+		energies.add(id,val);
+	}
+	Real getItem_py(const std::string& name){
+		int id=-1; findId(name,id,false,false); 
+		if (id<0) {PyErr_SetString(PyExc_KeyError,("Unknown energy name '"+name+"'.").c_str());  python::throw_error_already_set(); }
+		return energies.get(id);
+	}
+	void setItem_py(const std::string& name, Real val){
+		int id=-1; set(val,name,id);
+	}
+	void clear(){ energies.clear(); names.clear(); resetStep.clear();}
+
+	py::list keys_py(){ py::list ret; FOREACH(pairStringInt p, names) ret.append(p.first); return ret; }
+	void resetResettables(){ size_t sz=energies.size(); for(size_t id=0; id<sz; id++){ if(resetStep[id]) energies.reset(id); } }
+
+	typedef std::map<std::string,int> mapStringInt;
+	typedef std::pair<std::string,int> pairStringInt;
+
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(EnergyTracker,Serializable,"Storage for tracing energies. Only to be used if O.traceEnergy is True.",
+		((OpenMPArrayAccumulator<Real>,energies,,,"Energy values, in linear array"))
+		((mapStringInt,names,,Attr::hidden,"Associate textual name to an index in the energies array."))
+		((vector<bool>,resetStep,,Attr::hidden,"Whether the respective energy value should be reset at every step."))
+		,/*ctor*/
+		,/*py*/
+			.def("__getitem__",&EnergyTracker::getItem_py,"Get energy value for given name.")
+			.def("__setitem__",&EnergyTracker::setItem_py,"Set energy value for given name (will create a non-resettable item, if it does not exist yet).")
+			.def("clear",&EnergyTracker::clear,"Clear all stored values.")
+			.def("keys",&EnergyTracker::keys_py,"Return defined energies.")
+	)
+};
+REGISTER_SERIALIZABLE(EnergyTracker);

=== added file 'core/Engine.cpp'
--- core/Engine.cpp	1970-01-01 00:00:00 +0000
+++ core/Engine.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,13 @@
+#include<yade/core/Engine.hpp>
+
+CREATE_LOGGER(Engine);
+
+void Engine::action(){
+	LOG_FATAL("Engine "<<getClassName()<<" calling virtual method Engine::action(). Please submit bug report at http://bugs.launchpad.net/yade.";);
+	throw std::logic_error("Engine::action() called.");
+}
+
+void Engine::explicitAction(){
+	scene=Omega::instance().getScene().get(); action();
+}
+

=== added file 'core/Engine.hpp'
--- core/Engine.hpp	1970-01-01 00:00:00 +0000
+++ core/Engine.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,63 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/core/Omega.hpp>
+#include<yade/core/Timing.hpp>
+#include<yade/lib-base/Logging.hpp>
+#include<stdexcept>
+
+#include<boost/foreach.hpp>
+#ifndef FOREACH
+#define FOREACH BOOST_FOREACH
+#endif
+
+class Body;
+class Scene;
+
+class Engine: public Serializable{
+	public:
+		// pointer to the simulation, set at every step by Scene::moveToNextTimeStep
+		Scene* scene;
+		//! high-level profiling information; not serializable
+		TimingInfo timingInfo; 
+		//! precise profiling information (timing of fragments of the engine)
+		shared_ptr<TimingDeltas> timingDeltas;
+		virtual ~Engine() {};
+	
+		virtual bool isActivated() { return true; };
+		virtual void action();
+	private:
+		// py access funcs	
+		TimingInfo::delta timingInfo_nsec_get(){return timingInfo.nsec;};
+		void timingInfo_nsec_set(TimingInfo::delta d){ timingInfo.nsec=d;}
+		long timingInfo_nExec_get(){return timingInfo.nExec;};
+		void timingInfo_nExec_set(long d){ timingInfo.nExec=d;}
+		void explicitAction(); 
+
+	DECLARE_LOGGER;
+
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Engine,Serializable,"Basic execution unit of simulation, called from the simulation loop (O.engines)",
+		((bool,dead,false,,"If true, this engine will not run at all; can be used for making an engine temporarily deactivated and only resurrect it at a later point."))
+		((string,label,,,"Textual label for this object; must be valid python identifier, you can refer to it directly from python.")),
+		/* ctor */ scene=Omega::instance().getScene().get() ,
+		/* py */
+		.add_property("execTime",&Engine::timingInfo_nsec_get,&Engine::timingInfo_nsec_set,"Cummulative time this Engine took to run (only used if :yref:`O.timingEnabled<Omega.timingEnabled>`\\ ==\\ ``True``).")
+		.add_property("execCount",&Engine::timingInfo_nExec_get,&Engine::timingInfo_nExec_set,"Cummulative count this engine was run (only used if :yref:`O.timingEnabled<Omega.timingEnabled>`\\ ==\\ ``True``).")
+		.def_readonly("timingDeltas",&Engine::timingDeltas,"Detailed information about timing inside the Engine itself. Empty unless enabled in the source code and :yref:`O.timingEnabled<Omega.timingEnabled>`\\ ==\\ ``True``.")
+		.def("__call__",&Engine::explicitAction)
+	);
+};
+REGISTER_SERIALIZABLE(Engine);
+
+
+

=== added file 'core/FileGenerator.cpp'
--- core/FileGenerator.cpp	1970-01-01 00:00:00 +0000
+++ core/FileGenerator.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,72 @@
+/*************************************************************************
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include<cstdlib>
+#include<boost/date_time/posix_time/posix_time.hpp>
+
+#include<yade/core/Omega.hpp>
+#include<yade/lib-pyutil/gil.hpp>
+#include<yade/lib-serialization/ObjectIO.hpp>
+
+#include"FileGenerator.hpp"
+
+CREATE_LOGGER(FileGenerator);
+
+
+bool FileGenerator::generate(std::string& msg){ throw invalid_argument("Calling abstract FileGenerator::generate() does not make sense."); }
+
+
+bool FileGenerator::generateAndSave(const string& outputFileName, string& message)
+{
+	bool status;
+	message="";
+	boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+	try {
+		status=generate(message); // will modify message
+	}
+	catch(std::exception& e){
+		LOG_FATAL("Unhandled exception: "<<typeid(e).name()<<" : "<<e.what());
+		//abort(); // use abort, since we may want to inspect core
+		message = message + "Unhandled exception: " + typeid(e).name() + " : " + e.what();
+		return false;
+	}
+	// generation wasn't successful
+	if(status==false) return false;
+
+	else {
+		boost::posix_time::ptime now2 = boost::posix_time::second_clock::local_time();
+		boost::posix_time::time_duration generationTime = now2 - now; // generation time, without save time
+		try
+		{
+			yade::ObjectIO::save(outputFileName,"scene",scene);
+		}
+		catch(const std::runtime_error& e)
+		{
+			message+=std::string("File "+outputFileName+" cannot be saved: "+e.what());
+			return false;
+		}
+		boost::posix_time::ptime now3 = boost::posix_time::second_clock::local_time();
+		boost::posix_time::time_duration saveTime = now3 - now2; // save time
+		message=std::string("File "+outputFileName+" generated successfully."
+				+ "\ngeneration time: " + boost::posix_time::to_simple_string(generationTime) 
+				+ "\nsave time: "       + boost::posix_time::to_simple_string(saveTime)
+				+"\n\n")+message;
+		return true;
+	}
+}
+
+void FileGenerator::pyGenerate(const string& out){
+	string message;
+	bool ret=generateAndSave(out,message);
+	LOG_INFO((ret?"SUCCESS:\n":"FAILURE:\n")<<message);
+	if(ret==false) throw runtime_error(getClassName()+" reported error: "+message);
+}
+void FileGenerator::pyLoad(){
+	string xml(Omega::instance().tmpFilename()+".xml.bz2");
+	// LOG_DEBUG("Using temp file "<<xml);
+	pyGenerate(xml);
+	//this is ugly hack, yes...
+	pyRunString("yade.wrapper.Omega().load('"+xml+"')");
+}

=== added file 'core/FileGenerator.hpp'
--- core/FileGenerator.hpp	1970-01-01 00:00:00 +0000
+++ core/FileGenerator.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,41 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-base/Logging.hpp>
+
+#include "Scene.hpp"
+#include "ThreadWorker.hpp"
+
+class FileGenerator: public Serializable
+{
+	protected:
+		shared_ptr<Scene>	 scene;
+	public:
+		bool generateAndSave(const string& outFile, string& message);
+	protected :
+	//! Returns whether the generation was successful; message for user is in FileGenerator::message
+	virtual bool generate(std::string& msg);
+
+	void pyGenerate(const string& out);
+	void pyLoad();
+
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(FileGenerator,Serializable,"Base class for scene generators, preprocessors.",
+		/*attrs*/,
+		/*ctor*/
+		,
+		.def("generate",&FileGenerator::pyGenerate,(python::arg("out")),"Generate scene, save to given file")
+		.def("load",&FileGenerator::pyLoad,"Generate scene, save to temporary file and load immediately");
+	);
+	DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(FileGenerator);
+
+

=== added file 'core/ForceContainer.hpp'
--- core/ForceContainer.hpp	1970-01-01 00:00:00 +0000
+++ core/ForceContainer.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,240 @@
+// 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
+#pragma once
+
+#include<string.h>
+#include<vector>
+#include<yade/lib-base/Math.hpp>
+#include<yade/core/Body.hpp>
+
+#include<boost/static_assert.hpp>
+// make sure that (void*)&vec[0]==(void*)&vec
+BOOST_STATIC_ASSERT(sizeof(Vector3r)==3*sizeof(Real));
+
+
+#ifdef YADE_OPENMP
+
+#include<omp.h>
+/*! Container for Body External Variables (forces), typically forces and torques from interactions.
+ * Values should be reset at every iteration by calling ForceContainer::reset();
+ * If you want to add your own force type, you need to:
+ *
+ * 	1. Create storage vector
+ * 	2. Create accessor function
+ * 	3. Update the resize function
+ * 	4. Update the reset function
+ * 	5. update the sync function (for the multithreaded implementation)
+ *
+ * This class exists in two flavors: non-parallel and parallel. The parallel one stores
+ * force increments separately for every thread and sums those when sync() is called.
+ * The reason of this design is that the container is not truly random-access, but rather
+ * is written to everywhere in one phase and read in the next one. Adding to force/torque
+ * marks the container as dirty and sync() must be performed before reading the stored data.
+ * Calling getForce/getTorque when the container is not synchronized throws an exception.
+ *
+ * It is intentional that sync() needs to be called exlicitly, since syncs are expensive and
+ * the programmer should be aware of that. Sync is however performed only if the container
+ * is dirty. Every full sync increments the syncCount variable, that should ideally equal
+ * the number of steps (one per step).
+ *
+ * The number of threads (omp_get_max_threads) may not change once ForceContainer is constructed.
+ *
+ * The non-parallel flavor has the same interface, but sync() is no-op and synchronization
+ * is not enforced at all.
+ */
+
+//! This is the parallel flavor of ForceContainer
+class ForceContainer{
+	private:
+		typedef std::vector<Vector3r> vvector;
+		std::vector<vvector> _forceData;
+		std::vector<vvector> _torqueData;
+		std::vector<vvector> _moveData;
+		std::vector<vvector> _rotData;
+		vvector _force, _torque, _move, _rot;
+		std::vector<size_t> sizeOfThreads;
+		size_t size;
+		bool syncedSizes;
+		int nThreads;
+		bool synced,moveRotUsed;
+		boost::mutex globalMutex;
+		Vector3r _zero;
+
+		inline void ensureSize(Body::id_t id, int threadN){
+			assert(nThreads>omp_get_thread_num());
+			if (sizeOfThreads[threadN]<=(size_t)id) resize(min((size_t)1.5*(id+100),(size_t)(id+2000)),threadN);
+		}
+
+		inline void ensureSynced(){ if(!synced) throw runtime_error("ForceContainer not thread-synchronized; call sync() first!"); }
+
+		#if 0
+			/*! Function to allow friend classes to get force even if not synced.
+			* Dangerous! The caller must know what it is doing! (i.e. don't read after write
+			* for a particular body id. */
+			const Vector3r& getForceUnsynced (Body::id_t id){ensureSize(id); return _force[id];}
+			const Vector3r& getTorqueUnsynced(Body::id_t id){ensureSize(id); return _force[id];}
+		#endif
+		// dummy function to avoid template resolution failure
+		friend class boost::serialization::access; template<class ArchiveT> void serialize(ArchiveT & ar, unsigned int version){}
+	public:
+		ForceContainer(): size(0),syncedSizes(true),synced(true),moveRotUsed(false),_zero(Vector3r::Zero()),syncCount(0),lastReset(0){
+			nThreads=omp_get_max_threads();
+			for(int i=0; i<nThreads; i++){
+				_forceData.push_back(vvector()); _torqueData.push_back(vvector());
+				_moveData.push_back(vvector());  _rotData.push_back(vvector());
+				sizeOfThreads.push_back(0);
+			}
+		}
+
+		const Vector3r& getForce(Body::id_t id)         { ensureSynced(); return ((size_t)id<size)?_force[id]:_zero; }
+		void  addForce(Body::id_t id, const Vector3r& f){ ensureSize(id,omp_get_thread_num()); synced=false;   _forceData[omp_get_thread_num()][id]+=f;}
+		const Vector3r& getTorque(Body::id_t id)        { ensureSynced(); return ((size_t)id<size)?_torque[id]:_zero; }
+		void addTorque(Body::id_t id, const Vector3r& t){ ensureSize(id,omp_get_thread_num()); synced=false;   _torqueData[omp_get_thread_num()][id]+=t;}
+		const Vector3r& getMove(Body::id_t id)          { ensureSynced(); return ((size_t)id<size)?_move[id]:_zero; }
+		void  addMove(Body::id_t id, const Vector3r& m) { ensureSize(id,omp_get_thread_num()); synced=false; moveRotUsed=true; _moveData[omp_get_thread_num()][id]+=m;}
+		const Vector3r& getRot(Body::id_t id)           { ensureSynced(); return ((size_t)id<size)?_rot[id]:_zero; }
+		void  addRot(Body::id_t id, const Vector3r& r)  { ensureSize(id,omp_get_thread_num()); synced=false; moveRotUsed=true; _rotData[omp_get_thread_num()][id]+=r;}
+		/* To be benchmarked: sum thread data in getForce/getTorque upon request for each body individually instead of by the sync() function globally */
+		// this function is used from python so that running simulation is not slowed down by sync'ing on occasions
+		// since Vector3r writes are not atomic, it might (rarely) return wrong value, if the computation is running meanwhile
+		Vector3r getForceSingle (Body::id_t id){ Vector3r ret(Vector3r::Zero()); for(int t=0; t<nThreads; t++){ ret+=((size_t)id<sizeOfThreads[t])?_forceData [t][id]:_zero; } return ret; }
+		Vector3r getTorqueSingle(Body::id_t id){ Vector3r ret(Vector3r::Zero()); for(int t=0; t<nThreads; t++){ ret+=((size_t)id<sizeOfThreads[t])?_torqueData[t][id]:_zero; } return ret; }
+		Vector3r getMoveSingle  (Body::id_t id){ Vector3r ret(Vector3r::Zero()); for(int t=0; t<nThreads; t++){ ret+=((size_t)id<sizeOfThreads[t])?_moveData  [t][id]:_zero; } return ret; }
+		Vector3r getRotSingle   (Body::id_t id){ Vector3r ret(Vector3r::Zero()); for(int t=0; t<nThreads; t++){ ret+=((size_t)id<sizeOfThreads[t])?_rotData   [t][id]:_zero; } return ret; }
+		
+		inline void syncSizesOfContainers() {
+			if (syncedSizes) return;
+			//check whether all containers have equal length, and if not resize it
+			for(int i=0; i<nThreads; i++){
+				if (sizeOfThreads[i]<size) resize(size,i);
+			}
+			_force.resize(size,Vector3r::Zero());
+			_torque.resize(size,Vector3r::Zero());
+			_move.resize(size,Vector3r::Zero());
+			_rot.resize(size,Vector3r::Zero());
+			syncedSizes=true;
+		}
+		/* Sum contributions from all threads, save to _force&_torque.
+		 * Locks globalMutex, since one thread modifies common data (_force&_torque).
+		 * Must be called before get* methods are used. Exception is thrown otherwise, since data are not consistent. */
+		inline void sync(){
+			if(synced) return;
+			boost::mutex::scoped_lock lock(globalMutex);
+			if(synced) return; // if synced meanwhile
+
+			syncSizesOfContainers();
+
+			for(long id=0; id<(long)size; id++){
+				Vector3r sumF(Vector3r::Zero()), sumT(Vector3r::Zero());
+				for(int thread=0; thread<nThreads; thread++){ sumF+=_forceData[thread][id]; sumT+=_torqueData[thread][id];}
+				_force[id]=sumF; _torque[id]=sumT;
+			}
+			if(moveRotUsed){
+				for(long id=0; id<(long)size; id++){
+					Vector3r sumM(Vector3r::Zero()), sumR(Vector3r::Zero());
+					for(int thread=0; thread<nThreads; thread++){ sumM+=_moveData[thread][id]; sumR+=_rotData[thread][id];}
+					_move[id]=sumM; _rot[id]=sumR;
+				}
+			}
+			synced=true; syncCount++;
+		}
+		unsigned long syncCount;
+		long lastReset;
+
+		void resize(size_t newSize, int threadN){
+			_forceData [threadN].resize(newSize,Vector3r::Zero());
+			_torqueData[threadN].resize(newSize,Vector3r::Zero());
+			_moveData[threadN].resize(newSize,Vector3r::Zero());
+			_rotData[threadN].resize(newSize,Vector3r::Zero());
+			sizeOfThreads[threadN] = newSize;
+			if (size<newSize) size=newSize;
+			syncedSizes=false;
+		}
+		/*! Reset all data, also reset summary forces/torques and mark the container clean. */
+		// perhaps should be private and friend Scene or whatever the only caller should be
+		void reset(long iter){
+			syncSizesOfContainers();
+			for(int thread=0; thread<nThreads; thread++){
+				memset(&_forceData [thread][0],0,sizeof(Vector3r)*sizeOfThreads[thread]);
+				memset(&_torqueData[thread][0],0,sizeof(Vector3r)*sizeOfThreads[thread]);
+				if(moveRotUsed){
+					memset(&_moveData  [thread][0],0,sizeof(Vector3r)*sizeOfThreads[thread]);
+					memset(&_rotData   [thread][0],0,sizeof(Vector3r)*sizeOfThreads[thread]);
+				}
+			}
+			memset(&_force [0], 0,sizeof(Vector3r)*size);
+			memset(&_torque[0], 0,sizeof(Vector3r)*size);
+			if(moveRotUsed){
+				memset(&_move  [0], 0,sizeof(Vector3r)*size);
+				memset(&_rot   [0], 0,sizeof(Vector3r)*size);
+			}
+			synced=true; moveRotUsed=false;
+			lastReset=iter;
+		}
+		//! say for how many threads we have allocated space
+		const int& getNumAllocatedThreads() const {return nThreads;}
+		const bool& getMoveRotUsed() const {return moveRotUsed;}
+};
+
+#else
+//! This is the non-parallel flavor of ForceContainer
+class ForceContainer {
+	private:
+		std::vector<Vector3r> _force;
+		std::vector<Vector3r> _torque;
+		std::vector<Vector3r> _move;
+		std::vector<Vector3r> _rot;
+		size_t size;
+		inline void ensureSize(Body::id_t id){ if(size<=(size_t)id) resize(min((size_t)1.5*(id+100),(size_t)(id+2000)));}
+		#if 0
+			const Vector3r& getForceUnsynced (Body::id_t id){ return getForce(id);}
+			const Vector3r& getTorqueUnsynced(Body::id_t id){ return getForce(id);}
+		#endif
+		bool moveRotUsed;
+		// dummy function to avoid template resolution failure
+		friend class boost::serialization::access; template<class ArchiveT> void serialize(ArchiveT & ar, unsigned int version){}
+	public:
+		ForceContainer(): size(0), moveRotUsed(false), syncCount(0), lastReset(0){}
+		const Vector3r& getForce(Body::id_t id){ensureSize(id); return _force[id];}
+		void  addForce(Body::id_t id,const Vector3r& f){ensureSize(id); _force[id]+=f;}
+		const Vector3r& getTorque(Body::id_t id){ensureSize(id); return _torque[id];}
+		void  addTorque(Body::id_t id,const Vector3r& t){ensureSize(id); _torque[id]+=t;}
+		const Vector3r& getMove(Body::id_t id){ensureSize(id); return _move[id];}
+		void  addMove(Body::id_t id,const Vector3r& f){ensureSize(id); moveRotUsed=true; _move[id]+=f;}
+		const Vector3r& getRot(Body::id_t id){ensureSize(id); return _rot[id];}
+		void  addRot(Body::id_t id,const Vector3r& f){ensureSize(id); moveRotUsed=true; _rot[id]+=f;}
+		// single getters do the same as globally synced ones in the non-parallel flavor
+		const Vector3r& getForceSingle (Body::id_t id){ ensureSize(id); return _force [id]; }
+		const Vector3r& getTorqueSingle(Body::id_t id){ ensureSize(id); return _torque[id]; }
+		const Vector3r& getMoveSingle  (Body::id_t id){ ensureSize(id); return _move  [id]; }
+		const Vector3r& getRotSingle   (Body::id_t id){ ensureSize(id); return _rot   [id]; }
+
+		//! Set all forces to zero
+		void reset(long iter){
+			memset(&_force [0],0,sizeof(Vector3r)*size);
+			memset(&_torque[0],0,sizeof(Vector3r)*size);
+			if(moveRotUsed){
+				memset(&_move  [0],0,sizeof(Vector3r)*size);
+				memset(&_rot   [0],0,sizeof(Vector3r)*size);
+				moveRotUsed=false;
+			}
+			lastReset=iter;
+		}
+		//! No-op for API compatibility with the threaded version
+		void sync(){return;}
+		unsigned long syncCount;
+		// interaction in which the container was last reset; used by NewtonIntegrator to detect whether ForceResetter was not forgotten
+		long lastReset;
+		/*! Resize the container; this happens automatically,
+		 * but you may want to set the size beforehand to avoid resizes as the simulation grows. */
+		void resize(size_t newSize){
+			_force.resize(newSize,Vector3r::Zero());
+			_torque.resize(newSize,Vector3r::Zero());
+			_move.resize(newSize,Vector3r::Zero());
+			_rot.resize(newSize,Vector3r::Zero());
+			size=newSize;
+		}
+		const int getNumAllocatedThreads() const {return 1;}
+		const bool& getMoveRotUsed() const {return moveRotUsed;}
+};
+
+#endif

=== added file 'core/FrontEnd.cpp'
--- core/FrontEnd.cpp	1970-01-01 00:00:00 +0000
+++ core/FrontEnd.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,21 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include "FrontEnd.hpp"
+
+
+FrontEnd::FrontEnd()
+{	
+}
+
+
+FrontEnd::~FrontEnd()
+{
+
+}
+

=== added file 'core/FrontEnd.hpp'
--- core/FrontEnd.hpp	1970-01-01 00:00:00 +0000
+++ core/FrontEnd.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,29 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include "Omega.hpp"
+
+#include<yade/lib-factory/Factorable.hpp>
+
+class FrontEnd : public Factorable
+{	
+	public :
+		FrontEnd ();
+		virtual ~FrontEnd ();
+
+		virtual int run(int , char * []) { return -1;};
+		// called before actually invoking it
+		virtual bool available(){return false;}
+
+	REGISTER_CLASS_AND_BASE(FrontEnd,Factorable);
+};
+REGISTER_FACTORABLE(FrontEnd);
+
+

=== added file 'core/Functor.hpp'
--- core/Functor.hpp	1970-01-01 00:00:00 +0000
+++ core/Functor.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,77 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-multimethods/FunctorWrapper.hpp>
+
+class TimingDeltas;
+class Scene;
+
+class Functor: public Serializable
+{
+	public: virtual vector<std::string> getFunctorTypes(){throw;}
+	shared_ptr<TimingDeltas> timingDeltas;
+	//! updated before every dispatch loop by the dispatcher; DO NOT ABUSE access to scene, except for getting global variables like scene->dt.
+	Scene* scene;
+	virtual ~Functor(); // defined in Dispatcher.cpp
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Functor,Serializable,"Function-like object that is called by Dispatcher, if types of arguments match those the Functor declares to accept.",
+		((string,label,,,"Textual label for this object; must be valid python identifier, you can refer to it directly fron python (must be a valid python identifier).")),
+		/*ctor*/,
+		.def_readonly("timingDeltas",&Functor::timingDeltas,"Detailed information about timing inside the Dispatcher itself. Empty unless enabled in the source code and O.timingEnabled==True.")
+		.add_property("bases",&Functor::getFunctorTypes,"Ordered list of types (as strings) this functor accepts.")
+	);	
+};
+REGISTER_SERIALIZABLE(Functor);
+
+
+
+template
+<
+	class _DispatchType1,
+	class _ReturnType,
+	class _ArgumentTypes
+>
+class Functor1D: public Functor,
+			public FunctorWrapper<_ReturnType, _ArgumentTypes>
+{
+	public:
+		typedef _DispatchType1 DispatchType1; typedef _ReturnType ReturnType; typedef _ArgumentTypes ArgumentTypes; 
+		#define FUNCTOR1D(type1) public: std::string get1DFunctorType1(void){return string(#type1);}
+		virtual std::string get1DFunctorType1(void){throw runtime_error("Class "+this->getClassName()+" did not use FUNCTOR1D to declare its argument type?"); }
+		virtual vector<string> getFunctorTypes(void){vector<string> ret; ret.push_back(get1DFunctorType1()); return ret;};
+	REGISTER_CLASS_AND_BASE(Functor1D,Functor FunctorWrapper);
+	/* do not REGISTER_ATTRIBUTES here, since we are template; derived classes should call REGISTER_ATTRIBUTES(Functor,(their)(own)(attributes)), bypassing Functor1D */
+};
+
+
+template
+<
+	class _DispatchType1,
+	class _DispatchType2,
+	class _ReturnType,
+	class _ArgumentTypes
+>
+class Functor2D:	public Functor,
+			public FunctorWrapper<_ReturnType, _ArgumentTypes>
+{
+	public:
+		typedef _DispatchType1 DispatchType1; typedef _DispatchType2 DispatchType2; typedef _ReturnType ReturnType; typedef _ArgumentTypes ArgumentTypes; 
+		#define FUNCTOR2D(type1,type2) public: std::string get2DFunctorType1(void){return string(#type1);}; std::string get2DFunctorType2(void){return string(#type2);};
+		virtual std::string get2DFunctorType1(void){throw logic_error("Class "+this->getClassName()+" did not use FUNCTOR2D to declare its argument types?");}
+		virtual std::string get2DFunctorType2(void){throw logic_error("Class "+this->getClassName()+" did not use FUNCTOR2D to declare its argument types?");}
+		virtual vector<string> getFunctorTypes(){vector<string> ret; ret.push_back(get2DFunctorType1()); ret.push_back(get2DFunctorType2()); return ret;};
+	REGISTER_CLASS_AND_BASE(Functor2D,Functor FunctorWrapper);
+	/* do not REGISTER_ATTRIBUTES here, since we are template; derived classes should call REGISTER_ATTRIBUTES(Functor,(their)(own)(attributes)), bypassing Functor2D */
+};
+
+
+

=== added file 'core/GLConfig.hpp'
--- core/GLConfig.hpp	1970-01-01 00:00:00 +0000
+++ core/GLConfig.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,38 @@
+// code not yet for use (6/12/2009); if long here uselessly, delete.
+//
+
+// 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
+#include<yade/core/Serializable.hpp>
+/*! Storage for general 3d view settings.
+
+Is saved along with simulation and passed to every call to render(...).
+Contains more or less what used to be inside OpenGLRenderer.
+
+*/
+class GLConfig: public Serializable{
+
+	Vector3r lightPos,bgColor;
+	Body::id_t currSel;
+	bool dof,id,bbox,geom,wire,intrGeom,intrPhys;
+	int mask;
+	bool scaleDisplacements,scaleRotations;
+	Vector3r displacementScale; Real rotationScale;
+	vector<Se3r> clipPlaneSe3;
+	vector<int> clipPlaneActive; // should be bool, but serialization doesn't handle vector<bool>
+
+	// not saved
+	Vector3r highlightEmission0;
+	Vector3r highlightEmission1;
+
+	// normalized saw signal with given periodicity, with values ∈ 〈0,1〉 */
+	Real normSaw(Real t, Real period){ Real xi=(t-period*((int)(t/period)))/period; /* normalized value, (0-1〉 */ return (xi<.5?2*xi:2-2*xi); }
+	Real normSquare(Real t, Real period){ Real xi=(t-period*((int)(t/period)))/period; /* normalized value, (0-1〉 */ return (xi<.5?0:1); }
+
+	//! wrap number to interval x0…x1
+	Real wrapCell(const Real x, const Real x0, const Real x1);
+	//! wrap point to inside Scene's cell (identity if !Scene::isPeriodic)
+	Vector3r wrapCellPt(const Vector3r& pt, Scene* rb);
+	void drawPeriodicCell(Scene*);
+
+	REGISTER_ATTRIBUTES(Serializable,(dof)(id)(bbox)(geom)(wire)(intrGeom)(intrPhys)(mask)(scaleDisplacements)(scaleRotations)(displacementScale)(rotationScale)(clipPlaneSe3)(clipPlaneActive));
+};

=== added file 'core/GlobalEngine.hpp'
--- core/GlobalEngine.hpp	1970-01-01 00:00:00 +0000
+++ core/GlobalEngine.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,20 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include "Engine.hpp"
+
+class GlobalEngine: public Engine{
+	public :
+		virtual ~GlobalEngine() {};
+	YADE_CLASS_BASE_DOC(GlobalEngine,Engine,"Engine that will generally affect the whole simulation (contrary to PartialEngine).");
+};
+REGISTER_SERIALIZABLE(GlobalEngine);
+
+

=== added file 'core/GroupRelationData.cpp'
--- core/GroupRelationData.cpp	1970-01-01 00:00:00 +0000
+++ core/GroupRelationData.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,315 @@
+/*************************************************************************
+*  Copyright (C) 2008 by Vincent Richefeu                                *
+*  vincent.richefeu@xxxxxxxxxxx                                          *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include "GroupRelationData.hpp"
+
+#ifdef YADE_GROUP_RELATION_DATA
+
+GroupRelationData::GroupRelationData() : ngrp_(2), npar_(0)
+{ 
+  isActivated_ = false;
+}
+
+GroupRelationData::GroupRelationData(unsigned int ngrp) : ngrp_(ngrp), npar_(0)
+{ 
+  isActivated_ = false;
+}
+
+GroupRelationData::~GroupRelationData() 
+{
+  // Free memory for the action table
+/*
+  if (act_ != 0)
+    {
+    for(unsigned int i=0 ; i<ngrp_ ; ++i)
+      {
+      delete [] act_[i];
+      }
+    delete [] act_;
+    act_ = 0;
+    }
+  */
+
+  // Free memory for each parameter table
+  for(unsigned int p=0 ; p<npar_ ; ++p)
+    {
+    if (lpar_[p] != 0)
+      {
+      for(unsigned int i=0 ; i<ngrp_ ; ++i)
+        {
+        delete [] lpar_[p][i];
+        }
+      delete [] lpar_[p];
+      lpar_[p] = 0;
+      }
+    }
+}
+
+// void GroupRelationData::activate()
+// {
+//   istringstream istr;
+//   istr.str(commands_);
+//   read(istr);
+// }
+
+/*
+bool GroupRelationData::act(unsigned int g1, unsigned int g2) const
+{
+  if (g1 < ngrp_ && g2 < ngrp_)
+    return act_[g1][g2];
+  else
+    cerr << "@GroupRelationData::act, bad groupMask number" << endl;
+  
+  return false;
+}
+
+void GroupRelationData::activate(unsigned int g1, unsigned int g2)
+{
+  if (g1 < ngrp_ && g2 < ngrp_)
+    {
+    act_[g1][g2] = true;
+    act_[g2][g1] = true;
+    }
+  else
+    cerr << "@GroupRelationData::activate, bad groupMask number" << endl;
+}
+
+void GroupRelationData::deactivate(unsigned int g1, unsigned int g2)
+{
+  if (g1 < ngrp_ && g2 < ngrp_)
+    {
+    act_[g1][g2] = false;
+    act_[g2][g1] = false;
+    }
+  else
+    cerr << "@GroupRelationData::deactivate, bad groupMask number" << endl;
+}
+*/
+
+bool GroupRelationData::exists(string name)
+{
+  map<string, unsigned int >::const_iterator ip = idParam_.find(name);
+  if (ip == idParam_.end()) return false;
+  else return true;
+}
+
+unsigned int GroupRelationData::getId(string name)
+{
+  map<string, unsigned int >::const_iterator ip = idParam_.find(name);
+  if (ip != idParam_.end())
+    {
+    return (unsigned int) ip->second;
+    }
+  else
+    {
+    return npar_;
+    }    
+}
+
+double GroupRelationData::getParameter(string name, unsigned int g1, unsigned int g2) const
+{
+  // Retrieve the parameter identifier
+  unsigned int idPar;
+  map<string, unsigned int >::const_iterator ip = idParam_.find(name);
+  if (ip != idParam_.end())
+    {
+    idPar = ip->second;
+    }
+  else
+    {
+    cerr << "@GroupRelationData::getParameter, parameter " << name << " not found" << endl;
+    return 0.0;
+    }
+  
+  // Retrieve the value
+  if (g1 < ngrp_ && g2 < ngrp_)
+    {
+    return lpar_[idPar][g1][g2];
+    }
+  else
+    {
+    cerr << "@GroupRelationData::getParameter, bad groupMask number" << endl;
+    }
+  
+  return 0.0;    
+}
+
+double GroupRelationData::getParameterQuickly(unsigned int idPar, unsigned int g1, unsigned int g2) const
+{
+  // Here we have some confidence in the user in order to access more quickly the parameters !
+  return lpar_[idPar][g1][g2];    
+}
+
+void GroupRelationData::setParameter(string name, unsigned int g1, unsigned int g2, double value)
+{
+  // Retrieve the parameter identifier
+  unsigned int idPar;
+  map<string, unsigned int >::const_iterator ip = idParam_.find(name);
+  if (ip != idParam_.end())
+    {
+    idPar = ip->second;
+    }
+  else
+    {
+    cerr << "@GroupRelationData::setParameter, unknown parameter" << name << endl;
+    return;
+    }
+  
+  // Affect the value
+  if (g1 < ngrp_ && g2 < ngrp_)
+    {
+    lpar_[idPar][g1][g2] = value;
+    lpar_[idPar][g2][g1] = value;
+    }
+  else
+    {
+    cerr << "@GroupRelationData::setParameter, bad groupMask number" << endl;
+    }
+  
+  return;    
+}
+
+void GroupRelationData::addParameter(string name)
+{
+  double ** p = 0;
+  
+  //idParam_[name] = npar_++;
+  idParam_.insert(mapIdParam::value_type(name,npar_++));
+  
+  p = new double * [ngrp_];
+  if (p != 0)
+    {
+    for(unsigned int i = 0 ; i < ngrp_ ; ++i)
+      {
+      p[i] = new double [ngrp_];
+      }
+    }
+  else
+    cerr << "@GroupRelationData::addParameter, allocation problem" << endl;
+  
+  for (unsigned int i = 0 ; i < ngrp_ ; ++i)
+    for (unsigned int j = 0 ; j < ngrp_ ; ++j)
+      p[i][j] = 0.0;
+  
+  lpar_.push_back(p);
+}
+
+/*
+void GroupRelationData::initActivator()
+{
+  act_ = new bool * [ngrp_];
+  for(unsigned int i = 0 ; i < ngrp_ ; ++i)
+    {
+    act_[i] = new bool [ngrp_];
+    }
+  
+  // By default, all bodies can act on all other bodies 
+  for (unsigned int i = 0 ; i < ngrp_ ; ++i)
+    for (unsigned int j = 0 ; j < ngrp_ ; ++j)
+      act_[i][j] = true;
+}
+*/
+
+
+void GroupRelationData::read(istream & is)
+{
+  string token;
+  
+  is >> token;	
+  while(is)
+    {	
+    if      (token == "ngrp")      
+      {
+      is >> ngrp_;
+      if (ngrp_ == 0) cerr << "GroupRelationData::read, ngrp can not be 0" << endl;
+      }
+    else if (token == "parameter")
+      { 
+      if (ngrp_ == 0) cerr << "GroupRelationData::read, ngrp can not be 0" << endl;
+      string name;
+      is >> name;
+      addParameter(name);
+      }
+    else if (token == "setall")
+      { 
+      string parName;
+      double value;
+      
+      is >> parName >> value;
+      
+      for (unsigned int g1=0;g1<ngrp_;++g1)
+        for (unsigned int g2=0;g2<ngrp_;++g2)
+          setParameter(parName,g1,g2,value);
+      }
+    else if (token == "set")
+      { 
+      string parName;
+      unsigned int g1,g2;
+      double value;
+      
+      is >> parName >> g1 >> g2 >> value;
+      
+      setParameter(parName,g1,g2,value);
+      }
+    else if (token == "}") break;
+    else cerr << "@GroupRelationData::read, Unknown token: " << token << endl;
+    
+    is >> token;
+    }
+
+    if (ngrp_ > 0) isActivated_ = true;
+}
+
+/*
+void GroupRelationData::write(ostream & os)
+{
+  os << "ngrp " << ngrp_ << endl;
+
+  mapIdParam::iterator imap = idParam_.begin();
+  string parName;
+  while (imap != idParam_.end())
+    {
+    parName = imap->first;
+    os << "parameter " << parName << endl;
+    
+    for (unsigned int g1=0;g1<ngrp_;++g1)
+      {
+      for (unsigned int g2=0;g2<ngrp_;++g2)  
+        {
+        if (lpar_[imap->second][g1][g2]) 
+          {
+          os << "set " << parName << " " 
+          << g1 << " " << g2 << " " 
+          << lpar_[imap->second][g1][g2] << endl;
+          }
+        }
+      }
+    
+    ++imap;
+    }
+  
+}
+*/
+
+void GroupRelationData::postLoad(GroupRelationData&)
+{
+    string cmdstring = "";
+    for (unsigned int i = 0 ; i< commands_.size() ; ++i)
+      cmdstring = cmdstring + commands_[i] + " ";
+
+    istringstream istr;
+    istr.str(cmdstring);
+    
+    cout << istr.str() << endl;
+
+    read(istr);
+}
+
+
+
+#endif

=== added file 'core/GroupRelationData.hpp'
--- core/GroupRelationData.hpp	1970-01-01 00:00:00 +0000
+++ core/GroupRelationData.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,119 @@
+/*************************************************************************
+*  Copyright (C) 2008 by Vincent Richefeu                                *
+*  vincent.richefeu@xxxxxxxxxxx                                          *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+// conditionally disable GroupRelationData, remove the #if 0 to re-enable
+// is anyone using those? Vincent?
+
+#if 0
+#define YADE_GROUP_RELATION_DATA
+
+
+#include<yade/lib-serialization/Serializable.hpp>
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <map>
+#include <vector>
+
+using namespace std;
+
+//! \brief  Define the parameters between groupMasks
+//! \author V. Richefeu
+
+
+//  vector <double **> lpar_
+//  |
+//  |   +------------------------------------+
+//  |   | Kn  |   1     2     4        ...   |  <---- groupMasks
+//  |   | 1   |   1e8   1e8   1e10     ...   |
+//  +---| 2   |         xx    1e8      ...   |
+//  |   | 4   |  (SYM.)       1e8      ...   |
+//  |   | ... |                        ...   |
+//  |   +------------------------------------+
+//  |     ^groupMasks 
+//  |
+//  |   +------------------------------------+
+//  |   | nu  |   1     2     4        ...   |  <---- groupMasks
+//  |   | 1   |   0.4   0.3   0.3      ...   |
+//  +---| 2   |         xx    0.0      ...   |
+//  |   | 4   |  (SYM.)       0.5      ...   |
+//  |   | ... |                        ...   |
+//  |   +------------------------------------+
+//  |     ^groupMasks 
+//  ...
+
+class GroupRelationData : public Serializable
+{
+  typedef map<string ,unsigned int > mapIdParam;
+
+private:
+
+  unsigned int ngrp_;                   // Number of groupMasks
+  unsigned int npar_;                   // Number of parameters
+
+  map <string ,unsigned int > idParam_; // Hash table for parameter identifiers
+  vector <double **> lpar_;             // Table of parameter values
+
+  bool isActivated_;
+  //string commands_;
+  vector<string> commands_;
+    
+public:
+  
+  GroupRelationData(); 
+  GroupRelationData(unsigned int ngrp); 
+  ~GroupRelationData();
+  
+  //void activate();
+  bool isActivated() {return isActivated_;}
+
+  //! Return true if the parameter exist
+  //! \param name  Parameter name 
+  bool exists(string name);
+  
+  //! Get a parameter identifier from his name (returns the number of parameters if name is not found)
+  //! \param name  Parameter name
+  unsigned int getId(string name);
+  
+  //! Get a parameter value from his name (returns 0 in case of failure)
+  //! \param name  Parameter name 
+  //! \param g1    First groupMask
+  //! \param g2    Second groupMask
+  double getParameter(string name, unsigned int g1, unsigned int g2) const;
+  
+  //! Get quickly a parameter value from an identifier (crashes in case of failure)
+  //! \param idPar Parameter identifier (see function getId) 
+  //! \param g1    First groupMask
+  //! \param g2    Second groupMask
+  double getParameterQuickly(unsigned int idPar, unsigned int g1, unsigned int g2) const;
+  
+  //! Set a parameter value
+  //! \param name  Name of the parameter 
+  //! \param g1    First groupMask
+  //! \param g2    Second groupMask
+  //! \param value Parameter value
+  void setParameter(string name, unsigned int g1, unsigned int g2, double value);
+
+  //! Add a new parameter
+  void addParameter(string name);
+  
+  void read(istream & is);  
+  void write(ostream & os);
+
+  REGISTER_ATTRIBUTES(Serializable,(commands_));
+  REGISTER_CLASS_AND_BASE(GroupRelationData,Serializable);
+ 
+  public:
+	void postLoad(GroupRelationData&);
+};
+REGISTER_SERIALIZABLE(GroupRelationData);
+
+#endif

=== added file 'core/IGeom.hpp'
--- core/IGeom.hpp	1970-01-01 00:00:00 +0000
+++ core/IGeom.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,29 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include<yade/lib-base/Math.hpp>
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-multimethods/Indexable.hpp>
+#include<yade/core/Dispatcher.hpp>
+
+class IGeom : public Serializable, public Indexable
+{
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(IGeom,Serializable,"Geometrical configuration of interaction",
+		/*no attrs*/,
+		/*ctor*/,
+		/*py*/
+		YADE_PY_TOPINDEXABLE(IGeom)
+	);
+	REGISTER_INDEX_COUNTER(IGeom);
+};
+
+REGISTER_SERIALIZABLE(IGeom);
+
+

=== added file 'core/IPhys.hpp'
--- core/IPhys.hpp	1970-01-01 00:00:00 +0000
+++ core/IPhys.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,27 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include<yade/lib-base/Math.hpp>
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-multimethods/Indexable.hpp>
+#include<yade/core/Dispatcher.hpp>
+
+class IPhys : public Serializable, public Indexable
+{
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(IPhys,Serializable,"Physical (material) properties of :yref:`interaction<Interaction>`.",
+		/*attrs*/,
+		/*ctor*/,
+		/*py*/YADE_PY_TOPINDEXABLE(IPhys)
+	);
+	REGISTER_INDEX_COUNTER(IPhys);
+};
+REGISTER_SERIALIZABLE(IPhys);
+
+

=== added file 'core/Interaction.cpp'
--- core/Interaction.cpp	1970-01-01 00:00:00 +0000
+++ core/Interaction.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,39 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include"Interaction.hpp"
+
+#include<yade/core/Scene.hpp>
+
+Interaction::Interaction(Body::id_t newId1,Body::id_t newId2): id1(newId1), id2(newId2), cellDist(Vector3i(0,0,0)){ reset(); }
+
+bool Interaction::isFresh(Scene* rb){ return iterMadeReal==rb->iter;}
+
+void Interaction::init(){
+	isNeighbor = true;//NOTE : TriangulationCollider needs that
+	iterMadeReal=-1;
+	functorCache.geomExists=true;
+	//functorCache.geom=shared_ptr<IGeomFunctor>(); functorCache.phys=shared_ptr<IPhysFunctor>(); functorCache.constLaw=shared_ptr<LawFunctor>();
+}
+
+void Interaction::reset(){
+	geom=shared_ptr<IGeom>();
+	phys=shared_ptr<IPhys>();
+	init();
+}
+
+
+void Interaction::swapOrder(){
+	if(geom || phys){
+		throw std::logic_error("Bodies in interaction cannot be swapped if they have geom or phys.");
+	}
+	std::swap(id1,id2);
+	cellDist*=-1;
+}

=== added file 'core/Interaction.hpp'
--- core/Interaction.hpp	1970-01-01 00:00:00 +0000
+++ core/Interaction.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,76 @@
+// Copyright (C) 2004 by Olivier Galizzi <olivier.galizzi@xxxxxxx>
+//  Copyright (C) 2004 by Janek Kozicki <cosurgi@xxxxxxxxxx>
+//
+#pragma once
+#include<yade/lib-serialization/Serializable.hpp>
+// keep those two here, template instantiation & boost::python gets broken otherwise, e.g. https://bugs.launchpad.net/bugs/618766
+#include<yade/core/IGeom.hpp> 
+#include<yade/core/IPhys.hpp>
+#include<yade/core/Body.hpp>
+
+
+class IGeomFunctor;
+class IPhysFunctor;
+class LawFunctor;
+class Scene;
+
+class Interaction : public Serializable
+{
+	private	:
+		friend class IPhysDispatcher;
+		friend class InteractionLoop;
+	public :
+		bool isReal() const {return (bool)geom && (bool)phys;}
+		//! If this interaction was just created in this step (for the constitutive law, to know that it is the first time there)
+		bool isFresh(Scene* rb);
+
+		//! At which step this interaction was last detected by the collider. InteractionLoop will remove it if InteractionContainer::iterColliderLastRun==currentStep and iterLastSeen<currentStep
+		long iterLastSeen;      
+		//! NOTE : TriangulationCollider needs this (nothing else)
+		bool isNeighbor;
+
+		Interaction(Body::id_t newId1,Body::id_t newId2);
+
+		const Body::id_t& getId1() const {return id1;};
+		const Body::id_t& getId2() const {return id2;};
+
+		//! swaps order of bodies within the interaction
+		void swapOrder();
+
+		bool operator<(const Interaction& other) const { return getId1()<other.getId1() || (getId1()==other.getId1() && getId2()<other.getId2()); }
+
+		//! cache functors that are called for this interaction. Currently used by InteractionLoop.
+		struct {
+			// Whether geometry dispatcher exists at all; this is different from !geom, since that can mean we haven't populated the cache yet.
+			// Therefore, geomExists must be initialized to true first (done in Interaction::reset() called from ctor).
+			bool geomExists;
+			#ifdef YADE_DEVIRT_FUNCTORS
+				// is a IGeomFunctor::StaticFuncPtr, but we would have to #include a file from pkg-common here
+				// cast at those few places instead, for now
+				void* geomPtr;
+			#endif
+			// shared_ptr's are initialized to NULLs automagically
+			shared_ptr<IGeomFunctor> geom;
+			shared_ptr<IPhysFunctor> phys;
+			shared_ptr<LawFunctor> constLaw;
+		} functorCache;
+
+		//! Reset interaction to the intial state (keep only body ids)
+		void reset();
+		//! common initialization called from both constructor and reset()
+		void init();
+			
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Interaction,Serializable,"Interaction between pair of bodies.",
+		((Body::id_t,id1,0,Attr::readonly,":yref:`Id<Body::id>` of the first body in this interaction."))
+		((Body::id_t,id2,0,Attr::readonly,":yref:`Id<Body::id>` of the first body in this interaction."))
+		((long,iterMadeReal,-1,,"Step number at which the interaction was fully (in the sense of geom and phys) created. (Should be touched only by :yref:`IPhysDispatcher` and :yref:`InteractionLoop`, therefore they are made friends of Interaction"))
+		((shared_ptr<IGeom>,geom,,,"Geometry part of the interaction."))
+		((shared_ptr<IPhys>,phys,,,"Physical (material) part of the interaction."))
+		((Vector3i,cellDist,Vector3i(0,0,0),,"Distance of bodies in cell size units, if using periodic boundary conditions; id2 is shifted by this number of cells from its :yref:`State::pos` coordinates for this interaction to exist. Assigned by the collider.\n\n.. warning::\n\t(internal)  cellDist must survive Interaction::reset(), it is only initialized in ctor. Interaction that was cancelled by the constitutive law, was reset() and became only potential must have the priod information if the geometric functor again makes it real. Good to know after few days of debugging that :-)")),
+		/* ctor */ init(),
+		/*py*/
+		.add_property("isReal",&Interaction::isReal,"True if this interaction has both geom and phys; False otherwise.")
+	);
+};
+
+REGISTER_SERIALIZABLE(Interaction);

=== added file 'core/InteractionContainer.cpp'
--- core/InteractionContainer.cpp	1970-01-01 00:00:00 +0000
+++ core/InteractionContainer.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,155 @@
+// 2008 © Sergei Dorofeenko <sega@xxxxxxxxxxxxxxxx>
+// 2009,2010 © Václav Šmilauer <eudoxos@xxxxxxxx>
+
+#include "InteractionContainer.hpp"
+
+#ifdef YADE_OPENMP
+	#include<omp.h>
+#endif
+
+
+bool InteractionContainer::insert(const shared_ptr<Interaction>& i){
+	boost::mutex::scoped_lock lock(drawloopmutex);
+	Body::id_t id1=i->getId1(), id2=i->getId2();
+	if (id1>id2) swap(id1,id2);
+
+	if((size_t)id1>=vecmap.size()) vecmap.resize(id1+1); // resize linear map to accomodate id1
+
+	// inserted element maps id2->currSize; currSize will be incremented immediately
+	if(!vecmap[id1].insert(pair<Body::id_t,size_t>(id2,currSize)).second) return false; // id1,id2 pair already present
+		
+	//assert(intrs.size()==currSize);
+	intrs.resize(++currSize); // currSize updated
+	//assert(intrs.size()==currSize);
+
+	intrs[currSize-1]=i; // assign last element
+	
+	return true;
+}
+
+
+bool InteractionContainer::insert(Body::id_t id1,Body::id_t id2)
+{
+	shared_ptr<Interaction> i(new Interaction(id1,id2) );
+	return insert(i);	
+}
+
+
+void InteractionContainer::clear(){
+	boost::mutex::scoped_lock lock(drawloopmutex);
+
+	vecmap.clear();
+	intrs.clear();
+	pendingErase.clear();
+	currSize=0;
+}
+
+
+bool InteractionContainer::erase(Body::id_t id1,Body::id_t id2){
+	boost::mutex::scoped_lock lock(drawloopmutex);
+	if (id1>id2) swap(id1,id2);
+	if((size_t)id1>=vecmap.size()) return false; // id1 out of bounds
+	map<Body::id_t,size_t>::iterator mii;
+	mii=vecmap[id1].find(id2);
+	if(mii==vecmap[id1].end()) return false; // id2 not in interaction with id1
+	// interaction found; erase from vecmap and then from intrs as well
+	size_t iid=(*mii).second;
+	vecmap[id1].erase(mii);
+	// iid is not the last element; we have to move last one to its place
+	if (iid<currSize-1) {
+		intrs[iid]=intrs[currSize-1];
+		// adjust map, so that id1,id2 points to element at iid, which used to be last
+		id1=intrs[iid]->getId1();
+		id2=intrs[iid]->getId2();
+		if (id1>id2) swap(id1,id2);
+		vecmap[id1][id2]=iid;
+	}
+	//assert(intrs.size()==currSize);
+	// in either case, last element can be removed now
+	intrs.resize(--currSize); // currSize updated
+	//assert(intrs.size()==currSize);
+	return true;
+}
+
+
+const shared_ptr<Interaction>& InteractionContainer::find(Body::id_t id1,Body::id_t id2){
+	if (id1>id2) swap(id1,id2);
+
+	if ((size_t)id1>=vecmap.size()) { empty=shared_ptr<Interaction>(); return empty; }
+
+	map<Body::id_t,size_t>::iterator mii;
+	mii = vecmap[id1].find(id2);
+	if (mii!=vecmap[id1].end()) return intrs[(*mii).second];
+	else { empty=shared_ptr<Interaction>(); return empty; }
+}
+
+void InteractionContainer::requestErase(Body::id_t id1, Body::id_t id2, bool force){
+	find(id1,id2)->reset(); IdsForce v={id1,id2,force};
+	#ifdef YADE_OPENMP
+		threadsPendingErase[omp_get_thread_num()].push_back(v);
+	#else
+		pendingErase.push_back(v);
+	#endif
+}
+
+void InteractionContainer::clearPendingErase(){
+	#ifdef YADE_OPENMP
+		FOREACH(list<IdsForce>& pendingErase, threadsPendingErase){
+			pendingErase.clear();
+		}
+	#else
+		pendingErase.clear();
+	#endif
+}
+
+int InteractionContainer::unconditionalErasePending(){
+	int ret=0;
+	#ifdef YADE_OPENMP
+		// shadow this->pendingErase by the local variable, to share code
+		FOREACH(list<IdsForce>& pendingErase, threadsPendingErase){
+	#endif
+			if(!pendingErase.empty()){
+				FOREACH(const IdsForce& p, pendingErase){ ret++; erase(p.id1,p.id2); }
+				pendingErase.clear();
+			}
+	#ifdef YADE_OPENMP
+		}
+	#endif
+	return ret;
+}
+
+void InteractionContainer::eraseNonReal(){
+	typedef pair<int,int> Ids;
+	std::list<Ids> ids;
+	FOREACH(const shared_ptr<Interaction>& i, *this){
+		if(!i->isReal()) ids.push_back(Ids(i->getId1(),i->getId2()));
+	}
+	FOREACH(const Ids& id, ids){
+		this->erase(id.first,id.second);
+	}
+}
+
+// compare interaction based on their first id
+struct compPtrInteraction{
+	bool operator() (const shared_ptr<Interaction>& i1, const shared_ptr<Interaction>& i2) const {
+		return (*i1)<(*i2);
+	}
+};
+
+void InteractionContainer::preSave(InteractionContainer&){
+	FOREACH(const shared_ptr<Interaction>& I, *this){
+		if(I->geom || I->phys) interaction.push_back(I);
+		// since requestErase'd interactions have no interaction physics/geom, they are not saved
+	}
+	if(serializeSorted) std::sort(interaction.begin(),interaction.end(),compPtrInteraction());
+}
+void InteractionContainer::postSave(InteractionContainer&){ interaction.clear(); }
+
+
+void InteractionContainer::preLoad(InteractionContainer&){ interaction.clear(); }
+void InteractionContainer::postLoad(InteractionContainer&){
+	clear();
+	FOREACH(const shared_ptr<Interaction>& I, interaction){ insert(I); }
+	interaction.clear();
+}
+

=== added file 'core/InteractionContainer.hpp'
--- core/InteractionContainer.hpp	1970-01-01 00:00:00 +0000
+++ core/InteractionContainer.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,145 @@
+// 2004 © Olivier Galizzi <olivier.galizzi@xxxxxxx>
+// 2004 © Janek Kozicki <cosurgi@xxxxxxxxxx>
+// 2010 © Václav Šmilauer <eudoxos@xxxxxxxx>
+
+#pragma once
+
+#include<yade/lib-serialization/Serializable.hpp>
+#include<boost/thread/mutex.hpp>
+
+#ifdef YADE_OPENMP
+	#include<omp.h>
+#endif
+
+#include<yade/core/Interaction.hpp>
+
+#include<boost/foreach.hpp>
+#ifndef FOREACH
+#  define FOREACH BOOST_FOREACH
+#endif
+
+/* This InteractionContainer implementation stores interactions internally in 2 containers:
+a std::vector (which allows for const-time linear traversal) and
+std::vector of id1 holding std::map of id2 (allowing for fast search by id1,id2). Synchronization
+of both is handles by insert & erase methods.
+
+It was originally written by 2008 © Sergei Dorofeenko <sega@xxxxxxxxxxxxxxxx>,
+later devirtualized and put here.
+
+Alternative implementations of InteractionContainer should implement the same API. Due to performance
+reasons, no base class with virtual methods defining such API programatically is defined (it could
+be possible to create class template for this, though).
+*/
+class InteractionContainer: public Serializable{
+	private :
+		typedef vector<shared_ptr<Interaction> > ContainerT;
+		// linear array of container interactions
+		vector<shared_ptr<Interaction> > intrs;
+		// array where vecmap[id1] maps id2 to index in intrs (unsigned int)
+		vector<map<Body::id_t,size_t> > vecmap;
+		// always in sync with intrs.size()
+		size_t currSize;
+		shared_ptr<Interaction> empty;
+		// used only during serialization/deserialization
+		vector<shared_ptr<Interaction> > interaction;
+	public :
+		InteractionContainer(): currSize(0),serializeSorted(false),iterColliderLastRun(-1){
+			#ifdef YADE_OPENMP
+				threadsPendingErase.resize(omp_get_max_threads());
+			#endif
+		}
+		void clear();
+		// iterators
+		typedef ContainerT::iterator iterator;
+		typedef ContainerT::const_iterator const_iterator;
+		iterator begin(){return intrs.begin();}
+     	iterator end()  {return intrs.end();}
+		const_iterator begin() const {return intrs.begin();}
+     	const_iterator end()   const {return intrs.end();}
+		// insertion/deletion
+		bool insert(Body::id_t id1,Body::id_t id2);
+		bool insert(const shared_ptr<Interaction>& i);
+		bool erase(Body::id_t id1,Body::id_t id2);
+		const shared_ptr<Interaction>& find(Body::id_t id1,Body::id_t id2);
+		// index access
+		shared_ptr<Interaction>& operator[](size_t id){return intrs[id];}
+		const shared_ptr<Interaction>& operator[](size_t id) const { return intrs[id];}
+		size_t size(){ return currSize; }
+		// simulation API
+
+		//! Erase all non-real (in term of Interaction::isReal()) interactions
+		void eraseNonReal();
+
+		// mutual exclusion to avoid crashes in the rendering loop
+		boost::mutex drawloopmutex;
+		// sort interactions before serializations; useful if comparing XML files from different runs (false by default)
+		bool serializeSorted;
+		// iteration number when the collider was last run; set by the collider, if it wants interactions that were not encoutered in that step to be deleted by InteractionLoop (such as SpatialQuickSortCollider). Other colliders (such as InsertionSortCollider) set it it -1, which is the default
+		long iterColliderLastRun;
+		//! Ask for erasing the interaction given (from the constitutive law); this resets the interaction (to the initial=potential state) and collider should traverse pendingErase to decide whether to delete the interaction completely or keep it potential
+		void requestErase(Body::id_t id1, Body::id_t id2, bool force=false);
+		/*! List of pairs of interactions that will be (maybe) erased by the collider; if force==true, they will be deleted unconditionally.
+			
+			If accessed from within a parallel section, pendingEraseMutex must be locked (this is done inside requestErase for you).
+
+			If there is, at one point, a multi-threaded collider, pendingEraseMutex should be moved to the public part and used from there as well.
+		*/
+		struct IdsForce{ Body::id_t id1; Body::id_t id2; bool force; };
+		#ifdef YADE_OPENMP
+			vector<list<IdsForce> > threadsPendingErase;
+		#endif
+		list<IdsForce> pendingErase;
+		/*! Erase all pending interactions unconditionally.
+
+			This should be called only in rare cases that collider is not used but still interactions should be erased.
+			Otherwise collider should decide on a case-by-case basis, which interaction to erase for good and which to keep in the potential state
+			(without geom and phys).
+
+			This function doesn't lock pendingEraseMutex, as it is (supposedly) called from no-parallel sections only once per iteration
+		*/
+		int unconditionalErasePending();
+
+		/*! Clear the list of interaction pending erase: all interactions queued for considering erasing them
+		will be dropped; useful for colliders that handle that by themselves, without needing the hint;
+		with openMP, it would not be enough to call pendingErase->clear(), this helper function 
+		does it for all threads. Use this only if you understand this explanation. */
+		void clearPendingErase();
+
+		/*! Traverse all pending interactions and erase them if the (T*)->shouldBeErased(id1,id2) return true
+			and keep it if it return false; finally, pendingErase will be clear()'ed.
+
+			Class using this interface (which is presumably a collider) must define the 
+					
+				bool shouldBeErased(Body::id_t, Body::id_t) const
+
+			method which will be called for every interaction.
+
+			Returns number of interactions, have they been erased or not (this is useful to check if there were some erased, after traversing those)
+		*/
+		template<class T> int erasePending(const T& t, Scene* rb){
+			int ret=0;
+			#ifdef YADE_OPENMP
+				// shadow the this->pendingErase by the local variable, to share the code
+				FOREACH(list<IdsForce>& pendingErase, threadsPendingErase){
+			#endif
+					FOREACH(const IdsForce& p, pendingErase){
+						ret++;
+						if(p.force || t.shouldBeErased(p.id1,p.id2,rb)) erase(p.id1,p.id2);
+					}
+					pendingErase.clear();
+			#ifdef YADE_OPENMP
+				}
+			#endif
+			return ret;
+		}
+
+	void preLoad(InteractionContainer&);
+	void postLoad(InteractionContainer&);
+	void preSave(InteractionContainer&);
+	void postSave(InteractionContainer&);
+
+
+	REGISTER_ATTRIBUTES(Serializable,(interaction)(serializeSorted));
+	REGISTER_CLASS_AND_BASE(InteractionContainer,Serializable);
+};
+REGISTER_SERIALIZABLE(InteractionContainer);

=== added file 'core/Material.cpp'
--- core/Material.cpp	1970-01-01 00:00:00 +0000
+++ core/Material.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,32 @@
+#include<stdexcept>
+#include<yade/core/Material.hpp>
+#include<yade/core/Scene.hpp>
+#include<boost/foreach.hpp>
+#ifndef FOREACH
+	#define FOREACH BOOST_FOREACH
+#endif
+
+Material::~Material(){}
+
+const shared_ptr<Material> Material::byId(int id, Scene* w_){
+	Scene* w=w_?w_:Omega::instance().getScene().get();
+	assert(id>=0 && (size_t)id<w->materials.size());
+	assert(w->materials[id]->id == id);
+	return w->materials[id];
+}
+
+const shared_ptr<Material> Material::byLabel(const std::string& label, Scene* w_){
+	Scene* w=w_?w_:Omega::instance().getScene().get();
+	FOREACH(const shared_ptr<Material>& m, w->materials){
+		if(m->label == label) return m;
+	}
+	throw std::runtime_error(("No material labeled `"+label+"'.").c_str());
+}
+
+const int Material::byLabelIndex(const std::string& label, Scene* w_){
+	Scene* w=w_?w_:Omega::instance().getScene().get(); size_t iMax=w->materials.size();
+	for(size_t i=0; i<iMax; i++){
+		if(w->materials[i]->label==label) return i;
+	}
+	throw std::runtime_error(("No material labeled `"+label+"'.").c_str());
+}

=== added file 'core/Material.hpp'
--- core/Material.hpp	1970-01-01 00:00:00 +0000
+++ core/Material.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,50 @@
+// 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
+#pragma once
+#include<string>
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-multimethods/Indexable.hpp>
+#include<yade/core/State.hpp>
+#include<yade/core/Dispatcher.hpp>
+
+
+class Scene;
+/*! Material properties associated with a body.
+
+Historical note: this used to be part of the PhysicalParameters class.
+The other data are now in the State class.
+*/
+class Material: public Serializable, public Indexable{
+	public:
+		virtual ~Material();
+
+		//! Function to return empty default-initialized instance of State that 
+		// is supposed to go along with this Material. Don't override unless you need
+		// something else than basic State.
+		virtual shared_ptr<State> newAssocState() const { return shared_ptr<State>(new State); }
+		/*! Function that returns true if given State instance is what this material expects.
+			
+			Base Material class has no requirements, but the check would normally look like this:
+
+				return (bool)dynamic_cast<State*> state;
+		*/
+		virtual bool stateTypeOk(State*) const { return true; }
+
+		static const shared_ptr<Material> byId(int id, Scene* scene=NULL);
+		static const shared_ptr<Material> byId(int id, shared_ptr<Scene> scene) {return byId(id,scene.get());}
+		static const shared_ptr<Material> byLabel(const std::string& label, Scene* scene=NULL);
+		static const shared_ptr<Material> byLabel(const std::string& label, shared_ptr<Scene> scene) {return byLabel(label,scene.get());}
+		// return index of material, given its label
+		static const int byLabelIndex(const std::string& label, Scene* scene=NULL);
+
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Material,Serializable,"Material properties of a :yref:`body<Body>`.",
+		((int,id,((void)"not shared",-1),Attr::readonly,"Numeric id of this material; is non-negative only if this Material is shared (i.e. in O.materials), -1 otherwise. This value is set automatically when the material is inserted to the simulation via :yref:`O.materials.append<MaterialContainer.append>`. (This id was necessary since before boost::serialization was used, shared pointers were not tracked properly; it might disappear in the future)"))
+		((string,label,,,"Textual identifier for this material; can be used for shared materials lookup in :yref:`MaterialContainer`."))
+		((Real,density,1000,,"Density of the material [kg/m³]")),
+		/* ctor */,
+		/*py*/
+		.def("newAssocState",&Material::newAssocState,"Return new :yref:`State` instance, which is associated with this :yref:`Material`. Some materials have special requirement on :yref:`Body::state` type and calling this function when the body is created will ensure that they match. (This is done automatically if you use utils.sphere, … functions from python).")
+		YADE_PY_TOPINDEXABLE(Material)
+	);
+	REGISTER_INDEX_COUNTER(Material);
+};
+REGISTER_SERIALIZABLE(Material);

=== added file 'core/Omega.cpp'
--- core/Omega.cpp	1970-01-01 00:00:00 +0000
+++ core/Omega.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,260 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include"Omega.hpp"
+#include"Scene.hpp"
+#include"TimeStepper.hpp"
+#include"ThreadRunner.hpp"
+#include<yade/lib-base/Math.hpp>
+#include<yade/lib-multimethods/FunctorWrapper.hpp>
+#include<yade/lib-multimethods/Indexable.hpp>
+#include<cstdlib>
+#include<boost/filesystem/operations.hpp>
+#include<boost/filesystem/convenience.hpp>
+#include<boost/filesystem/exception.hpp>
+#include<boost/algorithm/string.hpp>
+#include<boost/thread/mutex.hpp>
+#include<boost/version.hpp>
+#include<boost/python.hpp>
+
+#include<yade/lib-serialization/ObjectIO.hpp>
+
+
+#include<cxxabi.h>
+
+#if BOOST_VERSION<103500
+class RenderMutexLock: public boost::try_mutex::scoped_try_lock{
+	public:
+	RenderMutexLock(): boost::try_mutex::scoped_try_lock(Omega::instance().renderMutex,true){/*cerr<<"Lock renderMutex"<<endl;*/}
+	~RenderMutexLock(){/* cerr<<"Unlock renderMutex"<<endl; */}
+};
+#else
+class RenderMutexLock: public boost::mutex::scoped_lock{
+	public:
+	RenderMutexLock(): boost::mutex::scoped_lock(Omega::instance().renderMutex){/* cerr<<"Lock renderMutex"<<endl; */}
+	~RenderMutexLock(){/* cerr<<"Unlock renderMutex"<<endl;*/ }
+};
+#endif
+
+CREATE_LOGGER(Omega);
+SINGLETON_SELF(Omega);
+
+const map<string,DynlibDescriptor>& Omega::getDynlibsDescriptor(){return dynlibs;}
+
+const shared_ptr<Scene>& Omega::getScene(){return scene;}
+void Omega::resetScene(){ RenderMutexLock lock; scene = shared_ptr<Scene>(new Scene);}
+
+Real Omega::getRealTime(){ return (microsec_clock::local_time()-startupLocalTime).total_milliseconds()/1e3; }
+time_duration Omega::getRealTime_duration(){return microsec_clock::local_time()-startupLocalTime;}
+
+
+void Omega::initTemps(){
+	char dirTemplate[]="/tmp/yade-XXXXXX";
+	tmpFileDir=mkdtemp(dirTemplate);
+	tmpFileCounter=0;
+}
+
+void Omega::cleanupTemps(){
+	filesystem::path tmpPath(tmpFileDir);
+	filesystem::remove_all(tmpPath);
+}
+
+std::string Omega::tmpFilename(){
+	if(tmpFileDir.empty()) throw runtime_error("tmpFileDir empty; Omega::initTemps not yet called()?");
+	boost::mutex::scoped_lock lock(tmpFileCounterMutex);
+	return tmpFileDir+"/tmp-"+lexical_cast<string>(tmpFileCounter++);
+}
+
+void Omega::reset(){
+	stop();
+	init();
+}
+
+void Omega::init(){
+	sceneFile="";
+	resetScene();
+	sceneAnother=shared_ptr<Scene>(new Scene);
+	timeInit();
+	createSimulationLoop();
+}
+
+void Omega::timeInit(){
+	startupLocalTime=microsec_clock::local_time();
+}
+
+void Omega::createSimulationLoop(){	simulationLoop=shared_ptr<ThreadRunner>(new ThreadRunner(&simulationFlow_));}
+void Omega::stop(){ LOG_DEBUG("");  if (simulationLoop&&simulationLoop->looping())simulationLoop->stop(); if (simulationLoop) simulationLoop=shared_ptr<ThreadRunner>(); }
+
+/* WARNING: even a single simulation step is run asynchronously; the call will return before the iteration is finished. */
+void Omega::step(){
+	if (simulationLoop){
+		simulationLoop->spawnSingleAction();
+	}
+}
+
+void Omega::run(){
+	if(!simulationLoop){ LOG_ERROR("No Omega::simulationLoop? Creating one (please report bug)."); createSimulationLoop(); }
+	if (simulationLoop && !simulationLoop->looping()){
+		simulationLoop->start();
+	}
+}
+
+
+void Omega::pause(){
+	if (simulationLoop && simulationLoop->looping()){
+		simulationLoop->stop();
+	}
+}
+
+bool Omega::isRunning(){ if(simulationLoop) return simulationLoop->looping(); else return false; }
+
+void Omega::buildDynlibDatabase(const vector<string>& dynlibsList){	
+	LOG_DEBUG("called with "<<dynlibsList.size()<<" plugins.");
+	boost::python::object wrapperScope=boost::python::import("yade.wrapper");
+	std::list<string> pythonables;
+	FOREACH(string name, dynlibsList){
+		shared_ptr<Factorable> f;
+		try {
+			LOG_DEBUG("Factoring plugin "<<name);
+			f = ClassFactory::instance().createShared(name);
+			dynlibs[name].isIndexable    = dynamic_pointer_cast<Indexable>(f);
+			dynlibs[name].isFactorable   = dynamic_pointer_cast<Factorable>(f);
+			dynlibs[name].isSerializable = dynamic_pointer_cast<Serializable>(f);
+			for(int i=0;i<f->getBaseClassNumber();i++){
+				dynlibs[name].baseClasses.insert(f->getBaseClassName(i));
+			}
+			if(dynlibs[name].isSerializable) pythonables.push_back(name);
+		}
+		catch (std::runtime_error& e){
+			/* FIXME: this catches all errors! Some of them are not harmful, however:
+			 * when a class is not factorable, it is OK to skip it; */	
+		}
+	}
+	// handle Serializable specially
+	//Serializable().pyRegisterClass(wrapperScope);
+	/* python classes must be registered such that base classes come before derived ones;
+	for now, just loop until we succeed; proper solution will be to build graphs of classes
+	and traverse it from the top. It will be done once all classes are pythonable. */
+	for(int i=0; i<100 && pythonables.size()>0; i++){
+		if(getenv("YADE_DEBUG")) cerr<<endl<<"[[[ Round "<<i<<" ]]]: ";
+		std::list<string> done;
+		for(std::list<string>::iterator I=pythonables.begin(); I!=pythonables.end(); ){
+			shared_ptr<Serializable> s=static_pointer_cast<Serializable>(ClassFactory::instance().createShared(*I));
+			try{
+				if(getenv("YADE_DEBUG")) cerr<<"{{"<<*I<<"}}";
+				s->pyRegisterClass(wrapperScope);
+				std::list<string>::iterator prev=I++;
+				pythonables.erase(prev);
+			} catch (...){
+				if(getenv("YADE_DEBUG")){ cerr<<"["<<*I<<"]"; PyErr_Print(); }
+				boost::python::handle_exception();
+				I++;
+			}
+		}
+	}
+
+	map<string,DynlibDescriptor>::iterator dli    = dynlibs.begin();
+	map<string,DynlibDescriptor>::iterator dliEnd = dynlibs.end();
+	for( ; dli!=dliEnd ; ++dli){
+		set<string>::iterator bci    = (*dli).second.baseClasses.begin();
+		set<string>::iterator bciEnd = (*dli).second.baseClasses.end();
+		for( ; bci!=bciEnd ; ++bci){
+			string name = *bci;
+			if (name=="Dispatcher1D" || name=="Dispatcher2D") (*dli).second.baseClasses.insert("Dispatcher");
+			else if (name=="Functor1D" || name=="Functor2D") (*dli).second.baseClasses.insert("Functor");
+			else if (name=="Serializable") (*dli).second.baseClasses.insert("Factorable");
+			else if (name!="Factorable" && name!="Indexable") {
+				shared_ptr<Factorable> f = ClassFactory::instance().createShared(name);
+				for(int i=0;i<f->getBaseClassNumber();i++)
+					dynlibs[name].baseClasses.insert(f->getBaseClassName(i));
+			}
+		}
+	}
+}
+
+
+bool Omega::isInheritingFrom(const string& className, const string& baseClassName){
+	return (dynlibs[className].baseClasses.find(baseClassName)!=dynlibs[className].baseClasses.end());
+}
+
+bool Omega::isInheritingFrom_recursive(const string& className, const string& baseClassName){
+	if (dynlibs[className].baseClasses.find(baseClassName)!=dynlibs[className].baseClasses.end()) return true;
+	FOREACH(const string& parent,dynlibs[className].baseClasses){
+		if(isInheritingFrom_recursive(parent,baseClassName)) return true;
+	}
+	return false;
+}
+
+void Omega::loadPlugins(vector<string> pluginFiles){
+	FOREACH(const string& plugin, pluginFiles){
+		LOG_DEBUG("Loading plugin "<<plugin);
+		if(!ClassFactory::instance().load(plugin)){
+			string err=ClassFactory::instance().lastError();
+			if(err.find(": undefined symbol: ")!=std::string::npos){
+				size_t pos=err.rfind(":");	assert(pos!=std::string::npos);
+				std::string sym(err,pos+2); //2 removes ": " from the beginning
+				int status=0; char* demangled_sym=abi::__cxa_demangle(sym.c_str(),0,0,&status);
+				LOG_FATAL(plugin<<": undefined symbol `"<<demangled_sym<<"'"); LOG_FATAL(plugin<<": "<<err); LOG_FATAL("Bailing out.");
+			}
+			else {
+				LOG_FATAL(plugin<<": "<<err<<" ."); /* leave space to not to confuse c++filt */ LOG_FATAL("Bailing out.");
+			}
+			abort();
+		}
+	}
+	list<string>& plugins(ClassFactory::instance().pluginClasses);
+	plugins.sort(); plugins.unique();
+	buildDynlibDatabase(vector<string>(plugins.begin(),plugins.end()));
+}
+
+void Omega::loadSimulation(const string& f){
+	bool isMem=algorithm::starts_with(f,":memory:");
+	if(!isMem && !filesystem::exists(f)) throw runtime_error("Simulation file to load doesn't exist: "+f);
+	if(isMem && memSavedSimulations.count(f)==0) throw runtime_error("Cannot load nonexistent memory-saved simulation "+f);
+	
+	LOG_INFO("Loading file "+f);
+	{
+		stop(); // stop current simulation if running
+		resetScene();
+		RenderMutexLock lock;
+		if(isMem){
+			istringstream iss(memSavedSimulations[f]);
+			yade::ObjectIO::load<typeof(scene),boost::archive::binary_iarchive>(iss,"scene",scene);
+		} else {
+			yade::ObjectIO::load(f,"scene",scene);
+		}
+	}
+	if(scene->getClassName()!="Scene") throw logic_error("Wrong file format (scene is not a Scene!?) in "+f);
+	sceneFile=f;
+	timeInit();
+	LOG_DEBUG("Simulation loaded");
+}
+
+
+
+void Omega::saveSimulation(const string& f){
+	if(f.size()==0) throw runtime_error("f of file to save has zero length.");
+	LOG_INFO("Saving file " << f);
+	if(algorithm::starts_with(f,":memory:")){
+		if(memSavedSimulations.count(f)>0) LOG_INFO("Overwriting in-memory saved simulation "<<f);
+		ostringstream oss;
+		yade::ObjectIO::save<typeof(scene),boost::archive::binary_oarchive>(oss,"scene",scene);
+		memSavedSimulations[f]=oss.str();
+	}
+	else {
+		// handles automatically the XML/binary distinction as well as gz/bz2 compression
+		yade::ObjectIO::save(f,"scene",scene); 
+	}
+	sceneFile=f;
+}
+
+
+
+

=== added file 'core/Omega.hpp'
--- core/Omega.hpp	1970-01-01 00:00:00 +0000
+++ core/Omega.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,130 @@
+/*************************************************************************
+* Copyright (C) 2004 by Olivier Galizzi         *
+* olivier.galizzi@xxxxxxx            *
+* Copyright (C) 2004 by Janek Kozicki         *
+* cosurgi@xxxxxxxxxx             *
+*                  *
+* This program is free software; it is licensed under the terms of the *
+* GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+// qt3 sucks
+#ifdef QT_MOC_CPP
+	#undef slots
+	#include<Python.h>
+	#define slots slots
+#else
+	#ifdef slots
+	 #undef slots
+	 #include<Python.h>
+	 #define slots
+	#else
+	 #include<Python.h>
+	#endif
+#endif
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <fstream>
+#include <set>
+#include <list>
+#include <time.h>
+#include <boost/thread/thread.hpp>
+#include <iostream>
+
+#include<yade/lib-base/Math.hpp>
+#include<yade/lib-factory/ClassFactory.hpp>
+
+#include<yade/lib-base/Singleton.hpp>
+
+#include "SimulationFlow.hpp"
+
+
+#ifndef FOREACH
+# define FOREACH BOOST_FOREACH
+#endif
+
+class Scene;
+class ThreadRunner;
+
+using namespace boost;
+using namespace boost::posix_time;
+using namespace std;
+
+struct DynlibDescriptor{
+	set<string> baseClasses;
+	bool isIndexable, isFactorable, isSerializable;
+};
+
+class Omega: public Singleton<Omega>{
+	shared_ptr<ThreadRunner> simulationLoop;
+	SimulationFlow simulationFlow_;
+	map<string,DynlibDescriptor> dynlibs; // FIXME : should store that in ClassFactory ?
+	void buildDynlibDatabase(const vector<string>& dynlibsList); // FIXME - maybe in ClassFactory ?
+	
+	shared_ptr<Scene> scene;
+	shared_ptr<Scene> sceneAnother; // used for temporarily running different simulation, in Omega().switchscene()
+
+	ptime startupLocalTime;
+
+	map<string,string> memSavedSimulations;
+
+	// to avoid accessing simulation when it is being loaded (should avoid crashes with the UI)
+	boost::mutex loadingSimulationMutex;
+	boost::mutex tmpFileCounterMutex;
+	long tmpFileCounter;
+	std::string tmpFileDir;
+
+	public:
+		// management, not generally useful
+		void init();
+		void reset();
+		void timeInit();
+		void initTemps();
+		void cleanupTemps();
+		const map<string,DynlibDescriptor>& getDynlibsDescriptor();
+		void loadPlugins(vector<string> pluginFiles);
+		bool isInheritingFrom(const string& className, const string& baseClassName );
+		bool isInheritingFrom_recursive(const string& className, const string& baseClassName );
+		void createSimulationLoop();
+		bool hasSimulationLoop(){return (bool)(simulationLoop);}
+		string gdbCrashBatch;
+		char** origArgv; int origArgc;
+		// do not change by hand
+		/* Mutex for:
+		* 1. GLViewer::paintGL (deffered lock: if fails, no GL painting is done)
+		* 2. other threads that wish to manipulate GL
+		* 3. Omega when substantial changes to the scene are being made (bodies being deleted, simulation loaded etc) so that GL doesn't access those and crash */
+		boost::try_mutex renderMutex;
+
+
+		void run();
+		void pause();
+		void step();
+		void stop(); // resets the simulationLoop
+		bool isRunning();
+		std::string sceneFile; // updated at load/save automatically
+		void loadSimulation(const string& name);
+		void saveSimulation(const string& name);
+
+		void resetScene();
+		const shared_ptr<Scene>& getScene();
+		//! Return unique temporary filename. May be deleted by the user; if not, will be deleted at shutdown.
+		string tmpFilename();
+		Real getRealTime();
+		time_duration getRealTime_duration();
+
+		// configuration directory used for logging config and possibly other things
+		std::string confDir;
+
+	DECLARE_LOGGER;
+
+	Omega(){ LOG_DEBUG("Constructing Omega."); }
+	~Omega(){}
+
+	FRIEND_SINGLETON(Omega);
+	friend class pyOmega;
+};
+
+

=== added file 'core/PartialEngine.cpp'
--- core/PartialEngine.cpp	1970-01-01 00:00:00 +0000
+++ core/PartialEngine.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,10 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include "PartialEngine.hpp"
+

=== added file 'core/PartialEngine.hpp'
--- core/PartialEngine.hpp	1970-01-01 00:00:00 +0000
+++ core/PartialEngine.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,24 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+#include <vector>
+#include<yade/core/Engine.hpp>
+#include<yade/core/Body.hpp>
+
+class PartialEngine: public Engine{
+	public:
+		virtual ~PartialEngine() {};
+	YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(PartialEngine,Engine,"Engine affecting only particular bodies in the simulation, defined by *ids*.",
+		((std::vector<int>,ids,,,":yref:`Ids<Body::id>` of bodies affected by this PartialEngine.")),
+		/*deprec*/ ((subscribedBodies,ids,"The old name was too long")), /*init*/, /* ctor */, /* py */
+	);
+};
+REGISTER_SERIALIZABLE(PartialEngine);
+
+

=== added file 'core/SConscript'
--- core/SConscript	1970-01-01 00:00:00 +0000
+++ core/SConscript	2013-11-15 08:22:02 +0000
@@ -0,0 +1,55 @@
+# syntax: python
+Import('*')
+
+pyMain='$PREFIX/bin/yade$SUFFIX'
+main=env.ScanReplace('main/main.py.in')
+batch=env.ScanReplace('main/yade-batch.in')
+env.AlwaysBuild(main)
+env.AlwaysBuild(batch)
+env.InstallAs(pyMain,main)
+env.InstallAs(pyMain+'-batch',batch)
+env.AddPostAction(pyMain,Chmod(pyMain,0755))
+env.AddPostAction(pyMain+'-batch',Chmod(pyMain+'-batch',0755))
+## for --rebuild
+if 'execCheck' in env and env['execCheck']!=env.subst(pyMain):
+	raise RuntimeError('execCheck option (%s) does not match what is about to be installed (%s)'%(env['execCheck'],env.subst(pyMain)))
+
+env.Install('$LIBDIR/py/yade',[
+	env.SharedLibrary('boot',['main/pyboot.cpp'],SHLIBPREFIX='',LIBS=env['LIBS']+['yade-support','core'])
+])
+
+env.Install('$LIBDIR/lib',[
+	env.SharedLibrary('core',
+		env.Combine('core.cpp',[
+			'Body.cpp',
+			'BodyContainer.cpp',
+			'Bound.cpp',
+			'Cell.cpp',
+			'PartialEngine.cpp',
+			'Engine.cpp',
+			'FileGenerator.cpp',
+			'FrontEnd.cpp',
+			'Interaction.cpp',
+			'InteractionContainer.cpp',
+			'GroupRelationData.cpp',
+			'Material.cpp',
+			'Scene.cpp',
+			'Dispatcher.cpp',
+			'Omega.cpp',
+			'Shape.cpp',
+			'SimulationFlow.cpp',
+			'State.cpp',
+			'ThreadRunner.cpp',
+			'ThreadWorker.cpp',
+			'TimeStepper.cpp',
+			'corePlugins.cpp'			
+			]
+			),
+		LIBS=env['LIBS']+[
+			'yade-support',
+			'rt', # realtime lib, for clock_gettime 
+			]+
+			(['yade-opengl'] if 'opengl' in env['features'] else [])
+			,
+	)
+])

=== added file 'core/Scene.cpp'
--- core/Scene.cpp	1970-01-01 00:00:00 +0000
+++ core/Scene.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,179 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include"Scene.hpp"
+#include<yade/core/Engine.hpp>
+#include<yade/core/Timing.hpp>
+#include<yade/core/TimeStepper.hpp>
+
+#include<yade/lib-base/Math.hpp>
+#include<boost/foreach.hpp>
+#include<boost/date_time/posix_time/posix_time.hpp>
+#include<boost/algorithm/string.hpp>
+
+#include<yade/core/BodyContainer.hpp>
+#include<yade/core/InteractionContainer.hpp>
+
+
+// POSIX-only
+#include<pwd.h>
+#include<unistd.h>
+#include<time.h>
+
+
+YADE_PLUGIN((Scene));
+CREATE_LOGGER(Scene);
+// should be elsewhere, probably
+bool TimingInfo::enabled=false;
+
+void Scene::fillDefaultTags(){
+	// fill default tags
+	struct passwd* pw;
+	char hostname[HOST_NAME_MAX];
+	gethostname(hostname,HOST_NAME_MAX);
+	pw=getpwuid(geteuid()); if(!pw) throw runtime_error("getpwuid(geteuid()) failed!");
+	// a few default tags
+	// real name: will have all non-ASCII characters replaced by ? since serialization doesn't handle that
+	// the standard GECOS format is Real Name,,, - first comma and after will be discarded
+	string gecos(pw->pw_gecos), gecos2; size_t p=gecos.find(","); if(p!=string::npos) boost::algorithm::erase_tail(gecos,gecos.size()-p); for(size_t i=0;i<gecos.size();i++){gecos2.push_back(((unsigned char)gecos[i])<128 ? gecos[i] : '?'); }
+	tags.push_back(boost::algorithm::replace_all_copy(string("author=")+gecos2+" ("+string(pw->pw_name)+"@"+hostname+")"," ","~"));
+	tags.push_back(string("isoTime="+boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time())));
+	string id=boost::posix_time::to_iso_string(boost::posix_time::second_clock::local_time())+"p"+lexical_cast<string>(getpid());
+	tags.push_back("id="+id);
+	tags.push_back("d.id="+id);
+	tags.push_back("id.d="+id);
+}
+
+
+
+void Scene::postLoad(Scene&){
+	// FIXME: this should be no longer necessary with boost::serialization, but it must be checked
+	/* since yade::serialization doesn't properly handle shared pointers, iterate over all bodies and make materials shared again, if id>=0 */
+	FOREACH(const shared_ptr<Body>& b, *bodies){
+		if(!b) continue; // erased body
+		if(!b->material || b->material->id<0) continue; // not a shared material
+		assert(b->material->id < (int)materials.size());
+		b->material=materials[b->material->id];
+	}
+}
+
+
+
+void Scene::moveToNextTimeStep(){
+	if(needsInitializers){
+		checkStateTypes();
+		FOREACH(shared_ptr<Engine> e, initializers){ e->scene=this; if(e->dead || !e->isActivated()) continue; e->action(); } 
+		needsInitializers=false;
+	}
+	if(!subStepping && subStep<0){
+		// ** 1. ** prologue
+		if(isPeriodic) cell->integrateAndUpdate(dt);
+		//forces.reset(); // uncomment if ForceResetter is removed
+		bool TimingInfo_enabled=TimingInfo::enabled; // cache the value, so that when it is changed inside the step, the engine that was just running doesn't get bogus values
+		TimingInfo::delta last=TimingInfo::getNow(); // actually does something only if TimingInfo::enabled, no need to put the condition here
+		// ** 2. ** engines
+		FOREACH(const shared_ptr<Engine>& e, engines){
+			e->scene=this;
+			if(e->dead || !e->isActivated()) continue;
+			e->action();
+			if(TimingInfo_enabled) {TimingInfo::delta now=TimingInfo::getNow(); e->timingInfo.nsec+=now-last; e->timingInfo.nExec+=1; last=now;}
+		}
+		// ** 3. ** epilogue
+		iter++;
+		time+=dt;
+	} else {
+		/* IMPORTANT: take care to copy EXACTLY the same sequence as is in the block above !! */
+		if(TimingInfo::enabled){ TimingInfo::enabled=false; LOG_INFO("O.timingEnabled disabled, since O.subStepping is used."); }
+		if(subStep<-1 || subStep>(int)engines.size()){ LOG_ERROR("Invalid value of Scene::subStep ("<<subStep<<"), setting to -1 (prologue will be run)."); subStep=-1; }
+		// if subStepping is disabled, it means we have not yet finished last step completely; in that case, do that here by running all remaining substeps at once
+		// if subStepping is enabled, just run the step we need (the loop is traversed only once, with subs==subStep)
+		int maxSubStep=subStep;
+		if(!subStepping){ maxSubStep=engines.size(); LOG_INFO("Running remaining sub-steps ("<<subStep<<"…"<<maxSubStep<<") before disabling sub-stepping."); }
+		for(int subs=subStep; subs<=maxSubStep; subs++){
+			assert(subs>=-1 && subs<=(int)engines.size());
+			// ** 1. ** prologue
+			if(subs==-1){ if(isPeriodic) cell->integrateAndUpdate(dt); }
+			// ** 2. ** engines
+			else if(subs>=0 && subs<(int)engines.size()){ const shared_ptr<Engine>& e(engines[subs]); e->scene=this; if(!e->dead && e->isActivated()) e->action(); }
+			// ** 3. ** epilogue
+			else if(subs==(int)engines.size()){ iter++; time+=dt; /* gives -1 along with the increment afterwards */ subStep=-2; }
+			// (?!)
+			else { /* never reached */ assert(false); }
+		}
+		subStep++; // if not substepping, this will make subStep=-2+1=-1, which is what we want
+	}
+}
+
+
+
+shared_ptr<Engine> Scene::engineByName(const string& s){
+	FOREACH(shared_ptr<Engine> e, engines){
+		if(e->getClassName()==s) return e;
+	}
+	return shared_ptr<Engine>();
+}
+
+bool Scene::timeStepperPresent(){
+	int n=0;
+	FOREACH(const shared_ptr<Engine>&e, engines){ if(dynamic_cast<TimeStepper*>(e.get())) n++; }
+	if(n>1) throw std::runtime_error(string("Multiple ("+lexical_cast<string>(n)+") TimeSteppers in the simulation?!").c_str());
+	return n>0;
+}
+
+bool Scene::timeStepperActive(){
+	int n=0; bool ret=false;
+	FOREACH(const shared_ptr<Engine>&e, engines){
+		TimeStepper* ts=dynamic_cast<TimeStepper*>(e.get()); if(ts) { ret=ts->active; n++; }
+	}
+	if(n>1) throw std::runtime_error(string("Multiple ("+lexical_cast<string>(n)+") TimeSteppers in the simulation?!").c_str());
+	return ret;
+}
+
+bool Scene::timeStepperActivate(bool a){
+	int n=0;
+	FOREACH(const shared_ptr<Engine> e, engines){
+		TimeStepper* ts=dynamic_cast<TimeStepper*>(e.get());
+		if(ts) { ts->setActive(a); n++; }
+	}
+	if(n>1) throw std::runtime_error(string("Multiple ("+lexical_cast<string>(n)+") TimeSteppers in the simulation?!").c_str());
+	return n>0;
+}
+
+
+
+void Scene::checkStateTypes(){
+	FOREACH(const shared_ptr<Body>& b, *bodies){
+		if(!b || !b->material) continue;
+		if(b->material && !b->state) throw std::runtime_error("Body #"+lexical_cast<string>(b->getId())+": has Body::material, but NULL Body::state.");
+		if(!b->material->stateTypeOk(b->state.get())){
+			throw std::runtime_error("Body #"+lexical_cast<string>(b->getId())+": Body::material type "+b->material->getClassName()+" doesn't correspond to Body::state type "+b->state->getClassName()+" (should be "+b->material->newAssocState()->getClassName()+" instead).");
+		}
+	}
+}
+
+void Scene::updateBound(){
+	if(!bound) bound=shared_ptr<Bound>(new Bound);
+	const Real& inf=std::numeric_limits<Real>::infinity();
+	Vector3r mx(-inf,-inf,-inf);
+	Vector3r mn(inf,inf,inf);
+	FOREACH(const shared_ptr<Body>& b, *bodies){
+		if(!b) continue;
+		if(b->bound){
+			for(int i=0; i<3; i++){
+				if(!isinf(b->bound->max[i])) mx[i]=max(mx[i],b->bound->max[i]);
+				if(!isinf(b->bound->min[i])) mn[i]=min(mn[i],b->bound->min[i]);
+			}
+		} else {
+	 		mx=mx.cwise().max(b->state->pos);
+ 			mn=mn.cwise().min(b->state->pos);
+		}
+	}
+	bound->min=mn; bound->max=mx;
+}

=== added file 'core/Scene.hpp'
--- core/Scene.hpp	1970-01-01 00:00:00 +0000
+++ core/Scene.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,98 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include<yade/core/Body.hpp>
+#include<yade/core/Cell.hpp>
+#include<yade/core/BodyContainer.hpp>
+#include<yade/core/Engine.hpp>
+#include<yade/core/Material.hpp>
+#include<yade/core/DisplayParameters.hpp>
+#include<yade/core/ForceContainer.hpp>
+#include<yade/core/InteractionContainer.hpp>
+#include<yade/core/EnergyTracker.hpp>
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255 
+#endif
+
+
+class Bound;
+
+class Scene: public Serializable{
+	public:
+		//! Adds material to Scene::materials. It also sets id of the material accordingly and returns it.
+		int addMaterial(shared_ptr<Material> m){ materials.push_back(m); m->id=(int)materials.size()-1; return m->id; }
+		//! Checks that type of Body::state satisfies Material::stateTypeOk. Throws runtime_error if not. (Is called from BoundDispatcher the first time it runs)
+		void checkStateTypes();
+		//! update our bound; used directly instead of a BoundFunctor, since we don't derive from Body anymore
+		void updateBound();
+
+		// neither serialized, nor accessible from python (at least not directly)
+		ForceContainer forces;
+
+		// initialize tags (author, date, time)
+		void fillDefaultTags();
+		// advance by one iteration by running all engines
+		void moveToNextTimeStep();
+
+		/* Functions operating on TimeStepper; they all throw exception if there is more than 1 */
+		// return whether a TimeStepper is present
+		bool timeStepperPresent();
+		// true if TimeStepper is present and active, false otherwise
+		bool timeStepperActive();
+		// (de)activate TimeStepper; returns whether the operation was successful (i.e. whether a TimeStepper was found)
+		bool timeStepperActivate(bool activate);
+
+		shared_ptr<Engine> engineByName(const string& s);
+
+		void postLoad(Scene&);
+
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR(Scene,Serializable,"Object comprising the whole simulation.",
+		#ifdef YADE_GROUP_RELATION_DATA
+			((shared_ptr<GroupRelationData>,grpRelationData,,Attr::hidden,"Assigns float value to all possible combinations of body group that interact."))
+		#endif
+		((Real,dt,1e-8,,"Current timestep for integration."))
+		((long,iter,0,Attr::readonly,"Current iteration (computational step) number"))
+		((bool,subStepping,false,,"Whether we currently advance by one engine in every step (rather than by single run through all engines)."))
+		((int,subStep,-1,Attr::readonly,"Number of sub-step; not to be changed directly. -1 means to run loop prologue (cell integration), 0…n-1 runs respective engines (n is number of engines), n runs epilogue (increment step number and time."))
+		((Real,time,0,Attr::readonly,"Simulation time (virtual time) [s]"))
+		((long,stopAtIter,0,,"Iteration after which to stop the simulation."))
+		#if 0
+			// not yet implemented
+			((Real,stopAtTime,0,,"Time at which to stop the simulation"))
+			((Real,stopAtRealTime,0,,"Time at which to stop the simulation"))
+		#endif
+		((bool,isPeriodic,false,Attr::readonly,"Whether periodic boundary conditions are active."))
+		((bool,trackEnergy,false,Attr::readonly,"Whether energies are being traced."))
+		((bool,needsInitializers,true,Attr::readonly,"Whether initializers will be run before the first step."))
+		((Body::id_t,selectedBody,-1,,"Id of body that is selected by the user"))
+
+		((list<string>,tags,,,"Arbitrary key=value associations (tags like mp3 tags: author, date, version, description etc.)"))
+		((vector<shared_ptr<Engine> >,engines,,Attr::hidden,"Engines sequence in the simulation."))
+		((vector<shared_ptr<Engine> >,initializers,,Attr::hidden,"Engines that will be run only once, before the first step."))
+		((shared_ptr<BodyContainer>,bodies,new BodyContainer,Attr::hidden,"Bodies contained in the scene."))
+		((shared_ptr<InteractionContainer>,interactions,new InteractionContainer,Attr::hidden,"All interactions between bodies."))
+		((shared_ptr<EnergyTracker>,energy,new EnergyTracker,Attr::hidden,"Energy values, if energy tracking is enabled."))
+		((vector<shared_ptr<Material> >,materials,,Attr::hidden,"Container of shared materials. Add elements using Scene::addMaterial, not directly. Do NOT remove elements from here unless you know what you are doing!"))
+		((shared_ptr<Bound>,bound,,Attr::hidden,"Bounding box of the scene (only used for rendering and initialized if needed)."))
+
+		((shared_ptr<Cell>,cell,new Cell,Attr::hidden,"Information on periodicity; only should be used if Scene::isPeriodic."))
+		((vector<shared_ptr<Serializable> >,miscParams,,Attr::hidden,"Store for arbitrary Serializable objects; will set static parameters during deserialization (primarily for GLDraw functors which otherwise have no attribute access)"))
+		((vector<shared_ptr<DisplayParameters> >,dispParams,,Attr::hidden,"'hash maps' of display parameters (since yade::serialization had no support for maps, emulate it via vector of strings in format key=value)"))
+
+		,
+		/*ctor*/ fillDefaultTags();
+	);
+	DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(Scene);
+

=== added file 'core/Shape.cpp'
--- core/Shape.cpp	1970-01-01 00:00:00 +0000
+++ core/Shape.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,2 @@
+#include<yade/core/Shape.hpp>
+Shape::~Shape(){}

=== added file 'core/Shape.hpp'
--- core/Shape.hpp	1970-01-01 00:00:00 +0000
+++ core/Shape.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,36 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-multimethods/Indexable.hpp>
+#include<yade/core/Dispatcher.hpp>
+
+#define BV_FUNCTOR_CACHE
+
+class BoundFunctor;
+
+class Shape: public Serializable, public Indexable {
+	public:
+		~Shape(); // vtable
+		#ifdef BV_FUNCTOR_CACHE
+			shared_ptr<BoundFunctor> boundFunctor;
+		#endif
+
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Shape,Serializable,"Geometry of a body",
+		((Vector3r,color,Vector3r(1,1,1),,"Color for rendering (normalized RGB)."))
+		((bool,wire,false,,"Whether this Shape is rendered using color surfaces, or only wireframe (can still be overridden by global config of the renderer)."))
+		((bool,highlight,false,,"Whether this Shape will be highlighted when rendered.")),
+		/*ctor*/,
+		/*py*/ YADE_PY_TOPINDEXABLE(Shape)
+	);
+	REGISTER_INDEX_COUNTER(Shape);
+};
+REGISTER_SERIALIZABLE(Shape);
+

=== added file 'core/SimulationFlow.cpp'
--- core/SimulationFlow.cpp	1970-01-01 00:00:00 +0000
+++ core/SimulationFlow.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,23 @@
+/*************************************************************************
+*  Copyright (C) 2006 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include "SimulationFlow.hpp"
+#include "Scene.hpp"
+#include "Omega.hpp"
+
+CREATE_LOGGER(SimulationFlow);
+
+void SimulationFlow::singleAction()
+{
+	Scene* scene=Omega::instance().getScene().get();
+	if (!scene) throw logic_error("SimulationFlow::singleAction: no Scene object?!");
+	if(scene->subStepping) { LOG_INFO("Sub-stepping disabled when running simulation continuously."); scene->subStepping=false; }
+	scene->moveToNextTimeStep();
+	if(scene->stopAtIter>0 && scene->iter==scene->stopAtIter) setTerminate(true);
+};
+

=== added file 'core/SimulationFlow.hpp'
--- core/SimulationFlow.hpp	1970-01-01 00:00:00 +0000
+++ core/SimulationFlow.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,22 @@
+/*************************************************************************
+*  Copyright (C) 2006 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include "ThreadWorker.hpp"
+
+class SimulationFlow // FIXME ; bad name
+	: public ThreadWorker
+{
+	public:
+		virtual void	singleAction();
+	DECLARE_LOGGER;
+};
+
+
+

=== added file 'core/State.cpp'
--- core/State.cpp	1970-01-01 00:00:00 +0000
+++ core/State.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,29 @@
+// 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
+#include<yade/core/State.hpp>
+#include<boost/foreach.hpp>
+#include<stdexcept>
+#ifndef FOREACH
+	#define FOREACH BOOST_FOREACH
+#endif
+
+void State::setDOFfromVector3r(Vector3r disp,Vector3r rot){
+	blockedDOFs=((disp[0]==1.0)?DOF_X :0)|((disp[1]==1.0)?DOF_Y :0)|((disp[2]==1.0)?DOF_Z :0)|
+		((rot [0]==1.0)?DOF_RX:0)|((rot [1]==1.0)?DOF_RY:0)|((rot [2]==1.0)?DOF_RZ:0);
+}
+
+std::vector<std::string> State::blockedDOFs_vec_get() const {
+	std::vector<std::string> ret;
+	#define _SET_DOF(DOF_ANY,str) if((blockedDOFs & State::DOF_ANY)!=0) ret.push_back(str);
+	_SET_DOF(DOF_X,"x"); _SET_DOF(DOF_Y,"y"); _SET_DOF(DOF_Z,"z"); _SET_DOF(DOF_RX,"rx"); _SET_DOF(DOF_RY,"ry"); _SET_DOF(DOF_RZ,"rz");
+	#undef _SET_DOF
+	return ret;
+}
+void State::blockedDOFs_vec_set(const std::vector<std::string>& dofs){
+	FOREACH(const std::string s, dofs){
+		#define _GET_DOF(DOF_ANY,str) if(s==str) { blockedDOFs|=State::DOF_ANY; continue; }
+		_GET_DOF(DOF_X,"x"); _GET_DOF(DOF_Y,"y"); _GET_DOF(DOF_Z,"z"); _GET_DOF(DOF_RX,"rx"); _GET_DOF(DOF_RY,"ry"); _GET_DOF(DOF_RZ,"rz");
+		#undef _GET_DOF
+		throw std::invalid_argument("Invalid  DOF specification `"+s+"', must be ∈{x,y,z,rx,ry,rz}.");
+	}
+}
+

=== added file 'core/State.hpp'
--- core/State.hpp	1970-01-01 00:00:00 +0000
+++ core/State.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,88 @@
+// 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
+#pragma once
+#include<yade/lib-serialization/Serializable.hpp>
+#include<yade/lib-multimethods/Indexable.hpp>
+#include<yade/core/Dispatcher.hpp>
+/*! State (internal & spatial variables) of a body.
+
+For now, I put position, orientation, velocity and angular velocity here,
+since (AFAIK) we have no bodies that lack them. If in the future
+someone needs bodies without orientation, then orientation and angular
+velocity can be pushed to a derived class (and the rest of code adapted
+to that).
+
+All state variables are initialized to zeros.
+
+Historical note: this used to be part of the PhysicalParameters class.
+The other data are now in the Material class.
+*/
+class State: public Serializable, public Indexable{
+	public:
+		/// linear motion (references to inside se3)
+		Vector3r& pos;
+		/// rotational motion (reference to inside se3)
+		Quaternionr& ori;
+
+		//! mutex for updating the parameters from within the interaction loop (only used rarely)
+		boost::mutex updateMutex;
+
+		
+		// bits for blockedDOFs
+		enum {DOF_NONE=0,DOF_X=1,DOF_Y=2,DOF_Z=4,DOF_RX=8,DOF_RY=16,DOF_RZ=32};
+		//! shorthand for all DOFs blocked
+		static const unsigned DOF_ALL=DOF_X|DOF_Y|DOF_Z|DOF_RX|DOF_RY|DOF_RZ;
+		//! shorthand for all displacements blocked
+		static const unsigned DOF_XYZ=DOF_X|DOF_Y|DOF_Z;
+		//! shorthand for all rotations blocked
+		static const unsigned DOF_RXRYRZ=DOF_RX|DOF_RY|DOF_RZ; 
+
+		//! Return DOF_* constant for given axis∈{0,1,2} and rotationalDOF∈{false(default),true}; e.g. axisDOF(0,true)==DOF_RX
+		static unsigned axisDOF(int axis, bool rotationalDOF=false){return 1<<(axis+(rotationalDOF?3:0));}		
+		//! set DOFs according to two Vector3r arguments (blocked is when disp[i]==1.0 or rot[i]==1.0)
+		void setDOFfromVector3r(Vector3r disp,Vector3r rot=Vector3r::Zero());
+		//! Getter of blockedDOFs for list of strings (e.g. DOF_X | DOR_RX | DOF_RZ → ['x','rx','rz'])
+		std::vector<std::string> blockedDOFs_vec_get() const;
+		//! Setter of blockedDOFs from list of strings (['x','rx','rz'] → DOF_X | DOR_RX | DOF_RZ)
+		void blockedDOFs_vec_set(const std::vector<std::string>& dofs);
+
+		//! Return displacement (current-reference position)
+		Vector3r displ() const {return pos-refPos;}
+		//! Return rotation (current-reference orientation, as Vector3r)
+		Vector3r rot() const { Quaternionr relRot=refOri.conjugate()*ori; AngleAxisr aa(relRot); return aa.axis()*aa.angle(); }
+
+		// python access functions: pos and ori are references to inside Se3r and cannot be pointed to directly
+		Vector3r pos_get() const {return pos;}
+		void pos_set(const Vector3r& p) {pos=p;}
+		Quaternionr ori_get() const {return ori; }
+		void ori_set(const Quaternionr& o){ori=o;}
+
+
+
+	//State(): se3(Vector3r::Zero(),Quaternionr::Identity()),pos(se3.position),vel(Vector3r::Zero()),accel(Vector3r::Zero()),mass(0.),ori(se3.orientation),angVel(Vector3r::Zero()),angAccel(Vector3r::Zero()),angMom(Vector3r::Zero()),inertia(Vector3r::Zero()),refPos(Vector3r::Zero()),refOri(Quaternionr::Identity()),blockedDOFs(DOF_NONE){}
+
+	YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(State,Serializable,"State of a body (spatial configuration, internal variables).",
+		((Se3r,se3,Se3r(Vector3r::Zero(),Quaternionr::Identity()),,"Position and orientation as one object."))
+		((Vector3r,vel,Vector3r::Zero(),,"Current linear velocity."))
+		((Vector3r,accel,Vector3r::Zero(),,"Current acceleration."))
+		((Real,mass,0,,"Mass of this body"))
+		((Vector3r,angVel,Vector3r::Zero(),,"Current angular velocity"))
+		((Vector3r,angAccel,Vector3r::Zero(),,"Current angular acceleration"))
+		((Vector3r,angMom,Vector3r::Zero(),,"Current angular momentum"))
+		((Vector3r,inertia,Vector3r::Zero(),,"Inertia of associated body, in local coordinate system."))
+		((Vector3r,refPos,Vector3r::Zero(),,"Reference position"))
+		((Quaternionr,refOri,Quaternionr::Identity(),,"Reference orientation"))
+		((unsigned,blockedDOFs,,,"[Will be overridden]")),
+		/* additional initializers */
+			((pos,se3.position))
+			((ori,se3.orientation)),
+		/* ctor */,
+		/*py*/
+		YADE_PY_TOPINDEXABLE(State)
+		.add_property("blockedDOFs",&State::blockedDOFs_vec_get,&State::blockedDOFs_vec_set,"Degress of freedom where linear/angular velocity will be always constant (equal to zero, or to an user-defined value), regardless of applied force/torque. List of any combination of 'x','y','z','rx','ry','rz'.")
+		// references must be set using wrapper funcs
+		.add_property("pos",&State::pos_get,&State::pos_set,"Current position.")
+		.add_property("ori",&State::ori_get,&State::ori_set,"Current orientation.") 
+	);
+	REGISTER_INDEX_COUNTER(State);
+};
+REGISTER_SERIALIZABLE(State);

=== added file 'core/ThreadRunner.cpp'
--- core/ThreadRunner.cpp	1970-01-01 00:00:00 +0000
+++ core/ThreadRunner.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,102 @@
+/*************************************************************************
+*  Copyright (C) 2006 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include "ThreadRunner.hpp"
+#include "ThreadWorker.hpp"
+
+#include <boost/thread/thread.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include<iostream>
+
+CREATE_LOGGER(ThreadRunner);
+
+void ThreadRunner::run()
+{
+	// this is the body of execution of separate thread
+	boost::mutex::scoped_lock lock(m_runmutex);
+	try{
+		workerThrew=false;
+		while(looping()) {
+			call();
+			if(m_thread_worker->shouldTerminate()){ stop(); return; }
+		}
+	} catch (std::exception& e){
+		LOG_FATAL("Exception occured: "<<endl<<e.what());
+		workerException=std::exception(e); workerThrew=true;
+		stop(); return;
+	}
+}
+
+void ThreadRunner::call()
+{
+	// this is the body of execution of separate thread
+	//
+	// FIXME - if several threads are blocked here and waiting, and the
+	// destructor is called we get a crash. This happens if some other
+	// thread is calling spwanSingleAction in a loop (instead of calling
+	// start() and stop() as it normally should). This is currently the
+	// case of SimulationController with synchronization turned on.
+	//
+	// the solution is to use a counter (perhaps recursive_mutex?) which
+	// will count the number of threads in the queue, and only after they
+	// all finish execution the destructor will be able to finish its work
+	// 
+	boost::mutex::scoped_lock lock(m_callmutex);
+	m_thread_worker->setTerminate(false);
+	m_thread_worker->callSingleAction();
+}
+
+void ThreadRunner::pleaseTerminate()
+{
+	stop();
+	m_thread_worker->setTerminate(true);
+}
+
+void ThreadRunner::spawnSingleAction()
+{
+	boost::mutex::scoped_lock boollock(m_boolmutex);
+	boost::mutex::scoped_lock calllock(m_callmutex);
+	if(m_looping) return;
+	boost::function0<void> call( boost::bind( &ThreadRunner::call , this ) );
+	boost::thread th(call);
+}
+
+void ThreadRunner::start()
+{
+	boost::mutex::scoped_lock lock(m_boolmutex);
+	if(m_looping) return;
+	m_looping=true;
+	boost::function0<void> run( boost::bind( &ThreadRunner::run , this ) );
+	boost::thread th(run);
+}
+
+void ThreadRunner::stop()
+{
+	//std::cerr<<__FILE__<<":"<<__LINE__<<":"<<__FUNCTION__<<std::endl;
+	if(!m_looping) return;
+	//std::cerr<<__FILE__<<":"<<__LINE__<<":"<<__FUNCTION__<<std::endl;
+	boost::mutex::scoped_lock lock(m_boolmutex);
+	//std::cerr<<__FILE__<<":"<<__LINE__<<":"<<__FUNCTION__<<std::endl;
+	m_looping=false;
+}
+
+bool ThreadRunner::looping()
+{
+	boost::mutex::scoped_lock lock(m_boolmutex);
+	return m_looping;
+}
+
+ThreadRunner::~ThreadRunner()
+{
+	pleaseTerminate();
+	boost::mutex::scoped_lock runlock(m_runmutex);
+	boost::mutex::scoped_lock calllock(m_callmutex);
+}
+

=== added file 'core/ThreadRunner.hpp'
--- core/ThreadRunner.hpp	1970-01-01 00:00:00 +0000
+++ core/ThreadRunner.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,78 @@
+/*************************************************************************
+*  Copyright (C) 2006 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include <boost/thread/mutex.hpp>
+
+/*! 
+\brief	ThreadRunner takes care of starting/stopping (executing) the
+	ThreadWorker in the separate thread. 
+
+	It is achieved by either:
+	- one execution of { ThreadWorker::singleAction(); } in separate thread
+	- a loop { while(looping() ) ThreadWorker::singleAction(); } in separate thread
+
+	Lifetime of ThreadRunner is guaranteed to be longer or equal to
+	the lifetime of	the separate thread of execution.
+
+	The ThreadRunner owner must make sure that ThreadWorker has longer or
+	equal lifetime than instance of ThreadRunner. Otherwise ThreadRunner
+	will try to execute a dead object, which will lead to crash.
+
+	Do not destroy immediately after call to singleAction(). Destructor can
+	kick in before a separate thread starts, which will lead to a crash.
+
+	User can explicitly ask the running thread to terminate execution. If
+	the thread supports it, it will terminate.
+
+\note	This code is reentrant. Simultaneous requests from other threads to
+	start/stop or perform singleAction() are expected.
+	   
+	So ThreadWorker(s) are running, while the user is interacting with the
+	UI frontend (doesn't matter whether the UI is graphical, ncurses or
+	any other).
+
+ */
+
+class ThreadWorker;
+
+class ThreadRunner
+{
+	private :
+		ThreadWorker*	m_thread_worker;
+		bool		m_looping;
+		boost::mutex	m_boolmutex;
+		boost::mutex	m_callmutex;
+		boost::mutex	m_runmutex;
+		void		run();
+		void		call();
+
+		DECLARE_LOGGER;
+
+	public :
+		ThreadRunner(ThreadWorker* c) : m_thread_worker(c), m_looping(false), workerThrew(false) {};
+		~ThreadRunner();
+
+		/// perform ThreadWorker::singleAction() in separate thread
+		void spawnSingleAction();
+		/// start doing singleAction() in a loop in separate thread
+		void start();
+		/// stop the loop (changes the flag checked by looping() )
+		void stop();
+		/// kindly ask the separate thread to terminate
+		void pleaseTerminate();
+		/// precondition for the loop started with start().
+		bool looping();
+		//! if true, workerException is copy of the exception thrown by the worker
+		bool workerThrew;
+		//! last exception thrown by the worker, if any
+		std::exception workerException;
+};
+
+

=== added file 'core/ThreadWorker.cpp'
--- core/ThreadWorker.cpp	1970-01-01 00:00:00 +0000
+++ core/ThreadWorker.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,77 @@
+/*************************************************************************
+*  Copyright (C) 2006 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include "ThreadWorker.hpp"
+
+void ThreadWorker::setTerminate(bool b)
+{
+	boost::mutex::scoped_lock lock(m_mutex);
+	m_should_terminate=b;
+};
+
+bool ThreadWorker::shouldTerminate()
+{
+	boost::mutex::scoped_lock lock(m_mutex);
+	return m_should_terminate;
+};
+		
+void ThreadWorker::setProgress(float i)
+{
+	boost::mutex::scoped_lock lock(m_mutex);
+	m_progress=i;
+};
+
+void ThreadWorker::setStatus(std::string s)
+{
+	boost::mutex::scoped_lock lock(m_mutex);
+	m_status=s;
+};
+
+float ThreadWorker::progress()
+{
+	boost::mutex::scoped_lock lock(m_mutex);
+	return m_progress;
+};
+
+std::string ThreadWorker::getStatus()
+{
+	boost::mutex::scoped_lock lock(m_mutex);
+	return m_status;
+};
+
+void ThreadWorker::setReturnValue(boost::any a)
+{
+	boost::mutex::scoped_lock lock(m_mutex);
+	m_val = a;
+};
+
+boost::any ThreadWorker::getReturnValue()
+{
+	boost::mutex::scoped_lock lock(m_mutex);
+	return m_val;
+};
+
+bool ThreadWorker::done()
+{
+	boost::mutex::scoped_lock lock(m_mutex);
+	return m_done;
+};
+
+void ThreadWorker::callSingleAction()
+{
+	{
+		boost::mutex::scoped_lock lock(m_mutex);
+		m_done = false;
+	}
+	this->singleAction();
+	{
+		boost::mutex::scoped_lock lock(m_mutex);
+		m_done = true;
+	}
+};
+

=== added file 'core/ThreadWorker.hpp'
--- core/ThreadWorker.hpp	1970-01-01 00:00:00 +0000
+++ core/ThreadWorker.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,63 @@
+/*************************************************************************
+*  Copyright (C) 2006 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include <boost/thread/mutex.hpp>
+#include <boost/any.hpp>
+
+class ThreadRunner;
+
+/*! 
+\brief	ThreadWorker contains information about tasks to be performed when
+	the separate thread is executed.
+ */
+
+class ThreadWorker	//         perhaps simulation steps, or stage? as it is a single stage
+			//         of the simulation, that consists of several steps
+			// Update: it is more general now. simulation stages perhaps will be derived from this class
+{
+	private:
+		/// You should check out ThreadRunner, it is used for execution control of this class
+		friend class ThreadRunner;
+		bool		m_should_terminate;
+		bool		m_done;
+		boost::mutex	m_mutex;
+		boost::any	m_val;
+		float		m_progress;
+		std::string	m_status;
+		void		callSingleAction();
+
+	protected:
+		void		setTerminate(bool);
+		/// singleAction() can check whether someone asked for termination, and terminate if/when possible
+		bool		shouldTerminate();
+		/// if something must be returned, set the result using this method
+		void		setReturnValue(boost::any);
+		/// if you feel monitored for progress, you can set it here: a value between 0.0 and 1.0
+		void		setProgress(float);
+		/// if you feel being monitored for what currently is done, set the message here
+		void		setStatus(std::string);
+		/// derived classes must define this method, that's what is executed in separate thread
+		virtual void	singleAction() = 0;
+
+	public:
+		ThreadWorker() : m_should_terminate(false), m_done(false), m_progress(0) {};
+		virtual		~ThreadWorker() {};
+
+		/// Returns a value between 0.0 and 1.0. Useful for updating a progress bar.
+		float		progress(); // get_progress ? (pick a naming convention, efngh)
+		/// You can display a message in GUI about what is the current work status
+		std::string	getStatus();
+		/// Check whether execution is finished,
+		bool		done();
+		/// then get the result.
+		boost::any	getReturnValue();
+};
+
+

=== added file 'core/TimeStepper.cpp'
--- core/TimeStepper.cpp	1970-01-01 00:00:00 +0000
+++ core/TimeStepper.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,29 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*  Copyright (C) 2004 by Janek Kozicki                                   *
+*  cosurgi@xxxxxxxxxx                                                    *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#include<yade/core/TimeStepper.hpp>
+#include<yade/core/GlobalEngine.hpp>
+#include<yade/core/Scene.hpp>
+
+bool TimeStepper::isActivated()
+{
+	return (active && (scene->iter % timeStepUpdateInterval == 0));
+}
+
+
+
+void TimeStepper::setActive(bool a, int nb)
+{
+	active = a; 
+	if (nb>0)
+		timeStepUpdateInterval = (unsigned int)nb;
+}
+
+

=== added file 'core/TimeStepper.hpp'
--- core/TimeStepper.hpp	1970-01-01 00:00:00 +0000
+++ core/TimeStepper.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,33 @@
+/*************************************************************************
+*  Copyright (C) 2004 by Olivier Galizzi                                 *
+*  olivier.galizzi@xxxxxxx                                               *
+*                                                                        *
+*  This program is free software; it is licensed under the terms of the  *
+*  GNU General Public License v2 or later. See file LICENSE for details. *
+*************************************************************************/
+
+#pragma once
+
+#include <list>
+#include <vector>
+#include "Interaction.hpp"
+#include "GlobalEngine.hpp"
+
+class Body;
+
+class TimeStepper: public GlobalEngine{
+	public:
+		virtual void computeTimeStep(Scene* ) { throw; };
+		virtual bool isActivated();
+		virtual void action() { computeTimeStep(scene);} ;
+		void setActive(bool a, int nb=-1);
+		
+		YADE_CLASS_BASE_DOC_ATTRS(
+			TimeStepper,GlobalEngine,"Engine defining time-step (fundamental class)",
+			((bool,active,true,,"is the engine active?"))
+			((unsigned int,timeStepUpdateInterval,1,,"dt update interval")));
+};
+
+REGISTER_SERIALIZABLE(TimeStepper);
+
+

=== added file 'core/Timing.hpp'
--- core/Timing.hpp	1970-01-01 00:00:00 +0000
+++ core/Timing.hpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,51 @@
+// 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
+#pragma once
+#include<time.h>
+#include<boost/python.hpp>
+
+struct TimingInfo{
+	typedef unsigned long long delta;
+	long nExec;
+	delta nsec;
+	TimingInfo():nExec(0),nsec(0){}
+	static delta getNow(bool evenIfDisabled=false)
+	{
+		if(!enabled && !evenIfDisabled) return 0L;
+#ifdef __APPLE__
+		std::cerr << "ERROR: Time profiling (TimingInfo) not implemented on Apples." << std::endl;
+		return 0L;
+#else
+		struct timespec ts; 
+		clock_gettime(CLOCK_MONOTONIC,&ts); 
+		return delta(1e9*ts.tv_sec+ts.tv_nsec);		
+#endif
+	}
+	static bool enabled;
+};
+
+/* Create TimingDeltas object, then every call to checkpoint() will add
+ * (or use existing) TimingInfo to data. It increases its nExec by 1
+ * and nsec by time elapsed since construction or last checkpoint.
+ */
+class TimingDeltas{
+		TimingInfo::delta last;
+		size_t i;
+	public:
+		vector<TimingInfo> data;
+		vector<string> labels;
+		TimingDeltas():i(0){}
+		void start(){if(!TimingInfo::enabled)return; i=0;last=TimingInfo::getNow();}
+		void checkpoint(const string& label){
+			if(!TimingInfo::enabled) return;
+			if(data.size()<=i) { data.resize(i+1); labels.resize(i+1); labels[i]=label;}
+			TimingInfo::delta now=TimingInfo::getNow();
+			data[i].nExec+=1; data[i].nsec+=now-last; last=now; i++;
+		}
+		void reset(){ data.clear(); labels.clear(); }
+		// python access
+		boost::python::list pyData(){
+			boost::python::list ret;
+			for(size_t i=0; i<data.size(); i++){ ret.append(boost::python::make_tuple(labels[i],data[i].nsec,data[i].nExec));}
+			return ret;
+		}
+};

=== added file 'core/corePlugins.cpp'
--- core/corePlugins.cpp	1970-01-01 00:00:00 +0000
+++ core/corePlugins.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,40 @@
+#include<yade/lib-factory/ClassFactory.hpp>
+// make core classes known to the class factory
+#include<yade/core/Body.hpp>
+#include<yade/core/BodyContainer.hpp>
+#include<yade/core/Bound.hpp>
+#include<yade/core/Cell.hpp>
+#include<yade/core/Dispatcher.hpp>
+#include<yade/core/EnergyTracker.hpp>
+#include<yade/core/Engine.hpp>
+#include<yade/core/FileGenerator.hpp>
+#include<yade/core/Functor.hpp>
+#include<yade/core/GlobalEngine.hpp>
+#include<yade/core/Interaction.hpp>
+#include<yade/core/InteractionContainer.hpp>
+#include<yade/core/IGeom.hpp>
+#include<yade/core/IPhys.hpp>
+#include<yade/core/Material.hpp>
+#include<yade/core/PartialEngine.hpp>
+#include<yade/core/Shape.hpp>
+#include<yade/core/State.hpp>
+#include<yade/core/TimeStepper.hpp>
+
+#include<boost/version.hpp>
+
+// these two are not accessible from python directly (though they should be in the future, perhaps)
+
+#if BOOST_VERSION>=104200
+	BOOST_CLASS_EXPORT_IMPLEMENT(BodyContainer);
+	BOOST_CLASS_EXPORT_IMPLEMENT(InteractionContainer);
+#else
+	BOOST_CLASS_EXPORT(BodyContainer);
+	BOOST_CLASS_EXPORT(InteractionContainer);
+#endif
+
+YADE_PLUGIN((Body)(Bound)(Cell)(Dispatcher)(EnergyTracker)(Engine)(FileGenerator)(Functor)(GlobalEngine)(Interaction)(IGeom)(IPhys)(Material)(PartialEngine)(Shape)(State)(TimeStepper));
+
+EnergyTracker::~EnergyTracker(){} // vtable
+
+//BOOST_CLASS_EXPORT(OpenMPArrayAccumulator<Real>);
+//BOOST_CLASS_EXPORT(OpenMPAccumulator<Real>);

=== added directory 'core/main'
=== added file 'core/main/main.py.in'
--- core/main/main.py.in	1970-01-01 00:00:00 +0000
+++ core/main/main.py.in	2013-11-15 08:22:02 +0000
@@ -0,0 +1,237 @@
+#!${pyExecutable}
+# encoding: utf-8
+# syntax:python
+
+import sys,os,os.path,time
+# get yade path (allow YADE_PREFIX to override)
+prefix,suffix='${runtimePREFIX}' if not os.environ.has_key('YADE_PREFIX') else os.environ['YADE_PREFIX'],'${SUFFIX}'
+# duplicate some items from yade.config here, so that we can increase verbosity when the c++ part is booting
+features,version='${features}'.split(','),'${realVersion}'
+
+## find available builds
+nonDebugLibDir=prefix+'/lib/yade'+suffix
+debugLibDir=nonDebugLibDir+'/dbg'
+hasDebug,hasNonDebug=os.path.exists(debugLibDir+'/py/yade/__init__.py'),os.path.exists(nonDebugLibDir+'/py/yade/__init__.py')
+if hasDebug and hasNonDebug: buildsAvailable='both non-debug and debug build'
+elif hasDebug and not hasNonDebug: buildsAvailable='debug build only'
+elif not hasDebug and hasNonDebug: buildsAvailable='non-debug build only'
+else:
+	raise RuntimeError('Neither non-debug nor debug build found! ('+nonDebugLibDir+'/py/yade/__init__.py, '+debugLibDir+'/py/yade/__init__.py)')
+
+
+# handle command-line options first
+import optparse
+par=optparse.OptionParser(usage='%prog [options] [ simulation.xml[.bz2] | script.py [script options]]',prog=os.path.basename(sys.argv[0]),version='%s (%s; %s)'%(version,','.join(features),buildsAvailable),description="Yade: open-source platform for dynamic compuations. Homepage http://www.yade-dem.org, code hosted at http://www.launchpad.net/yade. This is version %s (with features %s, %s)."%(version,','.join(features),buildsAvailable))
+par.add_option('-j','--threads',help='Number of OpenMP threads to run; defaults to number of cores. Equivalent to setting OMP_NUM_THREADS environment variable.',dest='threads',type='int')
+par.add_option('--update',help='Update deprecated class names in given script(s) using text search & replace. Changed files will be backed up with ~ suffix. Exit when done without running any simulation.',dest='updateScripts',action='store_true')
+par.add_option('--nice',help='Increase nice level (i.e. decrease priority) by given number.',dest='nice',type='int')
+par.add_option('-x',help='Exit when the script finishes',dest='exitAfter',action='store_true')
+par.add_option('-v',help='Increase logging verbosity; first occurence sets default logging level to info, second to debug, third to trace.'+
+	('' if 'log4cxx' in features else " (Since this build doesn't use log4cxx, this option will only have effect if repeated twice (\-vv), equivalent to setting YADE_DEBUG environment variable)"),action='count',dest='verbosity')
+par.add_option('-n',help="Run without graphical interface (equivalent to unsetting the DISPLAY environment variable)",dest='nogui',action='store_true')
+par.add_option('--generate-manpage',help="Generate man page documenting this program and exit",dest='manpage',metavar='FILE')
+par.add_option('--rebuild',help="Re-run build in the source directory, then run the updated yade with the same command line except \-\-rebuild. The build profile for this build (${profile}) and its stored parameters will be used.",dest='rebuild',action='store_true')
+par.add_option('--test',help="Run regression test suite and exit; the exists status is 0 if all tests pass, 1 if a test fails and 2 for an unspecified exception.",dest="test",action='store_true')
+par.add_option('--debug',help='Run the debug build, if available.',dest='debug',action='store_true')
+par.add_option('--no-gdb',help='Do not show backtrace when yade crashes (only effective with \-\-debug).',dest='noGdb',action='store_true',)
+par.disable_interspersed_args()
+
+opts,args=par.parse_args()
+
+# re-build yade so that the binary is up-to-date
+if opts.rebuild:
+	import subprocess
+	# rebuild
+	sourceRoot,profile='${sourceRoot}','${profile}' # replaced at install-time
+	cmd=['scons','-Q','-C',sourceRoot,'profile=%s!'%profile,'debug=%d'%(1 if opts.debug else 0),'execCheck=%s'%(prefix+'/bin/yade'+suffix)]
+	print 'Rebuilding yade using',' '.join(cmd)
+	if subprocess.call(cmd): raise RuntimeError('Error rebuilding Yade (--rebuild).')
+	# run ourselves
+	argv=[v for v in sys.argv if v!='--rebuild']
+	print 'Running yade using',' '.join(argv)
+	sys.exit(subprocess.call(argv))
+
+if opts.debug:
+	if not hasDebug:
+		raise RuntimeError('Debug build not available (run without --debug, or try --debug --rebuild)')
+	libDir=debugLibDir
+else:
+	if not hasNonDebug:
+		print 'WARNING: non-debug build not available, running with --debug instead (try --rebuild to get the non-debug build).'
+	libDir=nonDebugLibDir
+
+## remove later
+## python2.5 relative module imports workaround
+v=sys.version_info
+if v[0]==2 and v[1]<=5:
+	for submodule in ('yade','gts','yade/tests'):
+		sys.path.append(os.path.join(libDir,'py',submodule))
+
+sys.path.append(os.path.join(libDir,'py'))
+
+# run regression test suite and exit
+if opts.test:
+	import yade.tests
+	try:
+		result=yade.tests.testAll()
+	except:
+		print 20*'*'+' UNEXPECTED EXCEPTION WHILE RUNNING TESTS '+20*'*'
+		print 20*'*'+' '+str(sys.exc_info()[0])
+		print 20*'*'+" Please report bug at http://bugs.launchpad.net/yade providing the following traceback:"
+		import traceback; traceback.print_exc()
+		print 20*'*'+' Thank you '+20*'*'
+		sys.exit(2)
+	if result.wasSuccessful():
+		print "*** ALL TESTS PASSED ***"
+		sys.exit(0)
+	else:
+		print 20*'*'+' SOME TESTS FAILED '+20*'*'
+		sys.exit(1)
+
+
+# c++ boot code checks for YADE_DEBUG at some places; debug verbosity is equivalent
+# do this early, to have debug messages in the boot code (plugin registration etc)
+if opts.verbosity>1: os.environ['YADE_DEBUG']='1'
+
+# this must be done before loading yade libs ("import yade" below)
+# has no effeect after libgomp initializes
+if opts.threads: os.environ['OMP_NUM_THREADS']=str(opts.threads)
+elif int('$defThreads')>0:
+	os.environ['OMP_NUM_THREADS']='$defThreads'
+
+sys.stderr.write('Welcome to Yade '+version+'%s\n'%(' (debug build)' if opts.debug else ''))
+
+# initialization and c++ plugins import
+import yade
+# other parts we will need soon
+import yade.config
+import yade.wrapper
+import yade.log
+import yade.system
+import yade.runtime
+
+# continue option processing
+
+if opts.updateScripts:
+	yade.system.updateScripts(args)
+	sys.exit(0)
+if opts.manpage:
+	import yade.manpage
+	yade.manpage.generate_manpage(par,yade.config.metadata,opts.manpage,section=1,seealso='yade%s-batch (1)'%suffix)
+	print 'Manual page %s generated.'%opts.manpage
+	sys.exit(0)
+if opts.nice:
+	os.nice(opts.nice)
+if yade.config.debug and opts.noGdb:
+	yade.wrapper.Omega().disableGdb()
+if 'log4cxx' in yade.config.features and opts.verbosity:
+	yade.log.setLevel('',[yade.log.INFO,yade.log.DEBUG,yade.log.TRACE][min(opts.verbosity,2)])
+
+# modify sys.argv in-place so that it can be handled by userSession
+sys.argv=yade.runtime.argv=args
+yade.runtime.opts=opts
+
+from yade import *
+from math import *
+
+def userSession(qt4=False):
+	# prepare nice namespace for users
+	import yade
+	import sys
+	if len(sys.argv)>0:
+		arg0=sys.argv[0]
+		if qt4: yade.qt.Controller();
+		if sum(bool(arg0.endswith(ext)) for ext in ('.xml','.xml.bz2','.xml.gz','.yade','.yade.gz','.yade.bz2','.bin','.bin.gz','.bin.bz2'))>0:
+			if len(sys.argv)>1: raise RuntimeError('Extra arguments to saved simulation to run: '+' '.join(sys.argv[1:]))
+			sys.stderr.write("Running simulation "+arg0+'\n')
+			O=yade.wrapper.Omega(); O.load(arg0); O.run()
+		if arg0.endswith('.py'):
+			def runScript(script):
+				sys.stderr.write("Running script "+arg0+'\n')
+				try:
+					execfile(script,globals())
+				except SystemExit: raise
+				except: # all other exceptions
+					import traceback
+					traceback.print_exc()
+					if yade.runtime.opts.exitAfter: sys.exit(1)
+				if yade.runtime.opts.exitAfter: sys.exit(0)
+			#if qt4:
+			#	class RunScriptThread(QThread):
+			#		def __init__(self,script): QThread.__init__(self); self.script=script
+			#		def run(self): runScript(self.script)
+			#	worker=RunScriptThread(arg0)
+			#	worker.start()
+			#	print 'worker started'
+			#else:
+			runScript(arg0)
+	if yade.runtime.opts.exitAfter: sys.exit(0)
+	# show python console
+	if 1:
+		from IPython.Shell import IPShellEmbed
+		ipshell=IPShellEmbed(
+			#exit_msg='Bye.',
+			banner='[[ ^L clears screen, ^U kills line. '+
+				', '.join((['F12 controller','F11 3d view','F10 both','F9 generator'] if (qt4) else [])+['F8 plot'])+'. ]]',
+			rc_override=dict( # ipython options, see e.g. http://www.cv.nrao.edu/~rreid/casa/tips/ipy_user_conf.py
+				prompt_in1='Yade [\#]: ',
+				prompt_in2='     .\D.: ',
+				prompt_out=" ->  [\#]: ",
+				separate_in='0',
+				separate_out='0',
+				separate_out2='0',
+				#execfile=[prefix+'/lib/yade'+suffix+'/py/yade/ipython.py'],
+				readline_parse_and_bind=[
+					'tab: complete',
+					# only with the gui
+					# the escape codes might not work on non-linux terminals.
+					]
+					+(['"\e[24~": "\C-Uyade.qt.Controller();\C-M"','"\e[23~": "\C-Uyade.qt.View();\C-M"','"\e[21~": "\C-Uyade.qt.Controller(), yade.qt.View();\C-M"','"\e[20~": "\C-Uyade.qt.Generator();\C-M"'] if (qt4) else []) #F12,F11,F10,F9
+					+['"\e[19~": "\C-Uimport yade.plot; yade.plot.plot();\C-M"', #F8
+					'"\e[A": history-search-backward', '"\e[B": history-search-forward', # incremental history forward/backward
+					]
+			)
+		)
+		ipshell()
+		# save history -- a workaround for atexit handlers not being run (why?)
+		# http://lists.ipython.scipy.org/pipermail/ipython-user/2008-September/005839.html
+		import IPython.ipapi
+		IPython.ipapi.get().IP.atexit_operations()
+
+## run userSession in a way corresponding to the features we use:
+gui=None
+yade.runtime.hasDisplay=False # this is the default initialized in the module, anyway
+if 'qt4' in features: gui='qt4'
+if opts.nogui: gui=None
+if gui:
+	import Xlib.display
+	# PyQt4's QApplication does exit(1) if it is unable to connect to the display
+	# we however want to handle this gracefully, therefore
+	# we test the connection with bare xlib first, which merely raises DisplayError
+	try:
+		# contrary to display.Display, _BaseDisplay does not check for extensions and that avoids spurious message "Xlib.protocol.request.QueryExtension" (bug?)
+		Xlib.display._BaseDisplay();
+		yade.runtime.hasDisplay=True
+	except: 
+		# usually Xlib.error.DisplayError, but there can be Xlib.error.XauthError etc as well
+		# let's just pretend any exception means the display would not work
+		gui=None
+
+# run remote access things, before actually starting the user session
+from yade import remote
+yade.remote.useQThread=(gui=='qt4')
+yade.remote.runServers()
+
+if gui==None:
+	userSession()
+elif gui=='qt4':
+	## we already tested that DISPLAY is available and can be opened
+	## otherwise Qt4 might crash at this point
+	import PyQt4
+	from PyQt4 import QtGui
+	from PyQt4.QtCore import *
+	import yade.qt # this yade.qt is different from the one that comes with qt3
+	qapp=QtGui.QApplication(sys.argv)
+	userSession(qt4=True)
+O.exitNoBacktrace()
+

=== added file 'core/main/pyboot.cpp'
--- core/main/pyboot.cpp	1970-01-01 00:00:00 +0000
+++ core/main/pyboot.cpp	2013-11-15 08:22:02 +0000
@@ -0,0 +1,85 @@
+#include<yade/core/Omega.hpp>
+#include<yade/lib-base/Logging.hpp>
+
+#include<signal.h>
+#include<cstdlib>
+#include<cstdio>
+#include<iostream>
+#include<string>
+#include<stdexcept>
+
+#include<boost/python.hpp>
+#include<boost/filesystem/convenience.hpp>
+
+
+#ifdef YADE_LOG4CXX
+	#include<log4cxx/consoleappender.h>
+	#include<log4cxx/patternlayout.h>
+	log4cxx::LoggerPtr logger=log4cxx::Logger::getLogger("yade.boot");
+	/* Initialize log4dcxx automatically when the library is loaded. */
+	__attribute__((constructor)) void initLog4cxx() {
+		#ifdef LOG4CXX_TRACE
+			log4cxx::LevelPtr debugLevel=log4cxx::Level::getDebug(), infoLevel=log4cxx::Level::getInfo(), warnLevel=log4cxx::Level::getWarn();
+			// LOG4CXX_STR: http://old.nabble.com/Link-error-when-using-Layout-on-MS-Windows-td20906802.html
+			log4cxx::LayoutPtr layout(new log4cxx::PatternLayout(LOG4CXX_STR("%-5r %-5p %-10c %m%n")));
+			log4cxx::AppenderPtr appender(new log4cxx::ConsoleAppender(layout));
+			log4cxx::LoggerPtr localLogger=log4cxx::Logger::getLogger("yade");
+			localLogger->addAppender(appender);
+		#else // log4cxx 0.9
+			log4cxx::LevelPtr debugLevel=log4cxx::Level::DEBUG, infoLevel=log4cxx::Level::INFO, warnLevel=log4cxx::Level::WARN;
+			log4cxx::BasicConfigurator::configure();
+			log4cxx::LoggerPtr localLogger=log4cxx::Logger::getLogger("yade");
+		#endif
+		localLogger->setLevel(getenv("YADE_DEBUG")?debugLevel:warnLevel);
+		LOG4CXX_DEBUG(localLogger,"Log4cxx initialized.");
+	}
+#endif
+
+#ifdef YADE_DEBUG
+	void crashHandler(int sig){
+	switch(sig){
+		case SIGABRT:
+		case SIGSEGV:
+			signal(SIGSEGV,SIG_DFL); signal(SIGABRT,SIG_DFL); // prevent loops - default handlers
+			cerr<<"SIGSEGV/SIGABRT handler called; gdb batch file is `"<<Omega::instance().gdbCrashBatch<<"'"<<endl;
+			std::system((string("gdb -x ")+Omega::instance().gdbCrashBatch).c_str());
+			raise(sig); // reemit signal after exiting gdb
+			break;
+		}
+	}		
+#endif
+
+/* Initialize yade, loading given plugins */
+void yadeInitialize(python::list& pp, const std::string& confDir){
+
+	PyEval_InitThreads();
+
+	Omega& O(Omega::instance());
+	O.init();
+	O.origArgv=NULL; O.origArgc=0; // not needed, anyway
+	O.confDir=confDir;
+	O.initTemps();
+	#ifdef YADE_DEBUG
+		ofstream gdbBatch;
+		O.gdbCrashBatch=O.tmpFilename();
+		gdbBatch.open(O.gdbCrashBatch.c_str()); gdbBatch<<"attach "<<lexical_cast<string>(getpid())<<"\nset pagination off\nthread info\nthread apply all backtrace\ndetach\nquit\n"; gdbBatch.close();
+		signal(SIGABRT,crashHandler);
+		signal(SIGSEGV,crashHandler);
+	#endif
+	#ifdef YADE_LOG4CXX
+		// read logging configuration from file and watch it (creates a separate thread)
+		if(filesystem::exists(confDir+"/logging.conf")){
+			std::string logConf=confDir+"/logging.conf";
+			log4cxx::PropertyConfigurator::configure(logConf);
+			LOG_INFO("Loaded "<<logConf);
+		}
+	#endif
+	vector<string> ppp; for(int i=0; i<python::len(pp); i++) ppp.push_back(python::extract<string>(pp[i]));
+	Omega::instance().loadPlugins(ppp);
+}
+void yadeFinalize(){ Omega::instance().cleanupTemps(); }
+
+BOOST_PYTHON_MODULE(boot){
+	python::scope().attr("initialize")=&yadeInitialize;
+	python::scope().attr("finalize")=&yadeFinalize; //,"Finalize yade (only to be used internally).")
+}

=== added file 'core/main/yade-batch.in'
--- core/main/yade-batch.in	1970-01-01 00:00:00 +0000
+++ core/main/yade-batch.in	2013-11-15 08:22:02 +0000
@@ -0,0 +1,437 @@
+#!${pyExecutable}
+# encoding: utf-8
+#
+# vim: syntax=python
+# portions © 2008 Václav Šmilauer <eudoxos@xxxxxxxx>
+
+import os, sys, thread, time, logging, pipes, socket, xmlrpclib, re, shutil
+
+#socket.setdefaulttimeout(10) 
+
+## replaced by scons automatically
+prefix,suffix='${runtimePREFIX}' if not os.environ.has_key('YADE_PREFIX') else os.environ['YADE_PREFIX'],'${SUFFIX}'
+libDir=prefix+'/lib/yade'+suffix # run the batch always in non-debug mode (the spawned processes do honor debuggin flag, however)
+sys.path.append(os.path.join(libDir,'py'))
+executable=os.path.join(prefix,'bin','yade'+suffix)
+## we just need this ...
+import yade, yade.utils, yade.config, yade.remote
+
+
+class JobInfo():
+	def __init__(self,num,id,command,hrefCommand,log,nSlots,script,table,lineNo):
+		self.started,self.finished,self.duration,self.exitStatus=None,None,None,None
+		self.command=command; self.hrefCommand=hrefCommand; self.num=num; self.log=log; self.id=id; self.nSlots=nSlots; self.infoSocket=None
+		self.script=script; self.table=table; self.lineNo=lineNo
+		self.hasXmlrpc=False
+		self.status='PENDING'
+		self.threadNum=None
+		self.plotsLastUpdate,self.plotsFile=0.,yade.Omega().tmpFilename()+'.'+yade.remote.plotImgFormat
+	def saveInfo(self):
+		log=file(self.log,'a')
+		log.write("""
+=================== JOB SUMMARY ================
+id      : %s
+status  : %d (%s)
+duration: %s
+command : %s
+started : %s
+finished: %s
+"""%(self.id,self.exitStatus,'OK' if self.exitStatus==0 else 'FAILED',self.duration,self.command,time.asctime(time.localtime(self.started)),time.asctime(time.localtime(self.finished))));
+		log.close()
+	def ensureXmlrpc(self):
+		if not self.hasXmlrpc:
+			for l in open(self.log,'r'):
+				if not l.startswith('XMLRPC info provider on'): continue
+				url=l[:-1].split()[4]
+				self.xmlrpcConn=xmlrpclib.ServerProxy(url,allow_none=True)
+				self.hasXmlrpc=True
+	def getInfoDict(self):
+		if self.status!='RUNNING': return None
+		self.ensureXmlrpc()
+		return self.xmlrpcConn.basicInfo()
+	def updatePlots(self):
+		global opts
+		if self.status!='RUNNING': return
+		self.ensureXmlrpc()
+		if time.time()-self.plotsLastUpdate<opts.plotTimeout: return
+		self.plotsLastUpdate=time.time()
+		img=self.xmlrpcConn.plot()
+		if not img:
+			if os.path.exists(self.plotsFile): os.remove(self.plotsFile)
+			return
+		f=open(self.plotsFile,'wb')
+		f.write(img.data)
+		f.close()
+		#print yade.remote.plotImgFormat,'(%d bytes) written to %s'%(os.path.getsize(self.plotsFile),self.plotsFile)
+
+	def htmlStats(self):
+		ret='<tr>'
+		ret+='<td>%s</td>'%self.id
+		if self.status=='PENDING': ret+='<td bgcolor="grey">(pending)</td>'
+		elif self.status=='RUNNING': ret+='<td bgcolor="yellow">%s</td>'%t2hhmmss(time.time()-self.started)
+		elif self.status=='DONE': ret+='<td bgcolor="%s">%s</td>'%('lime' if self.exitStatus==0 else 'red',self.duration)
+		info=self.getInfoDict()
+		self.updatePlots() # checks for last update time
+		if info:
+			ret+='<td>'
+			if info['stopAtIter']>0:
+				ret+='<nobr>%2.2f%% done</nobr><br/><nobr>step %d/%d</nobr>'%(info['iter']*100./info['stopAtIter'],info['iter'],info['stopAtIter'])
+			else: ret+='<nobr>step %d</nobr>'%(info['iter'])
+			if info['realtime']!=0: ret+='<br/><nobr>avg %g/sec</nobr>'%(info['iter']/info['realtime'])
+			ret+='<br/><nobr>%d bodies</nobr><br/><nobr>%d intrs</nobr>'%(info['numBodies'],info['numIntrs'])
+			ret+='</td>'
+		else:
+			ret+='<td> (no info) </td>'
+		ret+='<td>%d</td>'%self.nSlots
+		# TODO: make clickable so that it can be served full-size
+		if os.path.exists(self.plotsFile):
+			if 0: pass
+				## all this mess to embed SVG; clicking on it does not work, though
+				## question posted at http://www.abclinuxu.cz/poradna/linux/show/314041
+				## see also http://www.w3schools.com/svg/svg_inhtml.asp and http://dutzend.blogspot.com/2010/04/svg-im-anklickbar-machen.html
+				#img='<object data="/jobs/%d/plots" type="%s" width="300px" alt="[plots]"/>'%(self.num,yade.remote.plotImgMimetype)
+				#img='<iframe src="/jobs/%d/plots" type="%s" width="300px" alt="[plots]"/>'%(self.num,yade.remote.plotImgMimetype)
+				#img='<embed src="/jobs/%d/plots" type="%s" width="300px" alt="[plots]"/>'%(self.num,yade.remote.plotImgMimetype)a
+			img='<img src="/jobs/%d/plots" width="300px" alt="[plots]">'%(self.num)
+			ret+='<td><a href="/jobs/%d/plots">%s</a></td>'%(self.num,img)
+		else: ret+='<td> (no plots) </td>'
+		ret+='<td>%s</td>'%self.hrefCommand
+		ret+='</tr>'
+		return ret
+def t2hhmmss(dt): return '%02d:%02d:%02d'%(dt//3600,(dt%3600)//60,(dt%60))
+
+def totalRunningTime():
+	tt0,tt1=[j.started for j in jobs if j.started],[j.finished for j in jobs if j.finished]+[time.time()]
+	# it is safe to suppose that 
+	if len(tt0)==0: return 0 # no job has been started at all
+	return max(tt1)-min(tt0)
+
+def globalHtmlStats():
+	t0=min([j.started for j in jobs if j.started!=None])
+	unfinished=len([j for j in jobs if j.status!='DONE'])
+	usedSlots=sum([j.nSlots for j in jobs if j.status=='RUNNING'])
+	global maxJobs
+	if unfinished:
+		ret='<p>Running for %s, since %s.</p>'%(t2hhmmss(totalRunningTime()),time.ctime(t0))
+	else:
+		failed=len([j for j in jobs if j.exitStatus!=0])
+		lastFinished=max([j.finished for j in jobs])
+		# FIXME: do not report sum of runnign time of all jobs, only the real timespan
+		ret='<p><span style="background-color:%s">Finished</span>, idle for %s, running time %s since %s.</p>'%('red' if failed else 'lime',t2hhmmss(time.time()-lastFinished),t2hhmmss(sum([j.finished-j.started for j in jobs if j.started is not None])),time.ctime(t0))
+	ret+='<p>Pid %d</p>'%(os.getpid())
+	ret+='<p>%d slots available, %d used, %d free.</p>'%(maxJobs,usedSlots,maxJobs-usedSlots)
+	ret+='<h3>Jobs</h3>'
+	nFailed=len([j for j in jobs if j.status=='DONE' and j.exitStatus!=0])
+	ret+='<p><b>%d</b> total, <b>%d</b> <span style="background-color:yellow">running</span>, <b>%d</b> <span style="background-color:lime">done</span>%s</p>'%(len(jobs),len([j for j in jobs if j.status=='RUNNING']), len([j for j in jobs if j.status=='DONE']),' (<b>%d <span style="background-color:red"><b>failed</b></span>)'%nFailed if nFailed>0 else '')
+	return ret
+
+from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
+import socket,re
+class HttpStatsServer(BaseHTTPRequestHandler):
+	favicon=None # binary favicon, created when first requested
+	def do_GET(self):
+		if not self.path or self.path=='/': self.sendGlobal()
+		else:
+			if self.path=='/favicon.ico':
+				if not self.__class__.favicon:
+					import base64
+					self.__class__.favicon=base64.b64decode(yade.remote.b64favicon)
+				self.sendHttp(self.__class__.favicon,contentType='image/vnd.microsoft.icon')
+				return
+			jobMatch=re.match('/jobs/([0-9]+)/(.*)',self.path)
+			if not jobMatch:
+				self.send_error(404,self.path); return
+			jobId=int(jobMatch.group(1))
+			if jobId>=len(jobs):
+				self.send_error(404,self.path); return
+			job=jobs[jobId]
+			rest=jobMatch.group(2)
+			if rest=='plots':
+				job.updatePlots() # internally checks for last update time
+				self.sendFile(job.plotsFile,contentType=yade.remote.plotImgMimetype,refresh=(0 if job.status=='DONE' else 5))
+			elif rest=='log':
+				if not os.path.exists(job.log):
+					self.send_error(404,self.path); return
+				## once we authenticate properly, send the whole file
+				## self.sendTextFile(jobs[jobId].log,refresh=5)
+				## now we have to filter away the cookie
+				cookieRemoved=False; data=''
+				for l in open(job.log):
+					if not cookieRemoved and l.startswith('TCP python prompt on'):
+						ii=l.find('auth cookie `'); l=l[:ii+13]+'******'+l[ii+19:]; cookieRemoved=True
+					data+=l
+				self.sendHttp(data,contentType='text/plain;charset=utf-8;',refresh=(0 if job.status=='DONE' else 5))
+			elif rest=='script':
+				self.sendPygmentizedFile(job.script,linenostep=5)
+			elif rest=='table':
+				self.sendPygmentizedFile(job.table,hl_lines=[job.lineNo],linenostep=1)
+			else: self.send_error(404,self.path)
+		return
+	def log_request(self,req): pass
+	def sendGlobal(self):
+		html='<HTML><TITLE>Yade-batch at %s overview</TITLE><BODY>\n'%(socket.gethostname())
+		html+=globalHtmlStats()
+		html+='<TABLE border=1><tr><th>id</th><th>status</th><th>info</th><th>slots</th><th>plots</th><th>command</th></tr>\n'
+		for j in jobs: html+=j.htmlStats()+'\n'
+		html+='</TABLE></BODY></HTML>'
+		self.sendHttp(html,contentType='text/html',refresh=5) # refresh sent as header
+	def sendTextFile(self,fileName,**headers):
+		if not os.path.exists(fileName): self.send_error(404); return
+		import codecs
+		f=codecs.open(f,encoding='utf-8')
+		self.sendHttp(f.read(),contentType='text/plain;charset=utf-8;',**headers)
+	def sendFile(self,fileName,contentType,**headers):
+		if not os.path.exists(fileName): self.send_error(404); return
+		f=open(fileName)
+		self.sendHttp(f.read(),contentType=contentType,**headers)
+	def sendHttp(self,data,contentType,**headers):
+		"Send file over http, using appropriate content-type. Headers are converted to strings. The *refresh* header is handled specially: if the value is 0, it is not sent at all."
+		self.send_response(200)
+		self.send_header('Content-type',contentType)
+		if 'refresh' in headers and headers['refresh']==0: del headers['refresh']
+		for h in headers: self.send_header(h,str(headers[h]))
+		self.end_headers()
+		self.wfile.write(data)
+		global httpLastServe
+		httpLastServe=time.time()
+	def sendPygmentizedFile(self,f,**kw):
+		if not os.path.exists(f):
+			self.send_error(404); return
+		try:
+			import codecs
+			from pygments import highlight
+			from pygments.lexers import PythonLexer
+			from pygments.formatters import HtmlFormatter
+			data=highlight(codecs.open(f,encoding='utf-8').read(),PythonLexer(),HtmlFormatter(linenos=True,full=True,encoding='utf-8',title=os.path.abspath(f),**kw))
+			self.sendHttp(data,contentType='text/html;charset=utf-8;')
+		except ImportError:
+			self.sendTextFile(f)
+def runHttpStatsServer():
+	maxPort=11000; port=9080
+	while port<maxPort:
+		try:
+			server=HTTPServer(('',port),HttpStatsServer)
+			import thread; thread.start_new_thread(server.serve_forever,())
+			print "http://localhost:%d shows batch summary"%port
+			break
+		except socket.error:
+			port+=1
+	if port==maxPort:
+		print "WARN: No free port in range 9080-11000, not starting HTTP stats server!"
+
+
+def runJob(job):
+	job.status='RUNNING'
+	job.started=time.time();
+	print '#%d (%s%s) started on %s'%(job.num,job.id,'' if job.nSlots==1 else '/%d'%job.nSlots,time.asctime())
+	job.exitStatus=os.system(job.command)
+	if job.exitStatus!=0 and len([l for l in open(job.log) if l.startswith('Yade: normal exit.')])>0: job.exitStatus=0
+	job.finished=time.time()
+	dt=job.finished-job.started;
+	job.duration=t2hhmmss(dt)
+	strStatus='done   ' if job.exitStatus==0 else 'FAILED '
+	job.status='DONE'
+	havePlot=False
+	if os.path.exists(job.plotsFile):
+		f=(job.log[:-3] if job.log.endswith('.log') else job.log+'.')+yade.remote.plotImgFormat
+		shutil.copy(job.plotsFile,f)
+		job.plotsFile=f
+		havePlot=True
+	print "#%d (%s%s) %s (exit status %d), duration %s, log %s%s"%(job.num,job.id,'' if job.nSlots==1 else '/%d'%job.nSlots,strStatus,job.exitStatus,job.duration,job.log,(', plot %s'%(job.plotsFile) if havePlot else ''))
+	job.saveInfo()
+	
+def runJobs(jobs,numSlots):
+	running,pending=0,len(jobs)
+	inf=1000000
+	while (running>0) or (pending>0):
+		pending,running,done=sum([j.nSlots for j in jobs if j.status=='PENDING']),sum([j.nSlots for j in jobs if j.status=='RUNNING']),sum([j.nSlots for j in jobs if j.status=='DONE'])
+		#print [j.status for j in jobs]
+		freeSlots=numSlots-running
+		minRequire=min([inf]+[j.nSlots for j in jobs if j.status=='PENDING'])
+		if minRequire==inf: minRequire=0
+		#print pending,'pending;',running,'running;',done,'done;',freeSlots,'free;',minRequire,'min'
+		if minRequire>freeSlots and running==0:
+			freeSlots=minRequire
+		for j in [j for j in jobs if j.status=='PENDING']:
+			if j.nSlots<=freeSlots:
+				thread.start_new_thread(runJob,(j,))
+				break
+		time.sleep(.5)
+		sys.stdout.flush()
+
+
+import sys,re,optparse,os
+def getNumCores():
+	nCpu=len([l for l in open('/proc/cpuinfo','r') if l.find('processor')==0])
+	if os.environ.has_key("OMP_NUM_THREADS"): return min(int(os.environ['OMP_NUM_THREADS']),nCpu)
+	return nCpu
+numCores=getNumCores()
+
+parser=optparse.OptionParser(usage='%prog [options] TABLE SIMULATION.py',description='%prog runs yade simulation multiple times with different parameters.\n\nSee https://yade-dem.org/sphinx/user.html#batch-queuing-and-execution-yade-batch for details.')
+parser.add_option('-j','--jobs',dest='maxJobs',type='int',help="Maximum number of simultaneous threads to run (default: number of cores, further limited by OMP_NUM_THREADS if set by the environment: %d)"%numCores,metavar='NUM',default=numCores)
+parser.add_option('--job-threads',dest='defaultThreads',type='int',help="Default number of threads for one job; can be overridden by per-job OMP_NUM_THREADS. Defaults to allocate all available cores (%d) for each job."%numCores,metavar='NUM',default=numCores)
+parser.add_option('--force-threads',action='store_true',dest='forceThreads')
+parser.add_option('--log',dest='logFormat',help='Format of job log files -- must contain a % or @, which will be replaced by line number or by description column respectively (default: SIMULATION.@.log)',metavar='FORMAT')
+parser.add_option('--global-log',dest='globalLog',help='Filename where to redirect output of yade-batch itself (as opposed to \-\-log); if not specified (default), stdout/stderr are used',metavar='FILE')
+parser.add_option('-l','--lines',dest='lineList',help='Lines of TABLE to use, in the format 2,3-5,8,11-13 (default: all available lines in TABLE)',metavar='LIST')
+parser.add_option('--nice',dest='nice',type='int',help='Nice value of spawned jobs (default: 10)',default=10)
+parser.add_option('--executable',dest='executable',help='Name of the program to run (default: %s)'%executable,default=executable,metavar='FILE')
+parser.add_option('--rebuild',dest='rebuild',help='Run executable(s) with \-\-rebuild prior to running any jobs.',default=False,action='store_true')
+parser.add_option('--debug',dest='debug',action='store_true',help='Run the executable with \-\-debug.',default=False)
+parser.add_option('--gnuplot',dest='gnuplotOut',help='Gnuplot file where gnuplot from all jobs should be put together',default=None,metavar='FILE')
+parser.add_option('--dry-run',action='store_true',dest='dryRun',help='Do not actually run (useful for getting gnuplot only, for instance)',default=False)
+parser.add_option('--http-wait',action='store_true',dest='httpWait',help='Do not quit if still serving overview over http repeatedly',default=False)
+parser.add_option('--generate-manpage',help='Generate man page documenting this program and exit',dest='manpage',metavar='FILE')
+parser.add_option('--plot-update',type='int',dest='plotAlwaysUpdateTime',help='Interval (in seconds) at which job plots will be updated even if not requested via HTTP. Non-positive values will make the plots not being updated and saved unless requested via HTTP (see \-\-plot-timeout for controlling maximum age of those).  Plots are saved at exit under the same name as the log file, with the .log extension removed. (default: 60 seconds)',metavar='TIME',default=60)
+parser.add_option('--plot-timeout',type='int',dest='plotTimeout',help='Maximum age (in seconds) of plots served over HTTP; they will be updated if they are older. (default: 10 seconds)',metavar='TIME',default=10)
+opts,args=parser.parse_args()
+logFormat,lineList,maxJobs,nice,executable,gnuplotOut,dryRun,httpWait,globalLog=opts.logFormat,opts.lineList,opts.maxJobs,opts.nice,opts.executable,opts.gnuplotOut,opts.dryRun,opts.httpWait,opts.globalLog
+
+if opts.manpage:
+	import yade.manpage
+	yade.config.metadata['short_desc']='batch system for computational platform Yade'
+	yade.config.metadata['long_desc']='Manage batches of computation jobs for the Yade platform; batches are described using text-file tables with parameters which are passed to individual runs of yade. Jobs are being run with pre-defined number of computational cores as soon as the required number of cores is available. Logs of all computations are stored in files and the batch progress can be watched online at (usually) http://localhost:9080. Unless overridden, the executable yade%s is used to run jobs.'%(suffix)
+	yade.manpage.generate_manpage(parser,yade.config.metadata,opts.manpage,section=1,seealso='yade%s (1)\n.br\nhttps://yade-dem.org/sphinx/user.html#batch-queuing-and-execution-yade-batch'%suffix)
+	print 'Manual page %s generated.'%opts.manpage
+	sys.exit(0)
+
+if globalLog:
+	sys.stderr=open(globalLog,"w")
+	sys.stdout=sys.stderr
+
+if len(args)!=2:
+	#print "Exactly two non-option arguments must be specified -- parameter table and script to be run.\n"
+	parser.print_help()
+	sys.exit(1)
+table,simul=args[0:2]
+if not logFormat: logFormat=(simul[:-3] if simul[-3:]=='.py' else simul)+".@.log"
+if (not '%' in logFormat) and ('@' not in logFormat): raise StandardError("Log string must contain at least one of `%', `@'")
+
+print "Will run `%s' on `%s' with nice value %d, output redirected to `%s', %d jobs at a time."%(executable,simul,nice,logFormat,maxJobs)
+
+reader=yade.utils.TableParamReader(table)
+params=reader.paramDict()
+availableLines=params.keys()
+
+print "Will use table `%s', with available lines"%(table),', '.join([str(i) for i in availableLines])+'.'
+
+if lineList:
+	useLines=[]
+	def numRange2List(s):
+		ret=[]
+		for l in s.split(','):
+			if "-" in l: ret+=range(*[int(s) for s in l.split('-')]); ret+=[ret[-1]+1]
+			else: ret+=[int(l)]
+		return ret
+	useLines0=numRange2List(lineList)
+	for l in useLines0:
+		if l not in availableLines: logging.warn('Skipping unavailable line %d that was requested from the command line.'%l)
+		else: useLines+=[l]
+else: useLines=availableLines
+print "Will use lines ",', '.join([str(i)+' (%s)'%params[i]['description'] for i in useLines])+'.'
+
+jobs=[]
+executables=set()
+for i,l in enumerate(useLines):
+	logFile=logFormat.replace('%',str(l))
+	logFile=logFile.replace('@',params[l]['description'])
+	envVars=[]
+	nSlots=opts.defaultThreads
+	for col in params[l].keys():
+		if col[0]!='!': continue
+		if col=='!OMP_NUM_THREADS':
+			nSlots=int(params[l][col]); maxCpu=getNumCores()
+		elif col=='!EXEC': executable=params[l][col]
+		else: envVars+=['%s=%s'%(head[1:],values[l][col])]
+	if nSlots>maxJobs:
+		if opts.forceThreads:
+			logging.info('Forcing job #%d to use only %d slots (max available) instead of %d requested'%(i,maxJobs,nSlots))
+			nSlots=maxJobs
+		else:
+			logging.warning('WARNING: job #%d will use %d slots but only %d are available'%(i,nSlots,maxJobs))
+	executables.add(executable)
+	# compose command-line: build the hyper-linked variant, then strip HTML tags (ugly, but ensures consistency)
+	env='PARAM_TABLE=<a href="jobs/%d/table">%s:%d</a> DISPLAY= %s '%(i,table,l,' '.join(envVars))
+	cmd='%s%s --threads=%d %s -x <a href="jobs/%d/script">%s</a>'%(executable,' --debug' if opts.debug else '',int(nSlots),'--nice=%s'%nice if nice!=None else '',i,simul)
+	log='> <a href="jobs/%d/log">%s</a> 2>&1'%(i,pipes.quote(logFile))
+	hrefCmd=env+cmd+log
+	fullCmd=re.sub('(<a href="[^">]+">|</a>)','',hrefCmd)
+	jobs.append(JobInfo(i,params[l]['description'],fullCmd,hrefCmd,logFile,nSlots,script=simul,table=table,lineNo=l))
+
+print "Master process pid",os.getpid()
+
+if opts.rebuild:
+	print "Rebuilding all active executables, since --rebuild was specified"
+	for e in executables:
+		import subprocess
+		if subprocess.call([e,'--rebuild','-x']+(['--debug'] if opts.debug else [])):
+			 raise RuntimeError('Error rebuilding %s (--rebuild).'%e)
+	print "Rebuilding done."
+		
+
+print "Job summary:"
+for job in jobs:
+	print '   #%d (%s%s):'%(job.num,job.id,'' if job.nSlots==1 else '/%d'%job.nSlots),job.command
+sys.stdout.flush()
+
+
+httpLastServe=0
+runHttpStatsServer()
+if opts.plotAlwaysUpdateTime>0:
+	# update plots periodically regardless of whether they are requested via HTTP
+	def updateAllPlots():
+		time.sleep(opts.plotAlwaysUpdateTime)
+		for job in jobs: job.updatePlots()
+	thread.start_new_thread(updateAllPlots,())
+
+# OK, go now
+if not dryRun: runJobs(jobs,maxJobs)
+
+print 'All jobs finished, total time ',t2hhmmss(totalRunningTime())
+
+plots=[]
+for j in jobs:
+	if not os.path.exists(j.plotsFile): continue
+	plots.append(j.plotsFile)
+if plots: print 'Plot files:',' '.join(plots)
+
+# for easy grepping in logfiles:
+print 'Log files:',' '.join([j.log for j in jobs])
+
+if not gnuplotOut:
+	print 'Bye.'
+else:
+	print 'Assembling gnuplot files…'
+	for job in jobs:
+		for l in file(job.log):
+			if l.startswith('gnuplot '):
+				job.plot=l.split()[1]
+				break
+	preamble,plots='',[]
+	for job in jobs:
+		if not 'plot' in job.__dict__:
+			print "WARN: No plot found for job "+job.id
+			continue
+		for l in file(job.plot):
+			if l.startswith('plot'):
+				# attempt to parse the plot line
+				ll=l.split(' ',1)[1][:-1] # rest of the line, without newline
+				# replace title 'something' with title 'description: something'
+				ll,nn=re.subn(r'title\s+[\'"]([^\'"]*)[\'"]',r'title "'+job.id+r': \1"',ll)
+				if nn==0:
+					logging.error("Plot line in "+job.plot+" not parsed (skipping): "+ll)
+				plots.append(ll)
+				break
+			if not plots: # first plot, copy all preceding lines
+				preamble+=l
+	gp=file(gnuplotOut,'w')
+	gp.write(preamble)
+	gp.write('plot '+','.join(plots))
+	print "gnuplot",gnuplotOut
+	print "Plot written, bye."
+if httpWait and time.time()-httpLastServe<30:
+	print "(continue serving http until no longer requested  as per --http-wait)"
+	while time.time()-httpLastServe<30:
+		time.sleep(1)
+
+yade.Omega().exitNoBacktrace()

=== added directory 'doc'
=== renamed directory 'doc' => 'doc.moved'
=== added file 'doc/Doxyfile'
--- doc/Doxyfile	1970-01-01 00:00:00 +0000
+++ doc/Doxyfile	2013-11-15 08:22:02 +0000
@@ -0,0 +1,1561 @@
+# Doxyfile 1.5.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file 
+# that follow. The default is UTF-8 which is also the encoding used for all 
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the 
+# iconv built into libc) for the transcoding. See 
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = Yade
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = trunk
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ./doxygen
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of 
+# source files, where putting all generated files in the same directory would 
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = YES
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, 
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), 
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, 
+# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, 
+# Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is 
+# used as the annotated text. Otherwise, the brief description is used as-is. 
+# If left blank, the following values are used ("$name" is automatically 
+# replaced with the name of the entity): "The $name class" "The $name widget" 
+# "The $name file" "is" "provides" "specifies" "contains" 
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
+# inherited members of a class in the documentation of that class as if those 
+# members were ordinary class members. Constructors, destructors and assignment 
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = ../
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like regular Qt-style comments 
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
+# interpret the first line (until the first dot) of a Qt-style 
+# comment as the brief description. If set to NO, the comments 
+# will behave just like regular Qt-style comments (thus requiring 
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
+# a new page for each member. If set to NO, the documentation of a member will 
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = "fixme=\par FIXME:\n"
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
+# sources only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Java. For instance, namespaces will be presented as packages, qualified 
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 
+# sources only. Doxygen will then generate output that is more tailored for 
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 
+# sources. Doxygen will then generate output that is tailored for 
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses. 
+# With this tag you can assign which parser to use for a given extension. 
+# Doxygen has a built-in mapping, but you can override or extend it using this tag. 
+# The format is ext=language, where ext is a file extension, and language is one of 
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, 
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat 
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), 
+# use: inc=Fortran f=C
+
+EXTENSION_MAPPING      = 
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 
+# to include (a tag file for) the STL sources as input, then you should 
+# set this tag to YES in order to let doxygen match functions declarations and 
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
+# func(std::string) {}). This also make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to 
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 
+# Doxygen will parse them like normal C++ but will assume all classes use public 
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter 
+# and setter methods for a property. Setting this option to YES (the default) 
+# will make doxygen to replace the get and set methods by a property in the 
+# documentation. This will only work if the methods are indeed getting or 
+# setting a simple type. If this is not the case, or you want to show the 
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = YES
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 
+# is documented as struct, union, or enum with the name of the typedef. So 
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct 
+# with name TypeT. When disabled the typedef will appear as a member of a file, 
+# namespace, or class. And the struct will be named TypeS. This can typically 
+# be useful for C code in case the coding convention dictates that all compound 
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 
+# determine which symbols to keep in memory and which to flush to disk. 
+# When the cache is full, less often used symbols will be written to disk. 
+# For small to medium size projects (<1000 input files) the default value is 
+# probably good enough. For larger projects a too small cache size can cause 
+# doxygen to be busy swapping symbols to and from disk most of the time 
+# causing a significant performance penality. 
+# If the system has enough physical memory increasing the cache will improve the 
+# performance by keeping more symbols in memory. Note that the value works on 
+# a logarithmic scale so increasing the size by one will rougly double the 
+# memory usage. The cache size is given by this formula: 
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be 
+# extracted and appear in the documentation as a namespace called 
+# 'anonymous_namespace{file}', where file will be replaced with the base 
+# name of the file that contains the anonymous namespace. By default 
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = YES
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 
+# hierarchy of group names into alphabetical order. If set to NO (the default) 
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. 
+# This will remove the Files entry from the Quick Index and from the 
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the 
+# Namespaces page. 
+# This will remove the Namespaces entry from the Quick Index 
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
+# doxygen should invoke to get the current version for each file (typically from 
+# the version control system). Doxygen will invoke the program by executing (via 
+# popen()) the command <command> <input-file>, where <command> is the value of 
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
+# provided by doxygen. Whatever the program writes to standard output 
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    = 
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by 
+# doxygen. The layout file controls the global structure of the generated output files 
+# in an output format independent way. The create the layout file that represents 
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a 
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name 
+# of the layout file.
+
+LAYOUT_FILE            = 
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for 
+# functions that are documented, but have no documentation for their parameters 
+# or return value. If set to NO (the default) doxygen will only warn about 
+# wrong or incomplete parameter documentation, but not about the absence of 
+# documentation.
+
+WARN_NO_PARAMDOC       = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text. Optionally the format may contain 
+# $version, which will be replaced by the version of the file (if it could 
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = ../core/ ../gui/ ../pkg/ ../py/ ../extra/
+
+# This tag can be used to specify the character encoding of the source files 
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
+# also the default input encoding. Doxygen uses libiconv (or the iconv built 
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.d \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.tpp \
+                         *.i++ \
+                         *.inl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.idl \
+                         *.odl \
+                         *.cs \
+                         *.php \
+                         *.php3 \
+                         *.inc \
+                         *.m \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.C \
+                         *.CC \
+                         *.C++ \
+                         *.II \
+                         *.I++ \
+                         *.H \
+                         *.HH \
+                         *.H++ \
+                         *.CS \
+                         *.PHP \
+                         *.PHP3 \
+                         *.M \
+                         *.MM \
+                         *.PY
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem feature) are excluded 
+# from the input.
+
+EXCLUDE_SYMLINKS       = YES
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories. Note that the wildcards are matched 
+# against the file with absolute path, so to exclude all test directories 
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = */.* */3rd-party/* */mgpost/* */SpherePadder/* */*.py
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
+# (namespaces, classes, functions, etc.) that should be excluded from the 
+# output. The symbol name can be a fully qualified name, a word, or if the 
+# wildcard * is used, a substring. Examples: ANamespace, AClass, 
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        = pyplusplus custom_* boost::* MetaEngine1D* MetaEngine2D* std::* EngineUnit1D* EngineUnit2D* try_mutex Serializable Indexable Factorable
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output. 
+# If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis. 
+# Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match. 
+# The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 
+# link to the source code. 
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code 
+# will point to the HTML generated by the htags(1) tool instead of doxygen 
+# built-in source browser. The htags tool is part of GNU's global source 
+# tagging system (see http://www.gnu.org/software/global/global.html). You 
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
+# documentation will contain sections that can be hidden and shown after the 
+# page has loaded. For this to work a browser that supports 
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files 
+# will be generated that can be used as input for Apple's Xcode 3 
+# integrated development environment, introduced with OSX 10.5 (Leopard). 
+# To create a documentation set, doxygen will generate a Makefile in the 
+# HTML output directory. Running make will produce the docset in that 
+# directory and running "make install" will install the docset in 
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 
+# it at startup. 
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 
+# feed. A documentation feed provides an umbrella under which multiple 
+# documentation sets from a single provider (such as a company or product suite) 
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 
+# should uniquely identify the documentation set bundle. This should be a 
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file 
+# content.
+
+CHM_INDEX_ENCODING     = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = YES
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER 
+# are set, an additional index file will be generated that can be used as input for 
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated 
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can 
+# be used to specify the file name of the resulting .qch file. 
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               = 
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = 
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 
+# Qt Help Project output. For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. 
+# For more information please see 
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   = 
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see 
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters";>Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  = 
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's 
+# filter section matches. 
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes";>Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  = 
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 
+# be used to specify the location of Qt's qhelpgenerator. 
+# If non-empty doxygen will try to run qhelpgenerator on the generated 
+# .qhp file.
+
+QHG_LOCATION           = 
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 
+# structure should be generated to display hierarchical information. 
+# If the tag value is set to FRAME, a side panel will be generated 
+# containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature. Other possible values 
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories, 
+# and Class Hierarchy pages using a tree view instead of an ordered list; 
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which 
+# disables this behavior completely. For backwards compatibility with previous 
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE 
+# respectively.
+
+GENERATE_TREEVIEW      = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included 
+# as images in the HTML documentation. The default is 10. Note that 
+# when you change the font size after a successful doxygen run you need 
+# to manually remove any form_*.png images from the HTML output directory 
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader. 
+# This is useful 
+# if you want to understand what is going on. 
+# On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed. To prevent a macro definition from being 
+# undefined via #undef or recursively expanded use the := operator 
+# instead of the = operator.
+
+PREDEFINED             = 
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse 
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#  
+# TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#  
+# TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links. 
+# Note that each tag file must have a unique name 
+# (where the name does NOT include the path) 
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
+# or super classes. Setting the tag to NO turns the diagrams off. Note that 
+# this option is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc 
+# command. Doxygen will then run the mscgen tool (see 
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where 
+# the mscgen tool resides. If left empty the tool is assumed to be found in the 
+# default search path.
+
+MSCGEN_PATH            = 
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output 
+# directory and reference it in all dot files that doxygen generates. This 
+# font does not include all possible unicode characters however, so when you need 
+# these (or just want a differently looking font) you can specify the font name 
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font, 
+# which can be done by putting it in a standard location or by setting the 
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory 
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the 
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a 
+# different font using DOT_FONTNAME you can set the path where dot 
+# can find it using this tag.
+
+DOT_FONTPATH           = 
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then 
+# doxygen will generate a call dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable call graphs 
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 
+# doxygen will generate a caller dependency graph for every global function 
+# or class method. Note that enabling this option will significantly increase 
+# the time of a run. So in most cases it will be better to enable caller 
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
+# then doxygen will show the dependencies a directory has on other directories 
+# in a graphical way. The dependency relations are determined by the #include 
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif 
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
+# nodes that will be shown in the graph. If the number of nodes in a graph 
+# becomes larger than this value, doxygen will truncate the graph, which is 
+# visualized by representing a node as a red box. Note that doxygen if the 
+# number of direct children of the root node in a graph is already larger than 
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes 
+# that lay further from the root node will be omitted. Note that setting this 
+# option to 1 or 2 may greatly reduce the computation time needed for large 
+# code bases. Also note that the size of a graph can be further restricted by 
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, because dot on Windows does not 
+# seem to support this out of the box. Warning: Depending on the platform used, 
+# enabling this option may lead to badly anti-aliased labels on the edges of 
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
+# files in one run (i.e. multiple -o and -T options on the command line). This 
+# makes dot run faster, but since only newer versions of dot (>1.8.10) 
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Options related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = YES

=== added file 'doc/README'
--- doc/README	1970-01-01 00:00:00 +0000
+++ doc/README	2013-11-15 08:22:02 +0000
@@ -0,0 +1,6 @@
+All documentation is at http://www.yade-dem.org, in particular see 
+https://yade-dem.org/index.php/Reference_documentation
+
+To generate documentation see sphinx/README
+
+

=== added file 'doc/logging.conf.sample'
--- doc/logging.conf.sample	1970-01-01 00:00:00 +0000
+++ doc/logging.conf.sample	2013-11-15 08:22:02 +0000
@@ -0,0 +1,38 @@
+# This is example logging configuration file for yade.
+#
+# Place it in ~/.yade/logging.conf if you want it to be loaded and watched for changes during execution as well.
+#
+# log4cxx homepage is http://logging.apache.org/log4cxx/
+# of particular interest is instroduction (http://logging.apache.org/log4cxx/manual/Introduction.html)
+# and pattern description (http://logging.apache.org/log4cxx/manual/classlog4cxx_1_1PatternLayout.html)
+#
+
+# Set root logger level to DEBUG, one appender for console and other to a file
+log4j.rootLogger=DEBUG,console,logfile
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+# A1 uses PatternLayout.
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+#log4j.appender.console.layout.ConversionPattern=%-4r %-5p %c %x - %m%n # this is the default
+log4j.appender.console.layout.ConversionPattern=%-5p %-10c %m%n
+
+# this appender creates logfile that is being rotated following a size criterion
+# better would be to rotate it at every execution, but I am not sure if that exists in log4cxx...
+log4j.appender.logfile=org.apache.log4j.RollingFileAppender
+log4j.appender.logfile.File=/tmp/yade.log
+log4j.appender.logfile.MaxFileSize=10MB
+log4j.appender.logfile.MaxBackupIndex=1 # Keep one backup file
+log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
+log4j.appender.logfile.layout.ConversionPattern=%-5p %t %-10c %m%n
+
+
+# Minimum level of messages you want to see
+# Childs inherit from their parents, unless overridden explicitly, therefore
+# the following disables DEBUG messages by default (everywhere)
+log4j.logger.yade=INFO
+# except for the classes where requested:
+#log4j.logger.yade.Omega=DEBUG
+log4j.logger.yade.DynLibManager=DEBUG
+
+
+

=== added file 'doc/references.bib'
--- doc/references.bib	1970-01-01 00:00:00 +0000
+++ doc/references.bib	2013-11-15 08:22:02 +0000
@@ -0,0 +1,373 @@
+***************************
+
+This file contains publications references from docstrings (as [Author2008]\_) of classes, in bibtex format.
+
+When adding new entries:
+
+1. Keep entries in the form Author2008 (Author is the first author), Author2008b if repeated
+
+2. Try to fill mandatory fields for given type of citations (http://en.wikipedia.org/wiki/Bibtex\\\#Entry\\\_Types)
+
+3. Do not use {\'i} funny escapes for accents, put everything in straight utf-8 
+
+Thanks.
+
+***************************
+
+@Article{ Chareyre2002a,
+	title = "Theoretical versus experimental modeling of the anchorage capacity of geotextiles in trenches.",
+	author = "B. Chareyre and L. Briancon and P. Villard",
+	journal = "Geosynthet. Int.",
+	pages = "97--123",
+	volume = "9",
+	number = "2",
+	year = "2002"
+}
+
+@Article{ Chareyre2005,
+	author = "Bruno Chareyre and Pascal Villard",
+	title = "Dynamic Spar Elements and Discrete Element Methods in Two Dimensions for the Modeling of Soil-Inclusion Problems",
+	publisher = "ASCE",
+	year = "2005",
+	journal = "Journal of Engineering Mechanics",
+	volume = "131",
+	number = "7",
+	pages = "689--698",
+	url = "https://yade-dem.org/wiki/File:Chareyre%26Villard2005_licensed.pdf";,
+	doi = "10.1061/(ASCE)0733-9399(2005)131:7(689)"
+}
+
+@Article{Duriez2010,
+	author = "J. Duriez and F.Darve and F.-V.Donze",
+	title = "A discrete modeling-based constitutive relation for infilled rock joints",
+	year = "2010",
+	journal = "International Journal of Rock Mechanics & Mining Sciences",
+	note = "in press"
+}
+
+@PhDThesis{ Chareyre2003,
+	author = "Bruno Chareyre",
+	title = "Mod{\'e}lisation du comportement d'ouvrages composites sol-g{\'e}osynth{\'e}tique par {\'e}l{\'e}ments discrets - Application aux tranch{\'e}es d'ancrage en t{\^e}te de talus.",
+	school = "Grenoble University",
+	year = "2003",
+	url = "http://tel.archives-ouvertes.fr/tel-00486807/fr/";
+}
+
+@InProceedings{ Chareyre2002b,
+	title = "Discrete element modeling of curved geosynthetic anchorages with known macro-properties.",
+	author = "B. Chareyre and P. Villard",
+	booktitle = "Proc., First Int. PFC Symposium, Gelsenkirchen, Germany",
+	year = "2002",
+	pages = "197--203"
+}
+
+@Article{ Villard2004a,
+	title = "Design methods for geosynthetic anchor trenches on the basis of true scale experiments and discrete element modelling",
+	author = "P. Villard and B. Chareyre",
+	journal = "Canadian Geotechnical Journal",
+	pages = "1193--1205",
+	volume = "41",
+	year = "2004"
+}
+
+@Article{ Lu1998,
+	author = "Ya Yan Lu",
+	title = "Computing the Logarithm of a Symmetric Positive Definite Matrix",
+	journal = "Appl. Numer. Math",
+	year = "1998",
+	volume = "26",
+	pages = "483--496",
+	doi = "10.1016/S0168-9274(97)00103-7",
+	url = "http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.37.759&rep=rep1&type=pdf";
+}
+
+@InProceedings{ Alonso2004,
+	title = "Micro-mechanical investigation of the granular ratcheting",
+	author = "F. Alonso-Marroqu{\'i}n and R. Garc{\'i}a-Rojo and H. J. Herrmann",
+	booktitle = "Cyclic Behaviour of Soils and Liquefaction Phenomena",
+	publisher = "Taylor \& Francis",
+	year = "2004",
+	month = "april",
+	isbn = "9058096203",
+	pages = "3--10",
+	editor = "T. Triantafyllidis",
+	url = "http://www.comphys.ethz.ch/hans/p/334.pdf";
+}
+
+@Article{ McNamara2008,
+	title = "Microscopic origin of granular ratcheting",
+	author = "S. McNamara and R. Garc{\'i}a-Rojo and H. J. Herrmann",
+	journal = "Physical Review E",
+	year = "2008",
+	number = "3",
+	volume = "77",
+	doi = "11.1103/PhysRevE.77.031304"
+}
+
+@InProceedings{ GarciaRojo2004,
+	author = "R. Garc{\'i}a-Rojo and S. McNamara and H. J. Herrmann",
+	title = "Discrete element methods for the micro-mechanical investigation of granular ratcheting",
+	booktitle = "Proceedings ECCOMAS 2004",
+	year = "2004",
+	address = "Jyvaskyla",
+	url = "http://www.ica1.uni-stuttgart.de/publications/2004/GMH04";
+}
+
+@Book{ Allen1989,
+	author = "M. P. Allen and D. J. Tildesley",
+	title = "Computer simulation of liquids",
+	year = "1989",
+	isbn = "0-19-855645-4",
+	publisher = "Clarendon Press",
+	address = "New York, NY, USA"
+}
+
+@Proceedings{ DeghmReport2006,
+	title = "Annual Report 2006",
+	year = "2006",
+	editor = "F. V. Donz{\'e}",
+	organization = "Discrete Element Group for Hazard Mitigation",
+	publisher = "Universit{\'e} Joseph Fourier, Grenoble",
+	url = " http://geo.hmg.inpg.fr/frederic/Discrete_Element_Group_FVD.html "
+}
+
+@Article{ Pournin2001,
+	title = "Molecular-dynamics force models for better control of energy dissipation in numerical simulations of dense granular media",
+	author = "L. Pournin and Th. M. Liebling and A. Mocellin",
+	journal = "Phys. Rev. E",
+	volume = "65",
+	number = "1",
+	pages = "011302",
+	numpages = "7",
+	year = "2001",
+	month = "Dec",
+	doi = "10.1103/PhysRevE.65.011302",
+	publisher = "American Physical Society"
+}
+
+@Article{ Jung1997,
+	author = "Derek Jung and Kamal K. Gupta",
+	title = "Octree-based hierarchical distance maps for collision detection",
+	journal = "Journal of Robotic Systems",
+	volume = "14",
+	number = "11",
+	pages = "789--806",
+	year = "1997",
+	doi = "10.1002/(SICI)1097-4563(199711)14:11<789::AID-ROB3>3.0.CO;2-Q"
+}
+
+@Article{ Hubbard1996,
+	author = "Philip M. Hubbard",
+	title = "Approximating polyhedra with spheres for time-critical collision detection",
+	journal = "ACM Trans. Graph.",
+	volume = "15",
+	number = "3",
+	year = "1996",
+	issn = "0730-0301",
+	pages = "179--210",
+	doi = "10.1145/231731.231732",
+	publisher = "ACM",
+	address = "New York, NY, USA"
+}
+
+@Article{ Klosowski1998,
+	author = "James T. Klosowski and Martin Held and Joseph S. B. Mitchell and Henry Sowizral and Karel Zikan",
+	title = "Efficient Collision Detection Using Bounding Volume Hierarchies of k-DOPs",
+	journal = "IEEE Transactions on Visualization and Computer Graphics",
+	year = "1998",
+	volume = "4",
+	pages = "21--36",
+	url = "http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.105.6555&rep=rep1&type=pdf";
+}
+
+@Article{ Munjiza2006,
+	Author = "A. Munjiza and E. Rougier and N. W. M. John",
+	Title = "MR linear contact detection algorithm",
+	journal = "International Journal for Numerical Methods in Engineering",
+	volume = "66",
+	number = "1",
+	pages = "46--71",
+	year = "2006",
+	publisher = "John Wiley \& Sons, Ltd.",
+	doi = "10.1002/nme.1538",
+	abstract = "Large-scale discrete element simulations, as well as a whole range of related problems, involve contact of a large number of separate bodies and an efficient and robust contact detection algorithm is necessary. There has been a number of contact detection algorithms with total detection time proportional to N ln(N) (where N is the total number of separate bodies) reported in the past. In more recent years algorithms with total CPU time proportional to N have been developed. In this work, a novel contact detection algorithm with total detection time proportional to N is proposed. The performance of the algorithm is not influenced by packing density, while memory requirements are insignificant. The algorithm is applicable to systems comprising bodies of a similar size. The algorithm is named MR (Munjiza-Rougier: Munjiza devised the algorithm, Rougier implemented it). In the second part of the paper the algorithm is extended to particles of different sizes. The new algorithm is called MMR (multi-step MR) algorithm."
+}
+
+@Article{ Munjiza1998,
+	Author = "A. Munjiza and K. R. F. Andrews",
+	Title = "NBS contact detection algorithm for bodies of similar size",
+	journal = "International Journal for Numerical Methods in Engineering",
+	volume = "43",
+	number = "1",
+	pages = "131--149",
+	year = "1998",
+	publisher = "John Wiley \& Sons, Ltd.",
+	doi = "10.1002/(SICI)1097-0207(19980915)43:1<131::AID-NME447>3.0.CO;2-S",
+	abstract = "Large-scale discrete element simulations, as well as a whole range of related problems, involve contact of a large number of separate bodies. In this context an efficient and robust contact detection algorithm is necessary. There has been a number of contact detection algorithms with total detection time (CPU time needed to detect all couples close to each other) proportional to Nln(N) (where N is the total number of separate bodies) reported in recent years. In this work a contact detection algorithm with total detection time proportional to N is reported. The algorithm is termed NBS, which stands for no binary search. In other words, the proposed algorithm involves no binary search at any stage. In addition the performance of the algorithm in terms of total detection time is not influenced by packing density, while memory requirements are insignificant. The only limitation of the algorithm is its applicability to the systems comprising bodies of similar size."
+}
+
+@Article{ Verlet1967,
+	title = "Computer ``Experiments'' on Classical Fluids. I. Thermodynamical Properties of Lennard-Jones Molecules",
+	author = "Loup Verlet",
+	journal = "Phys. Rev.",
+	volume = "159",
+	number = "1",
+	pages = "98",
+	year = "1967",
+	month = "Jul",
+	doi = "10.1103/PhysRev.159.98",
+	publisher = "American Physical Society"
+}
+
+@InProceedings{ Luding2008,
+	author = "Stefan Luding",
+	title = "Introduction to discrete element methods",
+	booktitle = "European Journal of Environmental and Civil Engineering",
+	publisher = "Lavoisier",
+	year = "2008",
+	isbn = "978-2-7462-2258-8",
+	pages = "785--826",
+	editor = "F{\'e}lix Darve and Jean-Pierre Ollivier"
+}
+
+@Article{ Wang2009,
+	title = "A new algorithm to model the dynamics of 3-D bonded rigid bodies with rotations",
+	author = "Yucang Wang",
+	journal = "Acta Geotechnica",
+	publisher = "Springer Berlin / Heidelberg",
+	issn = "1861-1125 (Print) 1861-1133 (Online)",
+	url = "http://www.springerlink.com/content/l2306412v1004871/";,
+	abstract = "In this paper we propose a new algorithm to simulate the dynamics of 3-D interacting rigid bodies. Six degrees of freedom are introduced to describe a single 3-D body or particle, and six relative motions and interactions are permitted between bonded bodies. We develop a new decomposition technique for 3-D rotation and pay particular attention to the fact that an arbitrary relative rotation between two coordinate systems or two rigid bodies can not be decomposed into three mutually independent rotations around three orthogonal axes. However, it can be decomposed into two rotations, one pure axial rotation around the line between the centers of two bodies, and another rotation on a specified plane controlled by another parameter. These two rotations, corresponding to the relative axial twisting and bending in our model, are sequence-independent. Therefore all interactions due to the relative translational and rotational motions between linked bodies can be uniquely determined using such a two-step decomposition technique. A complete algorithm for one such simulation is presented. Compared with existing methods, this algorithm is physically more reliable and has greater numerical accuracy.",
+	number = "2",
+	pages = "117--127",
+	volume = "4",
+	doi = "10.1007/s11440-008-0072-1",
+	year = "2009",
+	keywords = "Bonded rigid-bodies - Decomposition of 3-D finite rotations - Quaternion",
+	month = "July"
+}
+
+@Article{ Omelyan1999,
+	title = "A New Leapfrog Integrator of Rotational Motion. The Revised Angular-Momentum Approach",
+	author = "Igor P. Omelyan",
+	journal = "Molecular Simulation",
+	volume = "22",
+	number = "3",
+	year = "1999",
+	doi = "10.1080/08927029908022097",
+	url = "http://arxiv.org/pdf/physics/9901025";
+}
+
+@Article{ Neto2006,
+	author = "Natale Neto and Luca Bellucci",
+	title = "A new algorithm for rigid body molecular dynamics",
+	journal = "Chemical Physics",
+	volume = "328",
+	number = "1--3",
+	pages = "259--268",
+	year = "2006",
+	issn = "0301-0104",
+	doi = "10.1016/j.chemphys.2006.07.009"
+}
+
+@Article{ Johnson2008,
+	author = "Scott M. Johnson and John R. Williams and Benjamin K. Cook",
+	title = "Quaternion-based rigid body rotation integration algorithms for use in particle methods",
+	journal = "International Journal for Numerical Methods in Engineering",
+	volume = "74",
+	number = "8",
+	pages = "1303--1313",
+	year = "2008",
+	doi = "10.1002/nme.2210"
+}
+
+@InProceedings{ Addetta2001,
+	author = "G.~A. {D'Addetta} and F. {Kun} and E. {Ramm} and H.~J. {Herrmann}",
+	title = "{From solids to granulates - Discrete element simulations of fracture and fragmentation processes in geomaterials.}",
+	booktitle = "Continuous and Discontinuous Modelling of Cohesive-Frictional Materials",
+	year = 2001,
+	series = "Lecture Notes in Physics, Berlin Springer Verlag",
+	volume = 568,
+	editor = "{P.~A.~Vermeer, S.~Diebels, W.~Ehlers, H.~J.~Herrmann, S.~Luding, \& E.~Ramm}",
+	pages = "231--+",
+	url = "http://www.comphys.ethz.ch/hans/p/267.pdf";
+}
+
+@Book{ Pfc3dManual30,
+	author = "ICG",
+	title = "PFC3D (Particle Flow Code in 3D) Theory and Background Manual, version 3.0",
+	publisher = "Itasca Consulting Group",
+	year = "2003"
+}
+
+@PhDThesis{ Hentz2003,
+	Author = "S{\'e}ebastien Hentz",
+	Title = "Mod{\'e}lisation d'une Structure en B{\'e}ton Arm{\'e} Soumise {\`a} un Choc par la m{\'e}thode des El{\'e}ments Discrets",
+	School = "Universit{\'e} Grenoble 1 -- Joseph Fourier",
+	Year = "2003",
+	Month = "October"
+}
+
+@InProceedings{ Price2007,
+	Author = "Mathew Price and Vasile Murariu and Garry Morrison",
+	title = "Sphere clump generation and trajectory comparison for real particles",
+	booktitle = "Proceedings of Discrete Element Modelling 2007",
+	year = "2007",
+	url = "http://www.cogency.co.za/images/info/dem2007_sphereclump.pdf";
+}
+
+@InProceedings{ Kuhl2001,
+	title = "Microplane modelling and particle modelling of cohesive-frictional materials",
+	author = "E. Kuhl and G. A. D'Addetta and M. Leukart and E. Ramm",
+	booktitle = "Continuous and Discontinuous Modelling of Cohesive-Frictional Materials",
+	publisher = "Springer Berlin / Heidelberg",
+	issn = "1616-6361",
+	isbn = "978-3-540-41525-1",
+	url = "http://www.springerlink.com/content/e50544266r506615";,
+	abstract = "This paper aims at comparing the microplane model as a particular representative of the class of continuous material models with a discrete particle model which is of discontinuous nature. Thereby, the constitutive equations of both approaches will be based onVoigtshypothesis defining the strain state on the individual microplanes as well as the relative particle displacements. Through an appropriate constitutive assumption, the microplane stresses and the contact forces can be determined. In both cases, the equivalence of microscopic and macroscopic virtual work yields the overall stress strain relation. An elastic and an elasto-plastic material characterization of the microplane model and the particle model are derived and similarities of both approaches are illustrated.",
+	volume = "568",
+	series = "Lecture Notes in Physics",
+	year = "2001",
+	pages = "31--46",
+	doi = "10.1007/3-540-44424-6\_3"
+}
+
+@Article{ Thornton1991,
+	title = "Impact of elastic spheres with and without adhesion",
+	author = "Colin Thornton and K. K. Yin",
+	year = "1991",
+	journal = "Powder technology",
+	volume = "65",
+	pages = "153--166",
+	doi = "10.1016/0032-5910(91)80178-L"
+}
+
+@Article{ Thornton2000,
+	title = "Numerical simulations of deviatoric shear deformation of granular media",
+	author = "Colin Thornton",
+	journal = "G{\'e}otechnique",
+	pages = "43--53",
+	volume = "50",
+	year = "2000",
+	number = "1",
+	doi = "10.1680/geot.2000.50.1.43"
+}
+
+@Article{ CundallStrack1979,
+	author = "P.A. Cundall and O.D.L. Strack",
+	title = "A discrete numerical model for granular assemblies",
+	journal = "Geotechnique",
+	volume = "",
+	number = "29",
+	pages = "47--65",
+	year = "1979",
+	doi = "10.1680/geot.1979.29.1.47"
+}
+
+@Article{ Hassan2010,
+	author = "A. Hassan and B. Chareyre and F. Darve and J. Meyssonier and F. Flin",
+	title = "Microtomography-based Discrete Element Modelling of Creep in Snow",
+	journal = "Granular Matter",
+	year = "2010 (submitted)"
+}
+

=== added directory 'doc/sphinx'
=== added file 'doc/sphinx/README'
--- doc/sphinx/README	1970-01-01 00:00:00 +0000
+++ doc/sphinx/README	2013-11-15 08:22:02 +0000
@@ -0,0 +1,27 @@
+Generating yade documentation
+===============================
+
+1. Get sphinx 1.0 (development snapshots are fine) either from 
+
+* packages at https://launchpad.net/~yade-users/+archive/external
+** sudo apt-add-repository ppa:yade-users/external; sudo apt-get update; sudo apt-get install python-sphinx python-bibtex
+
+* from its repository:
+
+** hg clone http://bitbucket.org/birkenfeld/sphinx/
+** optionally apply the patch (only avoids warnings) from
+     http://bitbucket.org/birkenfeld/sphinx/issue/407/patch-do-not-inspect-boost-python-functions
+** run 
+     python setup.py install
+
+2. Python default encoding must be set to utf-8. As it is not the default, PYTHONPATH=. is used to make Python import local sitecustomize.py file at startup which changes this setting. (The value cannot be set after startup, from within the script)
+
+3. Run (from the current directory, replacing PREFIX by the yade install path)
+
+	PYTHONPATH=. yade yadeSphinx.py [optional outDir; _build by default]
+
+It will be create/update $outDir/{html,latex}. The latex file (Yade.tex) is to be processed with xelatex (rather than latex). See README.latex for details.
+
+====
+
+ipython_console_highlighting.py is copied from matplotlib's trunk/matplotlib/lib/matplotlib/sphinxext

=== added file 'doc/sphinx/bib2rst.py'
--- doc/sphinx/bib2rst.py	1970-01-01 00:00:00 +0000
+++ doc/sphinx/bib2rst.py	2013-11-15 08:22:02 +0000
@@ -0,0 +1,90 @@
+#!/usr/bin/python
+# encoding: utf-8
+try:
+	import _bibtex as bib
+	import _recode as bibRecode
+except ImportError:
+	raise ImportError("Unable to import _bibtex and/or _recode; install the python-bibtex package.")
+import sys
+
+def readBib(filename):
+	## _bibtex has horrible interface
+	bibfile=bib.open_file(filename,1) # 2nd argument: strict mode
+	db={}
+	#rq=bibRecode.request('latex..latin1')
+	while True:
+		entry=bib.next(bibfile)
+		if entry is None: break
+		key,type,dta=entry[0],entry[1],entry[4]
+		item={'type':type}
+		for field in dta.keys():
+			expanded=bib.expand(bibfile,dta[field],-1)
+			#conv=bibRecode.recode(rq,expanded[2])
+			item[field]=expanded[2].strip()
+		db[key]=item
+	## now we don't need _bibtex anymore, everything is in our dicts
+	return db
+
+def dumpBib(db):
+	for k in db.keys():
+		print k,db[k]
+
+def formatRest(db):
+	ret=[]
+	keys=db.keys(); keys.sort()
+	for key in keys:
+		i=db[key]; type=i['type']
+		line=r'.. [%s] \ '%key ## ← HACK: explicit space to prevent docutils from using abbreviated first name (e.g. "F.") as enumeration item; it works!!
+		if i.has_key('author'): author=i['author'].replace(' and ',', ') # the module does not handle this..?
+
+		# required fields from http://en.wikipedia.org/wiki/Bibtex
+		# in some cases, they are not present, anyway
+		if type=='article':
+			if i.has_key('author'): line+='%s '%author
+			if i.has_key('year'): line+='(%s), '%i['year']
+			line+='**%s**. *%s*'%(i['title'],i['journal'])
+			if i.has_key('issue'): line+=i['issue']
+			if i.has_key('volume'): line+=' (%s)'%i['volume']
+			if i.has_key('pages'): line+=', pages %s'%i['pages']
+			line+='.'
+		elif type=='book':
+			if i.has_key('author'): line+='%s '%author
+			if i.has_key('year'): line+='(%s), '%i['year']
+			line+='**%s**.'%i['title']
+			if i.has_key('publisher'): line+=' %s.'%i['publisher']
+		elif type=='inproceedings':
+			line+='%s (%s), **%s**. In *%s*.'%(author,i['year'],i['title'],i['booktitle'] if i.has_key('booktitle') else i['journal'])
+		elif type=='phdthesis':
+			line+='%s (%s), **%s**. PhD thesis at *%s*.'%(author,i['year'],i['title'],i['school'])
+		elif type=='mastersthesis':
+			line+='%s (%s), **%s**. Master thesis at *%s*.'%(author,i['year'],i['title'],i['school'])
+		elif type=='proceedings':
+			if i.has_key('editor'): line+='%s (ed.), '%i['editor']
+			line+='**%s** (%s).'%(i['title'],i['year'])
+			if i.has_key('organization'): line+=' *%s*.'%i['organization']
+			if i.has_key('publisher'): line+=' %s'%i['publisher']
+		elif type=='misc':
+			if i.has_key('author'): line+=author
+			if i.has_key('year'): line+=' %s'%i['year']
+			if i.has_key('title'): line+=' **%s**'%i['title']
+		# add doi and url to everything, if present
+		## ReST uses <..> to delimit URL, therefore < and > must be encoded in the URL (http://www.blooberry.com/indexdot/html/topics/urlencoding.htm)
+		def escapeUrl(url): return url.replace('<','%3c').replace('>','%3e')
+		if i.has_key('doi'): line+=' DOI `%s <http://dx.doi.org/%s>`_'%(i['doi'],escapeUrl(i['doi'])) 
+		if i.has_key('url'): line+=' `(fulltext) <%s>`__'%escapeUrl(i['url'])
+		if i.has_key('note'): line+=' (%s)'%i['note']
+		ret.append(line)
+	return [l.replace('@tilde@','~') for l in ret]
+
+def bib2rst(filename):
+	"""Return string representing all items in given bibtex file, formatted as ReST."""
+	import tempfile,shutil,os.path
+	d=tempfile.mkdtemp()
+	bib=d+'/'+os.path.basename(filename)
+	open(bib,'w').write(open(filename).read().replace('~','@tilde@'))
+	db=readBib(bib)
+	shutil.rmtree(d)
+	return '\n\n'.join(formatRest(db))
+if __name__=='__main__':
+	import sys
+	print bib2rst(sys.argv[1])

=== added file 'doc/sphinx/conf.py'
--- doc/sphinx/conf.py	1970-01-01 00:00:00 +0000
+++ doc/sphinx/conf.py	2013-11-15 08:22:02 +0000
@@ -0,0 +1,665 @@
+# -*- coding: utf-8 -*-
+#
+# Yade documentation build configuration file, created by
+# sphinx-quickstart on Mon Nov 16 21:49:34 2009.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# relevant posts to sphinx ML
+# http://groups.google.com/group/sphinx-dev/browse_thread/thread/b4fbc8d31d230fc4
+# http://groups.google.com/group/sphinx-dev/browse_thread/thread/118598245d5f479b
+
+#####################
+## custom yade roles
+#####################
+##
+## http://docutils.sourceforge.net/docs/howto/rst-roles.html
+
+import sys
+from docutils import nodes
+from sphinx import addnodes
+import docutils
+import re
+
+#
+# needed for creating hyperlink targets.
+# it should be cleand up and unified for both LaTeX and HTML via
+# the pending_xref node which gets resolved to real link target
+# by sphinx automatically once all docs have been processed.
+#
+# xrefs: http://groups.google.com/group/sphinx-dev/browse_thread/thread/d719d19307654548
+#
+#
+import __builtin__
+if 'latex' in sys.argv: __builtin__.writer='latex'
+elif 'html' in sys.argv: __builtin__.writer='html'
+else: raise RuntimeError("Must have either 'latex' or 'html' on the command line (hack for reference styles)")
+
+
+
+def yaderef_role(role,rawtext,text,lineno,inliner,options={},content=[]):
+	"Handle the :yref:`` role, by making hyperlink to yade.wrapper.*. It supports :yref:`Link text<link target>` syntax, like usual hyperlinking roles."
+	id=rawtext.split(':',2)[2][1:-1]
+	txt=id; explicitText=False
+	m=re.match('(.*)\s*<(.*)>\s*',id)
+	if m:
+		explicitText=True
+		txt,id=m.group(1),m.group(2)
+	id=id.replace('::','.')
+	#node=nodes.reference(rawtext,docutils.utils.unescape(txt),refuri='http://beta.arcig.cz/~eudoxos/yade/doxygen/?search=%s'%id,**options)
+	#node=nodes.reference(rawtext,docutils.utils.unescape(txt),refuri='yade.wrapper.html#yade.wrapper.%s'%id,**options)
+	return [mkYrefNode(id,txt,rawtext,role,explicitText,lineno,options)],[]
+
+def yadesrc_role(role,rawtext,lineno,inliner,options={},content=[]):
+	"Handle the :ysrc:`` role, making hyperlink to bzr repository webpage with that path. Supports :ysrc:`Link text<file/name>` syntax, like usual hyperlinking roles. If target ends with ``/``, it is assumed to be a directory."
+	id=rawtext.split(':',2)[2][1:-1]
+	txt=id
+	m=re.match('(.*)\s*<(.*)>\s*',id)
+	if m:
+		txt,id=m.group(1),m.group(2)
+	return [nodes.reference(rawtext,docutils.utils.unescape(txt),refuri='http://bazaar.launchpad.net/~yade-dev/yade/trunk/%s/head%%3A/%s'%('files' if txt.endswith('/') else 'annotate',id))],[] ### **options should be passed to nodes.reference as well
+
+# map modules to their html (rst) filenames. Used for sub-modules, where e.g. SpherePack is yade._packSphere.SpherePack, but is documented from yade.pack.rst
+moduleMap={
+	'yade._packPredicates':'yade.pack',
+	'yade._packSpherePadder':'yade.pack',
+	'yade._packSpheres':'yade.pack',
+	'yade._packObb':'yade.pack'
+}
+
+def mkYrefNode(target,text,rawtext,role,explicitText,lineno,options={}):
+	"""Create hyperlink to yade target. Targets starting with literal 'yade.' are absolute, but the leading 'yade.' will be stripped from the link text. Absolute tergets are supposed to live in page named yade.[module].html, anchored at #yade.[module2].[rest of target], where [module2] is identical to [module], unless mapped over by moduleMap.
+	
+	Other targets are supposed to live in yade.wrapper (such as c++ classes)."""
+
+	writer=__builtin__.writer # to make sure not shadowed by a local var
+	import string
+	if target.startswith('yade.'):
+		module='.'.join(target.split('.')[0:2])
+		module2=(module if module not in moduleMap.keys() else moduleMap[module])
+		if target==module: target='' # to reference the module itself
+		uri=('%%%s#%s'%(module2,target) if writer=='latex' else '%s.html#%s'%(module2,target))
+		if not explicitText and module!=module2:
+			text=module2+'.'+'.'.join(target.split('.')[2:])
+		text=string.replace(text,'yade.','',1)
+	elif target.startswith('external:'):
+		exttarget=target.split(':',1)[1]
+		if not explicitText: text=exttarget
+		target=exttarget if '.' in exttarget else 'module-'+exttarget
+		uri=(('%%external#%s'%target) if writer=='latex' else 'external.html#%s'%target)
+	else:
+		uri=(('%%yade.wrapper#yade.wrapper.%s'%target) if writer=='latex' else 'yade.wrapper.html#yade.wrapper.%s'%target)
+		#print writer,uri
+	if 0:
+		refnode=addnodes.pending_xref(rawtext,reftype=role,refexplicit=explicitText)
+		refnode.line=lineno
+		refnode['reftarget']=target
+		refnode+=nodes.literal(rawtext,text,classes=['ref',role])
+		return [refnode],[]
+		#ret.rawtext,reftype=role,
+	else:
+		return nodes.reference(rawtext,docutils.utils.unescape(text),refuri=uri,**options)
+	#return [refnode],[]
+
+def ydefault_role(role,rawtext,text,lineno,inliner,options={},content=[]):
+	"Handle the :ydefault:`something` role. fixSignature handles it now in the member signature itself, this merely expands to nothing."
+	return [],[]
+def yattrtype_role(role,rawtext,text,lineno,inliner,options={},content=[]):
+	"Handle the :yattrtype:`something` role. fixSignature handles it now in the member signature itself, this merely expands to nothing."
+	return [],[]
+# FIXME: should return readable representation of bits of the number (yade.wrapper.AttrFlags enum)
+def yattrflags_role(role,rawtext,text,lineno,inliner,options={},content=[]):
+	"Handle the :yattrflags:`something` role. fixSignature handles it now in the member signature itself."
+	return [],[]
+
+from docutils.parsers.rst import roles
+roles.register_canonical_role('yref', yaderef_role)
+roles.register_canonical_role('ysrc', yadesrc_role)
+roles.register_canonical_role('ydefault', ydefault_role)
+roles.register_canonical_role('yattrtype', yattrtype_role)
+roles.register_canonical_role('yattrflags', yattrflags_role)
+
+
+## http://sphinx.pocoo.org/config.html#confval-rst_epilog
+rst_epilog = """
+
+.. |yupdate| replace:: *(auto-updated)*
+.. |ycomp| replace:: *(auto-computed)*
+.. |ystatic| replace:: *(static)*
+"""
+
+
+def customExclude(app, what, name, obj, skip, options):
+	if name=='clone':
+		if 'Serializable.clone' in str(obj): return False
+		return True
+	if hasattr(obj,'__doc__') and obj.__doc__ and ('|ydeprecated|' in obj.__doc__ or '|yhidden|' in obj.__doc__): return True
+	#if re.match(r'\b(__init__|__reduce__|__repr__|__str__)\b',name): return True
+	if name.startswith('_'):
+		if name=='__init__':
+			# skip boost classes with parameterless ctor (arg1=implicit self)
+			if obj.__doc__=="\n__init__( (object)arg1) -> None": return True
+			# skip undocumented ctors
+			if not obj.__doc__: return True
+			# skip default ctor for serializable, taking dict of attrs
+			if obj.__doc__=='\n__init__( (object)arg1) -> None\n\nobject __init__(tuple args, dict kwds)': return True
+			#for i,l in enumerate(obj.__doc__.split('\n')): print name,i,l,'##'
+			return False
+		return True
+	return False
+
+def isBoostFunc(what,obj):
+	return what=='function' and obj.__repr__().startswith('<Boost.Python.function object at 0x')
+
+def isBoostMethod(what,obj):
+	"I don't know how to distinguish boost and non-boost methods..."
+	return what=='method' and obj.__repr__().startswith('<unbound method ');
+
+def replaceLaTeX(s):
+	# replace single non-escaped dollars $...$ by :math:`...`
+	# then \$ by single $
+	s=re.sub(r'(?<!\\)\$([^\$]+)(?<!\\)\$',r'\ :math:`\1`\ ',s)
+	return re.sub(r'\\\$',r'$',s)
+
+def fixSrc(app,docname,source):
+	source[0]=replaceLaTeX(source[0])
+
+def fixDocstring(app,what,name,obj,options,lines):
+	# remove empty default roles, which is not properly interpreted by docutils parser
+	for i in range(0,len(lines)):
+		lines[i]=lines[i].replace(':ydefault:``','')
+		lines[i]=lines[i].replace(':yattrtype:``','')
+		lines[i]=lines[i].replace(':yattrflags:``','')
+		#lines[i]=re.sub(':``',':` `',lines[i])
+	# remove signature of boost::python function docstring, which is the first line of the docstring
+	if isBoostFunc(what,obj):
+		l2=boostFuncSignature(name,obj)[1]
+		# we must replace lines one by one (in-place) :-|
+		# knowing that l2 is always shorter than lines (l2 is docstring with the signature stripped off)
+		for i in range(0,len(lines)):
+			lines[i]=l2[i] if i<len(l2) else ''
+	elif isBoostMethod(what,obj):
+		l2=boostFuncSignature(name,obj)[1]
+		for i in range(0,len(lines)):
+			lines[i]=l2[i] if i<len(l2) else ''
+	# LaTeX: replace $...$ by :math:`...`
+	# must be done after calling boostFuncSignature which uses original docstring
+	for i in range(0,len(lines)): lines[i]=replaceLaTeX(lines[i])
+
+
+def boostFuncSignature(name,obj,removeSelf=False):
+	"""Scan docstring of obj, returning tuple of properly formatted boost python signature
+	(first line of the docstring) and the rest of docstring (as list of lines).
+	The rest of docstring is stripped of 4 leading spaces which are automatically
+	added by boost.
+	
+	removeSelf will attempt to remove the first argument from the signature.
+	"""
+	doc=obj.__doc__
+	if doc==None: # not a boost method
+		return None,None
+	nname=name.split('.')[-1]
+	docc=doc.split('\n')
+	if len(docc)<2: return None,docc
+	doc1=docc[1]
+	# functions with weird docstring, likely not documented by boost
+	if not re.match('^'+nname+r'(.*)->.*$',doc1):
+		return None,docc
+	if doc1.endswith(':'): doc1=doc1[:-1]
+	strippedDoc=doc.split('\n')[2:]
+	# check if all lines are padded
+	allLinesHave4LeadingSpaces=True
+	for l in strippedDoc:
+		if l.startswith('    '): continue
+		allLinesHave4LeadingSpaces=False; break
+	# remove the padding if so
+	if allLinesHave4LeadingSpaces: strippedDoc=[l[4:] for l in strippedDoc]
+	for i in range(len(strippedDoc)):
+		# fix signatures inside docstring (one function with multiple signatures)
+		strippedDoc[i],n=re.subn(r'([a-zA-Z_][a-zA-Z0-9_]*\() \(object\)arg1(, |)',r'\1',strippedDoc[i].replace('->','→'))
+	# inspect dosctring after mangling
+	if 'getViscoelasticFromSpheresInteraction' in name and False:
+		print name
+		print strippedDoc
+		print '======================'
+		for l in strippedDoc: print l
+		print '======================'
+	sig=doc1.split('(',1)[1]
+	if removeSelf:
+		# remove up to the first comma; if no comma present, then the method takes no arguments
+		# if [ precedes the comma, add it to the result (ugly!)
+		try:
+			ss=sig.split(',',1)
+			if ss[0].endswith('['): sig='['+ss[1]
+			else: sig=ss[1]
+		except IndexError:
+			# grab the return value
+			try:
+				sig=') -> '+sig.split('->')[-1]
+		#if 'Serializable' in name: print 1000*'#',name
+			except IndexError:
+				sig=')'
+	return '('+sig,strippedDoc
+
+def fixSignature(app, what, name, obj, options, signature, return_annotation):
+	#print what,name,obj,signature#,dir(obj)
+	if what=='attribute':
+		doc=unicode(obj.__doc__)
+		ret=''
+		m=re.match('.*:ydefault:`(.*?)`.*',doc)
+		if m:
+			typ=''
+			#try:
+			#	clss='.'.join(name.split('.')[:-1])
+			#	instance=eval(clss+'()')
+			#	typ='; '+getattr(instance,name.split('.')[-1]).__class__.__name__
+			#	if typ=='; NoneType': typ=''
+			#except TypeError: ##no registered converted
+			#	typ=''
+			dfl=m.group(1)
+			m2=re.match(r'\s*\(\s*\(\s*void\s*\)\s*\"(.*)\"\s*,\s*(.*)\s*\)\s*',dfl)
+			if m2: dfl="%s, %s"%(m2.group(2),m2.group(1))
+			if dfl!='': ret+=' (='+dfl+'%s)'%typ
+			else: ret+=' (=uninitalized%s)'%typ
+		#m=re.match('.*\[(.{,8})\].*',doc)
+		#m=re.match('.*:yunit:`(.?*)`.*',doc)
+		#if m:
+		#	units=m.group(1)
+		#	print '@@@@@@@@@@@@@@@@@@@@@',name,units
+		#	ret+=' ['+units+']'
+		return ret,None
+	elif what=='class':
+		ret=[]
+		if len(obj.__bases__)>0:
+			base=obj.__bases__[0]
+			while base.__module__!='Boost.Python':
+				ret+=[base.__name__]
+				if len(base.__bases__)>0: base=base.__bases__[0]
+				else: break
+		if len(ret):
+			return ' (inherits '+u' → '.join(ret)+')',None
+		else: return None,None
+	elif isBoostFunc(what,obj):
+		sig=boostFuncSignature(name,obj)[0] or ' (wrapped c++ function)'
+		return sig,None
+	elif isBoostMethod(what,obj):
+		sig=boostFuncSignature(name,obj,removeSelf=True)[0]
+		return sig,None
+	#else: print what,name,obj.__repr__()
+	#return None,None
+		
+
+from sphinx import addnodes
+def parse_ystaticattr(env,attr,attrnode):
+	m=re.match(r'([a-zA-Z0-9_]+)\.(.*)\(=(.*)\)',attr)
+	if not m:
+		print 100*'@'+' Static attribute %s not matched'%attr
+		attrnode+=addnodes.desc_name(attr,attr)
+	klass,name,default=m.groups()
+	#attrnode+=addnodes.desc_type('static','static')
+	attrnode+=addnodes.desc_name(name,name)
+	plist=addnodes.desc_parameterlist()
+	if default=='': default='unspecified'
+	plist+=addnodes.desc_parameter('='+default,'='+default)
+	attrnode+=plist
+	attrnode+=addnodes.desc_annotation('  [static]','  [static]')
+	return klass+'.'+name
+
+#############################
+## set tab size
+###################
+## http://groups.google.com/group/sphinx-dev/browse_thread/thread/35b8071ffe9a8feb
+def setup(app):
+	from sphinx.highlighting import lexers
+	from pygments.lexers.compiled import CppLexer
+	lexers['cpp'] = CppLexer(tabsize=3) 
+	lexers['c++'] = CppLexer(tabsize=3) 
+	from pygments.lexers.agile import PythonLexer
+	lexers['python'] = PythonLexer(tabsize=3) 
+
+	app.connect('source-read',fixSrc)
+	
+	app.connect('autodoc-skip-member',customExclude)
+	app.connect('autodoc-process-signature',fixSignature)
+	app.connect('autodoc-process-docstring',fixDocstring)
+	app.add_description_unit('ystaticattr',None,objname='static attribute',indextemplate='pair: %s; static method',parse_node=parse_ystaticattr)
+
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+
+#
+# HACK: change ipython console regexp from ipython_console_highlighting.py
+import re
+sys.path.append(os.path.abspath('.'))
+
+import yade.config
+
+if 1:
+	import ipython_directive as id
+	id.rgxin =re.compile(r'(?:In |Yade )\[(\d+)\]:\s?(.*)\s*')
+	id.rgxout=re.compile(r'(?:Out| ->  )\[(\d+)\]:\s?(.*)\s*')
+	id.rgxcont=re.compile(r'(?:   +)\.\.+:\s?(.*)\s*')
+	id.fmtin  ='Yade [%d]:'
+	id.fmtout =' ->  [%d]: '  # for some reason, out and cont must have the trailing space
+	id.fmtcont='     .\D.: '
+	id.rc_override=dict(prompt_in1="Yade [\#]:",prompt_in2="     .\D.:",prompt_out=r" ->  [\#]: ")
+	id.reconfig_shell()
+
+	import ipython_console_highlighting as ich
+	ich.IPythonConsoleLexer.input_prompt = re.compile("(Yade \[[0-9]+\]: )")
+	ich.IPythonConsoleLexer.output_prompt = re.compile("(( ->  |Out)|\[[0-9]+\]: )")
+	ich.IPythonConsoleLexer.continue_prompt = re.compile("\s+\.\.\.+:")
+
+
+extensions = [
+    'sphinx.ext.autodoc',
+    'sphinx.ext.autosummary',
+    'sphinx.ext.coverage',
+    'sphinx.ext.pngmath',
+	 'sphinx.ext.graphviz',
+	 'sphinx.ext.inheritance_diagram',
+	#'matplotlib.sphinxext.mathmpl',
+    'ipython_directive',
+    'ipython_console_highlighting',
+    ]
+
+# the sidebar extension
+if False:
+	if writer=='html':
+		extensions+=['sphinx.ext.sidebar']
+
+	sidebar_all=True
+	sidebar_relling=True
+	#sidebar_abbrev=True
+	sidebar_tocdepth=3
+
+## http://trac.sagemath.org/sage_trac/attachment/ticket/7549/trac_7549-doc_inheritance_underscore.patch
+# GraphViz includes dot, neato, twopi, circo, fdp. 
+graphviz_dot = 'dot' 
+inheritance_graph_attrs = { 'rankdir' : 'BT' } 
+inheritance_node_attrs = { 'height' : 0.5, 'fontsize' : 12, 'shape' : 'oval' } 
+inheritance_edge_attrs = {} 
+
+my_latex_preamble=r'''
+\usepackage{euler} % must be loaded before fontspec for the whole doc (below); this must be kept for pngmath, however
+\usepackage{amsmath}
+\usepackage{amsbsy}
+%\usepackage{mathabx}
+\usepackage{underscore}
+\usepackage[all]{xy}
+
+% symbols
+\let\mat\boldsymbol % matrix
+\let\vec\boldsymbol % vector
+\let\tens\boldsymbol % tensor
+
+\def\normalized#1{\widehat{#1}}
+\def\locframe#1{\widetilde{#1}}
+
+% timestep
+\def\Dt{\Delta t}
+\def\Dtcr{\Dt_{\rm cr}}
+
+% algorithm complexity
+\def\bigO#1{\ensuremath{\mathcal{O}(#1)}}
+
+% variants for greek symbols
+\let\epsilon\varepsilon
+\let\theta\vartheta
+\let\phi\varphi
+
+% shorthands
+\let\sig\sigma
+\let\eps\epsilon
+
+% variables at different points of time 
+\def\prev#1{#1^-}
+\def\pprev#1{#1^\ominus}
+\def\curr#1{#1^{\circ}}
+\def\nnext#1{#1^\oplus}
+\def\next#1{#1^+}
+
+% shorthands for geometry
+\def\currn{\curr{\vec{n}}}
+\def\currC{\curr{\vec{C}}}
+\def\uT{\vec{u}_T}
+\def\curruT{\curr{\vec{u}}_T}
+\def\prevuT{\prev{\vec{u}}_T}
+\def\currn{\curr{\vec{n}}}
+\def\prevn{\prev{\vec{n}}}
+
+% motion
+\def\pprevvel{\pprev{\dot{\vec{u}}}}
+\def\nnextvel{\nnext{\dot{\vec{u}}}}
+\def\curraccel{\curr{\ddot{\vec{u}}}}
+\def\prevpos{\prev{\vec{u}}}
+\def\currpos{\curr{\vec{u}}}
+\def\nextpos{\next{\vec{u}}}
+\def\curraaccel{\curr{\dot{\vec{\omega}}}}
+\def\pprevangvel{\pprev{\vec{\omega}}}
+\def\nnextangvel{\nnext{\vec{\omega}}}
+\def\loccurr#1{\curr{\locframe{#1}}}
+
+
+\def\numCPU{n_{\rm cpu}}
+\DeclareMathOperator{\Align}{Align}
+\DeclareMathOperator{\sign}{sgn}
+
+
+% sorting algorithms
+\def\isleq#1{\currelem{#1}\ar@/^/[ll]^{\leq}}
+\def\isnleq#1{\currelem{#1}\ar@/^/[ll]^{\not\leq}}
+\def\currelem#1{\fbox{$#1$}}
+\def\sortSep{||}
+\def\sortInv{\hbox{\phantom{||}}}
+\def\sortlines#1{\xymatrix@=3pt{#1}}
+\def\crossBound{||\mkern-18mu<}
+
+'''
+
+pngmath_latex_preamble=r'\usepackage[active]{preview}'+my_latex_preamble
+
+pngmath_use_preview=True
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index-toctree'
+
+# General information about the project.
+project = u'Yade'
+copyright = u'2009, Václav Šmilauer'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = yade.config.version
+# The full version, including alpha/beta/rc tags.
+release = yade.config.revision
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+modindex_common_prefix = ['yade.']
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+html_theme_options = {'stickysidebar':'true','collapsiblesidebar':'true','rightsidebar':'false'}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = 'fig/yade-logo.png'
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = 'fig/yade-favicon.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['static-html']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+html_index='index.html'
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+html_additional_pages = { 'index':'index.html'}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Yadedoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+
+latex_elements=dict(
+	papersize='a4paper',
+	fontpkg=r'''
+\usepackage{euler}
+\usepackage{fontspec,xunicode,xltxtra}
+%\setmainfont[BoldFont={LMRoman10 Bold}]{CMU Concrete} %% CMU Concrete must be installed by hand as otf
+	''',
+	utf8extra='',
+	fncychap='',
+	preamble=my_latex_preamble,
+	footer='',
+	inputenc='',
+	fontenc=''
+)
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index-toctree', 'Yade.tex', u'Yade Documentation',
+   u'Václav Šmilauer', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True

=== added file 'doc/sphinx/external.rst'
--- doc/sphinx/external.rst	1970-01-01 00:00:00 +0000
+++ doc/sphinx/external.rst	2013-11-15 08:22:02 +0000
@@ -0,0 +1,25 @@
+External modules
+=================
+
+.. _yade.math
+
+miniEigen (math) module
+--------------------------
+
+.. automodule:: miniEigen
+	:members:
+	:undoc-members:
+
+
+.. _gts
+
+gts (GNU Triangulated surface) module
+--------------------------------------
+
+.. automodule:: gts
+	:members:
+	:undoc-members:
+	:show-inheritance:
+
+
+

=== added directory 'doc/sphinx/fig'
=== added file 'doc/sphinx/fig/cell-flip.pdf'
Binary files doc/sphinx/fig/cell-flip.pdf	1970-01-01 00:00:00 +0000 and doc/sphinx/fig/cell-flip.pdf	2013-11-15 08:22:02 +0000 differ
=== added file 'doc/sphinx/fig/cell-flip.png'
Binary files doc/sphinx/fig/cell-flip.png	1970-01-01 00:00:00 +0000 and doc/sphinx/fig/cell-flip.png	2013-11-15 08:22:02 +0000 differ
=== added file 'doc/sphinx/fig/cell-shear-aabb.ipe'
--- doc/sphinx/fig/cell-shear-aabb.ipe	1970-01-01 00:00:00 +0000
+++ doc/sphinx/fig/cell-shear-aabb.ipe	2013-11-15 08:22:02 +0000
@@ -0,0 +1,267 @@
+<?xml version="1.0"?>
+<!DOCTYPE ipe SYSTEM "ipe.dtd">
+<ipe version="70010" creator="Ipe 7.0.10">
+<info created="D:20100409151942" modified="D:20100409152120"/>
+<preamble>\usepackage{euler}</preamble>
+<ipestyle name="basic">
+<symbol name="arrow/arc(spx)">
+<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">
+0 0 m
+-1 0.333 l
+-1 -0.333 l
+h
+</path>
+</symbol>
+<symbol name="arrow/farc(spx)">
+<path stroke="sym-stroke" fill="white" pen="sym-pen">
+0 0 m
+-1 0.333 l
+-1 -0.333 l
+h
+</path>
+</symbol>
+<symbol name="mark/circle(sx)" transformations="translations">
+<path fill="sym-stroke">
+0.6 0 0 0.6 0 0 e
+0.4 0 0 0.4 0 0 e
+</path>
+</symbol>
+<symbol name="mark/disk(sx)" transformations="translations">
+<path fill="sym-stroke">
+0.6 0 0 0.6 0 0 e
+</path>
+</symbol>
+<symbol name="mark/fdisk(sfx)" transformations="translations">
+<group>
+<path fill="sym-stroke" fillrule="eofill">
+0.6 0 0 0.6 0 0 e
+0.4 0 0 0.4 0 0 e
+</path>
+<path fill="sym-fill">
+0.4 0 0 0.4 0 0 e
+</path>
+</group>
+</symbol>
+<symbol name="mark/box(sx)" transformations="translations">
+<path fill="sym-stroke" fillrule="eofill">
+-0.6 -0.6 m
+0.6 -0.6 l
+0.6 0.6 l
+-0.6 0.6 l
+h
+-0.4 -0.4 m
+0.4 -0.4 l
+0.4 0.4 l
+-0.4 0.4 l
+h
+</path>
+</symbol>
+<symbol name="mark/square(sx)" transformations="translations">
+<path fill="sym-stroke">
+-0.6 -0.6 m
+0.6 -0.6 l
+0.6 0.6 l
+-0.6 0.6 l
+h
+</path>
+</symbol>
+<symbol name="mark/fsquare(sfx)" transformations="translations">
+<group>
+<path fill="sym-stroke" fillrule="eofill">
+-0.6 -0.6 m
+0.6 -0.6 l
+0.6 0.6 l
+-0.6 0.6 l
+h
+-0.4 -0.4 m
+0.4 -0.4 l
+0.4 0.4 l
+-0.4 0.4 l
+h
+</path>
+<path fill="sym-fill">
+-0.4 -0.4 m
+0.4 -0.4 l
+0.4 0.4 l
+-0.4 0.4 l
+h
+</path>
+</group>
+</symbol>
+<symbol name="mark/cross(sx)" transformations="translations">
+<group>
+<path fill="sym-stroke">
+-0.43 -0.57 m
+0.57 0.43 l
+0.43 0.57 l
+-0.57 -0.43 l
+h
+</path>
+<path fill="sym-stroke">
+-0.43 0.57 m
+0.57 -0.43 l
+0.43 -0.57 l
+-0.57 0.43 l
+h
+</path>
+</group>
+</symbol>
+<symbol name="arrow/fnormal(spx)">
+<path stroke="sym-stroke" fill="white" pen="sym-pen">
+0 0 m
+-1 0.333 l
+-1 -0.333 l
+h
+</path>
+</symbol>
+<symbol name="arrow/pointed(spx)">
+<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">
+0 0 m
+-1 0.333 l
+-0.8 0 l
+-1 -0.333 l
+h
+</path>
+</symbol>
+<symbol name="arrow/fpointed(spx)">
+<path stroke="sym-stroke" fill="white" pen="sym-pen">
+0 0 m
+-1 0.333 l
+-0.8 0 l
+-1 -0.333 l
+h
+</path>
+</symbol>
+<symbol name="arrow/linear(spx)">
+<path stroke="sym-stroke" pen="sym-pen">
+-1 0.333 m
+0 0 l
+-1 -0.333 l
+</path>
+</symbol>
+<symbol name="arrow/fdouble(spx)">
+<path stroke="sym-stroke" fill="white" pen="sym-pen">
+0 0 m
+-1 0.333 l
+-1 -0.333 l
+h
+-1 0 m
+-2 0.333 l
+-2 -0.333 l
+h
+</path>
+</symbol>
+<symbol name="arrow/double(spx)">
+<path stroke="sym-stroke" fill="sym-stroke" pen="sym-pen">
+0 0 m
+-1 0.333 l
+-1 -0.333 l
+h
+-1 0 m
+-2 0.333 l
+-2 -0.333 l
+h
+</path>
+</symbol>
+<pen name="heavier" value="0.8"/>
+<pen name="fat" value="1.2"/>
+<pen name="ultrafat" value="2"/>
+<symbolsize name="large" value="5"/>
+<symbolsize name="small" value="2"/>
+<symbolsize name="tiny" value="1.1"/>
+<arrowsize name="large" value="10"/>
+<arrowsize name="small" value="5"/>
+<arrowsize name="tiny" value="3"/>
+<color name="red" value="1 0 0"/>
+<color name="green" value="0 1 0"/>
+<color name="blue" value="0 0 1"/>
+<color name="yellow" value="1 1 0"/>
+<color name="orange" value="1 0.647 0"/>
+<color name="gold" value="1 0.843 0"/>
+<color name="purple" value="0.627 0.125 0.941"/>
+<color name="gray" value="0.745"/>
+<color name="brown" value="0.647 0.165 0.165"/>
+<color name="navy" value="0 0 0.502"/>
+<color name="pink" value="1 0.753 0.796"/>
+<color name="seagreen" value="0.18 0.545 0.341"/>
+<color name="turquoise" value="0.251 0.878 0.816"/>
+<color name="violet" value="0.933 0.51 0.933"/>
+<color name="darkblue" value="0 0 0.545"/>
+<color name="darkcyan" value="0 0.545 0.545"/>
+<color name="darkgray" value="0.663"/>
+<color name="darkgreen" value="0 0.392 0"/>
+<color name="darkmagenta" value="0.545 0 0.545"/>
+<color name="darkorange" value="1 0.549 0"/>
+<color name="darkred" value="0.545 0 0"/>
+<color name="lightblue" value="0.678 0.847 0.902"/>
+<color name="lightcyan" value="0.878 1 1"/>
+<color name="lightgray" value="0.827"/>
+<color name="lightgreen" value="0.565 0.933 0.565"/>
+<color name="lightyellow" value="1 1 0.878"/>
+<dashstyle name="dashed" value="[4] 0"/>
+<dashstyle name="dotted" value="[1 3] 0"/>
+<dashstyle name="dash dotted" value="[4 2 1 2] 0"/>
+<dashstyle name="dash dot dotted" value="[4 2 1 2 1 2] 0"/>
+<textsize name="large" value="\large"/>
+<textsize name="Large" value="\Large"/>
+<textsize name="LARGE" value="\LARGE"/>
+<textsize name="huge" value="\huge"/>
+<textsize name="Huge" value="\Huge"/>
+<textsize name="small" value="\small"/>
+<textsize name="footnote" value="\footnotesize"/>
+<textsize name="tiny" value="\tiny"/>
+<textstyle name="center" begin="\begin{center}" end="\end{center}"/>
+<textstyle name="itemize" begin="\begin{itemize}" end="\end{itemize}"/>
+<textstyle name="item" begin="\begin{itemize}\item{}" end="\end{itemize}"/>
+<gridsize name="4 pts" value="4"/>
+<gridsize name="8 pts (~3 mm)" value="8"/>
+<gridsize name="16 pts (~6 mm)" value="16"/>
+<gridsize name="32 pts (~12 mm)" value="32"/>
+<gridsize name="10 pts (~3.5 mm)" value="10"/>
+<gridsize name="20 pts (~7 mm)" value="20"/>
+<gridsize name="14 pts (~5 mm)" value="14"/>
+<gridsize name="28 pts (~10 mm)" value="28"/>
+<gridsize name="56 pts (~20 mm)" value="56"/>
+<anglesize name="90 deg" value="90"/>
+<anglesize name="60 deg" value="60"/>
+<anglesize name="45 deg" value="45"/>
+<anglesize name="30 deg" value="30"/>
+<anglesize name="22.5 deg" value="22.5"/>
+<tiling name="falling" angle="-60" step="4" width="1"/>
+<tiling name="rising" angle="30" step="4" width="1"/>
+</ipestyle>
+<page>
+<layer name="alpha"/>
+<view layers="alpha" active="alpha"/>
+<path layer="alpha" stroke="black" arrow="normal/normal">
+32 760 m
+32 832 l
+</path>
+<path stroke="black" arrow="normal/normal">
+24 768 m
+88 768 l
+</path>
+<path matrix="1 0 0 1 8 0" stroke="black">
+48 816 m
+48 784 l
+80 784 l
+80 816 l
+h
+</path>
+<path matrix="1 0 0 1 96 0" stroke="black" arrow="normal/normal">
+32 760 m
+32 832 l
+</path>
+<path matrix="1 0 0 1 96 0" stroke="black" arrow="normal/normal">
+24 768 m
+88 768 l
+</path>
+<path matrix="1 0 0 1 8 0" stroke="black">
+16 0 0 16 64 800 e
+</path>
+<path matrix="1 0 0 1 104 0" stroke="black">
+16 0 0 16 64 800 e
+</path>
+<text transformations="translations" pos="40 832" stroke="black" type="label" valign="baseline">$R^3$</text>
+</page>
+</ipe>

=== added file 'doc/sphinx/fig/cell-shear-aabb.pdf'
Binary files doc/sphinx/fig/cell-shear-aabb.pdf	1970-01-01 00:00:00 +0000 and doc/sphinx/fig/cell-shear-aabb.pdf	2013-11-15 08:22:02 +0000 differ
=== added file 'doc/sphinx/fig/cell-shear-aabb.png'
Binary files doc/sphinx/fig/cell-shear-aabb.png	1970-01-01 00:00:00 +0000 and doc/sphinx/fig/cell-shear-aabb.png	2013-11-15 08:22:02 +0000 differ
=== added file 'doc/sphinx/fig/dispatch-loop.pdf'
--- doc/sphinx/fig/dispatch-loop.pdf	1970-01-01 00:00:00 +0000
+++ doc/sphinx/fig/dispatch-loop.pdf	2013-11-15 08:22:02 +0000
@@ -0,0 +1,174 @@
+%PDF-1.4
+%��
+3 0 obj
+<< /Length 4 0 R
+   /Filter /FlateDecode
+>>
+stream
+x��ZK�����v���E� ��,�h7���d���C��o�F��$��[�1r���̐��?�ކ��������+�ǟ�{w�Y<b�z�����"����}��࿑���4�9����c�x;�vb���Y8	G
q��)���kG-��2�9~:������"����z��N��j������E"���������Re��o‡ �������7�����"��Sdp��_t��qrҰ�B�^��5����:�OQ�j�}G�0��e�.z�����R�j����cF'�#�xrf�����&|~Ka��^c��'��Es��mᚎZ��3�B3;zO-�nq���Qʙ�蔾f�M�?B��E��(��������~|��}=�HLuOS����
�^��np[�~C򭽈����H�Q�΃
�L�{��l,|#qak}х�]%�Q�<��;�m�����
��������I��u7�1���N�!�����Oȧ�����q�؅����IjsV�0��1���x���O���/5~e�qOB⑅TI�F��+e"�W����f�p����
c�LQA�������|��_T[�"��A�����D���=�ws�I���
�ޗ�jR����mߟ���c����,G���e�-������ �.��lb���*�\��x����G�Hv�1��'�Es|��G�3tdx��F?'�����H���N����"�*	��Вl4c2��>K�P�R�_aF�����+�졫H���<*S�#Z)����w%�$����Sr]YUt��72��K��s�ϱ~%��6#�bG���l�[��O�}G���J���ee�]ѓ�$<8��Aj(p7e-����T��'�	t[uT�|A"]����t
+.[R]Dٟh�Ai`߱�ܪ�-Ud��(R�3��Y�`IYQ���[]�U�*�,�Q�C�ިA�^g��9p������0=
m.M��p�R��aP@��+ϥf�� ��ɢ�"�Xn���n1��R�ۃD�iΆ�PT<q��Ԓ��WI
+���b�80&�����.g"QFLVW9>N���+�B	K�JY�b��PPH@,����H��C2�KV�؆�";�b�h!�H��qQC$��
+f�d!��}�9ٿ�mXW3a�
��z砵�ȿ�vG�p�n�����
+�<xot��4R}6qB��\�Z���d�N)�qX@��`�PD$�6I��g�'QVC��H+6(Μu],�$�ɳ�[Vy��h�����.))]�?͸E݀S�Xj�|�3?0��*��b��c>���6�{7C�4')�p=eP�0W�������WF��ˎ��t�_D�b��-�I��懨S>���'�R�]Ea�O��3U�	�� F
�
+Ӂ|��(|:���d|�8E]��|�3 1����G��`��m~�6;�����mR'���O��`u�5����O�J���������QteR�INZH����M7��e��w����
+ͣ�A�H�t���6Ȧ�����S�ѷ�* Y	�	�D�#pk�Z���!l�Gm��ycgb�n��@�STcF���ȁn'W����/9FoF&y|���Rf�KF:Ȅ�7 4mk�ă
+�@�[�6��}�L*��j"kL�B!����G�
+�+W�v�3��B�،5���jS Z�h�5���S�2�-0u��?���%�L.U��
����.<��g4��֘���������)X�rǪ������Q=�
�[amt�J��rց�@p�~��<̯)����B��V�� 1����T��@�'B���@�7M#3t>�}2�kz|�����7a��g����,��\v?x��V����G������������i�*��@5,r���#i�	j\����J5������,��
��lC���wEܥl�k�>��pN7XT�=����"7��-:��ӣ�,huC*n�ʹY`�1�ԣ~�����l�G/ȳ#�?��G���F����4yQa����2-8RWS}(\i�B��f��7���T>8,�����X�fg~�������d����TC�@�\����.��:�7: ��-��]�9c�a�^���q�e�lh��|�c��JX�@ss*��ZN���,�O7*t�~=
d
'`[8���
+O�0D���9�7�!�du/'ߪ���F�B��M)�S̝C�.w�}��L:r��T���Ӳ���S{c�!h׫-6��ytDT�*�����Q��
k�Z�
+�ȅm�/�B�m,�js�������O���&ǰ���C�������bO4
+��ŏ��S��IC&�bQO��ǵ,ALט�@͐����(����",E���!0�&ĩqԅ<�E�M�����oSQgvD��R�
*Ţ4�)���4ܧ�!8y���M��g)����&۝���g�RK6��/���A����)�-7Bzp�E��-��(��n�n9c��:���7��#��A��x����������6w�z��*?}.5?-�N^�����uix�#���F�Ϸ7#gmy���sڞ@;;Jh&ګז�~�r$�ii)^^�*�p�(��q�Q����e�@+��e������f�N�c�"_5���؁�ezU9�9Q'a�:�z!q%�����}ǛO�ݞh|vQ�Yc�Roo��,nQ�s���'MTl.|!K'��=���Κ9;�B�)�����}jG�,���ɺcݘ�]����-�^��8ՠ���ս���
+��yd!l��_�噔���'M��yzV[��1�6���YK�uvcMw���]���]F�$�������y4%?뭁;뭁;˭�����;˵�;˭�;��w��
ܙ^�o
ܙ�
ܙ�
܅��k�pmd9.�q�gy+���ޯ
ܙ�
ܙ�
ܙo
ܙ�
\�ꥁ+�
+�6pM����@o�V�׉����ƒuT^������<�z�+��*�_J|��R��������O~�����_5y����M�/�$t����9/��v2�1<ٳ��=tyk�����ߴT����I^�bf�P��S����/t_$U��N1r�0e�p��]��+S����������@&�'](7=������S������_q?wS���w��v�%���k�;~�����]Ur����ul<m�s�]��y�
+endstream
+endobj
+4 0 obj
+   4313
+endobj
+2 0 obj
+<<
+   /ExtGState <<
+      /a0 << /CA 0.341818 /ca 0.341818 >>
+      /a1 << /CA 1 /ca 1 >>
+      /a2 << /CA 0.465455 /ca 0.465455 >>
+      /a3 << /CA 0 /ca 0 >>
+      /a4 << /CA 0.301818 /ca 0.301818 >>
+      /a5 << /CA 0.356364 /ca 0.356364 >>
+   >>
+   /Font <<
+      /f-0-0 5 0 R
+   >>
+>>
+endobj
+6 0 obj
+<< /Type /Page
+   /Parent 1 0 R
+   /MediaBox [ 0 0 320 82.400002 ]
+   /Contents 3 0 R
+   /Group <<
+      /Type /Group
+      /S /Transparency
+      /CS /DeviceRGB
+   >>
+   /Resources 2 0 R
+>>
+endobj
+7 0 obj
+<< /Length 8 0 R
+   /Filter /FlateDecode
+   /Length1 8420
+>>
+stream
+x��{\UU�Z�9�}8��p8��QQQ��y)�,T$s2Q234���xɌLM�23P4�j�QgƩ�e�Cf�� ,��������<���BTRN��L3�?CH������}��T�o!$���z�E$va>��|�3
+?�����3�ۉs�ĖT�ۛ�]��Y3���t$�s��X�O���8�x���^J�CR������^A�x�H7�����\j��8/�]jK��W$�������PJ!�Tv}!�I2y*8��닕�
+>_l���D%��#kt��l���_���G�-Q�ΏZ��uW6�p��m�?]s����M�bqڿ������ө�?M��<�������K33f
HJ���pqt�w��x��̯����m�+��~����oX���W_���V>�d��Z��,���Đ�^M�nbr�}5=�ݥ�!Y��ed�������r-=�Ė��+�=A�GJ]�SH�O��B'A�ISӐWK�u�/}U�Ϟ��Z_8�7�Ϡ=w�P&G%7	#�Q��S�Ү7Z7�T���"k��]Yi��*݅\>X�R�'D�A�n.6.]Z���)��vv�la���s��,@](C��I4)&U*����&+=�j�����&�cdq���nJ���
ˍkؑL�{�{�{Yɡ9B�''��iJ?u>�O�=��jO�)�;M�23��	�X��፹�g��W�>��Fa��Mv��p�O?:��4��?n���������7*�U��<���."���{!L@�B
+yK����߶�Q�GV��.���Y�c�+h�2�h$!��n�<"�P%�lu~��c�!�KX��S=����p@H��������k�E}H`��BR�.�Fj��F-CD��K-�&��-�36?����Άw�z>��s�!�u*��L���썐�캿�$�)�Q_a%i�d��4�������g24ݛ���ǥ�$���/��y�y�<^\^|^rq�el����"~mr]���=�z&��qűžbq\yl���9��i��zB*O|Rր��qY�
X�L������9��I��7Ο}|�^2�Jg�\9�rw�E3�q섫lU����L��*��I])�l+�]l�@&�d�{d/gGkF[����#�]�6�.���M�74=.#��>��^�~�?�*M�f����>1��v�L]3�18eg��˕������ւ��nCuG�%����ÇR��d`�N��b\ɱc�wTV��՝uU㷾��ǭQP'Yꤌ������N��([�QD�	z�ʉ�i�\ ά�l�A�����=Hk�����i$b?��o�)^K��E�ēi�ɥD:����^?4F7G9��,�#/&R������6�҆
k
�`Xzb^bq�:,o&~�ؕ� ���O��!LSF�X������w7-\�fwSSNÒ'���0+l�ܛ/uV"V<4s)1ϰ
m�}ooR�aj����lu�)�ο!a���RJxLwTL��n�"� j��G�ζ��_]3�_:�!<\�;��)�
+	�$��}��A�0v�o��0N$����B/�H�Y���ݴ����x|a��_Q����2j�]�{qqIib�����K��妑26&5�H��ѵ:Rq9&��2��n+BJȉ*%�R��L.S�2��f+��9ʜez��.��(�D'gZ�,�d�5������\={�N����[t(�7��)�4$�c��Z��$��*�Y�Ea�͡�cZ-.S�3:�������K�<�S n�8���(Y���� ��{h�����ɽ%oά��}�%]_�U�G^��k �Fv���ɫc�3#�4g,�����%��.]3��޸1“��(����U���2��c�ƿEι~�����l��Σ���G������0e����v�*i�E2JF^��S	*yJ�R� j�e��#�Ă�u���1���[$�AQ�����Z���"kL�A�L�b�*zN��Ä80��'Pe��r�P�؎������-aj��d��:��>,,J-K�a�e��V�a4h?H�{+�,OUf���%��k��>���B
���"�4������2��H��q���adH0�׀`�S�������d���<��,z ΰq�/�����������ʊ�����L, �#x�E�8T]S	q�q����ݦj�U�5צ)N��J8fך�v�UU$ �CthN祖�Lgk��p�ìٷS����͉喥�
Ks�������,)`W#lN[�-�F����+m�6�J�6�Y5�戠�:Y�����H��(؀��%Z�m}�~}ɢYB��������l{�#]��iPBP�����z�m�}�#��t�0	�Y�d�,�R�d�j���h�0G}���@/���?��+��[��ʱE���[�;��������4�f*4S�~��ܝ�LJ���N����>������bwZ81��P��TE�P���Ѳ���6���"�G��{��l��5F�����:T�ՆZ5?����>ai���})����
+�B��V����JX�vp���DC���rRL)K)OY�R�r=%y��P)���ê�U��Ӳ�4�E�f,_={_p�O�:$��??8&�gKն�	dz��N�p$�߾?6���������҃6'�<V��&��r����} ��W�Pvk.��ѴK�����L2�<�}C~���_N��zWEXx������&DZ^ޤ("[�.�H#A���a&mff��Gv�}����N���~�2��Lر�f�kv5r�c��	�}�vt���p�s�?�c_�؛��P�"2sV���ű���zECd��������s�I�@��@՘'H��u�.4�jU{������B��	,^���I����2ʂ��{������WI�IE�^ˣ��!{�uT���p�"�Jx���&s�/W<x�M�������fqm�o�������q�N��t�����WWc�%mݱ��܉�5�R�^�,��=&�E�WH�K�9�Kfj��>1�pćҊ�[����l&�
t���o�}7�[��k�x��|i�~�Ώ+W�^!�.(��n�����CNC���Ymo�����Kwi#�f$i*h[��н
���;]��?�`Gc������/�_�g��ၿ��AGPˈ�sm�o�6F�����i�9T�#�qs���qq�������4�Q­��ZR�tK���фԺ�����1c�,�ǰI�I��*0	ݷ0�
+�#��ȺC,+�R�k��@O��&[5U�%&b��Y����B1�z���\ƿ0�ڜ�5�[Nފcm�gh�i�6cd���.��x5K#�a�Ԡz�p��橏
+��"u�P&,ae�R�lf����+���
+H��YS��z�({�h9Zqkk�h��qb��񖀜�$�qZ�5���}�0F�A1���PF�#��=h�L&�B�8���ɓ'*�B:[��Q�s���G����]",�'��Lz�fy���T}\[f�V�j�6������/������^i�e�����e�ʛ���K�h43�4A�	���6����������B�`�B�z?ֆ���.�{�Dƚ����Z�ׂ����h'�q��Т�C�g�$Q��F��X�Y�����'�nl���N8HV�E���C,Mž��YI�=�7�db/!W�@n�r��0�!��b�xU�@�%�@,��d��lx[p����#��8B��O��/q�G��R����&�
+�v�l��_��E���\&�AF�����<��P��.��w���}��ǽf�������Ý�CK�l7=Iۤ
��\��W�	�4�q
+H5��՘#�xv�����ZO�,3q�ជ�{��Œ����*���,c���+X���Yd.�����ZR�+����p�3<s5]#�B���T���!���!8a�������;-���[���^yj�i���>��߸�)��Α#�WY0����?rDjH�BV����a?�l��f������	�<�m�U���}E�*��F�rD:D��[����/��R����� iR&)���{�fr�ؗ��\w��IW[�6�J����{�����|�Q��)��qi����9I~V�+����Iڈ����k�̂ ��i�P�����U?�G78���{����_�_e��ٗ�Њ['����/��ç>ɀ�������8���ep�������û.���s����������x��or8��fG9ѡ�"�84�������G��vxz��p���p�ë8��@!��B��PH��e�9�N/��2`�^,�:RW/p���m��=Ŷ�[����-*l氩�6q��A
N�����o��������[.V�&��CuP���?[�Ux��RcUnX�A%vTBr�"+t���x�C9�2���-cOqX��Bi����K8<a��x\�Ek��vX�ڡ���rx$~����N��9�a����fq���(h��0���q�:EeS��
+��b�̀�&�r!���M��{�al��O�_p�����������
�1^�6��èZY#8���;���r8�����v��
��a����r��0h��
r�,�
tB�b!��i,����i,�i�'�*�������������ƒ��C�x�9�/_;�b������Q؈�ȩ�<
+<���p����g���`��3+�����u���2��B�����*P'���XC�����
+endstream
+endobj
+8 0 obj
+   6354
+endobj
+9 0 obj
+<< /Length 10 0 R
+   /Filter /FlateDecode
+>>
+stream
+x�]�Mk�0����E�D(ۋ�~��&�1D��l��Ǚ�1��֌����.��a4�2ߜ"�u4�L�����4�f�������==DB�������?4�YE5����$�l����e��%��8��5-�S���N�Dd�e��OO�"k����*A9��Ae��U��:	:��_�]rP�:&�L
ҁ2�#��B?�`�
+���=%�U���W*�?�~�ُc�	��@�����ݜ�5L�'���U���
+endstream
+endobj
+10 0 obj
+   358
+endobj
+11 0 obj
+<< /Type /FontDescriptor
+   /FontName /BitstreamVeraSans
+   /Flags 4
+   /FontBBox [ -183 -235 1287 928 ]
+   /ItalicAngle 0
+   /Ascent 928
+   /Descent -235
+   /CapHeight 928
+   /StemV 80
+   /StemH 80
+   /FontFile2 7 0 R
+>>
+endobj
+12 0 obj
+<< /Type /Font
+   /Subtype /CIDFontType2
+   /BaseFont /BitstreamVeraSans
+   /CIDSystemInfo
+   << /Registry (Adobe)
+      /Ordering (Identity)
+      /Supplement 0
+   >>
+   /FontDescriptor 11 0 R
+   /W [0 [ 600 634 634 633 615 411 837 575 612 549 392 770 974 636 611 352 774 277 862 603 591 520 277 294 634 636 500 686 634 633 557 817 ]]
+>>
+endobj
+5 0 obj
+<< /Type /Font
+   /Subtype /Type0
+   /BaseFont /BitstreamVeraSans
+   /Encoding /Identity-H
+   /DescendantFonts [ 12 0 R]
+   /ToUnicode 9 0 R
+>>
+endobj
+1 0 obj
+<< /Type /Pages
+   /Kids [ 6 0 R ]
+   /Count 1
+>>
+endobj
+13 0 obj
+<< /Creator (cairo 1.8.8 (http://cairographics.org))
+   /Producer (cairo 1.8.8 (http://cairographics.org))
+>>
+endobj
+14 0 obj
+<< /Type /Catalog
+   /Pages 1 0 R
+>>
+endobj
+xref
+0 15
+0000000000 65535 f 
+0000012618 00000 n 
+0000004427 00000 n 
+0000000015 00000 n 
+0000004404 00000 n 
+0000012459 00000 n 
+0000004732 00000 n 
+0000004938 00000 n 
+0000011385 00000 n 
+0000011408 00000 n 
+0000011843 00000 n 
+0000011866 00000 n 
+0000012104 00000 n 
+0000012683 00000 n 
+0000012809 00000 n 
+trailer
+<< /Size 15
+   /Root 14 0 R
+   /Info 13 0 R
+>>
+startxref
+12862
+%%EOF

=== added file 'doc/sphinx/fig/dispatch-loop.svg'
--- doc/sphinx/fig/dispatch-loop.svg	1970-01-01 00:00:00 +0000
+++ doc/sphinx/fig/dispatch-loop.svg	2013-11-15 08:22:02 +0000
@@ -0,0 +1,354 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="399.08963"
+   height="102.38328"
+   id="svg2"
+   inkscape:label="Pozadí"
+   version="1.1"
+   inkscape:version="0.47pre4 r22446"
+   sodipodi:docname="dispatch-loop.svg">
+  <defs
+     id="defs3">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective9" />
+    <inkscape:perspective
+       id="perspective3659"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3694"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3723"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3758"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3801"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3889"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.979899"
+     inkscape:cx="217.86473"
+     inkscape:cy="22.154429"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1126"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata6">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Vrstva 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-26.274116,-0.93043024)">
+    <rect
+       style="fill:#d4a700;fill-opacity:0.34181818;stroke:#d4a700;stroke-width:2.02341175;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect2865"
+       width="129.27612"
+       height="90.132698"
+       x="27.285822"
+       y="12.169303" />
+    <rect
+       style="fill:#ff8080;fill-opacity:0.34181818;stroke:#d4a700;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect3639"
+       width="107.83379"
+       height="40.911179"
+       x="43.436562"
+       y="20.743895" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot2815"
+       style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="translate(-0.75761441,-0.25253814)"><flowRegion
+         id="flowRegion2817"><rect
+           id="rect2819"
+           width="324.28574"
+           height="57.142857"
+           x="50"
+           y="25.219324"
+           style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" /></flowRegion><flowPara
+         id="flowPara2821">Sphere+Sphere</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot2823"
+       style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="translate(2.3520666,-71.574701)"><flowRegion
+         id="flowRegion2825"><rect
+           id="rect2827"
+           width="324.28571"
+           height="74.285713"
+           x="52.857143"
+           y="112.36218"
+           style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" /></flowRegion><flowPara
+         id="flowPara2829">Facet+Sphere</flowPara></flowRoot>    <rect
+       style="fill:#87decd;fill-opacity:0.34181818;stroke:#000000;stroke-width:2.17540693;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:0.46545458;stroke-dasharray:none"
+       id="rect3748"
+       width="121.29543"
+       height="73.060654"
+       x="214.24005"
+       y="21.084137" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.93949091px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 144.6741,34.3507 72.2864,6.121424"
+       id="path2831"
+       inkscape:connector-type="polyline"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:none;stroke:#000000;stroke-width:0.96579325px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+       d="m 141.90933,51.57065 74.7855,-9.125578"
+       id="path2833"
+       inkscape:connector-type="polyline"
+       sodipodi:nodetypes="cc" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot2837"
+       style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="translate(62.124381,-4.7982246)"><flowRegion
+         id="flowRegion2839"><rect
+           id="rect2841"
+           width="95.459412"
+           height="20.455587"
+           x="173.4937"
+           y="39.431717" /></flowRegion><flowPara
+         id="flowPara2843">Dem3DofGeom</flowPara><flowPara
+         id="flowPara2845" /></flowRoot>    <rect
+       style="fill:#5555ff;fill-opacity:0.34181818;stroke:#000000;stroke-opacity:0.46545458"
+       id="rect3649"
+       width="111.11678"
+       height="25.506351"
+       x="42.678944"
+       y="66.705833" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot2847"
+       style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="translate(-3.2829958,8.5862966)"><flowRegion
+         id="flowRegion2849"><rect
+           id="rect2851"
+           width="114.65231"
+           height="25.001276"
+           x="48.739861"
+           y="63.675377" /></flowRegion><flowPara
+         id="flowPara2853">FrictMat+FrictMat</flowPara></flowRoot>    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 153.79573,80.847971 227.28432,71.50406"
+       id="path2855"
+       inkscape:connector-type="polyline"
+       sodipodi:nodetypes="cc" />
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot2857"
+       style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="translate(80.812204,-1.0101525)"><flowRegion
+         id="flowRegion2859"><rect
+           id="rect2861"
+           width="99.500023"
+           height="16.667517"
+           x="175.51401"
+           y="64.432991" /></flowRegion><flowPara
+         id="flowPara2863">FrictPhys</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3641"
+       style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#808000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="matrix(0,-1,1,0,14.778665,106.58155)"><flowRegion
+         id="flowRegion3643"><rect
+           id="rect3645"
+           width="32.577412"
+           height="11.364215"
+           x="52.780476"
+           y="15.94567"
+           style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#808000;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" /></flowRegion><flowPara
+         id="flowPara3647">Shape</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3641-7"
+       style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#2c5aa0;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="matrix(0,-1,1,0,14.7406,148.73663)"><flowRegion
+         id="flowRegion3643-3"><rect
+           id="rect3645-4"
+           width="32.577412"
+           height="11.364215"
+           x="52.780476"
+           y="15.94567"
+           style="font-size:8px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#2c5aa0;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" /></flowRegion><flowPara
+         id="flowPara3647-7">Material</flowPara></flowRoot>    <text
+       xml:space="preserve"
+       style="font-size:4px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       x="148.87294"
+       y="17.31669"
+       id="text3682"
+       sodipodi:linespacing="100%"
+       transform="matrix(0.99541901,0.09560851,-0.09560851,0.99541901,0,0)"><tspan
+         sodipodi:role="line"
+         id="tspan3684"
+         x="148.87294"
+         y="17.31669">Ig2_Sphere_Sphere_Dem3DofGeom</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:4px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       x="140.26605"
+       y="75.324471"
+       id="text3682-9"
+       sodipodi:linespacing="100%"
+       transform="matrix(0.99154808,-0.12973973,0.12973973,0.99154808,0,0)"><tspan
+         sodipodi:role="line"
+         x="140.26605"
+         y="75.324471"
+         id="tspan3711">Ig2_Facet_Sphere_Dem3DofGeom</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:4px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       x="149.65134"
+       y="94.587654"
+       id="text3682-9-2"
+       sodipodi:linespacing="100%"
+       transform="matrix(0.99283737,-0.11947368,0.11947368,0.99283737,0,0)"><tspan
+         sodipodi:role="line"
+         x="149.65134"
+         y="94.587654"
+         id="tspan3711-0">Ip2_FrictMat_FrictMat_FrictPhys</tspan></text>
+    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3740"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ff0000;fill-opacity:1;stroke:#000000;stroke-opacity:0;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="translate(1.0101525,2.2728432)"><flowRegion
+         id="flowRegion3742"><rect
+           id="rect3744"
+           width="43.941635"
+           height="19.445436"
+           x="30.809652"
+           y="-1.2269233"
+           style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ff0000;stroke:#000000;stroke-opacity:0;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" /></flowRegion><flowPara
+         id="flowPara3746">Body</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3740-1"
+       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ff2a2a;fill-opacity:1;stroke:#000000;stroke-opacity:0;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="translate(185.78568,11.696678)"><flowRegion
+         id="flowRegion3742-5"><rect
+           id="rect3744-8"
+           width="61.114231"
+           height="11.111678"
+           x="30.809652"
+           y="-1.2269233"
+           style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#ff2a2a;stroke:#000000;stroke-opacity:0;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" /></flowRegion><flowPara
+         id="flowPara3746-6">Interaction</flowPara></flowRoot>    <flowRoot
+       xml:space="preserve"
+       id="flowRoot3781"
+       style="font-size:6px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#8800aa;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+       transform="matrix(0,-1,1,0,191.35167,276.14482)"><flowRegion
+         id="flowRegion3783"><rect
+           id="rect3785"
+           width="69.195442"
+           height="32.324879"
+           x="218.95056"
+           y="28.320038"
+           style="font-size:6px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#8800aa;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" /></flowRegion><flow

Follow ups