[gmsh] 03/06: Imported Upstream version 2.8.5+dfsg

Anton Gladky gladk at moszumanska.debian.org
Fri Jul 25 21:21:00 UTC 2014


This is an automated email from the git hooks/post-receive script.

gladk pushed a commit to branch master
in repository gmsh.

commit d43e2c40b39628cf8ab9beccc3de30e764427012
Author: Anton Gladky <gladk at debian.org>
Date:   Fri Jul 25 21:59:08 2014 +0200

    Imported Upstream version 2.8.5+dfsg
---
 CMakeLists.txt                                     |  186 +-
 CTestConfig.cmake                                  |    3 +
 Common/CommandLine.cpp                             |   54 +-
 Common/Context.h                                   |    8 +-
 Common/CreateFile.cpp                              |   39 +-
 Common/DefaultOptions.h                            |   52 +-
 Common/Gmsh.cpp                                    |   30 +-
 Common/Gmsh.h                                      |    2 +
 Common/GmshConfig.h.in                             |    2 +
 Common/GmshDefines.h                               |    4 +-
 Common/GmshIO.h                                    |   45 +
 Common/GmshMessage.cpp                             |   54 +-
 Common/GmshMessage.h                               |    4 +
 Common/GmshRemote.cpp                              |   27 +-
 Common/GmshSocket.h                                |    3 +
 Common/OS.cpp                                      |    8 +-
 Common/OS.h                                        |    2 +-
 Common/OctreeInternals.cpp                         |    2 +-
 Common/OpenFile.cpp                                |  112 +-
 Common/OpenFile.h                                  |    6 +-
 Common/Options.cpp                                 |   92 +-
 Common/Options.h                                   |   12 +-
 Common/TreeUtils.cpp                               |    7 +
 Common/TreeUtils.h                                 |    1 +
 Common/gmshPopplerWrapper.cpp                      |   64 +-
 Common/gmshPopplerWrapper.h                        |   28 +-
 Common/onelab.h                                    |  106 +-
 Common/onelabUtils.cpp                             |   24 +-
 Common/onelabUtils.h                               |    2 +-
 Fltk/FlGui.cpp                                     |   37 +-
 Fltk/clippingWindow.cpp                            |    4 +-
 Fltk/colorbarWindow.cpp                            |   19 +-
 Fltk/contextWindow.cpp                             |    2 +-
 Fltk/drawContextFltkCairo.cpp                      |   20 +-
 Fltk/drawContextFltkStringTexture.cpp              |   38 +-
 Fltk/fileDialogs.cpp                               |   81 +
 Fltk/fileDialogs.h                                 |    1 +
 Fltk/graphicWindow.cpp                             |   76 +-
 Fltk/helpWindow.cpp                                |   59 +-
 Fltk/highOrderToolsWindow.cpp                      |   81 +-
 Fltk/inputRange.h                                  |   12 +-
 Fltk/inputValue.cpp                                |   10 +-
 Fltk/inputValue.h                                  |   18 +-
 Fltk/manipWindow.cpp                               |    2 +-
 Fltk/onelabGroup.cpp                               |  492 +-
 Fltk/onelabGroup.h                                 |   19 +-
 Fltk/openglWindow.cpp                              |    3 +-
 Fltk/optionWindow.cpp                              |   50 +-
 Fltk/optionWindow.h                                |    2 +-
 Fltk/pluginWindow.cpp                              |    2 +-
 Fltk/projectionEditor.cpp                          |    6 +-
 Fltk/visibilityWindow.cpp                          |   23 +-
 Geo/CMakeLists.txt                                 |    3 +-
 Geo/Cell.cpp                                       |   12 +-
 Geo/Cell.h                                         |    2 +-
 Geo/CellComplex.cpp                                |    9 +-
 Geo/CellComplex.h                                  |    2 +-
 Geo/Chain.cpp                                      |    2 +-
 Geo/Chain.h                                        |    2 +-
 Geo/ChainComplex.cpp                               |  389 +-
 Geo/ChainComplex.h                                 |   58 +-
 Geo/Curvature.h                                    |    9 +-
 Geo/ExtrudeParams.cpp                              |   17 +-
 Geo/GEdge.cpp                                      |  128 +-
 Geo/GEdge.h                                        |    6 +-
 Geo/GEdgeLoop.cpp                                  |   38 +-
 Geo/GFace.cpp                                      |   19 +-
 Geo/GFaceCompound.cpp                              |    1 +
 Geo/GModel.cpp                                     |   17 +-
 Geo/GModel.h                                       |   13 +-
 Geo/GModelFactory.cpp                              |   33 +-
 Geo/GModelFactory.h                                |    5 +
 Geo/GModelIO_CELUM.cpp                             |    1 +
 Geo/GModelIO_GEO.cpp                               |   17 +-
 Geo/GModelIO_MED.cpp                               |    4 +-
 Geo/GModelIO_MESH.cpp                              |   11 +-
 Geo/GModelIO_MSH2.cpp                              |   23 +-
 Geo/GModelIO_OCC.cpp                               |   60 +-
 Geo/GModelIO_OCC.h                                 |    1 +
 Geo/GModelIO_PLY.cpp                               |    2 +-
 Geo/GModelIO_SU2.cpp                               |    1 +
 Geo/GModelIO_UNV.cpp                               |   29 +-
 Geo/GRbf.cpp                                       |    2 +
 Geo/GRegion.cpp                                    |   20 +-
 Geo/GRegion.h                                      |    5 +
 Geo/Geo.cpp                                        |  544 +-
 Geo/Geo.h                                          |    6 +
 Geo/GeoInterpolation.cpp                           |    7 +-
 Geo/GeoStringInterface.cpp                         |   67 +-
 Geo/GeomMeshMatcher.cpp                            |    8 +-
 Geo/Homology.cpp                                   |    7 +-
 Geo/Homology.h                                     |    2 +-
 Geo/MElement.cpp                                   |   27 +-
 Geo/MElement.h                                     |    5 +-
 Geo/MElementCut.cpp                                |   12 +-
 Geo/MElementCut.h                                  |   12 +-
 Geo/MHexahedron.cpp                                |    8 -
 Geo/MHexahedron.h                                  |    2 +-
 Geo/MLine.cpp                                      |   68 +-
 Geo/MLine.h                                        |    4 +-
 Geo/MPoint.h                                       |    4 -
 Geo/MPrism.cpp                                     |   41 +-
 Geo/MPrism.h                                       |    2 +-
 Geo/MPyramid.cpp                                   |    8 -
 Geo/MPyramid.h                                     |    2 -
 Geo/MQuadrangle.cpp                                |    9 -
 Geo/MQuadrangle.h                                  |   14 +-
 Geo/MSubElement.cpp                                |   16 +-
 Geo/MSubElement.h                                  |    8 +-
 Geo/MTetrahedron.cpp                               |    8 -
 Geo/MTetrahedron.h                                 |    1 -
 Geo/MTriangle.cpp                                  |    8 -
 Geo/MTriangle.h                                    |    2 +-
 Geo/MVertexPositionSet.h                           |    1 +
 Geo/OCC_Connect.cpp                                |    8 +-
 Geo/SOrientedBoundingBox.cpp                       |   51 +-
 Geo/STensor3.cpp                                   |   21 +
 Geo/STensor3.h                                     |   11 +
 Geo/SVector3.h                                     |   34 +-
 Geo/boundaryLayersData.cpp                         |  165 +-
 Geo/boundaryLayersData.h                           |   12 +-
 Geo/closestPoint.cpp                               |   77 +
 Geo/closestPoint.h                                 |   25 +
 Geo/findLinks.cpp                                  |   33 +-
 Geo/gmshEdge.cpp                                   |  151 +-
 Geo/gmshEdge.h                                     |    2 +
 Geo/gmshEdgeDiscretize.cpp                         |  196 +
 Geo/gmshFace.cpp                                   |    1 -
 Geo/gmshLevelset.cpp                               |    3 +-
 Geo/intersectCurveSurface.cpp                      |   50 +-
 Geo/intersectCurveSurface.h                        |   29 +-
 Graphics/CMakeLists.txt                            |    1 +
 Graphics/drawContext.cpp                           |  202 +-
 Graphics/drawContext.h                             |    6 +-
 Graphics/gl2pgf.cpp                                |  715 ++
 Graphics/gl2pgf.h                                  |   16 +
 Mesh/BackgroundMesh.cpp                            |  130 +-
 Mesh/BackgroundMesh.h                              |   12 +
 Mesh/BoundaryLayers.cpp                            |  125 +-
 Mesh/CenterlineField.cpp                           |   15 +-
 Mesh/DivideAndConquer.cpp                          |   13 +-
 Mesh/DivideAndConquer.h                            |   43 +-
 Mesh/Field.cpp                                     |  164 +-
 Mesh/Generator.cpp                                 |  146 +-
 Mesh/HighOrder.cpp                                 | 1221 +--
 Mesh/HighOrder.h                                   |    5 -
 Mesh/QuadTriExtruded2D.cpp                         |   28 +-
 Mesh/cross3D.h                                     |    5 +-
 Mesh/directions3D.cpp                              |   10 +-
 Mesh/filterElements.cpp                            |    2 +-
 Mesh/meshGEdge.cpp                                 |   16 +-
 Mesh/meshGFace.cpp                                 |  742 +-
 Mesh/meshGFace.h                                   |    5 +-
 Mesh/meshGFaceDelaunayInsertion.cpp                |  460 +-
 Mesh/meshGFaceDelaunayInsertion.h                  |   17 +-
 Mesh/meshGFaceElliptic.cpp                         |   14 +-
 Mesh/meshGFaceLloyd.cpp                            |   34 +-
 Mesh/meshGFaceOptimize.cpp                         |   83 +-
 Mesh/meshGFaceOptimize.h                           |    5 +-
 Mesh/meshGFaceRecombine.cpp                        |    4 +-
 Mesh/meshGFaceTransfinite.cpp                      |    4 +-
 Mesh/meshGRegion.cpp                               |  351 +-
 Mesh/meshGRegion.h                                 |    4 +-
 Mesh/meshGRegionDelaunayInsertion.cpp              |  488 +-
 Mesh/meshGRegionDelaunayInsertion.h                |    3 +
 Mesh/meshGRegionLocalMeshMod.cpp                   |   18 +-
 Mesh/meshGRegionMMG3D.cpp                          |    3 +
 Mesh/meshPartition.cpp                             |    2 +-
 Mesh/meshRefine.cpp                                |   67 +-
 Mesh/periodical.cpp                                |   17 +-
 Mesh/surfaceFiller.cpp                             |  638 +-
 Mesh/surfaceFiller.h                               |    1 +
 Mesh/yamakawa.cpp                                  |   24 +-
 Numeric/BasisFactory.cpp                           |   73 +-
 Numeric/BasisFactory.h                             |    7 +
 Numeric/BergotBasis.h                              |    7 +-
 Numeric/CMakeLists.txt                             |    5 +
 Numeric/HilbertCurve.cpp                           |  275 +
 Mesh/surfaceFiller.h => Numeric/HilbertCurve.h     |   12 +-
 Numeric/JacobianBasis.cpp                          |  381 +-
 Numeric/JacobianBasis.h                            |  107 +-
 Numeric/MetricBasis.cpp                            | 1628 ++++
 Numeric/MetricBasis.h                              |  158 +
 Numeric/Numeric.cpp                                |   12 +-
 Numeric/Numeric.h                                  |    6 +-
 Numeric/bezierBasis.cpp                            |  757 +-
 Numeric/bezierBasis.h                              |   13 +-
 Numeric/decasteljau.cpp                            |  141 +
 Numeric/decasteljau.h                              |   22 +
 Numeric/discreteFrechetDistance.cpp                |   54 +
 Numeric/discreteFrechetDistance.h                  |    7 +
 Numeric/fullMatrix.h                               |   10 +
 Numeric/hausdorffDistance.cpp                      |  115 +
 Numeric/hausdorffDistance.h                        |    7 +
 Numeric/mathEvaluator.cpp                          |   14 +-
 Numeric/miniBasis.cpp                              |   37 +
 Numeric/miniBasis.h                                |    8 +
 Numeric/nodalBasis.h                               |    1 +
 Numeric/polynomialBasis.h                          |    1 +
 Parser/FunctionManager.cpp                         |   18 +-
 Parser/FunctionManager.h                           |   12 +-
 Parser/Gmsh.l                                      |   45 +-
 Parser/Gmsh.tab.cpp                                | 7959 ++++++++++----------
 Parser/Gmsh.tab.hpp                                |  452 +-
 Parser/Gmsh.y                                      |  646 +-
 Parser/Gmsh.yy.cpp                                 | 1724 +++--
 Parser/Parser.h                                    |    5 +-
 Plugin/AnalyseCurvedMesh.cpp                       |  956 +--
 Plugin/AnalyseCurvedMesh.h                         |  122 +-
 Plugin/CMakeLists.txt                              |    7 +-
 Plugin/CurvedBndDist.cpp                           |  166 +
 Plugin/CurvedBndDist.h                             |   29 +
 Plugin/Distance.cpp                                |  104 +-
 Plugin/FieldFromAmplitudePhase.cpp                 |   48 +-
 Plugin/HomologyComputation.cpp                     |    2 +-
 Plugin/HomologyComputation.h                       |    2 +-
 Plugin/HomologyPostProcessing.cpp                  |    2 +-
 Plugin/HomologyPostProcessing.h                    |    2 +-
 Plugin/Integrate.cpp                               |    2 +-
 Plugin/Lambda2.h                                   |    4 +-
 Plugin/LongitudeLatitude.cpp                       |   71 +-
 Plugin/MathEval.cpp                                |   25 +-
 Plugin/MinMax.cpp                                  |   71 +-
 Plugin/ModifyComponent.cpp                         |   20 +-
 Plugin/ModulusPhase.cpp                            |   24 +-
 Plugin/Particles.h                                 |    4 +-
 Plugin/PluginManager.cpp                           |    6 +
 Plugin/Scal2Tens.cpp                               |  142 +
 Plugin/Scal2Tens.h                                 |   33 +
 Plugin/Scal2Vec.cpp                                |  132 +-
 Plugin/SphericalRaise.cpp                          |   43 +-
 Plugin/StreamLines.h                               |    4 +-
 Plugin/Tetrahedralize.cpp                          |  111 +-
 Plugin/Transform.cpp                               |   33 +-
 Plugin/Triangulate.cpp                             |   88 +-
 Plugin/Warp.cpp                                    |   21 +-
 Post/PViewData.cpp                                 |   36 +-
 Post/PViewData.h                                   |   19 +-
 Post/PViewDataGModel.h                             |    1 +
 Post/PViewDataIO.cpp                               |   10 +-
 Post/PViewDataList.cpp                             |    8 +-
 Post/PViewDataListIO.cpp                           |    1 +
 Post/PViewIO.cpp                                   |    9 +-
 Post/PViewVertexArrays.cpp                         |   19 +-
 Post/adaptiveData.cpp                              |  149 +-
 Solver/dofManager.cpp                              |    3 +-
 Solver/eigenSolver.cpp                             |  114 +-
 Solver/eigenSolver.h                               |   54 +-
 Solver/elasticitySolver.cpp                        |  134 +-
 Solver/linearSystem.h                              |    1 +
 Solver/linearSystemPETSc.cpp                       |   29 +-
 Solver/linearSystemPETSc.h                         |   10 +-
 Solver/linearSystemPETSc.hpp                       |   14 +-
 Solver/multiscaleLaplace.cpp                       |   12 +-
 contrib/HighOrderMeshOptimizer/CMakeLists.txt      |    1 +
 contrib/HighOrderMeshOptimizer/OptHOM.cpp          |   66 +-
 contrib/HighOrderMeshOptimizer/OptHOM.h            |   13 +-
 contrib/HighOrderMeshOptimizer/OptHomElastic.cpp   |    2 +-
 contrib/HighOrderMeshOptimizer/OptHomElastic.h     |    2 +-
 .../HighOrderMeshOptimizer/OptHomFastCurving.cpp   |  660 +-
 contrib/HighOrderMeshOptimizer/OptHomFastCurving.h |   13 +-
 .../OptHomIntegralBoundaryDist.cpp                 |  521 ++
 .../OptHomIntegralBoundaryDist.h                   |   55 +
 contrib/HighOrderMeshOptimizer/OptHomMesh.cpp      |   72 +-
 contrib/HighOrderMeshOptimizer/OptHomMesh.h        |    2 +
 contrib/HighOrderMeshOptimizer/OptHomRun.cpp       |  150 +-
 contrib/HighOrderMeshOptimizer/OptHomRun.h         |    9 +-
 contrib/HighOrderMeshOptimizer/ParamCoord.cpp      |    1 +
 contrib/HighOrderMeshOptimizer/SuperEl.cpp         |  326 +-
 contrib/HighOrderMeshOptimizer/SuperEl.h           |   42 +-
 contrib/Metis/CMakeLists.txt                       |   62 -
 contrib/Tetgen1.4/CMakeLists.txt                   |   12 -
 contrib/Tetgen1.5/CMakeLists.txt                   |   12 -
 contrib/bamg/bamglib/Mesh2.h                       |    2 +-
 contrib/blossom/concorde97/INCLUDE/linkern.h       |    4 +-
 contrib/gmm/gmm_inoutput.h                         |  252 +-
 contrib/gmm/gmm_precond_diagonal.h                 |   10 +-
 contrib/mobile/Android/AndroidManifest.xml         |  104 +-
 .../Android/res/drawable-hdpi/ic_launcher.png      |  Bin 865 -> 8478 bytes
 .../Android/res/drawable-ldpi/ic_launcher.png      |  Bin 384 -> 4567 bytes
 .../Android/res/drawable-mdpi/ic_launcher.png      |  Bin 614 -> 5169 bytes
 .../Android/res/drawable-mdpi/icon_rotate.png      |  Bin 0 -> 13253 bytes
 .../Android/res/drawable-mdpi/icon_translate.png   |  Bin 0 -> 11127 bytes
 .../Android/res/layout/activity_fragment.xml       |   10 +-
 .../mobile/Android/res/layout/activity_model.xml   |   16 +-
 .../mobile/Android/res/layout/activity_twopane.xml |   47 +-
 contrib/mobile/Android/res/layout/control_bar.xml  |   77 +-
 .../mobile/Android/res/layout/fragment_options.xml |   46 +-
 .../res/layout/fragment_options_display.xml        |   10 +-
 contrib/mobile/Android/res/layout/list_header.xml  |   19 +-
 contrib/mobile/Android/res/layout/model.xml        |   17 +-
 contrib/mobile/Android/res/layout/splash.xml       |   30 +-
 contrib/mobile/Android/res/raw/models.zip          |  Bin 3480741 -> 0 bytes
 contrib/mobile/Android/res/values/strings.xml      |   38 +-
 contrib/mobile/Android/res/values/styles.xml       |    6 +-
 .../Android/src/org/geuz/onelab/AboutActivity.java |   40 +
 .../Android/src/org/geuz/onelab/GLESRender.java    |  101 +-
 .../mobile/Android/src/org/geuz/onelab/Gmsh.java   |  229 +-
 .../Android/src/org/geuz/onelab/MainActivity.java  |  509 +-
 .../mobile/Android/src/org/geuz/onelab/Model.java  |   68 +-
 .../src/org/geuz/onelab/ModelArrayAdapter.java     |   60 +-
 .../Android/src/org/geuz/onelab/ModelFragment.java |  405 +-
 .../Android/src/org/geuz/onelab/ModelList.java     |  400 +-
 .../src/org/geuz/onelab/OptionsActivity.java       |   30 +-
 .../geuz/onelab/OptionsPostProcessingFragment.java |    2 -
 .../Android/src/org/geuz/onelab/Parameter.java     |  151 +-
 .../src/org/geuz/onelab/ParameterNumber.java       |  508 +-
 .../src/org/geuz/onelab/ParameterString.java       |  274 +-
 .../src/org/geuz/onelab/SeparatedListView.java     |  294 +-
 .../Android/src/org/geuz/onelab/SplashScreen.java  |  139 +-
 .../Android/src/org/geuz/onelab/Stepper.java       |   80 +
 .../Android/src/org/geuz/onelab/StringTexture.java |  304 +-
 .../src/org/geuz/onelab/mGLSurfaceView.java        |  219 +-
 contrib/mobile/CMakeLists.txt                      |   84 +-
 contrib/mobile/README.txt                          |   30 +
 contrib/mobile/Trackball.cpp                       |   10 +-
 contrib/mobile/androidGModel.cpp                   |  572 +-
 contrib/mobile/androidGModel.h                     |   20 +-
 contrib/mobile/drawContext.cpp                     | 1312 ++--
 contrib/mobile/drawContext.h                       |   92 +-
 contrib/mobile/drawGeom.cpp                        |  129 +-
 contrib/mobile/drawMesh.cpp                        |  175 +-
 contrib/mobile/drawString.cpp                      |  114 +-
 contrib/mobile/drawString.h                        |   32 +-
 .../mobile/iOS/Onelab.xcodeproj/project.pbxproj    |   89 +-
 contrib/mobile/iOS/Onelab/AboutViewController.h    |    7 +
 contrib/mobile/iOS/Onelab/AboutViewController.mm   |   67 +
 contrib/mobile/iOS/Onelab/AppDelegate.h            |    8 -
 contrib/mobile/iOS/Onelab/AppDelegate.mm           |   72 +-
 contrib/mobile/iOS/Onelab/EAGLView.h               |    1 +
 contrib/mobile/iOS/Onelab/EAGLView.mm              |  237 +-
 .../AppIcon.appiconset/Contents.json               |   56 +
 .../AppIcon.appiconset/icon_app_ipad.png           |  Bin 0 -> 1915 bytes
 .../AppIcon.appiconset/icon_app_ipad_retina.png    |  Bin 0 -> 4144 bytes
 .../AppIcon.appiconset/icon_app_iphone_retina.png  |  Bin 0 -> 3193 bytes
 .../LaunchImage.launchimage/Contents.json          |   57 +
 .../LaunchImage.launchimage/splash1024x768.png     |  Bin 0 -> 6927 bytes
 .../LaunchImage.launchimage/splash1536x2048.png    |  Bin 0 -> 23429 bytes
 .../LaunchImage.launchimage/splash2048x1536.png    |  Bin 0 -> 22482 bytes
 .../LaunchImage.launchimage/splash640x1136.png     |  Bin 0 -> 7008 bytes
 .../LaunchImage.launchimage/splash640x960.png      |  Bin 0 -> 6328 bytes
 .../LaunchImage.launchimage/splash768x1024.png     |  Bin 0 -> 7117 bytes
 contrib/mobile/iOS/Onelab/Model.h                  |    8 -
 contrib/mobile/iOS/Onelab/Model.mm                 |  104 +-
 contrib/mobile/iOS/Onelab/ModelListController.h    |    8 -
 contrib/mobile/iOS/Onelab/ModelListController.mm   |  312 +-
 contrib/mobile/iOS/Onelab/ModelViewController.h    |   11 +-
 contrib/mobile/iOS/Onelab/ModelViewController.mm   |  511 +-
 contrib/mobile/iOS/Onelab/Onelab-Info.plist        |  160 +-
 contrib/mobile/iOS/Onelab/OptionsViewController.h  |    8 -
 contrib/mobile/iOS/Onelab/OptionsViewController.mm |  309 +-
 contrib/mobile/iOS/Onelab/Parameter.h              |   42 +-
 contrib/mobile/iOS/Onelab/Parameter.mm             |  496 +-
 .../mobile/iOS/Onelab/ParametersViewController.h   |   10 +-
 .../mobile/iOS/Onelab/ParametersViewController.mm  |  525 +-
 .../iOS/Onelab/PostProcessingViewController.h      |    8 -
 .../iOS/Onelab/PostProcessingViewController.mm     |  149 +-
 contrib/mobile/iOS/Onelab/SplitViewController.h    |   12 +-
 contrib/mobile/iOS/Onelab/SplitViewController.mm   |   58 +-
 contrib/mobile/iOS/Onelab/Utils.h                  |    8 -
 contrib/mobile/iOS/Onelab/Utils.mm                 |   38 +-
 contrib/mobile/iOS/Onelab/emulatorFix.c            |   13 +-
 .../iOS/Onelab/en.lproj/iPadStoryboard.storyboard  |  107 +-
 .../en.lproj/iPhoneiPodStoryboard.storyboard       |  192 +-
 .../iOS/Onelab/files/magnet/Magnetostatics.pro     |  215 -
 contrib/mobile/iOS/Onelab/files/magnet/infos.xml   |    9 -
 contrib/mobile/iOS/Onelab/files/magnet/magnet.geo  |   88 -
 contrib/mobile/iOS/Onelab/files/magnet/magnet.pro  |   67 -
 .../mobile/iOS/Onelab/files/magnet/magnet_data.pro |   14 -
 contrib/mobile/iOS/Onelab/files/pmsm/BH.pro        |   87 -
 contrib/mobile/iOS/Onelab/files/pmsm/infos.xml     |   11 -
 .../iOS/Onelab/files/pmsm/machine_magstadyn_a.pro  | 1091 ---
 contrib/mobile/iOS/Onelab/files/pmsm/pmsm.geo      |   96 -
 contrib/mobile/iOS/Onelab/files/pmsm/pmsm.pro      |  185 -
 .../iOS/Onelab/files/pmsm/pmsm_8p_circuit.pro      |  122 -
 contrib/mobile/iOS/Onelab/files/pmsm/pmsm_data.geo |  122 -
 .../mobile/iOS/Onelab/files/pmsm/pmsm_rotor.geo    |  164 -
 .../mobile/iOS/Onelab/files/pmsm/pmsm_stator.geo   |  217 -
 contrib/mobile/iOS/Onelab/icon_onelab.png          |  Bin 0 -> 5169 bytes
 contrib/mobile/iOS/Onelab/icon_rotate.png          |  Bin 0 -> 13253 bytes
 contrib/mobile/iOS/Onelab/icon_translate.png       |  Bin 0 -> 11127 bytes
 contrib/mobile/iOS/Onelab/main.mm                  |   14 +-
 contrib/mobile/iosGModel.cpp                       |   19 +-
 contrib/mobile/iosGModel.h                         |   30 +-
 contrib/mobile/movePosition.h                      |    7 +-
 contrib/mobile/utils/Android.cmake                 | 1125 +++
 ...ndroid_petsc_reconfigure-armv7-android-linux.py |   53 +
 contrib/mobile/utils/ant.properties                |    4 +
 contrib/mobile/utils/iOS.cmake                     |  131 +
 contrib/mobile/utils/icon_rotate.svg               |   60 +
 contrib/mobile/utils/icon_translate.svg            |   60 +
 contrib/mobile/utils/ios_f2cblaslapack_makefile    |   48 +
 .../ios_petsc_reconfigure-arm64-unknown-darwin.py  |   41 +
 contrib/mobile/utils/make_icon_ios.sh              |    8 +-
 contrib/mobile/utils/onelab_android.sh             |   93 -
 contrib/mobile/utils/onelab_android_build.sh       |  108 +
 contrib/mobile/utils/onelab_ios_build.sh           |   85 +
 contrib/mobile/utils/onelab_iossimulator_build.sh  |   57 +
 contrib/onelab/OLMakefile                          |   61 -
 contrib/onelab/OnelabParser.cpp                    |    8 +-
 contrib/onelab/python/onelab.py                    |  209 +-
 contrib/onelab/python/test.py                      |    2 +-
 contrib/onelab/python/wrappers/Makefile            |   11 -
 contrib/onelab/python/wrappers/OnelabClient.py     |   59 -
 contrib/onelab/python/wrappers/onelab.i            |   15 -
 contrib/onelab/python/wrappers/test.ol             |    2 -
 contrib/onelab/python/wrappers/test.py             |   20 -
 demos/piece-extr-rec.geo                           |   18 +-
 doc/CREDITS.txt                                    |    8 +-
 doc/VERSIONS.txt                                   |   10 +-
 doc/gmsh.html                                      |  141 +-
 doc/texinfo/commandline.texi                       |    6 +-
 doc/texinfo/gmsh.texi                              |   63 +-
 doc/texinfo/opt_fields.texi                        |   43 +
 doc/texinfo/opt_general.texi                       |   39 +-
 doc/texinfo/opt_geometry.texi                      |    7 +-
 doc/texinfo/opt_mesh.texi                          |    5 -
 doc/texinfo/opt_plugin.texi                        |  676 +-
 doc/texinfo/opt_print.texi                         |   17 +-
 doc/texinfo/opt_solver.texi                        |    8 +-
 doc/texinfo/shortcuts.texi                         |    2 +
 utils/converters/matlab/gmsh2pdetoolbox.m          |  287 +
 utils/icons/apple-touch-icon.png                   |  Bin 4921 -> 0 bytes
 utils/icons/gmsh.xcf                               |  Bin 987612 -> 1074968 bytes
 utils/icons/gmsh_mobile_master.png                 |  Bin 0 -> 79737 bytes
 utils/misc/package_gmsh_getdp.sh                   |    4 +-
 utils/solvers/c++/GmshSocket.h                     |    9 +-
 utils/solvers/c++/onelab.h                         |  119 +-
 wrappers/gmshpy/gmshGeo.i                          |   12 +-
 wrappers/gmshpy/gmshSolver.i                       |    1 +
 430 files changed, 27700 insertions(+), 19592 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index fea3a7f..0c00f7e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,6 +44,7 @@ opt(BUILD_IOS "Enable iOS (ARM) library target (experimental)" OFF)
 opt(CGNS "Enable CGNS mesh export (experimental)" OFF)
 opt(CAIRO "Enable Cairo to render fonts (experimental)" ${DEFAULT})
 opt(CHACO "Enable Chaco mesh partitioner (alternative to Metis)" ${DEFAULT})
+opt(COMPRESSED_IO "Enable compressed (gzip) input/output using zlib" OFF)
 opt(DINTEGRATION "Enable discrete integration (needed for levelsets)" ${DEFAULT})
 opt(FLTK "Enable FLTK graphical user interface (requires mesh/post)" ${DEFAULT})
 opt(FOURIER_MODEL "Enable Fourier geometrical models (experimental)" OFF)
@@ -63,8 +64,9 @@ opt(NATIVE_FILE_CHOOSER "Enable native file chooser in GUI" ${DEFAULT})
 opt(NETGEN "Enable Netgen 3D frontal mesh generator" ${DEFAULT})
 opt(NUMPY "Enable conversion between fullMatrix and numpy array (requires SWIG)" OFF)
 opt(OCC "Enable Open CASCADE geometrical models" ${DEFAULT})
-opt(ONELAB "Enable OneLab solver interface" ${DEFAULT})
-opt(ONELAB_METAMODEL "Enable OneLab metamodels (experimental)" ${DEFAULT})
+opt(ONELAB "Enable ONELAB solver interface" ${DEFAULT})
+opt(ONELAB2 "Enable experimental ONELAB-Cloud solver interface" OFF)
+opt(ONELAB_METAMODEL "Enable ONELAB metamodels (experimental)" ${DEFAULT})
 opt(OPENMP "Enable OpenMP (experimental)" OFF)
 opt(OPTHOM "Enable high-order mesh optimization tools" ${DEFAULT})
 opt(OS_SPECIFIC_INSTALL "Enable OS-specific (e.g. app bundle) installation" ${DEFAULT})
@@ -81,6 +83,7 @@ opt(SGEOM "Enable SGEOM interface to OCC (experimental)" OFF)
 opt(SLEPC "Enable SLEPc eigensolvers (required for conformal compounds)" ${DEFAULT})
 opt(SOLVER "Enable built-in finite element solvers (required for compounds)" ${DEFAULT})
 opt(TAUCS "Enable Taucs linear solver (alternative to PETSc)" ${DEFAULT})
+opt(TCMALLOC "Enable libtcmalloc, a fast malloc implementation but that does not release memory" OFF)
 opt(TETGEN "Enable Tetgen 3D initial mesh generator" ${DEFAULT})
 opt(TETGEN_OLD "Enable older version of Tetgen" OFF)
 opt(VORO3D "Enable Voro3D (for hex meshing, experimental)" ${DEFAULT})
@@ -89,7 +92,7 @@ opt(WRAP_PYTHON "Enable generation of Python wrappers" OFF)
 
 set(GMSH_MAJOR_VERSION 2)
 set(GMSH_MINOR_VERSION 8)
-set(GMSH_PATCH_VERSION 4)
+set(GMSH_PATCH_VERSION 5)
 set(GMSH_EXTRA_VERSION "" CACHE STRING "Gmsh extra version string")
 
 set(GMSH_VERSION "${GMSH_MAJOR_VERSION}.${GMSH_MINOR_VERSION}")
@@ -104,7 +107,7 @@ set(GMSH_API
     Common/OS.h Common/StringUtils.h Common/OpenFile.h
     Common/onelab.h Common/GmshSocket.h Common/onelabUtils.h
   Numeric/Numeric.h Numeric/GaussIntegration.h Numeric/polynomialBasis.h
-    Numeric/JacobianBasis.h Numeric/bezierBasis.h Numeric/fullMatrix.h
+    Numeric/JacobianBasis.h Numeric/MetricBasis.h Numeric/bezierBasis.h Numeric/fullMatrix.h
     Numeric/simpleFunction.h Numeric/cartesian.h Numeric/ElementType.h
   Geo/GModel.h Geo/GEntity.h Geo/GPoint.h Geo/GVertex.h Geo/GEdge.h 
     Geo/GFace.h Geo/GRegion.h Geo/GEdgeLoop.h Geo/GEdgeCompound.h 
@@ -336,6 +339,8 @@ if(ENABLE_BLAS_LAPACK)
         list(APPEND EXTERNAL_LIBRARIES ${LAPACK_LIB})
         set_config_option(HAVE_LAPACK "Lapack")
       endif(LAPACK_LIB)
+      # for isnan/isinf
+      add_definitions(-D_GLIBCXX_USE_C99_MATH=1)
     endif(ENABLE_BUILD_ANDROID)
 
     if(NOT HAVE_BLAS OR NOT HAVE_LAPACK)
@@ -385,6 +390,14 @@ if(ENABLE_BLAS_LAPACK)
   endif(BLAS_LAPACK_LIBRARIES)
 endif(ENABLE_BLAS_LAPACK)
 
+if(ENABLE_TCMALLOC)
+  find_library(TCMALLOC tcmalloc)
+  if(TCMALLOC)
+    set_config_option(HAVE_TCMALLOC "TCMalloc")
+    list(APPEND EXTERNAL_LIBRARIES ${TCMALLOC})
+  endif(TCMALLOC)
+endif(ENABLE_TCMALLOC)
+
 add_subdirectory(Common)
 add_subdirectory(Numeric)
 add_subdirectory(Geo)
@@ -489,16 +502,20 @@ if(ENABLE_NATIVE_FILE_CHOOSER)
 endif(ENABLE_NATIVE_FILE_CHOOSER)
 
 if(ENABLE_ONELAB)
-  set_config_option(HAVE_ONELAB "OneLab")
+  set_config_option(HAVE_ONELAB "ONELAB")
   if(ENABLE_ONELAB_METAMODEL)
     add_subdirectory(contrib/onelab)
     include_directories(contrib/onelab)
-    set_config_option(HAVE_ONELAB_METAMODEL "OneLabMetamodel")
+    set_config_option(HAVE_ONELAB_METAMODEL "ONELABMetamodel")
   endif(ENABLE_ONELAB_METAMODEL)
   file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/contrib/onelab/python/onelab.py
             DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
 endif(ENABLE_ONELAB)
 
+if(ENABLE_ONELAB2)
+  set_config_option(HAVE_ONELAB2 "ONELAB2")
+endif(ENABLE_ONELAB2)
+
 if(ENABLE_BUILD_IOS)
   find_file(CMAKE_TOOLCHAIN_FILE "ios.cmake")
   if(NOT CMAKE_TOOLCHAIN_FILE)
@@ -506,22 +523,9 @@ if(ENABLE_BUILD_IOS)
   endif(NOT CMAKE_TOOLCHAIN_FILE)
 endif(ENABLE_BUILD_IOS)
 
-if(ENABLE_BUILD_ANDROID)
-  find_file(CMAKE_TOOLCHAIN_FILE "android.toolchain.cmake")
-  if(NOT CMAKE_TOOLCHAIN_FILE)
-    message(FATAL_ERROR "Cannot compile Gmsh for android without android-cmake")
-  endif(NOT CMAKE_TOOLCHAIN_FILE)
-  set(CMAKE_BUILD_TYPE Release)
-  set(LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_CURRENT_BINARY_DIR})
-  set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/libs/)
-  add_library(androidGmsh SHARED ${GMSH_SRC})
-  set_target_properties(androidGmsh PROPERTIES OUTPUT_NAME Gmsh)
-  target_link_libraries(androidGmsh ${EXTERNAL_LIBRARIES})
-endif(ENABLE_BUILD_ANDROID)
-
 if(HAVE_FLTK OR HAVE_QT OR ENABLE_GRAPHICS)
   if(NOT HAVE_MESH OR NOT HAVE_POST OR NOT HAVE_PLUGINS OR NOT HAVE_ONELAB)
-    message(SEND_ERROR "Cannot compile GUI without Mesh, Post, Plugin and OneLab")
+    message(SEND_ERROR "Cannot compile GUI without Mesh, Post, Plugin and ONELAB")
   endif(NOT HAVE_MESH OR NOT HAVE_POST OR NOT HAVE_PLUGINS OR NOT HAVE_ONELAB)
 
   if(FLTK_JPEG)
@@ -654,16 +658,16 @@ if(ENABLE_MATHEX)
 endif(ENABLE_MATHEX)
 
 if(ENABLE_MPI)
-   find_package(MPI)
-   if(MPI_FOUND)
-     set_config_option(HAVE_MPI "MPI")
-     list(APPEND EXTERNAL_INCLUDES ${MPI_INCLUDE_DIR})
-     list(APPEND EXTERNAL_LIBRARIES ${MPI_LIBRARIES})
-     include(CMakeForceCompiler)
-     # Warning: this actually requires cmake >= 2.8.5
-     cmake_force_c_compiler(${MPI_C_COMPILER} "MPI C Compiler")
-     cmake_force_cxx_compiler(${MPI_CXX_COMPILER} "MPI C++ Compiler")
-   endif(MPI_FOUND)
+  find_package(MPI)
+  if(MPI_FOUND)
+    set_config_option(HAVE_MPI "MPI")
+    list(APPEND EXTERNAL_INCLUDES ${MPI_INCLUDE_DIR})
+    list(APPEND EXTERNAL_LIBRARIES ${MPI_LIBRARIES})
+    include(CMakeForceCompiler)
+    # Warning: this actually requires cmake >= 2.8.5
+    cmake_force_c_compiler(${MPI_C_COMPILER} "MPI C Compiler")
+    cmake_force_cxx_compiler(${MPI_CXX_COMPILER} "MPI C++ Compiler")
+  endif(MPI_FOUND)
 endif(ENABLE_MPI)
 
 if(ENABLE_POPPLER)
@@ -671,10 +675,10 @@ if(ENABLE_POPPLER)
   find_library(POPPLER_CPP_LIB poppler-cpp)
   find_path(POPPLER_INC "poppler/cpp/poppler-document.h" PATH_SUFFIXES src include)
   if(POPPLER_LIB AND POPPLER_INC)
-     set_config_option(HAVE_POPPLER "Poppler")
-     list(APPEND EXTERNAL_LIBRARIES ${POPPLER_LIB})
-     list(APPEND EXTERNAL_LIBRARIES ${POPPLER_CPP_LIB})
-     list(APPEND EXTERNAL_INCLUDES ${POPPLER_INC})
+    set_config_option(HAVE_POPPLER "Poppler")
+    list(APPEND EXTERNAL_LIBRARIES ${POPPLER_LIB})
+    list(APPEND EXTERNAL_LIBRARIES ${POPPLER_CPP_LIB})
+    list(APPEND EXTERNAL_INCLUDES ${POPPLER_INC})
   endif(POPPLER_LIB AND POPPLER_INC)
 endif(ENABLE_POPPLER)
 
@@ -921,6 +925,12 @@ if(HAVE_SOLVER)
       endif(NOT PETSC_LIBS)
       if(PETSC_LIBS)
         set_config_option(HAVE_PETSC "PETSc")
+	if(NOT HAVE_BLAS)
+          set_config_option(HAVE_BLAS "Blas(PETSc)")
+        endif(NOT HAVE_BLAS)
+	if(NOT HAVE_LAPACK)
+          set_config_option(HAVE_LAPACK "Lapack(PETSc)")
+        endif(NOT HAVE_LAPACK)
       endif(PETSC_LIBS)
       # find slepc (needs to be linked in before petsc)
       if(ENABLE_SLEPC)
@@ -1078,8 +1088,13 @@ if(ENABLE_ACIS)
   endif(ACIS_LIB)
 endif(ENABLE_ACIS)
 
+if(HAVE_ZLIB AND ENABLE_COMPRESSED_IO)
+  set_config_option(HAVE_COMPRESSED_IO "CompressedIO")
+endif(HAVE_ZLIB AND ENABLE_COMPRESSED_IO)
+
 if(ENABLE_WRAP_PYTHON)
   find_package(SWIG)
+  find_package(PythonInterp)
   find_package(PythonLibs)
   if(SWIG_FOUND AND PYTHONLIBS_FOUND)
     message(STATUS "Found SWIG version " ${SWIG_VERSION})
@@ -1094,7 +1109,10 @@ endif(ENABLE_WRAP_PYTHON)
 
 if(HAVE_PYTHON)
   if(ENABLE_NUMPY)
-    find_path(NUMPY_INC "numpyconfig.h" HINTS ${PYTHON_INCLUDE_PATH} PATH_SUFFIXES /numpy)
+    EXEC_PROGRAM (${PYTHON_EXECUTABLE}
+      ARGS "-c \"import numpy; print(numpy.get_include())\""
+      OUTPUT_VARIABLE NUMPY_INC
+      RETURN_VALUE NUMPY_NOT_FOUND)
     if(NUMPY_INC)
       list(APPEND EXTERNAL_INCLUDES ${NUMPY_INC})
       set_config_option(HAVE_NUMPY "Numpy")
@@ -1103,9 +1121,9 @@ if(HAVE_PYTHON)
 endif(HAVE_PYTHON)
 
 check_function_exists(vsnprintf HAVE_VSNPRINTF)
-if(NOT HAVE_VSNPRINTF AND NOT ENABLE_BUILD_IOS)
+if(NOT HAVE_VSNPRINTF AND NOT ENABLE_BUILD_IOS AND NOT ENABLE_BUILD_ANDROID)
   set_config_option(HAVE_NO_VSNPRINTF "NoVsnprintf")
-endif(NOT HAVE_VSNPRINTF AND NOT ENABLE_BUILD_IOS)
+endif(NOT HAVE_VSNPRINTF AND NOT ENABLE_BUILD_IOS AND NOT ENABLE_BUILD_ANDROID)
 
 check_include_file(sys/socket.h HAVE_SYS_SOCKET_H)
 if(HAVE_SYS_SOCKET_H)
@@ -1113,9 +1131,9 @@ if(HAVE_SYS_SOCKET_H)
 endif(HAVE_SYS_SOCKET_H)
 check_type_size(socklen_t SOCKLEN_T_SIZE)
 set(CMAKE_EXTRA_INCLUDE_FILES)
-if(NOT SOCKLEN_T_SIZE AND NOT ENABLE_BUILD_IOS)
+if(NOT SOCKLEN_T_SIZE AND NOT ENABLE_BUILD_IOS AND NOT ENABLE_BUILD_ANDROID)
   set_config_option(HAVE_NO_SOCKLEN_T "NoSocklenT")
-endif(NOT SOCKLEN_T_SIZE AND NOT ENABLE_BUILD_IOS)
+endif(NOT SOCKLEN_T_SIZE AND NOT ENABLE_BUILD_IOS AND NOT ENABLE_BUILD_ANDROID)
 
 check_include_file(stdint.h HAVE_STDINT_H)
 if(HAVE_STDINT_H)
@@ -1125,9 +1143,9 @@ else(HAVE_STDINT_H)
 endif(HAVE_STDINT_H)
 check_type_size(intptr_t INTPTR_T_SIZE)
 set(CMAKE_EXTRA_INCLUDE_FILES)
-if(NOT INTPTR_T_SIZE AND NOT ENABLE_BUILD_IOS)
+if(NOT INTPTR_T_SIZE AND NOT ENABLE_BUILD_IOS AND NOT ENABLE_BUILD_ANDROID)
   set_config_option(HAVE_NO_INTPTR_T "NoIntptrT")
-endif(NOT INTPTR_T_SIZE AND NOT ENABLE_BUILD_IOS)
+endif(NOT INTPTR_T_SIZE AND NOT ENABLE_BUILD_IOS AND NOT ENABLE_BUILD_ANDROID)
 
 check_include_file(dlfcn.h DLFCN_H)
 if(DLFCN_H)
@@ -1181,7 +1199,7 @@ endif(NOWARN)
 check_cxx_compiler_flag("-O0" NOOPT)
 if(NOOPT)
   file(GLOB_RECURSE NOOPT_SRC Numeric/robustPredicates.cpp Mesh/BDS.cpp
-                              Parser/Gmsh.tab.cpp contrib/Tetgen*/*.cxx)
+                              Parser/Gmsh.tab.cpp contrib/Tetgen*/predicates.cxx)
   foreach(FILE ${NOOPT_SRC})
     get_source_file_property(PROP ${FILE} COMPILE_FLAGS)
     if(PROP)
@@ -1240,9 +1258,10 @@ else(HAVE_FLTK)
   set(LINK_LIBRARIES ${EXTERNAL_LIBRARIES} ${LAPACK_LIBRARIES})
 endif(HAVE_FLTK)
 
-# try to use static gfortran on static Linux builds
+# Linux-specific linking
 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-  if(NOT ENABLE_BUILD_DYNAMIC)
+  # try to use static gfortran on static Linux builds
+  if(NOT ENABLE_BUILD_DYNAMIC AND NOT ENABLE_BUILD_SHARED)
     find_library(GFORTRAN_STATIC libgfortran.a)
     if(GFORTRAN_STATIC)
       message(STATUS "Using static libgfortran")
@@ -1252,7 +1271,13 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
       endforeach(STR)
       set(LINK_LIBRARIES ${LINK_LIBRARIES2})
     endif(GFORTRAN_STATIC)
-  endif(NOT ENABLE_BUILD_DYNAMIC)
+  endif(NOT ENABLE_BUILD_DYNAMIC AND NOT ENABLE_BUILD_SHARED)
+  if(HAVE_OCC)
+    find_library(RT_LIB rt)
+    if(RT_LIB)
+      list(APPEND LINK_LIBRARIES ${RT_LIB})
+    endif(RT_LIB)
+  endif(HAVE_OCC)
 endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 
 # we could specify include dirs more selectively, but this is simpler
@@ -1283,6 +1308,20 @@ if(ENABLE_BUILD_LIB)
   endif(MSVC)
 endif(ENABLE_BUILD_LIB)
 
+if(ENABLE_BUILD_ANDROID)
+  find_file(CMAKE_TOOLCHAIN_FILE "android.toolchain.cmake")
+  if(NOT CMAKE_TOOLCHAIN_FILE)
+    message(FATAL_ERROR "Cannot compile Gmsh for android without android-cmake")
+  endif(NOT CMAKE_TOOLCHAIN_FILE)
+  set(CMAKE_BUILD_TYPE Release)
+  set(LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_CURRENT_BINARY_DIR})
+  set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/libs/)
+  add_definitions(-DBUILD_ANDROID)
+  add_library(androidGmsh SHARED ${GMSH_SRC})
+  set_target_properties(androidGmsh PROPERTIES OUTPUT_NAME Gmsh)
+  target_link_libraries(androidGmsh ${EXTERNAL_LIBRARIES})
+endif(ENABLE_BUILD_ANDROID)
+
 # shared library target
 if(ENABLE_BUILD_SHARED OR ENABLE_BUILD_DYNAMIC OR 
    ENABLE_WRAP_PYTHON OR ENABLE_WRAP_JAVA)
@@ -1346,7 +1385,8 @@ if(WIN32 AND NOT MSVC OR CYGWIN)
     set(CMAKE_EXE_LINK_DYNAMIC_CXX_FLAGS)
   endif(ENABLE_BUILD_DYNAMIC)
 elseif(MSVC)
-  set_target_properties(gmsh PROPERTIES LINK_FLAGS "/STACK:16777216")
+  set_target_properties(gmsh PROPERTIES LINK_FLAGS
+    "/STACK:16777216 /SAFESEH:NO")
 endif(WIN32 AND NOT MSVC OR CYGWIN)
 
 # parser target
@@ -1493,15 +1533,14 @@ if(UNIX AND NOT CYGWIN)
   install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/doc/gmsh.1 DESTINATION ${GMSH_MAN})
 endif(UNIX AND NOT CYGWIN)
 
-add_custom_target(getHeaders
-  COMMAND ${CMAKE_COMMAND} -E remove_directory Headers
+add_custom_target(get_headers
   COMMAND ${CMAKE_COMMAND} -E make_directory Headers/gmsh
   WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
-  foreach(FILE ${GMSH_API})
-    add_custom_command(TARGET getHeaders POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
-        ${FILE} ${CMAKE_CURRENT_BINARY_DIR}/Headers/gmsh/
-        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-  endforeach(FILE)
+foreach(FILE ${GMSH_API})
+  add_custom_command(TARGET get_headers POST_BUILD COMMAND ${CMAKE_COMMAND} 
+    -E copy_if_different ${FILE} ${CMAKE_CURRENT_BINARY_DIR}/Headers/gmsh/
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+endforeach(FILE)
 
 find_program(MAKEINFO makeinfo)
 if(MAKEINFO)
@@ -1518,6 +1557,8 @@ if(MAKEINFO)
                      ARGS ${TEX_DIR}/gmsh.texi WORKING_DIRECTORY ${TEX_DIR})
   add_custom_target(html DEPENDS ${TEX_DIR}/gmsh.html)
   install(FILES ${TEX_DIR}/gmsh.html DESTINATION ${GMSH_DOC} OPTIONAL)
+else(MAKEINFO)
+  add_custom_target(html COMMAND ${CMAKE_COMMAND} -E touch ${TEX_DIR}/gmsh.html)
 endif(MAKEINFO)
 
 find_program(TEXI2PDF texi2pdf)
@@ -1555,22 +1596,16 @@ if(APPLE AND ENABLE_BUILD_LIB)
   get_target_property(LIBNAME lib LOCATION)
   add_custom_target(framework DEPENDS lib
     COMMAND ${CMAKE_COMMAND} -E remove_directory Gmsh.framework
-    COMMAND ${CMAKE_COMMAND} -E make_directory Gmsh.framework/Versions/A/Headers
-    COMMAND ${CMAKE_COMMAND} -E make_directory Gmsh.framework/Versions/A/Resources
-    COMMAND ${CMAKE_COMMAND} -E copy ${LIBNAME} Gmsh.framework/Versions/A/Gmsh
+    COMMAND ${CMAKE_COMMAND} -E make_directory Gmsh.framework/Headers
+    COMMAND ${CMAKE_COMMAND} -E make_directory Gmsh.framework/Resources
+    COMMAND ${CMAKE_COMMAND} -E copy ${LIBNAME} Gmsh.framework/Gmsh
     COMMAND ${CMAKE_COMMAND} -E copy Info_framework.plist 
-                                     Gmsh.framework/Versions/A/Resources/Info.plist
-    COMMAND ${CMAKE_COMMAND} -E create_symlink A Gmsh.framework/Versions/Current
-    COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Gmsh 
-                                               Gmsh.framework/Gmsh
-    COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Headers
-                                               Gmsh.framework/Headers
-    COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Resources
-                                               Gmsh.framework/Resources 
+                                     Gmsh.framework/Resources/Info.plist
+    COMMAND ${CMAKE_COMMAND} -E create_symlink . Gmsh.framework/Headers/gmsh
     WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
   foreach(FILE ${GMSH_API})
     add_custom_command(TARGET framework POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
-        ${FILE} ${CMAKE_CURRENT_BINARY_DIR}/Gmsh.framework/Versions/A/Headers/
+        ${FILE} ${CMAKE_CURRENT_BINARY_DIR}/Gmsh.framework/Headers/
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
   endforeach(FILE)
 endif(APPLE AND ENABLE_BUILD_LIB)
@@ -1628,7 +1663,7 @@ else(APPLE AND ENABLE_OS_SPECIFIC_INSTALL)
   set(CPACK_GENERATOR TGZ)
 endif(APPLE AND ENABLE_OS_SPECIFIC_INSTALL)
 
-if (HAVE_PYTHON)
+if(HAVE_PYTHON)
   add_subdirectory(wrappers/gmshpy)
 endif(HAVE_PYTHON)
 
@@ -1642,10 +1677,23 @@ endif(ENABLE_WRAP_JAVA)
 include(CPack)
 
 include(CTest)
-file(GLOB_RECURSE TESTFILES tutorial/*.geo)
+file(GLOB_RECURSE TESTFILES 
+     tutorial/*.geo demos/*.geo benchmarks/?d/*.geo benchmarks/extrude/*.geo)
 foreach(TESTFILE ${TESTFILES})
-  add_test(${TESTFILE} ./gmsh ${TESTFILE} -3 -o ./tmp.msh)
+  # use relative path for cygwin/mingw (the pure win exe built with the mingw 
+  # compilers does not understand a full cygwin-style path)
+  FILE(RELATIVE_PATH TEST ${CMAKE_CURRENT_BINARY_DIR} ${TESTFILE})
+  add_test(${TEST} ./gmsh ${TEST} -3 -nopopup -o ./tmp.msh)
 endforeach()
+# if(HAVE_PYTHON)
+#   file(GLOB_RECURSE TESTFILES tutorial/*.py)
+#   foreach(TESTFILE ${TESTFILES})
+#     add_test(NAME ${TESTFILE} 
+#              COMMAND ${PYTHON_EXECUTABLE}
+#                      ${TESTFILE} $<CONFIGURATION>)
+#     # sys.path.insert(0, "path/to/your/package")
+#   endforeach()
+# endif(HAVE_PYTHON)
 
 message(STATUS "")
 message(STATUS "Gmsh ${GMSH_VERSION} has been configured for ${GMSH_OS}")
@@ -1656,8 +1704,6 @@ message(STATUS " * C compiler: " ${CMAKE_C_COMPILER})
 message(STATUS " * C++ compiler: " ${CMAKE_CXX_COMPILER})
 message(STATUS " * Install prefix: " ${CMAKE_INSTALL_PREFIX})
 message(STATUS "")
-message(STATUS "Run 'ccmake ${CMAKE_CURRENT_SOURCE_DIR}' to fine-tune the configuration.")
-message(STATUS "")
 
 mark_as_advanced(GMSH_EXTRA_VERSION 
                  ACIS_LIB ANN_INC ANN_LIB CAIRO_LIB CAIRO_INC CGNS_INC GMM_INC 
diff --git a/CTestConfig.cmake b/CTestConfig.cmake
index cbd0908..41ef39d 100644
--- a/CTestConfig.cmake
+++ b/CTestConfig.cmake
@@ -11,3 +11,6 @@ set(CTEST_DROP_LOCATION "/CDash/submit.php?project=Gmsh")
 set(CTEST_TRIGGER_SITE "")
 set(SITE ${GMSH_HOST})
 set(BUILDNAME "${GMSH_OS}-${GMSH_PACKAGER}")
+
+set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_WARNINGS "1000")
+set(CTEST_CUSTOM_MAXIMUM_NUMBER_OF_ERRORS "1000")
diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp
index 0296f95..60eefc2 100644
--- a/Common/CommandLine.cpp
+++ b/Common/CommandLine.cpp
@@ -28,6 +28,10 @@
 #endif
 #endif
 
+#if defined(HAVE_PETSC)
+#include "petsc.h"
+#endif
+
 #if defined(HAVE_POST)
 #include "PView.h"
 #endif
@@ -74,7 +78,7 @@ std::vector<std::pair<std::string, std::string> > GetUsage()
   s.push_back(mp("-saveall",           "Save all elements (discard physical group definitions)"));
   s.push_back(mp("-parametric",        "Save vertices with their parametric coordinates"));
   s.push_back(mp("-algo string",       "Select mesh algorithm (meshadapt, del2d, front2d, "
-                                        "delquad, del3d, front3d, mmg3d)"));
+                                        "delquad, del3d, front3d, mmg3d, pack)"));
   s.push_back(mp("-smooth int",        "Set number of mesh smoothing steps"));
   s.push_back(mp("-order int",         "Set mesh order (1, ..., 5)"));
   s.push_back(mp("-optimize[_netgen]", "Optimize quality of tetrahedral elements"));
@@ -125,6 +129,7 @@ std::vector<std::pair<std::string, std::string> > GetUsage()
   s.push_back(mp("-pid",               "Print process id on stdout"));
   s.push_back(mp("-listen",            "Always listen to incoming connection requests"));
   s.push_back(mp("-watch pattern",     "Pattern of files to merge as they become available"));
+  s.push_back(mp("-bg file",           "Load background (image or PDF) file"));
   s.push_back(mp("-v int",             "Set verbosity level"));
   s.push_back(mp("-nopopup",           "Don't popup dialog windows in scripts"));
   s.push_back(mp("-string \"string\"", "Parse command string at startup"));
@@ -184,6 +189,7 @@ std::vector<std::pair<std::string, std::string> > GetShortcutsUsage(const std::s
   s.push_back(mp(cc + "r",         "Rename project file"));
   s.push_back(mp(cc + "s",         "Save file as"));
   s.push_back(mp("Shift+" + cc + "c", "Show clipping plane window"));
+  s.push_back(mp("Shift+" + cc + "h", "Show current options and workspace window"));
   s.push_back(mp("Shift+" + cc + "j", "Save options as default"));
   s.push_back(mp("Shift+" + cc + "m", "Show manipulator window"));
   s.push_back(mp("Shift+" + cc + "n", "Show option window"));
@@ -301,16 +307,7 @@ void GetOptions(int argc, char *argv[])
           i += 1;
         }
         else
-          Msg::Fatal("Missing client name and/or address of OneLab server");
-      }
-      else if(!strcmp(argv[i] + 1, "lol")) {
-        i++;
-        if(argv[i] && argv[i + 1] && argv[i + 1][0] != '-'){
-          Msg::LoadOnelabClient(argv[i], argv[i + 1]);
-          i += 2;
-        }
-        else
-          Msg::Fatal("Missing client name and/or address of OneLab server");
+          Msg::Fatal("Missing client name and/or address of ONELAB server");
       }
       else if(!strcmp(argv[i] + 1, "socket")) {
         i++;
@@ -712,16 +709,6 @@ void GetOptions(int argc, char *argv[])
         else
           Msg::Fatal("Missing number");
       }
-      else if(!strcmp(argv[i] + 1, "mpass")) {
-        i++;
-        if(argv[i]) {
-          CTX::instance()->mesh.multiplePasses = atoi(argv[i++]);
-          if(CTX::instance()->mesh.multiplePasses <= 0)
-            Msg::Fatal("Number of Mesh Passes must be > 0");
-        }
-        else
-          Msg::Fatal("Missing number");
-      }
       else if(!strcmp(argv[i] + 1, "ignorePartBound")) {
         i++;
         opt_mesh_ignore_part_bound(0, GMSH_SET, 1);
@@ -906,31 +893,38 @@ void GetOptions(int argc, char *argv[])
         CTX::instance()->solver.listen = 1;
         i++;
       }
+      else if(!strcmp(argv[i] + 1, "bg")){
+        i++;
+        if(argv[i])
+          CTX::instance()->bgImageFileName = argv[i++];
+        else
+          Msg::Fatal("Missing filename");
+      }
       else if(!strcmp(argv[i] + 1, "version") || !strcmp(argv[i] + 1, "-version")) {
         fprintf(stderr, "%s\n", GMSH_VERSION);
         Msg::Exit(0);
       }
       else if(!strcmp(argv[i] + 1, "info") || !strcmp(argv[i] + 1, "-info")) {
         fprintf(stderr, "Version          : %s\n", GMSH_VERSION);
+        fprintf(stderr, "License          : %s\n", GMSH_SHORT_LICENSE);
+        fprintf(stderr, "Build OS         : %s\n", GMSH_OS);
+        fprintf(stderr, "Build date       : %s\n", GMSH_DATE);
+        fprintf(stderr, "Build host       : %s\n", GMSH_HOST);
+        fprintf(stderr, "Build options    :%s\n", GMSH_CONFIG_OPTIONS);
 #if defined(HAVE_FLTK)
-        fprintf(stderr, "GUI toolkit      : FLTK %d.%d.%d\n", FL_MAJOR_VERSION,
+        fprintf(stderr, "FLTK version     : %d.%d.%d\n", FL_MAJOR_VERSION,
                 FL_MINOR_VERSION, FL_PATCH_VERSION);
-#else
-        fprintf(stderr, "GUI toolkit      : none\n");
 #endif
 #if defined(HAVE_PETSC)
+        fprintf(stderr, "PETSc version    : %d.%d.%d\n", PETSC_VERSION_MAJOR,
+                PETSC_VERSION_MINOR, PETSC_VERSION_SUBMINOR);
 #if defined(PETSC_USE_COMPLEX)
         fprintf(stderr, "PETSc arithmetic : Complex\n");
 #else
         fprintf(stderr, "PETSc arithmetic : Real\n");
 #endif
 #endif
-        fprintf(stderr, "License          : %s\n", GMSH_SHORT_LICENSE);
-        fprintf(stderr, "Build OS         : %s\n", GMSH_OS);
-        fprintf(stderr, "Build options    :%s\n", GMSH_CONFIG_OPTIONS);
-        fprintf(stderr, "Build date       : %s\n", GMSH_DATE);
-        fprintf(stderr, "Build host       : %s\n", GMSH_HOST);
-        fprintf(stderr, "Packager         : %s\n", GMSH_PACKAGER);
+        fprintf(stderr, "Packaged by      : %s\n", GMSH_PACKAGER);
         fprintf(stderr, "Web site         : http://www.geuz.org/gmsh/\n");
         fprintf(stderr, "Mailing list     : gmsh at geuz.org\n");
         Msg::Exit(0);
diff --git a/Common/Context.h b/Common/Context.h
index 485711d..2079af1 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -70,7 +70,7 @@ struct contextGeometryOptions {
   double tolerance, snap[3], transform[3][3], offset[3];
   int occFixDegenerated, occFixSmallEdges, occFixSmallFaces;
   int occSewFaces, occConnectFaces;
-  int copyMeshingMethod, exactExtrusion;
+  int copyMeshingMethod, copyDisplayAttributes, exactExtrusion;
   int matchGeomAndMesh;
   int hideCompounds, orientedPhysicals;
 };
@@ -180,7 +180,8 @@ class CTX {
   int bgGradient;
   // draw background image?
   std::string bgImageFileName;
-  double bgImagePosition[2];
+  double bgImagePosition[2], bgImageSize[2];
+  int bgImage3d, bgImagePage;
   // fltk font size (and delta for palette windows)
   int fontSize, deltaFontSize;
   // font name, FLTK enum and size for opengl graphics
@@ -241,7 +242,7 @@ class CTX {
     std::string socketName;
     std::string name[NUM_SOLVERS], executable[NUM_SOLVERS], remoteLogin[NUM_SOLVERS];
     int autoSaveDatabase, autoArchiveOutputFiles, autoMesh, autoMergeFile;
-    int autoHideNewViews, autoShowLastStep, autoCheck, showInvisibleParameters;
+    int autoShowViews, autoShowLastStep, autoCheck, showInvisibleParameters;
   }solver;
   // print options
   struct{
@@ -255,6 +256,7 @@ class CTX {
     int compositeWindows, deleteTmpFiles, background;
     int width, height;
     double parameter, parameterFirst, parameterLast, parameterSteps;
+    int pgfTwoDim, pgfExportAxis, pgfHorizBar;
     std::string parameterCommand;
   } print;
   // color options
diff --git a/Common/CreateFile.cpp b/Common/CreateFile.cpp
index a06efe0..d4a2a2d 100644
--- a/Common/CreateFile.cpp
+++ b/Common/CreateFile.cpp
@@ -6,7 +6,6 @@
 #include "GmshConfig.h"
 #include "GmshMessage.h"
 #include "GModel.h"
-#include "PView.h"
 #include "GmshDefines.h"
 #include "StringUtils.h"
 #include "Context.h"
@@ -27,6 +26,7 @@
 #include "gl2png.h"
 #include "gl2ppm.h"
 #include "gl2yuv.h"
+#include "gl2pgf.h"
 #endif
 
 int GetFileFormatFromExtension(const std::string &ext)
@@ -61,6 +61,7 @@ int GetFileFormatFromExtension(const std::string &ext)
   else if(ext == ".mpg")  return FORMAT_MPEG;
   else if(ext == ".mpeg") return FORMAT_MPEG;
   else if(ext == ".png")  return FORMAT_PNG;
+  else if(ext == ".pgf")  return FORMAT_PGF;
   else if(ext == ".ps")   return FORMAT_PS;
   else if(ext == ".eps")  return FORMAT_EPS;
   else if(ext == ".pdf")  return FORMAT_PDF;
@@ -112,6 +113,7 @@ std::string GetDefaultFileName(int format)
   case FORMAT_JPEG: name += ".jpg"; break;
   case FORMAT_MPEG: name += ".mpg"; break;
   case FORMAT_PNG:  name += ".png"; break;
+  case FORMAT_PGF:  name += ".todo"; break;
   case FORMAT_PS:   name += ".ps"; break;
   case FORMAT_EPS:  name += ".eps"; break;
   case FORMAT_PDF:  name += ".pdf"; break;
@@ -483,7 +485,7 @@ void CreateOutputFile(const std::string &fileName, int format,
           glLoadMatrixd(modelview);
         }
         else{
-          buffer.fill(CTX::instance()->batch);
+          drawContext::global()->drawCurrentOpenglWindow(true);
         }
         res = gl2psEndPage();
       }
@@ -513,10 +515,9 @@ void CreateOutputFile(const std::string &fileName, int format,
         gl2psBeginPage(base.c_str(), "Gmsh", viewport,
                        GL2PS_TEX, GL2PS_NO_SORT, GL2PS_NONE, GL_RGBA, 0, NULL,
                        0, 0, 0, buffsize, fp, base.c_str());
-        PixelBuffer buffer(width, height, GL_RGB, GL_UNSIGNED_BYTE);
         int oldtext = CTX::instance()->print.text;
         CTX::instance()->print.text = 1;
-        buffer.fill(CTX::instance()->batch);
+        drawContext::global()->drawCurrentOpenglWindow(true);
         CTX::instance()->print.text = oldtext;
         res = gl2psEndPage();
       }
@@ -524,6 +525,35 @@ void CreateOutputFile(const std::string &fileName, int format,
     }
     break;
 
+  case FORMAT_PGF:
+    {
+      if(!FlGui::available()) break;
+      // fill pixel buffer without colorbar and axes
+      int restoreGeneralAxis = (int) opt_general_axes(0, GMSH_GET, 0);
+      int restoreSmallAxis = (int) opt_general_small_axes(0, GMSH_GET, 0);
+      opt_general_axes(0, GMSH_SET, 0);
+      opt_general_small_axes(0, GMSH_SET, 0);
+      int num = -1; // id of the post view
+      int cnt = 0; // no of scales/colorbars active
+      for(unsigned int i = 0; i < opt_post_nb_views(0,GMSH_GET,0); i++) {
+        if(opt_view_visible(i, GMSH_GET, 0)) {
+          if (opt_view_show_scale(i, GMSH_GET, 0)) {
+            opt_view_show_scale(i, GMSH_SET, 0);
+            num = i; cnt++;
+          }
+        }
+      }
+      PixelBuffer *buffer = GetCompositePixelBuffer(GL_RGB, GL_UNSIGNED_BYTE);
+      drawContext *ctx = FlGui::instance()->getCurrentOpenglWindow()->getDrawContext();
+      print_pgf(name, num, cnt, buffer, ctx->r, ctx->viewport, ctx->proj, ctx->model);
+      delete buffer;
+      // restore view
+      if(restoreGeneralAxis) opt_general_axes(0, GMSH_SET| GMSH_GUI, 1);
+      if(restoreSmallAxis) opt_general_small_axes(0, GMSH_SET | GMSH_GUI, 1);
+      if(cnt > 0) opt_view_show_scale(num, GMSH_SET, 1);
+    }
+    break;
+
 #if defined(HAVE_MPEG_ENCODE)
   case FORMAT_MPEG:
   case FORMAT_MPEG_PREVIEW:
@@ -635,4 +665,3 @@ void CreateOutputFile(const std::string &fileName, int format,
   if(redraw) drawContext::global()->draw();
 #endif
 }
-
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 00ce9f2..a4ad06b 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -39,7 +39,7 @@ StringXString GeneralOptions_String[] = {
     "Z-axis label" },
 
   { F|O, "BackgroundImageFileName" , opt_general_background_image_filename , "" ,
-    "Background image file in JPEG or PNG format" },
+    "Background image file in JPEG, PNG or PDF format" },
 
   { F|O, "DefaultFileName" , opt_general_default_filename , "untitled.geo" ,
     "Default project file name" },
@@ -329,12 +329,25 @@ StringXNumber GeneralOptions_Number[] = {
 
   { F|O, "BackgroundGradient" , opt_general_background_gradient , 1. ,
     "Draw background gradient (0=none, 1=vertical, 2=horizontal, 3=radial)" },
-  { F|O, "BackgroundImagePositionX" , opt_general_background_image_position0 , 1.e5 ,
-    "X position (in pixels) of background image (< 0: measure from right edge; "
+  { F|O, "BackgroundImage3D" , opt_general_background_image_3d , 0 ,
+    "Create background image in the 3D model (units = model units) or as "
+    "2D background (units = pixels)" },
+  { F|O, "BackgroundImagePage" , opt_general_background_image_page , 0 ,
+    "Page to render in the background image (for multi-page PDFs)" },
+  { F|O, "BackgroundImagePositionX" , opt_general_background_image_position0 , 0 ,
+    "X position of background image (for 2D background: < 0: measure from right window edge; "
     ">= 1e5: centered)" },
-  { F|O, "BackgroundImagePositionY" , opt_general_background_image_position1 , 1.e5 ,
-    "Y position (in pixels) of background image (< 0: measure from bottom edge; "
+  { F|O, "BackgroundImagePositionY" , opt_general_background_image_position1 , 0 ,
+    "Y position of background image (for 2D background: < 0: measure from bottom window edge; "
     ">= 1e5: centered)" },
+  { F|O, "BackgroundImageWidth" , opt_general_background_image_size0 , -1. ,
+    "Width of background image (0: actual width if height = 0, natural scaling if not; "
+    "-1: graphic window width)" },
+  { F|O, "BackgroundImageHeight" , opt_general_background_image_size1 , -1 ,
+    "Height of background image (0: actual height if width = 0, natural scaling if not; "
+    "-1: graphic window height)" },
+  { F|O, "BoundingBoxSize" , opt_general_lc, 1. ,
+    "Overall bounding box size (read-only)" },
 
   { F|O, "Camera" , opt_general_camera_mode, 0. ,
     "Enable camera view mode" },
@@ -666,10 +679,10 @@ StringXNumber GeneralOptions_Number[] = {
   { F|O, "SmallAxes" , opt_general_small_axes , 1. ,
     "Display the small axes" },
   { F|O, "SmallAxesPositionX" , opt_general_small_axes_position0 , -60. ,
-    "X position (in pixels) of small axes (< 0: measure from right edge; >= 1e5:"
+    "X position (in pixels) of small axes (< 0: measure from right window edge; >= 1e5:"
     " centered)" },
   { F|O, "SmallAxesPositionY" , opt_general_small_axes_position1 , -40. ,
-    "Y position (in pixels) of small axes (< 0: measure from bottom edge; >= 1e5:"
+    "Y position (in pixels) of small axes (< 0: measure from bottom window edge; >= 1e5:"
     " centered)" },
   { F|O, "SmallAxesSize" , opt_general_small_axes_size , 30. ,
     "Size (in pixels) of small axes" },
@@ -726,12 +739,14 @@ StringXNumber GeneralOptions_Number[] = {
 
 StringXNumber GeometryOptions_Number[] = {
   { F|O, "AutoCoherence" , opt_geometry_auto_coherence , 1. ,
-    "Should all duplicate entities be automatically removed?" },
+    "Should all duplicate entities be automatically removed? (if ==2, also remove degenerate entities)" },
 
   { F,   "Clip" , opt_geometry_clip , 0.,
     "Enable clipping planes? (Plane[i]=2^i, i=0,...,5)" },
   { F|O, "CopyMeshingMethod" , opt_geometry_copy_meshing_method, 0. ,
     "Copy meshing method (unstructured or transfinite) when duplicating geometrical entities?" },
+  { F|O, "CopyDisplayAttributes" , opt_geometry_copy_display_attributes, 0. ,
+    "Copy display attributes (visibiliy, color) when duplicating geometrical entities?" },
 
   { F|O, "ExactExtrusion" , opt_geometry_exact_extrusion, 1. ,
     "Use exact extrusion formula in interpolations (set to 0 to allow "
@@ -1024,9 +1039,6 @@ StringXNumber MeshOptions_Number[] = {
     "Version of the MSH file format to use" },
   { F|O, "MshFilePartitioned" , opt_mesh_msh_file_partitioned , 0. ,
     "Split MSH file by mesh partition (0: no, 1: yes, 2: create physicals by partition)" },
-  { F|O, "MultiplePassesMeshes" , opt_mesh_multiple_passes , 0. ,
-    "Do a first simple mesh and use it for complex background meshes (curvatures...)" },
-
   { F|O, "PartitionHexWeight"     , opt_mesh_partition_hex_weight , 1 ,
     "Weight of hexahedral element for METIS load balancing" },
   { F|O, "PartitionPrismWeight"   , opt_mesh_partition_pri_weight , 1 ,
@@ -1201,11 +1213,12 @@ StringXNumber SolverOptions_Number[] = {
   { F|O, "AutoSaveDatabase" , opt_solver_auto_save_database , 0. ,
     "Automatically save database after each computation" },
   { F|O, "AutoMesh" , opt_solver_auto_mesh , 1. ,
-    "Automatically mesh if necesssary" },
+    "Automatically mesh if necesssary (0: never remesh; 1: on startup, use existing "
+    "mesh on disk if available; 2: always remesh)" },
   { F|O, "AutoMergeFile" , opt_solver_auto_merge_file , 1. ,
     "Automatically merge result files" },
-  { F|O, "AutoHideNewViews" , opt_solver_auto_hide_new_views , 0. ,
-    "Automcatically hide newly merged results" },
+  { F|O, "AutoShowViews" , opt_solver_auto_show_views , 2. ,
+    "Automcatically show newly merged results (0: none; 1: all; 2: last one)" },
   { F|O, "AutoShowLastStep" , opt_solver_auto_show_last_step , 1. ,
     "Automatically show the last time step in newly merged results" },
 
@@ -1544,11 +1557,20 @@ StringXNumber PrintOptions_Number[] = {
     "Number of steps in loop over print parameter" },
 
   { F|O, "Background" , opt_print_background , 0. ,
-    "Print background?" },
+    "Print background (gradient and image)?" },
 
   { F|O, "CompositeWindows" , opt_print_composite_windows , 0. ,
     "Composite all window tiles in the same output image (for bitmap output only)" },
 
+  { F|O, "PgfTwoDim" , opt_print_pgf_two_dim , 1. ,
+    "Output PGF format for two dimensions. Mostly irrelevant if `PgfExportAxis=0`. Default `1` (yes)." },
+
+  { F|O, "PgfExportAxis" , opt_print_pgf_export_axis , 0. ,
+    "Include axis in export pgf code (not in the png). Default `0` (no)." },
+
+  { F|O, "PgfHorizontalBar" , opt_print_pgf_horiz_bar , 0. ,
+    "Use a horizontal color bar in the pgf output. Default `0` (no)." },
+
   { F|O, "DeleteTemporaryFiles" , opt_print_delete_tmp_files , 1. ,
     "Delete temporary files used during printing" },
 
diff --git a/Common/Gmsh.cpp b/Common/Gmsh.cpp
index 7bfa425..3d24486 100644
--- a/Common/Gmsh.cpp
+++ b/Common/Gmsh.cpp
@@ -14,6 +14,9 @@
 #include "OpenFile.h"
 #include "CreateFile.h"
 #include "Options.h"
+#if defined(HAVE_PARSER)
+#include "Parser.h"
+#endif
 #include "CommandLine.h"
 #include "OS.h"
 #include "Context.h"
@@ -139,12 +142,25 @@ int GmshGetOption(const std::string &category, const std::string &name,
   return ColorOption(GMSH_GET, category.c_str(), index, name.c_str(), value);
 }
 
+int GmshRestoreDefaultOptions()
+{
+  ReInitOptions(0);
+  InitOptionsGUI(0);
+  return 1;
+}
+
 int GmshOpenProject(const std::string &fileName)
 {
   OpenProject(fileName);
   return 1;
 }
 
+int GmshClearProject()
+{
+  ClearProject();
+  return 1;
+}
+
 int GmshMergeFile(const std::string &fileName)
 {
   return MergeFile(fileName, true);
@@ -152,8 +168,8 @@ int GmshMergeFile(const std::string &fileName)
 
 int GmshMergePostProcessingFile(const std::string &fileName)
 {
-  return MergePostProcessingFile(fileName, CTX::instance()->solver.autoShowLastStep,
-                                 CTX::instance()->solver.autoHideNewViews, true);
+  return MergePostProcessingFile(fileName, CTX::instance()->solver.autoShowViews,
+                                 CTX::instance()->solver.autoShowLastStep, true);
 }
 
 int GmshWriteFile(const std::string &fileName)
@@ -193,7 +209,7 @@ int GmshBatch()
 
 #if defined(HAVE_POST) && defined(HAVE_MESH)
   if(!CTX::instance()->bgmFileName.empty()) {
-    MergeFile(CTX::instance()->bgmFileName);
+    MergePostProcessingFile(CTX::instance()->bgmFileName);
     if(PView::list.size())
       GModel::current()->getFields()->setBackgroundMesh(PView::list.size() - 1);
     else
@@ -206,6 +222,12 @@ int GmshBatch()
   }
   else if(CTX::instance()->batch == -2){
     GModel::current()->checkMeshCoherence(CTX::instance()->geom.tolerance);
+#if defined(HAVE_PARSER)
+    std::vector<std::string> s;
+    PrintParserSymbols(0, s);
+    for(unsigned int i = 0; i < s.size(); i++)
+      Msg::Direct("%s", s[i].c_str());
+#endif
   }
   else if(CTX::instance()->batch == -1){
     CreateOutputFile(CTX::instance()->outputFileName,
@@ -305,7 +327,7 @@ int GmshFLTK(int argc, char **argv)
 
   // read background mesh if any
   if(!CTX::instance()->bgmFileName.empty()) {
-    MergeFile(CTX::instance()->bgmFileName);
+    MergePostProcessingFile(CTX::instance()->bgmFileName);
     if(PView::list.size())
       GModel::current()->getFields()->setBackgroundMesh(PView::list.size() - 1);
     else
diff --git a/Common/Gmsh.h b/Common/Gmsh.h
index 8d5e21e..e6245c4 100644
--- a/Common/Gmsh.h
+++ b/Common/Gmsh.h
@@ -27,7 +27,9 @@ int GmshGetOption(const std::string &category, const std::string &name,
                   double &value, int index=0);
 int GmshGetOption(const std::string &category, const std::string &name,
                   unsigned int &value, int index=0);
+int GmshRestoreDefaultOptions();
 int GmshOpenProject(const std::string &fileName);
+int GmshClearProject();
 int GmshMergeFile(const std::string &fileName);
 int GmshMergePostProcessingFile(const std::string &fileName);
 int GmshWriteFile(const std::string &fileName);
diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in
index 5695622..b6e2c4b 100644
--- a/Common/GmshConfig.h.in
+++ b/Common/GmshConfig.h.in
@@ -16,6 +16,7 @@
 #cmakedefine HAVE_BLOSSOM
 #cmakedefine HAVE_CAIRO
 #cmakedefine HAVE_CHACO
+#cmakedefine HAVE_COMPRESSED_IO
 #cmakedefine HAVE_DLOPEN
 #cmakedefine HAVE_DINTEGRATION
 #cmakedefine HAVE_FLTK
@@ -46,6 +47,7 @@
 #cmakedefine HAVE_NO_VSNPRINTF
 #cmakedefine HAVE_OCC
 #cmakedefine HAVE_ONELAB
+#cmakedefine HAVE_ONELAB2
 #cmakedefine HAVE_ONELAB_METAMODEL
 #cmakedefine HAVE_OPENGL
 #cmakedefine HAVE_OPTHOM
diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h
index 9742f84..a4e360d 100644
--- a/Common/GmshDefines.h
+++ b/Common/GmshDefines.h
@@ -50,6 +50,7 @@
 #define FORMAT_CELUM 41
 #define FORMAT_SU2   42
 #define FORMAT_MPEG_PREVIEW 43
+#define FORMAT_PGF   44
 
 // Element types
 #define TYPE_PNT     1
@@ -209,8 +210,9 @@
 #define MSH_TRI_SUB 135
 #define MSH_TET_SUB 136
 #define MSH_TET_16  137
+#define MSH_TRI_MINI 138
 
-#define MSH_NUM_TYPE 137
+#define MSH_NUM_TYPE 138
 
 // Geometric entities
 #define ENT_NONE     0
diff --git a/Common/GmshIO.h b/Common/GmshIO.h
new file mode 100644
index 0000000..b15795c
--- /dev/null
+++ b/Common/GmshIO.h
@@ -0,0 +1,45 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+//
+// Contribued by Alexis Salzman
+
+#ifndef _GMSH_IO_H_
+#define _GMSH_IO_H_
+
+#include <stdio.h>
+#include "GmshConfig.h"
+
+#if defined(HAVE_COMPRESSED_IO) && defined(HAVE_LIBZ)
+
+#include <zlib.h>
+typedef gzFile gmshFILE;
+typedef z_off_t gmshfpos_t;
+#define gmshopen gzopen
+#define gmshgets(a,b,c) gzgets((c),(a),(b))
+#define gmshclose gzclose
+#define gmsheof gzeof
+#define gmshgetc gzgetc
+#define gmshprintf gzprintf
+#define gmsherror(a){ int ernum; char *gzerror(a,&ernum); return ernum; }
+#define gmshsetpos(a, b){ return gzseek(a,*b,SEEK_SET); }
+#define gmshgetpos(a, b){ *b=gztell(a); return 0; }
+
+#else
+
+typedef FILE *gmshFILE;
+typedef fpos_t gmshfpos_t;
+#define gmshopen Fopen
+#define gmshgets fgets
+#define gmshclose fclose
+#define gmsheof feof
+#define gmshgetc getc
+#define gmshprintf fprintf
+#define gmsherror ferror
+#define gmshsetpos fsetpos
+#define gmshgetpos fgetpos
+
+#endif
+
+#endif
diff --git a/Common/GmshMessage.cpp b/Common/GmshMessage.cpp
index 03b718b..3b96500 100644
--- a/Common/GmshMessage.cpp
+++ b/Common/GmshMessage.cpp
@@ -3,13 +3,18 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
+#include "GmshConfig.h"
+
+#if defined(HAVE_MPI)
+#include <mpi.h>
+#endif
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <math.h>
 #include <string.h>
 #include <time.h>
 #include <sys/stat.h>
-#include "GmshConfig.h"
 #include "GmshMessage.h"
 #include "GmshSocket.h"
 #include "Gmsh.h"
@@ -24,10 +29,6 @@
 #include "onelab.h"
 #endif
 
-#if defined(HAVE_MPI)
-#include <mpi.h>
-#endif
-
 #if defined(HAVE_PETSC)
 #include <petsc.h>
 #endif
@@ -61,6 +62,7 @@ std::string Msg::_execName;
 onelab::client *Msg::_onelabClient = 0;
 onelab::server *onelab::server::_server = 0;
 #endif
+std::string Msg::_gmshOnelabAction = "";
 
 #if defined(HAVE_NO_VSNPRINTF)
 static int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
@@ -321,7 +323,7 @@ void Msg::Warning(const char *fmt, ...)
 {
   _warningCount++;
 
-  if(_commRank || _verbosity < 2) return;
+  if(_verbosity < 2) return;
 
   char str[5000];
   va_list args;
@@ -347,14 +349,17 @@ void Msg::Warning(const char *fmt, ...)
     if(!streamIsFile(stderr) && streamIsVT100(stderr)){
       c0 = "\33[35m"; c1 = "\33[0m";  // magenta
     }
-    fprintf(stderr, "%sWarning : %s%s\n", c0, str, c1);
+    if(_commSize > 1)
+      fprintf(stderr, "%sWarning : [rank %3d] %s%s\n", c0, _commRank, str, c1);
+    else
+      fprintf(stderr, "%sWarning : %s%s\n", c0, str, c1);
     fflush(stderr);
   }
 }
 
 void Msg::Info(const char *fmt, ...)
 {
-  if(_commRank || _verbosity < 4) return;
+  if(_verbosity < 4) return;
 
   char str[5000];
   va_list args;
@@ -379,7 +384,10 @@ void Msg::Info(const char *fmt, ...)
 #endif
 
   if(CTX::instance()->terminal){
-    fprintf(stdout, "Info    : %s\n", str);
+    if(_commSize > 1)
+      fprintf(stdout, "Info    : [rank %3d] %s\n", _commRank, str);
+    else
+      fprintf(stdout, "Info    : %s\n", str);
     fflush(stdout);
   }
 }
@@ -390,7 +398,7 @@ void Msg::RequestRender()
 
 void Msg::Direct(const char *fmt, ...)
 {
-  if(_commRank || _verbosity < 3) return;
+  if(_verbosity < 3) return;
 
   char str[5000];
   va_list args;
@@ -419,14 +427,17 @@ void Msg::Direct(const char *fmt, ...)
     if(!streamIsFile(stdout) && streamIsVT100(stdout)){
       c0 = "\33[34m"; c1 = "\33[0m";  // blue
     }
-    fprintf(stdout, "%s%s%s\n", c0, str, c1);
+    if(_commSize > 1)
+      fprintf(stdout, "%s[rank %3d] %s%s\n", c0, _commRank, str, c1);
+    else
+      fprintf(stdout, "%s%s%s\n", c0, str, c1);
     fflush(stdout);
   }
 }
 
 void Msg::StatusBar(bool log, const char *fmt, ...)
 {
-  if(_commRank || _verbosity < 4) return;
+  if(_verbosity < 4) return;
 
   char str[5000];
   va_list args;
@@ -455,7 +466,10 @@ void Msg::StatusBar(bool log, const char *fmt, ...)
 #endif
 
   if(log && CTX::instance()->terminal){
-    fprintf(stdout, "Info    : %s\n", str);
+    if(_commSize > 1)
+      fprintf(stdout, "Info    : [rank %3d] %s\n", _commRank, str);
+    else
+      fprintf(stdout, "Info    : %s\n", str);
     fflush(stdout);
   }
 }
@@ -737,8 +751,8 @@ public:
   void sendMergeFileRequest(const std::string &name)
   {
     if(name.find(".geo") != std::string::npos){
-      MergePostProcessingFile(name, CTX::instance()->solver.autoShowLastStep,
-			      CTX::instance()->solver.autoHideNewViews, true);
+      MergePostProcessingFile(name, CTX::instance()->solver.autoShowViews,
+                              CTX::instance()->solver.autoShowLastStep, true);
       GModel::current()->setFileName(name);
     }
     else if((name.find(".opt") != std::string::npos)){
@@ -748,8 +762,8 @@ public:
       MergeFile(name);
     }
     else
-      MergePostProcessingFile(name, CTX::instance()->solver.autoShowLastStep,
-			      CTX::instance()->solver.autoHideNewViews, true);
+      MergePostProcessingFile(name, CTX::instance()->solver.autoShowViews,
+                              CTX::instance()->solver.autoShowLastStep, true);
   }
   void sendInfo(const std::string &msg){ Msg::Info("%s", msg.c_str()); }
   void sendWarning(const std::string &msg){ Msg::Warning("%s", msg.c_str()); }
@@ -786,7 +800,7 @@ void Msg::InitializeOnelab(const std::string &name, const std::string &sockname)
     std::vector<onelab::string> ps;
     _onelabClient->get(ps, name + "/Action");
     if(ps.size()){
-      //Info("Performing OneLab '%s'", ps[0].getValue().c_str());
+      //Info("Performing ONELAB '%s'", ps[0].getValue().c_str());
       if(ps[0].getValue() == "initialize") Exit(0);
     }
   }
@@ -887,7 +901,7 @@ void Msg::ExchangeOnelabParameter(const std::string &key,
   if(name.empty()){
     if(copt.size() || fopt.size())
       Msg::Error("From now on you need to use the `Name' attribute to create a "
-                 "OneLab parameter: `Name \"%s\"'",
+                 "ONELAB parameter: `Name \"%s\"'",
                  _getParameterName(key, copt).c_str());
     return;
   }
@@ -992,7 +1006,7 @@ void Msg::ExchangeOnelabParameter(const std::string &key,
   if(name.empty()){
     if(copt.size() || fopt.size())
       Msg::Error("From now on you need to use the `Name' attribute to create a "
-                 "OneLab parameter: `Name \"%s\"'",
+                 "ONELAB parameter: `Name \"%s\"'",
                  _getParameterName(key, copt).c_str());
     return;
   }
diff --git a/Common/GmshMessage.h b/Common/GmshMessage.h
index 79f47ab..2345fee 100644
--- a/Common/GmshMessage.h
+++ b/Common/GmshMessage.h
@@ -45,6 +45,8 @@ class Msg {
   static GmshClient *_client;
   // communication with onelab server
   static onelab::client *_onelabClient;
+  // internal onelab status for Gmsh parser
+  static std::string _gmshOnelabAction;
   // executable name
   static std::string _execName;
  public:
@@ -100,6 +102,8 @@ class Msg {
   static bool UseOnelab();
   static void SetOnelabNumber(std::string name, double val, bool visible);
   static void SetOnelabString(std::string name, std::string val, bool visible);
+  static void SetGmshOnelabAction(std::string action){ _gmshOnelabAction = action; }
+  static std::string GetGmshOnelabAction(){ return _gmshOnelabAction; }
   static void ExchangeOnelabParameter(const std::string &key,
                                       std::vector<double> &val,
                                       std::map<std::string, std::vector<double> > &fopt,
diff --git a/Common/GmshRemote.cpp b/Common/GmshRemote.cpp
index 4c701d4..83b1245 100644
--- a/Common/GmshRemote.cpp
+++ b/Common/GmshRemote.cpp
@@ -3,8 +3,20 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
-#include <sstream>
 #include "GmshConfig.h"
+
+#if defined(HAVE_MPI)
+#include <mpi.h>
+#define MPI_GMSH_COMPUTE_VIEW  1
+#define MPI_GMSH_DATA_READY    2
+#define MPI_GMSH_VARRAY        3
+#define MPI_GMSH_VARRAY_LEN    4
+#define MPI_GMSH_SHUTDOWN      5
+#define MPI_GMSH_PARSE_STRING  6
+#define MPI_GMSH_MERGE_FILE    7
+#endif
+
+#include <sstream>
 #include "GmshMessage.h"
 
 #if defined(HAVE_ONELAB) && defined(HAVE_POST)
@@ -19,17 +31,6 @@
 #include "PViewData.h"
 #include "PViewDataRemote.h"
 
-#if defined(HAVE_MPI)
-#include <mpi.h>
-#define MPI_GMSH_COMPUTE_VIEW  1
-#define MPI_GMSH_DATA_READY    2
-#define MPI_GMSH_VARRAY        3
-#define MPI_GMSH_VARRAY_LEN    4
-#define MPI_GMSH_SHUTDOWN      5
-#define MPI_GMSH_PARSE_STRING  6
-#define MPI_GMSH_MERGE_FILE    7
-#endif
-
 static void computeAndSendVertexArrays(GmshClient *client, bool compute=true)
 {
   for(unsigned int i = 0; i < PView::list.size(); i++){
@@ -294,7 +295,7 @@ int GmshRemote()
 
 int GmshRemote()
 {
-  Msg::Error("GmshRemote requires Post and OneLab modules");
+  Msg::Error("GmshRemote requires Post and ONELAB modules");
   return 0;
 }
 
diff --git a/Common/GmshSocket.h b/Common/GmshSocket.h
index 158f9e6..467a936 100644
--- a/Common/GmshSocket.h
+++ b/Common/GmshSocket.h
@@ -85,6 +85,8 @@ class GmshSocket{
     GMSH_SPEED_TEST          = 30,
     GMSH_PARAMETER_CLEAR     = 31,
     GMSH_PARAMETER_UPDATE    = 32,
+    GMSH_OPEN_PROJECT        = 33,
+    GMSH_CLIENT_CHANGED      = 34,
     GMSH_OPTION_1            = 100,
     GMSH_OPTION_2            = 101,
     GMSH_OPTION_3            = 102,
@@ -193,6 +195,7 @@ class GmshSocket{
   void Error(const char *str){ SendString(GMSH_ERROR, str); }
   void Progress(const char *str){ SendString(GMSH_PROGRESS, str); }
   void MergeFile(const char *str){ SendString(GMSH_MERGE_FILE, str); }
+  void OpenProject(const char *str){ SendString(GMSH_OPEN_PROJECT, str); }
   void ParseString(const char *str){ SendString(GMSH_PARSE_STRING, str); }
   void SpeedTest(const char *str){ SendString(GMSH_SPEED_TEST, str); }
   void Option(int num, const char *str)
diff --git a/Common/OS.cpp b/Common/OS.cpp
index 3b0f4bb..808b26b 100644
--- a/Common/OS.cpp
+++ b/Common/OS.cpp
@@ -21,7 +21,7 @@
 #include <sys/sysctl.h>
 #endif
 
-#if defined(__linux__)
+#if defined(__linux__) && !defined(BUILD_ANDROID)
 #include <sys/sysinfo.h>
 #endif
 
@@ -284,6 +284,8 @@ double TotalRam()
   status.dwLength = sizeof(status);
   GlobalMemoryStatusEx(&status);
   ram = status.ullTotalPhys  / ((double)1024 * 1024);
+#elif defined(BUILD_ANDROID)
+  ram = 1024;
 #elif defined(__linux__)
   struct sysinfo infos;
   if(sysinfo(&infos) != -1)
@@ -339,7 +341,7 @@ int StatFile(const std::string &fileName)
   return ret;
 }
 
-int CreateDirectory(const std::string &dirName)
+int CreateSingleDir(const std::string &dirName)
 {
 #if defined(WIN32) && !defined(__CYGWIN__)
   setwbuf(0, dirName.c_str());
@@ -358,7 +360,7 @@ void CreatePath(const std::string &fullPath)
   size_t cur = 0;
   while(cur != std::string::npos) {
     cur = dirname.find("/", cur + 1);
-    CreateDirectory(dirname.substr(0, cur));
+    CreateSingleDir(dirname.substr(0, cur));
   }
 }
 
diff --git a/Common/OS.h b/Common/OS.h
index 6c9fc46..685005b 100644
--- a/Common/OS.h
+++ b/Common/OS.h
@@ -22,7 +22,7 @@ std::string GetHostName();
 int UnlinkFile(const std::string &fileName);
 int StatFile(const std::string &fileName);
 int KillProcess(int pid);
-int CreateDirectory(const std::string &dirName);
+int CreateSingleDir(const std::string &dirName);
 void CreatePath(const std::string &fullPath);
 int SystemCall(const std::string &command, bool blocking=false);
 std::string GetCurrentWorkdir();
diff --git a/Common/OctreeInternals.cpp b/Common/OctreeInternals.cpp
index c84ab17..c678799 100644
--- a/Common/OctreeInternals.cpp
+++ b/Common/OctreeInternals.cpp
@@ -391,7 +391,7 @@ void *searchAllElements(octantBucket *_buckets_head, double *_pt, globalInfo *_g
 
   ptrBucket = findElementBucket(_buckets_head, _pt);
   if (ptrBucket == NULL) {
-    Msg::Error("The point is not in the domain");
+    Msg::Debug("The point is not in the domain");
     return NULL;
   }
 
diff --git a/Common/OpenFile.cpp b/Common/OpenFile.cpp
index 4e6a10c..0da2124 100644
--- a/Common/OpenFile.cpp
+++ b/Common/OpenFile.cpp
@@ -7,6 +7,7 @@
 #include <string.h>
 #include "GmshConfig.h"
 #include "GmshMessage.h"
+#include "GmshIO.h"
 #include "Options.h"
 #include "Geo.h"
 #include "GModel.h"
@@ -85,6 +86,12 @@ static void FinishUpBoundingBox()
     double l = sqrt(SQU(range[0]) + SQU(range[2]));
     CTX::instance()->min[1] -= l; CTX::instance()->max[1] += l;
   }
+
+  CTX::instance()->lc = sqrt(SQU(CTX::instance()->max[0] - CTX::instance()->min[0]) +
+                             SQU(CTX::instance()->max[1] - CTX::instance()->min[1]) +
+                             SQU(CTX::instance()->max[2] - CTX::instance()->min[2]));
+  for(int i = 0; i < 3; i++)
+    CTX::instance()->cg[i] = 0.5 * (CTX::instance()->min[i] + CTX::instance()->max[i]);
 }
 
 void SetBoundingBox(double xmin, double xmax,
@@ -95,12 +102,6 @@ void SetBoundingBox(double xmin, double xmax,
   CTX::instance()->min[1] = ymin; CTX::instance()->max[1] = ymax;
   CTX::instance()->min[2] = zmin; CTX::instance()->max[2] = zmax;
   FinishUpBoundingBox();
-  CTX::instance()->lc = sqrt(SQU(CTX::instance()->max[0] - CTX::instance()->min[0]) +
-                             SQU(CTX::instance()->max[1] - CTX::instance()->min[1]) +
-                             SQU(CTX::instance()->max[2] - CTX::instance()->min[2]));
-  for(int i = 0; i < 3; i++)
-    CTX::instance()->cg[i] = 0.5 * (CTX::instance()->min[i] + CTX::instance()->max[i]);
-
 }
 
 void SetBoundingBox(bool aroundVisible)
@@ -126,12 +127,6 @@ void SetBoundingBox(bool aroundVisible)
   CTX::instance()->min[1] = bb.min().y(); CTX::instance()->max[1] = bb.max().y();
   CTX::instance()->min[2] = bb.min().z(); CTX::instance()->max[2] = bb.max().z();
   FinishUpBoundingBox();
-  CTX::instance()->lc = sqrt(SQU(CTX::instance()->max[0] - CTX::instance()->min[0]) +
-                             SQU(CTX::instance()->max[1] - CTX::instance()->min[1]) +
-                             SQU(CTX::instance()->max[2] - CTX::instance()->min[2]));
-  for(int i = 0; i < 3; i++)
-    CTX::instance()->cg[i] = 0.5 * (CTX::instance()->min[i] + CTX::instance()->max[i]);
-
 }
 
 // FIXME: this is necessary for now to have an approximate CTX::instance()->lc
@@ -173,7 +168,7 @@ static void ComputeMaxEntityNum()
              GModel::current()->getMaxElementaryNumber(3));
 }
 
-static std::vector<FILE*> openedFiles;
+static std::vector<gmshFILE> openedFiles;
 
 int ParseFile(const std::string &fileName, bool close, bool warnIfMissing)
 {
@@ -184,8 +179,8 @@ int ParseFile(const std::string &fileName, bool close, bool warnIfMissing)
 
   // add 'b' for pure Windows programs: opening in text mode messes up
   // fsetpos/fgetpos (used e.g. for user-defined functions)
-  FILE *fp;
-  if(!(fp = Fopen(fileName.c_str(), "rb"))){
+  gmshFILE fp;
+  if(!(fp = gmshopen(fileName.c_str(), "rb"))){
     if(warnIfMissing)
       Msg::Warning("Unable to open file '%s'", fileName.c_str());
     return 0;
@@ -196,7 +191,7 @@ int ParseFile(const std::string &fileName, bool close, bool warnIfMissing)
 #endif
 
   std::string old_yyname = gmsh_yyname;
-  FILE *old_yyin = gmsh_yyin;
+  gmshFILE old_yyin = gmsh_yyin;
   int old_yyerrorstate = gmsh_yyerrorstate;
   int old_yylineno = gmsh_yylineno;
   int old_yyviewindex = gmsh_yyviewindex;
@@ -207,7 +202,7 @@ int ParseFile(const std::string &fileName, bool close, bool warnIfMissing)
   gmsh_yylineno = 1;
   gmsh_yyviewindex = 0;
 
-  while(!feof(gmsh_yyin)){
+  while(!gmsheof(gmsh_yyin)){
     gmsh_yyparse();
     if(gmsh_yyerrorstate > 20){
       if(gmsh_yyerrorstate != 999) // 999 is a volontary exit
@@ -219,7 +214,7 @@ int ParseFile(const std::string &fileName, bool close, bool warnIfMissing)
 
   if(close){
     gmsh_yyflush();
-    fclose(gmsh_yyin);
+    gmshclose(gmsh_yyin);
   }
   else{
     openedFiles.push_back(gmsh_yyin);
@@ -240,6 +235,21 @@ int ParseFile(const std::string &fileName, bool close, bool warnIfMissing)
 #endif
 }
 
+static bool doSystemUncompress(std::string fileName, std::string noExt)
+{
+  std::ostringstream sstream;
+  sstream << "File '"<< fileName << "' is in gzip format.\n\n"
+          << "Do you want to uncompress it?";
+  if(Msg::GetAnswer(sstream.str().c_str(), 0, "Cancel", "Uncompress")){
+    if(SystemCall(std::string("gunzip -c ") + fileName + " > " + noExt, true))
+      Msg::Warning("Potentially failed to uncompress `%s': check directory permissions",
+                   fileName.c_str());
+    GModel::current()->setFileName(noExt);
+    return true;
+  }
+  return false;
+}
+
 void ParseString(const std::string &str)
 {
   if(str.empty()) return;
@@ -262,7 +272,8 @@ static int defineSolver(const std::string &name)
   return NUM_SOLVERS - 1;
 }
 
-int MergeFile(const std::string &fileName, bool warnIfMissing, bool setWindowTitle)
+int MergeFile(const std::string &fileName, bool warnIfMissing, bool setWindowTitle,
+              bool setBoundingBox)
 {
   if(GModel::current()->getName() == ""){
     GModel::current()->setFileName(fileName);
@@ -276,7 +287,7 @@ int MergeFile(const std::string &fileName, bool warnIfMissing, bool setWindowTit
 
   // added 'b' for pure Windows programs, since some of these files
   // contain binary data
-  FILE *fp = Fopen(fileName.c_str(), "rb");
+  gmshFILE fp = gmshopen(fileName.c_str(), "rb");
   if(!fp){
     if(warnIfMissing)
       Msg::Warning("Unable to open file '%s'", fileName.c_str());
@@ -284,8 +295,8 @@ int MergeFile(const std::string &fileName, bool warnIfMissing, bool setWindowTit
   }
 
   char header[256];
-  if(!fgets(header, sizeof(header), fp)){ fclose(fp); return 0; }
-  fclose(fp);
+  if(!gmshgets(header, sizeof(header), fp)){ gmshclose(fp); return 0; }
+  gmshclose(fp);
 
   Msg::StatusBar(true, "Reading '%s'...", fileName.c_str());
 
@@ -293,18 +304,18 @@ int MergeFile(const std::string &fileName, bool warnIfMissing, bool setWindowTit
   std::string noExt = split[0] + split[1], ext = split[2];
 
   if(ext == ".gz") {
-    // the real solution would be to rewrite all our I/O functions in
-    // terms of gzFile, but until then, this is better than nothing
-    std::ostringstream sstream;
-    sstream << "File '"<< fileName << "' is in gzip format.\n\n"
-            << "Do you want to uncompress it?";
-    if(Msg::GetAnswer(sstream.str().c_str(), 0, "Cancel", "Uncompress")){
-      if(SystemCall(std::string("gunzip -c ") + fileName + " > " + noExt, true))
-        Msg::Error("Failed to uncompress `%s': check directory permissions",
-                   fileName.c_str());
-      GModel::current()->setFileName(noExt);
-      return MergeFile(noExt, false, setWindowTitle);
+#if defined(HAVE_COMPRESSED_IO) && defined(HAVE_LIBZ)
+    std::vector<std::string> subsplit = SplitFileName(noExt);
+    ext = subsplit[2];
+    if(ext != ".geo" && ext != ".GEO" &&
+       ext != ".unv" && ext != ".UNV"){
+      if(doSystemUncompress(fileName, noExt))
+        return MergeFile(noExt, false, setWindowTitle);
     }
+#else
+    if(doSystemUncompress(fileName, noExt))
+      return MergeFile(noExt, false, setWindowTitle);
+#endif
   }
 
   // force reading msh file even if wrong extension if the header
@@ -349,14 +360,6 @@ int MergeFile(const std::string &fileName, bool warnIfMissing, bool setWindowTit
   else if(ext == ".diff" || ext == ".DIFF"){
     status = GModel::current()->readDIFF(fileName);
   }
-  else if(ext == ".pdf" || ext == ".PDF"){
-#if defined(HAVE_POPPLER)
-    status = gmshPopplerWrapper::instance()->load_from_file(fileName);
-#else
-    Msg::Error("Gmsh has to be compiled with POPPLER for displaying PDF documents");
-    status = 0;
-#endif
-  }
   else if(ext == ".med" || ext == ".MED" || ext == ".mmed" || ext == ".MMED" ||
           ext == ".rmed" || ext == ".RMED"){
     status = GModel::readMED(fileName);
@@ -433,12 +436,6 @@ int MergeFile(const std::string &fileName, bool warnIfMissing, bool setWindowTit
     return 1;
   }
 #endif
-#if defined(HAVE_ONELAB_METAMODEL) && defined(HAVE_FLTK)
-  else if(ext == ".ol"){
-    // FIXME: this is a hack -- think about a better way
-    status = metamodel_cb(fileName);
-  }
-#endif
   else {
     CTX::instance()->geom.draw = 1;
     if(!strncmp(header, "$PTS", 4) || !strncmp(header, "$NO", 3) ||
@@ -478,7 +475,7 @@ int MergeFile(const std::string &fileName, bool warnIfMissing, bool setWindowTit
   }
 
   ComputeMaxEntityNum();
-  SetBoundingBox();
+  if(setBoundingBox) SetBoundingBox();
   CTX::instance()->geom.draw = 1;
   CTX::instance()->mesh.changed = ENT_ALL;
 
@@ -507,8 +504,8 @@ int MergeFile(const std::string &fileName, bool warnIfMissing, bool setWindowTit
   return status;
 }
 
-int MergePostProcessingFile(const std::string &fileName, bool showLastStep,
-                            bool hideNewViews, bool warnIfMissing)
+int MergePostProcessingFile(const std::string &fileName, int showViews,
+                            bool showLastStep, bool warnIfMissing)
 {
 #if defined(HAVE_POST)
   // check if there is a mesh in the file
@@ -550,22 +547,23 @@ int MergePostProcessingFile(const std::string &fileName, bool showLastStep,
     GModel *m = new GModel();
     GModel::setCurrent(m);
   }
-  int ret = MergeFile(fileName, warnIfMissing);
+  int ret = MergeFile(fileName, warnIfMissing, true,
+                      old->bounds().empty() ? true : false);
   GModel::setCurrent(old);
   old->setVisibility(1);
 
   // hide everything except the onelab X-Y graphs
-  if(hideNewViews){
+  if(showViews == 0){
     for(unsigned int i = 0; i < PView::list.size(); i++){
-      if(PView::list[i]->getData()->getFileName().substr(0, 6) != "OneLab")
+      if(PView::list[i]->getData()->getFileName().substr(0, 6) != "ONELAB")
         PView::list[i]->getOptions()->visible = 0;
     }
   }
-  else if(n < PView::list.size()){
+  else if(showViews == 2 && n < PView::list.size()){
     // if we created new views, assume we only want to see those (and the
     // onelab X-Y graphs)
     for(unsigned int i = 0; i < n; i++){
-      if(PView::list[i]->getData()->getFileName().substr(0, 6) != "OneLab")
+      if(PView::list[i]->getData()->getFileName().substr(0, 6) != "ONELAB")
         PView::list[i]->getOptions()->visible = 0;
     }
   }
@@ -603,7 +601,7 @@ void ClearProject()
   // close the files that might have been left open by ParseFile
   if(openedFiles.size()){
     for(unsigned int i = 0; i < openedFiles.size(); i++)
-      fclose(openedFiles[i]);
+      gmshclose(openedFiles[i]);
     openedFiles.clear();
   }
   Msg::Info("Done clearing all models and views");
@@ -680,7 +678,7 @@ void OpenProject(const std::string &fileName, bool setWindowTitle)
   // close the files that might have been left open by ParseFile
   if(openedFiles.size()){
     for(unsigned int i = 0; i < openedFiles.size(); i++)
-      fclose(openedFiles[i]);
+      gmshclose(openedFiles[i]);
     openedFiles.clear();
   }
 
diff --git a/Common/OpenFile.h b/Common/OpenFile.h
index 2997f0e..0812c73 100644
--- a/Common/OpenFile.h
+++ b/Common/OpenFile.h
@@ -13,9 +13,9 @@ void ParseString(const std::string &str);
 void OpenProject(const std::string &filename, bool setWindowTitle=true);
 void OpenProjectMacFinder(const char *fileName);
 int MergeFile(const std::string &fileName, bool warnIfMissing=false,
-              bool setWindowTitle=true);
-int MergePostProcessingFile(const std::string &fileName, bool showLastStep=false,
-                            bool hideNewViews=false, bool warnIfMissing=false);
+              bool setWindowTitle=true, bool setBoundingBox=true);
+int MergePostProcessingFile(const std::string &fileName, int showViews=2,
+                            bool showLastStep=false, bool warnIfMissing=false);
 void ClearProject();
 void SetBoundingBox(double xmin, double xmax,
                     double ymin, double ymax,
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 3d76466..552de15 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -842,7 +842,9 @@ void PrintOptionsDoc()
       GMSH_Plugin *p = it->second;
       if(p->getType() == GMSH_Plugin::GMSH_POST_PLUGIN) {
         fprintf(file, "@item Plugin(%s)\n", p->getName().c_str());
-        fprintf(file, "%s\n", p->getHelp().c_str());
+        std::string help = p->getHelp();
+        Sanitize_String_Texi(help);
+        fprintf(file, "%s\n", help.c_str());
         int m = p->getNbOptionsStr();
         if(m){
           fprintf(file, "String options:\n");
@@ -1088,8 +1090,17 @@ std::string opt_general_display(OPT_ARGS_STR)
 
 std::string opt_general_background_image_filename(OPT_ARGS_STR)
 {
-  if(action & GMSH_SET)
+  if(action & GMSH_SET){
+#if defined(HAVE_FLTK)
+    if(CTX::instance()->bgImageFileName != val && FlGui::available()){
+      for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++)
+        for(unsigned int j = 0; j < FlGui::instance()->graph[i]->gl.size(); j++)
+          FlGui::instance()->graph[i]->gl[j]->getDrawContext()->
+            invalidateBgImageTexture();
+    }
+#endif
     CTX::instance()->bgImageFileName = val;
+  }
   return CTX::instance()->bgImageFileName;
 }
 
@@ -2794,6 +2805,11 @@ double opt_general_zmax(OPT_ARGS_NUM)
   return bb.empty() ? 0. : bb.max().z();
 }
 
+double opt_general_lc(OPT_ARGS_NUM)
+{
+  return CTX::instance()->lc;
+}
+
 double opt_general_axes(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET){
@@ -3199,7 +3215,7 @@ double opt_general_background_gradient(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET){
     CTX::instance()->bgGradient = (int)val;
-    if(CTX::instance()->bgGradient < 0 || CTX::instance()->bgGradient > 4)
+    if(CTX::instance()->bgGradient < 0 || CTX::instance()->bgGradient > 3)
       CTX::instance()->bgGradient = 0;
   }
 #if defined(HAVE_FLTK)
@@ -3224,6 +3240,34 @@ double opt_general_background_image_position1(OPT_ARGS_NUM)
   return CTX::instance()->bgImagePosition[1];
 }
 
+double opt_general_background_image_size0(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->bgImageSize[0] = val;
+  return CTX::instance()->bgImageSize[0];
+}
+
+double opt_general_background_image_size1(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->bgImageSize[1] = val;
+  return CTX::instance()->bgImageSize[1];
+}
+
+double opt_general_background_image_3d(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->bgImage3d = (int)val;
+  return CTX::instance()->bgImage3d;
+}
+
+double opt_general_background_image_page(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->bgImagePage = (int)val;
+  return CTX::instance()->bgImagePage;
+}
+
 double opt_general_trackball(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
@@ -4397,8 +4441,9 @@ double opt_geometry_occ_fix_small_faces(OPT_ARGS_NUM)
 
 double opt_geometry_occ_sew_faces(OPT_ARGS_NUM)
 {
-  if(action & GMSH_SET)
+  if(action & GMSH_SET){
     CTX::instance()->geom.occSewFaces = val ? 1 : 0;
+  }
 #if defined(HAVE_FLTK)
   if(FlGui::available() && (action & GMSH_GUI)) {
     FlGui::instance()->options->geo.butt[13]->value
@@ -4533,6 +4578,13 @@ double opt_geometry_copy_meshing_method(OPT_ARGS_NUM)
   return CTX::instance()->geom.copyMeshingMethod;
 }
 
+double opt_geometry_copy_display_attributes(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->geom.copyDisplayAttributes = (int)val;
+  return CTX::instance()->geom.copyDisplayAttributes;
+}
+
 double opt_geometry_exact_extrusion(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
@@ -5672,13 +5724,6 @@ double opt_mesh_second_order_experimental(OPT_ARGS_NUM)
   return CTX::instance()->mesh.secondOrderExperimental;
 }
 
-double opt_mesh_multiple_passes(OPT_ARGS_NUM)
-{
-  if(action & GMSH_SET)
-    CTX::instance()->mesh.multiplePasses = (int)val;
-  return CTX::instance()->mesh.multiplePasses;
-}
-
 double opt_mesh_second_order_linear(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
@@ -6173,11 +6218,11 @@ double opt_solver_auto_merge_file(OPT_ARGS_NUM)
   return CTX::instance()->solver.autoMergeFile;
 }
 
-double opt_solver_auto_hide_new_views(OPT_ARGS_NUM)
+double opt_solver_auto_show_views(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
-    CTX::instance()->solver.autoHideNewViews = (int)val;
-  return CTX::instance()->solver.autoHideNewViews;
+    CTX::instance()->solver.autoShowViews = (int)val;
+  return CTX::instance()->solver.autoShowViews;
 }
 
 double opt_solver_auto_show_last_step(OPT_ARGS_NUM)
@@ -8616,6 +8661,25 @@ double opt_print_background(OPT_ARGS_NUM)
   return CTX::instance()->print.background;
 }
 
+double opt_print_pgf_two_dim(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->print.pgfTwoDim= (int)val;
+  return CTX::instance()->print.pgfTwoDim;
+}
+double opt_print_pgf_export_axis(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->print.pgfExportAxis= (int)val;
+  return CTX::instance()->print.pgfExportAxis;
+}
+double opt_print_pgf_horiz_bar(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->print.pgfHorizBar = (int)val;
+  return CTX::instance()->print.pgfHorizBar;
+}
+
 double opt_print_text(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
diff --git a/Common/Options.h b/Common/Options.h
index 6bbb799..5712018 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -187,6 +187,10 @@ double opt_general_color_scheme(OPT_ARGS_NUM);
 double opt_general_background_gradient(OPT_ARGS_NUM);
 double opt_general_background_image_position0(OPT_ARGS_NUM);
 double opt_general_background_image_position1(OPT_ARGS_NUM);
+double opt_general_background_image_size0(OPT_ARGS_NUM);
+double opt_general_background_image_size1(OPT_ARGS_NUM);
+double opt_general_background_image_3d(OPT_ARGS_NUM);
+double opt_general_background_image_page(OPT_ARGS_NUM);
 double opt_general_verbosity(OPT_ARGS_NUM);
 double opt_general_progress_meter_step(OPT_ARGS_NUM);
 double opt_general_nopopup(OPT_ARGS_NUM);
@@ -206,6 +210,7 @@ double opt_general_ymin(OPT_ARGS_NUM);
 double opt_general_ymax(OPT_ARGS_NUM);
 double opt_general_zmin(OPT_ARGS_NUM);
 double opt_general_zmax(OPT_ARGS_NUM);
+double opt_general_lc(OPT_ARGS_NUM);
 double opt_general_axes(OPT_ARGS_NUM);
 double opt_general_axes_mikado(OPT_ARGS_NUM);
 double opt_general_axes_auto_position(OPT_ARGS_NUM);
@@ -360,6 +365,7 @@ double opt_geometry_snap1(OPT_ARGS_NUM);
 double opt_geometry_snap2(OPT_ARGS_NUM);
 double opt_geometry_clip(OPT_ARGS_NUM);
 double opt_geometry_copy_meshing_method(OPT_ARGS_NUM);
+double opt_geometry_copy_display_attributes(OPT_ARGS_NUM);
 double opt_geometry_exact_extrusion(OPT_ARGS_NUM);
 double opt_geometry_match_geom_and_mesh(OPT_ARGS_NUM);
 double opt_mesh_label_sampling(OPT_ARGS_NUM);
@@ -447,7 +453,6 @@ double opt_mesh_mesh_only_visible(OPT_ARGS_NUM);
 double opt_mesh_min_circ_points(OPT_ARGS_NUM);
 double opt_mesh_allow_swap_edge_angle(OPT_ARGS_NUM);
 double opt_mesh_min_curv_points(OPT_ARGS_NUM);
-double opt_mesh_multiple_passes(OPT_ARGS_NUM);
 double opt_mesh_order(OPT_ARGS_NUM);
 double opt_mesh_ho_optimize(OPT_ARGS_NUM);
 double opt_mesh_ho_nlayers(OPT_ARGS_NUM);
@@ -508,7 +513,7 @@ double opt_solver_auto_archive_output_files(OPT_ARGS_NUM);
 double opt_solver_auto_check(OPT_ARGS_NUM);
 double opt_solver_auto_mesh(OPT_ARGS_NUM);
 double opt_solver_auto_merge_file(OPT_ARGS_NUM);
-double opt_solver_auto_hide_new_views(OPT_ARGS_NUM);
+double opt_solver_auto_show_views(OPT_ARGS_NUM);
 double opt_solver_auto_show_last_step(OPT_ARGS_NUM);
 double opt_solver_show_invisible_parameters(OPT_ARGS_NUM);
 double opt_post_horizontal_scales(OPT_ARGS_NUM);
@@ -667,6 +672,9 @@ double opt_print_gif_sort(OPT_ARGS_NUM);
 double opt_print_gif_interlace(OPT_ARGS_NUM);
 double opt_print_gif_transparent(OPT_ARGS_NUM);
 double opt_print_background(OPT_ARGS_NUM);
+double opt_print_pgf_two_dim(OPT_ARGS_NUM);
+double opt_print_pgf_export_axis(OPT_ARGS_NUM);
+double opt_print_pgf_horiz_bar(OPT_ARGS_NUM);
 double opt_print_text(OPT_ARGS_NUM);
 double opt_print_tex_as_equation(OPT_ARGS_NUM);
 double opt_print_composite_windows(OPT_ARGS_NUM);
diff --git a/Common/TreeUtils.cpp b/Common/TreeUtils.cpp
index 1521270..f59fe4e 100644
--- a/Common/TreeUtils.cpp
+++ b/Common/TreeUtils.cpp
@@ -27,6 +27,13 @@ void Tree_Delete(Tree_T * tree)
   Free(tree);
 }
 
+void Tree_Delete(Tree_T * tree, void (*freefn) (void * ))
+{
+  if(!tree) return;
+  avl_free_table(tree->root, freefn, 0);
+  Free(tree);
+}
+
 void *Tree_Add(Tree_T * tree, void *data)
 {
   if(!tree) return 0;
diff --git a/Common/TreeUtils.h b/Common/TreeUtils.h
index 7dd9526..e76b57a 100644
--- a/Common/TreeUtils.h
+++ b/Common/TreeUtils.h
@@ -16,6 +16,7 @@ typedef struct {
 
 Tree_T *Tree_Create(int size, int (*fcmp)(const void *a, const void *b));
 void    Tree_Delete(Tree_T *Tree);
+void    Tree_Delete(Tree_T *Tree, void (*freefn)(void * ) );
 void   *Tree_Add(Tree_T *tree, void *data);
 int     Tree_Nbr(Tree_T *Tree);
 int     Tree_Insert(Tree_T *Tree, void *data);
diff --git a/Common/gmshPopplerWrapper.cpp b/Common/gmshPopplerWrapper.cpp
index 0d0d40a..63f580d 100644
--- a/Common/gmshPopplerWrapper.cpp
+++ b/Common/gmshPopplerWrapper.cpp
@@ -12,57 +12,71 @@
 #include <poppler/cpp/poppler-page-renderer.h>
 
 gmshPopplerWrapper *gmshPopplerWrapper::_instance = 0;
-poppler::document  *gmshPopplerWrapper::_current_doc = 0;
+poppler::document  *gmshPopplerWrapper::_currentDoc = 0;
 #if defined(HAVE_OPENGL)
-std::map<int,GLuint> gmshPopplerWrapper::_pages2textures;
+std::map<int, GLuint> gmshPopplerWrapper::_pages2textures;
 int gmshPopplerWrapper::_w = -1;
 int gmshPopplerWrapper::_h = -1;
-int gmshPopplerWrapper::_current_page = 0;
+int gmshPopplerWrapper::_currentPage = 0;
 #endif
 
-gmshPopplerWrapper *gmshPopplerWrapper::instance() {
-  if (!_instance)_instance = new gmshPopplerWrapper;
+gmshPopplerWrapper *gmshPopplerWrapper::instance()
+{
+  if(!_instance) _instance = new gmshPopplerWrapper;
   return _instance;
 }
 
-int gmshPopplerWrapper::load_from_file (const std::string &file_name,
-					const std::string &owner_password,
-					const std::string &user_password){
-  if (_current_doc) delete _current_doc;
-  _current_doc = poppler::document::load_from_file (file_name,owner_password,
-						    user_password);
-  if (!_current_doc) return 0;
-  Msg::Info("PDF File has been loaded in the Wrapper");
+int gmshPopplerWrapper::loadFromFile(const std::string &fileName,
+                                     const std::string &ownerPassword,
+                                     const std::string &userPassword)
+{
+  if (_currentDoc) delete _currentDoc;
+
+  Msg::Info("Loading PDF file `%s'...", fileName.c_str());
+  _currentDoc = poppler::document::load_from_file(fileName, ownerPassword,
+                                                   userPassword);
+  if (!_currentDoc) return 0;
+
+  Msg::Info("Loaded PDF file `%s'", fileName.c_str());
   //  createBitmap(1,72.,72.,-1,-1,-1,-1);
   return 1;
 }
 
+int gmshPopplerWrapper::getNumPages()
+{
+  if(!_currentDoc) return 0;
+  return _currentDoc->pages();
+}
+
 #if defined(HAVE_OPENGL)
 GLuint gmshPopplerWrapper::getTextureForPage(double xres,
-					     double yres) {
-  int iPage = _current_page;
+					     double yres)
+{
+  int iPage = _currentPage;
+  int numPages = getNumPages();
+  if(iPage < 0) iPage = 0;
+  if(iPage > numPages - 1) iPage = numPages - 1;
   std::map<int,GLuint>::iterator it = _pages2textures.find(iPage);
-  if (it != _pages2textures.end())return it->second;
-  if (!_current_doc)return 0;
-  poppler::page *_current_page = _current_doc->create_page (iPage);
+  if (it != _pages2textures.end()) return it->second;
+  if (!_currentDoc) return 0;
+
+  poppler::page *page = _currentDoc->create_page(iPage);
   poppler::page_renderer pr;
-  poppler::image im =  pr.render_page (_current_page,xres,yres,-1,-1,-1);
+  pr.set_render_hint(poppler::page_renderer::text_antialiasing, true);
+  pr.set_render_hint(poppler::page_renderer::antialiasing, true);
+  poppler::image im = pr.render_page(page, xres, yres, -1, -1, -1);
   _w = im.width();
   _h = im.height();
-  //  im.save("page.png","png");
   GLuint texture;
   glGenTextures(1, &texture);
   glBindTexture(GL_TEXTURE_2D, texture);
   _pages2textures[iPage] = texture;
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
-  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.width(),im.height(), 0,
-	       GL_RGBA, GL_UNSIGNED_BYTE,im.const_data());
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, im.width(), im.height(), 0,
+	       GL_RGBA, GL_UNSIGNED_BYTE, im.const_data());
   return texture;
 }
 #endif
 
-
 #endif
-
diff --git a/Common/gmshPopplerWrapper.h b/Common/gmshPopplerWrapper.h
index d225c70..3cca44b 100644
--- a/Common/gmshPopplerWrapper.h
+++ b/Common/gmshPopplerWrapper.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
-#ifndef  _GMSHPOPPLERWRAPPER_PDF_H_
+#ifndef _GMSHPOPPLERWRAPPER_PDF_H_
 #define _GMSHPOPPLERWRAPPER_PDF_H_
 
 #include "GmshConfig.h"
@@ -24,26 +24,28 @@
 
 class gmshPopplerWrapper {
 private:
-  static int _current_page;
-  static poppler::document *_current_doc;
+  static int _currentPage;
+  static poppler::document *_currentDoc;
   static gmshPopplerWrapper *_instance;
-  static int _w,_h;
+  static int _w, _h;
 #if defined(HAVE_OPENGL)
   static std::map<int,GLuint> _pages2textures; // map pages to textures
 #endif
 
 public:
   static gmshPopplerWrapper *instance();
-  static int load_from_file (const std::string &file_name,
-			     const std::string &owner_password=std::string(),
-			     const std::string &user_password=std::string());
-  static int width() {return _w;}
-  static int height() {return _h;}
-  static void setCurrentPageUp () {_current_page++;}
-  static void setCurrentPageDown () {if(_current_page > 0) _current_page--;}
+  static int loadFromFile(const std::string &file_name,
+                          const std::string &owner_password=std::string(),
+                          const std::string &user_password=std::string());
+  static int width(){ return _w; }
+  static int height(){ return _h; }
+  static int getNumPages();
+  static void setCurrentPage(int num){ _currentPage = num; }
+  static int getCurrentPage(){ return _currentPage; }
+  static void setCurrentPageUp(){ if(_currentPage < getNumPages()) _currentPage++; }
+  static void setCurrentPageDown(){ if(_currentPage > 0) _currentPage--; }
 #if defined(HAVE_OPENGL)
-  static GLuint getTextureForPage(double xres,
-				  double yres) ;
+  static GLuint getTextureForPage(double xres, double yres);
 #endif
 };
 
diff --git a/Common/onelab.h b/Common/onelab.h
index 3dce36d..8cd774a 100644
--- a/Common/onelab.h
+++ b/Common/onelab.h
@@ -1,4 +1,4 @@
-// OneLab - Copyright (C) 2011-2014 ULg-UCL
+// ONELAB - Copyright (C) 2011-2014 ULg-UCL
 //
 // Permission is hereby granted, free of charge, to any person
 // obtaining a copy of this software and associated documentation
@@ -53,13 +53,11 @@ namespace onelab{
     std::string _label;
     // a help string
     std::string _help;
-    // clients that use this parameter
-    std::set<std::string> _clients;
-    // flag to check if the value of the parameter has been changed since the
-    // last computation (normally this is reset after all the clients have been
-    // run)
-    bool _changed;
-    // flag indicating that the _changed flag of this parameter will always be
+    // map of clients that use this parameter, associated with a "changed" flag
+    // (set to false if the client has already been run with the current value of
+    // the parameter)
+    std::map<std::string, bool> _clients;
+    // flag indicating that the "changed" flags of this parameter will always be
     // reset to false when the parameter is updated
     bool _neverChanged;
     // should the parameter be visible in the interface?
@@ -72,13 +70,24 @@ namespace onelab{
   public:
     parameter(const std::string &name="", const std::string &label="",
               const std::string &help="")
-      : _name(name), _label(label), _help(help), _changed(true),
-        _neverChanged(false), _visible(true), _readOnly(false) {}
+      : _name(name), _label(label), _help(help), _neverChanged(false),
+        _visible(true), _readOnly(false) {}
     virtual ~parameter(){}
     void setName(const std::string &name){ _name = name; }
     void setLabel(const std::string &label){ _label = label; }
     void setHelp(const std::string &help){ _help = help; }
-    void setChanged(bool changed){ _changed = changed; }
+    void setChanged(bool changed, const std::string &client="")
+    {
+      if(client.size()){
+        std::map<std::string, bool>::iterator it = _clients.find(client);
+        if(it != _clients.end()) it->second = changed;
+      }
+      else{
+        for(std::map<std::string, bool>::iterator it = _clients.begin();
+            it != _clients.end(); it++)
+          it->second = changed;
+      }
+    }
     void setNeverChanged(bool never){ _neverChanged = never; }
     void setVisible(bool visible){ _visible = visible; }
     void setReadOnly(bool readOnly){ _readOnly = readOnly; }
@@ -90,9 +99,13 @@ namespace onelab{
     {
       _attributes = attributes;
     }
-    void setClients(const std::set<std::string> &clients){ _clients = clients; }
-    void addClient(const std::string &client){ _clients.insert(client); }
-    void addClients(const std::set<std::string> &clients)
+    void setClients(const std::map<std::string, bool> &clients){ _clients = clients; }
+    void addClient(const std::string &client, bool changed)
+    {
+      if(_clients.find(client) == _clients.end())
+        _clients[client] = changed;
+    }
+    void addClients(const std::map<std::string, bool> &clients)
     {
       _clients.insert(clients.begin(), clients.end());
     }
@@ -100,6 +113,7 @@ namespace onelab{
     {
       return (_clients.find(client) != _clients.end());
     }
+    int getNumClients() { return (int)_clients.size(); };
     virtual std::string getType() const = 0;
     const std::string &getName() const { return _name; }
     const std::string &getLabel() const { return _label; }
@@ -122,7 +136,21 @@ namespace onelab{
         s = s.substr(1);
       return s;
     }
-    bool getChanged() const { return _changed; }
+    bool getChanged(const std::string &client="") const
+    {
+      if(client.size()){
+        std::map<std::string, bool>::const_iterator it = _clients.find(client);
+        if(it != _clients.end()) return it->second;
+        else return false;
+      }
+      else{
+        for(std::map<std::string, bool>::const_iterator it = _clients.begin();
+            it != _clients.end(); it++){
+          if(it->second) return true;
+        }
+        return false;
+      }
+    }
     bool getNeverChanged() const { return _neverChanged; }
     bool getVisible() const { return _visible; }
     bool getReadOnly() const { return _readOnly; }
@@ -136,10 +164,10 @@ namespace onelab{
     {
       return _attributes;
     }
-    const std::set<std::string> &getClients() const { return _clients; }
+    const std::map<std::string, bool> &getClients() const { return _clients; }
     static char charSep() { return '\0'; }
     static double maxNumber() { return 1e200; }
-    static std::string version() { return "1.05"; }
+    static std::string version() { return "1.1"; }
     static std::string getNextToken(const std::string &msg,
                                     std::string::size_type &first,
                                     char separator=charSep())
@@ -185,7 +213,6 @@ namespace onelab{
               << sanitize(getLabel()) << charSep()
               << sanitize(getHelp()) << charSep()
               << (getNeverChanged() ? 1 : 0) << charSep()
-              << (getChanged() ? 1 : 0) << charSep()
               << (getVisible() ? 1 : 0) << charSep()
               << (getReadOnly() ? 1 : 0) << charSep()
               << _attributes.size() << charSep();
@@ -194,9 +221,10 @@ namespace onelab{
         sstream << sanitize(it->first) << charSep()
                 << sanitize(it->second) << charSep();
       sstream << getClients().size() << charSep();
-      for(std::set<std::string>::const_iterator it = getClients().begin();
+      for(std::map<std::string, bool>::const_iterator it = getClients().begin();
           it != getClients().end(); it++)
-        sstream << sanitize(*it) << charSep();
+        sstream << sanitize(it->first) << charSep()
+                << (it->second ? 1 : 0) << charSep();
       return sstream.str();
     }
     virtual std::string::size_type fromChar(const std::string &msg)
@@ -208,7 +236,6 @@ namespace onelab{
       setLabel(getNextToken(msg, pos));
       setHelp(getNextToken(msg, pos));
       setNeverChanged(atoi(getNextToken(msg, pos).c_str()));
-      setChanged(atoi(getNextToken(msg, pos).c_str()));
       setVisible(atoi(getNextToken(msg, pos).c_str()));
       setReadOnly(atoi(getNextToken(msg, pos).c_str()));
       int numAttributes = atoi(getNextToken(msg, pos).c_str());
@@ -219,7 +246,8 @@ namespace onelab{
       int numClients = atoi(getNextToken(msg, pos).c_str());
       for(int i = 0; i < numClients; i++){
         std::string client(getNextToken(msg, pos));
-        addClient(client);
+        int changed = atoi(getNextToken(msg, pos).c_str());
+        addClient(client, changed ? true : false);
       }
       return pos;
     }
@@ -254,7 +282,7 @@ namespace onelab{
     {
       time_t now;
       time(&now);
-      fprintf(fp, "OneLab database created by %s on %s",
+      fprintf(fp, "ONELAB database created by %s on %s",
               creator.c_str(), ctime(&now));
       for(unsigned int i = 0; i < msg.size(); i++){
         fprintf(fp, "%d ", (int)msg[i].size());
@@ -329,7 +357,7 @@ namespace onelab{
     }
     void update(const number &p)
     {
-      addClients(p.getClients()); // complete the list of clients
+      addClients(p.getClients());
       setLabel(p.getLabel());
       setHelp(p.getHelp());
       setVisible(p.getVisible());
@@ -654,19 +682,20 @@ namespace onelab{
       return false;
     }
     // set a parameter in the parameter space; if it already exists, update it
-    // (adding new clients if necessary). This needs to be locked to avoid race
-    // conditions when several clients try to set a parameter at the same time.
+    // (adding new clients if necessary). This would need to be locked to avoid
+    // race conditions when several clients try to set a parameter at the same
+    // time.
     template <class T> bool _set(const T &p, const std::string &client,
                                  std::set<T*, parameterLessThan> &ps)
     {
       typename std::set<T*, parameterLessThan>::iterator it = ps.find((T*)&p);
       if(it != ps.end()){
         (*it)->update(p);
-        if(client.size()) (*it)->addClient(client);
+        if(client.size()) (*it)->addClient(client, true);
       }
       else{
         T* newp = new T(p);
-        if(client.size()) newp->addClient(client);
+        if(client.size()) newp->addClient(client, true);
         ps.insert(newp);
       }
       return true;
@@ -674,7 +703,7 @@ namespace onelab{
     // get the parameter matching the given name, or all the parameters in the
     // category if no name is given. If we find a given parameter by name, we
     // add the client requesting the parameter to the list of clients for this
-    // parameter. This also needs to be locked.
+    // parameter. This would also need to be locked.
     template <class T> bool _get(std::vector<T> &p, const std::string &name,
                                  const std::string &client,
                                  std::set<T*, parameterLessThan> &ps)
@@ -689,7 +718,7 @@ namespace onelab{
         T tmp(name);
         typename std::set<T*, parameterLessThan>::iterator it = ps.find(&tmp);
         if(it != ps.end()){
-          if(client.size()) (*it)->addClient(client);
+          if(client.size()) (*it)->addClient(client, true);
           p.push_back(**it);
         }
       }
@@ -763,23 +792,21 @@ namespace onelab{
       _getAllParameters(ps);
       for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin();
           it != ps.end(); it++){
-        if((client.empty() || (*it)->hasClient(client)) && (*it)->getChanged()){
+        if((*it)->getChanged(client)){
           return true;
         }
       }
       return false;
     }
-    // set the changed flag for all parameters (optionnally only affect those
-    // parameters that depend on a given client)
-    bool setChanged(bool changed, const std::string &client="")
+    // set the changed flag for all the parameters that depend on the given
+    // client (or for all parameters if no client name is provided)
+    void setChanged(bool changed, const std::string &client="")
     {
       std::set<parameter*, parameterLessThan> ps;
       _getAllParameters(ps);
       for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin();
           it != ps.end(); it++)
-        if(client.empty() || (*it)->hasClient(client))
-          (*it)->setChanged(changed);
-      return true;
+        (*it)->setChanged(changed, client);
     }
     // serialize the parameter space (optionally only serialize those parameters
     // that depend on the given client)
@@ -849,6 +876,7 @@ namespace onelab{
     virtual void sendError(const std::string &msg){ std::cerr << msg << std::endl; }
     virtual void sendProgress(const std::string &msg){ std::cout << msg << std::endl; }
     virtual void sendMergeFileRequest(const std::string &msg){}
+    virtual void sendOpenProjectRequest(const std::string &msg){}
     virtual void sendParseStringRequest(const std::string &msg){}
     virtual void sendVertexArray(const std::string &msg){}
     virtual bool clear(const std::string &name) = 0;
@@ -1230,6 +1258,10 @@ namespace onelab{
     {
       if(_gmshClient) _gmshClient->MergeFile(msg.c_str());
     }
+    void sendOpenProjectRequest(const std::string &msg)
+    {
+      if(_gmshClient) _gmshClient->OpenProject(msg.c_str());
+    }
     void sendParseStringRequest(const std::string &msg)
     {
       if(_gmshClient) _gmshClient->ParseString(msg.c_str());
diff --git a/Common/onelabUtils.cpp b/Common/onelabUtils.cpp
index b099b78..40541f5 100644
--- a/Common/onelabUtils.cpp
+++ b/Common/onelabUtils.cpp
@@ -234,7 +234,7 @@ namespace onelabUtils {
     PView *view = 0;
 
     for(unsigned int i = 0; i < PView::list.size(); i++){
-      if(PView::list[i]->getData()->getFileName() == "OneLab" + graphNum){
+      if(PView::list[i]->getData()->getFileName() == "ONELAB" + graphNum){
         view = PView::list[i];
         break;
       }
@@ -273,7 +273,7 @@ namespace onelabUtils {
       }
       else{
         view = new PView(xName, yName, x, y);
-        view->getData()->setFileName("OneLab" + graphNum);
+        view->getData()->setFileName("ONELAB" + graphNum);
         view->getOptions()->intervalsType = PViewOptions::Discrete;
         view->getOptions()->autoPosition = num / 2 + 2;
       }
@@ -291,16 +291,23 @@ namespace onelabUtils {
   void setFirstComputationFlag(bool val){ _firstComputation = val; }
   bool getFirstComputationFlag(){ return _firstComputation; }
 
-  bool runGmshClient(const std::string &action, bool meshAuto)
+  bool runGmshClient(const std::string &action, int meshAuto)
   {
     bool redraw = false;
 
+    // do nothing in case of a python metamodel
+    std::vector<onelab::number> pn;
+    onelab::server::instance()->get(pn, "IsPyMetamodel");
+    if(pn.size() && pn[0].getValue()) return redraw;
+
     onelab::server::citer it = onelab::server::instance()->findClient("Gmsh");
     if(it == onelab::server::instance()->lastClient()) return redraw;
 
     onelab::client *c = it->second;
     std::string mshFileName = onelabUtils::getMshFileName(c);
 
+    Msg::SetGmshOnelabAction(action);
+
     static std::string modelName = GModel::current()->getName();
 
     if(action == "initialize"){
@@ -313,8 +320,8 @@ namespace onelabUtils {
     else if(action == "check"){
       if(onelab::server::instance()->getChanged("Gmsh") ||
          modelName != GModel::current()->getName()){
-        // reload geometry if Gmsh parameters have been modified or if the model
-        // name has changed
+        // reload geometry if Gmsh parameters have been modified or
+        // if the model name has changed
         modelName = GModel::current()->getName();
         redraw = true;
         OpenProject(GModel::current()->getFileName(), false);
@@ -328,8 +335,9 @@ namespace onelabUtils {
         modelName = GModel::current()->getName();
         redraw = true;
         OpenProject(GModel::current()->getFileName(), false);
-        if(getFirstComputationFlag() && !StatFile(mshFileName)){
-          Msg::Info("Skipping mesh generation: assuming '%s' is up-to-date",
+        if(getFirstComputationFlag() && !StatFile(mshFileName) && meshAuto != 2){
+          Msg::Info("Skipping mesh generation: assuming '%s' is up-to-date "
+                    "(use Solver.AutoMesh=2 to force mesh generation)",
                     mshFileName.c_str());
         }
         else if(!GModel::current()->empty() && meshAuto){
@@ -349,6 +357,8 @@ namespace onelabUtils {
       onelab::server::instance()->setChanged(false, "Gmsh");
     }
 
+    Msg::SetGmshOnelabAction("");
+
     return redraw;
   }
 
diff --git a/Common/onelabUtils.h b/Common/onelabUtils.h
index 5ddc9c7..9f77c34 100644
--- a/Common/onelabUtils.h
+++ b/Common/onelabUtils.h
@@ -19,7 +19,7 @@ namespace onelabUtils {
   bool incrementLoop(const std::string &level);
   std::vector<double> getRange(onelab::number &p);
   bool updateGraph(const std::string &graphNum);
-  bool runGmshClient(const std::string &action, bool meshAuto);
+  bool runGmshClient(const std::string &action, int meshAuto);
   bool getFirstComputationFlag();
   void setFirstComputationFlag(bool val);
 
diff --git a/Fltk/FlGui.cpp b/Fltk/FlGui.cpp
index cb3a1df..a5a7cf8 100644
--- a/Fltk/FlGui.cpp
+++ b/Fltk/FlGui.cpp
@@ -198,9 +198,39 @@ static void gamepad_handler(void *data)
   }
 }
 
+static void error_handler(const char *fmt, ...)
+{
+  char str[5000];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+  if(!strcmp(str, "Insufficient GL support")){ // this should be fatal
+    CTX::instance()->terminal = 1;
+    Msg::Error("%s (FLTK internal error)", str);
+    Msg::Fatal("Your system does not seem to support OpenGL - aborting");
+  }
+  else{
+    Msg::Error("%s (FLTK internal error)", str);
+  }
+}
+
+static void fatal_error_handler(const char *fmt, ...)
+{
+  char str[5000];
+  va_list args;
+  va_start(args, fmt);
+  vsnprintf(str, sizeof(str), fmt, args);
+  va_end(args);
+  CTX::instance()->terminal = 1;
+  Msg::Fatal("%s (FLTK internal error)", str);
+}
 
 FlGui::FlGui(int argc, char **argv)
 {
+  Fl::error = error_handler;
+  Fl::fatal = fatal_error_handler;
+
   // set X display
   if(CTX::instance()->display.size())
     Fl::display(CTX::instance()->display.c_str());
@@ -761,7 +791,7 @@ void FlGui::updateViews(bool numberOfViewsHasChanged, bool deleteWidgets)
   for(unsigned int i = 0; i < graph.size(); i++)
     graph[i]->checkAnimButtons();
   if(numberOfViewsHasChanged){
-    onelab->rebuildTree(deleteWidgets);
+    if(onelab) onelab->rebuildTree(deleteWidgets);
     options->resetBrowser();
     options->resetExternalViewList();
     fields->loadFieldViewList();
@@ -779,6 +809,8 @@ void FlGui::resetVisibility()
 {
   if(visibility->win->shown())
     visibility_cb(NULL, NULL);
+  if(help->options->shown())
+    help_options_cb(NULL, NULL);
 }
 
 openglWindow *FlGui::getCurrentOpenglWindow()
@@ -1103,11 +1135,12 @@ void FlGui::saveMessages(const char *fileName)
 
 void FlGui::rebuildTree(bool deleteWidgets)
 {
-  onelab->rebuildTree(deleteWidgets);
+  if(onelab) onelab->rebuildTree(deleteWidgets);
 }
 
 void FlGui::openModule(const std::string &name)
 {
+  if(!onelab) return;
   if(!onelab->isManuallyClosed("0Modules/" + name))
     onelab->openTreeItem("0Modules/" + name);
 }
diff --git a/Fltk/clippingWindow.cpp b/Fltk/clippingWindow.cpp
index 2e3e303..da504cc 100644
--- a/Fltk/clippingWindow.cpp
+++ b/Fltk/clippingWindow.cpp
@@ -321,14 +321,14 @@ void clippingWindow::resetBrowser()
                                    fabs(CTX::instance()->max[i])));
   val1 *= 1.5;
 
-  plane[3]->step(val1 / 200.);
+  plane[3]->step(val1 / 200., 1);
   plane[3]->minimum(-val1);
   plane[3]->maximum(val1);
 
   fillBoxValuesFromPlaneValues();
 
   for(int i = 0; i < 6; i++){
-    box[i]->step(val1 / 200.);
+    box[i]->step(val1 / 200., 1);
     box[i]->minimum(-val1);
     box[i]->maximum(val1);
   }
diff --git a/Fltk/colorbarWindow.cpp b/Fltk/colorbarWindow.cpp
index 05a66ce..930bbfe 100644
--- a/Fltk/colorbarWindow.cpp
+++ b/Fltk/colorbarWindow.cpp
@@ -9,7 +9,7 @@
 // and Andre Battaiola.
 
 #include <FL/fl_draw.H>
-#include "colorbarWindow.h"   
+#include "colorbarWindow.h"
 #include "ColorTable.h"
 #include "Context.h"
 
@@ -78,8 +78,6 @@ void colorbarWindow::redraw_range(int a, int b)
   int intensity = 0;
   double H, S, V;
 
-  make_current();
-
   if(a < 0)
     a = 0;
   if(b >= ct->size)
@@ -250,8 +248,6 @@ void colorbarWindow::redraw_marker()
   char str[50];
   double val;
 
-  make_current();
-
   y0 = marker_y;
   y1 = h() - 1;
 
@@ -280,11 +276,11 @@ void colorbarWindow::draw()
   label_y = h() - 5;
   marker_y = label_y - marker_height - font_height;
   wedge_y = marker_y - wedge_height;
-  color_bg = fl_color_cube(CTX::instance()->unpackRed(CTX::instance()->color.bg) * 
+  color_bg = fl_color_cube(CTX::instance()->unpackRed(CTX::instance()->color.bg) *
                            FL_NUM_RED / 256,
-                           CTX::instance()->unpackGreen(CTX::instance()->color.bg) * 
+                           CTX::instance()->unpackGreen(CTX::instance()->color.bg) *
                            FL_NUM_GREEN / 256,
-                           CTX::instance()->unpackBlue(CTX::instance()->color.bg) * 
+                           CTX::instance()->unpackBlue(CTX::instance()->color.bg) *
                            FL_NUM_BLUE / 256);
   redraw_range(0, ct->size - 1);
   redraw_marker();
@@ -571,7 +567,6 @@ int colorbarWindow::handle(int event)
     if(move_marker) {
       // changing marker position
       marker_pos = entry;
-      redraw_marker();
     }
     else {
       // changing color graph
@@ -613,14 +608,10 @@ int colorbarWindow::handle(int event)
         }
         ct->table[i] = CTX::instance()->packColor(red, green, blue, alpha);
       }
-      // redraw the color curves
-      if(pentry < entry)
-        redraw_range(pentry - 1, entry + 1);
-      else
-        redraw_range(entry - 1, pentry + 1);
       pentry = entry;
       *viewchanged = true;
     }
+    redraw();
     return 1;
   }
 
diff --git a/Fltk/contextWindow.cpp b/Fltk/contextWindow.cpp
index 24893d8..deff825 100644
--- a/Fltk/contextWindow.cpp
+++ b/Fltk/contextWindow.cpp
@@ -67,7 +67,7 @@ geometryContextWindow::geometryContextWindow(int deltaFontSize)
       input[24] = new Fl_Input(2 * WB, 2 * WB + 3 * BH, IW, BH, "Label");
       input[24]->value("");
       input[25] = new Fl_Input(2 * WB, 2 * WB + 4 * BH, IW, BH, "Path");
-      input[25]->value("Gmsh/Parameters");
+      input[25]->value("Parameters");
       for(int i = 0; i < 2; i++)   input[i]->align(FL_ALIGN_RIGHT);
       for(int i = 24; i < 26; i++) input[i]->align(FL_ALIGN_RIGHT);
       {
diff --git a/Fltk/drawContextFltkCairo.cpp b/Fltk/drawContextFltkCairo.cpp
index 5b2f804..c1b9dca 100644
--- a/Fltk/drawContextFltkCairo.cpp
+++ b/Fltk/drawContextFltkCairo.cpp
@@ -95,21 +95,21 @@ class drawContextFltkCairo::queueString {
     glScalef (2.0f / winw, 2.0f /  winh, 1.0f);
     glTranslatef (-winw / 2.0f, -winh / 2.0f, 0.0f);
     //write the texture on screen
-    glEnable (GL_TEXTURE_RECTANGLE_ARB);
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
     glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
     glDisable(GL_LIGHTING);
-    glDisable (GL_DEPTH_TEST);
-    glEnable (GL_BLEND);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glGenTextures (1, &textureId);
-    glBindTexture (GL_TEXTURE_RECTANGLE_ARB, textureId);
-    glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA,
-                  cairo_image_surface_get_width(surface),
-                  cairo_image_surface_get_height(surface), 0,
-                  GL_ALPHA, GL_UNSIGNED_BYTE, cairo_image_surface_get_data(surface));
+    glGenTextures(1, &textureId);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textureId);
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA,
+                 cairo_image_surface_get_width(surface),
+                 cairo_image_surface_get_height(surface), 0,
+                 GL_ALPHA, GL_UNSIGNED_BYTE, cairo_image_surface_get_data(surface));
     //glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_SRC0_ALPHA);
     //printf("error %i %s\n", __LINE__, gluErrorString(glGetError()));
-    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 
     pos = 0;
     for(std::vector<element>::iterator it = _elements.begin(); it != _elements.end();  ++it) {
diff --git a/Fltk/drawContextFltkStringTexture.cpp b/Fltk/drawContextFltkStringTexture.cpp
index b0787be..6c20e06 100644
--- a/Fltk/drawContextFltkStringTexture.cpp
+++ b/Fltk/drawContextFltkStringTexture.cpp
@@ -13,7 +13,7 @@
 #endif
 
 class drawContextFltkStringTexture::queueString {
-  public :
+ public :
   typedef struct {
     std::string text;
     GLfloat x, y, z;
@@ -23,17 +23,16 @@ class drawContextFltkStringTexture::queueString {
     int height;
   } element;
 
-  private:
+ private:
   std::vector<element> _elements;
   int _totalWidth, _maxHeight;
 
-  public:
+ public:
   queueString()
   {
     _totalWidth = 0;
     _maxHeight = 0;
   }
-
   void append(const element &elem)
   {
     if (_totalWidth + elem.width > 1000)
@@ -42,7 +41,6 @@ class drawContextFltkStringTexture::queueString {
     _totalWidth += elem.width;
     _maxHeight = std::max(_maxHeight, elem.height);
   }
-
   void flush()
   {
     //1000 should be _totalWidth but it does not work
@@ -68,28 +66,28 @@ class drawContextFltkStringTexture::queueString {
     //setup matrices
     GLint matrixMode;
     GLuint textureId;
-    glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
-    glMatrixMode (GL_PROJECTION);
+    glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
+    glMatrixMode(GL_PROJECTION);
     glPushMatrix();
     glLoadIdentity ();
-    glMatrixMode (GL_MODELVIEW);
+    glMatrixMode(GL_MODELVIEW);
     glPushMatrix();
     glLoadIdentity ();
     float winw = Fl_Window::current()->w();
     float winh = Fl_Window::current()->h();
-    glScalef (2.0f / winw, 2.0f /  winh, 1.0f);
-    glTranslatef (-winw / 2.0f, -winh / 2.0f, 0.0f);
+    glScalef(2.0f / winw, 2.0f /  winh, 1.0f);
+    glTranslatef(-winw / 2.0f, -winh / 2.0f, 0.0f);
     //write the texture on screen
-    glEnable (GL_TEXTURE_RECTANGLE_ARB);
+    glEnable(GL_TEXTURE_RECTANGLE_ARB);
     glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
     glDisable(GL_LIGHTING);
-    glDisable (GL_DEPTH_TEST);
-    glEnable (GL_BLEND);
+    glDisable(GL_DEPTH_TEST);
+    glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    glGenTextures (1, &textureId);
-    glBindTexture (GL_TEXTURE_RECTANGLE_ARB, textureId);
-    glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA, w, h, 0,
-                  GL_ALPHA, GL_UNSIGNED_BYTE, data);
+    glGenTextures(1, &textureId);
+    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textureId);
+    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_ALPHA, w, h, 0,
+                 GL_ALPHA, GL_UNSIGNED_BYTE, data);
     //glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_SRC0_ALPHA);
     //printf("error %i %s\n", __LINE__, gluErrorString(glGetError()));
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -100,7 +98,6 @@ class drawContextFltkStringTexture::queueString {
       glColor4f(it->r, it->g, it->b, it->alpha);
       int Lx = it->width;
       int Ly = it->height;
-
       glBegin (GL_QUADS);
       glTexCoord2f(pos, 0);
       glVertex2f(0.0f, Ly);
@@ -110,7 +107,7 @@ class drawContextFltkStringTexture::queueString {
       glVertex2f(Lx, 0.0f);
       glTexCoord2f(pos, Ly);
       glVertex2f(0.0f, 0.0f);
-      glEnd ();
+      glEnd();
       pos += Lx;
       glTranslatef(-it->x, -it->y, -it->z);
     }
@@ -122,7 +119,7 @@ class drawContextFltkStringTexture::queueString {
     glPopMatrix(); // GL_MODELVIEW
     glMatrixMode (GL_PROJECTION);
     glPopMatrix();
-    glMatrixMode (matrixMode);
+    glMatrixMode(matrixMode);
     _elements.clear();
     _maxHeight = 0;
     _totalWidth = 0;
@@ -162,4 +159,3 @@ void drawContextFltkStringTexture::setFont(int fontid, int fontsize)
   _currentFontId = fontid;
   _currentFontSize = fontsize;
 }
-
diff --git a/Fltk/fileDialogs.cpp b/Fltk/fileDialogs.cpp
index 2326e95..10e48d1 100644
--- a/Fltk/fileDialogs.cpp
+++ b/Fltk/fileDialogs.cpp
@@ -5,6 +5,7 @@
 //
 // Contributor(s):
 //   Stephen Guzik
+//   Sebastian Eiser
 //
 
 #include <limits>
@@ -312,6 +313,86 @@ int genericBitmapFileDialog(const char *name, const char *title, int format)
   return 0;
 }
 
+// pgf dialog
+
+int pgfBitmapFileDialog(const char *name, const char *title, int format)
+{
+  struct _pgfBitmapFileDialog{
+    Fl_Window *window;
+    Fl_Value_Slider *s[2];
+    Fl_Check_Button *b[3];
+    Fl_Value_Input *v[2];
+    Fl_Button *ok, *cancel;
+  };
+  static _pgfBitmapFileDialog *dialog = NULL;
+
+  if(!dialog){
+    dialog = new _pgfBitmapFileDialog;
+    int h = 3 * WB + 5 * BH, w = 2 * BB + 3 * WB, y = WB;
+    dialog->window = new Fl_Double_Window(w, h);
+    dialog->window->box(GMSH_WINDOW_BOX);
+    dialog->window->set_modal();
+    dialog->b[0] = new Fl_Check_Button
+      (WB, y, 2 * BB + WB, BH, "Flat graphics"); y += BH;
+    dialog->b[0]->type(FL_TOGGLE_BUTTON);
+    dialog->b[1] = new Fl_Check_Button
+      (WB, y, 2 * BB + WB, BH, "Export axis (for entire fig)"); y += BH;
+    dialog->b[1]->type(FL_TOGGLE_BUTTON);
+    dialog->b[2] = new Fl_Check_Button
+      (WB, y, 2 * BB + WB, BH, "Horizontal colorbar"); y += BH;
+    dialog->b[2]->type(FL_TOGGLE_BUTTON);
+    dialog->v[0] = new Fl_Value_Input
+      (WB, y, BB / 2, BH);
+    dialog->v[0]->minimum(-1);
+    dialog->v[0]->maximum(5000);
+    dialog->v[0]->step(1);
+    dialog->v[1] = new Fl_Value_Input
+      (WB + BB / 2, y, BB - BB / 2, BH, "Dimensions"); y += BH;
+    dialog->v[1]->minimum(-1);
+    dialog->v[1]->maximum(5000);
+    dialog->v[1]->step(1);
+    dialog->v[1]->align(FL_ALIGN_RIGHT);
+    dialog->ok = new Fl_Return_Button(WB, y + WB, BB, BH, "OK");
+    dialog->cancel = new Fl_Button(2 * WB + BB, y + WB, BB, BH, "Cancel");
+    dialog->window->end();
+    dialog->window->hotspot(dialog->window);
+  }
+
+  dialog->window->label(title);
+  dialog->b[0]->value(CTX::instance()->print.pgfTwoDim);
+  dialog->b[1]->value(CTX::instance()->print.pgfExportAxis);
+  dialog->b[2]->value(CTX::instance()->print.pgfHorizBar);
+  dialog->v[0]->value(CTX::instance()->print.width);
+  dialog->v[1]->value(CTX::instance()->print.height);
+  dialog->window->show();
+
+  while(dialog->window->shown()){
+    Fl::wait();
+    for (;;) {
+      Fl_Widget* o = Fl::readqueue();
+      if (!o) break;
+      if (o == dialog->ok) {
+        opt_print_text(0, GMSH_SET | GMSH_GUI, 0); // never print any text
+        opt_print_pgf_two_dim(0, GMSH_SET | GMSH_GUI, (int)dialog->b[0]->value());
+        opt_print_background(0, GMSH_SET | GMSH_GUI, 0); // never print background
+        opt_print_pgf_export_axis(0, GMSH_SET | GMSH_GUI, (int)dialog->b[1]->value());
+        opt_print_pgf_horiz_bar(0, GMSH_SET | GMSH_GUI, (int)dialog->b[2]->value());
+        opt_print_composite_windows(0, GMSH_SET | GMSH_GUI, 0); // never do compositing print
+        opt_print_width(0, GMSH_SET | GMSH_GUI, (int)dialog->v[0]->value());
+        opt_print_height(0, GMSH_SET | GMSH_GUI, (int)dialog->v[1]->value());
+        CreateOutputFile(name, format);
+        dialog->window->hide();
+        return 1;
+      }
+      if (o == dialog->window || o == dialog->cancel){
+        dialog->window->hide();
+        return 0;
+      }
+    }
+  }
+  return 0;
+}
+
 // TeX dialog
 
 int latexFileDialog(const char *name)
diff --git a/Fltk/fileDialogs.h b/Fltk/fileDialogs.h
index c9cdf6b..b8a7291 100644
--- a/Fltk/fileDialogs.h
+++ b/Fltk/fileDialogs.h
@@ -25,6 +25,7 @@ int mpegFileDialog(const char *filename);
 int gifFileDialog(const char *filename);
 int geoFileDialog(const char *filename);
 int genericBitmapFileDialog(const char *filename, const char *title, int format);
+int pgfBitmapFileDialog(const char *filename, const char *title, int format);
 int genericMeshFileDialog(const char *filename, const char *title, int format,
                           bool binary_support, bool element_tag_support);
 int posFileDialog(const char *name);
diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index 77ced14..9ec0a45 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -302,6 +302,8 @@ static int _save_pdf(const char *name){ return gl2psFileDialog
     (name, "PDF Options", FORMAT_PDF); }
 static int _save_png(const char *name){ return genericBitmapFileDialog
     (name, "PNG Options", FORMAT_PNG); }
+static int _save_pgf(const char *name){ return pgfBitmapFileDialog
+    (name, "PGF Options", FORMAT_PGF); }
 static int _save_ps(const char *name){ return gl2psFileDialog
     (name, "PS Options", FORMAT_PS); }
 static int _save_ppm(const char *name){ return genericBitmapFileDialog
@@ -350,6 +352,7 @@ static int _save_auto(const char *name)
   case FORMAT_TEX  : return _save_tex(name);
   case FORMAT_PDF  : return _save_pdf(name);
   case FORMAT_PNG  : return _save_png(name);
+  case FORMAT_PGF  : return _save_pgf(name);
   case FORMAT_PS   : return _save_ps(name);
   case FORMAT_PPM  : return _save_ppm(name);
   case FORMAT_SVG  : return _save_svg(name);
@@ -411,6 +414,7 @@ static void file_save_as_cb(Fl_Widget *w, void *data)
     {"Image - PDF" TT "*.pdf", _save_pdf},
 #if defined(HAVE_LIBPNG)
     {"Image - PNG" TT "*.png", _save_png},
+    {"Image - PGF" TT "*.pgf", _save_pgf},
 #endif
     {"Image - PostScript" TT "*.ps", _save_ps},
     {"Image - PPM" TT "*.ppm", _save_ppm},
@@ -1988,7 +1992,7 @@ static Fl_Menu_Item bar_table[] = {
   {"&Help", 0, 0, 0, FL_SUBMENU},
     {"On&line Documentation", 0, (Fl_Callback *)help_online_cb, 0, FL_MENU_DIVIDER},
     {"&Keyboard and Mouse Usage",  FL_CTRL+'h', (Fl_Callback *)help_basic_cb, 0, FL_MENU_DIVIDER},
-    {"&Current Options",      0, (Fl_Callback *)status_options_cb, (void*)"?", 0},
+    {"&Current Options and Workspace", FL_CTRL+FL_SHIFT+'h', (Fl_Callback *)status_options_cb, (void*)"?", 0},
     {"&Restore all Options to Default Settings", 0, (Fl_Callback *)options_restore_defaults_cb, 0, FL_MENU_DIVIDER},
     {"&About Gmsh",           0, (Fl_Callback *)help_about_cb, 0},
     {0},
@@ -2051,8 +2055,8 @@ static Fl_Menu_Item sysbar_table[] = {
     {0},
   {"Help", 0, 0, 0, FL_SUBMENU},
     {"Online Documentation", 0, (Fl_Callback *)help_online_cb, 0, FL_MENU_DIVIDER},
-    {"Keyboard and Mouse Usage",        0, (Fl_Callback *)help_basic_cb, 0, FL_MENU_DIVIDER},
-    {"Current Options",      0, (Fl_Callback *)status_options_cb, (void*)"?"},
+    {"Keyboard and Mouse Usage", 0, (Fl_Callback *)help_basic_cb, 0, FL_MENU_DIVIDER},
+    {"Current Options and Workspace", FL_META+FL_SHIFT+'h', (Fl_Callback *)status_options_cb, (void*)"?"},
     {"Restore all Options to Default Settings", 0, (Fl_Callback *)options_restore_defaults_cb, 0},
     {0},
   {0}
@@ -2448,49 +2452,49 @@ void status_options_cb(Fl_Widget *w, void *data)
   }
   else if(what == "quick_access"){ // quick access menu
     static Fl_Menu_Item menu[] = {
-      { "Axes", 0, quick_access_cb, (void*)"axes",
+      { "Axes", FL_ALT + 'a', quick_access_cb, (void*)"axes",
         FL_MENU_TOGGLE },
       { "Projection mode", 0, 0, 0, FL_SUBMENU },
-         { "Orthographic", 0, quick_access_cb, (void*)"orthographic"},
+         { "Orthographic", FL_ALT + 'o', quick_access_cb, (void*)"orthographic"},
          { "Perspective", 0, quick_access_cb, (void*)"perspective"},
          { 0 },
       { "All general options...", 0, quick_access_cb, (void*)"general",
         FL_MENU_DIVIDER, 0, FL_ITALIC },
       { "Geometry visibility", 0, 0, 0, FL_SUBMENU },
-         { "Points", 0, quick_access_cb, (void*)"geometry_points",
+         { "Points", FL_ALT + 'p', quick_access_cb, (void*)"geometry_points",
            FL_MENU_TOGGLE },
-         { "Lines", 0, quick_access_cb, (void*)"geometry_lines",
+         { "Lines", FL_ALT + 'l', quick_access_cb, (void*)"geometry_lines",
            FL_MENU_TOGGLE },
-         { "Surfaces ", 0, quick_access_cb, (void*)"geometry_surfaces",
+         { "Surfaces ", FL_ALT + 's', quick_access_cb, (void*)"geometry_surfaces",
          FL_MENU_TOGGLE },
-         { "Volumes", 0, quick_access_cb, (void*)"geometry_volumes",
+         { "Volumes", FL_ALT + 'v', quick_access_cb, (void*)"geometry_volumes",
            FL_MENU_TOGGLE },
          { 0 },
       { "All geometry options...", 0, quick_access_cb, (void*)"geometry",
         FL_MENU_DIVIDER, 0, FL_ITALIC },
       { "Mesh visibility", 0, 0, 0, FL_SUBMENU },
-         { "Nodes", 0, quick_access_cb, (void*)"mesh_points",
+         { "Nodes", FL_ALT + FL_SHIFT + 'p', quick_access_cb, (void*)"mesh_points",
            FL_MENU_TOGGLE },
-         { "Lines", 0, quick_access_cb, (void*)"mesh_lines",
-           FL_MENU_TOGGLE },
-         { "Surface edges ", 0, quick_access_cb, (void*)"mesh_surfaces_edges",
-           FL_MENU_TOGGLE },
-         { "Surface faces", 0, quick_access_cb, (void*)"mesh_surfaces_faces",
-           FL_MENU_TOGGLE },
-         { "Volume edges", 0, quick_access_cb, (void*)"mesh_volumes_edges",
-           FL_MENU_TOGGLE },
-         { "Volume faces", 0, quick_access_cb, (void*)"mesh_volumes_faces",
+         { "Lines", FL_ALT + FL_SHIFT + 'l', quick_access_cb, (void*)"mesh_lines",
            FL_MENU_TOGGLE },
+         { "Surface edges ", FL_ALT + FL_SHIFT + 's', quick_access_cb,
+           (void*)"mesh_surfaces_edges", FL_MENU_TOGGLE },
+         { "Surface faces", FL_ALT + FL_SHIFT + 'd', quick_access_cb,
+           (void*)"mesh_surfaces_faces", FL_MENU_TOGGLE },
+         { "Volume edges", FL_ALT + FL_SHIFT + 'v', quick_access_cb,
+           (void*)"mesh_volumes_edges", FL_MENU_TOGGLE },
+         { "Volume faces", FL_ALT + FL_SHIFT + 'b', quick_access_cb,
+           (void*)"mesh_volumes_faces", FL_MENU_TOGGLE },
          { 0 },
-      { "Toggle mesh display", 0, quick_access_cb, (void*)"mesh_toggle" },
+      { "Toggle mesh display", FL_ALT + 'm', quick_access_cb, (void*)"mesh_toggle" },
       { "Global mesh size factor", 0, quick_access_cb, (void*)"mesh_size" },
       { "All mesh options...", 0, quick_access_cb, (void*)"mesh",
         FL_MENU_DIVIDER, 0, FL_ITALIC },
-      { "View element outlines ", 0, quick_access_cb, (void*)"view_element_outlines",
-        FL_MENU_TOGGLE },
+      { "View element outlines ", FL_ALT + 'e', quick_access_cb,
+        (void*)"view_element_outlines", FL_MENU_TOGGLE },
       { "View normal raise", 0, quick_access_cb, (void*)"view_normal_raise" },
       { "View intervals", 0, 0, 0, FL_SUBMENU },
-         { "Iso-values", 0, quick_access_cb, (void*)"view_iso"},
+         { "Iso-values", FL_ALT + 't', quick_access_cb, (void*)"view_iso"},
          { "Continuous map", 0, quick_access_cb, (void*)"view_continous"},
          { "Filled iso-values", 0, quick_access_cb, (void*)"view_filled"},
          { "Numeric values", 0, quick_access_cb, (void*)"view_numeric"},
@@ -2741,6 +2745,14 @@ static void message_browser_cb(Fl_Widget *w, void *data)
     g->copySelectedMessagesToClipboard();
 }
 
+static void tile_cb(Fl_Widget *w, void *data)
+{
+  if(Fl::event() == FL_RELEASE){
+    // rebuild the tree when we relase the mouse after resizing
+    FlGui::instance()->rebuildTree(true);
+  }
+}
+
 // This dummy box class permits to define a box widget that will not eat the
 // FL_ENTER/FL_LEAVE events (the box widget in fltk > 1.1 does that, so that
 // gl->handle() was not called when the mouse moved)
@@ -2992,12 +3004,18 @@ graphicWindow::graphicWindow(bool main, int numTiles, bool detachedMenu)
   }
 
   if(main && !detachedMenu){
+#if defined(HAVE_ONELAB2)
+    // Hey Maxime, this is for you!
+#else
     _onelab = new onelabGroup(0, mh, twidth, height - mh - sh);
+    _onelab->enableTreeWidgetResize(false);
+#endif
   }
   else{
     _onelab = 0;
   }
 
+  _tile->callback(tile_cb);
   _tile->end();
 
   // resize the tiles to match the prescribed sizes
@@ -3019,6 +3037,7 @@ graphicWindow::graphicWindow(bool main, int numTiles, bool detachedMenu)
     _menuwin->callback(file_quit_cb);
     _menuwin->box(GMSH_WINDOW_BOX);
     _onelab = new onelabGroup(0, 0, _menuwin->w(), _menuwin->h());
+    _onelab->enableTreeWidgetResize(true);
     _menuwin->position(CTX::instance()->menuPosition[0],
                        CTX::instance()->menuPosition[1]);
     _menuwin->resizable(_onelab);
@@ -3075,6 +3094,9 @@ void graphicWindow::detachMenu()
   _menuwin->size_range(_onelab->getMinWindowWidth(), _onelab->getMinWindowHeight());
   _menuwin->end();
   _menuwin->show();
+
+  _onelab->enableTreeWidgetResize(true);
+  _onelab->rebuildTree(true);
 }
 
 void graphicWindow::attachMenu()
@@ -3099,6 +3121,9 @@ void graphicWindow::attachMenu()
   _tile->add(_onelab);
   _onelab->resize(_tile->x(), _tile->y(), w, _tile->h());
   _tile->redraw();
+
+  _onelab->enableTreeWidgetResize(false);
+  _onelab->rebuildTree(true);
 }
 
 void graphicWindow::attachDetachMenu()
@@ -3116,6 +3141,8 @@ void graphicWindow::showMenu()
     int maxw = _win->w();
     if(width > maxw) width = maxw / 2;
     setMenuWidth(width);
+    // necessary until resizing of 0-sized groups works
+    _onelab->rebuildTree(true);
   }
 }
 
@@ -3266,12 +3293,13 @@ void graphicWindow::checkAnimButtons()
 
 void graphicWindow::setMenuWidth(int w)
 {
+  if(!_onelab) return;
   if(_menuwin){
     _menuwin->size(std::max(w, _onelab->getMinWindowWidth()), _menuwin->h());
     _menuwin->redraw();
     return;
   }
-  if(!_onelab || !_browser) return;
+  if(!_browser) return;
   double dw = w - _onelab->w();
   if(!dw) return;
   for(unsigned int i = 0; i < gl.size(); i++){
diff --git a/Fltk/helpWindow.cpp b/Fltk/helpWindow.cpp
index 083feb9..245d7b2 100644
--- a/Fltk/helpWindow.cpp
+++ b/Fltk/helpWindow.cpp
@@ -8,18 +8,24 @@
 #include <FL/Fl_Help_View.H>
 #include <FL/Fl_Check_Button.H>
 #include <FL/Fl_Input.H>
-#include <FL/Fl_Value_Input.H>
 #include <FL/Fl_Color_Chooser.H>
+#include "GmshConfig.h"
 #include "FlGui.h"
+#include "inputValue.h"
 #include "helpWindow.h"
 #include "paletteWindow.h"
 #include "CommandLine.h"
 #include "StringUtils.h"
 #include "OS.h"
 #include "Options.h"
+#include "Parser.h"
 #include "Context.h"
 #include "drawContext.h"
 
+#if defined(HAVE_PETSC)
+#include "petsc.h"
+#endif
+
 static const char *help_link(Fl_Widget *w, const char *uri)
 {
   fl_open_uri(uri);
@@ -35,7 +41,7 @@ struct opt_data{
 static void interactive_cb(Fl_Widget* w, void* data)
 {
   if(!data) return;
-  Fl_Value_Input *v = (Fl_Value_Input*)w;
+  inputValueFloat *v = (inputValueFloat*)w;
   opt_data *d = (opt_data*)data;
   double val = v->value();
   NumberOption(GMSH_SET|GMSH_GUI, d->category.c_str(), d->index,
@@ -63,10 +69,10 @@ double numberOrStringOptionChooser(const std::string &category, int index,
   Fl_Window *win = new paletteWindow(width, height, false, t.c_str());
   win->set_modal();
   win->hotspot(win);
-  Fl_Value_Input *number = 0;
+  inputValueFloat *number = 0;
   Fl_Input *string = 0;
   if(isNumber){
-    number = new Fl_Value_Input(WB, WB, width - 2 * WB, BH);
+    number = new inputValueFloat(WB, WB, width - 2 * WB, BH);
     number->value(valn);
     if(isInteractive){
       static opt_data d;
@@ -75,7 +81,7 @@ double numberOrStringOptionChooser(const std::string &category, int index,
       d.name = name;
       number->minimum(minimum);
       number->maximum(maximum);
-      number->step(step);
+      number->step(step, 1);
       number->callback(interactive_cb, (void*)&d);
       number->when(FL_WHEN_RELEASE);
     }
@@ -243,26 +249,30 @@ void help_options_cb(Fl_Widget *w, void *data)
   std::transform(search.begin(), search.end(), search.begin(), ::tolower);
 
   PrintOptions(0, GMSH_FULLRC, diff, help, 0, &s0);
+  PrintParserSymbols(help, s0);
+
+  int top = FlGui::instance()->help->browser->topline();
   FlGui::instance()->help->browser->clear();
   for(unsigned int i = 0; i < s0.size(); i++){
     std::string::size_type sep = s0[i].rfind('\0');
-    void *data = 0;
+    void *d = 0;
     if(sep != std::string::npos){
       std::string tmp = s0[i].substr(sep + 1);
-      if(tmp == "number") data = (void*)"number";
-      else if(tmp == "string") data = (void*)"string";
-      else if(tmp == "color") data = (void*)"color";
+      if(tmp == "number") d = (void*)"number";
+      else if(tmp == "string") d = (void*)"string";
+      else if(tmp == "color") d = (void*)"color";
     }
     if(search.empty()){
-      FlGui::instance()->help->browser->add(s0[i].c_str(), data);
+      FlGui::instance()->help->browser->add(s0[i].c_str(), d);
     }
     else{
       std::string tmp(s0[i]);
       std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
       if(tmp.find(search) != std::string::npos)
-        FlGui::instance()->help->browser->add(s0[i].c_str(), data);
+        FlGui::instance()->help->browser->add(s0[i].c_str(), d);
     }
   }
+  FlGui::instance()->help->browser->topline(top);
 }
 
 helpWindow::helpWindow()
@@ -289,12 +299,21 @@ helpWindow::helpWindow()
             << "<p>Please send all questions and bug reports to "
             << "<a href=\"mailto:gmsh at geuz.org\">gmsh at geuz.org</a></center>"
             << "<ul>"
-            << "<li><i>GUI toolkit:</i> FLTK "
-            << FL_MAJOR_VERSION << "." << FL_MINOR_VERSION << "." << FL_PATCH_VERSION
             << "<li><i>Build OS:</i> " << GetGmshBuildOS()
             << "<li><i>Build date:</i> " << GetGmshBuildDate()
             << "<li><i>Build host:</i> " << GetGmshBuildHost()
             << "<li><i>Build options:</i>" << GetGmshBuildOptions()
+            << "<li><i>FLTK version:</i> "
+            << FL_MAJOR_VERSION << "." << FL_MINOR_VERSION << "." << FL_PATCH_VERSION
+#if defined(HAVE_PETSC)
+            << "<li><i>PETSc version:</i> " << PETSC_VERSION_MAJOR << "."
+            << PETSC_VERSION_MINOR << "." << PETSC_VERSION_SUBMINOR
+#if defined(PETSC_USE_COMPLEX)
+            << "<li><i>PETSc arithmetic:</i> Complex"
+#else
+            << "<li><i>PETSc arithmetic:</i> Real"
+#endif
+#endif
             << "<li><i>Packaged by:</i> " << GetGmshPackager()
             << "</ul>"
             << "<center>Visit <a href=\"http://geuz.org/gmsh/\">http://geuz.org/gmsh/</a> "
@@ -369,25 +388,25 @@ helpWindow::helpWindow()
 
     options = new paletteWindow
       (width, height, CTX::instance()->nonModalWindows ? true : false,
-       "Current Options");
+       "Current Options and Worskspace");
     options->box(GMSH_WINDOW_BOX);
 
     int BW = (width - 4 * WB) / 3;
 
     modified = new Fl_Check_Button
-      (WB, WB, BW, BH, "Show modified");
+      (WB, WB, BW, BH, "Only show modified");
     modified->type(FL_TOGGLE_BUTTON);
     modified->callback(help_options_cb);
-    modified->tooltip("Show options with values different from defaults");
+    modified->tooltip("Show only values different from defaults");
 
     showhelp = new Fl_Check_Button
       (2 * WB + BW, WB, BW, BH, "Show help");
     showhelp->type(FL_TOGGLE_BUTTON);
     showhelp->callback(help_options_cb);
-    showhelp->tooltip("Show help string for each option");
+    showhelp->tooltip("Show help strings");
 
     Fl_Group* o = new Fl_Group(3 * WB + 2 * BW, WB, BW, BH);
-    o->tooltip("Filter options");
+    o->tooltip("Filter values");
     o->box(FL_DOWN_BOX);
     o->color(FL_BACKGROUND2_COLOR);
     search = new Fl_Input
@@ -405,12 +424,12 @@ helpWindow::helpWindow()
     browser->textsize(FL_NORMAL_SIZE - 2);
     browser->type(FL_MULTI_BROWSER);
     browser->callback(browser_cb);
-    browser->tooltip("Double-click to edit option");
+    browser->tooltip("Double-click to edit value");
 
     options->resizable(browser);
     options->position(Fl::x() + Fl::w()/2 - width / 2,
                       Fl::y() + Fl::h()/2 - height / 2);
-    options->size_range(about->w(), about->h());
+    options->size_range(width, height);
     options->end();
   }
 
diff --git a/Fltk/highOrderToolsWindow.cpp b/Fltk/highOrderToolsWindow.cpp
index 64dde81..f2cc517 100644
--- a/Fltk/highOrderToolsWindow.cpp
+++ b/Fltk/highOrderToolsWindow.cpp
@@ -84,28 +84,28 @@ static void chooseopti_cb(Fl_Widget *w, void *data)
 
   switch(algo) {
   case 0: {                                           // Optimization
-    o->push[0]->activate();
     o->choice[0]->activate();
     o->choice[3]->activate();
-    for (int i=2;i<=11;i++) o->value[i]->activate();
-    //    o->push[1]->activate();
+    for (int i=1;i<=8;i++) o->value[i]->activate();
+    if (o->choice[3]->value() == 0)
+      for (int i=9;i<=11;i++) o->value[i]->deactivate();
+    else
+      for (int i=9;i<=11;i++) o->value[i]->activate();
     break;
   }
   case 1: {                                           // Elastic analogy
     o->choice[0]->deactivate();
     o->choice[3]->deactivate();
-    for (int i=2;i<=11;i++) o->value[i]->deactivate();
-    //   o->push[1]->deactivate();
+    for (int i=1;i<=11;i++) o->value[i]->deactivate();
     break;
   }
   case 2: {                                           // Fast curving
     o->choice[0]->deactivate();
     o->choice[3]->deactivate();
-    for (int i=2;i<=6;i++)
+    o->value[1]->deactivate();
+    o->value[2]->activate();
+    for (int i=3;i<=11;i++)
       o->value[i]->deactivate();
-    for (int i=9;i<=11;i++) o->value[i]->deactivate();
-    for (int i=7;i<=8;i++) o->value[i]->activate();
-    //   o->push[1]->deactivate();
     break;
   }
   }
@@ -115,8 +115,10 @@ static void chooseopti_cb(Fl_Widget *w, void *data)
 static void chooseopti_strategy(Fl_Widget *w, void *data)
 {
   highOrderToolsWindow *o = FlGui::instance()->highordertools;
-  if (o->choice[3]->value() == 0) for (int i=9;i<=11;i++) o->value[i]->deactivate();
-  else for (int i=9;i<=11;i++) o->value[i]->activate();
+  if (o->choice[3]->value() == 0)
+    for (int i=9;i<=11;i++) o->value[i]->deactivate();
+  else
+    for (int i=9;i<=11;i++) o->value[i]->activate();
 }
 
 static void highordertools_runopti_cb(Fl_Widget *w, void *data)
@@ -127,28 +129,26 @@ static void highordertools_runopti_cb(Fl_Widget *w, void *data)
     FlGui::instance()->graph[0]->showMessages();
 
   const int algo = o->choice[2]->value();
-  double threshold_min = o->value[1]->value();
   bool onlyVisible = (bool)o->butt[1]->value();
-  int nbLayers = (int) o->value[2]->value();
-  double threshold_max = o->value[8]->value();
 
   int NE = 0;
-  for (GModel::riter it = GModel::current()->firstRegion(); it != GModel::current()->lastRegion(); ++it){
+  for (GModel::riter it = GModel::current()->firstRegion();
+       it != GModel::current()->lastRegion(); ++it) {
     NE += (*it)->getNumMeshElements();
   }
+  int dim = GModel::current()->getDim() == 3 ? ( NE ? 3 : 2 ) :  GModel::current()->getDim();
 
 
 #if defined(HAVE_OPTHOM)
   switch(algo) {
   case 0: {                                                               // Optimization
     OptHomParameters p;
-    p.nbLayers = nbLayers;
-    p.BARRIER_MIN = threshold_min;
-    p.BARRIER_MAX = threshold_max;
+    p.nbLayers = (int) o->value[2]->value();
+    p.BARRIER_MIN = o->value[1]->value();
+    p.BARRIER_MAX = o->value[8]->value();
     p.onlyVisible = onlyVisible;
     // change dim if no 3D elements are there
-    p.dim = GModel::current()->getDim() == 3 ? ( NE ? 3 : 2 ) :  GModel::current()->getDim();
-    printf("%d %d\n",NE,p.dim);
+    p.dim = dim;
     p.itMax = (int) o->value[3]->value();
     p.optPassMax = (int) o->value[4]->value();
     p.weightFixed =  o->value[5]->value();
@@ -164,16 +164,14 @@ static void highordertools_runopti_cb(Fl_Widget *w, void *data)
     break;
   }
   case 1: {                                                               // Elastic analogy
-    ElasticAnalogy(GModel::current(), threshold_min, onlyVisible);
+    ElasticAnalogy(GModel::current(), onlyVisible);
     break;
   }
   case 2: {                                                               // Fast curving
     FastCurvingParameters p;
-    p.BARRIER_MIN = threshold_min;
-    p.BARRIER_MAX = threshold_max;
     p.onlyVisible = onlyVisible;
-    p.dim = GModel::current()->getDim() == 3 ? ( NE ? 3 : 2 ) :  GModel::current()->getDim();
-    p.distanceFactor =  o->value[7]->value();
+    p.dim = dim;
+    p.maxNumLayers = (int) o->value[2]->value();
     HighOrderMeshFastCurving(GModel::current(), p);
     break;
   }
@@ -253,7 +251,7 @@ highOrderToolsWindow::highOrderToolsWindow(int deltaFontSize)
   y += BH;
 
   butt[2] = new Fl_Check_Button
-    (x, y, width - 4 * WB, BH, "Generate curvilinear elements");
+    (x, y, width - 4 * WB, BH, "Use CAD model to curve mesh");
   butt[2]->type(FL_TOGGLE_BUTTON);
   butt[2]->value(1);
 
@@ -273,12 +271,24 @@ highOrderToolsWindow::highOrderToolsWindow(int deltaFontSize)
   {
     y += BH;
     Fl_Box *b = new Fl_Box
-      (x - WB, y, width, BH, "2. Optimization of high order elements");
+      (x - WB, y, width, BH, "2. Regularization of high order elements");
     b->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
   }
 
   y += BH;
+  static Fl_Menu_Item menu_method[] = {
+    {"Optimization", 0, 0, 0},
+    {"Elastic Analogy", 0, 0, 0},
+    {"Fast Curving", 0, 0, 0},
+    {0}
+  };
+  choice[2] = new Fl_Choice
+    (x, y, IW, BH, "Algorithm");
+  choice[2]->align(FL_ALIGN_RIGHT);
+  choice[2]->menu(menu_method);
+  choice[2]->callback(chooseopti_cb);
 
+  y += BH;
   value[1] = new Fl_Value_Input
     (x, y, IW/2.0, BH);
   value[1]->minimum(0);
@@ -313,27 +323,12 @@ highOrderToolsWindow::highOrderToolsWindow(int deltaFontSize)
   value[7]->align(FL_ALIGN_RIGHT);
   value[7]->value(12);
 
-  static Fl_Menu_Item menu_method[] = {
-    {"Optimization", 0, 0, 0},
-    {"Elastic Analogy", 0, 0, 0},
-    {"Fast Curving", 0, 0, 0},
-    {0}
-  };
-
   y += BH;
-  choice[2] = new Fl_Choice
-    (x, y, IW, BH, "Algorithm");
-  choice[2]->align(FL_ALIGN_RIGHT);
-  choice[2]->menu(menu_method);
-  choice[2]->callback(chooseopti_cb);
-
   static Fl_Menu_Item menu_objf[] = {
     {"Fixed", 0, 0, 0},
     {"Free", 0, 0, 0},
     {0}
   };
-
-  y += BH;
   choice[0] = new Fl_Choice
     (x, y, IW, BH, "Boundary vertices");
   choice[0]->menu(menu_objf);
@@ -411,7 +406,7 @@ highOrderToolsWindow::highOrderToolsWindow(int deltaFontSize)
 
   y += 1.5*BH;
   push[1] = new Fl_Button
-    (width - BB - 2 * WB, y, BB, BH, "Optimize");
+    (width - BB - 2 * WB, y, BB, BH, "Regularize");
   push[1]->callback(highordertools_runopti_cb);
 
   // win->resizable(o);
diff --git a/Fltk/inputRange.h b/Fltk/inputRange.h
index de2c266..7b799d9 100644
--- a/Fltk/inputRange.h
+++ b/Fltk/inputRange.h
@@ -20,7 +20,7 @@
 
 class inputRange : public Fl_Group {
  private:
-  inputValue *_input;
+  inputValueFloat *_input;
   Fl_Toggle_Button *_loop_butt;
   Fl_Button *_range_butt, *_graph_butt;
   Fl_Menu_Button *_graph_menu;
@@ -41,7 +41,7 @@ class inputRange : public Fl_Group {
       if(_choices.size() > 1){
         _input->minimum(_choices[0]);
         _input->maximum(_choices[_choices.size() - 1]);
-        _input->step(_choices[1] - _choices[0]);
+        _input->step(_choices[1] - _choices[0], 1);
       }
       _step = 0.;
     }
@@ -58,7 +58,7 @@ class inputRange : public Fl_Group {
       }
       if(_step == 0.) _step = 1.;
       if(_step != 1.) tmp << " : " << _step;
-      _input->step(_step);
+      _input->step(_step, 1);
       _choices.clear();
     }
     _range = tmp.str();
@@ -88,7 +88,7 @@ class inputRange : public Fl_Group {
       if(_choices.size() > 1){
         _input->minimum(_choices[0]);
         _input->maximum(_choices[_choices.size() - 1]);
-        _input->step(_choices[1] - _choices[0]);
+        _input->step(_choices[1] - _choices[0], 1);
       }
       _step = 0.;
     }
@@ -121,7 +121,7 @@ class inputRange : public Fl_Group {
         _step = atof(step.c_str());
       else
         _step = 1.;
-      _input->step(_step);
+      _input->step(_step, 1);
       _choices.clear();
     }
   }
@@ -248,7 +248,7 @@ class inputRange : public Fl_Group {
     int dot_w = FL_NORMAL_SIZE - 2, loop_w = FL_NORMAL_SIZE + 6, graph_w = loop_w;
     int input_w = w - dot_w - loop_w - graph_w;
 
-    _input = new inputValue(x, y, input_w, h);
+    _input = new inputValueFloat(x, y, input_w, h);
     _input->callback(_input_cb, this);
     _input->when(FL_WHEN_ENTER_KEY|FL_WHEN_RELEASE);
 
diff --git a/Fltk/inputValue.cpp b/Fltk/inputValue.cpp
index e7edb48..dd0707c 100644
--- a/Fltk/inputValue.cpp
+++ b/Fltk/inputValue.cpp
@@ -8,9 +8,9 @@
 #include <stdlib.h>
 #include <FL/math.h>
 
-void inputValue::new_input_cb(Fl_Widget*, void* v)
+void inputValueFloat::new_input_cb(Fl_Widget*, void* v)
 {
-  inputValue& t = *(inputValue*)v;
+  inputValueFloat& t = *(inputValueFloat*)v;
   double nv = strtod(t.input.value(), 0);
   if (nv != t.value() || t.when() & FL_WHEN_NOT_CHANGED) {
     t.set_value(nv);
@@ -19,14 +19,14 @@ void inputValue::new_input_cb(Fl_Widget*, void* v)
   }
 }
 
-inputValue::inputValue(int x, int y, int w, int h, const char *l) :
-  Fl_Value_Input(x, y, w, h, l)
+inputValueFloat::inputValueFloat(int x, int y, int w, int h, const char *l) :
+  inputValue(x, y, w, h, l)
 {
   input.type(FL_FLOAT_INPUT);
   input.callback(new_input_cb, this);
 }
 
-int inputValue::handle(int event)
+int inputValueFloat::handle(int event)
 {
   double v;
   int delta;
diff --git a/Fltk/inputValue.h b/Fltk/inputValue.h
index c5627c3..0ec88b5 100644
--- a/Fltk/inputValue.h
+++ b/Fltk/inputValue.h
@@ -9,16 +9,26 @@
 #include <FL/Fl.H>
 #include <FL/Fl_Value_Input.H>
 
-// this is basically the same as Fl_Value_Input, except that we force the
-// underlying input to always accept floats (whatever the step value)
+// same as FL_Value_Input, but prints values in engineering notation
 
 class inputValue : public Fl_Value_Input
 {
+ public:
+  inputValue(int x, int y, int w, int h, const char *l=0) :
+    Fl_Value_Input(x, y, w, h, l) {}
+  virtual int format(char *buffer){ return sprintf(buffer, "%g", value()); }
+};
+
+
+// same as inputValue, but forces the underlying FL_Value_Input to always accept
+// floats (whatever the step value)
+
+class inputValueFloat : public inputValue
+{
  private:
   static void new_input_cb(Fl_Widget*,void*);
  public:
-  inputValue(int x, int y, int w, int h, const char *l=0);
-  virtual int format(char *buffer){ return sprintf(buffer, "%g", value()); }
+  inputValueFloat(int x, int y, int w, int h, const char *l=0);
   int handle(int event);
 };
 
diff --git a/Fltk/manipWindow.cpp b/Fltk/manipWindow.cpp
index 9a742f2..d3b457b 100644
--- a/Fltk/manipWindow.cpp
+++ b/Fltk/manipWindow.cpp
@@ -123,7 +123,7 @@ void manipWindow::update(bool force)
       value[i]->step(1.);
       value[i+3]->minimum(-val1);
       value[i+3]->maximum(val1);
-      value[i+3]->step(val1 / 200.);
+      value[i+3]->step(val1 / 200., 1);
       value[i+6]->minimum(0.01);
       value[i+6]->maximum(100.);
       value[i+6]->step(0.01);
diff --git a/Fltk/onelabGroup.cpp b/Fltk/onelabGroup.cpp
index 6104aec..71bc0b7 100644
--- a/Fltk/onelabGroup.cpp
+++ b/Fltk/onelabGroup.cpp
@@ -50,9 +50,9 @@ typedef unsigned long intptr_t;
 #include "metamodel.h"
 #endif
 
-// This file contains the Gmsh/FLTK specific parts of the OneLab
+// This file contains the Gmsh/FLTK specific parts of the ONELAB
 // interface. You'll need to reimplement this if you plan to build a different
-// OneLab server.
+// ONELAB server.
 
 class onelabGmshServer : public GmshServer{
  private:
@@ -209,7 +209,7 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
       std::string version, ptype, name;
       onelab::parameter::getInfoFromChar(message, version, ptype, name);
       if(onelab::parameter::version() != version){
-        Msg::Error("OneLab version mismatch (server: %s / client: %s)",
+        Msg::Error("ONELAB version mismatch (server: %s / client: %s)",
                    onelab::parameter::version().c_str(), version.c_str());
       }
       else if(ptype == "number"){
@@ -243,7 +243,7 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
         onelab::function p; p.fromChar(message); set(p);
       }
       else
-        Msg::Error("Unknown OneLab parameter type: %s", ptype.c_str());
+        Msg::Error("Unknown ONELAB parameter type: %s", ptype.c_str());
     }
     break;
   case GmshSocket::GMSH_PARAMETER_QUERY:
@@ -251,7 +251,7 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
       std::string version, ptype, name, reply;
       onelab::parameter::getInfoFromChar(message, version, ptype, name);
       if(onelab::parameter::version() != version){
-        Msg::Error("OneLab version mismatch (server: %s / client: %s)",
+        Msg::Error("ONELAB version mismatch (server: %s / client: %s)",
                    onelab::parameter::version().c_str(), version.c_str());
       }
       else if(ptype == "number"){
@@ -271,7 +271,7 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
         if(par.size() == 1) reply = par[0].toChar();
       }
       else
-        Msg::Error("Unknown OneLab parameter type in query: %s", ptype.c_str());
+        Msg::Error("Unknown ONELAB parameter type in query: %s", ptype.c_str());
 
       if(reply.size()){
         getGmshServer()->SendMessage
@@ -290,7 +290,7 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
       std::vector<std::string> replies;
       onelab::parameter::getInfoFromChar(message, version, ptype, name);
       if(onelab::parameter::version() != version){
-        Msg::Error("OneLab version mismatch (server: %s / client: %s)",
+        Msg::Error("ONELAB version mismatch (server: %s / client: %s)",
                    onelab::parameter::version().c_str(), version.c_str());
       }
       else if(ptype == "number"){
@@ -314,12 +314,12 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
             it != functions.end(); it++) replies.push_back((*it).toChar());
       }
       else
-        Msg::Error("Unknown OneLab parameter type in query: %s", ptype.c_str());
+        Msg::Error("Unknown ONELAB parameter type in query: %s", ptype.c_str());
 
       for(unsigned int i = 0; i < replies.size(); i++)
         getGmshServer()->SendMessage
           (GmshSocket::GMSH_PARAMETER_QUERY_ALL, replies[i].size(), &replies[i][0]);
-      reply = "Sent all OneLab " + ptype + "s";
+      reply = "Sent all ONELAB " + ptype + "s";
       getGmshServer()->SendMessage
         (GmshSocket::GMSH_PARAMETER_QUERY_END, reply.size(), &reply[0]);
     }
@@ -342,8 +342,8 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
   case GmshSocket::GMSH_MERGE_FILE:
     if(CTX::instance()->solver.autoMergeFile){
       unsigned int n = PView::list.size();
-      MergePostProcessingFile(message, CTX::instance()->solver.autoShowLastStep,
-                              CTX::instance()->solver.autoHideNewViews, true);
+      MergePostProcessingFile(message, CTX::instance()->solver.autoShowViews,
+                              CTX::instance()->solver.autoShowLastStep, true);
       drawContext::global()->draw();
       if(FlGui::available() && n != PView::list.size()){
         FlGui::instance()->rebuildTree(true);
@@ -351,6 +351,10 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
       }
     }
     break;
+  case GmshSocket::GMSH_OPEN_PROJECT:
+    OpenProject(message);
+    drawContext::global()->draw();
+    break;
   case GmshSocket::GMSH_PARSE_STRING:
     ParseString(message);
     drawContext::global()->draw();
@@ -394,17 +398,23 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
   case GmshSocket::GMSH_OLPARSE:
     {
 #if defined(HAVE_ONELAB_METAMODEL)
-      localSolverClient *c = new InterfacedClient("OLParser","","");
-      std::vector<std::string> split = SplitOLFileName(message);
+      std::string::size_type first = 0;
+      std::string name = onelab::parameter::getNextToken(message, first);
+      std::string fileName = onelab::parameter::getNextToken(message, first);
+      std::vector<std::string> split = SplitOLFileName(fileName);
       std::string ofileName = split[0] + split[1] ;
       std::ofstream outfile(ofileName.c_str());
-      if (outfile.is_open())
-        c->convert_onefile(message, outfile);
+      localSolverClient *c = new InterfacedClient(name,"","");
+      if (outfile.is_open()) {
+        Msg::Info("Preprocess file <%s>",ofileName.c_str());
+        c->convert_onefile(fileName, outfile);
+      }
       else
         Msg::Error("The file <%s> cannot be opened",ofileName.c_str());
       outfile.close();
 
-      std::string reply = "done"; // reply is dummy
+      std::string reply = onelab::server::instance()->getChanged(c->getName()) ?
+        "true" : "false";
       getGmshServer()->SendMessage
         (GmshSocket::GMSH_OLPARSE, reply.size(), &reply[0]);
 
@@ -412,6 +422,23 @@ bool gmshLocalNetworkClient::receiveMessage(gmshLocalNetworkClient *master)
 #endif
     }
     break;
+  case GmshSocket::GMSH_CLIENT_CHANGED:
+    {
+      std::string::size_type first = 0;
+      std::string command = onelab::parameter::getNextToken(message, first);
+       std::string name = onelab::parameter::getNextToken(message, first);
+     if(command == "get"){
+       std::string reply = onelab::server::instance()->getChanged(name) ?
+        "true" : "false";
+      getGmshServer()->SendMessage
+        (GmshSocket::GMSH_CLIENT_CHANGED, reply.size(), &reply[0]);
+      }
+      else if(command == "set"){
+	std::string changed = onelab::parameter::getNextToken(message, first);
+	onelab::server::instance()->setChanged(changed=="true"?true:false,name);
+      }
+    }
+    break;
   default:
     Msg::Warning("Received unknown message type (%d)", type);
     break;
@@ -576,6 +603,11 @@ static bool incrementLoops()
   else if(onelabUtils::incrementLoop("2")) ret = true;
   else if(onelabUtils::incrementLoop("1")) ret = true;
 
+  //Define ONELAB parameter indicating whether or not in a loop
+  onelab::number n("0Metamodel/Loop",ret?1:0);
+  n.setVisible(false);
+  onelab::server::instance()->set(n);
+
   if(FlGui::available() && onelab::server::instance()->getChanged())
     FlGui::instance()->rebuildTree(false);
 
@@ -592,7 +624,8 @@ static void updateGraphs()
     redraw = redraw || ret;
   }
   if(redraw){
-    FlGui::instance()->updateViews(true, true);
+    // don't delete the widgets, as this is called in widget callbacks
+    FlGui::instance()->updateViews(true, false);
     drawContext::global()->draw();
   }
 }
@@ -603,6 +636,7 @@ static std::string timeStamp()
   time(&now);
   tm *t = localtime(&now);
   char stamp[32];
+  // stamp.size() is always 20
   sprintf(stamp, "_%04d-%02d-%02d_%02d-%02d-%02d", 1900 + t->tm_year,
           1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
   return std::string(stamp);
@@ -623,7 +657,13 @@ static void saveDb(const std::string &fileName)
 
 static void archiveOutputFiles(const std::string &fileName)
 {
-  std::string stamp = timeStamp();
+  std::string stamp;
+  std::vector<onelab::string> ps;
+  onelab::server::instance()->get(ps,"0Metamodel/9Tag");
+  if(ps.size())
+    stamp.assign(ps[0].getValue()+timeStamp());
+  else
+    stamp.assign(timeStamp());
 
   // add time stamp in all output files in the db, and rename them on disk
   std::vector<onelab::string> strings;
@@ -639,7 +679,7 @@ static void archiveOutputFiles(const std::string &fileName)
         if(n < 18 || split[1][n-3] != '-' || split[1][n-6] != '-' ||
            split[1][n-9] != '_'){
           std::string old = names[j];
-          CreateDirectory(split[0] + "archive/");
+          CreateSingleDir(split[0] + "archive/");
           names[j] = split[0] + "archive/" + split[1] + stamp + split[2];
           Msg::Info("Renaming '%s' into '%s'", old.c_str(), names[j].c_str());
           rename(old.c_str(), names[j].c_str());
@@ -655,13 +695,41 @@ static void archiveOutputFiles(const std::string &fileName)
   // save stamped db
   {
     std::vector<std::string> split = SplitFileName(fileName);
-    CreateDirectory(split[0] + "archive/");
+    CreateSingleDir(split[0] + "archive/");
     saveDb(split[0] + "archive/" + split[1] + stamp + split[2]);
   }
 
   FlGui::instance()->rebuildTree(true);
 }
 
+static void archiveSolutionFiles(const std::string &fileName)
+{
+  // extract tag from dbName
+  std::vector<std::string> split = SplitFileName(fileName);
+  std::string tag = split[1].substr(6); // cut off 'onelab'
+
+  // add tag to all solution files in the db, and rename them on disk
+  std::vector<onelab::string> strings;
+  onelab::server::instance()->get(strings,"0Metamodel/9Solution files");
+  if(strings.size()){
+    std::vector<std::string> names = strings[0].getChoices();
+    if(names.size()){
+      for(unsigned int j = 0; j < names.size(); j++){
+	std::vector<std::string> split = SplitFileName(names[j]);
+	std::string old = names[j];
+	CreateSingleDir(split[0] + "archive/");
+	names[j] = split[0] + "archive/" + split[1] + tag + split[2];
+	Msg::Info("Renaming '%s' into '%s'", old.c_str(), names[j].c_str());
+	rename(old.c_str(), names[j].c_str());
+      }
+      strings[0].setValue(names[0]);
+      strings[0].setChoices(names);
+      onelab::server::instance()->set(strings[0]);
+      FlGui::instance()->rebuildTree(true);
+    }
+  }
+}
+
 static void loadDb(const std::string &name)
 {
   Msg::StatusBar(true, "Loading database '%s'...", name.c_str());
@@ -675,6 +743,60 @@ static void loadDb(const std::string &name)
     Msg::Error("Could not load database '%s'", name.c_str());
 }
 
+static void resetDb(bool runGmshClient)
+{
+  Msg::Info("Resetting database");
+
+  // clear everything except persistent parameters
+  std::vector<onelab::number> allNumbers, persistentNumbers;
+  std::vector<onelab::string> allStrings, persistentStrings;
+  onelab::server::instance()->get(allNumbers);
+  onelab::server::instance()->get(allStrings);
+  for(unsigned int i = 0; i < allNumbers.size(); i++){
+    if(allNumbers[i].getAttribute("Persistent") == "1")
+      persistentNumbers.push_back(allNumbers[i]);
+  }
+  for(unsigned int i = 0; i < allStrings.size(); i++){
+    if(allStrings[i].getAttribute("Persistent") == "1")
+      persistentStrings.push_back(allStrings[i]);
+  }
+
+  // TODO FIXME: this will be removed once the new stable version of getdp is
+  // released
+  for(onelab::server::citer it = onelab::server::instance()->firstClient();
+      it != onelab::server::instance()->lastClient(); it++){
+    onelab::client *c = it->second;
+    std::vector<onelab::number> ps;
+    c->get(ps, c->getName() + "/UseCommandLine");
+    if(ps.size()) persistentNumbers.push_back(ps[0]);
+    c->get(ps, c->getName() + "/GuessModelName");
+    if(ps.size()) persistentNumbers.push_back(ps[0]);
+    std::vector<onelab::string> ps2;
+    c->get(ps2, c->getName() + "/FileExtension");
+    if(ps2.size()) persistentStrings.push_back(ps2[0]);
+  }
+  // END TODO
+
+  // clear the db
+  onelab::server::instance()->clear();
+
+  // run Gmsh client for non-python metamodels
+  if(runGmshClient && onelab::server::instance()->findClient("Gmsh") !=
+     onelab::server::instance()->lastClient())
+    onelabUtils::runGmshClient("reset", CTX::instance()->solver.autoMesh);
+
+  for(unsigned int i = 0; i < persistentNumbers.size(); i++){
+    Msg::Info("Restoring persistent parameter %s",
+              persistentNumbers[i].getName().c_str());
+    onelab::server::instance()->set(persistentNumbers[i]);
+  }
+  for(unsigned int i = 0; i < persistentStrings.size(); i++){
+    Msg::Info("Restoring persistent parameter %s",
+              persistentStrings[i].getName().c_str());
+    onelab::server::instance()->set(persistentStrings[i]);
+  }
+}
+
 void onelab_cb(Fl_Widget *w, void *data)
 {
   if(!data) return;
@@ -683,7 +805,7 @@ void onelab_cb(Fl_Widget *w, void *data)
 
   if(action == "refresh"){
     updateGraphs();
-    FlGui::instance()->rebuildTree(true);
+    FlGui::instance()->rebuildTree(false); // FIXME: true would be better
     return;
   }
 
@@ -710,28 +832,28 @@ void onelab_cb(Fl_Widget *w, void *data)
 
   if(action == "save"){
     std::vector<std::string> db = onelab::server::instance()->toChar();
-    Msg::Direct("OneLab database:");
+    Msg::Direct("ONELAB database:");
     for(unsigned int i = 0; i < db.size(); i++){
       for(unsigned int j = 0; j < db[i].size(); j++)
         if(db[i][j] == onelab::parameter::charSep()) db[i][j] = '|';
       Msg::Direct("%s", db[i].c_str());
     }
 
+    std::string fileName = "onelab.db";
+    // add user defined tag, if any
     std::vector<onelab::string> ps;
-    onelab::server::instance()->get(ps,"TAGSIMU");
-    std::string dbName, s;
-    if(ps.size())
-      dbName.assign("onelab" + ps[0].getValue() + ".db");
-    else
-      dbName = "onelab.db";
-    s.assign(SplitFileName(GModel::current()->getFileName())[0] + dbName);
+    onelab::server::instance()->get(ps,"0Metamodel/9Tag");
+    if(ps.size()){
+      fileName.assign("onelab" + ps[0].getValue() + ".db");
+      ps[0].setValue("");
+      onelab::server::instance()->set(ps[0]);
+    }
+
+    std::string s;
+    s.assign(SplitFileName(GModel::current()->getFileName())[0] + fileName);
     if(fileChooser(FILE_CHOOSER_CREATE, "Save", "*.db", s.c_str())){
+      archiveSolutionFiles(fileChooserGetName(1));
       saveDb(fileChooserGetName(1));
-      if(ps.size()){
-      	ps[0].setValue("");
-      	onelab::server::instance()->set(ps[0]);
-      	FlGui::instance()->rebuildTree(true);
-      }
     }
 
     return;
@@ -746,36 +868,20 @@ void onelab_cb(Fl_Widget *w, void *data)
     std::string db = SplitFileName(GModel::current()->getFileName())[0] + "onelab.db";
     if(fileChooser(FILE_CHOOSER_SINGLE, "Load", "*.db", db.c_str()))
       loadDb(fileChooserGetName(1));
+
+    // switch to "restore" mode"
+    // (the metamodel will use archived solution files)
+    std::vector<onelab::number> pn;
+    onelab::server::instance()->get(pn,"0Metamodel/9Use restored solution");
+    if(pn.size()){
+      pn[0].setValue(1);
+      onelab::server::instance()->set(pn[0]);
+    }
     action = "check";
   }
 
   if(action == "reset"){
-    // clear everything except command line and model name setup (maybe we
-    // should just re-run initialize?)
-    std::vector<onelab::number> useCommandLines, guessModelNames;
-    std::vector<onelab::string> fileExtensions;
-    for(onelab::server::citer it = onelab::server::instance()->firstClient();
-      it != onelab::server::instance()->lastClient(); it++){
-      onelab::client *c = it->second;
-      std::vector<onelab::number> ps;
-      c->get(ps, c->getName() + "/UseCommandLine");
-      if(ps.size()) useCommandLines.push_back(ps[0]);
-      c->get(ps, c->getName() + "/GuessModelName");
-      if(ps.size()) guessModelNames.push_back(ps[0]);
-      std::vector<onelab::string> ps2;
-      c->get(ps2, c->getName() + "/FileExtension");
-      if(ps2.size()) fileExtensions.push_back(ps2[0]);
-    }
-    onelab::server::instance()->clear();
-    if(onelab::server::instance()->findClient("Gmsh") !=
-       onelab::server::instance()->lastClient())
-      onelabUtils::runGmshClient(action, CTX::instance()->solver.autoMesh);
-    for(unsigned int i = 0; i < useCommandLines.size(); i++)
-      onelab::server::instance()->set(useCommandLines[i]);
-    for(unsigned int i = 0; i < guessModelNames.size(); i++)
-      onelab::server::instance()->set(guessModelNames[i]);
-    for(unsigned int i = 0; i < fileExtensions.size(); i++)
-      onelab::server::instance()->set(fileExtensions[i]);
+    resetDb(true);
     action = "check";
   }
 
@@ -785,53 +891,42 @@ void onelab_cb(Fl_Widget *w, void *data)
 
   if(action == "compute") initializeLoops();
 
-  // check whether we are running a metamodel (.ol or .py)
-  std::vector<onelab::number> n;
-  onelab::server::instance()->get(n, "IsMetamodel");
-  bool isMetamodel = (n.size() && n[0].getValue());
-  onelab::server::instance()->get(n, "IsPyMetamodel");
-  bool isPyMetamodel = (n.size() && n[0].getValue());
-
   do{ // enter loop
 
-    // if the client is a not a metamodel, run Gmsh
-    if(!isMetamodel && !isPyMetamodel){
-      if(onelabUtils::runGmshClient(action, CTX::instance()->solver.autoMesh))
-        drawContext::global()->draw();
-    }
+    //run Gmsh client for non-python metamodels
+    if(onelabUtils::runGmshClient(action, CTX::instance()->solver.autoMesh))
+      drawContext::global()->draw();
 
     if(action == "compute")
       FlGui::instance()->onelab->checkForErrors("Gmsh");
     if(FlGui::instance()->onelab->stop()) break;
 
-    if(isMetamodel){
-#if defined(HAVE_ONELAB_METAMODEL)
-      if(metamodel(action)){
-        OpenProject(GModel::current()->getFileName());
-        drawContext::global()->draw();
-      }
-#endif
-    }
-    else{
-      // iterate over all other clients (there should normally only be one)
-      for(onelab::server::citer it = onelab::server::instance()->firstClient();
-          it != onelab::server::instance()->lastClient(); it++){
-        onelab::client *c = it->second;
-        if(c->getName() == "Gmsh" || // local Gmsh client
-           c->getName() == "Listen" || // unknown client connecting through "-listen"
-           c->getName() == "GmshRemote") // distant post-processing Gmsh client
-          continue;
-        if(action != "initialize") onelabUtils::guessModelName(c);
-        onelab::string o(c->getName() + "/Action", action);
-        o.setVisible(false);
-        o.setNeverChanged(true);
-        onelab::server::instance()->set(o);
+    // iterate over all other clients (there should normally only be one)
+    for(onelab::server::citer it = onelab::server::instance()->firstClient();
+	it != onelab::server::instance()->lastClient(); it++){
+      onelab::client *c = it->second;
+      if(c->getName() == "Gmsh" || // local Gmsh client
+	 c->getName() == "Listen" || // unknown client connecting through "-listen"
+	 c->getName() == "GmshRemote") // distant post-processing Gmsh client
+	continue;
+      if(action != "initialize") onelabUtils::guessModelName(c);
+      onelab::string o(c->getName() + "/Action", action);
+      o.setVisible(false);
+      o.setNeverChanged(true);
+      onelab::server::instance()->set(o);
+      // we should skip the computation here if no parameter has changed for the
+      // solver:
+      //
+      //if(action != "compute" || onelab::server::instance()->getChanged(c->getName()))
         c->run();
-        if(action == "compute"){
-          FlGui::instance()->onelab->checkForErrors(c->getName());
-        }
-        if(FlGui::instance()->onelab->stop()) break;
+      if(action == "compute"){
+        // after computing with this solver, mark the parameters as unchanged
+        // for this solver
+        onelab::server::instance()->setChanged(false, c->getName());
+
+	FlGui::instance()->onelab->checkForErrors(c->getName());
       }
+      if(FlGui::instance()->onelab->stop()) break;
     }
 
     if(action != "initialize"){
@@ -874,8 +969,8 @@ void onelab_option_cb(Fl_Widget *w, void *data)
     CTX::instance()->solver.autoMesh = val;
   else if(what == "merge")
     CTX::instance()->solver.autoMergeFile = val;
-  else if(what == "hide")
-    CTX::instance()->solver.autoHideNewViews = val;
+  else if(what == "show")
+    CTX::instance()->solver.autoShowViews = val ? 2 : 0;
   else if(what == "step")
     CTX::instance()->solver.autoShowLastStep = val;
   else if(what == "invisible"){
@@ -1031,7 +1126,7 @@ static unsigned char gear_bits[] = {
 #endif
 
 onelabGroup::onelabGroup(int x, int y, int w, int h, const char *l)
-  : Fl_Group(x,y,w,h,l), _stop(false)
+  : Fl_Group(x,y,w,h,l), _stop(false), _enableTreeWidgetResize(false)
 {
   int col = FL_BACKGROUND2_COLOR;
   color(col);
@@ -1093,7 +1188,7 @@ onelabGroup::onelabGroup(int x, int y, int w, int h, const char *l)
              FL_MENU_TOGGLE);
   _gear->add("Merge results automatically", 0, onelab_option_cb, (void*)"merge",
              FL_MENU_TOGGLE);
-  _gear->add("Hide new views", 0, onelab_option_cb, (void*)"hide",
+  _gear->add("Show new views", 0, onelab_option_cb, (void*)"show",
              FL_MENU_TOGGLE);
   _gear->add("Always show last step", 0, onelab_option_cb, (void*)"step",
              FL_MENU_TOGGLE);
@@ -1151,14 +1246,21 @@ void onelabGroup::_addParameter(T &p)
   Fl_Color c;
   if(getFlColor(p.getAttribute("Highlight"), c)) highlight = true;
   Fl_Tree_Item *n = _tree->add(p.getName().c_str());
+  n->labelsize(FL_NORMAL_SIZE + 4);
   _tree->begin();
-  Fl_Widget *widget = _addParameterWidget(p, n, highlight, c);
-  _treeWidgets.push_back(widget);
+  int ww = _baseWidth - (n->depth() + 1) * _indent;
+  ww *= _widgetLabelRatio; // FIXME CHANGE THIS
+  int hh = n->labelsize() + 4;
+  Fl_Group *grp = new Fl_Group(1, 1, ww, hh);
+  Fl_Widget *widget = _addParameterWidget(p, ww, hh, n, highlight, c);
+  grp->end();
+  if(!_enableTreeWidgetResize) grp->resizable(0);
+  _treeWidgets.push_back(grp);
   widget->copy_label(p.getShortName().c_str());
   std::string help = p.getLabel().size() ? p.getLabel() : p.getShortName();
   if(p.getHelp().size()) help += ":\n" + p.getHelp();
   widget->copy_tooltip(help.c_str());
-  n->widget(widget);
+  n->widget(grp);
   _tree->end();
 }
 
@@ -1167,18 +1269,22 @@ void onelabGroup::_addMenu(const std::string &path, Fl_Callback *callback, void
   Fl_Tree_Item *n = _tree->add(path.c_str());
   _tree->begin();
   int ww = _baseWidth - (n->depth() + 1) * _indent;
-  Fl_Button *but = new Fl_Button(1, 1, ww, 1);
+  int hh = n->labelsize() + 4;
+  Fl_Group *grp = new Fl_Group(1, 1, ww, hh);
+  Fl_Button *but = new Fl_Button(1, 1, ww, hh);
   but->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
   but->callback(callback, data);
   but->box(FL_FLAT_BOX);
   but->color(_tree->color());
   but->selection_color(_tree->color());
-  _treeWidgets.push_back(but);
+  grp->end();
+  if(!_enableTreeWidgetResize) grp->resizable(0);
+  _treeWidgets.push_back(grp);
   std::string label = path;
   std::string::size_type last = path.find_last_of('/');
   if(last != std::string::npos) label = path.substr(last + 1);
   but->copy_label(label.c_str());
-  n->widget(but);
+  n->widget(grp);
   _tree->end();
 }
 
@@ -1188,10 +1294,14 @@ void onelabGroup::_addSolverMenu(int num)
   path << "0Modules/Solver/Solver" << num;
   Fl_Tree_Item *n = _tree->add(path.str().c_str());
   int ww = _baseWidth - (n->depth() + 1) * _indent;
+  int hh = n->labelsize() + 4;
   _tree->begin();
-  solverButton *but = new solverButton(1, 1, ww, 1, num, _tree->color());
-  _treeWidgets.push_back(but);
-  n->widget(but);
+  Fl_Group *grp = new Fl_Group(1, 1, ww, hh);
+  new solverButton(1, 1, ww, hh, num, _tree->color());
+  grp->end();
+  if(!_enableTreeWidgetResize) grp->resizable(0);
+  _treeWidgets.push_back(grp);
+  n->widget(grp);
   _tree->end();
 }
 
@@ -1201,10 +1311,14 @@ void onelabGroup::_addViewMenu(int num)
   path << "0Modules/Post-processing/View" << num;
   Fl_Tree_Item *n = _tree->add(path.str().c_str());
   int ww = _baseWidth - (n->depth() + 1) * _indent;
+  int hh = n->labelsize() + 4;
   _tree->begin();
-  viewButton *but = new viewButton(1, 1, ww, 1, num, _tree->color());
-  _treeWidgets.push_back(but);
-  n->widget(but);
+  Fl_Group *grp = new Fl_Group(1, 1, ww, hh);
+  new viewButton(1, 1, ww, hh, num, _tree->color());
+  grp->end();
+  if(!_enableTreeWidgetResize) grp->resizable(0);
+  _treeWidgets.push_back(grp);
+  n->widget(grp);
   _tree->end();
 }
 
@@ -1213,14 +1327,32 @@ viewButton *onelabGroup::getViewButton(int num)
   char tmp[256];
   sprintf(tmp, "0Modules/Post-processing/View%d", num);
   Fl_Tree_Item *n = _tree->find_item(tmp);
-  if(n) return (viewButton*)n->widget();
+  if(n){
+    Fl_Group *grp = (Fl_Group*)n->widget();
+    return (viewButton*)grp->child(0);
+  }
   return 0;
 }
 
-static void setGmshOption(onelab::number &n)
+template <class T>
+static void setGmshOption(T &n)
 {
   std::string opt = n.getAttribute("GmshOption");
   if(opt.empty()) return;
+  if(opt == "ResetDatabase"){ // special option to reset the onelab db
+    resetDb(false);
+    FlGui::instance()->rebuildTree(false);
+    return;
+  }
+  if(opt == "Reset"){ // reset db + models except current one
+    resetDb(false);
+    for(int i = PView::list.size() - 1; i >= 0; i--)
+      delete PView::list[i];
+    for(int i = GModel::list.size() - 1; i >= 0; i--)
+      if(GModel::list[i] != GModel::current()) delete GModel::list[i];
+    FlGui::instance()->rebuildTree(false);
+    return;
+  }
   std::string::size_type dot = opt.find('.');
   if(dot == std::string::npos) return;
   GmshSetOption(opt.substr(0, dot), opt.substr(dot + 1), n.getValue());
@@ -1237,8 +1369,8 @@ static void onelab_number_check_button_cb(Fl_Widget *w, void *data)
     Fl_Check_Button *o = (Fl_Check_Button*)w;
     onelab::number old = numbers[0];
     numbers[0].setValue(o->value());
-    onelab::server::instance()->set(numbers[0]);
     setGmshOption(numbers[0]);
+    onelab::server::instance()->set(numbers[0]);
     autoCheck(old, numbers[0]);
   }
 }
@@ -1254,8 +1386,8 @@ static void onelab_number_choice_cb(Fl_Widget *w, void *data)
     std::vector<double> choices = numbers[0].getChoices();
     onelab::number old = numbers[0];
     if(o->value() < (int)choices.size()) numbers[0].setValue(choices[o->value()]);
-    onelab::server::instance()->set(numbers[0]);
     setGmshOption(numbers[0]);
+    onelab::server::instance()->set(numbers[0]);
     autoCheck(old, numbers[0]);
   }
 }
@@ -1279,8 +1411,8 @@ static void onelab_number_input_range_cb(Fl_Widget *w, void *data)
     o->doCallbackOnValues(true);
     numbers[0].setAttribute("Loop", o->loop());
     numbers[0].setAttribute("Graph", o->graph());
-    onelab::server::instance()->set(numbers[0]);
     setGmshOption(numbers[0]);
+    onelab::server::instance()->set(numbers[0]);
     updateGraphs();
     autoCheck(old, numbers[0]);
   }
@@ -1300,20 +1432,16 @@ static void onelab_number_output_range_cb(Fl_Widget *w, void *data)
   }
 }
 
-Fl_Widget *onelabGroup::_addParameterWidget(onelab::number &p, Fl_Tree_Item *n,
-                                            bool highlight, Fl_Color c)
+Fl_Widget *onelabGroup::_addParameterWidget(onelab::number &p, int ww, int hh,
+                                            Fl_Tree_Item *n, bool highlight, Fl_Color c)
 {
-  n->labelsize(FL_NORMAL_SIZE + 4);
-  int ww = _baseWidth - (n->depth() + 1) * _indent;
-  ww *= _widgetLabelRatio;
-
   char *path = strdup(getPath(n).c_str());
   _treeStrings.push_back(path);
 
   // enumeration (display choices as value labels, not numbers)
   if(p.getChoices().size() &&
      p.getChoices().size() == p.getValueLabels().size()){
-    Fl_Choice *but = new Fl_Choice(1, 1, ww, 1);
+    Fl_Choice *but = new Fl_Choice(1, 1, ww, hh);
     std::vector<Fl_Menu_Item> menu;
     std::map<double, std::string> labels(p.getValueLabels());
     for(std::map<double, std::string>::iterator it = labels.begin();
@@ -1343,7 +1471,7 @@ Fl_Widget *onelabGroup::_addParameterWidget(onelab::number &p, Fl_Tree_Item *n,
   if(p.getChoices().size() == 2 &&
      p.getChoices()[0] == 0 && p.getChoices()[1] == 1){
     n->labelsize(FL_NORMAL_SIZE + 2);
-    Fl_Check_Button *but = new Fl_Check_Button(1, 1, ww / _widgetLabelRatio, 1);
+    Fl_Check_Button *but = new Fl_Check_Button(1, 1, ww / _widgetLabelRatio, hh);
     but->box(FL_FLAT_BOX);
     but->color(_tree->color());
     but->value(p.getValue());
@@ -1355,7 +1483,7 @@ Fl_Widget *onelabGroup::_addParameterWidget(onelab::number &p, Fl_Tree_Item *n,
 
   // non-editable value
   if(p.getReadOnly()){
-    outputRange *but = new outputRange(1, 1, ww, 1);
+    outputRange *but = new outputRange(1, 1, ww, hh);
     but->callback(onelab_number_output_range_cb, (void*)path);
     but->value(p.getValue());
     but->align(FL_ALIGN_RIGHT);
@@ -1365,7 +1493,7 @@ Fl_Widget *onelabGroup::_addParameterWidget(onelab::number &p, Fl_Tree_Item *n,
   }
 
   // general number input
-  inputRange *but = new inputRange(1, 1, ww, 1, onelab::parameter::maxNumber(),
+  inputRange *but = new inputRange(1, 1, ww, hh, onelab::parameter::maxNumber(),
                                    p.getAttribute("ReadOnlyRange") == "1");
   but->value(p.getValue());
   but->minimum(p.getMin());
@@ -1391,6 +1519,7 @@ static void onelab_string_button_cb(Fl_Widget *w, void *data)
     std::string tmp = FixRelativePath(GModel::current()->getFileName(),
                                       strings[0].getValue());
     MergeFile(tmp);
+    setGmshOption(strings[0]);
     autoCheck(strings[0], strings[0], true);
     drawContext::global()->draw();
   }
@@ -1406,6 +1535,7 @@ static void onelab_string_input_cb(Fl_Widget *w, void *data)
     Fl_Input *o = (Fl_Input*)w;
     onelab::string old = strings[0];
     strings[0].setValue(o->value());
+    setGmshOption(strings[0]);
     onelab::server::instance()->set(strings[0]);
     autoCheck(old, strings[0]);
   }
@@ -1432,6 +1562,7 @@ static void onelab_string_input_choice_cb(Fl_Widget *w, void *data)
     }
     if(choices.size())
       strings[0].setAttribute("MultipleSelection", choices);
+    setGmshOption(strings[0]);
     onelab::server::instance()->set(strings[0]);
     autoCheck(old, strings[0]);
   }
@@ -1478,17 +1609,15 @@ static void multiple_selection_menu_cb(Fl_Widget *w, void *data)
   but->do_callback();
 }
 
-Fl_Widget *onelabGroup::_addParameterWidget(onelab::string &p, Fl_Tree_Item *n,
-                                            bool highlight, Fl_Color c)
+Fl_Widget *onelabGroup::_addParameterWidget(onelab::string &p, int ww, int hh,
+                                            Fl_Tree_Item *n, bool highlight, Fl_Color c)
 {
-  int ww = _baseWidth - (n->depth() + 1) * _indent;
-
   char *path = strdup(getPath(n).c_str());
   _treeStrings.push_back(path);
 
   // macro button
   if(p.getAttribute("Macro") == "Gmsh"){
-    Fl_Button *but = new Fl_Button(1, 1, ww, 1);
+    Fl_Button *but = new Fl_Button(1, 1, ww / _widgetLabelRatio, hh);
     but->box(FL_FLAT_BOX);
     but->color(_tree->color());
     but->selection_color(_tree->color());
@@ -1498,12 +1627,9 @@ Fl_Widget *onelabGroup::_addParameterWidget(onelab::string &p, Fl_Tree_Item *n,
     return but;
   }
 
-  ww *= _widgetLabelRatio;
-  n->labelsize(FL_NORMAL_SIZE + 4);
-
   // non-editable value
   if(p.getReadOnly()){
-    Fl_Output *but = new Fl_Output(1, 1, ww, 1);
+    Fl_Output *but = new Fl_Output(1, 1, ww, hh);
     but->value(p.getValue().c_str());
     but->align(FL_ALIGN_RIGHT);
     if(highlight) but->color(c);
@@ -1512,7 +1638,7 @@ Fl_Widget *onelabGroup::_addParameterWidget(onelab::string &p, Fl_Tree_Item *n,
 
   // simple string (no menu)
   if(p.getChoices().empty() && p.getKind() != "file"){
-    Fl_Input *but = new Fl_Input(1, 1, ww, 1);
+    Fl_Input *but = new Fl_Input(1, 1, ww, hh);
     but->value(p.getValue().c_str());
     but->callback(onelab_string_input_cb, (void*)path);
     but->when(FL_WHEN_ENTER_KEY);
@@ -1522,7 +1648,7 @@ Fl_Widget *onelabGroup::_addParameterWidget(onelab::string &p, Fl_Tree_Item *n,
   }
 
   // general string input
-  Fl_Input_Choice *but = new Fl_Input_Choice(1, 1, ww, 1);
+  Fl_Input_Choice *but = new Fl_Input_Choice(1, 1, ww, hh);
   std::string multipleSelection = p.getAttribute("MultipleSelection");
   if(multipleSelection.size())
     but->menubutton()->callback(multiple_selection_menu_cb, but);
@@ -1574,26 +1700,22 @@ static void onelab_region_input_cb(Fl_Widget *w, void *data)
   }
 }
 
-Fl_Widget *onelabGroup::_addParameterWidget(onelab::region &p, Fl_Tree_Item *n,
-                                            bool highlight, Fl_Color c)
+Fl_Widget *onelabGroup::_addParameterWidget(onelab::region &p, int ww, int hh,
+                                            Fl_Tree_Item *n, bool highlight, Fl_Color c)
 {
-  n->labelsize(FL_NORMAL_SIZE + 4);
-  int ww = _baseWidth - (n->depth() + 1) * _indent;
-  ww *= _widgetLabelRatio;
-
   char *path = strdup(getPath(n).c_str());
   _treeStrings.push_back(path);
 
   // non-editable value
   if(p.getReadOnly()){
-    inputRegion *but = new inputRegion(1, 1, ww, 1, true);
+    inputRegion *but = new inputRegion(1, 1, ww, hh, true);
     but->value(p.getValue());
     but->align(FL_ALIGN_RIGHT);
     if(highlight) but->color(c);
     return but;
   }
 
-  inputRegion *but = new inputRegion(1, 1, ww, 1, false);
+  inputRegion *but = new inputRegion(1, 1, ww, hh, false);
   but->value(p.getValue());
   but->align(FL_ALIGN_RIGHT);
   but->callback(onelab_region_input_cb, (void*)path);
@@ -1601,16 +1723,12 @@ Fl_Widget *onelabGroup::_addParameterWidget(onelab::region &p, Fl_Tree_Item *n,
   return but;
 }
 
-Fl_Widget *onelabGroup::_addParameterWidget(onelab::function &p, Fl_Tree_Item *n,
-                                            bool highlight, Fl_Color c)
+Fl_Widget *onelabGroup::_addParameterWidget(onelab::function &p, int ww, int hh,
+                                            Fl_Tree_Item *n, bool highlight, Fl_Color c)
 {
-  n->labelsize(FL_NORMAL_SIZE + 4);
-  int ww = _baseWidth - (n->depth() + 1) * _indent;
-  ww *= _widgetLabelRatio;
-
   // non-editable value
   if(1 || p.getReadOnly()){
-    Fl_Output *but = new Fl_Output(1, 1, ww, 1);
+    Fl_Output *but = new Fl_Output(1, 1, ww, hh);
     but->value("TODO function");
     but->align(FL_ALIGN_RIGHT);
     if(highlight) but->color(c);
@@ -1687,17 +1805,18 @@ void onelabGroup::rebuildTree(bool deleteWidgets)
   for(Fl_Tree_Item *n = _tree->first(); n; n = n->next()){
     if(n->has_children()){
       int ww = _baseWidth - (n->depth() + 1) * _indent;
+      int hh = n->labelsize() + 4;
       _tree->begin();
 #if 0 // FIXME this can crash FLTK when submenus are intially closed (somehow
       // the widget is badly positioned and overlaps the open icon, leading to
       // a corrupted Fl_Tree_Item)
-      Fl_Button *but = new Fl_Button(1, 1, ww, 1);
+      Fl_Button *but = new Fl_Button(1, 1, ww, hh);
       but->box(FL_NO_BOX);
       but->clear_visible_focus();
       but->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
       but->callback(onelab_subtree_cb, (void*)n);
 #else
-      Fl_Box *but = new Fl_Box(1, 1, ww, 1);
+      Fl_Box *but = new Fl_Box(1, 1, ww, hh);
       //but->labelfont(FL_HELVETICA_ITALIC);
       but->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
 #endif
@@ -1836,16 +1955,15 @@ std::string onelabGroup::getPath(Fl_Tree_Item *item)
   return std::string(path);
 }
 
-void onelabGroup::rebuildSolverList()
+void onelabGroup::updateGearMenu()
 {
-  // update gear menu
   Fl_Menu_Item* menu = (Fl_Menu_Item*)_gear->menu();
   int values[8] = {CTX::instance()->solver.autoSaveDatabase,
                    CTX::instance()->solver.autoArchiveOutputFiles,
                    CTX::instance()->solver.autoCheck,
                    CTX::instance()->solver.autoMesh,
                    CTX::instance()->solver.autoMergeFile,
-                   CTX::instance()->solver.autoHideNewViews,
+                   CTX::instance()->solver.autoShowViews,
                    CTX::instance()->solver.autoShowLastStep,
                    CTX::instance()->solver.showInvisibleParameters};
   for(int i = 0; i < 8; i++){
@@ -1855,8 +1973,12 @@ void onelabGroup::rebuildSolverList()
     else
       menu[idx].clear();
   }
+}
+
+void onelabGroup::rebuildSolverList()
+{
+  updateGearMenu();
 
-  // update Gmsh solver menu
   std::vector<std::string> names, exes, hosts;
   for(int i = 0; i < NUM_SOLVERS; i++){
     if(opt_solver_name(i, GMSH_GET, "").size()){
@@ -1935,6 +2057,8 @@ void onelabGroup::addSolver(const std::string &name, const std::string &executab
 
 void solver_cb(Fl_Widget *w, void *data)
 {
+  if(!FlGui::instance()->onelab) return;
+
   int num = (intptr_t)data;
   if(num >= 0){
     std::string name = opt_solver_name(num, GMSH_GET, "");
@@ -1948,7 +2072,10 @@ void solver_cb(Fl_Widget *w, void *data)
 
   if(CTX::instance()->solver.autoSaveDatabase){
     std::string db = SplitFileName(GModel::current()->getFileName())[0] + "onelab.db";
-    if(!StatFile(db)) loadDb(db);
+    if(!StatFile(db)){
+      loadDb(db);
+      CTX::instance()->launchSolverAtStartup = -1;
+    }
   }
 
   if(FlGui::instance()->onelab->isBusy())
@@ -1962,6 +2089,7 @@ void solver_cb(Fl_Widget *w, void *data)
       onelab_cb(0, (void*)"check");
     else
       onelab_cb(0, (void*)"refresh");
+    FlGui::instance()->onelab->updateGearMenu();
   }
 
   CTX::instance()->launchSolverAtStartup = -1;
@@ -1979,6 +2107,10 @@ void solver_batch_cb(Fl_Widget *w, void *data)
     return;
   }
 
+  onelab::number n("0Metamodel/Batch", CTX::instance()->batch);
+  n.setVisible(false);
+  onelab::server::instance()->set(n);
+
   // create client
   onelab::localNetworkClient *c = new gmshLocalNetworkClient(name, exe, host);
   c->setIndex(num);
@@ -2011,6 +2143,7 @@ void solver_batch_cb(Fl_Widget *w, void *data)
     o.setValue("compute");
     onelab::server::instance()->set(o);
     c->run();
+    onelab::server::instance()->setChanged(false, c->getName());
   } while(incrementLoops());
 
   if(CTX::instance()->solver.autoSaveDatabase ||
@@ -2026,38 +2159,3 @@ void flgui_wait_cb(double time)
   FlGui::instance()->wait(time);
 }
 
-int metamodel_cb(const std::string &name, const std::string &action)
-{
-#if defined(HAVE_ONELAB_METAMODEL)
-  if(FlGui::instance()->onelab->isBusy())
-    FlGui::instance()->onelab->show();
-  else{
-    initializeMetamodel(Msg::GetExecutableName(),Msg::GetOnelabClient(),
-			&flgui_wait_cb,Msg::GetVerbosity());
-
-    onelab::number n("IsMetamodel", 1.);
-    n.setVisible(false);
-    onelab::server::instance()->set(n);
-    std::vector<std::string> split = SplitFileName(name);
-    onelab::string s1("Arguments/WorkingDir",
-		      split[0].size() ? split[0] : GetCurrentWorkdir());
-    s1.setVisible(false);
-    s1.setAttribute("NotInDb","True");
-    onelab::server::instance()->set(s1);
-    onelab::string s2("Arguments/FileName", split[1]);
-    s2.setVisible(false);
-    onelab::server::instance()->set(s2);
-
-    FlGui::instance()->onelab->rebuildSolverList();
-
-    if(FlGui::instance()->available()){
-      onelab_cb(0, (void*)"check");
-    }
-    else
-      metamodel(action);
-  }
-  return 1;
-#else
-  return 0;
-#endif
-}
diff --git a/Fltk/onelabGroup.h b/Fltk/onelabGroup.h
index b9bbc44..f125872 100644
--- a/Fltk/onelabGroup.h
+++ b/Fltk/onelabGroup.h
@@ -29,16 +29,17 @@ class onelabGroup : public Fl_Group{
   int _minWindowWidth, _minWindowHeight;
   double _widgetLabelRatio;
   std::set<std::string> _manuallyClosed;
+  bool _enableTreeWidgetResize;
   void _computeWidths();
   template <class T> void _addParameter(T &p);
-  Fl_Widget *_addParameterWidget(onelab::number &p, Fl_Tree_Item *n,
-                                 bool highlight, Fl_Color c);
-  Fl_Widget *_addParameterWidget(onelab::string &p, Fl_Tree_Item *n,
-                                 bool highlight, Fl_Color c);
-  Fl_Widget *_addParameterWidget(onelab::region &p, Fl_Tree_Item *n,
-                                 bool highlight, Fl_Color c);
-  Fl_Widget *_addParameterWidget(onelab::function &p, Fl_Tree_Item *n,
-                                 bool highlight, Fl_Color c);
+  Fl_Widget *_addParameterWidget(onelab::number &p, int ww, int hh,
+                                 Fl_Tree_Item *n, bool highlight, Fl_Color c);
+  Fl_Widget *_addParameterWidget(onelab::string &p, int ww, int hh,
+                                 Fl_Tree_Item *n, bool highlight, Fl_Color c);
+  Fl_Widget *_addParameterWidget(onelab::region &p, int ww, int hh,
+                                 Fl_Tree_Item *n, bool highlight, Fl_Color c);
+  Fl_Widget *_addParameterWidget(onelab::function &p, int ww, int hh,
+                                 Fl_Tree_Item *n, bool highlight, Fl_Color c);
   void _addMenu(const std::string &path, Fl_Callback *callback, void *data);
   void _addSolverMenu(int num);
   void _addViewMenu(int num);
@@ -46,8 +47,10 @@ class onelabGroup : public Fl_Group{
   void _addGmshMenus();
  public:
   onelabGroup(int x, int y, int w, int h, const char *l=0);
+  void updateGearMenu();
   void rebuildSolverList();
   void rebuildTree(bool deleteWidgets);
+  void enableTreeWidgetResize(bool value){ _enableTreeWidgetResize = value; }
   void redrawTree(){ _tree->redraw(); }
   void openTreeItem(const std::string &name);
   void setButtonVisibility();
diff --git a/Fltk/openglWindow.cpp b/Fltk/openglWindow.cpp
index 2399c23..6a83afb 100644
--- a/Fltk/openglWindow.cpp
+++ b/Fltk/openglWindow.cpp
@@ -342,7 +342,8 @@ int openglWindow::handle(int event)
     return Fl_Gl_Window::handle(event);
 
   case FL_PUSH:
-    if(Fl::event_clicks() == 1){ // double-click
+    if(Fl::event_clicks() == 1 && !selectionMode){
+      // double-click and not in selection mode
       status_options_cb(0, (void*)"quick_access");
       Fl::event_clicks(-1);
       return 1;
diff --git a/Fltk/optionWindow.cpp b/Fltk/optionWindow.cpp
index 1fc37c5..a4deb5d 100644
--- a/Fltk/optionWindow.cpp
+++ b/Fltk/optionWindow.cpp
@@ -18,6 +18,7 @@ typedef unsigned long intptr_t;
 #include "GmshDefines.h"
 #include "GmshMessage.h"
 #include "FlGui.h"
+#include "inputValue.h"
 #include "optionWindow.h"
 #include "gamepadWindow.h"
 #include "graphicWindow.h"
@@ -47,14 +48,6 @@ extern StringXColor PostProcessingOptions_Color[] ;
 extern StringXColor ViewOptions_Color[] ;
 extern StringXColor PrintOptions_Color[] ;
 
-class engineeringValueInput : public Fl_Value_Input
-{
- public:
-  engineeringValueInput(int x, int y, int w, int h, const char *l=0) :
-    Fl_Value_Input(x, y, w, h, l) {}
-  virtual int format(char *buffer){ return sprintf(buffer, "%g", value()); }
-};
-
 static Fl_Menu_Item menu_point_display[] = {
   {"Color dot",   0, 0, 0},
   {"3D sphere",   0, 0, 0},
@@ -130,6 +123,7 @@ Fl_Menu_Item menu_font_names[] = {
   {"Courier-BoldOblique",   0, 0, (void*)FL_COURIER_BOLD_ITALIC},
   {"Symbol",                0, 0, (void*)FL_SYMBOL},
   {"ZapfDingbats",          0, 0, (void*)FL_ZAPF_DINGBATS},
+  {"Screen",                0, 0, (void*)FL_SCREEN},
   {0}
 };
 
@@ -358,7 +352,6 @@ static void general_options_ok_cb(Fl_Widget *w, void *data)
   opt_general_axes(0, GMSH_SET, o->general.choice[4]->value());
   opt_general_background_gradient(0, GMSH_SET, o->general.choice[5]->value());
 
-
   if( (opt_general_gamepad(0, GMSH_GET, 0) !=  o->general.butt[19]->value() )
       || ( opt_general_camera_mode(0, GMSH_GET, 0) !=  o->general.butt[18]->value() )){
     if((opt_general_gamepad(0, GMSH_GET, 0) == 1 )
@@ -380,10 +373,10 @@ static void general_options_ok_cb(Fl_Widget *w, void *data)
   opt_general_camera_aperture(0, GMSH_SET, o->general.value[31]->value());
   if(opt_general_stereo_mode(0, GMSH_GET, 0) != o->general.butt[17]->value()) {
     opt_general_stereo_mode(0, GMSH_SET, o->general.butt[17]->value());
-    for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++) FlGui::instance()->graph[i]->setStereo((bool)CTX::instance()->stereo);
+    for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++)
+      FlGui::instance()->graph[i]->setStereo((bool)CTX::instance()->stereo);
   }
 
-
   if(CTX::instance()->fastRedraw)
     CTX::instance()->post.draw = CTX::instance()->mesh.draw = 0;
   drawContext::global()->draw();
@@ -534,7 +527,8 @@ static void mesh_options_ok_cb(Fl_Widget *w, void *data)
   opt_mesh_angle_smooth_normals(0, GMSH_SET, o->mesh.value[18]->value());
 
   opt_mesh_recombine3d_all(0, GMSH_SET, o->mesh.butt[22]->value());
-  opt_mesh_point_type(0, GMSH_SET, o->mesh.choice[0]->value());  opt_mesh_algo2d(0, GMSH_SET,
+  opt_mesh_point_type(0, GMSH_SET, o->mesh.choice[0]->value());
+  opt_mesh_algo2d(0, GMSH_SET,
                   (o->mesh.choice[2]->value() == 1) ? ALGO_2D_MESHADAPT :
                   (o->mesh.choice[2]->value() == 2) ? ALGO_2D_DELAUNAY :
                   (o->mesh.choice[2]->value() == 3) ? ALGO_2D_FRONTAL :
@@ -1799,7 +1793,6 @@ optionWindow::optionWindow(int deltaFontSize)
         {"Vertical", 0, 0, 0},
         {"Horizontal", 0, 0, 0},
         {"Radial", 0, 0, 0},
-        {"Image", 0, 0, 0},
         {0}
       };
 
@@ -3213,7 +3206,7 @@ optionWindow::optionWindow(int deltaFontSize)
         (L + 2 * WB + ss  , 2 * WB + 2 * BH, ss, BH);
       view.value[53] = new Fl_Value_Input
         (L + 2 * WB + 2*ss, 2 * WB + 2 * BH, ss, BH, " X");
-      view.value[40] = new engineeringValueInput
+      view.value[40] = new inputValueFloat
         (L + 2 * WB + IW  , 2 * WB + 2 * BH, 7*IW/10, BH);
 
       view.value[54] = new Fl_Value_Input
@@ -3222,7 +3215,7 @@ optionWindow::optionWindow(int deltaFontSize)
         (L + 2 * WB + ss  , 2 * WB + 3 * BH, ss, BH);
       view.value[56] = new Fl_Value_Input
         (L + 2 * WB + 2*ss, 2 * WB + 3 * BH, ss, BH, " Y +");
-      view.value[41] = new engineeringValueInput
+      view.value[41] = new inputValueFloat
         (L + 2 * WB + IW  , 2 * WB + 3 * BH, 7*IW/10, BH);
 
       view.value[57] = new Fl_Value_Input
@@ -3231,21 +3224,21 @@ optionWindow::optionWindow(int deltaFontSize)
         (L + 2 * WB + ss  , 2 * WB + 4 * BH, ss, BH);
       view.value[59] = new Fl_Value_Input
         (L + 2 * WB + 2*ss, 2 * WB + 4 * BH, ss, BH, " Z");
-      view.value[42] = new engineeringValueInput
+      view.value[42] = new inputValueFloat
         (L + 2 * WB + IW  , 2 * WB + 4 * BH, 7*IW/10, BH);
 
       Fl_Box *b2 = new Fl_Box
         (FL_NO_BOX, L + 2 * WB + 2 * IW-3*WB, 2 * WB + 1 * BH, 7*IW/10, BH, "Raise:");
       b2->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT);
 
-      view.value[43] = new engineeringValueInput
+      view.value[43] = new inputValueFloat
         (L + 2 * WB + 2 * IW-3*WB, 2 * WB + 2 * BH, 7*IW/10, BH);
-      view.value[44] = new engineeringValueInput
+      view.value[44] = new inputValueFloat
         (L + 2 * WB + 2 * IW-3*WB, 2 * WB + 3 * BH, 7*IW/10, BH);
-      view.value[45] = new engineeringValueInput
+      view.value[45] = new inputValueFloat
         (L + 2 * WB + 2 * IW-3*WB, 2 * WB + 4 * BH, 7*IW/10, BH);
 
-      view.value[46] = new engineeringValueInput
+      view.value[46] = new inputValueFloat
         (L + 2 * WB, 2 * WB + 5 * BH, 3*ss, BH, "Normal raise");
 
       for(int i = 40; i <= 46; i++){
@@ -3273,7 +3266,7 @@ optionWindow::optionWindow(int deltaFontSize)
       view.choice[11]->add("Self");
       view.choice[11]->callback(view_options_ok_cb);
 
-      view.value[2] = new engineeringValueInput
+      view.value[2] = new inputValueFloat
         (L + 2 * WB, 2 * WB + 8 * BH, IW, BH, "Factor");
       view.value[2]->align(FL_ALIGN_RIGHT);
       view.value[2]->when(FL_WHEN_RELEASE);
@@ -3375,7 +3368,7 @@ optionWindow::optionWindow(int deltaFontSize)
         view.value[60]->align(FL_ALIGN_RIGHT);
         view.value[60]->callback(view_options_ok_cb);
 
-        view.value[63] = new engineeringValueInput
+        view.value[63] = new inputValueFloat
           (L + 2 * WB, 2 * WB + 8 * BH, IW, BH, "Displacement factor");
         view.value[63]->minimum(0.);
         view.value[63]->maximum(1.);
@@ -3635,7 +3628,7 @@ void optionWindow::updateViewGroup(int index)
   opt_view_axes_zmin(index, GMSH_GUI, 0);
   opt_view_axes_zmax(index, GMSH_GUI, 0);
   for(int i = 13; i <= 18; i++){
-    view.value[i]->step(CTX::instance()->lc / 200.);
+    view.value[i]->step(CTX::instance()->lc / 200., 1);
     view.value[i]->minimum(-CTX::instance()->lc);
     view.value[i]->maximum(CTX::instance()->lc);
   }
@@ -3684,7 +3677,7 @@ void optionWindow::updateViewGroup(int index)
   opt_view_offset1(index, GMSH_GUI, 0);
   opt_view_offset2(index, GMSH_GUI, 0);
   for(int i = 40; i <= 42; i++) {
-    view.value[i]->step(val1 / 200.);
+    view.value[i]->step(val1 / 200., 1);
     view.value[i]->minimum(-val1);
     view.value[i]->maximum(val1);
   }
@@ -3702,7 +3695,7 @@ void optionWindow::updateViewGroup(int index)
   opt_view_raise2(index, GMSH_GUI, 0);
   opt_view_normal_raise(index, GMSH_GUI, 0);
   for(int i = 43; i <= 46; i++) {
-    view.value[i]->step(val2 / 200.);
+    view.value[i]->step(val2 / 200., 1);
     view.value[i]->minimum(-val2);
     view.value[i]->maximum(val2);
   }
@@ -3712,7 +3705,7 @@ void optionWindow::updateViewGroup(int index)
   opt_view_gen_raise0(index, GMSH_GUI, "");
   opt_view_gen_raise1(index, GMSH_GUI, "");
   opt_view_gen_raise2(index, GMSH_GUI, "");
-  view.value[2]->step(val2 / 200.);
+  view.value[2]->step(val2 / 200., 1);
   view.value[2]->minimum(-val2);
   view.value[2]->maximum(val2);
 
@@ -3752,7 +3745,7 @@ void optionWindow::updateViewGroup(int index)
 
   opt_view_displacement_factor(index, GMSH_GUI, 0);
   double val3 = 2. * CTX::instance()->lc / maxval;
-  view.value[63]->step(val3 / 100.);
+  view.value[63]->step(val3 / 100., 1);
   view.value[63]->maximum(val3);
 
   opt_view_external_view(index, GMSH_GUI, 0);
@@ -3868,7 +3861,8 @@ void optionWindow::activate(const char *what)
   }
   else if(!strcmp(what, "general_camera")){
     if(general.butt[19]->value()){
-      if(CTX::instance()->gamepad && CTX::instance()->gamepad->active ) general.gamepadconfig->activate();
+      if(CTX::instance()->gamepad && CTX::instance()->gamepad->active)
+        general.gamepadconfig->activate();
     }
     else{
       general.gamepadconfig->deactivate();
diff --git a/Fltk/optionWindow.h b/Fltk/optionWindow.h
index 0e67892..b7dea7b 100644
--- a/Fltk/optionWindow.h
+++ b/Fltk/optionWindow.h
@@ -22,7 +22,7 @@
 #include "colorbarWindow.h"
 #include "gamepadWindow.h"
 
-#define NUM_FONTS 14
+#define NUM_FONTS 15
 extern Fl_Menu_Item menu_font_names[];
 
 class optionWindow{
diff --git a/Fltk/pluginWindow.cpp b/Fltk/pluginWindow.cpp
index 316b55e..a448d99 100644
--- a/Fltk/pluginWindow.cpp
+++ b/Fltk/pluginWindow.cpp
@@ -91,7 +91,7 @@ static void plugin_browser_cb(Fl_Widget *w, void *data)
     if(sxn->function){
       p->dialogBox->value[i]->callback(plugin_input_value_cb, (void*)sxn->function);
       if(iView >= 0){
-        p->dialogBox->value[i]->step(sxn->function(iView, 1, 0.));
+        p->dialogBox->value[i]->step(sxn->function(iView, 1, 0.), 1);
         p->dialogBox->value[i]->minimum(sxn->function(iView, 2, 0.));
         p->dialogBox->value[i]->maximum(sxn->function(iView, 3, 0.));
       }
diff --git a/Fltk/projectionEditor.cpp b/Fltk/projectionEditor.cpp
index 33b4b42..1c5f905 100644
--- a/Fltk/projectionEditor.cpp
+++ b/Fltk/projectionEditor.cpp
@@ -808,7 +808,7 @@ projection::projection(fourierProjectionFace *f, int x, int y, int w, int h,
       parameters.push_back(v);
       v->maximum(bounds.max()[i] + 10. * CTX::instance()->lc);
       v->minimum(bounds.min()[i] - 10. * CTX::instance()->lc);
-      v->step(CTX::instance()->lc / 100.);
+      v->step(CTX::instance()->lc / 100., 1);
       v->value(pc[i]);
       v->label((i == 0) ? "X" : (i == 1) ? "Y" : "Z");
     }
@@ -858,7 +858,7 @@ projection::projection(fourierProjectionFace *f, int x, int y, int w, int h,
       parameters.push_back(v);
       v->maximum(CTX::instance()->lc * 10.);
       v->minimum(CTX::instance()->lc / 100.);
-      v->step(CTX::instance()->lc / 100.);
+      v->step(CTX::instance()->lc / 100., 1);
       v->value(CTX::instance()->lc / 10.);
       v->label((i == 0) ? "Scale0" : (i == 1) ? "Scale1" : "Scale2");
     }
@@ -869,7 +869,7 @@ projection::projection(fourierProjectionFace *f, int x, int y, int w, int h,
     Fl_Value_Input *v = new Fl_Value_Input(x, y + (9 + i) * bh, bb, bh);
     v->maximum(10. * CTX::instance()->lc);
     v->minimum(-10. * CTX::instance()->lc);
-    v->step(CTX::instance()->lc / 100.);
+    v->step(CTX::instance()->lc / 100., 1);
     v->label(strdup(ps->GetLabel(i).c_str()));
     v->value(ps->GetParameter(i));
     parameters.push_back(v);
diff --git a/Fltk/visibilityWindow.cpp b/Fltk/visibilityWindow.cpp
index 1b8ed65..f2be0d7 100644
--- a/Fltk/visibilityWindow.cpp
+++ b/Fltk/visibilityWindow.cpp
@@ -471,6 +471,7 @@ static void _add_vertex(GVertex *gv, Fl_Tree *tree, std::string path)
   std::ostringstream vertex;
   vertex << path << "Point " << gv->tag() << "/";
   Fl_Tree_Item *n = tree->add(vertex.str().c_str());
+  if(!n) return;
   if(gv->getVisibility()) n->select(1);
   n->user_data((void*)gv);
   n->close();
@@ -481,6 +482,7 @@ static void _add_edge(GEdge *ge, Fl_Tree *tree, std::string path)
   std::ostringstream edge;
   edge << path << "Line " << ge->tag() << "/";
   Fl_Tree_Item *n = tree->add(edge.str().c_str());
+  if(!n) return;
   if(ge->getVisibility()) n->select(1);
   n->user_data((void*)ge);
   n->close();
@@ -495,6 +497,7 @@ static void _add_face(GFace *gf, Fl_Tree *tree, std::string path)
   std::ostringstream face;
   face << path << "Surface " << gf->tag() << "/";
   Fl_Tree_Item *n = tree->add(face.str().c_str());
+  if(!n) return;
   if(gf->getVisibility()) n->select(1);
   n->user_data((void*)gf);
   n->close();
@@ -508,6 +511,7 @@ static void _add_region(GRegion *gr, Fl_Tree *tree, std::string path)
   std::ostringstream region;
   region << path << "Volume " << gr->tag() << "/";
   Fl_Tree_Item *n = tree->add(region.str().c_str());
+  if(!n) return;
   if(gr->getVisibility()) n->select(1);
   n->user_data((void*)gr);
   n->close();
@@ -532,28 +536,28 @@ static void _add_physical_group(int dim, int num, std::vector<GEntity*> &ge,
   case 3:
     group << "Physical Volume " << num << name << "/";
     n = tree->add(group.str().c_str());
-    n->close();
+    if(n) n->close();
     for(unsigned int i = 0; i < ge.size(); i++)
       _add_region((GRegion*)ge[i], tree, group.str());
     break;
   case 2:
     group << "Physical Surface " << num << name << "/";
     n = tree->add(group.str().c_str());
-    n->close();
+    if(n) n->close();
     for(unsigned int i = 0; i < ge.size(); i++)
       _add_face((GFace*)ge[i], tree, group.str());
     break;
   case 1:
     group << "Physical Line " << num << name << "/";
     n = tree->add(group.str().c_str());
-    n->close();
+    if(n) n->close();
     for(unsigned int i = 0; i < ge.size(); i++)
       _add_edge((GEdge*)ge[i], tree, group.str());
     break;
   case 0:
     group << "Physical Point " << num << name << "/";
     n = tree->add(group.str().c_str());
-    n->close();
+    if(n) n->close();
     for(unsigned int i = 0; i < ge.size(); i++)
       _add_vertex((GVertex*)ge[i], tree, group.str());
     break;
@@ -592,13 +596,14 @@ static void _rebuild_tree_browser(bool force)
 
     Fl_Tree_Item *n;
     n = FlGui::instance()->visibility->tree->add(model.str().c_str());
-    if(m->getVisibility()) n->select(1);
-    n->close();
+    if(n){
+      if(m->getVisibility()) n->select(1);
+      n->close();
+    }
 
     std::string elementary = model.str() + "Elementary entities/";
     n = FlGui::instance()->visibility->tree->add(elementary.c_str());
-    n->close();
-
+    if(n) n->close();
     for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); it++)
       _add_region(*it, FlGui::instance()->visibility->tree, elementary);
     for(GModel::fiter it = m->firstFace(); it != m->lastFace(); it++)
@@ -610,7 +615,7 @@ static void _rebuild_tree_browser(bool force)
 
     std::string physical = model.str() + "Physical groups/";
     n = FlGui::instance()->visibility->tree->add(physical.c_str());
-    n->close();
+    if(n) n->close();
 
     std::map<int, std::vector<GEntity*> > groups[4];
     m->getPhysicalGroups(groups);
diff --git a/Geo/CMakeLists.txt b/Geo/CMakeLists.txt
index 2c56e9b..ed90152 100644
--- a/Geo/CMakeLists.txt
+++ b/Geo/CMakeLists.txt
@@ -5,6 +5,7 @@
 
 set(SRC
   boundaryLayersData.cpp
+  closestPoint.cpp
   intersectCurveSurface.cpp
   GEntity.cpp STensor3.cpp
     GVertex.cpp GEdge.cpp GFace.cpp GRegion.cpp
@@ -12,7 +13,7 @@ set(SRC
   GRegionCompound.cpp GRbf.cpp
     gmshVertex.cpp gmshEdge.cpp gmshFace.cpp gmshRegion.cpp
    gmshSurface.cpp
-    OCCVertex.cpp OCCEdge.cpp OCCFace.cpp OCCRegion.cpp
+   OCCVertex.cpp OCCEdge.cpp OCCFace.cpp OCCRegion.cpp
     discreteEdge.cpp discreteFace.cpp discreteRegion.cpp
     fourierEdge.cpp fourierFace.cpp fourierProjectionFace.cpp
   ACISVertex.cpp
diff --git a/Geo/Cell.cpp b/Geo/Cell.cpp
index dc95c70..38c86a2 100644
--- a/Geo/Cell.cpp
+++ b/Geo/Cell.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #include "Cell.h"
 #include "MTriangle.h"
@@ -230,6 +230,7 @@ int Cell::findBdCellOrientation(Cell* cell, int i) const
       if(_v[MTriangle::edges_tri(i, 1)]->getNum() == v[0]->getNum() &&
          _v[MTriangle::edges_tri(i, 0)]->getNum() == v[1]->getNum())
         return -1;
+      break;
     case 4:
       if(_v[MQuadrangle::edges_quad(i, 0)]->getNum() == v[0]->getNum() &&
          _v[MQuadrangle::edges_quad(i, 1)]->getNum() == v[1]->getNum())
@@ -237,6 +238,7 @@ int Cell::findBdCellOrientation(Cell* cell, int i) const
       if(_v[MQuadrangle::edges_quad(i, 0)]->getNum() == v[1]->getNum() &&
          _v[MQuadrangle::edges_quad(i, 1)]->getNum() == v[0]->getNum())
         return -1;
+      break;
     default: return 0;
     }
   case 3:
@@ -266,6 +268,7 @@ int Cell::findBdCellOrientation(Cell* cell, int i) const
          _v[MTetrahedron::faces_tetra(i, 1)]->getNum() == v[1]->getNum() &&
          _v[MTetrahedron::faces_tetra(i, 2)]->getNum() == v[0]->getNum())
         return -1;
+      break;
     case 5:
       if(i < 4) {
         if(_v[MPyramid::faces_pyramid(i, 0)]->getNum() == v[0]->getNum() &&
@@ -336,6 +339,7 @@ int Cell::findBdCellOrientation(Cell* cell, int i) const
           return -1;
       }
       return 0;
+      break;
     case 6:
       if(i < 2) {
         if(_v[MPrism::faces_prism(i, 0)]->getNum() == v[0]->getNum() &&
@@ -405,6 +409,7 @@ int Cell::findBdCellOrientation(Cell* cell, int i) const
            _v[MPrism::faces_prism(i, 3)]->getNum() == v[2]->getNum())
           return -1;
       }
+      break;
     case 8:
       if(_v[MHexahedron::faces_hexa(i, 0)]->getNum() == v[0]->getNum() &&
          _v[MHexahedron::faces_hexa(i, 1)]->getNum() == v[1]->getNum() &&
@@ -446,6 +451,7 @@ int Cell::findBdCellOrientation(Cell* cell, int i) const
          _v[MHexahedron::faces_hexa(i, 2)]->getNum() == v[3]->getNum() &&
          _v[MHexahedron::faces_hexa(i, 3)]->getNum() == v[2]->getNum())
         return -1;
+      break;
     default: return 0;
     }
   default: return 0;
@@ -574,8 +580,8 @@ void Cell::removeBoundaryCell(Cell* cell, bool other)
   biter it = _bd.find(cell);
   if(it != _bd.end()){
     it->second.set(0);
-    if(it->second.geto() == 0) _bd.erase(it);
     if(other) it->first->removeCoboundaryCell(this, false);
+    if(it->second.geto() == 0) _bd.erase(it);
   }
 }
 
@@ -584,8 +590,8 @@ void Cell::removeCoboundaryCell(Cell* cell, bool other)
   biter it = _cbd.find(cell);
   if(it != _cbd.end()){
     it->second.set(0);
-    if(it->second.geto() == 0) _cbd.erase(it);
     if(other) it->first->removeBoundaryCell(this, false);
+    if(it->second.geto() == 0) _cbd.erase(it);
   }
 }
 
diff --git a/Geo/Cell.h b/Geo/Cell.h
index 3473a89..9cb6f9b 100644
--- a/Geo/Cell.h
+++ b/Geo/Cell.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #ifndef _CELL_H_
 #define _CELL_H_
diff --git a/Geo/CellComplex.cpp b/Geo/CellComplex.cpp
index 7405363..5b85852 100644
--- a/Geo/CellComplex.cpp
+++ b/Geo/CellComplex.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #include "CellComplex.h"
 #include "MElement.h"
@@ -317,6 +317,7 @@ int CellComplex::coreduction(Cell* startCell, int omit,
     Qset.erase(s);
     if(s->getBoundarySize() == 1 &&
        inSameDomain(s, s->firstBoundary()->first) &&
+       !s->getImmune() && !s->firstBoundary()->first->getImmune() &&
        abs(s->firstBoundary()->second.get()) < 2){
       s->getBoundary(bd_s);
       removeCell(s);
@@ -356,7 +357,7 @@ int CellComplex::reduction(int dim, int omit,
       Cell* cell = *cit;
       if(cell->getCoboundarySize() == 1 &&
          inSameDomain(cell, cell->firstCoboundary()->first) &&
-         !cell->getImmune() &&
+         !cell->getImmune() && !cell->firstCoboundary()->first->getImmune() &&
          !cell->firstCoboundary()->first->getImmune() &&
          abs(cell->firstCoboundary()->second.get()) < 2){
 	cit++;
@@ -399,6 +400,7 @@ int CellComplex::coreduction(int dim, int omit,
       Cell* cell = *cit;
       if(cell->getBoundarySize() == 1 &&
          inSameDomain(cell, cell->firstBoundary()->first) &&
+         !cell->getImmune() && !cell->firstBoundary()->first->getImmune() &&
          abs(cell->firstBoundary()->second.get()) < 2) {
         ++cit;
 	if(dim-1 == omit){
@@ -775,7 +777,8 @@ int CellComplex::cocombine(int dim)
         Cell* c2 = it->first;
 
         if(!(*c1 == *c2) && abs(or1) == abs(or2)
-           && inSameDomain(s, c1) && inSameDomain(s, c2)){
+           && inSameDomain(s, c1) && inSameDomain(s, c2)
+           && c1->getImmune() == c2->getImmune()){
 
           removeCell(s, true, false);
 
diff --git a/Geo/CellComplex.h b/Geo/CellComplex.h
index 8dadc53..cade65d 100644
--- a/Geo/CellComplex.h
+++ b/Geo/CellComplex.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #ifndef _CELLCOMPLEX_H_
 #define _CELLCOMPLEX_H_
diff --git a/Geo/Chain.cpp b/Geo/Chain.cpp
index cdc9de9..e87b32d 100644
--- a/Geo/Chain.cpp
+++ b/Geo/Chain.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #include "Chain.h"
 #include "MLine.h"
diff --git a/Geo/Chain.h b/Geo/Chain.h
index 8ef7981..124f420 100644
--- a/Geo/Chain.h
+++ b/Geo/Chain.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #ifndef _CHAIN_H_
 #define _CHAIN_H_
diff --git a/Geo/ChainComplex.cpp b/Geo/ChainComplex.cpp
index 87ce204..eef0be4 100644
--- a/Geo/ChainComplex.cpp
+++ b/Geo/ChainComplex.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #include "GmshConfig.h"
 #if defined(HAVE_KBIPACK)
@@ -193,11 +193,19 @@ void ChainComplex::Inclusion(int lowDim, int highDim)
 
   int rows = gmp_matrix_rows(Bbasis);
   int cols = gmp_matrix_cols(Bbasis);
-  if(rows < cols) return;
+  if(rows < cols) {
+    destroy_gmp_matrix(Zbasis);
+    destroy_gmp_matrix(Bbasis);
+    return;
+  }
 
   rows = gmp_matrix_rows(Zbasis);
   cols = gmp_matrix_cols(Zbasis);
-  if(rows < cols) return;
+  if(rows < cols) {
+    destroy_gmp_matrix(Zbasis);
+    destroy_gmp_matrix(Bbasis);
+    return;
+  }
 
   // inv(U)*A*inv(V) = S
   gmp_normal_form* normalForm
@@ -210,6 +218,7 @@ void ChainComplex::Inclusion(int lowDim, int highDim)
 
     gmp_matrix_get_elem(elem, i, i, normalForm->canonical);
     if(mpz_cmp_si(elem,0) == 0){
+      destroy_gmp_matrix(Bbasis);
       destroy_gmp_normal_form(normalForm);
       return;
     }
@@ -240,7 +249,12 @@ void ChainComplex::Inclusion(int lowDim, int highDim)
       if(mpz_cmp_si(remainder, 0) == 0){
         gmp_matrix_set_elem(result, i, j, LB);
       }
-      else return;
+      else {
+        destroy_gmp_matrix(Zbasis);
+        destroy_gmp_matrix(LB);
+        destroy_gmp_normal_form(normalForm);
+        return;
+      }
     }
   }
 
@@ -391,7 +405,6 @@ void ChainComplex::computeHomology(bool dual)
   return;
 }
 
-
 void ChainComplex::matrixTest()
 {
   const int rows = 3;
@@ -401,11 +414,11 @@ void ChainComplex::matrixTest()
   for(int i = 1; i<=rows*cols; i++) elems[i-1] = i;
 
   gmp_matrix* matrix = create_gmp_matrix_int(rows, cols, elems);
-
   gmp_matrix* copymatrix = copy_gmp_matrix(matrix, 3, 2, 3, 5);
-
   printMatrix(matrix);
   printMatrix(copymatrix);
+  destroy_gmp_matrix(matrix);
+  destroy_gmp_matrix(copymatrix);
 }
 
 std::vector<int> ChainComplex::getCoeffVector(int dim, int chainNumber)
@@ -437,9 +450,8 @@ std::vector<int> ChainComplex::getCoeffVector(int dim, int chainNumber)
 
 gmp_matrix* ChainComplex::getBasis(int dim, int basis)
 {
-  if(dim > -2 && dim < 5 && basis == 2) return _codH[dim+1];
+  if(dim > -2 && dim < 4 && basis == 2) return _codH[dim+1];
   if(dim < 0 || dim > 4) return NULL;
-  if(basis == 0) return create_gmp_matrix_identity(getBasisSize(dim, 0));
   else if(basis == 1) return _kerH[dim];
   else if(basis == 3) return _Hbasis[dim];
   else return NULL;
@@ -452,9 +464,10 @@ void ChainComplex::getBasisChain(std::map<Cell*, int, Less_Cell>& chain,
   gmp_matrix* basisMatrix = getBasis(dim, basis);
 
   chain.clear();
-  if(dim < 0 || dim > 4) return;
-  if(basisMatrix == NULL
-     || (int)gmp_matrix_cols(basisMatrix) < num) return;
+  if(dim < 0 || dim > 3) return;
+  if(basisMatrix == NULL || (int)gmp_matrix_cols(basisMatrix) < num){
+    return;
+  }
 
   int elemi;
   long int elemli;
@@ -464,7 +477,7 @@ void ChainComplex::getBasisChain(std::map<Cell*, int, Less_Cell>& chain,
   int torsion = 1;
   if(basis == 3) torsion = getTorsion(dim, num);
 
-  for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
+  for(citer cit = this->firstCell(dim); cit != this->lastCell(dim); cit++){
     Cell* cell = cit->first;
     int index = cit->second;
     gmp_matrix_get_elem(elem, index, num, basisMatrix);
@@ -682,354 +695,4 @@ void ChainComplex::deImmuneCells(std::map<Cell*, int, Less_Cell>& cells)
   }
 }
 
-HomologySequence::HomologySequence(ChainComplex* subcomplex,
-				   ChainComplex* complex,
-				   ChainComplex* relcomplex)
-{
-  _subcomplex = subcomplex;
-  _complex = complex;
-  _relcomplex = relcomplex;
-
-  mpz_t elem;
-  mpz_init_set_si(elem, -1);
-  for(int i = 0; i < 4; i++){
-    _Ic_sub[i] = NULL;
-    _Ic_rel[i] = NULL;
-
-    _Dh[i] = NULL;
-    _invDh[i] = NULL;
-
-    _Jh[i] = NULL;
-    _Ih[i] = NULL;
-    _invJh[i] = NULL;
-    _invIh[i] = NULL;
-
-  }
-
-  findIcMaps();
-
-  /*findDhMap(1);
-  findInvIhMap(0);
-  blockHBasis(_Dh[1], _invIh[0], _subcomplex, 0);*/
-
-  /*findJhMap(1);
-  findInvDhMap(1);
-  blockHBasis(_Jh[1], _invDh[1], _relcomplex, 1);*/
-
-}
-
-HomologySequence::~HomologySequence()
-{
-  for(int i = 0; i < 4; i++){
-    destroy_gmp_matrix(_Ic_sub[i]);
-    destroy_gmp_matrix(_Ic_rel[i]);
-    destroy_gmp_matrix(_Ih[i]);
-    destroy_gmp_matrix(_Jh[i]);
-    destroy_gmp_matrix(_invIh[i]);
-    destroy_gmp_matrix(_invJh[i]);
-    destroy_gmp_matrix(_Dh[i]);
-    destroy_gmp_matrix(_invDh[i]);
-  }
-}
-
-void HomologySequence::findIcMaps()
-{
-  for(int i = 0; i < 4; i++){
-    mpz_t one;
-    mpz_init_set_si(one, 1);
-    if(_complex->getBasisSize(i, 0) > 0
-       && _subcomplex->getBasisSize(i, 0) > 0){
-      _Ic_sub[i] = create_gmp_matrix_zero(_complex->getBasisSize(i, 0),
-					  _subcomplex->getBasisSize(i, 0));
-      //printf("rows %d, cols %d. \n", _complex->getBasisSize(i, 0),
-      //	     _subcomplex->getBasisSize(i, 0));
-      for(ChainComplex::citer cit = _complex->firstCell(i);
-	  cit != _complex->lastCell(i); cit++){
-	Cell* cell = cit->first;
-	int row = cit->second;
-	int col = _subcomplex->getCellIndex(cell);
-	//printf("row %d, col %d. \n", row, col);
-	if(col != 0) gmp_matrix_set_elem(one, row, col, _Ic_sub[i]);
-      }
-    }
-
-    if(_complex->getBasisSize(i, 0) > 0
-       && _relcomplex->getBasisSize(i, 0) > 0){
-      _Ic_rel[i] = create_gmp_matrix_zero(_complex->getBasisSize(i, 0),
-					  _relcomplex->getBasisSize(i, 0));
-      //printf("rows %d, cols %d. \n", _complex->getBasisSize(i, 0),
-      for(ChainComplex::citer cit = _complex->firstCell(i);
-	  cit != _complex->lastCell(i); cit++){
-	Cell* cell = cit->first;
-	int row = cit->second;
-	int col = _relcomplex->getCellIndex(cell);
-	//printf("row %d, col %d. \n", row, col);
-	if(col != 0) gmp_matrix_set_elem(one, row, col, _Ic_rel[i]);
-      }
-    }
-    mpz_clear(one);
-  }
-}
-
-void HomologySequence::findIhMap(int i)
-{
-  if(_Ic_sub[i] != NULL
-     && _complex->getBasisSize(i, 3) > 0
-     && _subcomplex->getBasisSize(i, 3) > 0){
-    gmp_matrix* IH = copy_gmp_matrix(_Ic_sub[i], 1, 1,
-				     gmp_matrix_rows(_Ic_sub[i]),
-				     gmp_matrix_cols(_Ic_sub[i]));
-    gmp_matrix_right_mult(IH, _subcomplex->getBasis(i, 3));
-    _Ih[i] = createIncMap(IH, _complex->getBasis(i, 3));
-  }
-}
-
-void HomologySequence::findInvIhMap(int i)
-{
-  if(_Ic_sub[i] != NULL
-     && _complex->getBasisSize(i, 3) > 0
-     && _subcomplex->getBasisSize(i, 3) > 0){
-    gmp_matrix* IH = copy_gmp_matrix(_Ic_sub[i], 1, 1,
-				     gmp_matrix_rows(_Ic_sub[i]),
-				     gmp_matrix_cols(_Ic_sub[i]));
-    gmp_matrix_transp(IH);
-    gmp_matrix_right_mult(IH, _complex->getBasis(i, 3));
-    _invIh[i] = createIncMap(IH, _subcomplex->getBasis(i, 3));
-  }
-}
-
-void HomologySequence::findJhMap(int i)
-{
-  if(_Ic_rel[i] != NULL
-     && _complex->getBasisSize(i, 3) > 0
-     && _relcomplex->getBasisSize(i, 3) > 0){
-    gmp_matrix* JH = copy_gmp_matrix(_Ic_rel[i], 1, 1,
-				     gmp_matrix_rows(_Ic_rel[i]),
-				     gmp_matrix_cols(_Ic_rel[i]));
-    gmp_matrix_transp(JH);
-    gmp_matrix_right_mult(JH, _complex->getBasis(i, 3));
-    _Jh[i] = createIncMap(JH, _relcomplex->getBasis(i, 3));
-  }
-}
-
-void HomologySequence::findInvJhMap(int i)
-{
-  if(_Ic_rel[i] != NULL
-   && _complex->getBasisSize(i, 3) > 0
-     && _relcomplex->getBasisSize(i, 3) > 0){
-    gmp_matrix* JH = copy_gmp_matrix(_Ic_rel[i], 1, 1,
-				     gmp_matrix_rows(_Ic_rel[i]),
-				     gmp_matrix_cols(_Ic_rel[i]));
-    gmp_matrix_right_mult(JH, _relcomplex->getBasis(i, 3));
-    _invJh[i] = createIncMap(JH, _complex->getBasis(i, 3));
-  }
-}
-
-void HomologySequence::findDhMap(int i)
-{
-  if(i > 0 && _relcomplex->getBasisSize(i, 3) > 0
-     && _subcomplex->getBasisSize(i-1, 3) > 0
-     && _complex->getBoundaryOp(i) != NULL){
-    gmp_matrix* JDIH = copy_gmp_matrix(_Ic_sub[i-1], 1, 1,
-				       gmp_matrix_rows(_Ic_sub[i-1]),
-				       gmp_matrix_cols(_Ic_sub[i-1]));
-    gmp_matrix_transp(JDIH);
-    gmp_matrix_right_mult(JDIH, _complex->getBoundaryOp(i));
-    gmp_matrix_right_mult(JDIH, _Ic_rel[i]);
-    gmp_matrix_right_mult(JDIH, _relcomplex->getBasis(i, 3));
-    _Dh[i] = createIncMap(JDIH, _subcomplex->getBasis(i-1, 3));
-  }
-}
-
-void HomologySequence::findInvDhMap(int i)
-{
-  if(i > 0 && _relcomplex->getBasisSize(i, 3) > 0
-     && _subcomplex->getBasisSize(i-1, 3) > 0
-     && _complex->getBoundaryOp(i) != NULL){
-    gmp_matrix* JDIH = copy_gmp_matrix(_Ic_rel[i], 1, 1,
-				       gmp_matrix_rows(_Ic_rel[i]),
-				       gmp_matrix_cols(_Ic_rel[i]));
-    gmp_matrix_transp(JDIH);
-    gmp_matrix* bd = _complex->getBoundaryOp(i);
-    gmp_matrix_transp(bd);
-    gmp_matrix_right_mult(JDIH, bd);
-    gmp_matrix_transp(bd);
-    gmp_matrix_right_mult(JDIH, _Ic_sub[i-1]);
-    gmp_matrix_right_mult(JDIH, _subcomplex->getBasis(i-1, 3));
-    _invDh[i] = createIncMap(JDIH, _relcomplex->getBasis(i, 3));
-  }
-}
-
-//i: a->b  : aBasis = bBasis*incMap
-gmp_matrix* HomologySequence::createIncMap(gmp_matrix* domBasis,
-					   gmp_matrix* codBasis)
-{
-  if(domBasis == NULL || codBasis == NULL){
-    printf("ERROR: null matrix given. \n");
-    return NULL;
-  }
-
-  int rows = gmp_matrix_rows(domBasis);
-  int cols = gmp_matrix_cols(domBasis);
-  if(rows < cols || rows == 0 || cols == 0) return NULL;
-
-  rows = gmp_matrix_rows(codBasis);
-  cols = gmp_matrix_cols(codBasis);
-  if(rows < cols || rows == 0 || cols == 0) return NULL;
-
-  gmp_matrix* temp = codBasis;
-  codBasis = copy_gmp_matrix(temp, 1, 1,
-			     gmp_matrix_rows(temp),
-			     gmp_matrix_cols(temp));
-  // inv(U)*A*inv(V) = S
-  gmp_normal_form* normalForm
-    = create_gmp_Smith_normal_form(codBasis, INVERTED, INVERTED);
-
-  mpz_t elem;
-  mpz_init(elem);
-
-  for(int i = 1; i <= cols; i++){
-    gmp_matrix_get_elem(elem, i, i, normalForm->canonical);
-    if(mpz_cmp_si(elem,0) == 0){
-      destroy_gmp_normal_form(normalForm);
-      return NULL;
-    }
-  }
-
-  gmp_matrix_left_mult(normalForm->left, domBasis);
-  gmp_matrix* LB = copy_gmp_matrix(domBasis, 1, 1,
-				   gmp_matrix_cols(codBasis),
-				   gmp_matrix_cols(domBasis));
-  destroy_gmp_matrix(domBasis);
-
-  rows = gmp_matrix_rows(LB);
-  cols = gmp_matrix_cols(LB);
-
-  mpz_t divisor;
-  mpz_init(divisor);
-  mpz_t remainder;
-  mpz_init(remainder);
-  mpz_t result;
-  mpz_init(result);
-
-  for(int i = 1; i <= rows; i++){
-    gmp_matrix_get_elem(divisor, i, i, normalForm->canonical);
-    for(int j = 1; j <= cols; j++){
-      gmp_matrix_get_elem(elem, i, j, LB);
-      mpz_cdiv_qr(result, remainder, elem, divisor);
-      if(mpz_cmp_si(remainder, 0) == 0){
-        gmp_matrix_set_elem(result, i, j, LB);
-      }
-      else return NULL;
-    }
-  }
-
-  gmp_matrix_left_mult(normalForm->right, LB);
-
-  mpz_clear(elem);
-  mpz_clear(divisor);
-  mpz_clear(result);
-  destroy_gmp_normal_form(normalForm);
-  return LB;
-}
-
-gmp_matrix* HomologySequence::removeZeroCols(gmp_matrix* matrix)
-{
-  mpz_t elem;
-  mpz_init(elem);
-
-  int rows = gmp_matrix_rows(matrix);
-  int cols = gmp_matrix_cols(matrix);
-  //printMatrix(matrix);
-  std::vector<int> zcols;
-
-  for(int j = 1; j <= cols; j++){
-    bool zcol = true;
-    for(int i = 1; i <= rows; i++){
-      gmp_matrix_get_elem(elem, i, j, matrix);
-      if(mpz_cmp_si(elem, 0) != 0){
-	zcol = false;
-	break;
-      }
-    }
-    if(zcol) zcols.push_back(j);
-  }
-  if(zcols.empty()) return matrix;
-
-  gmp_matrix* newMatrix = create_gmp_matrix_zero(rows, cols-zcols.size());
-  if(cols-zcols.size() == 0) return newMatrix;
-
-  int k = 0;
-  for(int j = 1; j <= cols; j++){
-    if((int)zcols.size()-1 < k) break;
-    if(zcols.at(k) == j) { k++; continue; }
-    for(int i = 1; i <= rows; i++){
-      gmp_matrix_get_elem(elem, i, j, matrix);
-      gmp_matrix_set_elem(elem, i, j-k, newMatrix);
-    }
-  }
-  //printMatrix(newMatrix);
-  destroy_gmp_matrix(matrix);
-  mpz_clear(elem);
-  return newMatrix;
-}
-
-void HomologySequence::blockHBasis(gmp_matrix* block1T,
-				   gmp_matrix* block2T,
-				   ChainComplex* complex, int dim)
-{
-  printMatrix(block1T);
-  printMatrix(block2T);
-
-  if(block1T == NULL && block2T == NULL) return;
-
-  gmp_matrix* Hbasis = complex->getBasis(dim, 3);
-
-  if(block1T == NULL && block2T != NULL){
-    gmp_matrix_right_mult(Hbasis, block2T);
-    printMatrix(Hbasis);
-    return;
-  }
-  if(block1T != NULL && block2T == NULL){
-    gmp_matrix_right_mult(Hbasis, block1T);
-    printMatrix(Hbasis);
-    return;
-  }
-
-  int rows = gmp_matrix_rows(Hbasis);
-  int cols = gmp_matrix_cols(Hbasis);
-  gmp_matrix* temp1 = copy_gmp_matrix(Hbasis, 1, 1, rows, cols);
-  gmp_matrix* temp2 = copy_gmp_matrix(Hbasis, 1, 1, rows, cols);
-
-  printMatrix(temp1);
-  printMatrix(temp2);
-
-  gmp_matrix_right_mult(temp1, block1T);
-  gmp_matrix_right_mult(temp2, block2T);
-
-  printMatrix(temp1);
-  printMatrix(temp2);
-  temp1 = removeZeroCols(temp1);
-  temp2 = removeZeroCols(temp2);
-  printMatrix(temp1);
-  printMatrix(temp2);
-
-  int bcol = gmp_matrix_cols(temp1);
-
-  mpz_t elem;
-  mpz_init(elem);
-  for(int i = 1; i <= rows; i++){
-    for(int j = 1; j <= cols; j++){
-      if(j <= bcol) gmp_matrix_get_elem(elem, i, j, temp1);
-      else gmp_matrix_get_elem(elem, i, j-bcol, temp2);
-      gmp_matrix_set_elem(elem, i, j, Hbasis);
-    }
-  }
-
-  printMatrix(Hbasis);
-  mpz_clear(elem);
-  destroy_gmp_matrix(temp1);
-  destroy_gmp_matrix(temp2);
-}
-
 #endif
diff --git a/Geo/ChainComplex.h b/Geo/ChainComplex.h
index 8712eda..9804057 100644
--- a/Geo/ChainComplex.h
+++ b/Geo/ChainComplex.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #ifndef _CHAINCOMPLEX_H_
 #define _CHAINCOMPLEX_H_
@@ -110,7 +110,6 @@ class ChainComplex
 
   int getDim() const { return _dim; }
 
-  // 0 : C basis (chains)
   // 1 : Z basis (cycles)
   // 2 : B basis (boundaries)
   // 3 : H basis (homology)
@@ -179,61 +178,6 @@ class ChainComplex
   void matrixTest();
 };
 
-
-// An experimental class to modify computed bases for homology spaces
-// so that the basis chains are decomposed according to the long
-// exact homology sequence.
-class HomologySequence
-{
- private:
-  ChainComplex* _subcomplex;
-  ChainComplex* _complex;
-  ChainComplex* _relcomplex;
-
-  gmp_matrix* _Ic_sub[4];
-  gmp_matrix* _Ic_rel[4];
-
-  gmp_matrix* _Ih[4];
-  gmp_matrix* _Jh[4];
-  gmp_matrix* _invIh[4];
-  gmp_matrix* _invJh[4];
-
-
-  gmp_matrix* _Dh[4];
-  gmp_matrix* _invDh[4];
-
-  void findIcMaps();
-  void findIhMap(int i);
-  void findInvIhMap(int i);
-  void findJhMap(int i);
-  void findInvJhMap(int i);
-  void findDhMap(int i);
-  void findInvDhMap(int i);
-
- public:
-
-  HomologySequence(ChainComplex* subcomplex, ChainComplex* complex,
-		   ChainComplex* relcomplex);
-  ~HomologySequence();
-
-  // create an inclusion map from domBasis to codBasis
-  // (deletes domBasis, leaves codBasis unaffected)
-  gmp_matrix* createIncMap(gmp_matrix* domBasis,
-			   gmp_matrix* codBasis);
-
-
-  gmp_matrix* removeZeroCols(gmp_matrix* matrix);
-  void blockHBasis(gmp_matrix* block1T, gmp_matrix* block2T,
-		   ChainComplex* complex, int dim);
-
-  int printMatrix(gmp_matrix* matrix){
-    if(matrix == NULL){ printf("NULL matrix. \n"); return 0; }
-    printf("%d rows and %d columns\n",
-           (int)gmp_matrix_rows(matrix), (int)gmp_matrix_cols(matrix));
-    return gmp_matrix_printf(matrix); }
-
-};
-
 #endif
 #endif
 
diff --git a/Geo/Curvature.h b/Geo/Curvature.h
index ff83f0e..27c9229 100644
--- a/Geo/Curvature.h
+++ b/Geo/Curvature.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
-#ifndef _CURVATUREL_H_
+#ifndef _CURVATURE_H_
 #define _CURVATURE_H_
 
 #include "GModel.h"
@@ -58,7 +58,7 @@ private:
     bool _isMapInitialized;
 
     //Model and list of selected entities with give physical tag:
-    GModel* _model;    
+    GModel* _model;
     GFaceList _EntityArray;
 
     //Averaged vertex normals
@@ -181,7 +181,7 @@ public:
   typedef enum {RUSIN=1,RBF=2, SIMPLE=3} typeOfCurvature;
   static Curvature& getInstance();
   static bool valueAlreadyComputed();
-  
+
   inline void setGModel(GModel* model)
   {
     _model = model;
@@ -193,7 +193,7 @@ public:
   //void retrievePhysicalSurfaces(const std::string & face_tag);
 
   void computeCurvature(GModel* model, typeOfCurvature typ);
-  
+
   /// The following function implements algorithm from:
   /// Implementation of an Algorithm for Approximating the Curvature Tensor
   /// on a Triangular Surface Mesh in the Vish Environment
@@ -229,5 +229,4 @@ public:
 
 };
 
-
 #endif
diff --git a/Geo/ExtrudeParams.cpp b/Geo/ExtrudeParams.cpp
index a1fe11b..e19f2f5 100644
--- a/Geo/ExtrudeParams.cpp
+++ b/Geo/ExtrudeParams.cpp
@@ -14,7 +14,7 @@ std::vector<SPoint3> ExtrudeParams::normalsCoherence;
 // If one section of the boundary layer index = 0 or 1  is not supposed to be
 // scaled...that section's normals will have scaleFactor = 1.0 (exactly  1.0 to all sig figs)
 // ...however, if that non-scaled
-// section borders a scaled section, the boundary normals will extrude consistently (an 
+// section borders a scaled section, the boundary normals will extrude consistently (an
 // average of scaled and non-scaled heights).
 bool ExtrudeParams::calcLayerScaleFactor[2] = {0,0};  // Added by Trevor Strickler
 
@@ -63,16 +63,19 @@ void ExtrudeParams::Extrude(int iLayer, int iElemLayer,
                             double &x, double &y, double &z)
 {
   double t = u(iLayer, iElemLayer);
-  // Trevor Strickler (this definitely relies on fixing lateral boundary extruded
-  // surfaces if mesh.ScaleLast is changed by ReplaceDuplicates.  This is done in BoundaryLayers.cpp right now.
-  if( geo.Type == BOUNDARY_LAYER && calcLayerScaleFactor[mesh.BoundaryLayerIndex]  && iLayer == mesh.NbLayer-1 &&
-      mesh.BoundaryLayerIndex >= 0 && mesh.BoundaryLayerIndex <= 1 && normals[mesh.BoundaryLayerIndex] ){
+  // Trevor Strickler (this definitely relies on fixing lateral boundary
+  // extruded surfaces if mesh.ScaleLast is changed by ReplaceDuplicates.  This
+  // is done in BoundaryLayers.cpp right now.
+  if(geo.Type == BOUNDARY_LAYER && iLayer == mesh.NbLayer-1 &&
+     mesh.BoundaryLayerIndex >= 0 && mesh.BoundaryLayerIndex <= 1 &&
+     calcLayerScaleFactor[mesh.BoundaryLayerIndex] &&
+     normals[mesh.BoundaryLayerIndex]){
     double scale = 1.0;
     normals[mesh.BoundaryLayerIndex]->get_scale(x, y, z, &scale);
-    if( fabs(scale-1.0) <= xyzv::eps )
+    if(fabs(scale-1.0) <= xyzv::eps)
       scale = 1.0;
     else{
-      if( mesh.NbLayer == 1 )
+      if(mesh.NbLayer <= 1)
 	t = t * scale;
       else
         t = (t-mesh.hLayer[mesh.NbLayer-2])*scale + mesh.hLayer[mesh.NbLayer-2];
diff --git a/Geo/GEdge.cpp b/Geo/GEdge.cpp
index 30baf14..ddbaec1 100644
--- a/Geo/GEdge.cpp
+++ b/Geo/GEdge.cpp
@@ -14,9 +14,10 @@
 #include "MLine.h"
 #include "GaussLegendre1D.h"
 #include "Context.h"
+#include "closestPoint.h"
 
 GEdge::GEdge(GModel *model, int tag, GVertex *_v0, GVertex *_v1)
-  : GEntity(model, tag), _tooSmall(false), v0(_v0), v1(_v1), compound(0)
+  : GEntity(model, tag), _tooSmall(false), _cp(0), v0(_v0), v1(_v1), compound(0)
 {
   if(v0) v0->addEdge(this);
   if(v1 && v1 != v0) v1->addEdge(this);
@@ -28,7 +29,7 @@ GEdge::~GEdge()
 {
   if(v0) v0->delEdge(this);
   if(v1 && v1 != v0) v1->delEdge(this);
-
+  if (_cp)delete _cp;
   deleteMesh();
 }
 
@@ -177,10 +178,19 @@ std::string GEdge::getAdditionalInfoString()
   std::ostringstream sstream;
   if(v0 && v1) sstream << "{" << v0->tag() << " " << v1->tag() << "}";
 
-  if(meshAttributes.method == MESH_TRANSFINITE)
-    sstream << " transfinite";
+  if(meshAttributes.method == MESH_TRANSFINITE){
+    sstream << " transfinite (" << meshAttributes.nbPointsTransfinite;
+    int type = meshAttributes.typeTransfinite;
+    if(std::abs(type) == 1)
+      sstream << ", progression " << sign(type) * meshAttributes.coeffTransfinite;
+    else if(std::abs(type) == 2)
+      sstream << ", bump " << meshAttributes.coeffTransfinite;
+    sstream << ")";
+  }
   if(meshAttributes.extrude)
     sstream << " extruded";
+  if(meshAttributes.reverseMesh)
+    sstream << " reversed";
 
   return sstream.str();
 }
@@ -367,49 +377,6 @@ GPoint GEdge::closestPoint(const SPoint3 &q, double &t) const
   return point(t);
 }
 
-bool GEdge::computeDistanceFromMeshToGeometry (double &d2, double &dmax)
-{
-  d2 = 0.0; dmax = 0.0;
-  if (geomType() == Line) return true;
-  if (!lines.size())return false;
-  IntPt *pts;
-  int npts;
-  lines[0]->getIntegrationPoints(2*lines[0]->getPolynomialOrder(), &npts, &pts);
-
-  for (unsigned int i = 0; i < lines.size(); i++){
-    MLine *l = lines[i];
-    double t[256];
-
-    for (int j=0; j< l->getNumVertices();j++){
-      MVertex *v = l->getVertex(j);
-      if (v->onWhat() == getBeginVertex()){
-	t[j] = getLowerBound();
-      }
-      else if (v->onWhat() == getEndVertex()){
-	t[j] = getUpperBound();
-      }
-      else {
-	v->getParameter(0,t[j]);
-      }
-    }
-    for (int j=0;j<npts;j++){
-      SPoint3 p;
-      l->pnt(pts[j].pt[0],0,0,p);
-      double tinit = l->interpolate(t,pts[j].pt[0],0,0);
-      GPoint pc = closestPoint(p, tinit);
-      if (!pc.succeeded())continue;
-      double dsq =
-	(pc.x()-p.x())*(pc.x()-p.x()) +
-	(pc.y()-p.y())*(pc.y()-p.y()) +
-	(pc.z()-p.z())*(pc.z()-p.z());
-      d2 += pts[i].weight * fabs(l->getJacobianDeterminant(pts[j].pt[0],0,0)) * dsq;
-      dmax = std::max(dmax,sqrt(dsq));
-    }
-  }
-  d2 = sqrt(d2);
-  return true;
-}
-
 double GEdge::parFromPoint(const SPoint3 &P) const
 {
   double t;
@@ -517,3 +484,70 @@ void GEdge::relocateMeshVertices()
     }
   }
 }
+
+SPoint3 GEdge :: closestPoint (SPoint3 &p, double tolerance)
+{
+  if (!_cp || _cp->tol() != tolerance)    {
+    if(_cp)printf("coucou %12.15E %22.15E \n",tolerance,_cp->tol());
+    else printf("coucou %12.5E \n",tolerance);
+    if (_cp) delete _cp;
+    _cp = new closestPointFinder (this, tolerance);
+  }
+  return (*_cp)(p);
+}
+
+
+typedef struct {
+  SPoint3 p;
+  double t;
+  int next;
+} sortedPoint;
+
+static double sqDistPointSegment(const SPoint3 &p, const SPoint3 &s0, const SPoint3 &s1)
+{
+  SVector3 d(s1 - s0);
+  SVector3 d0(p - s0);
+  SVector3 d1(p - s1);
+  double dn2 = crossprod(d, d0).normSq();
+  double dt2 = std::max(0., std::max(-dot(d, d0), dot(d, d1)));
+  dt2 *= dt2;
+  return (dt2 + dn2) / d.normSq();
+}
+
+static void _discretize(double tol, GEdge * edge, std::vector<sortedPoint> &upts, int pos0)
+{
+  const int pos1 = upts[pos0].next;
+  const SPoint3 & p0 = upts[pos0].p;
+  const double t0 = upts[pos0].t;
+  const SPoint3 & p1 = upts[pos1].p;
+  const double t1 = upts[pos1].t;
+  const double tmid = 0.5 * (t0 + t1);
+  const SPoint3 pmid(edge->position(tmid));
+  const double d2 = sqDistPointSegment(pmid, p0, p1);
+  if (d2 < tol * tol)
+    return;
+  sortedPoint pnt = {pmid, tmid, pos1};
+  upts.push_back(pnt);
+  const int posmid = upts.size() - 1;
+  upts[pos0].next = posmid;
+  _discretize(tol, edge, upts, pos0);
+  _discretize(tol, edge, upts, posmid);
+}
+
+void GEdge::discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts)
+{
+  std::vector<sortedPoint> upts;
+  sortedPoint pnt1 = {getBeginVertex()->xyz(), 0., 1};
+  upts.push_back(pnt1);
+  sortedPoint pnt2 = {getEndVertex()->xyz(), 1., -1};
+  upts.push_back(pnt2);
+  _discretize(tol, this, upts, 0);
+  dpts.clear();
+  dpts.reserve(upts.size());
+  ts.clear();
+  ts.reserve(upts.size());
+  for (int p = 0; p != -1; p = upts[p].next) {
+    dpts.push_back(upts[p].p);
+    ts.push_back(upts[p].t);
+  }
+}
diff --git a/Geo/GEdge.h b/Geo/GEdge.h
index 0e5b5cf..dbb584c 100644
--- a/Geo/GEdge.h
+++ b/Geo/GEdge.h
@@ -22,13 +22,14 @@ class MElement;
 class MLine;
 class ExtrudeParams;
 class GEdgeCompound;
+class closestPointFinder;
 
 // A model edge.
 class GEdge : public GEntity {
  private:
   double _length;
   bool _tooSmall;
-
+  closestPointFinder *_cp;
  protected:
   GVertex *v0, *v1;
   // FIXME: normals need to be mutable at the moment, because thay can
@@ -208,7 +209,8 @@ class GEdge : public GEntity {
 
   void addLine(MLine *line){ lines.push_back(line); }
 
-  bool computeDistanceFromMeshToGeometry (double &d2, double &dmax);
+  virtual void discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts);
+  SPoint3 closestPoint (SPoint3 &p, double tolerance);
 };
 
 #endif
diff --git a/Geo/GEdgeLoop.cpp b/Geo/GEdgeLoop.cpp
index 73ae2c4..a551295 100644
--- a/Geo/GEdgeLoop.cpp
+++ b/Geo/GEdgeLoop.cpp
@@ -20,7 +20,7 @@ int countInList(std::list<GEdge*> &wire, GEdge *ge)
   std::list<GEdge*>::iterator ite = wire.end();
   int count = 0;
   while(it != ite){
-    if(*it == ge) count++; 
+    if(*it == ge) count++;
     ++it;
   }
   return count;
@@ -31,7 +31,7 @@ GEdgeSigned nextOne(GEdgeSigned *thisOne, std::list<GEdge*> &wire)
   if(!thisOne){
     GEdge *ge = *(wire.begin());
     wire.erase(wire.begin());
-    return GEdgeSigned(1, ge);   
+    return GEdgeSigned(1, ge);
   }
 
   GVertex *gv = thisOne->getEndVertex();
@@ -52,14 +52,14 @@ GEdgeSigned nextOne(GEdgeSigned *thisOne, std::list<GEdge*> &wire)
   while(it != ite){
     GEdge *ge = *it;
     if(countInList(possibleChoices, ge) == 2){
-      wire.erase(std::remove_if(wire.begin(), wire.end(), 
-                                std::bind2nd(std::equal_to<GEdge*>(), ge)), 
+      wire.erase(std::remove_if(wire.begin(), wire.end(),
+                                std::bind2nd(std::equal_to<GEdge*>(), ge)),
                  wire.end());
       wire.push_back(ge);
       GVertex *v1 = ge->getBeginVertex();
       GVertex *v2 = ge->getEndVertex();
-      if(v1 == gv) return GEdgeSigned(1, ge);   
-      if(v2 == gv) return GEdgeSigned(-1, ge);   
+      if(v1 == gv) return GEdgeSigned(1, ge);
+      if(v2 == gv) return GEdgeSigned(-1, ge);
       Msg::Error("Something wrong in edge loop 1");
       thisOne->print();
     }
@@ -70,19 +70,19 @@ GEdgeSigned nextOne(GEdgeSigned *thisOne, std::list<GEdge*> &wire)
   while(it != ite){
     GEdge *ge = *it;
     if(ge != thisOne->ge){
-      wire.erase(std::remove_if(wire.begin(),wire.end(), 
-                                std::bind2nd(std::equal_to<GEdge*>(), ge)), 
+      wire.erase(std::remove_if(wire.begin(),wire.end(),
+                                std::bind2nd(std::equal_to<GEdge*>(), ge)),
                  wire.end());
       GVertex *v1 = ge->getBeginVertex();
       GVertex *v2 = ge->getEndVertex();
-      if(v1 == gv) return GEdgeSigned(1, ge);   
+      if(v1 == gv) return GEdgeSigned(1, ge);
       if(v2 == gv) return GEdgeSigned(-1, ge);
       Msg::Error("Something wrong in edge loop 2");
       thisOne->print();
-    }   
+    }
     ++it;
   }
-  
+
   // should never end up here
   return GEdgeSigned(0, 0);
 }
@@ -93,21 +93,21 @@ int GEdgeLoop::count(GEdge* ge) const
   GEdgeLoop::citer ite = end();
   int count = 0;
   while(it != ite){
-    if(it->ge == ge) count++; 
+    if(it->ge == ge) count++;
     ++it;
   }
   return count;
 }
 
 static void loopTheLoop(std::list<GEdge*> &wire,
-			std::list<GEdgeSigned> &loop,  
+			std::list<GEdgeSigned> &loop,
 			GEdge **degeneratedToInsert)
 {
   GEdgeSigned *prevOne = 0;
   GEdgeSigned ges(0,0);
 
   while(wire.size()){
-    if (prevOne && (*degeneratedToInsert) && 
+    if (prevOne && (*degeneratedToInsert) &&
 	(*degeneratedToInsert)->getBeginVertex () == prevOne->getEndVertex()){
       ges = GEdgeSigned(1,*degeneratedToInsert);
       *degeneratedToInsert = 0;
@@ -118,7 +118,7 @@ static void loopTheLoop(std::list<GEdge*> &wire,
       if (0){
 	Msg::Error("Something wrong in edge loop of size=%d, no sign !", wire.size());
 	for (std::list<GEdge* >::iterator it = wire.begin(); it != wire.end(); it++){
-	  Msg::Error("GEdge=%d begin=%d end =%d", (*it)->tag(), 
+	  Msg::Error("GEdge=%d begin=%d end =%d", (*it)->tag(),
 		     (*it)->getBeginVertex()->tag(), (*it)->getEndVertex()->tag());
 	}
       }
@@ -127,7 +127,7 @@ static void loopTheLoop(std::list<GEdge*> &wire,
     prevOne = ⩾
     // ges.print();
     loop.push_back(ges);
-  }  
+  }
 }
 
 
@@ -144,7 +144,7 @@ GEdgeLoop::GEdgeLoop(const std::list<GEdge*> &cwire)
     if (ed->degenerate(0))degenerated.push_back(ed);
     else wire.push_back(ed);
   }
-  
+
   if (degenerated.size() == 1){
     wire.push_front(degenerated[0]);
   }
@@ -153,9 +153,9 @@ GEdgeLoop::GEdgeLoop(const std::list<GEdge*> &cwire)
     wire.push_front(degenerated[0]);
   }
   else if (degenerated.size() > 2){
-    Msg::Error("More than two degenerated edges in one model face");
+    Msg::Error("More than two degenerated edges in one model face of an OCC model");
   }
-  
+
   while (!wire.empty()){
     //    printf("wire.size = %d\n",wire.size());
     loopTheLoop(wire,loop,&degeneratedToInsert);
diff --git a/Geo/GFace.cpp b/Geo/GFace.cpp
index 546daf9..d44829d 100644
--- a/Geo/GFace.cpp
+++ b/Geo/GFace.cpp
@@ -261,18 +261,17 @@ surface_params GFace::getSurfaceParams() const
 
 std::list<GVertex*> GFace::vertices() const
 {
-  std::list<GEdge*>::const_iterator it = l_edges.begin();
-  std::list<GVertex*>ret;
-  while (it != l_edges.end()){
+  std::set<GVertex*> v;
+  for(std::list<GEdge*>::const_iterator it = l_edges.begin();
+      it != l_edges.end(); ++it){
     GVertex *v1 = (*it)->getBeginVertex();
+    if(v1) v.insert(v1);
     GVertex *v2 = (*it)->getEndVertex();
-    if(v1 && std::find(ret.begin(), ret.end(), v1) == ret.end())
-      ret.push_back(v1);
-    if(v2 && std::find(ret.begin(), ret.end(), v2) == ret.end())
-      ret.push_back(v2);
-    ++it;
+    if(v2) v.insert(v2);
   }
-  return ret;
+  std::list<GVertex*> res;
+  res.insert(res.begin(), v.begin(), v.end());
+  return res;
 }
 
 void GFace::setVisibility(char val, bool recursive)
@@ -1473,9 +1472,9 @@ void GFace::addLayersOfQuads(int nLayers, GVertex *gv, double hmin, double ratio
 	hmin += hlayer;
       }
       fprintf(f,"};\n");
-      fclose(f);
     }
   }
+  fclose(f);
 }
 
 void GFace::relocateMeshVertices()
diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp
index 10ceb24..fd78dcc 100644
--- a/Geo/GFaceCompound.cpp
+++ b/Geo/GFaceCompound.cpp
@@ -1668,6 +1668,7 @@ void GFaceCompound::parametrize(iterationStep step, typeOfMapping tom) const
     }
   }
 
+  delete mapping;
   delete lsys;
 }
 
diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index f74a2f5..3a00394 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -171,10 +171,12 @@ GModel *GModel::findByName(const std::string &name, const std::string &fileName)
   return 0;
 }
 
-void GModel::destroy()
+void GModel::destroy(bool keepName)
 {
-  _name.clear();
-  _fileNames.clear();
+  if(!keepName){
+    _name.clear();
+    _fileNames.clear();
+  }
 
   _maxVertexNum = _maxElementNum = 0;
   _checkPointedMaxVertexNum = _checkPointedMaxElementNum = 0;
@@ -430,7 +432,7 @@ int GModel::getMaxPhysicalNumber(int dim)
   getEntities(entities);
   int num = 0;
   for(unsigned int i = 0; i < entities.size(); i++)
-    if(entities[i]->dim() == dim)
+    if(dim < 0 || entities[i]->dim() == dim)
       for(unsigned int j = 0; j < entities[i]->physicals.size(); j++)
         num = std::max(num, std::abs(entities[i]->physicals[j]));
   return num;
@@ -1463,7 +1465,7 @@ void GModel::checkMeshCoherence(double tolerance)
     int num = 0;
     for(unsigned int i = 0; i < vertices.size(); i++)
       if(!vertices[i]->getIndex()){
-        Msg::Info("Duplicate vertex at (%.16g,%.16g,%.16g)",
+        Msg::Info("Duplicate vertex %d at (%.16g,%.16g,%.16g)", vertices[i]->getNum(),
                   vertices[i]->x(), vertices[i]->y(), vertices[i]->z());
         num++;
       }
@@ -2796,6 +2798,11 @@ GEntity *GModel::addCone(std::vector<double> p1, std::vector<double> p2,
   return 0;
 }
 
+void GModel::healGeometry(double tolerance)
+{
+  if(_factory) _factory->healGeometry(this, tolerance);
+}
+
 GModel *GModel::computeBooleanUnion(GModel *tool, int createNewModel)
 {
   if(_factory)
diff --git a/Geo/GModel.h b/Geo/GModel.h
index 6bbd50b..e1a6f31 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -158,10 +158,6 @@ class GModel
   std::set<int> meshPartitions;
   int partitionSize[2];
 
-  // boundary layer columns i.e. list of vertices that form columns
-  // in boundary layers
-  BoundaryLayerColumns _columns;
-
  public:
   GModel(std::string name="");
   virtual ~GModel();
@@ -182,8 +178,8 @@ class GModel
   // *not* have a link to the fileName
   static GModel *findByName(const std::string &name, const std::string &fileName="");
 
-  // delete everything in a GModel
-  void destroy();
+  // delete everything in a GModel (optionally keep name and fileName)
+  void destroy(bool keepName=false);
 
   // get/set global vertex/element num
   int getMaxVertexNumber(){ return _maxVertexNum; }
@@ -304,7 +300,7 @@ class GModel
   void deletePhysicalGroup(int dim, int num);
 
   // return the highest number associated with a physical entity of a
-  // given dimension
+  // given dimension (or highest for all dimenions if dim < 0)
   int getMaxPhysicalNumber(int dim);
 
   // elementary/physical name iterator
@@ -525,6 +521,9 @@ class GModel
   GEntity *addCone(std::vector<double> p1, std::vector<double> p2, double radius1,
                    double radius2);
 
+  // heal geometry using the factory
+  void healGeometry(double tolerance = -1);
+
   // boolean operators acting on 2 models
   GModel *computeBooleanUnion(GModel *tool, int createNewModel=0);
   GModel *computeBooleanIntersection(GModel *tool, int createNewModel=0);
diff --git a/Geo/GModelFactory.cpp b/Geo/GModelFactory.cpp
index 2bbac86..6bf5b36 100644
--- a/Geo/GModelFactory.cpp
+++ b/Geo/GModelFactory.cpp
@@ -391,6 +391,9 @@ std::vector<GEntity*> GeoFactory::extrudeBoundaryLayer(GModel *gm, GEntity *e,
     }
   }
 
+  List_Delete(list_out);
+  List_Delete(tmp);
+
   return extrudedEntities;
 
   // //return the new created entity
@@ -424,6 +427,16 @@ std::vector<GEntity*> GeoFactory::extrudeBoundaryLayer(GModel *gm, GEntity *e,
 
 };
 
+void GeoFactory::healGeometry(GModel *gm, double tolerance)
+{
+  GModel *current = GModel::current();
+  GModel::setCurrent(gm);
+  ReplaceAllDuplicatesNew(tolerance);
+  gm->destroy();
+  gm->importGEOInternals();
+  GModel::setCurrent(current);
+}
+
 #if defined(HAVE_OCC)
 #include "OCCIncludes.h"
 #include "GModelIO_OCC.h"
@@ -601,7 +614,7 @@ GEdge *OCCFactory::addSpline(GModel *gm, const splineType &type,
   }
   else if (type == BSPLINE) {
 
-    Handle(Geom_BSplineCurve) Bez = GeomAPI_PointsToBSpline(ctrlPoints).Curve(); 
+    Handle(Geom_BSplineCurve) Bez = GeomAPI_PointsToBSpline(ctrlPoints).Curve();
 
     if (occv1 && occv2)
       occEdge = BRepBuilderAPI_MakeEdge(Bez,occv1->getShape(),occv2->getShape()).Edge();
@@ -1568,6 +1581,18 @@ GEntity *OCCFactory::addPipe(GModel *gm, GEntity *base, std::vector<GEdge *> wir
   return ret;
 }
 
+void OCCFactory::healGeometry(GModel *gm, double tolerance)
+{
+  if (tolerance < 0.)
+    tolerance = CTX::instance()->geom.tolerance;
+  if (!gm || !gm->_occ_internals)
+    return;
+  //gm->_occ_internals->healGeometry(tolerance, false, false, false, true, false, false);
+  gm->_occ_internals->healGeometry(tolerance, true, true, true, true, true, true);
+  gm->_occ_internals->buildLists();
+  gm->_occ_internals->buildGModel(gm);
+}
+
 //Prepare SGEOM integration
 #if defined(HAVE_SGEOM) && defined(HAVE_OCC)
 
@@ -1607,6 +1632,12 @@ GRegion* SGEOMFactory::addVolume(GModel *gm, std::vector<std::vector<GFace *> >
   return 0;
 }
 
+void SGEOMFactory::healGeometry(GModel *gm, double tolerance)
+{
+  Msg::Error("healGeometry not implemented yet for SGEOMFactory");
+  return 0;
+}
+
 #endif
 
 #endif
diff --git a/Geo/GModelFactory.h b/Geo/GModelFactory.h
index ba9aa2b..ffab382 100644
--- a/Geo/GModelFactory.h
+++ b/Geo/GModelFactory.h
@@ -217,6 +217,8 @@ class GModelFactory {
     Msg::Error("setPhysicalNumToEntitiesInBox not implemented yet");
   }
 
+  virtual void healGeometry(GModel *gm, double tolerance = -1.) = 0;
+
 };
 
 class GeoFactory : public GModelFactory {
@@ -230,6 +232,7 @@ class GeoFactory : public GModelFactory {
   std::vector<GFace *> addRuledFaces(GModel *gm, std::vector<std::vector<GEdge *> > edges);
   std::vector<GEntity*> extrudeBoundaryLayer(GModel *gm, GEntity *e, int nbLayers,
                                              double hLayers, int dir, int view);
+  void healGeometry(GModel *gm, double tolerance = -1.);
 };
 
 #if defined(HAVE_OCC)
@@ -288,6 +291,7 @@ class OCCFactory : public GModelFactory {
                                      std::vector<double> p1, std::vector<double> p2);
 
   void fillet(GModel *gm, std::vector<int> edges, double radius);
+  void healGeometry(GModel *gm, double tolerance = -1.);
 };
 
 #endif
@@ -301,6 +305,7 @@ class SGEOMFactory : public GModelFactory {
   GEdge *addLine(GModel *gm,GVertex *v1, GVertex *v2);
   GFace *addPlanarFace(GModel *gm, std::vector<std::vector<GEdge *> > edges);
   GRegion *addVolume(GModel *gm, std::vector<std::vector<GFace *> > faces);
+  void healGeometry(GModel *gm, double tolerance = -1.);
 };
 
 #endif
diff --git a/Geo/GModelIO_CELUM.cpp b/Geo/GModelIO_CELUM.cpp
index 74a29cb..79783b7 100644
--- a/Geo/GModelIO_CELUM.cpp
+++ b/Geo/GModelIO_CELUM.cpp
@@ -28,6 +28,7 @@ int GModel::writeCELUM(const std::string &name, bool saveAll,
   FILE *fps = Fopen(names.c_str(), "w");
   if(!fps){
     Msg::Error("Unable to open file '%s'", names.c_str());
+    fclose(fpf);
     return 0;
   }
 
diff --git a/Geo/GModelIO_GEO.cpp b/Geo/GModelIO_GEO.cpp
index 0fec60f..59d761a 100644
--- a/Geo/GModelIO_GEO.cpp
+++ b/Geo/GModelIO_GEO.cpp
@@ -164,7 +164,6 @@ int GModel::importGEOInternals()
           add(e);
         }
 
-
         if(!c->Visible) e->setVisibility(0);
         if(c->Color.type) e->setColor(c->Color.mesh);
         if(c->degenerated) {
@@ -195,7 +194,6 @@ int GModel::importGEOInternals()
 	  }
 	}
         int param = CTX::instance()->mesh.remeshParam;
-
 	GFaceCompound::typeOfCompound typ = GFaceCompound::HARMONIC_CIRCLE;
 	if (param == 1) typ =  GFaceCompound::CONFORMAL_SPECTRAL;
 	if (param == 2) typ =  GFaceCompound::RADIAL_BASIS;
@@ -204,18 +202,16 @@ int GModel::importGEOInternals()
 	if (param == 5) typ =  GFaceCompound::CONVEX_PLANE;
 	if (param == 6) typ =  GFaceCompound::HARMONIC_SQUARE;
 	if (param == 7) typ =  GFaceCompound::CONFORMAL_FE;
-
         int algo = CTX::instance()->mesh.remeshAlgo;
 	f = new GFaceCompound(this, s->Num, comp, b[0], b[1], b[2], b[3], typ, algo);
-
         f->meshAttributes.recombine = s->Recombine;
         f->meshAttributes.recombineAngle = s->RecombineAngle;
         f->meshAttributes.method = s->Method;
         f->meshAttributes.extrude = s->Extrude;
-        // transfinite import Added by Trevor Strickler.  This helps when experimenting
-        // to create compounds from transfinite surfs. Not having it does not break
-        // anything Gmsh *officially* does right now, but maybe it was left out by mistake??? and could
-        // cause problems later?
+        // transfinite import Added by Trevor Strickler.  This helps when
+        // experimenting to create compounds from transfinite surfs. Not having
+        // it does not break anything Gmsh *officially* does right now, but
+        // maybe it was left out by mistake??? and could cause problems later?
         f->meshAttributes.transfiniteArrangement = s->Recombine_Dir;
         f->meshAttributes.corners.clear();
         for(int i = 0; i < List_Nbr(s->TrsfPoints); i++){
@@ -227,7 +223,6 @@ int GModel::importGEOInternals()
           else
             Msg::Error("Unknown vertex %d in transfinite attributes", corn->Num);
         }
-        
         add(f);
         if(s->EmbeddedCurves){
           for(int i = 0; i < List_Nbr(s->EmbeddedCurves); i++){
@@ -256,8 +251,10 @@ int GModel::importGEOInternals()
         f = new gmshFace(this, s);
         add(f);
       }
-      else
+      else{
+        if(s->Typ == MSH_SURF_PLAN) f->computeMeanPlane(); // recompute in case geom has changed
         f->resetMeshAttributes();
+      }
       if(!s->Visible) f->setVisibility(0);
       if(s->Color.type) f->setColor(s->Color.mesh);
     }
diff --git a/Geo/GModelIO_MED.cpp b/Geo/GModelIO_MED.cpp
index 6420c7e..959d329 100644
--- a/Geo/GModelIO_MED.cpp
+++ b/Geo/GModelIO_MED.cpp
@@ -442,7 +442,9 @@ int GModel::readMED(const std::string &name, int meshIndex)
           char tmp[MED_TAILLE_LNOM + 1];
           strncpy(tmp, &groupNames[j * MED_TAILLE_LNOM], MED_TAILLE_LNOM);
           tmp[MED_TAILLE_LNOM] = '\0';
-          int pnum = setPhysicalName(tmp, ge->dim());
+          // don't use same physical number across dimensions, as e.g. getdp
+          // does not support this
+          int pnum = setPhysicalName(tmp, ge->dim(), getMaxPhysicalNumber(-1) + 1);
           if(std::find(ge->physicals.begin(), ge->physicals.end(), pnum) ==
              ge->physicals.end())
             ge->physicals.push_back(pnum);
diff --git a/Geo/GModelIO_MESH.cpp b/Geo/GModelIO_MESH.cpp
index ab9dfbc..0d2e73a 100644
--- a/Geo/GModelIO_MESH.cpp
+++ b/Geo/GModelIO_MESH.cpp
@@ -56,7 +56,10 @@ int GModel::readMESH(const std::string &name)
     if(buffer[0] != '#'){ // skip comments and empty lines
       str[0]='\0';
       sscanf(buffer, "%s", str);
-      if(!strcmp(str, "Dimension")){
+      if(!strncmp(buffer, "Dimension 3", 11)){
+        // alternative single-line 'Dimension' field used by CGAL
+      }
+      else if(!strcmp(str, "Dimension")){
         if(!fgets(buffer, sizeof(buffer), fp)) break;
       }
       else if(!strcmp(str, "Vertices")){
@@ -254,7 +257,7 @@ int GModel::writeMESH(const std::string &name, int elementTagType,
   }
 
   if(numEdges){
-    if(CTX::instance()->mesh.order == 2)
+    if(CTX::instance()->mesh.order == 2) // FIXME (check getPolynomialOrder())
       fprintf(fp, " EdgesP2\n");
     else
       fprintf(fp, " Edges\n");
@@ -269,7 +272,7 @@ int GModel::writeMESH(const std::string &name, int elementTagType,
     }
   }
   if(numTriangles){
-    if(CTX::instance()->mesh.order == 2)
+    if(CTX::instance()->mesh.order == 2) // FIXME (check getPolynomialOrder())
       fprintf(fp, " TrianglesP2\n");
     else
       fprintf(fp, " Triangles\n");
@@ -297,7 +300,7 @@ int GModel::writeMESH(const std::string &name, int elementTagType,
   }
   if(numTetrahedra){
     if(CTX::instance()->mesh.order == 2)
-      fprintf(fp, " TetrahedraP2\n");
+      fprintf(fp, " TetrahedraP2\n"); // FIXME (check getPolynomialOrder())
     else
       fprintf(fp, " Tetrahedra\n");
     fprintf(fp, " %d\n", numTetrahedra);
diff --git a/Geo/GModelIO_MSH2.cpp b/Geo/GModelIO_MSH2.cpp
index 4f3d7e0..21e09d9 100644
--- a/Geo/GModelIO_MSH2.cpp
+++ b/Geo/GModelIO_MSH2.cpp
@@ -409,17 +409,24 @@ int GModel::_readMSH2(const std::string &name)
             }
           }
           int *indices = new int[numVertices];
-          for(int j = 0; j < numVertices; j++)
-            if(fscanf(fp, "%d", &indices[j]) != 1){ fclose(fp); return 0; }
+          for(int j = 0; j < numVertices; j++){
+            if(fscanf(fp, "%d", &indices[j]) != 1){
+              delete [] indices;
+              fclose(fp);
+              return 0;
+            }
+          }
           std::vector<MVertex*> vertices;
           if(vertexVector.size()){
             if(!getVertices(numVertices, indices, vertexVector, vertices, minVertex)){
+              delete [] indices;
               fclose(fp);
               return 0;
             }
           }
           else{
             if(!getVertices(numVertices, indices, vertexMap, vertices)){
+              delete [] indices;
               fclose(fp);
               return 0;
             }
@@ -487,6 +494,8 @@ int GModel::_readMSH2(const std::string &name)
               Msg::Error("Domain element %d not found for element %d", dom2, num);
 #endif
 	  }
+          delete [] indices;
+
           if (CTX::instance()->mesh.ignorePartBound && elementary<0) continue;
           MElement *e = createElementMSH2(this, num, type, physical, elementary,
                                           partition, vertices, elements, physicals,
@@ -502,7 +511,6 @@ int GModel::_readMSH2(const std::string &name)
             _ghostCells.insert(std::pair<MElement*, short>(e, ghosts[j]));
           if(numElements > 100000)
             Msg::ProgressMeter(i + 1, numElements, true, "Reading elements");
-          delete [] indices;
         }
       }
       else{
@@ -518,7 +526,11 @@ int GModel::_readMSH2(const std::string &name)
           unsigned int n = 1 + numTags + numVertices;
           int *data = new int[n];
           for(int i = 0; i < numElms; i++) {
-            if(fread(data, sizeof(int), n, fp) != n){ fclose(fp); return 0; }
+            if(fread(data, sizeof(int), n, fp) != n){
+              delete [] data;
+              fclose(fp);
+              return 0;
+            }
             if(swap) SwapBytes((char*)data, sizeof(int), n);
             int num = data[0];
             int physical = (numTags > 0) ? data[1] : 0;
@@ -534,12 +546,14 @@ int GModel::_readMSH2(const std::string &name)
             std::vector<MVertex*> vertices;
             if(vertexVector.size()){
               if(!getVertices(numVertices, indices, vertexVector, vertices, minVertex)){
+                delete [] data;
                 fclose(fp);
                 return 0;
               }
             }
             else{
               if(!getVertices(numVertices, indices, vertexMap, vertices)){
+                delete [] data;
                 fclose(fp);
                 return 0;
               }
@@ -841,6 +855,7 @@ int GModel::_writeMSH2(const std::string &name, double version, bool binary,
                        bool saveAll, bool saveParametric, double scalingFactor,
                        int elementStartNum, int saveSinglePartition, bool multipleView)
 {
+
   FILE *fp;
   if(multipleView)
     fp = Fopen(name.c_str(), binary ? "ab" : "a");
diff --git a/Geo/GModelIO_OCC.cpp b/Geo/GModelIO_OCC.cpp
index 8dd9728..3632cf7 100644
--- a/Geo/GModelIO_OCC.cpp
+++ b/Geo/GModelIO_OCC.cpp
@@ -35,6 +35,37 @@ void OCC_Internals::buildLists()
   addShapeToLists(shape);
 }
 
+void  OCC_Internals::buildShapeFromGModel(GModel* gm){
+  somap.Clear();
+  shmap.Clear();
+  fmap.Clear();
+  wmap.Clear();
+  emap.Clear();
+  vmap.Clear();
+  for (GModel::riter it = gm->firstRegion(); it != gm->lastRegion() ; ++it){
+    if ((*it)->getNativeType() == GEntity::OpenCascadeModel){
+      OCCRegion *occ = static_cast<OCCRegion*> (*it);
+      if (occ)addShapeToLists (occ->getTopoDS_Shape());
+    }
+  }
+  for (GModel::fiter it = gm->firstFace(); it != gm->lastFace() ; ++it){
+    if ((*it)->getNativeType() == GEntity::OpenCascadeModel){
+      OCCFace *occ = static_cast<OCCFace*> (*it);
+      if(occ)addShapeToLists (occ->getTopoDS_Face ());
+    }
+  }
+  BRep_Builder B;
+  TopoDS_Compound C;
+  B.MakeCompound(C);
+  for(int i = 1; i <= vmap.Extent(); i++) B.Add(C, vmap(i));
+  for(int i = 1; i <= emap.Extent(); i++) B.Add(C, emap(i));
+  for(int i = 1; i <= wmap.Extent(); i++) B.Add(C, wmap(i));
+  for(int i = 1; i <= fmap.Extent(); i++) B.Add(C, fmap(i));
+  for(int i = 1; i <= shmap.Extent(); i++) B.Add(C, shmap(i));
+  for(int i = 1; i <= somap.Extent(); i++) B.Add(C, somap(i));
+  shape = C;
+}
+
 void OCC_Internals::buildShapeFromLists(TopoDS_Shape _shape)
 {
   BRep_Builder B;
@@ -211,6 +242,7 @@ void OCC_Internals::healGeometry(double tolerance, bool fixdegenerated,
                                  bool fixsmalledges, bool fixspotstripfaces,
                                  bool sewfaces, bool makesolids, bool connect)
 {
+  
   if(!fixdegenerated && !fixsmalledges && !fixspotstripfaces &&
      !sewfaces && !makesolids && !connect) return;
 
@@ -708,33 +740,32 @@ GRegion* OCC_Internals::addRegionToModel(GModel *model, TopoDS_Solid region)
 /* I needed getGTagOfOCC*ByNativePtr whithin setPhysicalNumToEntitiesInBox */
 int OCC_Internals::getGTagOfOCCVertexByNativePtr(GModel *model, TopoDS_Vertex toFind)
 {
-	if(gvNumCache.IsBound(toFind))
-		return (int)gvNumCache.Find(toFind);
-	return 0;	
+  if(gvNumCache.IsBound(toFind))
+    return (int)gvNumCache.Find(toFind);
+  return 0;
 }
 
 int OCC_Internals::getGTagOfOCCFaceByNativePtr(GModel *model, TopoDS_Face toFind)
 {
-	if(gfNumCache.IsBound(toFind))
-		return (int)gfNumCache.Find(toFind);
-	return 0;
+  if(gfNumCache.IsBound(toFind))
+    return (int)gfNumCache.Find(toFind);
+  return 0;
 }
 
 int OCC_Internals::getGTagOfOCCEdgeByNativePtr(GModel *model, TopoDS_Edge toFind)
 {
-	if(geNumCache.IsBound(toFind))
-		return (int)geNumCache.Find(toFind);
-	return 0;
+  if(geNumCache.IsBound(toFind))
+    return (int)geNumCache.Find(toFind);
+  return 0;
 }
 
 int OCC_Internals::getGTagOfOCCSolidByNativePtr(GModel *model, TopoDS_Solid toFind)
 {
-	if(grNumCache.IsBound(toFind))
-		return (int)grNumCache.Find(toFind);
-	return 0;	
+  if(grNumCache.IsBound(toFind))
+    return (int)grNumCache.Find(toFind);
+  return 0;
 }
 
-
 void OCC_Internals::buildGModel(GModel *model)
 {
   // building geom vertices
@@ -1048,6 +1079,8 @@ int GModel::readOCCIGES(const std::string &fn)
 
 int GModel::writeOCCBREP(const std::string &fn)
 {
+  _occ_internals->buildShapeFromGModel(this);
+  
   if(!_occ_internals){
     Msg::Error("No OpenCASCADE model found");
     return 0;
@@ -1059,6 +1092,7 @@ int GModel::writeOCCBREP(const std::string &fn)
 
 int GModel::writeOCCSTEP(const std::string &fn)
 {
+  _occ_internals->buildShapeFromGModel(this);
   if(!_occ_internals){
     Msg::Error("No OpenCASCADE model found");
     return 0;
diff --git a/Geo/GModelIO_OCC.h b/Geo/GModelIO_OCC.h
index f45d293..445a9d5 100644
--- a/Geo/GModelIO_OCC.h
+++ b/Geo/GModelIO_OCC.h
@@ -27,6 +27,7 @@ class OCC_Internals {
   TopoDS_Shape getShape () { return shape; }
   void buildLists();
   void buildShapeFromLists(TopoDS_Shape _shape);
+  void buildShapeFromGModel(GModel*);
   void addShapeToLists(TopoDS_Shape shape);
   void healGeometry(double tolerance, bool fixdegenerated,
                     bool fixsmalledges, bool fixspotstripfaces,
diff --git a/Geo/GModelIO_PLY.cpp b/Geo/GModelIO_PLY.cpp
index 068d004..23a37e6 100644
--- a/Geo/GModelIO_PLY.cpp
+++ b/Geo/GModelIO_PLY.cpp
@@ -70,7 +70,7 @@ int GModel::readPLY(const std::string &name)
   char buffer[256], str[256], str2[256], str3[256];
   std::string s1;
   int elementary = getMaxElementaryNumber(-1) + 1;
-  int nbv, nbf;
+  int nbv = 0, nbf = 0;
   int nbprop = 0;
   int nbView = 0;
   std::vector<std::string> propName;
diff --git a/Geo/GModelIO_SU2.cpp b/Geo/GModelIO_SU2.cpp
index 7e38f4c..ec1170e 100644
--- a/Geo/GModelIO_SU2.cpp
+++ b/Geo/GModelIO_SU2.cpp
@@ -34,6 +34,7 @@ int GModel::writeSU2(const std::string &name, bool saveAll, double scalingFactor
   int ndime = getDim();
   if(ndime != 2 && ndime != 3){
     Msg::Error("SU2 mesh output valid only for 2D or 3D models (not %dD)", ndime);
+    fclose(fp);
     return 0;
   }
 
diff --git a/Geo/GModelIO_UNV.cpp b/Geo/GModelIO_UNV.cpp
index c0801d8..03bb8e1 100644
--- a/Geo/GModelIO_UNV.cpp
+++ b/Geo/GModelIO_UNV.cpp
@@ -7,6 +7,8 @@
 #include <string.h>
 #include "GModel.h"
 #include "OS.h"
+#include "GmshIO.h"
+
 #include "MLine.h"
 #include "MTriangle.h"
 #include "MQuadrangle.h"
@@ -17,7 +19,7 @@
 
 int GModel::readUNV(const std::string &name)
 {
-  FILE *fp = Fopen(name.c_str(), "r");
+  gmshFILE fp = gmshopen(name.c_str(), "r");
   if(!fp){
     Msg::Error("Unable to open file '%s'", name.c_str());
     return 0;
@@ -29,21 +31,21 @@ int GModel::readUNV(const std::string &name)
 
   _vertexMapCache.clear();
 
-  while(!feof(fp)) {
-    if(!fgets(buffer, sizeof(buffer), fp)) break;
+  while(!gmsheof(fp)) {
+    if(!gmshgets(buffer, sizeof(buffer), fp)) break;
     if(!strncmp(buffer, "    -1", 6)){
-      if(!fgets(buffer, sizeof(buffer), fp)) break;
+      if(!gmshgets(buffer, sizeof(buffer), fp)) break;
       if(!strncmp(buffer, "    -1", 6))
-        if(!fgets(buffer, sizeof(buffer), fp)) break;
+        if(!gmshgets(buffer, sizeof(buffer), fp)) break;
       int record = 0;
       sscanf(buffer, "%d", &record);
       if(record == 2411){ // nodes
         Msg::Info("Reading nodes");
-        while(fgets(buffer, sizeof(buffer), fp)){
+        while(gmshgets(buffer, sizeof(buffer), fp)){
           if(!strncmp(buffer, "    -1", 6)) break;
           int num, dum;
           if(sscanf(buffer, "%d %d %d %d", &num, &dum, &dum, &dum) != 4) break;
-          if(!fgets(buffer, sizeof(buffer), fp)) break;
+          if(!gmshgets(buffer, sizeof(buffer), fp)) break;
           double x, y, z;
           for(unsigned int i = 0; i < strlen(buffer); i++)
             if(buffer[i] == 'D') buffer[i] = 'E';
@@ -54,7 +56,7 @@ int GModel::readUNV(const std::string &name)
       else if(record == 2412){ // elements
         Msg::Info("Reading elements");
         std::map<int, int> warn;
-        while(fgets(buffer, sizeof(buffer), fp)){
+        while(gmshgets(buffer, sizeof(buffer), fp)){
           if(strlen(buffer) < 3) continue; // possible line ending after last fscanf
           if(!strncmp(buffer, "    -1", 6)) break;
           int num, type, elementary, physical, color, numNodes;
@@ -82,7 +84,7 @@ int GModel::readUNV(const std::string &name)
           case 11: case 21: case 22: case 31:
           case 23: case 24: case 32:
             // beam elements
-            if(!fgets(buffer, sizeof(buffer), fp)) break;
+            if(!gmshgets(buffer, sizeof(buffer), fp)) break;
             int dum;
             if(sscanf(buffer, "%d %d %d", &dum, &dum, &dum) != 3) break;
             break;
@@ -90,11 +92,14 @@ int GModel::readUNV(const std::string &name)
           std::vector<MVertex*> vertices(numNodes);
           for(int i = 0; i < numNodes; i++){
             int n;
-            if(!fscanf(fp, "%d", &n)){ fclose(fp); return 0; }
+            if(!gmshgets(buffer, 11, fp)){ gmshclose(fp); return 0; }
+            if(strlen(buffer) < 10)
+                if(!gmshgets(buffer, 11, fp)){ gmshclose(fp); return 0; }
+            if(!sscanf(buffer, "%d", &n)){ gmshclose(fp); return 0; }
             vertices[i] = getMeshVertexByTag(n);
             if(!vertices[i]){
               Msg::Error("Wrong vertex index %d", n);
-              fclose(fp);
+              gmshclose(fp);
               return 0;
             }
           }
@@ -189,7 +194,7 @@ int GModel::readUNV(const std::string &name)
   for(int i = 0; i < 4; i++)
     _storePhysicalTagsInEntities(i, physicals[i]);
 
-  fclose(fp);
+  gmshclose(fp);
   return 1;
 }
 
diff --git a/Geo/GRbf.cpp b/Geo/GRbf.cpp
index 30965a0..b3a0d8b 100644
--- a/Geo/GRbf.cpp
+++ b/Geo/GRbf.cpp
@@ -232,6 +232,8 @@ void GRbf::buildOctree(double radius)
   }
 
   Octree_Delete(oct);
+  delete [] _sph;
+
   buildXYZkdtree();
 }
 
diff --git a/Geo/GRegion.cpp b/Geo/GRegion.cpp
index afd6772..669365e 100644
--- a/Geo/GRegion.cpp
+++ b/Geo/GRegion.cpp
@@ -14,6 +14,7 @@
 #include "MElementCut.h"
 #include "GmshMessage.h"
 #include "VertexArray.h"
+#include "boundaryLayersData.h"
 
 GRegion::GRegion(GModel *model, int tag) : GEntity (model, tag)
 {
@@ -27,7 +28,6 @@ GRegion::~GRegion()
     (*it)->delRegion(this);
     ++it;
   }
-
   deleteMesh();
 }
 
@@ -265,11 +265,20 @@ std::list<GEdge*> GRegion::edges() const
   std::list<GFace*>::const_iterator it = l_faces.begin();
   while(it != l_faces.end()){
     std::list<GEdge*> e2;
+
     e2 = (*it)->edges();
     std::list<GEdge*>::const_iterator it2 = e2.begin();
     while (it2 != e2.end()){
-      if(std::find(e.begin(), e.end(), *it2) == e.end())
-        e.push_back(*it2);
+      GEdge *edge = *it2;
+
+      // FIXME: we need to fix the compound design and decide what to do; same
+      // thing for faces() (either store or compute the entities, either use
+      // original or compound entities, etc.)
+      if(edge->getCompound())
+        edge = (GEdge*)edge->getCompound();
+
+      if(std::find(e.begin(), e.end(), edge) == e.end())
+        e.push_back(edge);
       ++it2;
     }
     ++it;
@@ -397,9 +406,8 @@ double GRegion::computeSolidProperties(std::vector<double> cg,
   return volume;
 }
 
-
-std::list<GVertex*> GRegion :: vertices() const {
-
+std::list<GVertex*> GRegion::vertices() const
+{
   std::set<GVertex*> v;
   for (std::list<GFace*>::const_iterator it = l_faces.begin(); it != l_faces.end() ; ++it){
     const GFace *gf = *it;
diff --git a/Geo/GRegion.h b/Geo/GRegion.h
index 110c232..c87d268 100644
--- a/Geo/GRegion.h
+++ b/Geo/GRegion.h
@@ -11,6 +11,7 @@
 #include <vector>
 #include <stdio.h>
 #include "GEntity.h"
+#include "boundaryLayersData.h"
 
 class MElement;
 class MTetrahedron;
@@ -20,6 +21,7 @@ class MPyramid;
 class MPolyhedron;
 class ExtrudeParams;
 class GRegionCompound;
+class BoundaryLayerColumns;
 
 // A model region.
 class GRegion : public GEntity {
@@ -32,6 +34,7 @@ class GRegion : public GEntity {
   // replace faces (for gluing) for specific modelers, we have to
   // re-create internal data ...
   virtual void replaceFacesInternal (std::list<GFace*> &) {}
+  BoundaryLayerColumns _columns;
 
  public:
   GRegion(GModel *model, int tag);
@@ -135,6 +138,8 @@ class GRegion : public GEntity {
   void addPrism(MPrism *p){ prisms.push_back(p); }
   void addPyramid(MPyramid *p){ pyramids.push_back(p); }
   void addPolyhedron(MPolyhedron *p){ polyhedra.push_back(p); }
+  // get the boundary layer columns
+  BoundaryLayerColumns *getColumns () {return &_columns;}
 };
 
 #endif
diff --git a/Geo/Geo.cpp b/Geo/Geo.cpp
index 41e285a..dc09d28 100644
--- a/Geo/Geo.cpp
+++ b/Geo/Geo.cpp
@@ -11,6 +11,7 @@
 #include "GModel.h"
 #include "GeoInterpolation.h"
 #include "Context.h"
+#include "MVertexPositionSet.h"
 
 #if defined(HAVE_MESH)
 #include "Field.h"
@@ -958,6 +959,9 @@ static void CopyVertex(Vertex *v, Vertex *vv)
   vv->Pos.X = v->Pos.X;
   vv->Pos.Y = v->Pos.Y;
   vv->Pos.Z = v->Pos.Z;
+  if(CTX::instance()->geom.copyDisplayAttributes){
+    vv->Visible = v->Visible;
+  }
 }
 
 static Vertex *DuplicateVertex(Vertex *v)
@@ -976,16 +980,20 @@ static int compareAbsCurve(const void *a, const void *b)
   return abs(q->Num) - abs(w->Num);
 }
 
-static void CopyCurve(Curve *c, Curve *cc, bool copyMeshingMethod)
+static void CopyCurve(Curve *c, Curve *cc)
 {
   cc->Typ = c->Typ;
-  if(copyMeshingMethod){
+  if(CTX::instance()->geom.copyMeshingMethod){
     cc->Method = c->Method;
     cc->nbPointsTransfinite = c->nbPointsTransfinite;
     cc->typeTransfinite = c->typeTransfinite;
     cc->coeffTransfinite = c->coeffTransfinite;
     cc->ReverseMesh = c->ReverseMesh;
   }
+  if(CTX::instance()->geom.copyDisplayAttributes){
+    cc->Visible = c->Visible;
+    cc->Color = c->Color;
+  }
   cc->l = c->l;
   for(int i = 0; i < 4; i++)
     for(int j = 0; j < 4; j++)
@@ -999,10 +1007,10 @@ static void CopyCurve(Curve *c, Curve *cc, bool copyMeshingMethod)
   End_Curve(cc);
 }
 
-static Curve *DuplicateCurve(Curve *c, bool copyMeshingMethod)
+static Curve *DuplicateCurve(Curve *c)
 {
   Curve *pc = Create_Curve(NEWLINE(), 0, 1, NULL, NULL, -1, -1, 0., 1.);
-  CopyCurve(c, pc, copyMeshingMethod);
+  CopyCurve(c, pc);
   Tree_Insert(GModel::current()->getGEOInternals()->Curves, &pc);
   for(int i = 0; i < List_Nbr(c->Control_Points); i++) {
     Vertex *v;
@@ -1016,14 +1024,14 @@ static Curve *DuplicateCurve(Curve *c, bool copyMeshingMethod)
   return pc;
 }
 
-static void CopySurface(Surface *s, Surface *ss, bool copyMeshingMethod)
+static void CopySurface(Surface *s, Surface *ss)
 {
-   // Trevor Strickler modified
-   if(s->Typ == MSH_SURF_COMPOUND)
-     ss->Typ = MSH_SURF_REGL;
-   else
-     ss->Typ = s->Typ;
-   if(copyMeshingMethod){
+  // Trevor Strickler modified
+  if(s->Typ == MSH_SURF_COMPOUND)
+    ss->Typ = MSH_SURF_REGL;
+  else
+    ss->Typ = s->Typ;
+  if(CTX::instance()->geom.copyMeshingMethod){
     ss->Method = s->Method;
     ss->Recombine = s->Recombine;
     ss->RecombineAngle = s->RecombineAngle;
@@ -1031,6 +1039,10 @@ static void CopySurface(Surface *s, Surface *ss, bool copyMeshingMethod)
     if(List_Nbr(s->TrsfPoints))
       Msg::Warning("Only automatic transfinite surface specifications can be copied");
   }
+  if(CTX::instance()->geom.copyDisplayAttributes){
+    ss->Visible = s->Visible;
+    ss->Color = s->Color;
+  }
   ss->Generatrices = List_Create(List_Nbr(s->Generatrices) + 1, 1, sizeof(Curve *));
   ss->GeneratricesByTag = List_Create(List_Nbr(s->GeneratricesByTag) + 1, 1, sizeof(int));
   ss->InSphereCenter = s->InSphereCenter; // FIXME: hack...
@@ -1039,44 +1051,48 @@ static void CopySurface(Surface *s, Surface *ss, bool copyMeshingMethod)
   End_Surface(ss);
 }
 
-static Surface *DuplicateSurface(Surface *s, bool copyMeshingMethod)
+static Surface *DuplicateSurface(Surface *s)
 {
   Surface *ps = Create_Surface(NEWSURFACE(), 0);
-  CopySurface(s, ps, copyMeshingMethod);
+  CopySurface(s, ps);
   Tree_Insert(GModel::current()->getGEOInternals()->Surfaces, &ps);
   for(int i = 0; i < List_Nbr(ps->Generatrices); i++) {
     Curve *c;
     List_Read(ps->Generatrices, i, &c);
-    Curve *newc = DuplicateCurve(c, copyMeshingMethod);
+    Curve *newc = DuplicateCurve(c);
     List_Write(ps->Generatrices, i, &newc);
   }
   return ps;
 }
 
-static void CopyVolume(Volume *v, Volume *vv, bool copyMeshingMethod)
+static void CopyVolume(Volume *v, Volume *vv)
 {
   vv->Typ = v->Typ;
-  if(copyMeshingMethod){
+  if(CTX::instance()->geom.copyMeshingMethod){
     vv->Method = v->Method;
     vv->QuadTri = v->QuadTri;
     vv->Recombine3D = v->Recombine3D;
     if(List_Nbr(v->TrsfPoints))
       Msg::Warning("Only automatic transfinite volume specifications can be copied");
   }
+  if(CTX::instance()->geom.copyDisplayAttributes){
+    vv->Visible = v->Visible;
+    vv->Color = v->Color;
+  }
   List_Copy(v->Surfaces, vv->Surfaces);
   List_Copy(v->SurfacesOrientations, vv->SurfacesOrientations);
   List_Copy(v->SurfacesByTag, vv->SurfacesByTag);
 }
 
-static Volume *DuplicateVolume(Volume *v, bool copyMeshingMethod)
+static Volume *DuplicateVolume(Volume *v)
 {
   Volume *pv = Create_Volume(NEWVOLUME(), 0);
-  CopyVolume(v, pv, copyMeshingMethod);
+  CopyVolume(v, pv);
   Tree_Insert(GModel::current()->getGEOInternals()->Volumes, &pv);
   for(int i = 0; i < List_Nbr(pv->Surfaces); i++) {
     Surface *s;
     List_Read(pv->Surfaces, i, &s);
-    Surface *news = DuplicateSurface(s, copyMeshingMethod);
+    Surface *news = DuplicateSurface(s);
     List_Write(pv->Surfaces, i, &news);
   }
   return pv;
@@ -1111,7 +1127,7 @@ void CopyShape(int Type, int Num, int *New)
       Msg::Error("Unknown curve %d", Num);
       return;
     }
-    newc = DuplicateCurve(c, CTX::instance()->geom.copyMeshingMethod);
+    newc = DuplicateCurve(c);
     *New = newc->Num;
     break;
   case MSH_SURF_TRIC:
@@ -1121,7 +1137,7 @@ void CopyShape(int Type, int Num, int *New)
       Msg::Error("Unknown surface %d", Num);
       return;
     }
-    news = DuplicateSurface(s, CTX::instance()->geom.copyMeshingMethod);
+    news = DuplicateSurface(s);
     *New = news->Num;
     break;
   case MSH_VOLUME:
@@ -1129,7 +1145,7 @@ void CopyShape(int Type, int Num, int *New)
       Msg::Error("Unknown volume %d", Num);
       return;
     }
-    newvol = DuplicateVolume(vol, CTX::instance()->geom.copyMeshingMethod);
+    newvol = DuplicateVolume(vol);
     *New = newvol->Num;
     break;
   default:
@@ -2099,39 +2115,38 @@ static List_T *GetCompoundUniqueEdges(Surface *ps)
   // Part 2: Make the unique list
 
   std::vector<int> comp_surfs = ps->compound;
-  if( comp_surfs.size() == 0 || ps->Typ != MSH_SURF_COMPOUND ){
+  if(comp_surfs.size() == 0 || ps->Typ != MSH_SURF_COMPOUND){
     Msg::Error("Surface %d is not compound", ps->Num);
-    return (List_T*)(0);
+    return 0;
   }
 
   int num_surfs = comp_surfs.size();
-  List_T *bnd_c= List_Create(4, 1, sizeof(Curve*));
+  List_T *bnd_c = List_Create(4, 1, sizeof(Curve*));
 
   std::map<int, unsigned int> count_map;
 
   for( int i = 0; i < num_surfs; i++ ){
     Surface *s = FindSurface(std::abs(comp_surfs[i]));
-    if( !s ){
+    if(!s){
       Msg::Error("Unknown surface %d", std::abs(comp_surfs[i]) );
-      return (List_T*)(0);
+      List_Delete(bnd_c);
+      return 0;
     }
     int num_in_surf = List_Nbr(s->Generatrices);
     for( int m = 0; m < num_in_surf; m++ ){
       Curve *c=0;
       List_Read(s->Generatrices, m, &c);
-
-      if( !c ){
+      if(!c){
         Msg::Error("Unknown curve");
-        return (List_T*)(0);
+        List_Delete(bnd_c);
+        return 0;
       }
-
-      if( !FindCurve(-c->Num)  ) {
+      if(!FindCurve(-c->Num)) {
         Msg::Error("Unknown curve %d", -c->Num );
-        return (List_T*)(0);
+        List_Delete(bnd_c);
+        return 0;
       }
-
       int abs_Num = std::abs(c->Num) ;
-
       if( count_map.find( abs_Num ) == count_map.end() )
         count_map[ abs_Num ] = 1;
       else
@@ -2141,7 +2156,7 @@ static List_T *GetCompoundUniqueEdges(Surface *ps)
 
   // Now, create the list of uniques.  Exclude any repeats of abs(c->num) of
   //   course.
-  for( int i = 0; i < num_surfs; i++ ){
+  for(int i = 0; i < num_surfs; i++){
     Surface *s = FindSurface(std::abs(comp_surfs[i]));
     int num_in_surf = List_Nbr(s->Generatrices);
     for( int m = 0; m < num_in_surf; m++ ){
@@ -2151,7 +2166,8 @@ static List_T *GetCompoundUniqueEdges(Surface *ps)
       if( itmap != count_map.end() ){
         if( itmap->second == 1 ){
           List_Add(bnd_c, &c);
-	  // for duplicates  -- if coherence on, do not need. if coherence off, should not try to find them
+	  // for duplicates -- if coherence on, do not need. if coherence off,
+	  // should not try to find them
           /*bool unique_flag = true;
           std::map<int, unsigned int>::iterator itmap2 = count_map.begin();
 
@@ -2173,8 +2189,9 @@ static List_T *GetCompoundUniqueEdges(Surface *ps)
       }
       else{ // if not found the curve in the count_map
         Msg::Error("A problem in finding unique curves in extrusion of compound surface %d",
-                   std::abs(ps->Num) );
-        return (List_T*)(0);
+                   std::abs(ps->Num));
+        List_Delete(bnd_c);
+        return 0;
       }
     }
   }
@@ -2191,57 +2208,60 @@ static List_T *GetCompoundUniqueEdges(Surface *ps)
 // loop.
 // Only one problem: Sometimes holes can be selected as the first loop, though
 // this should not create many real problems on a copied top surface.
-static List_T* GetOrderedUniqueEdges( Surface *s )
+static List_T* GetOrderedUniqueEdges(Surface *s)
 {
   List_T* unique = GetCompoundUniqueEdges(s);
+  if(!unique) return 0;
 
   // need to sort out the list into ordered, oriented loops before passing
   // these into the gmsh geometry system.
   // Have to get list of surface numbers
   int numgen = List_Nbr(unique);
 
-  if(!numgen) return 0;
+  if(!numgen){
+    List_Delete(unique);
+    return 0;
+  }
 
   List_T *gen_nums = List_Create(numgen, 1, sizeof(int));
 
-  for( int i = 0; i < numgen; i++ ){
+  for(int i = 0; i < numgen; i++){
     Curve *ctemp = 0;
     List_Read(unique, i, &ctemp);
-    if( !ctemp ){
-      Msg::Error("No such curve.");
+    if(!ctemp){
+      Msg::Error("No such curve");
+      List_Delete(gen_nums);
+      List_Delete(unique);
       return 0;
     }
-
     List_Add(gen_nums, &(ctemp->Num));
   }
 
-  sortEdgesInLoop(0,gen_nums,1);
+  sortEdgesInLoop(0, gen_nums, 1);
 
   // put sorted list of curve pointers back into compnd_gen and generatrices
   List_Reset(unique);
-  for( int i = 0; i < List_Nbr(gen_nums); i++ ){
-
+  for(int i = 0; i < List_Nbr(gen_nums); i++){
     Curve *ctemp = 0;
     int j;
     List_Read(gen_nums, i, &j);
-    if( !(ctemp = FindCurve(j)) ){
-      Msg::Error("No such curve %d.", j);
+    if(!(ctemp = FindCurve(j))){
+      Msg::Error("No such curve %d", j);
+      List_Delete(gen_nums);
+      List_Delete(unique);
       return 0;
     }
     List_Add(unique, &ctemp);
   }
 
   List_Delete(gen_nums);
-
   return unique;
-
 }
 
 // Duplicate removal
 
 static int compareTwoPoints(const void *a, const void *b)
 {
-
   Vertex *q = *(Vertex **)a;
   Vertex *w = *(Vertex **)b;
 
@@ -2341,15 +2361,130 @@ static void MaxNumSurface(void *a, void *b)
     std::max(GModel::current()->getGEOInternals()->MaxSurfaceNum, s->Num);
 }
 
+static void ReplaceDuplicatePointsNew(double tol = -1.)
+{
+  Msg::Info("New Coherence...");
+  if (tol < 0)
+    tol = CTX::instance()->geom.tolerance * CTX::instance()->lc;
+
+  // create kdtree
+  std::map<MVertex*, Vertex*> v2V;
+  std::vector<MVertex*> all;
+  List_T *tmp = Tree2List(GModel::current()->getGEOInternals()->Points);
+  for(int i = 0; i < List_Nbr(tmp); i++) {
+    Vertex *V;
+    List_Read(tmp, i, &V);
+    MVertex *v = new MVertex(V->Pos.X, V->Pos.Y, V->Pos.Z);
+    all.push_back(v);
+    v2V[v] = V;
+  }
+  List_Delete(tmp);
+  MVertexPositionSet pos(all);
+
+  // touch all points
+  tmp = Tree2List(GModel::current()->getGEOInternals()->Points);
+  for(int i = 0; i < List_Nbr(tmp); i++) {
+    Vertex *V;
+    List_Read(tmp, i, &V);
+    pos.find(V->Pos.X, V->Pos.Y, V->Pos.Z, tol);
+  }
+  List_Delete(tmp);
+
+  // replace points in curves
+  tmp = Tree2List(GModel::current()->getGEOInternals()->Curves);
+
+  for(int i = 0; i < List_Nbr(tmp); i++) {
+    Curve *c;
+    List_Read(tmp, i, &c);
+    // replace begin/end points
+    c->beg = v2V[pos.find(c->beg->Pos.X, c->beg->Pos.Y, c->beg->Pos.Z, tol)];
+    c->end = v2V[pos.find(c->end->Pos.X, c->end->Pos.Y, c->end->Pos.Z, tol)];
+
+    // replace control points
+    for(int j = 0; j < List_Nbr(c->Control_Points); j++) {
+      Vertex *V;
+      List_Read(c->Control_Points, j, &V);
+      List_Write(c->Control_Points, j,
+		 &v2V[pos.find(V->Pos.X, V->Pos.Y, V->Pos.Z, tol)]);
+    }
+    // replace extrusion sources
+    if(c->Extrude && c->Extrude->geo.Mode == EXTRUDED_ENTITY){
+      Vertex *V = FindPoint(std::abs(c->Extrude->geo.Source));
+      if(V) c->Extrude->geo.Source =
+	      v2V[pos.find(V->Pos.X, V->Pos.Y, V->Pos.Z, tol)]->Num;
+    }
+  }
+  List_Delete(tmp);
+
+  // replace points in surfaces
+  tmp = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
+  for(int i = 0; i < List_Nbr(tmp); i++) {
+    Surface *s;
+    List_Read(tmp, i, &s);
+    // replace transfinite corners
+    for(int j = 0; j < List_Nbr(s->TrsfPoints); j++){
+      Vertex *V;
+      List_Read(s->TrsfPoints, j, &V);
+      List_Write(s->TrsfPoints, j,
+                 &v2V[pos.find(V->Pos.X, V->Pos.Y, V->Pos.Z, tol)]);
+    }
+  }
+  List_Delete(tmp);
+
+  // replace points in volumes
+  tmp = Tree2List(GModel::current()->getGEOInternals()->Volumes);
+  for(int i = 0; i < List_Nbr(tmp); i++) {
+    Volume *vol;
+    List_Read(tmp, i, &vol);
+    // replace transfinite corners
+    for(int j = 0; j < List_Nbr(vol->TrsfPoints); j++){
+      Vertex *V;
+      List_Read(vol->TrsfPoints, j, &V);
+      List_Write(vol->TrsfPoints, j,
+                 &v2V[pos.find(V->Pos.X, V->Pos.Y, V->Pos.Z, tol)]);
+    }
+  }
+  List_Delete(tmp);
+
+  // replace points in physical groups
+  for(int i = 0; i < List_Nbr(GModel::current()->getGEOInternals()->PhysicalGroups); i++){
+    PhysicalGroup *p;
+    List_Read(GModel::current()->getGEOInternals()->PhysicalGroups, i, &p);
+    if(p->Typ == MSH_PHYSICAL_POINT){
+      for(int j = 0; j < List_Nbr(p->Entities); j++){
+        int num;
+        List_Read(p->Entities, j, &num);
+        Vertex *V = FindPoint(std::abs(num));
+        if(V) List_Write(p->Entities, j,
+                         &(v2V[pos.find(V->Pos.X, V->Pos.Y, V->Pos.Z, tol)]->Num));
+      }
+    }
+  }
+
+  int start = Tree_Nbr(GModel::current()->getGEOInternals()->Points);
+  for(unsigned int i = 0; i < all.size(); i++){
+    if(all[i]->getIndex() == 0){
+      Vertex *V = v2V[all[i]];
+      Tree_Suppress(GModel::current()->getGEOInternals()->Points, &V);
+      Free_Vertex(&V, NULL);
+    }
+    delete all[i];
+  }
+  int end = Tree_Nbr(GModel::current()->getGEOInternals()->Points);
+  Msg::Info("Done new Coherence (removed %d additional points)", end - start);
+}
 
 static void ReplaceDuplicatePoints(std::map<int, int> * v_report = 0)
 {
-  // FIXME: This routine is in fact logically wrong (the compareTwoPoints
-  // function used in the avl tree is not a appropriate comparison
-  // function). The fix is simple (use a multi dimensional tree, e.g.,
-  // MVertexPositionSet), but fixing the routine would break backward
-  // compatibility with old .geo files. This will be fixed in the new abstract
-  // GModel CAD creation routines.
+  // This routine is logically wrong: the compareTwoPoints() function used in
+  // the avl tree is not an appropriate comparison function. Fixing the routine
+  // is easy (we need to a multi-dimensional tree), but it would break backward
+  // compatibility with old .geo files (the point ids after "Coherence" would
+  // change, as which point gets removed is implementation-dependent).
+  //
+  // Instead, we still use this routine, but call the new one if an error is
+  // detected.
+
   Vertex *v, *v2, **pv, **pv2;
   Curve *c;
   Surface *s;
@@ -2358,7 +2493,6 @@ static void ReplaceDuplicatePoints(std::map<int, int> * v_report = 0)
   Tree_T *allNonDuplicatedPoints = Tree_Create(sizeof(Vertex *), compareTwoPoints);
 
   // Create unique points
-
   int start = Tree_Nbr(GModel::current()->getGEOInternals()->Points);
 
   List_T *All = Tree2List(GModel::current()->getGEOInternals()->Points);
@@ -2382,7 +2516,6 @@ static void ReplaceDuplicatePoints(std::map<int, int> * v_report = 0)
   List_Delete(All);
 
   int end = Tree_Nbr(GModel::current()->getGEOInternals()->Points);
-
   if(start == end) {
     Tree_Delete(points2delete);
     Tree_Delete(allNonDuplicatedPoints);
@@ -2396,21 +2529,34 @@ static void ReplaceDuplicatePoints(std::map<int, int> * v_report = 0)
     Tree_Action(GModel::current()->getGEOInternals()->Points, MaxNumPoint);
   }
 
-  // Replace old points in curves
+  bool success = true;
 
+  // Replace old points in curves
   All = Tree2List(GModel::current()->getGEOInternals()->Curves);
   for(int i = 0; i < List_Nbr(All); i++) {
     List_Read(All, i, &c);
     // replace begin/end points
-    if(!Tree_Query(allNonDuplicatedPoints, &c->beg))
-      Msg::Error("Weird point %d in Coherence", c->beg->Num);
-    if(!Tree_Query(allNonDuplicatedPoints, &c->end))
-      Msg::Error("Weird point %d in Coherence", c->end->Num);
+    if(!Tree_Query(allNonDuplicatedPoints, &c->beg)){
+      Msg::Debug("Could not replace point %d in old Coherence", c->beg->Num);
+      Tree_Insert(GModel::current()->getGEOInternals()->Points, &c->beg);
+      Tree_Suppress(points2delete, &c->beg);
+      success = false;
+    }
+    if(!Tree_Query(allNonDuplicatedPoints, &c->end)){
+      Msg::Debug("Could not replace point %d in old Coherence", c->end->Num);
+      Tree_Insert(GModel::current()->getGEOInternals()->Points, &c->end);
+      Tree_Suppress(points2delete, &c->end);
+      success = false;
+    }
     // replace control points
     for(int j = 0; j < List_Nbr(c->Control_Points); j++) {
       pv = (Vertex **)List_Pointer(c->Control_Points, j);
-      if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, pv)))
-        Msg::Error("Weird point %d in Coherence", (*pv)->Num);
+      if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, pv))){
+        Msg::Debug("Could not replace point %d in old Coherence", (*pv)->Num);
+        Tree_Insert(GModel::current()->getGEOInternals()->Points, pv);
+        Tree_Suppress(points2delete, pv);
+        success = false;
+      }
       else
         List_Write(c->Control_Points, j, pv2);
     }
@@ -2418,8 +2564,12 @@ static void ReplaceDuplicatePoints(std::map<int, int> * v_report = 0)
     if(c->Extrude && c->Extrude->geo.Mode == EXTRUDED_ENTITY){
       v2 = FindPoint(std::abs(c->Extrude->geo.Source), points2delete);
       if(v2){
-        if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, &v2)))
-          Msg::Error("Weird point %d in Coherence", v2->Num);
+        if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, &v2))){
+          Msg::Debug("Could not replace point %d in old Coherence", v2->Num);
+          Tree_Insert(GModel::current()->getGEOInternals()->Points, &v2);
+          Tree_Suppress(points2delete, &v2);
+          success = false;
+        }
         else
           c->Extrude->geo.Source = (*pv2)->Num;
       }
@@ -2428,15 +2578,18 @@ static void ReplaceDuplicatePoints(std::map<int, int> * v_report = 0)
   List_Delete(All);
 
   // Replace old points in surfaces
-
   All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
   for(int i = 0; i < List_Nbr(All); i++) {
     List_Read(All, i, &s);
     // replace transfinite corners
     for(int j = 0; j < List_Nbr(s->TrsfPoints); j++){
       pv = (Vertex **)List_Pointer(s->TrsfPoints, j);
-      if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, pv)))
-        Msg::Error("Weird point %d in Coherence", (*pv)->Num);
+      if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, pv))){
+        Msg::Debug("Could not replace point %d in old Coherence", (*pv)->Num);
+        Tree_Insert(GModel::current()->getGEOInternals()->Points, pv);
+        Tree_Suppress(points2delete, pv);
+        success = false;
+      }
       else
         List_Write(s->TrsfPoints, j, pv2);
     }
@@ -2444,15 +2597,18 @@ static void ReplaceDuplicatePoints(std::map<int, int> * v_report = 0)
   List_Delete(All);
 
   // Replace old points in volumes
-
   All = Tree2List(GModel::current()->getGEOInternals()->Volumes);
   for(int i = 0; i < List_Nbr(All); i++) {
     List_Read(All, i, &vol);
     // replace transfinite corners
     for(int j = 0; j < List_Nbr(vol->TrsfPoints); j++){
       pv = (Vertex **)List_Pointer(vol->TrsfPoints, j);
-      if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, pv)))
-        Msg::Error("Weird point %d in Coherence", (*pv)->Num);
+      if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, pv))){
+        Msg::Debug("Could not replace point %d in old Coherence", (*pv)->Num);
+        Tree_Insert(GModel::current()->getGEOInternals()->Points, pv);
+        Tree_Suppress(points2delete, pv);
+        success = false;
+      }
       else
         List_Write(vol->TrsfPoints, j, pv2);
     }
@@ -2469,8 +2625,12 @@ static void ReplaceDuplicatePoints(std::map<int, int> * v_report = 0)
         List_Read(p->Entities, j, &num);
         v2 = FindPoint(std::abs(num), points2delete);
         if(v2){
-          if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, &v2)))
-            Msg::Error("Weird point %d in Coherence", v2->Num);
+          if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, &v2))){
+            Msg::Debug("Could not replace point %d in old Coherence", v2->Num);
+            Tree_Insert(GModel::current()->getGEOInternals()->Points, &v2);
+            Tree_Suppress(points2delete, &v2);
+            success = false;
+          }
           else
             List_Write(p->Entities, j, &(*pv2)->Num);
         }
@@ -2481,6 +2641,8 @@ static void ReplaceDuplicatePoints(std::map<int, int> * v_report = 0)
   Tree_Action(points2delete, Free_Vertex);
   Tree_Delete(points2delete);
   Tree_Delete(allNonDuplicatedPoints);
+
+  if(!success) ReplaceDuplicatePointsNew();
 }
 
 static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
@@ -2491,7 +2653,6 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
   Tree_T *allNonDuplicatedCurves = Tree_Create(sizeof(Curve *), compareTwoCurves);
 
   // Create unique curves
-
   int start = Tree_Nbr(GModel::current()->getGEOInternals()->Curves);
 
   List_T *All = Tree2List(GModel::current()->getGEOInternals()->Curves);
@@ -2503,6 +2664,9 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
         if(!(c2 = FindCurve(-c->Num))) {
           Msg::Error("Unknown curve %d", -c->Num);
           List_Delete(All);
+          Tree_Action(curves2delete, Free_Curve);
+          Tree_Delete(curves2delete);
+          Tree_Delete(allNonDuplicatedCurves);
           return;
         }
         Tree_Insert(allNonDuplicatedCurves, &c2);
@@ -2537,6 +2701,7 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
   int end = Tree_Nbr(GModel::current()->getGEOInternals()->Curves);
 
   if(start == end) {
+    Tree_Action(curves2delete, Free_Curve);
     Tree_Delete(curves2delete);
     Tree_Delete(allNonDuplicatedCurves);
     return;
@@ -2550,7 +2715,6 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
   }
 
   // Replace old curves in curves
-
   All = Tree2List(GModel::current()->getGEOInternals()->Curves);
   for(int i = 0; i < List_Nbr(All); i++) {
     List_Read(All, i, &c);
@@ -2559,7 +2723,7 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
       c2 = FindCurve(std::abs(c->Extrude->geo.Source), curves2delete);
       if(c2){
         if(!(pc2 = (Curve **)Tree_PQuery(allNonDuplicatedCurves, &c2)))
-          Msg::Error("Weird curve %d in Coherence", c2->Num);
+          Msg::Error("Could not replace curve %d in Coherence", c2->Num);
         else
           c->Extrude->geo.Source = (*pc2)->Num;
       }
@@ -2568,7 +2732,6 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
   List_Delete(All);
 
   // Replace old curves in surfaces
-
   All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
   for(int i = 0; i < List_Nbr(All); i++) {
     List_Read(All, i, &s);
@@ -2576,7 +2739,7 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
     for(int j = 0; j < List_Nbr(s->Generatrices); j++) {
       pc = (Curve **)List_Pointer(s->Generatrices, j);
       if(!(pc2 = (Curve **)Tree_PQuery(allNonDuplicatedCurves, pc)))
-        Msg::Error("Weird curve %d in Coherence", (*pc)->Num);
+        Msg::Error("Could not replace curve %d in Coherence", (*pc)->Num);
       else {
         List_Write(s->Generatrices, j, pc2);
         // arghhh: check compareTwoCurves!
@@ -2588,7 +2751,7 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
       for(int j = 0; j < List_Nbr(s->EmbeddedCurves); j++) {
         pc = (Curve **)List_Pointer(s->EmbeddedCurves, j);
         if(!(pc2 = (Curve **)Tree_PQuery(allNonDuplicatedCurves, pc)))
-          Msg::Error("Weird curve %d in Coherence", (*pc)->Num);
+          Msg::Error("Could not replace curve %d in Coherence", (*pc)->Num);
         else {
           List_Write(s->EmbeddedCurves, j, pc2);
           End_Curve(*pc2);
@@ -2600,7 +2763,7 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
       c2 = FindCurve(std::abs(s->Extrude->geo.Source), curves2delete);
       if(c2){
         if(!(pc2 = (Curve **)Tree_PQuery(allNonDuplicatedCurves, &c2)))
-          Msg::Error("Weird curve %d in Coherence", c2->Num);
+          Msg::Error("Could not replace curve %d in Coherence", c2->Num);
         else
           s->Extrude->geo.Source = (*pc2)->Num;
       }
@@ -2619,7 +2782,7 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
         c2 = FindCurve(std::abs(num), curves2delete);
         if(c2){
           if(!(pc2 = (Curve **)Tree_PQuery(allNonDuplicatedCurves, &c2)))
-            Msg::Error("Weird curve %d in Coherence", c2->Num);
+            Msg::Error("Could not replace curve %d in Coherence", c2->Num);
           else
             List_Write(p->Entities, j, &(*pc2)->Num);
         }
@@ -2632,6 +2795,165 @@ static void ReplaceDuplicateCurves(std::map<int, int> * c_report = 0)
   Tree_Delete(allNonDuplicatedCurves);
 }
 
+/*
+  1) Find duplicate points and replace in curves
+  2) Find duplicate curves and replace in surfaces
+  3) Find duplicate surfaces and replace in volumes
+
+--> some curves are degenerate (zero length)
+--> some surfaces are degenerate (zero surface)
+--> some volumes are degenerate (zero volume)
+
+*/
+
+static void RemoveDegenerateCurves()
+{
+  { // remove degenerate curves from surface generatrices
+    List_T *All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
+    for(int i = 0; i < List_Nbr(All); i++) {
+      Surface *s;
+      List_Read(All, i, &s);
+      List_T *ll = s->Generatrices;
+      s->Generatrices = List_Create(4, 1, sizeof(Curve *));
+      // List_Delete(s->GeneratricesByTag);
+      // s->GeneratricesByTag = List_Create(4, 1, sizeof(int));
+      for(int j = 0; j < List_Nbr(ll); j++) {
+	Curve *c;
+	List_Read(ll, j, &c);
+	if (!c->degenerate()){
+	  List_Add(s->Generatrices, &c);
+	  // List_Add(s->GeneratricesByTag, &c->Num);
+	}
+      }
+      if (List_Nbr(ll) != List_Nbr(s->Generatrices))
+        Msg::Info("Coherence : Surface %d goes from %d to %d boundary curves",
+                  s->Num, List_Nbr(ll), List_Nbr(s->Generatrices));
+      List_Delete(ll);
+    }
+  }
+
+  { // actually remove the curves
+    List_T *All = Tree2List(GModel::current()->getGEOInternals()->Curves);
+    for(int i = 0; i < List_Nbr(All); i++) {
+      Curve *c;
+      List_Read(All, i, &c);
+      if(c->degenerate()) {
+	DeleteCurve(c->Num);
+	// DeleteCurve(-c->Num);
+      }
+    }
+  }
+}
+
+static void RemoveDegenerateVolumes()
+{
+  List_T *Vols = Tree2List(GModel::current()->getGEOInternals()->Volumes);
+  for(int k = 0; k < List_Nbr(Vols); k++) {
+    Volume *v;
+    List_Read(Vols, k, &v);
+    std::set<int> unique;
+    int N = List_Nbr(v->Surfaces);
+    for(int j = 0; j < N; j++) {
+      Surface *s;
+      List_Read(v->Surfaces, j, &s);
+      std::set<int>::iterator it = unique.find(-s->Num);
+      if (it == unique.end()) unique.insert(s->Num);
+      else unique.erase(it);
+    }
+    if(N - unique.size())
+      Msg::Info("Coherence : Removing %d seams on Volume %d", N-unique.size(), v->Num);
+
+    List_T *ll = v->Surfaces;
+    List_T *ll2 = v->SurfacesOrientations;
+    v->Surfaces = List_Create(1, 2, sizeof(Surface *));
+    v->SurfacesOrientations = List_Create(1, 2, sizeof(int));
+    for(int j = 0; j < List_Nbr(ll); j++) {
+      Surface *s;
+      List_Read(ll, j, &s);
+      if (unique.find(s->Num) != unique.end()){
+	List_Add(v->Surfaces,&s);
+	List_Add(v->SurfacesOrientations, List_Pointer(ll2, j));
+      }
+    }
+    List_Delete(ll);
+    List_Delete(ll2);
+    if (List_Nbr(v->Surfaces) == 0){
+      Msg::Info("Coherence Volume %d is removed (degenerated)",v->Num);
+      DeleteVolume(v->Num);
+    }
+  }
+}
+
+static void RemoveDegenerateSurfaces()
+{
+  List_T *All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
+
+  for(int i = 0; i < List_Nbr(All); i++) {
+    Surface *s;
+    std::set<int> unique;
+    List_Read(All, i, &s);
+    int N = List_Nbr(s->Generatrices);
+    for(int j = 0; j < N; j++) {
+      Curve *c;
+      List_Read(s->Generatrices, j, &c);
+      std::set<int>::iterator it = unique.find(-c->Num);
+      if (it == unique.end())unique.insert(c->Num);
+      else unique.erase(it);
+    }
+
+    if (N-unique.size())
+      Msg::Info("Coherence : Removing %d seams on Surface %d", N-unique.size(),s->Num);
+
+    List_T *ll = s->Generatrices;
+    s->Generatrices = List_Create(4, 1, sizeof(Curve *));
+    // List_Delete(s->GeneratricesByTag);
+    // s->GeneratricesByTag = List_Create(4, 1, sizeof(int));
+    for(int j = 0; j < List_Nbr(ll); j++) {
+      Curve *c;
+      List_Read(ll, j, &c);
+      if (unique.find(c->Num) != unique.end()){
+	List_Add(s->Generatrices,&c);
+	// List_Add(s->GeneratricesByTag, &c->Num);
+      }
+    }
+    List_Delete(ll);
+
+    if(s->degenerate()) {
+      Msg::Info("Coherence Surface %d is removed (degenerated)", s->Num);
+      List_T *Vols = Tree2List(GModel::current()->getGEOInternals()->Volumes);
+      for(int k = 0; k < List_Nbr(Vols); k++) {
+	Volume *v;
+	List_Read(Vols, k, &v);
+	List_T *ll= v->Surfaces;
+	List_T *ll2=  v->SurfacesOrientations;
+	v->Surfaces = List_Create(1, 2, sizeof(Surface *));
+	v->SurfacesOrientations = List_Create(1, 2, sizeof(int));
+	for(int j = 0; j < List_Nbr(ll); j++) {
+	  if(compareSurface(List_Pointer(ll, j), &s)){
+	    List_Add(v->Surfaces, List_Pointer(ll, j));
+	    List_Add(v->SurfacesOrientations, List_Pointer(ll2, j));
+	  }
+	}
+	List_Delete (ll);
+	List_Delete (ll2);
+      }
+      DeleteSurface(s->Num);
+    }
+  }
+}
+
+bool Surface::degenerate() const
+{
+  int N = List_Nbr(Generatrices);
+  int Nd = 0;
+  for(int i = 0; i < N; i++) {
+    Curve *c;
+    List_Read(Generatrices, i, &c);
+    if(!c->degenerate())Nd++;
+  }
+  return Nd == 0;
+}
+
 static void ReplaceDuplicateSurfaces(std::map<int, int> *s_report = 0)
 {
   Surface *s, *s2, **ps, **ps2;
@@ -2640,7 +2962,6 @@ static void ReplaceDuplicateSurfaces(std::map<int, int> *s_report = 0)
   Tree_T *allNonDuplicatedSurfaces = Tree_Create(sizeof(Surface *), compareTwoSurfaces);
 
   // Create unique surfaces
-
   int start = Tree_Nbr(GModel::current()->getGEOInternals()->Surfaces);
 
   List_T *All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
@@ -2669,6 +2990,7 @@ static void ReplaceDuplicateSurfaces(std::map<int, int> *s_report = 0)
   int end = Tree_Nbr(GModel::current()->getGEOInternals()->Surfaces);
 
   if(start == end) {
+    Tree_Action(surfaces2delete, Free_Surface);
     Tree_Delete(surfaces2delete);
     Tree_Delete(allNonDuplicatedSurfaces);
     return;
@@ -2682,7 +3004,6 @@ static void ReplaceDuplicateSurfaces(std::map<int, int> *s_report = 0)
   }
 
   // Replace old surfaces in surfaces
-
   All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
   for(int i = 0; i < List_Nbr(All); i++) {
     List_Read(All, i, &s);
@@ -2691,7 +3012,7 @@ static void ReplaceDuplicateSurfaces(std::map<int, int> *s_report = 0)
       s2 = FindSurface(std::abs(s->Extrude->geo.Source), surfaces2delete);
       if(s2){
         if(!(ps2 = (Surface **)Tree_PQuery(allNonDuplicatedSurfaces, &s2)))
-          Msg::Error("Weird surface %d in Coherence", s2->Num);
+          Msg::Error("Could not replace surface %d in Coherence", s2->Num);
         else
           s->Extrude->geo.Source = (*ps2)->Num;
       }
@@ -2700,7 +3021,6 @@ static void ReplaceDuplicateSurfaces(std::map<int, int> *s_report = 0)
   List_Delete(All);
 
   // Replace old surfaces in volumes
-
   All = Tree2List(GModel::current()->getGEOInternals()->Volumes);
   for(int i = 0; i < List_Nbr(All); i++) {
     List_Read(All, i, &vol);
@@ -2708,7 +3028,7 @@ static void ReplaceDuplicateSurfaces(std::map<int, int> *s_report = 0)
     for(int j = 0; j < List_Nbr(vol->Surfaces); j++) {
       ps = (Surface **)List_Pointer(vol->Surfaces, j);
       if(!(ps2 = (Surface **)Tree_PQuery(allNonDuplicatedSurfaces, ps)))
-        Msg::Error("Weird surface %d in Coherence", (*ps)->Num);
+        Msg::Error("Could not replace surface %d in Coherence", (*ps)->Num);
       else
         List_Write(vol->Surfaces, j, ps2);
     }
@@ -2717,7 +3037,7 @@ static void ReplaceDuplicateSurfaces(std::map<int, int> *s_report = 0)
       s2 = FindSurface(std::abs(vol->Extrude->geo.Source), surfaces2delete);
       if(s2){
         if(!(ps2 = (Surface **)Tree_PQuery(allNonDuplicatedSurfaces, &s2)))
-          Msg::Error("Weird surface %d in Coherence", s2->Num);
+          Msg::Error("Could not replace surface %d in Coherence", s2->Num);
         else
           vol->Extrude->geo.Source = (*ps2)->Num;
       }
@@ -2736,7 +3056,7 @@ static void ReplaceDuplicateSurfaces(std::map<int, int> *s_report = 0)
         s2 = FindSurface(std::abs(num), surfaces2delete);
         if(s2){
           if(!(ps2 = (Surface **)Tree_PQuery(allNonDuplicatedSurfaces, &s2)))
-            Msg::Error("Weird surface %d in Coherence", s2->Num);
+            Msg::Error("Could not replace surface %d in Coherence", s2->Num);
           else
             List_Write(p->Entities, j, &(*ps2)->Num);
         }
@@ -2764,6 +3084,12 @@ static void ReplaceAllDuplicates(std::vector<std::map<int, int> > &report)
   ReplaceDuplicatePoints(vertex_report);
   ReplaceDuplicateCurves(curve_report);
   ReplaceDuplicateSurfaces(surface_report);
+
+  if(CTX::instance()->geom.autoCoherence == 2){
+    RemoveDegenerateCurves();
+    RemoveDegenerateSurfaces();
+    RemoveDegenerateVolumes();
+  }
 }
 
 void ReplaceAllDuplicates()
@@ -2773,6 +3099,15 @@ void ReplaceAllDuplicates()
   ReplaceAllDuplicates(report);
 }
 
+void ReplaceAllDuplicatesNew(double tol)
+{
+  if (tol < 0)
+    tol = CTX::instance()->geom.tolerance * CTX::instance()->lc;
+  ReplaceDuplicatePointsNew(tol);
+  ReplaceDuplicateCurves(NULL);
+  ReplaceDuplicateSurfaces(NULL);
+}
+
 // Extrusion routines
 
 void ProtudeXYZ(double &x, double &y, double &z, ExtrudeParams *e)
@@ -3011,7 +3346,7 @@ int Extrude_ProtudeCurve(int type, int ic,
 
   Msg::Debug("Extrude Curve %d", ic);
 
-  chapeau = DuplicateCurve(pc, false);
+  chapeau = DuplicateCurve(pc);
 
   chapeau->Extrude = new ExtrudeParams(COPIED_ENTITY);
   chapeau->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
@@ -3190,7 +3525,7 @@ int Extrude_ProtudeSurface(int type, int is,
 
   Msg::Debug("Extrude Surface %d", is);
 
-  chapeau = DuplicateSurface(ps, false);
+  chapeau = DuplicateSurface(ps);
   chapeau->Extrude = new ExtrudeParams(COPIED_ENTITY);
   chapeau->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
   chapeau->Extrude->geo.Source = is; // not ps->Num: we need the sign info
@@ -3335,7 +3670,7 @@ int Extrude_ProtudeSurface(int type, int is,
     break;
   default:
     Msg::Error("Unknown extrusion type");
-    return ps->Num;
+    break;
   }
 
   // this is done only for backward compatibility with the old
@@ -3366,7 +3701,6 @@ int Extrude_ProtudeSurface(int type, int is,
 
   List_Reset(ListOfTransformedPoints);
 
-
   return chap_num;
 }
 
@@ -3517,7 +3851,7 @@ struct PointSurface{
   Surface *s;
 };
 
-static void projectPS(fullVector<double> &x, fullVector<double> &res, void *data)
+static bool projectPS(fullVector<double> &x, fullVector<double> &res, void *data)
 {
   PointSurface *ps = (PointSurface*)data;
   Vertex c = InterpolateSurface(ps->s, x(0), x(1), 0, 0);
@@ -3531,6 +3865,7 @@ static void projectPS(fullVector<double> &x, fullVector<double> &res, void *data
     (c.Pos.X - ps->p->Pos.X) * dv.Pos.X +
     (c.Pos.Y - ps->p->Pos.Y) * dv.Pos.Y +
     (c.Pos.Z - ps->p->Pos.Z) * dv.Pos.Z;
+  return true;
 }
 
 bool ProjectPointOnSurface(Surface *s, Vertex &p, double uv[2])
@@ -3725,7 +4060,7 @@ bool SplitCurve(int line_id, List_T *vertices_id, List_T *shapes)
     }
   }
   List_Delete(Surfs);
-  
+
   // replace original curve by the new curves in physical groups
   for(int i = 0; i < List_Nbr(GModel::current()->getGEOInternals()->PhysicalGroups); i++){
     PhysicalGroup *p = *(PhysicalGroup**)List_Pointer
@@ -3742,7 +4077,7 @@ bool SplitCurve(int line_id, List_T *vertices_id, List_T *shapes)
       }
     }
   }
-  
+
   DeleteShape(c->Typ, c->Num);
   List_Delete(new_list);
   List_Delete(rshapes);
@@ -3757,7 +4092,7 @@ struct CurveSurface{
   Surface *s;
 };
 
-static void intersectCS(fullVector<double> &uvt, fullVector<double> &res, void *data)
+static bool intersectCS(fullVector<double> &uvt, fullVector<double> &res, void *data)
 {
   CurveSurface *cs = (CurveSurface*)data;
   Vertex vs = InterpolateSurface(cs->s, uvt(0), uvt(1), 0, 0);
@@ -3765,6 +4100,7 @@ static void intersectCS(fullVector<double> &uvt, fullVector<double> &res, void *
   res(0) = vs.Pos.X - vc.Pos.X;
   res(1) = vs.Pos.Y - vc.Pos.Y;
   res(2) = vs.Pos.Z - vc.Pos.Z;
+  return true;
 }
 
 
@@ -3823,6 +4159,7 @@ void sortEdgesInLoop(int num, List_T *edges, bool orient)
       if(c->Typ == MSH_SEGM_DISCRETE){
         Msg::Debug("Aborting line loop sort for discrete edge: hope you know "
 		   "what you're doing ;-)");
+        List_Delete(temp);
         return;
       }
     }
@@ -3961,8 +4298,9 @@ void setSurfaceEmbeddedCurves(Surface *s, List_T *curves)
           int inters = intersection_segments(p3, p4, q3, q4, x);
 
           if (inters && x[0] != 0. && x[1] != 0. && x[0] != 1. && x[1] != 1.){
-            SPoint3 p = SPoint3( (1.-x[0])*p3.x() + x[0]*p4.x() ,
-                                 (1.-x[0])*p3.y() + x[0]*p4.y() , 0);
+            SPoint3 p = SPoint3( (1.-x[0])*p3.x() + x[0]*p4.x(),
+                                 (1.-x[0])*p3.y() + x[0]*p4.y(),
+                                 (1.-x[0])*p3.z() + x[0]*p4.z());
             // case to treat
             bool createPoint = false, mergePoint = false;
             bool splitcToAddInSurf = false, splitcDejaInSurf = false;
diff --git a/Geo/Geo.h b/Geo/Geo.h
index 4097c29..024c7ad 100644
--- a/Geo/Geo.h
+++ b/Geo/Geo.h
@@ -155,6 +155,10 @@ class Curve{
     Color.type = 1;
     Color.geom = Color.mesh = value;
   }
+  bool degenerate() const{
+    if (beg == end && Typ ==  MSH_SEGM_LINE)return true;
+    return false;
+  }
 };
 
 class EdgeLoop{
@@ -214,6 +218,7 @@ class Surface{
       }
     }
   }
+  bool degenerate() const;
 };
 
 class SurfaceLoop{
@@ -392,6 +397,7 @@ int Extrude_ProtudeSurface(int type, int is,
 void ProtudeXYZ(double &x, double &y, double &z, ExtrudeParams *e);
 
 void ReplaceAllDuplicates();
+void ReplaceAllDuplicatesNew(double tol = -1.);
 
 bool ProjectPointOnSurface(Surface *s, Vertex &p, double uv[2]);
 
diff --git a/Geo/GeoInterpolation.cpp b/Geo/GeoInterpolation.cpp
index 1270eb7..37c5b98 100644
--- a/Geo/GeoInterpolation.cpp
+++ b/Geo/GeoInterpolation.cpp
@@ -135,12 +135,14 @@ SPoint2 InterpolateCubicSpline(Vertex *v[4], double t, double mat[4][4],
   }
   return p;
 }
+
 // Bezier
 static Vertex InterpolateBezier(Curve *Curve, double u, int derivee)
 {
   int NbCurves = (List_Nbr(Curve->Control_Points) - 1) / 3;
   int iCurve = (int)floor(u * (double)NbCurves);
-  if(iCurve == NbCurves) iCurve -= 1; // u = 1
+  if(iCurve >= NbCurves) iCurve = NbCurves - 1; // u = 1
+  if(iCurve <= 0) iCurve = 0;
   double t1 = (double)(iCurve) / (double)(NbCurves);
   double t2 = (double)(iCurve+1) / (double)(NbCurves);
   double t = (u - t1) / (t2 - t1);
@@ -546,6 +548,9 @@ static Vertex TransfiniteTri(Vertex c1, Vertex c2, Vertex c3,
 // u = 1 ; v = 0 --> f(1,1) = s2 + s2 - s2 = s2
 // v = 0 --> (1-u)c1(u) + u c1(u) = c1(u) --> COOL
 
+// FIXME: but what happens when v > u ? You interpolate the curves outside
+// ubeg/uend... Argh.
+
 #define TRAN_TRIB(c1,c1b,c2,c2b,c3,c3b,s1,s2,s3,u,v)\
       (1.-u)*(c1+c3b-s1)+(u-v)*(c2+c1b-s2)+v*(c3+c2b-s3);
 
diff --git a/Geo/GeoStringInterface.cpp b/Geo/GeoStringInterface.cpp
index 7b29975..82c5790 100644
--- a/Geo/GeoStringInterface.cpp
+++ b/Geo/GeoStringInterface.cpp
@@ -26,10 +26,18 @@
 
 void add_infile(std::string text, std::string fileName, bool forceDestroy)
 {
+  std::vector<std::string> split = SplitFileName(fileName);
+  std::string noExt = split[0] + split[1], ext = split[2];
+#if defined(HAVE_COMPRESSED_IO) && defined(HAVE_LIBZ)
+  bool compressed = false;
+  if(ext == ".gz"){
+    ext = SplitFileName(noExt)[2];
+    compressed = true;
+  }
+#endif
   // make sure we don't add stuff in a non-geo file
   if(!CTX::instance()->expertMode) {
-    std::vector<std::string> split = SplitFileName(fileName);
-    if(split[2].size() && split[2] != ".geo" && split[2] != ".GEO"){
+    if(ext.size() && ext != ".geo" && ext != ".GEO" ){
       std::ostringstream sstream;
       sstream <<
         "A scripting command is going to be appended to a non-`.geo' file. Are\n"
@@ -68,19 +76,19 @@ void add_infile(std::string text, std::string fileName, bool forceDestroy)
 
 #if defined(HAVE_PARSER)
   std::string tmpFileName = CTX::instance()->homeDir + CTX::instance()->tmpFileName;
-  FILE *gmsh_yyin_old = gmsh_yyin;
-  if(!(gmsh_yyin = Fopen(tmpFileName.c_str(), "w"))) {
+  gmshFILE gmsh_yyin_old = gmsh_yyin;
+  FILE *tmp_file;
+  if(!(tmp_file = Fopen(tmpFileName.c_str(), "w"))) {
     Msg::Error("Unable to open temporary file '%s'", tmpFileName.c_str());
-    gmsh_yyin = gmsh_yyin_old;
     return;
   }
-  fprintf(gmsh_yyin, "%s\n", text.c_str());
-  fclose(gmsh_yyin);
-  gmsh_yyin = Fopen(tmpFileName.c_str(), "r");
-  while(!feof(gmsh_yyin)) {
+  fprintf(tmp_file, "%s\n", text.c_str());
+  fclose(tmp_file);
+  gmsh_yyin = gmshopen(tmpFileName.c_str(), "r");
+  while(!gmsheof(gmsh_yyin)) {
     gmsh_yyparse();
   }
-  fclose(gmsh_yyin);
+  gmshclose(gmsh_yyin);
   gmsh_yyin = gmsh_yyin_old;
 
   if(forceDestroy){
@@ -91,6 +99,28 @@ void add_infile(std::string text, std::string fileName, bool forceDestroy)
   GModel::current()->importGEOInternals();
   CTX::instance()->mesh.changed = ENT_ALL;
 
+  // here we have to be explicit otherwise we append compressed stuff to ascii
+  // file!
+#if defined(HAVE_COMPRESSED_IO) && defined(HAVE_LIBZ)
+  if(compressed){
+    gmshFILE fp = gmshopen(fileName.c_str(), "a");
+    if(!fp) {
+      Msg::Error("Unable to open file '%s'", fileName.c_str());
+      return;
+    }
+    gmshprintf(fp, "%s\n", text.c_str());
+    gmshclose(fp);
+  }
+  else{
+    FILE *fp = Fopen(fileName.c_str(), "a");
+    if(!fp) {
+      Msg::Error("Unable to open file '%s'", fileName.c_str());
+      return;
+    }
+    fprintf(fp, "%s\n", text.c_str());
+    fclose(fp);
+  }
+#else
   FILE *fp = Fopen(fileName.c_str(), "a");
   if(!fp) {
     Msg::Error("Unable to open file '%s'", fileName.c_str());
@@ -98,6 +128,8 @@ void add_infile(std::string text, std::string fileName, bool forceDestroy)
   }
   fprintf(fp, "%s\n", text.c_str());
   fclose(fp);
+#endif
+
 #else
   Msg::Error("GEO file creation not available without Gmsh parser");
 #endif
@@ -208,10 +240,17 @@ void add_param(std::string par, std::string value, std::string label,
                std::string path, std::string fileName)
 {
   std::ostringstream sstream;
-  sstream << "DefineConstant[ " << par << " = { " << value;
-  if(label.size()) sstream << ", Label \"" << label << "\"";
-  if(path.size()) sstream << ", Path \"" << path << "\"";
-  sstream << "}];";
+  sstream << par << " = DefineNumber[ " << value;
+  sstream << ", Name \"";
+  if(path.size() && label.size())
+    sstream << path << "/" << label;
+  else if(path.size())
+    sstream << path << "/" << par;
+  else if(label.size())
+    sstream << label;
+  else
+    sstream << par;
+  sstream << "\" ];";
   add_infile(sstream.str(), fileName);
 }
 
diff --git a/Geo/GeomMeshMatcher.cpp b/Geo/GeomMeshMatcher.cpp
index 79ddb23..29efce6 100644
--- a/Geo/GeomMeshMatcher.cpp
+++ b/Geo/GeomMeshMatcher.cpp
@@ -705,11 +705,17 @@ int GeomMeshMatcher::match(GModel *geom, GModel *mesh)
 
   // This will match SURFACES
   std::vector<Pair<GFace*, GFace*> > *coresp_f = matchFaces(geom, mesh, coresp_e,ok);
-  matchRegions(geom, mesh, coresp_f,ok);
+
+  std::vector<Pair<GRegion*, GRegion*> > *coresp_r = matchRegions(geom, mesh, coresp_f,ok);
 
   std::map<MVertex*,MVertex*> _mesh_to_geom;
   copy_vertices(geom, mesh, _mesh_to_geom,coresp_v,coresp_e,coresp_f);
   copy_elements(geom, mesh, _mesh_to_geom,coresp_v,coresp_e,coresp_f);
 
+  delete coresp_v;
+  delete coresp_e;
+  delete coresp_f;
+  delete coresp_r;
+
   return 1;
 }
diff --git a/Geo/Homology.cpp b/Geo/Homology.cpp
index 97eab68..2893565 100644
--- a/Geo/Homology.cpp
+++ b/Geo/Homology.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #include "Homology.h"
 
@@ -472,8 +472,7 @@ std::vector<int> Homology::_addToModel(int dim, bool co, bool post, int physical
 
 void Homology::addChainsToModel(int dim, bool post, int physicalNumRequest) const
 {
-  //std::vector<int> physicals;
-  if(!_homologyComputed[dim])
+  if(dim > -1 && !_homologyComputed[dim])
     Msg::Warning("%d-Homology is not computed", dim);
   if(dim == -1) {
     for(int j = 0; j < 4; j++) {
@@ -487,7 +486,7 @@ void Homology::addChainsToModel(int dim, bool post, int physicalNumRequest) cons
 
 void Homology::addCochainsToModel(int dim, bool post, int physicalNumRequest) const
 {
-  if(!_cohomologyComputed[dim])
+  if(dim > -1 && !_cohomologyComputed[dim])
     Msg::Warning("%d-Cohomology is not computed", dim);
   if(dim == -1) {
     for(int j = 0; j < 4; j++) {
diff --git a/Geo/Homology.h b/Geo/Homology.h
index 7768a31..5469c04 100644
--- a/Geo/Homology.h
+++ b/Geo/Homology.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #ifndef _HOMOLOGY_H_
 #define _HOMOLOGY_H_
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index adcd2ec..108be65 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -309,6 +309,13 @@ std::string MElement::getInfoString()
   return std::string(tmp);
 }
 
+const nodalBasis* MElement::getFunctionSpace(int order, bool serendip) const
+{
+  if (order == -1) return BasisFactory::getNodalBasis(getTypeForMSH());
+  int tag = ElementType::getTag(getType(), order, serendip);
+  return tag ? BasisFactory::getNodalBasis(tag) : NULL;
+}
+
 static double _computeDeterminantAndRegularize(const MElement *ele, double jac[3][3])
 {
   double dJ = 0;
@@ -461,11 +468,11 @@ void MElement::getSignedJacobian(fullVector<double> &jacobian, int o)
   getJacobianFuncSpace(o)->getSignedJacobian(nodesXYZ,jacobian);
 }
 
-void MElement::getNodesCoord(fullMatrix<double> &nodesXYZ)
+void MElement::getNodesCoord(fullMatrix<double> &nodesXYZ) const
 {
   const int numNodes = getNumShapeFunctions();
   for (int i = 0; i < numNodes; i++) {
-    MVertex *v = getShapeFunctionNode(i);
+    const MVertex *v = getShapeFunctionNode(i);
     nodesXYZ(i,0) = v->x();
     nodesXYZ(i,1) = v->y();
     nodesXYZ(i,2) = v->z();
@@ -1560,3 +1567,19 @@ MElement *MElementFactory::create(int num, int type, const std::vector<int> &dat
 
   return element;
 }
+
+double MElement::skewness() {
+  double minsk = 1.0;
+  for (int i=0;i<getNumFaces();i++){
+    MFace f = getFace(i);
+    if (f.getNumVertices() == 3){
+      //      MTriangle t (f.getVertex(0),f.getVertex(1),f.getVertex(2));
+      //      minsk = std::min(minsk, t.etaShapeMeasure ());
+    }
+    else if (f.getNumVertices() == 4){
+      MQuadrangle q (f.getVertex(0),f.getVertex(1),f.getVertex(2),f.getVertex(3));
+      minsk = std::min(minsk, q.etaShapeMeasure ());
+    }
+  }
+  return minsk;
+}
diff --git a/Geo/MElement.h b/Geo/MElement.h
index 99637b1..db684db 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -179,6 +179,7 @@ class MElement
   double maxDistToStraight();
 
   // get the quality measures
+  double skewness();
   virtual double rhoShapeMeasure();
   virtual double gammaShapeMeasure(){ return 0.; }
   virtual double etaShapeMeasure(){ return 0.; }
@@ -225,7 +226,7 @@ class MElement
   virtual std::string getInfoString();
 
   // get the function space for the element
-  virtual const nodalBasis* getFunctionSpace(int order=-1) const { return 0; }
+  virtual const nodalBasis* getFunctionSpace(int order=-1, bool serendip=false) const;
 
   // get the function space for the jacobian of the element
   virtual const JacobianBasis* getJacobianFuncSpace(int order=-1) const { return 0; }
@@ -271,7 +272,7 @@ class MElement
     double jac[3][3]; return getJacobian(u, v, w, jac);
   }
   void getSignedJacobian(fullVector<double> &jacobian, int o = -1);
-  void getNodesCoord(fullMatrix<double> &nodesXYZ);
+  void getNodesCoord(fullMatrix<double> &nodesXYZ) const;
   virtual int getNumShapeFunctions() const{ return getNumVertices(); }
   virtual int getNumPrimaryShapeFunctions() { return getNumPrimaryVertices(); }
   virtual const MVertex *getShapeFunctionNode(int i) const{ return getVertex(i); }
diff --git a/Geo/MElementCut.cpp b/Geo/MElementCut.cpp
index d80893f..3d14181 100644
--- a/Geo/MElementCut.cpp
+++ b/Geo/MElementCut.cpp
@@ -606,9 +606,9 @@ static void elementSplitMesh(MElement *e, std::vector<gLevelset *> &RPN,
   int gLsTag = RPN[RPN.size() - 1]->getTag();
 
   MElement *copy = e->copy(vertexMap, newParents, newDomains);
-  double eps = 1.e-6;
+  double eps = 1.e-10;
   bool splitElem = false;
- 
+
   //split acording to center of gravity
   // double lsMean = 0.0;
   // int lsTag = 1;
@@ -622,14 +622,14 @@ static void elementSplitMesh(MElement *e, std::vector<gLevelset *> &RPN,
   int ils = 0;
   for(int k = 1; k < e->getNumVertices(); k++){
     int lsTag2 = (verticesLs(iLs, e->getVertex(k)->getIndex()) > eps) ? -1 : 1;
-    if (lsTag * lsTag2 < 0.0) {
+    if (lsTag * lsTag2 < 0) {
       lsTag = -1;
       splitElem = true;
       if(RPN.size() > 1){
         for(; ils < verticesLs.size1() - 1; ils++){
           int lsT1 = (verticesLs(ils, e->getVertex(0)->getIndex()) > eps) ? -1 : 1;
           int lsT2 = (verticesLs(ils, e->getVertex(k)->getIndex()) > eps) ? -1 : 1;
-          if(lsT1 * lsT2 < 0.0) break;
+          if(lsT1 * lsT2 < 0) break;
         }
        for(int i = 0; i <= ils; i++)
           if(!RPN[i]->isPrimitive()) ils++;
@@ -638,7 +638,7 @@ static void elementSplitMesh(MElement *e, std::vector<gLevelset *> &RPN,
       break;
     }
   }
-  
+
   //invert tag
   //lsTag = 1; //negative ls
   //for(int k = 0; k < e->getNumVertices(); k++){
@@ -1412,7 +1412,7 @@ static void elementCutMesh(MElement *e, std::vector<gLevelset *> &RPN,
     break;
   default :
     Msg::Error("This type of element cannot be cut %d.",eType);
-    return;
+    break;
   }
 
   for(unsigned int i = 0; i < ipS.size(); i++)
diff --git a/Geo/MElementCut.h b/Geo/MElementCut.h
index f1a011c..a8229ea 100644
--- a/Geo/MElementCut.h
+++ b/Geo/MElementCut.h
@@ -121,9 +121,9 @@ class MPolyhedron : public MElement {
       vol += _parts[i]->getVolume();
     return vol;
   }
-  virtual const nodalBasis* getFunctionSpace(int order=-1) const
+  virtual const nodalBasis* getFunctionSpace(int order=-1, bool serendip=false) const
   {
-    return (_orig ? _orig->getFunctionSpace(order) : 0);
+    return (_orig ? _orig->getFunctionSpace(order, serendip) : 0);
   }
   virtual const JacobianBasis* getJacobianFuncSpace(int order=-1) const
   {
@@ -271,9 +271,9 @@ class MPolygon : public MElement {
   virtual int getNumChildren() const { return _parts.size(); }
   virtual MElement *getChild(int i) const { return _parts[i]; }
   virtual bool ownsParent() const { return _owner; }
-  virtual const nodalBasis* getFunctionSpace(int order=-1) const
+  virtual const nodalBasis* getFunctionSpace(int order=-1, bool serendip=false) const
   {
-    return (_orig ? _orig->getFunctionSpace(order) : 0);
+    return (_orig ? _orig->getFunctionSpace(order, serendip) : 0);
   }
   virtual const JacobianBasis* getJacobianFuncSpace(int order=-1) const
   {
@@ -341,9 +341,9 @@ class MLineChild : public MLine {
       delete _orig;
   }
   virtual int getTypeForMSH() const { return MSH_LIN_C; }
-  virtual const nodalBasis* getFunctionSpace(int order=-1) const
+  virtual const nodalBasis* getFunctionSpace(int order=-1, bool serendip=false) const
   {
-    if(_orig) return _orig->getFunctionSpace(order);
+    if(_orig) return _orig->getFunctionSpace(order, serendip);
     return 0;
   }
   virtual const JacobianBasis* getJacobianFuncSpace(int order=-1) const
diff --git a/Geo/MHexahedron.cpp b/Geo/MHexahedron.cpp
index f862e64..31f5e74 100644
--- a/Geo/MHexahedron.cpp
+++ b/Geo/MHexahedron.cpp
@@ -193,14 +193,6 @@ int MHexahedronN::getNumEdgesRep(bool curved)
   return curved ? 12 * CTX::instance()->mesh.numSubEdges : 12;
 }
 
-const nodalBasis* MHexahedron::getFunctionSpace(int order) const
-{
-  if (order == -1) return BasisFactory::getNodalBasis(getTypeForMSH());
-
-  int tag = ElementType::getTag(TYPE_HEX, order);
-  return tag ? BasisFactory::getNodalBasis(tag) : NULL;
-}
-
 const JacobianBasis* MHexahedron::getJacobianFuncSpace(int order) const
 {
   if (order == -1) return BasisFactory::getJacobianBasis(getTypeForMSH());
diff --git a/Geo/MHexahedron.h b/Geo/MHexahedron.h
index 22ddc41..94fd92b 100644
--- a/Geo/MHexahedron.h
+++ b/Geo/MHexahedron.h
@@ -59,7 +59,6 @@ class MHexahedron : public MElement {
   virtual MVertex *getVertex(int num){ return _v[num]; }
   virtual const MVertex *getVertex(int num) const { return _v[num]; }
   virtual void setVertex(int num,  MVertex *v){ _v[num] = v; }
-  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const;
   virtual MVertex *getVertexDIFF(int num)
   {
@@ -405,6 +404,7 @@ class MHexahedron27 : public MHexahedron {
     v[8] = _vs[12+num];
   }
   virtual int getTypeForMSH() const { return MSH_HEX_27; }
+  virtual int getTypeForVTK() const { return 29; }
   virtual const char *getStringForPOS() const { return "SH2"; }
   virtual const char *getStringForDIFF() const { return "ElmB27n3D"; }
   virtual void reverse()
diff --git a/Geo/MLine.cpp b/Geo/MLine.cpp
index 4dfc65f..1299cb4 100644
--- a/Geo/MLine.cpp
+++ b/Geo/MLine.cpp
@@ -10,14 +10,7 @@
 #include "GaussLegendre1D.h"
 #include "Context.h"
 #include "qualityMeasures.h"
-
-const nodalBasis* MLine::getFunctionSpace(int order) const
-{
-  if (order == -1) return BasisFactory::getNodalBasis(getTypeForMSH());
-
-  int tag = ElementType::getTag(TYPE_LIN, order);
-  return tag ? BasisFactory::getNodalBasis(tag) : NULL;
-}
+#include "decasteljau.h"
 
 const JacobianBasis* MLine::getJacobianFuncSpace(int order) const
 {
@@ -87,3 +80,62 @@ void MLineN::getEdgeRep(bool curved, int num, double *x, double *y, double *z, S
   }
   else MLine::getEdgeRep(false, num, x, y, z, n);
 }
+
+void MLine::discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts)
+{
+  ts.clear();
+  ts.push_back(-1);
+  ts.push_back(1);
+  dpts.clear();
+  dpts.push_back(getVertex(0)->point());
+  dpts.push_back(getVertex(1)->point());
+}
+
+void MLine3::discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts)
+{
+  SPoint3 p0 = getVertex(0)->point();
+  SPoint3 p2 = getVertex(1)->point();
+  SPoint3 p1 = getVertex(2)->point() * 2 - (p0  + p2) * 0.5;
+  decasteljau(tol, p0, p1, p2, dpts, ts);
+  for (size_t i = 0; i < ts.size(); ++i)
+    ts[i] = -1 + 2 * ts[i];
+}
+
+void MLineN::discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts)
+{
+  int order = getPolynomialOrder();
+  if (order == 3) {
+    SPoint3 p0 = getVertex(0)->point();
+    SPoint3 p3 = getVertex(1)->point();
+    SPoint3 p1 = p0 * (-5./6) + p3 * (1./3) + getVertex(2)->point() * 3. - getVertex(3)->point() * 1.5;
+    SPoint3 p2 = p0 * (1./3) + p3 * (-5./6) - getVertex(2)->point() * 1.5 + getVertex(3)->point() * 3.;
+    decasteljau(tol, p0, p1, p2, p3, dpts, ts);
+    for (size_t i = 0; i < ts.size(); ++i)
+      ts[i] = -1 + 2 * ts[i];
+    return;
+  }
+  fullMatrix<double> lagNodes(order + 1, 3), bezNodes( order + 1, 3);
+  for (int i = 0; i < order + 1; ++i) {
+    MVertex *v = getVertex(i);
+    lagNodes(i, 0) = v->x();
+    lagNodes(i, 1) = v->y();
+    lagNodes(i, 2) = v->z();
+  }
+  const bezierBasis *bez = BasisFactory::getBezierBasis(TYPE_LIN, order);
+  bez->matrixLag2Bez.mult(lagNodes, bezNodes);
+  std::vector<SPoint3> pts(bezNodes.size1());
+  pts[0][0] = bezNodes(0, 0);
+  pts[0][1] = bezNodes(0, 1);
+  pts[0][2] = bezNodes(0, 2);
+  pts[order][0] = bezNodes(1, 0);
+  pts[order][1] = bezNodes(1, 1);
+  pts[order][2] = bezNodes(1, 2);
+  for (int i = 0; i < order - 1; ++i) {
+    pts[i + 1][0] = bezNodes(i + 2, 0);
+    pts[i + 1][1] = bezNodes(i + 2, 1);
+    pts[i + 1][2] = bezNodes(i + 2, 2);
+  }
+  decasteljau(tol, pts, dpts, ts);
+    for (size_t i = 0; i < ts.size(); ++i)
+      ts[i] = -1 + 2 * ts[i];
+}
diff --git a/Geo/MLine.h b/Geo/MLine.h
index d6e4748..378a4d6 100644
--- a/Geo/MLine.h
+++ b/Geo/MLine.h
@@ -74,7 +74,6 @@ class MLine : public MElement {
   {
     MVertex *tmp = _v[0]; _v[0] = _v[1]; _v[1] = tmp;
   }
-  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const;
   virtual bool isInside(double u, double v, double w) const
   {
@@ -97,6 +96,7 @@ class MLine : public MElement {
     return SPoint3(0, 0, 0);
   }
   virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts);
+  virtual void discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts);
 };
 
 /*
@@ -150,6 +150,7 @@ class MLine3 : public MLine {
   {
     num < 2 ? MLine::getNode(num, u, v, w) : MElement::getNode(num, u, v, w);
   }
+  virtual void discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts);
 };
 
 /*
@@ -209,6 +210,7 @@ class MLineN : public MLine {
   {
     num < 2 ? MLine::getNode(num, u, v, w) : MElement::getNode(num, u, v, w);
   }
+  virtual void discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts);
 };
 
 struct compareMLinePtr {
diff --git a/Geo/MPoint.h b/Geo/MPoint.h
index 0ce0bee..df733f1 100644
--- a/Geo/MPoint.h
+++ b/Geo/MPoint.h
@@ -61,10 +61,6 @@ class MPoint : public MElement {
   {
     s[0][0] = s[0][1] = s[0][2] = 0.;
   }
-  virtual const nodalBasis* getFunctionSpace(int o) const
-  {
-    return BasisFactory::getNodalBasis(MSH_PNT);
-  }
   virtual const JacobianBasis* getJacobianFuncSpace(int o) const
   {
     return BasisFactory::getJacobianBasis(MSH_PNT);
diff --git a/Geo/MPrism.cpp b/Geo/MPrism.cpp
index b83af8b..41c2b69 100644
--- a/Geo/MPrism.cpp
+++ b/Geo/MPrism.cpp
@@ -32,14 +32,6 @@ void MPrism::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
   *pts = getGQPriPts(pOrder);
 }
 
-const nodalBasis* MPrism::getFunctionSpace(int order) const
-{
-  if (order == -1) return BasisFactory::getNodalBasis(getTypeForMSH());
-
-  int tag = ElementType::getTag(TYPE_PRI, order);
-  return tag ? BasisFactory::getNodalBasis(tag) : NULL;
-}
-
 const JacobianBasis* MPrism::getJacobianFuncSpace(int order) const
 {
   if (order == -1) return BasisFactory::getJacobianBasis(getTypeForMSH());
@@ -524,3 +516,36 @@ void MPrismN::getFaceVertices(const int num, std::vector<MVertex*> &v) const
   _addFaceNodes(num,_order,_vs,ind,v);
 
 }
+
+static double scaled_jacobian(MVertex* a,MVertex* b,MVertex* c,MVertex* d){
+  double val;
+  double l1,l2,l3;
+  SVector3 vec1,vec2,vec3;
+
+  vec1 = SVector3(b->x()-a->x(),b->y()-a->y(),b->z()-a->z());
+  vec2 = SVector3(c->x()-a->x(),c->y()-a->y(),c->z()-a->z());
+  vec3 = SVector3(d->x()-a->x(),d->y()-a->y(),d->z()-a->z());
+
+  l1 = vec1.norm();
+  l2 = vec2.norm();
+  l3 = vec3.norm();
+
+  val = dot(vec1,crossprod(vec2,vec3));
+  return fabs(val)/(l1*l2*l3);
+}
+
+double MPrism::gammaShapeMeasure() {
+  MVertex *a = getVertex(0),*b= getVertex(1),*c= getVertex(2);
+  MVertex *d = getVertex(3),*e= getVertex(4),*f= getVertex(5);
+  const double j [6] = {
+    scaled_jacobian(a,b,c,d),
+    scaled_jacobian(b,a,c,e),
+    scaled_jacobian(c,a,b,f),
+    scaled_jacobian(d,a,e,f),
+    scaled_jacobian(e,b,d,f),
+    scaled_jacobian(f,c,d,e)};  
+  const double result = *std::min_element(j,j+6);
+  printf("%12.5E\n",result);
+  return result;
+}
+
diff --git a/Geo/MPrism.h b/Geo/MPrism.h
index 2a2075f..df37180 100644
--- a/Geo/MPrism.h
+++ b/Geo/MPrism.h
@@ -128,8 +128,8 @@ class MPrism : public MElement {
     tmp = _v[0]; _v[0] = _v[1]; _v[1] = tmp;
     tmp = _v[3]; _v[3] = _v[4]; _v[4] = tmp;
   }
-  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const;
+  virtual double gammaShapeMeasure();
   virtual int getVolumeSign();
   virtual void getNode(int num, double &u, double &v, double &w) const
   {
diff --git a/Geo/MPyramid.cpp b/Geo/MPyramid.cpp
index 4bf9103..1d2af2d 100644
--- a/Geo/MPyramid.cpp
+++ b/Geo/MPyramid.cpp
@@ -33,14 +33,6 @@ void MPyramid::getIntegrationPoints(int pOrder, int *npts, IntPt **pts)
   *pts = getGQPyrPts(pOrder);
 }
 
-const nodalBasis* MPyramid::getFunctionSpace(int order) const
-{
-  if (order == -1) return BasisFactory::getNodalBasis(getTypeForMSH());
-
-  int tag = ElementType::getTag(TYPE_PYR, order);
-  return tag ? BasisFactory::getNodalBasis(tag) : NULL;
-}
-
 const JacobianBasis* MPyramid::getJacobianFuncSpace(int o) const
 {
   // FIXME add other order and see MPyramid::getFunctionSpace for 'design'
diff --git a/Geo/MPyramid.h b/Geo/MPyramid.h
index 423a7d0..7bfdc27 100644
--- a/Geo/MPyramid.h
+++ b/Geo/MPyramid.h
@@ -69,7 +69,6 @@ class MPyramid : public MElement {
   virtual MVertex *getVertex(int num){ return _v[num]; }
   virtual const MVertex *getVertex(int num) const{ return _v[num]; }
   virtual void setVertex(int num,  MVertex *v){ _v[num] = v; }
-  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const;
   virtual int getNumEdges(){ return 8; }
   virtual MEdge getEdge(int num) const
@@ -166,7 +165,6 @@ class MPyramid : public MElement {
   }
   static int faces_pyramid(const int face, const int vert)
   {
-    // only triangular faces
     static const int f[5][4] = {
       {0, 1, 4, -1},
       {3, 0, 4, -1},
diff --git a/Geo/MQuadrangle.cpp b/Geo/MQuadrangle.cpp
index 271c6d7..56aa05f 100644
--- a/Geo/MQuadrangle.cpp
+++ b/Geo/MQuadrangle.cpp
@@ -7,7 +7,6 @@
 #include "MQuadrangle.h"
 #include "GaussLegendre1D.h"
 #include "Context.h"
-#include "qualityMeasures.h"
 #include "Numeric.h"
 #include "BasisFactory.h"
 
@@ -17,14 +16,6 @@
 
 #define SQU(a)      ((a)*(a))
 
-const nodalBasis* MQuadrangle::getFunctionSpace(int order) const
-{
-  if (order == -1) return BasisFactory::getNodalBasis(getTypeForMSH());
-
-  int tag = ElementType::getTag(TYPE_QUA, order);
-  return tag ? BasisFactory::getNodalBasis(tag) : NULL;
-}
-
 const JacobianBasis* MQuadrangle::getJacobianFuncSpace(int order) const
 {
   if (order == -1) return BasisFactory::getJacobianBasis(getTypeForMSH());
diff --git a/Geo/MQuadrangle.h b/Geo/MQuadrangle.h
index 07f171f..187e6c6 100644
--- a/Geo/MQuadrangle.h
+++ b/Geo/MQuadrangle.h
@@ -117,7 +117,6 @@ class MQuadrangle : public MElement {
   virtual const char *getStringForBDF() const { return "CQUAD4"; }
   virtual const char *getStringForDIFF() const { return "ElmB4n2D"; }
   virtual const char *getStringForINP() const { return "CPS4"/*"C2D4"*/; }
-  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const;
   virtual void getNode(int num, double &u, double &v, double &w) const
   {
@@ -316,6 +315,7 @@ class MQuadrangle9 : public MQuadrangle {
     v[8] = _vs[4];
   }
   virtual int getTypeForMSH() const { return MSH_QUA_9; }
+  virtual int getTypeForVTK() const { return 28; }
   virtual const char *getStringForPOS() const { return "SQ2"; }
   virtual const char *getStringForDIFF() const { return "ElmB9n2D"; }
   virtual void reverse()
@@ -400,6 +400,10 @@ class MQuadrangleN : public MQuadrangle {
     MQuadrangle::_getFaceVertices(v);
     for(unsigned int i = 0; i != _vs.size(); ++i) v[i + 4] = _vs[i];
   }
+  virtual const char *getStringForPOS() const
+  {
+    return (getTypeForMSH() == MSH_QUA_9) ? "SQ2" : "SQ";
+  }
   virtual int getTypeForMSH() const
   {
     if(_order== 1 && _vs.size() + 4 == 4)   return MSH_QUA_4;
@@ -425,6 +429,12 @@ class MQuadrangleN : public MQuadrangle {
     Msg::Error("no tag matches a p%d quadrangle with %d vertices", _order, 4+_vs.size());
     return 0;
   }
+  virtual int getTypeForVTK() const
+  {
+    if(_order== 2 && _vs.size() + 4 == 9) return 28;
+    if(_order== 2 && _vs.size() + 4 == 8)  return 23;
+    return MQuadrangle::getTypeForVTK();
+  }
   virtual void reverse()
   {
     MVertex *tmp;
@@ -479,7 +489,7 @@ struct compareMQuadrangleLexicographic
     if(_v1[1] > _v2[1]) return false;
     if(_v1[2] < _v2[2]) return true;
     if(_v1[2] > _v2[2]) return false;
-    if(_v1[3] < _v1[3]) return true;
+    if(_v1[3] < _v2[3]) return true;
     return false;
   }
 };
diff --git a/Geo/MSubElement.cpp b/Geo/MSubElement.cpp
index 3a4e24d..ae58a39 100644
--- a/Geo/MSubElement.cpp
+++ b/Geo/MSubElement.cpp
@@ -17,9 +17,9 @@ MSubTetrahedron::~MSubTetrahedron()
   if(_base) delete _base;
 }
 
-const nodalBasis* MSubTetrahedron::getFunctionSpace(int order) const
+const nodalBasis* MSubTetrahedron::getFunctionSpace(int order, bool serendip) const
 {
-  if(_orig) return _orig->getFunctionSpace(order);
+  if(_orig) return _orig->getFunctionSpace(order, serendip);
   return 0;
 }
 
@@ -209,9 +209,9 @@ MSubTriangle::~MSubTriangle()
   if(_base) delete _base;
 }
 
-const nodalBasis* MSubTriangle::getFunctionSpace(int order) const
+const nodalBasis* MSubTriangle::getFunctionSpace(int order, bool serendip) const
 {
-  if(_orig) return _orig->getFunctionSpace(order);
+  if(_orig) return _orig->getFunctionSpace(order, serendip);
   return 0;
 }
 
@@ -447,9 +447,9 @@ MSubLine::~MSubLine()
   if(_base) delete _base;
 }
 
-const nodalBasis* MSubLine::getFunctionSpace(int order) const
+const nodalBasis* MSubLine::getFunctionSpace(int order, bool serendip) const
 {
-  if(_orig) return _orig->getFunctionSpace(order);
+  if(_orig) return _orig->getFunctionSpace(order, serendip);
   return 0;
 }
 
@@ -676,9 +676,9 @@ MSubPoint::~MSubPoint()
   if(_base) delete _base;
 }
 
-const nodalBasis* MSubPoint::getFunctionSpace(int order) const
+const nodalBasis* MSubPoint::getFunctionSpace(int order, bool serendip) const
 {
-  if(_orig) return _orig->getFunctionSpace(order);
+  if(_orig) return _orig->getFunctionSpace(order, serendip);
   return 0;
 }
 
diff --git a/Geo/MSubElement.h b/Geo/MSubElement.h
index 72404d0..9415ead 100644
--- a/Geo/MSubElement.h
+++ b/Geo/MSubElement.h
@@ -41,7 +41,7 @@ class MSubTetrahedron : public MTetrahedron
   ~MSubTetrahedron();
 
   virtual int getTypeForMSH() const { return MSH_TET_SUB; }
-  virtual const nodalBasis* getFunctionSpace(int order=-1) const;
+  virtual const nodalBasis* getFunctionSpace(int order=-1, bool serendip=false) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int order=-1) const;
   // the parametric coordinates are the coordinates in the local parent element
   virtual void getShapeFunctions(double u, double v, double w, double s[], int order=-1) const;
@@ -99,7 +99,7 @@ class MSubTriangle : public MTriangle
   ~MSubTriangle();
 
   virtual int getTypeForMSH() const { return MSH_TRI_SUB; }
-  virtual const nodalBasis* getFunctionSpace(int order=-1) const;
+  virtual const nodalBasis* getFunctionSpace(int order=-1, bool serendip=false) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int order=-1) const;
   // the parametric coordinates are the coordinates in the local parent element
   virtual void getShapeFunctions(double u, double v, double w, double s[], int order=-1) const;
@@ -157,7 +157,7 @@ class MSubLine : public MLine
   ~MSubLine();
 
   virtual int getTypeForMSH() const { return MSH_LIN_SUB; }
-  virtual const nodalBasis* getFunctionSpace(int order=-1) const;
+  virtual const nodalBasis* getFunctionSpace(int order=-1, bool serendip=false) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int order=-1) const;
   // the parametric coordinates are the coordinates in the local parent element
   virtual void getShapeFunctions(double u, double v, double w, double s[], int order=-1) const;
@@ -215,7 +215,7 @@ class MSubPoint : public MPoint
   ~MSubPoint();
 
   virtual int getTypeForMSH() const { return MSH_PNT_SUB; }
-  virtual const nodalBasis* getFunctionSpace(int order=-1) const;
+  virtual const nodalBasis* getFunctionSpace(int order=-1, bool serendip=false) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int order=-1) const;
   // the parametric coordinates are the coordinates in the local parent element
   virtual void getShapeFunctions(double u, double v, double w, double s[], int order=-1) const;
diff --git a/Geo/MTetrahedron.cpp b/Geo/MTetrahedron.cpp
index 6a7ce29..43e5587 100644
--- a/Geo/MTetrahedron.cpp
+++ b/Geo/MTetrahedron.cpp
@@ -100,14 +100,6 @@ void MTetrahedron::xyz2uvw(double xyz[3], double uvw[3]) const
   sys3x3(mat, b, uvw, &det);
 }
 
-const nodalBasis* MTetrahedron::getFunctionSpace(int order) const
-{
-  if (order == -1) return BasisFactory::getNodalBasis(getTypeForMSH());
-
-  int tag = ElementType::getTag(TYPE_TET, order);
-  return tag ? BasisFactory::getNodalBasis(tag) : NULL;
-}
-
 const JacobianBasis* MTetrahedron::getJacobianFuncSpace(int order) const
 {
   if (order == -1) return BasisFactory::getJacobianBasis(getTypeForMSH());
diff --git a/Geo/MTetrahedron.h b/Geo/MTetrahedron.h
index 245fdc0..721b880 100644
--- a/Geo/MTetrahedron.h
+++ b/Geo/MTetrahedron.h
@@ -129,7 +129,6 @@ class MTetrahedron : public MElement {
   virtual double getCircumRadius();
   virtual double etaShapeMeasure();
   virtual void xyz2uvw(double xyz[3], double uvw[3]) const;
-  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const;
   virtual void getNode(int num, double &u, double &v, double &w) const
   {
diff --git a/Geo/MTriangle.cpp b/Geo/MTriangle.cpp
index 28ab257..587d7a1 100644
--- a/Geo/MTriangle.cpp
+++ b/Geo/MTriangle.cpp
@@ -116,14 +116,6 @@ void MTriangle::xyz2uvw(double xyz[3], double uvw[3]) const
   uvw[2] = 0.;
 }
 
-const nodalBasis* MTriangle::getFunctionSpace(int order) const
-{
-  if (order == -1) return BasisFactory::getNodalBasis(getTypeForMSH());
-
-  int tag = ElementType::getTag(TYPE_TRI, order);
-  return tag ? BasisFactory::getNodalBasis(tag) : NULL;
-}
-
 const JacobianBasis* MTriangle::getJacobianFuncSpace(int order) const
 {
   if (order == -1) return BasisFactory::getJacobianBasis(getTypeForMSH());
diff --git a/Geo/MTriangle.h b/Geo/MTriangle.h
index dbda43a..3b8fba8 100644
--- a/Geo/MTriangle.h
+++ b/Geo/MTriangle.h
@@ -124,7 +124,6 @@ class MTriangle : public MElement {
   {
     MVertex *tmp = _v[1]; _v[1] = _v[2]; _v[2] = tmp;
   }
-  virtual const nodalBasis* getFunctionSpace(int o=-1) const;
   virtual const JacobianBasis* getJacobianFuncSpace(int o=-1) const;
   virtual void getNode(int num, double &u, double &v, double &w) const
   {
@@ -328,6 +327,7 @@ class MTriangleN : public MTriangle {
     Msg::Error("no tag matches a p%d triangle with %d vertices", _order, 3+_vs.size());
     return 0;
   }
+  virtual int getTypeForVTK() const { return (_order==2) ? 22 : MTriangle::getTypeForVTK(); }
   virtual void reverse()
   {
     MVertex *tmp;
diff --git a/Geo/MVertexPositionSet.h b/Geo/MVertexPositionSet.h
index 27f379e..d8f3fc2 100644
--- a/Geo/MVertexPositionSet.h
+++ b/Geo/MVertexPositionSet.h
@@ -63,6 +63,7 @@ class MVertexPositionSet{
         return _vertices[_index[i]];
     }
     if(_index[0] >= 0 && sqrt(_dist[0]) < tolerance){
+      //      printf("tol %g dist %g x %g %g %g\n",tolerance,_dist[0],x,y,z);
       _vertices[_index[0]]->setIndex(-1);
       return _vertices[_index[0]];
     }
diff --git a/Geo/OCC_Connect.cpp b/Geo/OCC_Connect.cpp
index 1e9dbb9..ff37000 100644
--- a/Geo/OCC_Connect.cpp
+++ b/Geo/OCC_Connect.cpp
@@ -60,6 +60,7 @@
 // Printing routines
 ////////////////////////////////////////////////////////////////////////////////
 
+/*
 static inline ostream &operator <<(ostream &o,const TopAbs_ShapeEnum &A)
 {
     switch(A) {
@@ -86,12 +87,14 @@ static inline ostream &operator <<(ostream &o,const TopAbs_State &A)
     default: return o << "Unknown";
     }
 }
+*/
 
 static inline ostream &operator <<(ostream &o,const gp_Pnt &p)
 {
   return o << "(" << p.Coord(1) << "," << p.Coord(2) << "," << p.Coord(3) << ")";
 }
 
+/*
 static inline ostream &operator <<(ostream &o,const TopOpeBRep_P2Dstatus &A)
 {
     switch(A) {
@@ -103,6 +106,7 @@ static inline ostream &operator <<(ostream &o,const TopOpeBRep_P2Dstatus &A)
     default: return o << "Unknown";
     }
 }
+*/
 
 template <typename T>
 static inline std::ostream &operator<<(std::ostream &out, std::set<T> const &a)
@@ -831,7 +835,7 @@ void OCC_Connect::MergeVertices(TopoDS_Shape &shape1,TopoDS_Shape &shape2) const
 {
     TopTools_IndexedMapOfShape imap, omap;
     TopExp::MapShapes(shape1,TopAbs_VERTEX,imap);
-    TopExp::MapShapes(shape2,TopAbs_VERTEX,imap);
+    TopExp::MapShapes(shape2,TopAbs_VERTEX,omap);
     BRepTools_ReShape replacer;
     for(int i=0;i<imap.Extent();i++) {
         for(int j=0;j<omap.Extent();j++) {
@@ -875,7 +879,7 @@ void OCC_Connect::MergeEdges(TopoDS_Shape &shape1, TopoDS_Shape &shape2) const
 {
     TopTools_IndexedMapOfShape imap, omap;
     TopExp::MapShapes(shape1,TopAbs_EDGE,imap);
-    TopExp::MapShapes(shape2,TopAbs_EDGE,imap);
+    TopExp::MapShapes(shape2,TopAbs_EDGE,omap);
     BRepTools_ReShape replacer;
     for(int i=0;i<imap.Extent();i++) {
         for(int j=0;j<omap.Extent();j++) {
diff --git a/Geo/SOrientedBoundingBox.cpp b/Geo/SOrientedBoundingBox.cpp
index 755fa8b..76d000d 100644
--- a/Geo/SOrientedBoundingBox.cpp
+++ b/Geo/SOrientedBoundingBox.cpp
@@ -314,13 +314,13 @@ SOrientedBoundingBox* SOrientedBoundingBox::buildOBB(std::vector<SPoint3> vertic
     center[0] = (vmaxs(0)+vmins(0))/2.0;
     center[1] = (vmaxs(1)+vmins(1))/2.0;
     center[2] = (vmaxs(2)+vmins(2))/2.0;
-    
+
     return(new SOrientedBoundingBox(center, sizes[0], sizes[1], sizes[2],
                                     Axis1, Axis2, Axis3));
   }
 
-
-  // We take the smallest component, then project the data on the plane defined by the other twos
+  // We take the smallest component, then project the data on the plane defined
+  // by the other twos
 
   int smallest_comp = 0;
   if (sizes[0] <= sizes[1] && sizes[0] <= sizes[2])
@@ -334,9 +334,11 @@ SOrientedBoundingBox* SOrientedBoundingBox::buildOBB(std::vector<SPoint3> vertic
   // We just ignore the coordinate corresponding to smallest_comp.
   std::vector<SPoint2*> points;
   for (int i = 0; i < num_vertices; i++) {
-    SPoint2* p = new SPoint2(projected(smallest_comp==0?1:0,i), projected(smallest_comp==2?1:2,i));
+    SPoint2* p = new SPoint2(projected(smallest_comp==0?1:0,i),
+                             projected(smallest_comp==2?1:2,i));
     bool keep = true;
-    for (std::vector<SPoint2*>::iterator point = points.begin();point != points.end();point++) {
+    for (std::vector<SPoint2*>::iterator point = points.begin();
+         point != points.end();point++) {
       if ( fabs((*p)[0] -(**point)[0]) < 10e-10 && fabs((*p)[1] -(**point)[1]) < 10e-10 ) {
         keep = false;
         break;
@@ -354,12 +356,19 @@ SOrientedBoundingBox* SOrientedBoundingBox::buildOBB(std::vector<SPoint3> vertic
   record.numPoints = points.size();
   srand((unsigned)time(0));
   for (unsigned int i = 0; i < points.size(); i++) {
-    record.points[i].where.h = points[i]->x()+(10e-6)*sizes[smallest_comp==0?1:0]*(-0.5+((double)rand())/RAND_MAX);
-    record.points[i].where.v = points[i]->y()+(10e-6)*sizes[smallest_comp==2?1:0]*(-0.5+((double)rand())/RAND_MAX);
+    record.points[i].where.h = points[i]->x()+
+      (10e-6)*sizes[smallest_comp==0?1:0]*(-0.5+((double)rand())/RAND_MAX);
+    record.points[i].where.v = points[i]->y()+
+      (10e-6)*sizes[smallest_comp==2?1:0]*(-0.5+((double)rand())/RAND_MAX);
     record.points[i].adjacent = NULL;
   }
 
-  record.MakeMeshWithPoints();
+  try{
+    record.MakeMeshWithPoints();
+  }
+  catch(const char *err){
+    Msg::Error("%s", err);
+  }
 
   std::vector<Segment> convex_hull;
   for (int i = 0; i < record.numTriangles; i++) {
@@ -373,8 +382,10 @@ SOrientedBoundingBox* SOrientedBoundingBox::buildOBB(std::vector<SPoint3> vertic
 
     for (int j = 0; j < 3; j++) {
       bool okay = true;
-      for (std::vector<Segment>::iterator seg = convex_hull.begin(); seg != convex_hull.end(); seg++) {
-        if ( ((*seg).from == segs[j].from && (*seg).from == segs[j].to) ||  ((*seg).from == segs[j].to && (*seg).from == segs[j].from)) {
+      for (std::vector<Segment>::iterator seg = convex_hull.begin();
+           seg != convex_hull.end(); seg++) {
+        if ( ((*seg).from == segs[j].from && (*seg).from == segs[j].to) ||
+             ((*seg).from == segs[j].to && (*seg).from == segs[j].from)) {
           convex_hull.erase(seg);
           okay = false;
           break;
@@ -401,7 +412,8 @@ SOrientedBoundingBox* SOrientedBoundingBox::buildOBB(std::vector<SPoint3> vertic
   least_rectangle.size->at(0) = -1;
   least_rectangle.size->at(1) = 1;
 
-  for (std::vector<Segment>::iterator seg = convex_hull.begin(); seg != convex_hull.end(); seg++) {
+  for (std::vector<Segment>::iterator seg = convex_hull.begin();
+       seg != convex_hull.end(); seg++) {
 
     fullVector<double> segment(2);
     //segment(0) = record.points[(*seg).from].where.h - record.points[(*seg).to].where.h;
@@ -457,7 +469,8 @@ SOrientedBoundingBox* SOrientedBoundingBox::buildOBB(std::vector<SPoint3> vertic
     rotation_inv.mult(axis2,axis_rot2);
 //*/
 
-    if ((least_rectangle.area() == -1) || (max_x-min_x)*(max_y-min_y) < least_rectangle.area()) {
+    if ((least_rectangle.area() == -1) ||
+        (max_x-min_x)*(max_y-min_y) < least_rectangle.area()) {
 
       least_rectangle.size->at(0) = max_x-min_x;
       least_rectangle.size->at(1) = max_y-min_y;
@@ -499,8 +512,8 @@ SOrientedBoundingBox* SOrientedBoundingBox::buildOBB(std::vector<SPoint3> vertic
     raw_data[2][2+i] = least_rectangle.axisY->at(0)*left_eigv(i,smallest_comp==0?1:0) +
                        least_rectangle.axisY->at(1)*left_eigv(i,smallest_comp==2?1:2);
   }
-  //  Msg::Info("Test 1 : %f %f",least_rectangle.center->at(0),least_rectangle.center->at(1));
-//  Msg::Info("Test 2 : %f %f",least_rectangle.axisY->at(0),least_rectangle.axisY->at(1));
+  // Msg::Info("Test 1 : %f %f",least_rectangle.center->at(0),least_rectangle.center->at(1));
+  // Msg::Info("Test 2 : %f %f",least_rectangle.axisY->at(0),least_rectangle.axisY->at(1));
 
   int tri[3];
 
@@ -558,7 +571,8 @@ SOrientedBoundingBox* SOrientedBoundingBox::buildOBB(std::vector<SPoint3> vertic
     aux2(i) = left_eigv(i,smallest_comp==0?1:0);
     aux3(i) = left_eigv(i,smallest_comp==2?1:2);
   }
-  center = aux1*center_pca + aux2*least_rectangle.center->at(0) + aux3*least_rectangle.center->at(1);
+  center = aux1*center_pca + aux2*least_rectangle.center->at(0) +
+    aux3*least_rectangle.center->at(1);
   //center[1] = -center[1];
 
   /*
@@ -578,7 +592,8 @@ SOrientedBoundingBox* SOrientedBoundingBox::buildOBB(std::vector<SPoint3> vertic
 #endif
 }
 
-double SOrientedBoundingBox::compare(SOrientedBoundingBox& obb1, SOrientedBoundingBox& obb2)
+double SOrientedBoundingBox::compare(SOrientedBoundingBox& obb1,
+                                     SOrientedBoundingBox& obb2)
 {
   // "center term"
   double center_term = norm(obb1.getCenter() - obb2.getCenter());
@@ -587,7 +602,8 @@ double SOrientedBoundingBox::compare(SOrientedBoundingBox& obb1, SOrientedBoundi
   double size_term = 0.0;
   for (int i = 0; i < 3; i++) {
     if ((obb1.getSize())(i) + (obb2.getSize())(i) != 0) {
-      size_term += fabs((obb1.getSize())(i) - (obb2.getSize())(i)) / ((obb1.getSize())(i) + (obb2.getSize())(i));
+      size_term += fabs((obb1.getSize())(i) - (obb2.getSize())(i)) /
+        ((obb1.getSize())(i) + (obb2.getSize())(i));
     }
   }
 
@@ -598,5 +614,4 @@ double SOrientedBoundingBox::compare(SOrientedBoundingBox& obb1, SOrientedBoundi
   }
 
   return (center_term + size_term + orientation_term);
-
 }
diff --git a/Geo/STensor3.cpp b/Geo/STensor3.cpp
index fee79d2..fc55716 100644
--- a/Geo/STensor3.cpp
+++ b/Geo/STensor3.cpp
@@ -48,6 +48,27 @@ SMetric3 intersection (const SMetric3 &m1, const SMetric3 &m2)
   return iv;
 }
 
+SMetric3 intersection_alauzet (const SMetric3 &m1, const SMetric3 &m2)
+{
+  SMetric3 im1 = m1.invert();
+  fullMatrix<double> V(3,3);
+  fullVector<double> S(3);
+  im1 *= m2;
+  im1.eig(V,S,true);
+  SVector3 v0(V(0,0),V(1,0),V(2,0));
+  SVector3 v1(V(0,1),V(1,1),V(2,1));
+  SVector3 v2(V(0,2),V(1,2),V(2,2));
+  // is this required??
+  v0.normalize();
+  v1.normalize();
+  v2.normalize();
+  double l0 = std::max(dot(v0,m1,v0),dot(v0,m2,v0));
+  double l1 = std::max(dot(v1,m1,v1),dot(v1,m2,v1));
+  double l2 = std::max(dot(v2,m1,v2),dot(v2,m2,v2));
+  SMetric3 iv(l0,l1,l2,v0,v1,v2);
+  return iv;
+}
+
 // preserve orientation of m1 !!!
 SMetric3 intersection_conserveM1 (const SMetric3 &m1, const SMetric3 &m2)
 {
diff --git a/Geo/STensor3.h b/Geo/STensor3.h
index f4afda1..220fde1 100644
--- a/Geo/STensor3.h
+++ b/Geo/STensor3.h
@@ -173,6 +173,8 @@ SMetric3 intersection_conserve_mostaniso_2d (const SMetric3 &m1, const SMetric3
 // compute the largest inscribed ellipsoid...
 SMetric3 intersection (const SMetric3 &m1,
                        const SMetric3 &m2);
+SMetric3 intersection_alauzet (const SMetric3 &m1,
+                       const SMetric3 &m2);
 SMetric3 interpolation (const SMetric3 &m1,
                         const SMetric3 &m2,
                         const double t);
@@ -339,6 +341,15 @@ class STensor3 {
           val = fabs(_val[i]);
     return val;
   };
+  double norm2()const{
+    double sqr = 0;
+    for (int i=0; i<3; i++){
+      for (int j =0; j<3; j++){
+	sqr += this->operator()(i,j)*this->operator()(i,j);
+      }
+    }
+    return sqrt(sqr);
+  }
 };
 
 // tensor product
diff --git a/Geo/SVector3.h b/Geo/SVector3.h
index b942568..815752d 100644
--- a/Geo/SVector3.h
+++ b/Geo/SVector3.h
@@ -30,9 +30,9 @@ class SVector3 {
   inline double z(void) const { return P.z(); }
   inline double norm() const { return sqrt(P[0] * P[0] + P[1] * P[1] + P[2] * P[2]); }
   inline double normSq() const{ return (P[0] * P[0] + P[1] * P[1] + P[2] * P[2]); }
-  // Beware that " w = v.normalize() " produces the vector 
+  // Beware that " w = v.normalize() " produces the vector
   // w = (v.norm(), v.norm(), v.norm()), which is NOT a unit vector!
-  // Use " w = v.unit() " to affect to "w" the unit vector parallel to "v". 
+  // Use " w = v.unit() " to affect to "w" the unit vector parallel to "v".
   double normalize(){
     double n = norm(); if(n){ P[0] /= n; P[1] /= n; P[2] /= n; }
     return n;
@@ -75,6 +75,20 @@ class SVector3 {
 
   // Needed to allow the initialization of a SPoint3 from a SPoint3, a distance and a direction
   SPoint3 point() const{return P;}
+  int getMaxValue(double& val) const{
+    if ((P[0] >=P[1]) && (P[0]>=P[2])){
+      val = P[0];
+      return 0;
+    }
+    else if ((P[1] >=P[0]) && (P[1]>=P[2])){
+      val = P[1];
+      return 1;
+    }
+    else {
+      val = P[2];
+      return 2;
+    }
+  }
 
 };
 
@@ -95,7 +109,7 @@ inline SVector3 crossprod(const SVector3 &a, const SVector3 &b)
 inline double angle (const SVector3 &a, const SVector3 &b){
   double cosTheta = dot(a,b);
   double sinTheta = norm(crossprod(a,b));
-  return atan2 (sinTheta,cosTheta);  
+  return atan2 (sinTheta,cosTheta);
 }
 
 
@@ -146,7 +160,7 @@ inline void buildOrthoBasis_naive(SVector3 &dir, SVector3 &dir1, SVector3 &dir2)
        Msg::Error("Problem with computing orthoBasis");
        Msg::Exit(1);
    }
-   // printf("XYZ =%g %g %g r=%g dir0 = %g %g %g dir1 = %g %g %g dir2 =%g %g %g\n", 
+   // printf("XYZ =%g %g %g r=%g dir0 = %g %g %g dir1 = %g %g %g dir2 =%g %g %g\n",
    // 	  x,y,z,d, dir[0], dir[1], dir[2], dir1[0], dir1[1], dir1[2],  dir2[0], dir2[1], dir2[2] );
    // printf("0x1 =%g 1x2=%g 2x1=%g \n", dot(dir, dir1), dot(dir1,dir2), dot(dir2,dir));
    dir1.normalize();
@@ -166,12 +180,12 @@ inline void buildOrthoBasis(SVector3 &normal, SVector3 &tangent, SVector3 &binor
   //build a binormal from tangent and normal:
   binormal = crossprod(tangent, normal);
   double t1 = binormal.normalize();
-  
+
   //and correct the tangent from the binormal and the normal.
   tangent = crossprod(normal, binormal);
   double t2 = tangent.normalize();
-  
-  if (t1 == 0.0 || t2 == 0.0) 
+
+  if (t1 == 0.0 || t2 == 0.0)
     buildOrthoBasis_naive(normal, tangent, binormal);
 
 }
@@ -186,12 +200,12 @@ inline void buildOrthoBasis2(SVector3 &normal, SVector3 &tangent, SVector3 &bino
   //build a binormal from tangent and normal:
   binormal = crossprod(tangent, normal);
   double t1 = binormal.normalize();
-  
+
   //and correct the tangent from the binormal and the normal.
   tangent = crossprod(normal, binormal);
   double t2 = tangent.normalize();
-  
-  if (t1 == 0.0 || t2 == 0.0) 
+
+  if (t1 == 0.0 || t2 == 0.0)
     buildOrthoBasis_naive(normal, tangent, binormal);
 
 }
diff --git a/Geo/boundaryLayersData.cpp b/Geo/boundaryLayersData.cpp
index 7bbed0a..dc0f707 100644
--- a/Geo/boundaryLayersData.cpp
+++ b/Geo/boundaryLayersData.cpp
@@ -22,7 +22,7 @@
 
 BoundaryLayerField* getBLField(GModel *gm){ return 0; }
 bool buildAdditionalPoints2D (GFace *gf ) { return false; }
-BoundaryLayerColumns * buildAdditionalPoints3D (GRegion *gr) { return 0; }
+bool buildAdditionalPoints3D (GRegion *gr) { return false; }
 void buildMeshMetric(GFace *gf, double *uv, SMetric3 &m, double metric[3]) {}
 faceColumn BoundaryLayerColumns::getColumns(GFace *gf, MVertex *v1, MVertex *v2,
                                             MVertex *v3, int side)
@@ -33,6 +33,7 @@ edgeColumn BoundaryLayerColumns::getColumns(MVertex *v1, MVertex *v2 , int side)
 {
   return edgeColumn(BoundaryLayerData(),BoundaryLayerData());
 }
+
 #else
 
 #include "Field.h"
@@ -145,14 +146,17 @@ void buildMeshMetric(GFace *gf, double *uv, SMetric3 &m, double metric[3])
   metric[2] = res[1][1];
 }
 
-const BoundaryLayerData & BoundaryLayerColumns::getColumn(MVertex *v, MFace f)
+const BoundaryLayerData & BoundaryLayerColumns::getColumn(MVertex *v, MFace f) const
 {
   int N = getNbColumns(v) ;
   if (N == 1) return getColumn(v, 0);
-  GFace *gf = _inverse_classification[f];
-  for (int i=0;i<N;i++){
-    const BoundaryLayerData & c = getColumn(v, i);
-    if (std::find(c._joint.begin(),c._joint.end(),gf) != c._joint.end())return c;
+  std::map<MFace, GFace*, Less_Face>::const_iterator it = _inverse_classification.find(f);
+  if (it != _inverse_classification.end()) {
+    GFace *gf = it->second;
+    for (int i=0;i<N;i++){
+      const BoundaryLayerData & c = getColumn(v, i);
+      if (std::find(c._joint.begin(),c._joint.end(),gf) != c._joint.end())return c;
+    }
   }
   static BoundaryLayerData error;
   return error;
@@ -317,41 +321,41 @@ static void treat2Connections(GFace *gf, MVertex *_myVert, MEdge &e1, MEdge &e2,
       }
       else if (fan){
 
-	if (USEFANS__){
-	  int fanSize = FANSIZE__;
-	  // if the angle is greater than PI, than reverse the sense
-	  double alpha1 = atan2(N1[SIDE].y(),N1[SIDE].x());
-	  double alpha2 = atan2(N2[SIDE].y(),N2[SIDE].x());
-	  double AMAX = std::max(alpha1,alpha2);
-	  double AMIN = std::min(alpha1,alpha2);
-	  MEdge ee[2];
-	  if (alpha1 > alpha2){
-	    ee[0] = e2;ee[1] = e1;
-	  }
-	  else {
-	    ee[0] = e1;ee[1] = e2;
-	  }
-	  if ( AMAX - AMIN >= M_PI){
-	    double temp = AMAX;
-	    AMAX = AMIN + 2*M_PI;
-	    AMIN = temp;
-	    MEdge eee0 = ee[0];
-	    ee[0] = ee[1];ee[1] = eee0;
-	  }
-	  _columns->addFan (_myVert,ee[0],ee[1],true);
-	  for (int i=-1; i<=fanSize; i++){
-	    double t = (double)(i+1)/ (fanSize+1);
-	    double alpha = t * AMAX + (1.-t)* AMIN;
-	    SVector3 x (cos(alpha),sin(alpha),0);
-	    x.normalize();
-	    _dirs.push_back(x);
-	  }
+	int fanSize = FANSIZE__;
+	// if the angle is greater than PI, than reverse the sense
+	double alpha1 = atan2(N1[SIDE].y(),N1[SIDE].x());
+	double alpha2 = atan2(N2[SIDE].y(),N2[SIDE].x());
+	double AMAX = std::max(alpha1,alpha2);
+	double AMIN = std::min(alpha1,alpha2);
+	MEdge ee[2];
+	if (alpha1 > alpha2){
+	  ee[0] = e2;ee[1] = e1;
 	}
 	else {
-	  _dirs.push_back(N1[SIDE]);
-	  _dirs.push_back(N2[SIDE]);
+	  ee[0] = e1;ee[1] = e2;
+	}
+	if ( AMAX - AMIN >= M_PI){
+	  double temp = AMAX;
+	  AMAX = AMIN + 2*M_PI;
+	  AMIN = temp;
+	  MEdge eee0 = ee[0];
+	  ee[0] = ee[1];ee[1] = eee0;
+	}
+	_columns->addFan (_myVert,ee[0],ee[1],true);
+	for (int i=-1; i<=fanSize; i++){
+	  double t = (double)(i+1)/ (fanSize+1);
+	  double alpha = t * AMAX + (1.-t)* AMIN;
+	  SVector3 x (cos(alpha),sin(alpha),0);
+	  x.normalize();
+	  _dirs.push_back(x);
 	}
       }
+      /*
+      else {
+	_dirs.push_back(N1[SIDE]);
+	_dirs.push_back(N2[SIDE]);
+	}
+      */
     }
   }
 }
@@ -965,6 +969,45 @@ fanTopology :: fanTopology (GRegion * gr, const std::set<GEdge*> &detectedFans,
   }
 }
 
+// This is the tricky part
+// We have to find a vector N that has the following properties
+// V = (x,y,z) / (x^2+y^2+z^2)^{1/2} is a point on the unit sphere
+// the n[i]'s are points on the unit sphere
+// V maximizes  min_i (V * n[i])
+// This means I'd like to find point V that is
+
+/*
+static void filterVectors(std::vector<SVector3> &n)
+{
+  std::vector<SVector3> temp;
+  temp.push_back(n[0]);
+  for (unsigned int i = 1 ; i<n.size() ; i++){
+    bool found = false;
+    for (unsigned int j = 0 ; j<temp.size() ; j++){
+      double d = dot(n[i],temp[j]);
+      if (d < 0.98)found = true;
+    }
+    if (found) temp.push_back(n[i]);
+  }
+  n = temp;
+}
+*/
+
+static SVector3 computeBestNormal(std::vector<SVector3> &n)
+{
+  //  filterVectors (n);
+  SVector3 V;
+  if (n.size() == 1)V = n[0];
+  else if (n.size() == 2)V = n[0]+n[1];
+  else if (n.size() == 3)circumCenterXYZ(n[0],n[1],n[2],V);
+  else {
+    Msg::Warning("suboptimal choice for exterior normal: %d vectors to average",n.size());
+    for (unsigned int i = 0 ; i<n.size() ; i++)V+=n[i];
+  }
+  V.normalize();
+  return V;
+}
+
 
 static int createColumnsBetweenFaces(GRegion *gr,
 				     MVertex *myV,
@@ -976,7 +1019,6 @@ static int createColumnsBetweenFaces(GRegion *gr,
 				     fanTopology &ft)
 {
   SVector3 n[256];
-  SPoint3 c[256];
   int count = 0;
   GFace *gfs[256];
 
@@ -987,8 +1029,8 @@ static int createColumnsBetweenFaces(GRegion *gr,
 	   _faces.lower_bound(*it);
 	 itm != _faces.upper_bound(*it); ++itm){
 
-      n[count] += _normals[itm->second->getFace(0)];
-      c[count] = itm->second->getFace(0).barycenter();
+      SVector3 N = _normals[itm->second->getFace(0)];
+      n[count] += N;
     }
     gfs[count] = *it;
     n[count].normalize();
@@ -1013,15 +1055,22 @@ static int createColumnsBetweenFaces(GRegion *gr,
 
 
   for (std::set<int>::iterator it = gs.begin(); it != gs.end() ; ++it){
-    std::pair<std::multimap<int, GFace*>::iterator, std::multimap<int, GFace*>::iterator> range = lGroup.equal_range(*it);
+    std::pair<std::multimap<int, GFace*>::iterator,
+              std::multimap<int, GFace*>::iterator> range = lGroup.equal_range(*it);
     std::vector<GFace*> joint;
-    for (std::multimap<int, GFace*>::iterator itm =  range.first ; itm !=  range.second ; itm++)
+    for (std::multimap<int, GFace*>::iterator itm =  range.first ;
+         itm !=  range.second ; itm++)
       joint.push_back(itm->second);
     joints.push_back(joint);
-    SVector3 avg (0,0,0);
+    //    SVector3 avg (0,0,0);
+    std::vector<SVector3> ns;
+
     for (unsigned int i=0;i<joint.size(); i++){
-      avg += n[inv[joint[i]]];
+      ns.push_back( n[inv[joint[i]]] );
+      //      avg += n[inv[joint[i]]];
     }
+    SVector3 avg = computeBestNormal(ns);
+
     std::vector<MVertex*> _column;
     std::vector<SMetric3> _metrics;
     avg.normalize();
@@ -1034,7 +1083,6 @@ static int createColumnsBetweenFaces(GRegion *gr,
   //    printf("%d %d\n",gs.size(),joints.size());
   //  }
 
-
   // create wedges
   if (joints.size() > 1){
     for (unsigned int I = 0     ; I < joints.size() ; I++){
@@ -1083,7 +1131,7 @@ static void createColumnsOnSymmetryPlane(MVertex *myV,
       //	  printf("%d columns\n",N);
       std::set<GFace*>::iterator itff = _allGFaces.begin();
       GFace *g1 = *itff ; ++itff; GFace *g2 = *itff;
-      int sense = 1;
+      bool sense = true;
       std::vector<GFace*> _joint;
 
       const BoundaryLayerFan *fan = _face_columns->getFan(myV);
@@ -1096,19 +1144,18 @@ static void createColumnsOnSymmetryPlane(MVertex *myV,
 	if (v11 == myV){
 	  if (v12->onWhat()->dim() == 1){
 	    GEdge *ge1 = (GEdge*)v12->onWhat();
-	    //		printf("COUCOU %d %d %d\n",fan->sense,std::find(l1.begin(),l1.end(),ge1) != l1.end(),std::find(l2.begin(),l2.end(),ge1) != l2.end());
 	    if (std::find(l1.begin(),l1.end(),ge1) != l1.end())sense = fan->sense;
-	    else if (std::find(l2.begin(),l2.end(),ge1) != l2.end())sense = -fan->sense;
-	    //else printf("strange1 %d %d \n");
+	    else if (std::find(l2.begin(),l2.end(),ge1) != l2.end())sense = !fan->sense;
 	  }
-	  else Msg::Error("Cannot choose between directions in a BL (dim = %d)",v12->onWhat()->dim());
+	  else
+            Msg::Error("Cannot choose between directions in a BL (dim = %d)",
+                       v12->onWhat()->dim());
 	}
 	else {
 	  if (v11->onWhat()->dim() == 1){
 	    GEdge *ge1 = (GEdge*)v11->onWhat();
 	    if (std::find(l1.begin(),l1.end(),ge1) != l1.end())sense = fan->sense;
-	    else if (std::find(l2.begin(),l2.end(),ge1) != l2.end())sense = -fan->sense;
-	    //else printf("strange2 %d %d \n");
+	    else if (std::find(l2.begin(),l2.end(),ge1) != l2.end())sense = !fan->sense;
 	  }
 	  else Msg::Error("Cannot choose between directions in a BL");
 	}
@@ -1117,13 +1164,13 @@ static void createColumnsOnSymmetryPlane(MVertex *myV,
 	Msg::Error("No fan on the outgoing BL");
       }
       _joint.push_back(g1);
-      const BoundaryLayerData & c0 = _face_columns->getColumn(myV,sense==1 ? 0 : N-1);
+      const BoundaryLayerData & c0 = _face_columns->getColumn(myV,sense ? 0 : N-1);
       _columns->addColumn(c0._n,myV, c0._column, c0._metrics,_joint);
       _joint.clear();
       _joint.push_back(g2);
-      const BoundaryLayerData & cN = _face_columns->getColumn(myV,sense==1 ? N-1 : 0);
+      const BoundaryLayerData & cN = _face_columns->getColumn(myV,sense ? N-1 : 0);
       _columns->addColumn(cN._n,myV, cN._column, cN._metrics,_joint);
-      if (sense==1){
+      if (sense){
 	for (int k=1;k<N-1;k++){
 	  const BoundaryLayerData & c = _face_columns->getColumn(myV,k);
 	  _columns->addColumn(c._n,myV, c._column, c._metrics);
@@ -1161,15 +1208,15 @@ static bool preprocessVertex (MVertex *v,
   return onSymmetryPlane;
 }
 
-BoundaryLayerColumns *buildAdditionalPoints3D(GRegion *gr)
+bool buildAdditionalPoints3D(GRegion *gr)
 {
   BoundaryLayerField *blf = getBLField (gr->model());
 
-  if (!blf)return 0;
+  if (!blf) return false;
 
   blf->setupFor3d();
 
-  BoundaryLayerColumns * _columns = new BoundaryLayerColumns;
+  BoundaryLayerColumns *_columns = gr->getColumns();
 
   std::list<GFace*> faces = gr->faces();
   std::list<GFace*>::iterator itf = faces.begin();
@@ -1299,7 +1346,7 @@ BoundaryLayerColumns *buildAdditionalPoints3D(GRegion *gr)
 
   // END OF DEBUG STUFF
 
-  return _columns;
+  return true;
 }
 
 #endif
diff --git a/Geo/boundaryLayersData.h b/Geo/boundaryLayersData.h
index baf7529..160c1e5 100644
--- a/Geo/boundaryLayersData.h
+++ b/Geo/boundaryLayersData.h
@@ -113,9 +113,9 @@ public:
      return 0;
   }
 
-  const BoundaryLayerData &getColumn(MVertex *v, MFace f);
+  const BoundaryLayerData &getColumn(MVertex *v, MFace f) const;
 
-  inline const BoundaryLayerData &getColumn(MVertex *v, MEdge e)
+  inline const BoundaryLayerData &getColumn(MVertex *v, MEdge e) const
   {
     std::map<MVertex*,BoundaryLayerFan>::const_iterator it = _fans.find(v);
     int N = getNbColumns(v) ;
@@ -133,11 +133,11 @@ public:
   }
   edgeColumn getColumns(MVertex *v1, MVertex *v2 , int side);
   faceColumn getColumns(GFace *gf, MVertex *v1, MVertex *v2 , MVertex* v3, int side);
-  inline int getNbColumns(MVertex *v) { return _data.count(v); }
-  inline const BoundaryLayerData &getColumn(MVertex *v, int iColumn)
+  inline int getNbColumns(MVertex *v) const { return _data.count(v); }
+  inline const BoundaryLayerData &getColumn(MVertex *v, int iColumn) const
   {
     int count = 0;
-    for(std::multimap<MVertex*,BoundaryLayerData>::iterator itm  = _data.lower_bound(v);
+    for(std::multimap<MVertex*,BoundaryLayerData>::const_iterator itm  = _data.lower_bound(v);
         itm != _data.upper_bound(v); ++itm){
       if (count++ == iColumn) return itm->second;
     }
@@ -148,7 +148,7 @@ public:
 
 BoundaryLayerField* getBLField(GModel *gm);
 bool buildAdditionalPoints2D (GFace *gf ) ;
-BoundaryLayerColumns * buildAdditionalPoints3D (GRegion *gr) ;
+bool buildAdditionalPoints3D (GRegion *gr) ;
 void buildMeshMetric(GFace *gf, double *uv, SMetric3 &m, double metric[3]);
 
 #endif
diff --git a/Geo/closestPoint.cpp b/Geo/closestPoint.cpp
new file mode 100644
index 0000000..2b3816d
--- /dev/null
+++ b/Geo/closestPoint.cpp
@@ -0,0 +1,77 @@
+#include "closestPoint.h"
+#include "GEntity.h"
+#include "GEdge.h"
+#include "GFace.h"
+#include <vector>
+
+static void oversample (std::vector<SPoint3> &s, double tol){
+  std::vector<SPoint3> t;
+  for (unsigned int i=1;i<s.size();i++){
+    SPoint3 p0 = s[i-1];
+    SPoint3 p1 = s[i];
+    double d = p0.distance(p1);
+    int N = (int) (d / tol);
+    t.push_back(p0);
+    for (int j=1;j<N;j++){
+      const double xi = (double) j/ N;
+      t.push_back(p0 + (p1-p0)*xi);
+    }
+    t.push_back(p1);
+  }
+  s = t;
+}
+
+closestPointFinder :: closestPointFinder (GEntity *ge, double e) : _tolerance (e)
+{
+#if defined(HAVE_ANN)
+  std::vector<SPoint3> pts;
+  if (ge->dim() == 1){
+    GEdge *edge = ge->cast2Edge();
+    if (edge){
+      std::vector<double> ts;
+      edge->discretize(_tolerance, pts,ts);
+      //    printf("%d points\n",pts.size());
+      oversample (pts, _tolerance);
+      //    printf("%d points after oversampling\n",pts.size());
+    }
+    else{
+      Msg::Error("Can get edge in closestPointFinder");
+    }
+  }
+  index = new ANNidx[1];
+  dist = new ANNdist[1];
+  zeronodes = annAllocPts(pts.size(), 3);
+  for (unsigned int k=0;k<pts.size();k++){
+    zeronodes[k][0] = pts[k].x();
+    zeronodes[k][1] = pts[k].y();
+    zeronodes[k][2] = pts[k].z();
+  }
+  kdtree = new ANNkd_tree(zeronodes, pts.size(), 3);
+#else
+  Msg::Fatal("Gmsh should be compiled using ANN");
+#endif
+}
+
+closestPointFinder :: ~closestPointFinder ()
+{
+#if defined(HAVE_ANN)
+  if(kdtree) delete kdtree;
+  if(zeronodes) annDeallocPts(zeronodes);
+  delete[]index;
+  delete[]dist;
+#endif
+}
+
+SPoint3 closestPointFinder ::operator() (const SPoint3 &p)
+{
+#if defined(HAVE_ANN)
+  double xyz[3] = {p.x(),p.y(),p.z()};
+  kdtree->annkSearch(xyz, 1, index, dist);
+  return SPoint3(zeronodes[index[0]][0],
+		 zeronodes[index[0]][1],
+		 zeronodes[index[0]][2]);
+#else
+  return p;
+#endif
+}
+
diff --git a/Geo/closestPoint.h b/Geo/closestPoint.h
new file mode 100644
index 0000000..b80b6f9
--- /dev/null
+++ b/Geo/closestPoint.h
@@ -0,0 +1,25 @@
+#ifndef _CLOSEST_POINT_H_
+#define _CLOSEST_POINT_H_
+#include "GmshConfig.h"
+#if defined(HAVE_ANN)
+#include "ANN/ANN.h"
+#endif
+#include "SPoint3.h"
+class GEntity;
+class closestPointFinder
+{
+#if defined(HAVE_ANN)
+  ANNkd_tree *kdtree;
+  ANNpointArray zeronodes;
+  ANNidxArray index;
+  ANNdistArray dist;
+#endif
+  double _tolerance;
+ public :
+  closestPointFinder (GEntity*, double);
+  ~closestPointFinder ();
+  SPoint3 operator () (const SPoint3 & p);
+  inline double tol() const {return _tolerance;}
+};
+
+#endif
diff --git a/Geo/findLinks.cpp b/Geo/findLinks.cpp
index 9b4213e..d724282 100644
--- a/Geo/findLinks.cpp
+++ b/Geo/findLinks.cpp
@@ -5,6 +5,7 @@
 
 #include <stdlib.h>
 #include "GmshMessage.h"
+#include "MallocUtils.h"
 #include "GModel.h"
 #include "TreeUtils.h"
 #include "ListUtils.h"
@@ -18,6 +19,13 @@ typedef struct{
   List_T *l;
 }lnk;
 
+
+static void freeLink(void * link)
+{
+  List_Delete(((lnk*) link)->l);
+  Free(link);
+}
+
 static int complink(const void *a, const void *b)
 {
   lnk *q = (lnk*)a;
@@ -38,7 +46,7 @@ static void recurFindLinkedEdges(int ed, List_T *edges, Tree_T *points,
     return;
   }
 
-  int ip[2];  
+  int ip[2];
   ip[0] = ge->getBeginVertex()->tag();
   ip[1] = ge->getEndVertex()->tag();
 
@@ -102,7 +110,7 @@ static void orientAndSortEdges(List_T *edges, Tree_T *links)
   List_T *temp = List_Create(List_Nbr(edges), 1, sizeof(int));
   List_Copy(edges, temp);
   List_Reset(edges);
-  
+
   int num;
   List_Read(temp, 0, &num);
   List_Add(edges, &num);
@@ -110,6 +118,7 @@ static void orientAndSortEdges(List_T *edges, Tree_T *links)
   GEdge *ge0 = GModel::current()->getEdgeByTag(abs(num));
   if(!ge0){
     Msg::Error("Unknown curve %d", abs(num));
+    List_Delete(temp);
     return;
   }
 
@@ -128,6 +137,7 @@ static void orientAndSortEdges(List_T *edges, Tree_T *links)
         GEdge *ge1 = GModel::current()->getEdgeByTag(abs(na.a));
         if(!ge1){
           Msg::Error("Unknown curve %d", abs(na.a));
+          List_Delete(temp);
           return;
         }
         if(lk.n == ge1->getBeginVertex()->tag()){
@@ -144,7 +154,7 @@ static void orientAndSortEdges(List_T *edges, Tree_T *links)
       }
     }
   }
-  
+
   List_Delete(temp);
 }
 
@@ -153,8 +163,11 @@ int allEdgesLinked(int ed, List_T *edges)
   Tree_T *links = Tree_Create(sizeof(lnk), complink);
   Tree_T *points = Tree_Create(sizeof(int), fcmp_int);
 
-  if(!createEdgeLinks(links))
+  if(!createEdgeLinks(links)){
+    Tree_Delete(links, freeLink);
+    Tree_Delete(points);
     return 0;
+  }
 
   // initialize point tree with all hanging points
   for(int i = 0; i < List_Nbr(edges); i++){
@@ -163,6 +176,8 @@ int allEdgesLinked(int ed, List_T *edges)
     GEdge *ge = GModel::current()->getEdgeByTag(abs(num));
     if(!ge){
       Msg::Error("Unknown curve %d", abs(num));
+      Tree_Delete(links, freeLink);
+      Tree_Delete(points);
       return 0;
     }
     int ip[2];
@@ -193,7 +208,7 @@ int allEdgesLinked(int ed, List_T *edges)
     orientAndSortEdges(edges, links);
   }
 
-  Tree_Delete(links);
+  Tree_Delete(links, freeLink);
   Tree_Delete(points);
 
   return found;
@@ -201,7 +216,7 @@ int allEdgesLinked(int ed, List_T *edges)
 
 // Find all linked faces
 
-static void recurFindLinkedFaces(int fac, List_T *faces, Tree_T *edges, 
+static void recurFindLinkedFaces(int fac, List_T *faces, Tree_T *edges,
                                  Tree_T *links)
 {
   GFace *gf = GModel::current()->getFaceByTag(abs(fac));
@@ -265,7 +280,7 @@ int allFacesLinked(int fac, List_T *faces)
 {
   Tree_T *links = Tree_Create(sizeof(lnk), complink);
   Tree_T *edges = Tree_Create(sizeof(int), fcmp_int);
-  
+
   createFaceLinks(links);
 
   // initialize edge tree with all boundary edges
@@ -275,6 +290,8 @@ int allFacesLinked(int fac, List_T *faces)
     GFace *gf = GModel::current()->getFaceByTag(abs(num));
     if(!gf){
       Msg::Error("Unknown surface %d", abs(num));
+      Tree_Delete(links, freeLink);
+      Tree_Delete(edges);
       return 0;
     }
     std::list<GEdge*> l = gf->edges();
@@ -305,7 +322,7 @@ int allFacesLinked(int fac, List_T *faces)
     // necessary...
   }
 
-  Tree_Delete(links);
+  Tree_Delete(links, freeLink);
   Tree_Delete(edges);
 
   return found;
diff --git a/Geo/gmshEdge.cpp b/Geo/gmshEdge.cpp
index 8bd39ea..4d99633 100644
--- a/Geo/gmshEdge.cpp
+++ b/Geo/gmshEdge.cpp
@@ -12,6 +12,7 @@
 #include "GeoInterpolation.h"
 #include "GmshMessage.h"
 #include "Context.h"
+#include "decasteljau.h"
 
 gmshEdge::gmshEdge(GModel *m, Curve *edge, GVertex *v1, GVertex *v2)
   : GEdge(m, edge->Num, v1, v2), c(edge)
@@ -19,6 +20,15 @@ gmshEdge::gmshEdge(GModel *m, Curve *edge, GVertex *v1, GVertex *v2)
   resetMeshAttributes();
 }
 
+bool gmshEdge::degenerate(int dim) const
+{
+  if (c->beg == c->end && c->Typ ==  MSH_SEGM_LINE){
+    Msg::Info("Model Edge %d is degenerate", tag());
+    return true;
+  }
+  return false;
+}
+
 void gmshEdge::resetMeshAttributes()
 {
   meshAttributes.method = c->Method;
@@ -36,7 +46,6 @@ Range<double> gmshEdge::parBounds(int i) const
 
 GPoint gmshEdge::point(double par) const
 {
-
   Vertex a = InterpolateCurve(c, par, 0);
   return GPoint(a.Pos.X, a.Pos.Y, a.Pos.Z, this, par);
 }
@@ -49,7 +58,6 @@ SVector3 gmshEdge::firstDer(double par) const
 
 SVector3 gmshEdge::secondDer(double par) const
 {
-
   Vertex a = InterpolateCurve(c, par, 2);
   return SVector3(a.Pos.X, a.Pos.Y, a.Pos.Z);
 }
@@ -84,6 +92,21 @@ std::string gmshEdge::getAdditionalInfoString()
       sstream << v->Num;
     }
     sstream << "}";
+
+    if(meshAttributes.method == MESH_TRANSFINITE){
+      sstream << " transfinite (" << meshAttributes.nbPointsTransfinite;
+      int type = meshAttributes.typeTransfinite;
+      if(std::abs(type) == 1)
+        sstream << ", progression " << sign(type) * meshAttributes.coeffTransfinite;
+      else if(std::abs(type) == 2)
+        sstream << ", bump " << meshAttributes.coeffTransfinite;
+      sstream << ")";
+    }
+    if(meshAttributes.extrude)
+      sstream << " extruded";
+    if(meshAttributes.reverseMesh)
+      sstream << " reversed";
+
     return sstream.str();
   }
   else
@@ -406,3 +429,127 @@ void gmshEdge::writeGEO(FILE *fp)
   if(meshAttributes.reverseMesh)
     fprintf(fp, "Reverse Line {%d};\n", tag());
 }
+
+static inline SPoint3 curveGetPoint(Curve *c, int i)
+{
+  Vertex *v;
+  List_Read(c->Control_Points, i , &v);
+  return SPoint3(v->Pos.X, v->Pos.Y, v->Pos.Z);
+}
+
+void gmshEdge::discretize(double tol, std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  switch(c->Typ) {
+    case MSH_SEGM_LINE :
+      {
+        int NPt = List_Nbr(c->Control_Points);
+        pts.resize(NPt);
+        ts.resize(NPt);
+        for (int i = 0; i < NPt; ++i) {
+          pts[i]= curveGetPoint(c, i);
+          ts[i] = i / (double) (NPt - 1);
+        }
+        return;
+      }
+    case MSH_SEGM_BEZIER :
+      {
+        int NbCurves = (List_Nbr(c->Control_Points) - 1) / 3;
+        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
+          double t1 = (iCurve) / (double)(NbCurves);
+          double t2 = (iCurve+1) / (double)(NbCurves);
+          SPoint3 pt[4];
+          for(int i = 0; i < 4; i++) {
+            pt[i] = curveGetPoint(c, iCurve * 3 + i);
+          }
+          std::vector<double> lts;
+          std::vector<SPoint3> lpts;
+          decasteljau(tol, pt[0], pt[1], pt[2], pt[3], lpts, lts);
+          for (size_t i = (iCurve == 0 ? 0 : 1); i < lpts.size(); ++i) {
+            pts.push_back(lpts[i]);
+            ts.push_back(t1 + lts[i] * (t2 - t1));
+          }
+        }
+        break;
+      }
+    case MSH_SEGM_BSPLN:
+      {
+        bool periodic = (c->end == c->beg);
+        int NbControlPoints = List_Nbr(c->Control_Points);
+        int NbCurves = NbControlPoints + (periodic ? -1 : 1);
+        SPoint3 pt[4];
+        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
+          double t1 = (iCurve) / (double)(NbCurves);
+          double t2 = (iCurve+1) / (double)(NbCurves);
+          for(int i = 0; i < 4; i++) {
+            int k;
+            if (periodic) {
+              k = (iCurve - 1 + i) % (NbControlPoints - 1);
+              if (k < 0)
+                k += NbControlPoints - 1;
+            }
+            else {
+              k = std::max(0, std::min(iCurve - 2 + i, NbControlPoints -1));
+            }
+            pt[i] = curveGetPoint(c, k);
+          }
+          SPoint3 bpt[4] = {
+            (pt[0] + pt[1] * 4 + pt[2]) * (1./6.),
+            (pt[1] * 2 + pt[2]) * (1./3.),
+            (pt[1] + pt[2] * 2) * (1./3.),
+            (pt[1] + pt[2] * 4 + pt[3]) * (1./6.)
+          };
+          std::vector<double> lts;
+          std::vector<SPoint3> lpts;
+          decasteljau(tol, bpt[0], bpt[1], bpt[2], bpt[3], lpts, lts);
+          for (size_t i = (iCurve == 0 ? 0 : 1); i < lpts.size(); ++i) {
+            pts.push_back(lpts[i]);
+            ts.push_back(t1 + lts[i] * (t2 - t1));
+          }
+        }
+        break;
+      }
+    case MSH_SEGM_SPLN:
+      {
+        int NbCurves = List_Nbr(c->Control_Points) - 1;
+        SPoint3 pt[4];
+        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
+          double t1 = (iCurve) / (double)(NbCurves);
+          double t2 = (iCurve+1) / (double)(NbCurves);
+          pt[1] = curveGetPoint(c, iCurve);
+          pt[2] = curveGetPoint(c, iCurve + 1);
+          if(iCurve == 0) {
+            if(c->beg == c->end)
+              pt[0] = curveGetPoint(c, NbCurves - 1);
+            else
+              pt[0] = SPoint3(pt[1] * 2 - pt[2]);
+          }
+          else
+            pt[0] = curveGetPoint(c, iCurve - 1);
+          if(iCurve == NbCurves - 1) {
+            if(c->beg == c->end)
+              pt[3] = curveGetPoint(c, 1);
+            else
+              pt[3] = SPoint3(2 * pt[2] - pt[1]);
+          }
+          else
+            pt[3] = curveGetPoint(c, iCurve + 2);
+          SPoint3 bpt[4] = {
+            pt[1],
+            (pt[1] * 6 + pt[2] - pt[0]) * (1./6.),
+            (pt[2] * 6 - pt[3] + pt[1]) * (1./6.),
+            pt[2]
+          };
+          std::vector<double> lts;
+          std::vector<SPoint3> lpts;
+          decasteljau(tol, bpt[0], bpt[1], bpt[2], bpt[3], lpts, lts);
+          for (size_t i = (iCurve == 0 ? 0 : 1); i < lpts.size(); ++i) {
+            pts.push_back(lpts[i]);
+            ts.push_back(t1 + lts[i] * (t2 - t1));
+          }
+        }
+        break;
+      }
+    default :
+      GEdge::discretize(tol, pts, ts);
+  }
+}
diff --git a/Geo/gmshEdge.h b/Geo/gmshEdge.h
index f54bcfb..c66d33c 100644
--- a/Geo/gmshEdge.h
+++ b/Geo/gmshEdge.h
@@ -29,6 +29,8 @@ class gmshEdge : public GEdge {
   virtual void resetMeshAttributes();
   virtual SPoint2 reparamOnFace(const GFace *face, double epar, int dir) const;
   virtual void writeGEO(FILE *fp);
+  void discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts);
+  virtual bool degenerate(int dim) const;
 };
 
 #endif
diff --git a/Geo/gmshEdgeDiscretize.cpp b/Geo/gmshEdgeDiscretize.cpp
new file mode 100644
index 0000000..b85e429
--- /dev/null
+++ b/Geo/gmshEdgeDiscretize.cpp
@@ -0,0 +1,196 @@
+#include <cstdio>
+#include <cmath>
+#include <vector>
+#include "SPoint3.h"
+#include "SVector3.h"
+#include "GEdge.h"
+#include "gmshEdge.h"
+#include "Geo.h"
+
+
+class discreteList {
+  std::vector<std::pair<SPoint3, double> > _pts;
+  std::vector<int> _next;
+  public:
+  int insertPoint(int pos, const SPoint3 &pt, double t) {
+    _pts.push_back(std::make_pair(pt, t));
+    _next.push_back(_next[pos + 1]);
+    _next[pos + 1] = _pts.size() - 1;
+    return _pts.size() - 1;
+  }
+  void sort(std::vector<SPoint3> &spts, std::vector<double> &ts) {
+    spts.clear();
+    spts.reserve(_pts.size());
+    ts.clear();
+    ts.reserve(_pts.size());
+    for (int p = _next[0]; p != -1; p = _next[p + 1]) {
+      spts.push_back(_pts[p].first);
+      ts.push_back(_pts[p].second);
+    }
+  }
+  discreteList() {
+    _next.push_back(-1);
+  }
+};
+
+static void decasteljau(double tol, discreteList &discrete, int pos, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2, const SPoint3 &p3, double t0, double t3)
+{
+  SVector3 d30 = p3 - p0;
+  SVector3 d13 = p1 - p3;
+  SVector3 d23 = p2 - p3;
+  SVector3 d130 = crossprod(d13, d30);
+  SVector3 d230 = crossprod(d23, d30);
+  double d = std::max(dot(d130, d130), dot(d230, d230));
+  double l2 = dot(d30, d30);
+
+  if(d < tol * tol * l2) {
+    return;
+  }
+
+  SPoint3 p01((p0 + p1) * 0.5);
+  SPoint3 p12((p1 + p2) * 0.5);
+  SPoint3 p23((p2 + p3) * 0.5);
+  SPoint3 p012((p01 + p12) * 0.5);
+  SPoint3 p123((p12 + p23) * 0.5);
+  SPoint3 p0123((p012 + p123) * 0.5);
+  double t0123 = 0.5 * (t0 + t3);
+  int newpos = discrete.insertPoint(pos, p0123, t0123);
+
+  decasteljau(tol, discrete, pos, p0, p01, p012, p0123, t0, t0123);
+  decasteljau(tol, discrete, newpos, p0123, p123, p23, p3, t0123, t3);
+}
+
+static int discretizeBezier(double tol, discreteList &discrete, int pos, const SPoint3 pt[4], double t0, double t3, bool insertFirstPoint)
+{
+  if (insertFirstPoint)
+    pos = discrete.insertPoint(pos, pt[0], t0);
+  int newp = discrete.insertPoint(pos, pt[3], t3);
+  decasteljau(tol, discrete, pos, pt[0], pt[1], pt[2], pt[3], t0, t3);
+  return newp;
+}
+
+static int discretizeBSpline(double tol, discreteList &discrete, int pos, const SPoint3 pt[4], double t0, double t3, bool insertFirstPoint)
+{
+  SPoint3 bpt[4] = {
+    SPoint3((pt[0] + 4 * pt[1]  + pt[2]) * (1./6.)),
+    SPoint3((2 * pt[1] + pt[2]) * (1./3.)),
+    SPoint3((pt[1] + 2 * pt[2]) * (1./3.)),
+    SPoint3((pt[1] + 4 * pt[2] + pt[3]) * (1./6.))
+  };
+  return discretizeBezier(tol, discrete, pos, bpt, t0, t3, insertFirstPoint);
+}
+
+static int discretizeCatmullRom(double tol, discreteList &discrete, int pos, const SPoint3 pt[4], double t0, double t3, bool insertFirstPoint)
+{
+  SPoint3 bpt[4] = {
+    pt[1],
+    SPoint3(( 6 * pt[1] + pt[2] - pt[0]) * (1./6.)),
+    SPoint3(( 6 * pt[2] - pt[3] + pt[1]) * (1./6.)),
+    pt[2]
+  };
+  return discretizeBezier(tol, discrete, pos, bpt, t0, t3, insertFirstPoint);
+}
+
+static inline SPoint3 curveGetPoint(Curve *c, int i)
+{
+  Vertex *v;
+  List_Read(c->Control_Points, i , &v);
+  return SPoint3(v->Pos.X, v->Pos.Y, v->Pos.Z);
+}
+
+static void discretizeCurve(Curve *c, double tol, std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  discreteList discrete;
+  switch(c->Typ) {
+    case MSH_SEGM_LINE :
+      {
+        int NPt = List_Nbr(c->Control_Points);
+        pts.resize(NPt);
+        ts.resize(NPt);
+        for (int i = 0; i < NPt; ++i) {
+          pts[i]= curveGetPoint(c, i);
+          ts[i] = i / (double) (NPt - 1);
+        }
+        return;
+      }
+    case MSH_SEGM_BEZIER :
+      {
+        int back = -1;
+        int NbCurves = (List_Nbr(c->Control_Points) - 1) / 3;
+        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
+          double t1 = (iCurve) / (double)(NbCurves);
+          double t2 = (iCurve+1) / (double)(NbCurves);
+          SPoint3 pt[4];
+          for(int i = 0; i < 4; i++) {
+            pt[i] = curveGetPoint(c, iCurve * 3 + i);
+          }
+          back = discretizeBezier(tol, discrete, back, pt, t1, t2, iCurve == 0);
+        }
+        break;
+      }
+    case MSH_SEGM_BSPLN:
+      {
+        int back = -1;
+        bool periodic = (c->end == c->beg);
+        int NbControlPoints = List_Nbr(c->Control_Points);
+        int NbCurves = NbControlPoints + (periodic ? -1 : 1);
+        SPoint3 pt[4];
+        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
+          double t1 = (iCurve) / (double)(NbCurves);
+          double t2 = (iCurve+1) / (double)(NbCurves);
+          for(int i = 0; i < 4; i++) {
+            int k;
+            if (periodic) {
+              k = (iCurve - 1 + i) % (NbControlPoints - 1);
+              if (k < 0)
+                k += NbControlPoints - 1;
+            }
+            else {
+              k = std::max(0, std::min(iCurve - 2 + i, NbControlPoints -1));
+            }
+            pt[i] = curveGetPoint(c, k);
+          }
+          back = discretizeBSpline(tol, discrete, back, pt, t1, t2, iCurve == 0);
+        }
+        break;
+      }
+    case MSH_SEGM_SPLN:
+      {
+        int NbCurves = List_Nbr(c->Control_Points) - 1;
+        SPoint3 pt[4];
+        int back = -1;
+        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
+          double t1 = (iCurve) / (double)(NbCurves);
+          double t2 = (iCurve+1) / (double)(NbCurves);
+          pt[1] = curveGetPoint(c, iCurve);
+          pt[2] = curveGetPoint(c, iCurve + 1);
+          if(iCurve == 0) {
+            if(c->beg == c->end)
+              pt[0] = curveGetPoint(c, NbCurves - 1);
+            else
+              pt[0] = SPoint3(pt[1] * 2 - pt[2]);
+          }
+          else
+            pt[0] = curveGetPoint(c, iCurve - 1);
+          if(iCurve == NbCurves - 1) {
+            if(c->beg == c->end)
+              pt[3] = curveGetPoint(c, 1);
+            else
+              pt[3] = SPoint3(2 * pt[2] - pt[1]);
+          }
+          else
+            pt[3] = curveGetPoint(c, iCurve + 2);
+          back = discretizeCatmullRom(tol, discrete, back, pt, t1, t2, iCurve == 0);
+        }
+        break;
+      }
+    default :
+      Msg::Fatal("not implemented");
+  }
+  discrete.sort(pts, ts);
+}
+
+void gmshEdge::discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts)
+{
+  discretizeCurve(c, tol, dpts, ts);
+}
diff --git a/Geo/gmshFace.cpp b/Geo/gmshFace.cpp
index a5f4db2..39fa658 100644
--- a/Geo/gmshFace.cpp
+++ b/Geo/gmshFace.cpp
@@ -437,5 +437,4 @@ bool gmshFace::buildSTLTriangulation(bool force)
   }
   va_geom_triangles->finalize();
   return true;
-
 }
diff --git a/Geo/gmshLevelset.cpp b/Geo/gmshLevelset.cpp
index d695bb9..96599d5 100644
--- a/Geo/gmshLevelset.cpp
+++ b/Geo/gmshLevelset.cpp
@@ -1250,7 +1250,7 @@ void gLevelsetNACA00::getClosestBndPoint(double x, double y, double z,
 {
 
   static const int maxIter = 100;
-  static const double tol = 1.e-8;
+  static const double tol = 1.e-10;
 
   const double tolr = tol/_c; // Tolerance (scaled bu chord)
   in = false;                 // Whether the point is inside the airfoil
@@ -1283,6 +1283,7 @@ void gLevelsetNACA00::getClosestBndPoint(double x, double y, double z,
       if (fabs(mIncr) < tolr) break;
       else xtb -= mIncr;
       if (xtb < tolr) xtb = tolr;
+      if (xtb > _c-tolr) xtb = _c-tolr;
     }
     xb = _x0+xtb;
     yb = (y >= _y0) ? _y0+ytb : _y0-ytb;
diff --git a/Geo/intersectCurveSurface.cpp b/Geo/intersectCurveSurface.cpp
index c125bef..0d1ba82 100644
--- a/Geo/intersectCurveSurface.cpp
+++ b/Geo/intersectCurveSurface.cpp
@@ -1,20 +1,24 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
 #include "intersectCurveSurface.h"
 #include "Numeric.h"
 
-static void _kaboom(fullVector<double> &uvt, 
-			    fullVector<double> &res, void *_data);
+static bool _kaboom(fullVector<double> &uvt,
+                    fullVector<double> &res, void *_data);
 
-struct intersectCurveSurfaceData 
+struct intersectCurveSurfaceData
 {
   const curveFunctor &c;
   const surfaceFunctor &s;
   const double epsilon;
-  intersectCurveSurfaceData (const curveFunctor & _c, 
-			     const surfaceFunctor & _s, 
-			     const double &eps) : c(_c),s(_s),epsilon(eps)
-  { }
-
-  bool apply (double newPoint[3]){
+  intersectCurveSurfaceData(const curveFunctor & _c,
+                            const surfaceFunctor & _s,
+                            const double &eps) : c(_c),s(_s),epsilon(eps){}
+  bool apply(double newPoint[3])
+  {
     try {
       fullVector<double> uvt(3);
       uvt(0) = newPoint[0];
@@ -24,8 +28,8 @@ struct intersectCurveSurfaceData
       _kaboom(uvt,res,this);
       //      printf("start with %12.5E\n",res.norm());
       if (res.norm() < epsilon)return true;
-      
-      
+
+
       if(newton_fd(_kaboom, uvt, this)){
 	//      printf("--- CONVERGED -----------\n");
 	newPoint[0] = uvt(0);
@@ -33,31 +37,31 @@ struct intersectCurveSurfaceData
 	newPoint[2] = uvt(2);
 	//	printf("newton done\n");
 	return true;
-      }    
+      }
     }
     catch (...){
-      //      printf("intersect curve surface failed !\n");
+      // printf("intersect curve surface failed !\n");
     }
-    //    printf("newton failsed\n");
+    // printf("newton failed\n");
     return false;
   }
 };
 
-void _kaboom(fullVector<double> &uvt, 
-	     fullVector<double> &res, void *_data){
+static bool _kaboom(fullVector<double> &uvt,
+                    fullVector<double> &res, void *_data)
+{
   intersectCurveSurfaceData *data = (intersectCurveSurfaceData*)_data;
-  //  printf("coucuo1 %g %g\n",uvt(0),uvt(1));
-  SPoint3 s = data->s(uvt(0),uvt(1));
-  //  printf("coucuo1\n");
+  SPoint3 s = data->s(uvt(0), uvt(1));
   SPoint3 c = data->c(uvt(2));
-  //  printf("coucuo1\n");
   res(0) = s.x() - c.x();
   res(1) = s.y() - c.y();
   res(2) = s.z() - c.z();
-  //    printf("%g %g %g vs %g %g %g \n",s.x(),s.y(),s.z(),c.x(),c.y(),c.z());
+  return true;
 }
 
-int intersectCurveSurface (curveFunctor &c, surfaceFunctor & s, double uvt[3], double epsilon){
-  intersectCurveSurfaceData data(c,s,epsilon);
+int intersectCurveSurface(curveFunctor &c, surfaceFunctor & s, double uvt[3],
+                          double epsilon)
+{
+  intersectCurveSurfaceData data(c, s, epsilon);
   return data.apply(uvt);
 }
diff --git a/Geo/intersectCurveSurface.h b/Geo/intersectCurveSurface.h
index c06c10c..2c70b5f 100644
--- a/Geo/intersectCurveSurface.h
+++ b/Geo/intersectCurveSurface.h
@@ -8,20 +8,20 @@
 
 // Intersection of a curve and a surface using newton's method
 // FD are used to compute derivatives of the parametrizations
+#include <math.h>
 #include "SPoint3.h"
 #include "SVector3.h"
 #include "GFace.h"
 #include "GEdge.h"
-#include "math.h"
 
-class surfaceFunctor 
+class surfaceFunctor
 {
 public :
   virtual ~surfaceFunctor(){}
   virtual SPoint3 operator () (double u, double v) const = 0;
 };
 
-class curveFunctor 
+class curveFunctor
 {
 public :
   virtual ~curveFunctor(){}
@@ -57,10 +57,11 @@ class curveFunctorCircle : public curveFunctor
   SVector3 middle;
   double d;
 public :
-  curveFunctorCircle(const SVector3 & _n1, const SVector3 & _n2, const SVector3 & _middle, const double & _d) : 
-  n1(_n1),n2(_n2),middle(_middle),d(_d) {
-  }
-  virtual SPoint3 operator () (double t) const {
+  curveFunctorCircle(const SVector3 & _n1, const SVector3 & _n2,
+                     const SVector3 & _middle, const double & _d) :
+    n1(_n1), n2(_n2), middle(_middle), d(_d){}
+  virtual SPoint3 operator () (double t) const
+  {
     SVector3 dir = (n1*cos(t)+n2*sin(t))*d;
     return SPoint3(middle.x() + dir.x(),
 		   middle.y() + dir.y(),
@@ -73,17 +74,21 @@ class surfaceFunctorPlane : public surfaceFunctor
   const SPoint3 p;
   const SVector3 v1,v2;
 public :
-  surfaceFunctorPlane(const SPoint3 &_p, const SVector3 &_v1, const SVector3 &_v2) : p(_p),v1(_v1),v2(_v2) {}
-  virtual SPoint3 operator () (double u, double v) const {
+  surfaceFunctorPlane(const SPoint3 &_p, const SVector3 &_v1, const SVector3 &_v2)
+    : p(_p),v1(_v1),v2(_v2) {}
+  virtual SPoint3 operator () (double u, double v) const
+  {
     return SPoint3 (p.x() + u * v1.x() + v * v2.x(),
-		   p.y() + u * v1.y() + v * v2.y(),
-		   p.z() + u * v1.z() + v * v2.z()) ;
+                    p.y() + u * v1.y() + v * v2.y(),
+                    p.z() + u * v1.z() + v * v2.z()) ;
   }
 };
+
 // intersects the curve and the surface using Newton.
 // the initial guess should be a good guess
 // returns 1 --> OK
 // returns 0 --> NOT CONVERGED
-int intersectCurveSurface (curveFunctor &c, surfaceFunctor & s, double uvt[3], double epsilon);
+int intersectCurveSurface(curveFunctor &c, surfaceFunctor & s, double uvt[3],
+                          double epsilon);
 
 #endif
diff --git a/Graphics/CMakeLists.txt b/Graphics/CMakeLists.txt
index e4f73ec..68b94a6 100644
--- a/Graphics/CMakeLists.txt
+++ b/Graphics/CMakeLists.txt
@@ -21,6 +21,7 @@ set(SRC
   gl2png.cpp
   gl2ppm.cpp
   gl2yuv.cpp
+  gl2pgf.cpp
 )
 
 file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) 
diff --git a/Graphics/drawContext.cpp b/Graphics/drawContext.cpp
index 553e252..845431a 100644
--- a/Graphics/drawContext.cpp
+++ b/Graphics/drawContext.cpp
@@ -17,6 +17,7 @@
 #include "PView.h"
 #include "PViewOptions.h"
 #include "VertexArray.h"
+#include "StringUtils.h"
 #include "gl2ps.h"
 
 #if defined(HAVE_FLTK)
@@ -29,7 +30,6 @@
 #include "gmshPopplerWrapper.h"
 #endif
 
-
 drawContextGlobal *drawContext::_global = 0;
 
 drawContext::drawContext(drawTransform *transform)
@@ -52,7 +52,7 @@ drawContext::drawContext(drawTransform *transform)
   vxmin = vymin = vxmax = vymax = 0.;
   pixel_equiv_x = pixel_equiv_y = 0.;
 
-  _bgImageSize[0] = _bgImageSize[1] = 0;
+  _bgImageTexture = _bgImageW = _bgImageH = 0;
 
   _quadric = 0; // cannot create it here: needs valid opengl context
   _displayLists = 0;
@@ -283,6 +283,7 @@ void drawContext::draw3d()
   if(!CTX::instance()->camera) initPosition();
   drawAxes();
   drawGeom();
+  drawBackgroundImage(true);
   drawMesh();
   drawPost();
 }
@@ -353,87 +354,140 @@ void drawContext::drawBackgroundGradient()
     }
     glEnd();
   }
-#if defined(HAVE_POPPLER)
-  else if(CTX::instance()->bgGradient == 4){ // PDF @ background
-    // FIXME: this should move to drawBackgroundImage below!
-    GLuint texture = gmshPopplerWrapper::getTextureForPage(800,600);
-    glEnable(GL_TEXTURE_2D);
-    glBindTexture(GL_TEXTURE_2D,texture);
-    glBegin(GL_QUADS);
-    glColor4ubv((GLubyte *) & CTX::instance()->color.bg);
+}
 
-    int dw =viewport[2] - viewport[0];
-    int dh =viewport[3] - viewport[1];
+void drawContext::invalidateBgImageTexture()
+{
+  if(_bgImageTexture) glDeleteTextures(1, &_bgImageTexture);
+  _bgImageTexture = 0;
+}
 
-    int dw_im = gmshPopplerWrapper::width();
-    int dh_im = gmshPopplerWrapper::height();
+void drawContext::drawBackgroundImage(bool threeD)
+{
+  if(CTX::instance()->bgImageFileName.empty() ||
+     (CTX::instance()->bgImage3d && !threeD) ||
+     (!CTX::instance()->bgImage3d && threeD)) return;
 
-    // conserve aspect ratio : dw / dh = dw_im / dh_im
-    //    dw = dh * dw_im / dh_im;
-    dh = dw * dh_im / dw_im;
+  std::string name = FixRelativePath(GModel::current()->getFileName(),
+                                     CTX::instance()->bgImageFileName);
+  std::string ext = SplitFileName(CTX::instance()->bgImageFileName)[2];
 
-    glTexCoord2f(1.0f,1.0f);glVertex2i(viewport[2],    viewport[3]-dh);
-    glTexCoord2f(1.0f,0.0f);glVertex2i(viewport[2],    viewport[3]);
-    glTexCoord2f(0.0f,0.0f);glVertex2i(viewport[2]-dw, viewport[3]);
-    glTexCoord2f(0.0f,1.0f);glVertex2i(viewport[2]-dw, viewport[3]-dh);
-    glEnd();
-  }
-#endif
-
-}
+  double x = CTX::instance()->bgImagePosition[0];
+  double y = CTX::instance()->bgImagePosition[1];
+  double w = CTX::instance()->bgImageSize[0];
+  double h = CTX::instance()->bgImageSize[1];
 
-void drawContext::drawBackgroundImage()
-{
-#if defined(HAVE_FLTK)
-  if(CTX::instance()->bgImageFileName.empty()) return;
-
-  if(_bgImage.empty()){
-    int idot = CTX::instance()->bgImageFileName.find_last_of('.');
-    std::string ext;
-    if(idot > 0 && idot < (int)CTX::instance()->bgImageFileName.size())
-      ext = CTX::instance()->bgImageFileName.substr(idot + 1);
-    Fl_RGB_Image *img = 0;
-    if(ext == "jpg" || ext == "JPG" || ext == "jpeg" || ext == "JPEG")
-      img = new Fl_JPEG_Image(CTX::instance()->bgImageFileName.c_str());
-    else if(ext == "png" || ext == "PNG")
-      img = new Fl_PNG_Image(CTX::instance()->bgImageFileName.c_str());
-    if(img && img->d() >= 3){
-      const unsigned char *data = img->array;
-      for(int j = img->h() - 1; j >= 0; j--) {
-        for(int i = 0; i < img->w(); i++) {
-          int idx = j * img->w() * img->d() + i * img->d();
-          _bgImage.push_back((GLfloat)data[idx] / 255.F);
-          _bgImage.push_back((GLfloat)data[idx + 1] / 255.F);
-          _bgImage.push_back((GLfloat)data[idx + 2] / 255.F);
-        }
+  if(ext == ".pdf" || ext == ".PDF"){
+#if defined(HAVE_POPPLER)
+    if(!_bgImageTexture){
+      if(!gmshPopplerWrapper::instance()->loadFromFile(name)){
+        Msg::Error("Could not load PDF file '%s'", name.c_str());
+        CTX::instance()->bgImageFileName.clear();
+        return;
       }
-      _bgImageSize[0] = img->w();
-      _bgImageSize[1] = img->h();
     }
-    if(!_bgImageSize[0] || !_bgImageSize[1]){
-      Msg::Error("Could not load valid background image");
-      // make sure we don't try to load it again
-      for(int i = 0; i < 3; i++) _bgImage.push_back(0);
-      _bgImageSize[0] = _bgImageSize[1] = 1;
+    gmshPopplerWrapper::instance()->setCurrentPage(CTX::instance()->bgImagePage);
+    _bgImageTexture = gmshPopplerWrapper::instance()->getTextureForPage(300, 300);
+    _bgImageW = gmshPopplerWrapper::instance()->width();
+    _bgImageH = gmshPopplerWrapper::instance()->height();
+#else
+    Msg::Error("Gmsh must be compiled with Poppler support to load PDFs");
+    CTX::instance()->bgImageFileName.clear();
+    return;
+#endif
+  }
+  else{
+#if defined(HAVE_FLTK)
+    if(!_bgImageTexture){
+      Fl_RGB_Image *img = 0;
+      if(ext == ".jpg" || ext == ".JPG" || ext == ".jpeg" || ext == ".JPEG")
+        img = new Fl_JPEG_Image(name.c_str());
+      else if(ext == ".png" || ext == ".PNG")
+        img = new Fl_PNG_Image(name.c_str());
+      if(!img){
+        Msg::Error("Could not load background image '%s'", name.c_str());
+        CTX::instance()->bgImageFileName.clear();
+        return;
+      }
+      Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(2048, 2048);
+      glGenTextures(1, &_bgImageTexture);
+      glBindTexture(GL_TEXTURE_2D, _bgImageTexture);
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img2->w(), img2->h(), 0,
+                   (img2->d() == 4) ? GL_RGBA : GL_RGB,
+                   GL_UNSIGNED_BYTE, img2->array);
+      _bgImageW = img->w();
+      _bgImageH = img->h();
+      delete img;
+      delete img2;
     }
-    if(img) delete img;
+#else
+    Msg::Error("Gmsh must be compiled with FLTK support to load JPEGs or PNGs");
+    CTX::instance()->bgImageFileName.clear();
+    return;
+#endif
   }
 
-  double x = CTX::instance()->bgImagePosition[0];
-  double y = CTX::instance()->bgImagePosition[1];
-  int c = fix2dCoordinates(&x, &y);
-  if(c & 1) x -= _bgImageSize[0] / 2.;
-  if(c & 2) y -= _bgImageSize[1] / 2.;
-  if(x < viewport[0]) x = viewport[0];
-  if(y < viewport[1]) y = viewport[1];
-  glRasterPos2d(x, y);
-  glPixelStorei(GL_PACK_ALIGNMENT, 1);
-  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-  glDrawPixels(_bgImageSize[0], _bgImageSize[1], GL_RGB, GL_FLOAT,
-               (void*)&_bgImage[0]);
-  gl2psDrawPixels(_bgImageSize[0], _bgImageSize[1], 0, 0, GL_RGB, GL_FLOAT,
-                  (void*)&_bgImage[0]);
-#endif
+  if(!_bgImageTexture) return;
+
+  if(w < 0 && h < 0){
+    w = viewport[2] - viewport[0];
+    h = viewport[3] - viewport[1];
+  }
+  else if(w < 0 && h == 0){
+    w = viewport[2] - viewport[0];
+    h = w * _bgImageH / _bgImageW;
+  }
+  else if(w < 0){
+    w = viewport[2] - viewport[0];
+  }
+  else if(w == 0 && h < 0){
+    h = viewport[3] - viewport[1];
+    w = h * _bgImageW / _bgImageH;
+  }
+  else if(h < 0){
+    h = viewport[3] - viewport[1];
+  }
+  else if(w == 0 && h == 0){
+    w = _bgImageW;
+    h = _bgImageH;
+  }
+  else if(h == 0){
+    h = w * _bgImageH / _bgImageW;
+  }
+  else if(w == 0){
+    w = h * _bgImageW / _bgImageH;
+  }
+
+  Msg::Debug("Background image: x=%g y=%g w=%g h=%g", x, y, w, h);
+
+  glEnable(GL_BLEND);
+  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  glEnable(GL_TEXTURE_2D);
+  glBindTexture(GL_TEXTURE_2D, _bgImageTexture);
+  glBegin(GL_QUADS);
+  glColor4ubv((GLubyte *) & CTX::instance()->color.bg);
+  if(threeD){
+    glTexCoord2f(1.0f, 1.0f); glVertex2d(x+w, y);
+    glTexCoord2f(1.0f, 0.0f); glVertex2d(x+w, y+h);
+    glTexCoord2f(0.0f, 0.0f); glVertex2d(x, y+h);
+    glTexCoord2f(0.0f, 1.0f); glVertex2d(x, y);
+  }
+  else{
+    int c = fix2dCoordinates(&x, &y); // y=0 now means top
+    if(c & 1) x -= w / 2.;
+    if(c & 2) y += h / 2.;
+    if(x < viewport[0]) x = viewport[0];
+    if(y < viewport[1]) y = viewport[1];
+    glTexCoord2f(1.0f, 1.0f); glVertex2d(x+w, y-h);
+    glTexCoord2f(1.0f, 0.0f); glVertex2d(x+w, y);
+    glTexCoord2f(0.0f, 0.0f); glVertex2d(x, y);
+    glTexCoord2f(0.0f, 1.0f); glVertex2d(x, y-h);
+  }
+  glEnd();
+  glDisable(GL_TEXTURE_2D);
+  glDisable(GL_BLEND);
 }
 
 void drawContext::initProjection(int xpick, int ypick, int wpick, int hpick)
@@ -541,7 +595,7 @@ void drawContext::initProjection(int xpick, int ypick, int wpick, int hpick)
       // hack for GL2PS (to make sure that the image is in front of the
       // gradient)
       glTranslated(0., 0., 0.01 * clip_far);
-      drawBackgroundImage();
+      drawBackgroundImage(false);
       glPopMatrix();
       glEnable(GL_DEPTH_TEST);
     }
diff --git a/Graphics/drawContext.h b/Graphics/drawContext.h
index 5fd6442..2f1285f 100644
--- a/Graphics/drawContext.h
+++ b/Graphics/drawContext.h
@@ -110,8 +110,7 @@ class drawContext {
   GLuint _displayLists;
   std::set<GModel*> _hiddenModels;
   std::set<PView*> _hiddenViews;
-  std::vector<GLfloat> _bgImage;
-  int _bgImageSize[2];
+  GLuint _bgImageTexture, _bgImageW, _bgImageH;
  public:
   Camera camera;
   double r[3]; // current Euler angles (in degrees!)
@@ -178,6 +177,7 @@ class drawContext {
   bool isVisible(PView *v){ return (_hiddenViews.find(v) == _hiddenViews.end()); }
   void createQuadricsAndDisplayLists();
   void invalidateQuadricsAndDisplayLists();
+  void invalidateBgImageTexture();
   void buildRotationMatrix();
   void setQuaternion(double p1x, double p1y, double p2x, double p2y);
   void addQuaternion(double p1x, double p1y, double p2x, double p2y);
@@ -201,7 +201,7 @@ class drawContext {
   void drawMesh();
   void drawPost();
   void drawBackgroundGradient();
-  void drawBackgroundImage();
+  void drawBackgroundImage(bool moving);
   void drawText2d();
   void drawGraph2d();
   void drawAxis(double xmin, double ymin, double zmin,
diff --git a/Graphics/gl2pgf.cpp b/Graphics/gl2pgf.cpp
new file mode 100644
index 0000000..e352ea5
--- /dev/null
+++ b/Graphics/gl2pgf.cpp
@@ -0,0 +1,715 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+//
+// Contributed by Sebastian Eiser
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "GmshConfig.h"
+#include "PixelBuffer.h"
+#include "OS.h"
+#include "Context.h"
+#include "PView.h"
+#include "PViewData.h"
+#include "Numeric.h"
+#include "Options.h"
+#include "StringUtils.h"
+#include "gl2png.h"
+
+static int assembleColmapStr(const int num, const int intType, int &samples,
+                             std::string &ret)
+{
+  GmshColorTable * ct = GetColorTable(num); // i
+  ret.assign("\\pgfplotsset{\ncolormap={gmshcolormap}{%% note: "
+             "Only needed once if colorbars do not change\n");
+
+  samples = (int) opt_view_nb_iso(num, GMSH_GET, 0);
+  double step = 0.;
+  switch (intType){
+    case 2: samples=64; break; // continuous is approximated by 64 samples
+    case 3: break; // filled (sampled colorbar)
+    case 1: break; // iso lines
+    case 4:  // numericals
+    default:
+      return 1;
+  }
+  step = (double) (1.*ct->size)/(samples-1.);
+  int r, g, b, a;
+  unsigned int idx;
+  char tmp[265];
+  for (unsigned int j=0; j < (unsigned int) samples-1; j++ /*j+=4*/) {
+    idx = (unsigned int)j*step;
+    //printf("j=%d, idx=%d step=%f\n", j, idx, step);
+    r = CTX::instance()->unpackRed(ct->table[idx]);
+    g = CTX::instance()->unpackGreen(ct->table[idx]);
+    b = CTX::instance()->unpackBlue(ct->table[idx]);
+    a = CTX::instance()->unpackAlpha(ct->table[idx]);
+    if (a != 255)
+      Msg::Warning("PGF export does not handle transparent colormaps");
+
+    sprintf(tmp, "rgb255=(%d,%d,%d) ",r,g,b);
+    ret.append(tmp);
+
+    if (intType != 2) // sampled
+      // reinsert, because then the end color is interpreted correctly
+      // for shader=flat mean
+      ret.append(tmp);
+  }
+  //endpoint
+  r = CTX::instance()->unpackRed(ct->table[ct->size-1]);
+  g = CTX::instance()->unpackGreen(ct->table[ct->size-1]);
+  b = CTX::instance()->unpackBlue(ct->table[ct->size-1]);
+  sprintf(tmp, "rgb255=(%d,%d,%d) ",r,g,b);
+  ret.append(tmp);
+  if (intType != 2) // sampled
+    // reinsert, because then the end color is interpreted correctly
+    // for shader=flat mean
+    ret.append(tmp);
+
+  ret.append("}\n}%%\n");
+
+  return 0;
+}
+
+static int assembleColbarStr(const int num, const int intType, const int samples,
+                             std::string &ret)
+{
+  double cbmin, cbmax;
+  cbmin = opt_view_min(num, GMSH_GET, 0);
+  cbmax = opt_view_max(num, GMSH_GET, 0);
+  int rangeType = (int) opt_view_range_type(num, GMSH_GET,0);
+  char tmp[265];
+  switch (rangeType) {
+    case 2:
+      {
+        cbmin = opt_view_custom_min(num, GMSH_GET, 0);
+        cbmax = opt_view_custom_max(num, GMSH_GET, 0);
+        break;
+      }
+    case 1: // default
+    case 3: // per time step FIXME
+    default: break;
+  }
+  ret.assign("\tcolorbar style={\n\t\t%%width=0.5cm, "
+             "%% adjust width of colorbar\n"
+             "\t\t%%height=6cm,%% adjust height of colorbar,\n");
+  if (intType != 2) { // sampled
+    sprintf(tmp, "\t\tsamples=%d,\n", samples+1);
+    ret.append(tmp);
+  }
+
+  int scaleType = (int) opt_view_scale_type(num, GMSH_GET, 0);
+  int horizontal = (int) opt_print_pgf_horiz_bar(0, GMSH_GET, 0);
+  //1 linear
+  //2 log
+  //3 double log ???
+  if (scaleType == 2) { // log
+    // see http://tex.stackexchange.com/questions/23750/log-color-bar-meta-data-in-pgfplot
+    if (horizontal)
+      sprintf(tmp, "\t\txticklabel={$10^{\\pgfmathparse{\\tick}"
+              "\\pgfmathprintnumber\\pgfmathresult}$},\n");
+    else
+      sprintf(tmp, "\t\tyticklabel={$10^{\\pgfmathparse{\\tick}"
+              "\\pgfmathprintnumber\\pgfmathresult}$},\n");
+    ret.append(tmp);
+  }
+
+  ret.append("\t}]\n\t  %% a dummy plot for the colorbar (invisible):\n");
+  if (scaleType == 2) {// log
+    cbmin = log10 (cbmin);
+    cbmax = log10 (cbmax);
+  }
+  sprintf(tmp, "\t  \\addplot[point meta min=%f,"
+          "point meta max=%f, update limits=false, draw=none, colorbar source]\n\t"
+          "coordinates{(1,1)};\n", cbmin, cbmax);
+  ret.append(tmp);
+  return 0;
+}
+
+static int assemblePostAxis(const int num, const int intType, std::string &ret)
+{
+  int horizontal = (int) opt_print_pgf_horiz_bar(0, GMSH_GET, 0);
+  std::string post_var;
+  char tmp[265];
+  post_var = PView::list[num]->getData()->getName();
+
+  if (!post_var.empty()) {
+    sprintf(tmp,"\ttitle={%s},\n", post_var.c_str() );
+    ret.assign(tmp);
+  }
+  ret.append("\tcolorbar,\n\tcolormap name=gmshcolormap,\n");
+  if (horizontal) {
+    ret.append("\tcolorbar horizontal,\n");
+  }
+  else {
+    ret.append("\tcolorbar right, %% or left...\n");
+  }
+  if (intType == 3){  // sampled
+    ret.append("\tcolorbar sampled,\n");
+  }
+  else if (intType == 1){
+    ret.append("\tcolorbar sampled line,\n");
+  }
+  return 0;
+}
+
+static int getMinMaxOfAxis(const int num, double result[8][3])
+{
+  double xmin, xmax, ymin, ymax, zmin, zmax;
+  // axes ranges
+  if (!(int) opt_general_axes_auto_position(0, GMSH_GET,0)) {
+    // needs to get manual axes set
+    xmin = opt_general_axes_xmin(0, GMSH_GET, 0);
+    xmax = opt_general_axes_xmax(0, GMSH_GET, 0);
+    ymin = opt_general_axes_ymin(0, GMSH_GET, 0);
+    ymax = opt_general_axes_ymax(0, GMSH_GET, 0);
+    zmin = opt_general_axes_zmin(0, GMSH_GET, 0);
+    zmax = opt_general_axes_zmax(0, GMSH_GET, 0);
+    fprintf(stderr,"General axes non auto, using\n");
+    fprintf(stderr,"x=(%f,%f), y=(%f,%f), z=(%f,%f)\n",
+            xmin, xmax, ymin, ymax, zmin, zmax);
+  }
+  else if (num >= 0 && !(int) opt_view_axes_auto_position(num, GMSH_GET,0) ) {
+    // needs to get manual axes set
+    xmin = opt_view_axes_xmin(num, GMSH_GET, 0);
+    xmax = opt_view_axes_xmax(num, GMSH_GET, 0);
+    ymin = opt_view_axes_ymin(num, GMSH_GET, 0);
+    ymax = opt_view_axes_ymax(num, GMSH_GET, 0);
+    zmin = opt_view_axes_zmin(num, GMSH_GET, 0);
+    zmax = opt_view_axes_zmax(num, GMSH_GET, 0);
+    fprintf(stderr,"View axes non auto, using:\n");
+    fprintf(stderr,"x=(%f,%f), y=(%f,%f), z=(%f,%f)\n",
+            xmin, xmax, ymin, ymax, zmin, zmax);
+  }
+  else {// default
+    xmin = CTX::instance()->min[0];
+    xmax = CTX::instance()->max[0];
+    ymin = CTX::instance()->min[1];
+    ymax = CTX::instance()->max[1];
+    zmin = CTX::instance()->min[2];
+    zmax = CTX::instance()->max[2];
+    fprintf(stderr,"Axes auto, using:\n");
+    fprintf(stderr,"x=(%f,%f), y=(%f,%f), z=(%f,%f)\n",
+            xmin, xmax, ymin, ymax, zmin, zmax);
+  }
+  result[0][0] = result[1][0] = result[2][0] = result[3][0] = xmin;
+  result[4][0] = result[5][0] = result[6][0] = result[7][0] = xmax;
+
+  result[0][1] = result[1][1] = result[4][1] = result[5][1] = ymin;
+  result[2][1] = result[3][1] = result[6][1] = result[7][1] = ymax;
+
+  result[0][2] = result[2][2] = result[4][2] = result[6][2] = zmin;
+  result[1][2] = result[3][2] = result[5][2] = result[7][2] = zmax;
+  // result = {
+  //     { xmin, ymin, zmin}, // origin
+  //     { xmin, ymin, zmax}, // y end
+  //     { xmin, ymax, zmin}, // y end z end
+  //     { xmin, ymax, zmax}, // y end z end
+  //     { xmax, ymin, zmin}, // x end
+  //     { xmax, ymin, zmax}, // x end y end
+  //     { xmax, ymax, zmin}, // x end y end z end
+  //     { xmax, ymax, zmax} // x end  z end
+  // };
+  return 0;
+}
+
+static int assemble2d(const int num, const int exportAxis, std::string &axisstr,
+                      std::string &plotstr, double *eulerAngles)
+{
+  double axPts[8][3];
+  double factor=1.;
+  double xmin, xmax, ymin, ymax;
+
+  axisstr.append("\taxis equal image, %% use png aspect ratio\n");
+
+  if (exportAxis) {
+    getMinMaxOfAxis(num, axPts);
+    std::string xlab, ylab, zlab;
+    xlab = CTX::instance()->axesLabel[0];
+    ylab = CTX::instance()->axesLabel[1];
+    zlab = CTX::instance()->axesLabel[2];
+    if (xlab.empty())
+      xlab = "x";
+    if (ylab.empty())
+      ylab = "y";
+    if (zlab.empty())
+      zlab = "z";
+
+    fprintf(stderr,"Euler two dim: 0:%f, 1:%f, 2:%f\n",
+           eulerAngles[0], eulerAngles[1], eulerAngles[2]);
+    int r0 = (int) (eulerAngles[0]+0.5);
+    int r1 = (int) (eulerAngles[1]+0.5);
+    int r2 = (int) (eulerAngles[2]+0.5);
+    if (r0 % 90 != 0 || r1 % 90 != 0 || r2 % 90 !=0) {
+      fprintf(stderr,"Euler two dim: 0:%d, 1:%d, 2:%d\n", r0, r1, r2);
+      Msg::Error("Please select a plane view (X, Y, Z)");
+      return 1;
+    }
+    if (r0 % 180 == 0 && r1 % 360 == 0 && r2 % 180 == 0) {
+      // xy
+      xmin=axPts[0][0]; xmax=axPts[4][0]; ymin=axPts[0][1]; ymax=axPts[2][1];
+      if (r2 == 180)
+        axisstr.append("\tx dir=reverse,\n");
+      if ((r2 == 180 && abs(r0) < 1) || (r0 == 180 && abs(r2) < 1))
+        axisstr.append("\ty dir=reverse,\n");
+      axisstr.append("\txlabel={" + xlab + "},\n");
+      axisstr.append("\tylabel={" + ylab + "},\n");
+    }
+    else if (r0 % 180 == 0 && r1 % 360 ==0 && (r2 == 90 || r2 == 270)) {
+      // yx
+      xmin=axPts[0][1]; xmax=axPts[2][1]; ymin=axPts[0][0]; ymax=axPts[4][0];
+      if (r2 == 90)
+        axisstr.append("\tx dir=reverse,\n");
+      if (r2 == 270 || (r2 == 90 && r0 == 180))
+        axisstr.append("\ty dir=reverse,\n");
+      axisstr.append("\txlabel={" + ylab + "},\n");
+      axisstr.append("\tylabel={" + xlab + "},\n");
+    }
+    else if ((r0 == 90 || r0 == 270) && r1 % 360 == 0 &&
+             (r2 == 90 || r2 == 270)) {
+      xmin=axPts[0][1]; xmax=axPts[2][1]; ymin=axPts[0][2]; ymax=axPts[1][2];
+      if(r2 == 90)
+        axisstr.append("\tx dir=reverse,\n");
+      if(r0 == 90)
+        axisstr.append("\ty dir=reverse,\n");
+      // yz
+      axisstr.append("\txlabel={" + ylab + "},\n");
+      axisstr.append("\tylabel={" + zlab + "},\n");
+    }
+    else if (r0 % 360 == 0 && (r1 == 90 || r1 == 270) && r2 % 180 == 0) {
+      // zy
+      xmin=axPts[0][2]; xmax=axPts[1][2]; ymin=axPts[0][1]; ymax=axPts[2][1];
+      if (r1 == 270)
+        axisstr.append("\tx dir=reverse,\n");
+      if (r2 == 180)
+        axisstr.append("\ty dir=reverse,\n");
+      axisstr.append("\txlabel={" + zlab + "},\n");
+      axisstr.append("\tylabel={" + ylab + "},\n");
+    }
+    else if ((r0 == 90 || r0 == 270) && r1 % 360 == 0 && r2 % 180 == 0) {
+      // xz
+      xmin=axPts[0][0]; xmax=axPts[4][0]; ymin=axPts[0][2]; ymax=axPts[1][2];
+      if (r2 == 180) // x dir=reverse
+        axisstr.append("\tx dir=reverse,\n");
+      if (r0 == 90)
+        axisstr.append("\ty dir=reverse,\n");
+      axisstr.append("\txlabel={" + xlab + "},\n");
+      axisstr.append("\tylabel={" + zlab + "},\n");
+    }
+    else if (r0 % 360 == 0 && (r1 == 90 || r1 == 270) &&
+             (r2 == 90 || r2 == 270)) {
+      if (r1 == 270)
+        axisstr.append("\tx dir=reverse,\n");
+      if (r2 == 270)
+        axisstr.append("\ty dir=reverse,\n");
+      // zx
+      xmin=axPts[0][2]; xmax=axPts[1][2]; ymin=axPts[0][0]; ymax=axPts[4][0];
+      axisstr.append("\txlabel={" + zlab + "},\n");
+      axisstr.append("\tylabel={" + xlab + "},\n");
+    }
+    else {
+      Msg::Error("Cannot infer orientation from Euler angles...");
+      // this should not happen
+      //error=true;
+      return 2;
+    }
+    if (fabs(xmax - xmin) < 1e-8 ||
+        fabs(ymax - ymin) < 1e-8) {
+      Msg::Error("I inferred x (%f) or y (%f) dimension to be zero. Cannot produce.",
+                 fabs(xmax - xmin), fabs(ymax - ymin));
+      return 3;
+    }
+
+    double diagonal[3] = {xmax-xmin, ymax-ymin, 0};
+    double minlen = norm3(diagonal);
+    std::string suffix;
+    if(minlen < 1e-5) {
+      factor=1e6;
+      suffix.assign(" / $\\mu$m");
+    }
+    else if(minlen < 0.01) {
+      factor=1e3;
+      suffix.assign(" / mm");
+    }
+    else if(minlen > 1e6) {
+      factor=1e-6;
+      suffix.assign(" / Mm");
+    }
+    else if(minlen > 1000) {
+      factor=1e-3;
+      suffix.assign(" / Km");
+    }
+    if (factor != 1) {
+      char tmp[265];
+      sprintf(tmp, "The pgf output has been rescaled in order to please "
+              "the TeX number precision/range. Rescaling your results by "
+              "a factor %g", factor);
+      Msg::Warning(tmp);
+      // sprintf(tmp, "$\\times 10^{%d}$},",(int)(log10(factor)+0.5));
+      // std::string repl = tmp;
+      // replace two labels
+      std::size_t foundy = axisstr.rfind("},");
+      if (foundy!=std::string::npos)
+        axisstr.insert(foundy,suffix);
+      else
+        return 4;
+
+      std::size_t foundx = axisstr.rfind("},", foundy);
+      if (foundx!=std::string::npos)
+        axisstr.insert(foundx,suffix);
+      else
+        return 4;
+    }
+    // axis options
+    axisstr.append("\tenlargelimits=false, %% tight axis, use xmin=<val>, ");
+    axisstr.append("xmax=<val> for custom bounding box\n");
+    axisstr.append("\taxis on top,\n\tscale only axis,\n");
+  }
+  else {
+    // no axis
+    xmin=0, xmax=1, ymin=0, ymax=1;
+    axisstr.append("\thide axis,\n");
+  }
+  char tmp[265];
+  sprintf(tmp,"\t  \\addplot graphics[xmin=%f, xmax=%f, ymin=%f, ymax=%f]\n",
+          xmin*factor, xmax*factor, ymin*factor, ymax*factor);
+
+  plotstr.assign(tmp);
+
+  return 0;
+}
+
+static int assemble3d(const int num, const int exportAxis, std::string &axisstr,
+                      std::string &plotstr, double *eulerAngles, int *viewport,
+                      double *proj, double *model, int ypix, int xpix)
+{
+  if (exportAxis) {
+    axisstr.append("\tenlargelimits=false, %% tight axis, use xmin=<val>, ");
+    axisstr.append("xmax=<val> for custom bounding box\n");
+    axisstr.append("\tgrid=both,\n\tminor tick num=1,\n");
+    std::string xlab, ylab, zlab;
+    xlab = CTX::instance()->axesLabel[0];
+    ylab = CTX::instance()->axesLabel[1];
+    zlab = CTX::instance()->axesLabel[2];
+    if (xlab.empty())
+      xlab = "x";
+    if (ylab.empty())
+      ylab = "y";
+    if (zlab.empty())
+      zlab = "z";
+    axisstr.append("\txlabel={" + xlab + "}, %%\n\tylabel={" +
+            ylab + "},\n\tzlabel={" + zlab + "},\n");
+
+    axisstr.append("\tzlabel style={rotate=-90},\n"); // bug?
+  }
+  else {
+    if(opt_general_orthographic(0, GMSH_GET, 0) == 0 ) {
+      Msg::Warning("Axes are not orthogonal, but because you do not want "
+                   "any axes, I'll continue with a 2d picture.");
+      return assemble2d(num, 0, axisstr, plotstr, eulerAngles);
+    }
+    if (CTX::instance()->camera) {
+      Msg::Warning("Camera output not supported, but since you do not want "
+                   "any axes, I'll continue with a 2d picture.");
+      return assemble2d(num, 0, axisstr, plotstr, eulerAngles);
+    }
+    axisstr.append("\thide axis,\n");
+  }
+
+  if(opt_general_orthographic(0, GMSH_GET, 0) == 0 && exportAxis) {
+    Msg::Warning("Cannot produce output if axes are not orthogonal.");
+    Msg::Error("Please switch to orthographic projection mode "
+               "('Alt + o') and retry if you want to output axes.");
+    return 1;
+  }
+
+  double axPts[8][3];
+  getMinMaxOfAxis(num, axPts);
+  double factor=1.;
+  // requires the pixel coordinates of the axis ends (actually any four
+  // points with all different x/y/z <pixX, pixY> would suffice)
+  double axViewPt[8][3];
+  std::vector<int> acceptableAnchors;
+  std::vector<int> masked;
+
+  bool  reorder = false;
+  double minlen = 0.;
+  std::string suffix;
+  for (unsigned int j=0; j < 8; j++) {
+    // project the 8 axis end points to pixel coordinates,
+    // accept if they are in the screen range.
+
+    gluProject(axPts[j][0], axPts[j][1], axPts[j][2], model, proj,
+            viewport, &axViewPt[j][0], &axViewPt[j][1], &axViewPt[j][2]);
+    // printf("x=%f, y=%f, z=%f\n", axPts[j][0], axPts[j][1], axPts[j][2]);
+    // printf("xprn=%f, yprn=%f, zprn=%f\n",
+    //        axViewPt[j][0], axViewPt[j][1], axViewPt[j][2]);
+    if ((int)(axViewPt[j][0]+0.5) <= xpix &&
+            (int)(axViewPt[j][1]+0.5) <= ypix)  {
+      acceptableAnchors.push_back(j);
+    }
+    else
+      masked.push_back(j);
+    if (j>0) {
+      // respecting TeXs range limts (1e-4 relative precision)
+      minlen = norm3(axPts[j]);
+      //fprintf(stderr,"j=%d, vec length %f:\n", j, minlen);
+      if(minlen < 1e-5) {
+        factor=1e6;
+        suffix.assign("/$\\mu$m");
+      }
+      else if(minlen < 0.01) {
+        factor=1e3;
+        suffix.assign("/mm");
+      }
+      else if(minlen > 1e6) {
+        factor=1e-6;
+        suffix.assign("/Mm");
+      }
+      else if(minlen > 1000) {
+        factor=1e-3;
+        suffix.assign("/Km");
+      }
+    }
+    if (j == 1 && acceptableAnchors.size() == 2) {
+      // precaution: if the first two coordinates are accepted, a
+      // division by zero can occur in pgfplots
+      // furthermore, four points with equal x=xmin leads to
+      // singular system in pgfplots
+      reorder=true;
+      acceptableAnchors.pop_back();
+    }
+  }
+  if (reorder) acceptableAnchors.push_back(1);
+
+  if (acceptableAnchors.size() < 4) {
+    Msg::Error("Unable to calculate anchors for pgf output. "
+               "Make sure the entire scene is visible or adjust "
+               "the axes min/max values to fit inside your screen.");
+    return 2;
+  }
+  if (factor != 1) {
+    char tmp[265];
+    sprintf(tmp, "The pgf output has been rescaled in order to please "
+            "the TeX number precision/range. Rescaling your results by "
+            "a factor %g", factor);
+    Msg::Warning(tmp);
+    // replace three labels
+    if (exportAxis) {
+      // xlabel={x<>}, %%
+      // ylabel={y<>},
+      // zlabel={z<>},
+      // zlabel style={rotate=-90},
+      std::size_t foundrot = axisstr.rfind("},");
+      std::size_t foundz = axisstr.rfind("},", foundrot-1);
+      if (foundz!=std::string::npos)
+        axisstr.insert(foundz,suffix);
+      else
+        return 4;
+      std::size_t foundy = axisstr.rfind("},",foundz);
+      if (foundy!=std::string::npos)
+        axisstr.insert(foundy,suffix);
+      else
+        return 4;
+
+      std::size_t foundx = axisstr.rfind("},", foundy);
+      if (foundx!=std::string::npos)
+        axisstr.insert(foundx,suffix);
+      else
+        return 4;
+    }
+  }
+
+  char tmp[265];
+  plotstr.assign("\t  \\addplot3[surf] graphics[debug=false,%%=visual,\n");
+  plotstr.append("\t    points={%%\n");
+
+  unsigned int j=0;
+  for (std::vector<int>::iterator it = acceptableAnchors.begin();
+       it != acceptableAnchors.end(); ++it, j++) {
+    sprintf(tmp,"\t    (%f,%f,%f)", factor*axPts[*it][0],
+            factor*axPts[*it][1], factor*axPts[*it][2]);
+    plotstr.append(tmp);
+    if (j > 3) {
+      plotstr.append("%%");
+    }
+    // ypix-y syntax for easier debugging w/ e.g. gimp pixel
+    sprintf(tmp," => (%d, %d-%d)\n", (int)(axViewPt[*it][0]+0.5),
+            ypix,ypix-(int)(axViewPt[*it][1]+0.5));
+    plotstr.append(tmp);
+  }
+  for (std::vector<int>::iterator it = masked.begin();
+       it != masked.end(); ++it) {
+    sprintf(tmp,"\t    (%f,%f,%f)", factor*axPts[*it][0],
+            factor*axPts[*it][1], factor*axPts[*it][2]);
+    plotstr.append(tmp);
+    plotstr.append(" %% out of pixel range, discarded\n");
+  }
+  plotstr.append("\t    }]\n");
+  return 0;
+}
+
+int print_pgf(const std::string &name, const int num, const int cnt, 
+              PixelBuffer *buffer, double *eulerAngles,
+              int *viewport, double *proj, double *model)
+{
+  int ypix = buffer->getHeight();
+  int xpix = buffer->getWidth();
+
+  std::string base = SplitFileName(name)[1];
+  std::string path = SplitFileName(name)[0];
+  std::string pngfilen = path + base + ".png";
+  std::string pgffilen = path + base + ".pgf";
+  std::string texfilen = path + base + ".tex";
+  FILE *fp = Fopen(pngfilen.c_str(), "wb");
+  if(!fp){
+    Msg::Error("Unable to open file '%s'", pngfilen.c_str());
+    return 1;
+  }
+  create_png(fp, buffer, 100);
+  fclose(fp);
+
+  // write pgf
+  int twoDim = (int)opt_print_pgf_two_dim(0, GMSH_GET, 0);
+  int exportAxis = (int)opt_print_pgf_export_axis(0, GMSH_GET, 0);
+  if (cnt > 1)
+    Msg::Warning("PGF colorbar output works only with a single visible "
+                 "scale. Consider disabling all but one. I can only create a "
+                 "single colorbar. Colorbar will be suppressed");
+
+  int samples;
+  std::string colmap_s, colbar_s, post_axis_s;
+  // color map
+  if (cnt == 1) { // one post processing view scale visible
+    int intType = (int) opt_view_intervals_type(num, GMSH_GET, 0);
+    if(assembleColmapStr(num, intType, samples, colmap_s) != 0) {
+      Msg::Error("Unable to assemble colormap for PGF output");
+      return 1;
+    }
+    if(assemblePostAxis(num, intType, post_axis_s) != 0) {
+      Msg::Error("Unable to assemble post processing axis for PGF output");
+      return 1;
+    }
+    if(assembleColbarStr(num, intType, samples, colbar_s) != 0) {
+      Msg::Error("Unable to assemble colorbar for PGF output");
+      return 1;
+    }
+  }
+  else {
+    colbar_s.assign("\t]\n"); // close axis without colorbar and dummy plot
+  }
+
+  std::string axis_s, plot_s;
+  axis_s.assign("\\begin{tikzpicture}\n\\begin{axis}[\n\twidth=.5\\linewidth,"
+                "%% set figure width here\n");
+  if (twoDim) {
+    if (assemble2d(num, exportAxis, axis_s, plot_s, eulerAngles) != 0) {
+      return 1;
+    }
+  }
+  else { // 3d
+    if (assemble3d(num, exportAxis, axis_s, plot_s, eulerAngles,
+                   viewport, proj, model, ypix, xpix) != 0) {
+      return 1;
+    }
+  }
+  char tmp[265];
+  sprintf(tmp,"\t    {%s.png};\n", base.c_str());
+  plot_s.append(tmp);
+
+  fp = Fopen(pgffilen.c_str(), "wb");
+  if(!fp){
+    Msg::Error("Unable to open file '%s'", pgffilen.c_str());
+    return 1;
+  }
+  fprintf(fp, "%s", colmap_s.c_str());
+  fprintf(fp, "%s", axis_s.c_str());
+  fprintf(fp, "%s", post_axis_s.c_str());
+  fprintf(fp, "%s", colbar_s.c_str());
+  fprintf(fp, "%s", plot_s.c_str());
+  fprintf(fp, "\\end{axis}\n\\end{tikzpicture}%%\n");
+  fclose(fp);
+
+  if (twoDim)  {
+    // try to trim the png...
+    char tmp[2048];
+    if (system(NULL)) {
+      std::string pngname = name;
+      pngname.replace(pngname.end()-3, pngname.end(), "png");
+      sprintf(tmp, "convert -trim %s %s", pngname.c_str(), pngname.c_str());
+      Msg::Info("Running:");
+      Msg::Info(tmp);
+      int ret = system(tmp);
+      Msg::Info("Conversion returned value %d", ret);
+      if (ret == 0) // success
+        Msg::Info("Automatic trim successful.");
+      else {
+        Msg::Warning("Cannot automatically trim output png.");
+        sprintf(tmp, "One should now manually crop the margins, using e.g."
+                "gimp or `convert -trim %s %s` to get rid of any remaining"
+                "margins.", pngfilen.c_str(), pngfilen.c_str());
+        Msg::Warning(tmp);
+      }
+    }
+    else {
+      Msg::Warning("Cannot automatically trim output png.");
+      sprintf(tmp, "One should now manually crop the margins, using e.g."
+              "gimp or `convert -trim %s %s` to get rid of any remaining"
+              "margins.", pngfilen.c_str(), pngfilen.c_str());
+      Msg::Warning(tmp);
+    }
+  }
+
+  // try to add transparency, do not(!) crop otherwise the transformation
+  // matrix is wrong!!!!
+  if (!twoDim)  {
+    char tmp[2048];
+    if (system(NULL)) {
+      std::string pngname = name;
+      pngname.replace(pngname.end()-3, pngname.end(), "png");
+      sprintf(tmp, "convert -transparent white %s %s",
+              pngname.c_str(), pngname.c_str());
+      Msg::Info("Running:");
+      Msg::Info(tmp);
+      int ret = system(tmp);
+      Msg::Info("Conversion returned value %d", ret);
+      if (ret == 0) // success
+        Msg::Info("Automatic transparent white background successful.");
+      else {
+        Msg::Warning("Cannot automatically add transparency to png.");
+        sprintf(tmp, "One should now manually add a transparent layer in "
+                "order to not obstruct the axis. e.g. using gimp or "
+                "convert -transparent white %s %s`.",
+                pngfilen.c_str(), pngfilen.c_str());
+        Msg::Warning(tmp);
+      }
+    }
+    else { // exit (EXIT_FAILURE);
+      Msg::Warning("Cannot automatically add transparency to output png.");
+      sprintf(tmp, "One should now manually add a transparent layer in "
+              "order to not obstruct the axis. e.g. using gimp or "
+              "`convert -transparent white %s %s`.",
+              pngfilen.c_str(), pngfilen.c_str());
+      Msg::Warning(tmp);
+    }
+  }
+
+  // try to write a helper tex file just in case it does not exist
+  fp = Fopen(texfilen.c_str(), "r");
+  if(fp){
+    fclose(fp);
+    Msg::Info("File '%s' exists, please add '\\input{%s}' by yourself.",
+              texfilen.c_str(), pgffilen.c_str());
+  }
+  else {
+    fp = Fopen(texfilen.c_str(), "w");
+    fprintf(fp,"\\documentclass{article}\n\\usepackage{pgfplots}\n"
+            "\\pgfplotsset{compat=1.8}\n\\begin{document}\n");
+    fprintf(fp,"\n\\input{%s}\n", pgffilen.c_str());
+    fprintf(fp,"\n\\end{document}\n");
+    fclose(fp);
+  }
+  return 0;
+}
diff --git a/Graphics/gl2pgf.h b/Graphics/gl2pgf.h
new file mode 100644
index 0000000..22e905f
--- /dev/null
+++ b/Graphics/gl2pgf.h
@@ -0,0 +1,16 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
+#ifndef _GL2PGF_H_
+#define _GL2PGF_H_
+
+#include <string>
+#include "PixelBuffer.h"
+
+int print_pgf(const std::string &name, const int num, const int cnt, 
+              PixelBuffer *buffer, double *eulerAngles,
+              int *viewport, double *proj, double *model);
+
+#endif
diff --git a/Mesh/BackgroundMesh.cpp b/Mesh/BackgroundMesh.cpp
index b215630..70509ca 100644
--- a/Mesh/BackgroundMesh.cpp
+++ b/Mesh/BackgroundMesh.cpp
@@ -472,6 +472,7 @@ void backgroundMesh::unset()
   _current = 0;
 }
 
+double backgroundMesh::sizeFactor = 1.0;
 backgroundMesh::backgroundMesh(GFace *_gf, bool cfd)
 #if defined(HAVE_ANN)
   : _octree(0), uv_kdtree(0), nodes(0), angle_nodes(0), angle_kdtree(0)
@@ -503,7 +504,7 @@ backgroundMesh::backgroundMesh(GFace *_gf, bool cfd)
         _vertices.push_back(newv);
         _3Dto2D[v] = newv;
         _2Dto3D[newv] = v;
-	if(v->onWhat()->dim()<2) myBCNodes.insert(p);
+        if(v->onWhat()->dim()<2) myBCNodes.insert(p);
       }
       else newv = it->second;
       news[j] = newv;
@@ -513,20 +514,20 @@ backgroundMesh::backgroundMesh(GFace *_gf, bool cfd)
 
 #if defined(HAVE_ANN)
   //printf("creating uv kdtree %d \n", myBCNodes.size());
-    index = new ANNidx[2];
-    dist  = new ANNdist[2];
-    nodes = annAllocPts(myBCNodes.size(), 3);
-    std::set<SPoint2>::iterator itp = myBCNodes.begin();
-    int ind = 0;
-    while (itp != myBCNodes.end()){
-      SPoint2 pt = *itp;
-      //fprintf(of, "SP(%g,%g,%g){%g};\n", pt.x(), pt.y(), 0.0, 10000);
-      nodes[ind][0] = pt.x();
-      nodes[ind][1] = pt.y();
-      nodes[ind][2] = 0.0;
-      itp++; ind++;
-    }
-    uv_kdtree = new ANNkd_tree(nodes, myBCNodes.size(), 3);
+  index = new ANNidx[2];
+  dist  = new ANNdist[2];
+  nodes = annAllocPts(myBCNodes.size(), 3);
+  std::set<SPoint2>::iterator itp = myBCNodes.begin();
+  int ind = 0;
+  while (itp != myBCNodes.end()){
+    SPoint2 pt = *itp;
+    //fprintf(of, "SP(%g,%g,%g){%g};\n", pt.x(), pt.y(), 0.0, 10000);
+    nodes[ind][0] = pt.x();
+    nodes[ind][1] = pt.y();
+    nodes[ind][2] = 0.0;
+    itp++; ind++;
+  }
+  uv_kdtree = new ANNkd_tree(nodes, myBCNodes.size(), 3);
 #endif
 
   // build a search structure
@@ -568,8 +569,8 @@ backgroundMesh::~backgroundMesh()
 }
 
 static void propagateValuesOnFace(GFace *_gf,
-                                  std::map<MVertex*,double> &dirichlet,
-				  bool in_parametric_plane = false)
+    std::map<MVertex*,double> &dirichlet,
+    bool in_parametric_plane = false)
 {
 #if defined(HAVE_SOLVER)
   linearSystem<double> *_lsys = 0;
@@ -655,19 +656,19 @@ void backgroundMesh::propagate1dMesh(GFace *_gf)
       for(unsigned int i = 0; i < (*it)->lines.size(); i++ ){
         MVertex *v1 = (*it)->lines[i]->getVertex(0);
         MVertex *v2 = (*it)->lines[i]->getVertex(1);
-	if (v1 != v2){
-	  double d = sqrt((v1->x() - v2->x()) * (v1->x() - v2->x()) +
-			  (v1->y() - v2->y()) * (v1->y() - v2->y()) +
-			  (v1->z() - v2->z()) * (v1->z()  -v2->z()));
-	  for (int k=0;k<2;k++){
-	    MVertex *v = (*it)->lines[i]->getVertex(k);
-	    std::map<MVertex*, double>::iterator itv = sizes.find(v);
-	    if (itv == sizes.end())
-	      sizes[v] = log(d);
-	    else
-	      itv->second = 0.5 * (itv->second + log(d));
-	  }
-	}
+        if (v1 != v2){
+          double d = sqrt((v1->x() - v2->x()) * (v1->x() - v2->x()) +
+              (v1->y() - v2->y()) * (v1->y() - v2->y()) +
+              (v1->z() - v2->z()) * (v1->z()  -v2->z()));
+          for (int k=0;k<2;k++){
+            MVertex *v = (*it)->lines[i]->getVertex(k);
+            std::map<MVertex*, double>::iterator itv = sizes.find(v);
+            if (itv == sizes.end())
+              sizes[v] = log(d);
+            else
+              itv->second = 0.5 * (itv->second + log(d));
+          }
+        }
       }
     }
   }
@@ -714,14 +715,14 @@ void backgroundMesh::propagateCrossFieldByDistance(GFace *_gf)
         v[1] = (*it)->lines[i]->getVertex(1);
         SPoint2 p1,p2;
         reparamMeshEdgeOnFace(v[0],v[1],_gf,p1,p2);
-	/* a correct way of computing angles  */
-	Pair<SVector3, SVector3> der = _gf->firstDer((p1+p2)*.5);
-	SVector3 t1 = der.first();
-	SVector3 t2 (v[1]->x()-v[0]->x(),v[1]->y()-v[0]->y(),v[1]->z()-v[0]->z());
-	t1.normalize();
-	t2.normalize();
-	double _angle = angle (t1,t2);
-	//        double angle = atan2 ( p1.y()-p2.y() , p1.x()-p2.x() );
+        /* a correct way of computing angles  */
+        Pair<SVector3, SVector3> der = _gf->firstDer((p1+p2)*.5);
+        SVector3 t1 = der.first();
+        SVector3 t2 (v[1]->x()-v[0]->x(),v[1]->y()-v[0]->y(),v[1]->z()-v[0]->z());
+        t1.normalize();
+        t2.normalize();
+        double _angle = angle (t1,t2);
+        //        double angle = atan2 ( p1.y()-p2.y() , p1.x()-p2.x() );
         crossField2d::normalizeAngle (_angle);
         for (int i=0;i<2;i++){
           std::map<MVertex*,double>::iterator itc = _cosines4.find(v[i]);
@@ -731,7 +732,7 @@ void backgroundMesh::propagateCrossFieldByDistance(GFace *_gf)
             its->second  = 0.5*(its->second + sin(4*_angle));
           }
           else {
-	    _param[v[i]] = (i==0) ? p1 : p2;
+            _param[v[i]] = (i==0) ? p1 : p2;
             _cosines4[v[i]] = cos(4*_angle);
             _sines4[v[i]] = sin(4*_angle);
           }
@@ -789,15 +790,15 @@ void backgroundMesh::propagateCrossField(GFace *_gf)
         v[1] = (*it)->lines[i]->getVertex(1);
         SPoint2 p1,p2;
         reparamMeshEdgeOnFace(v[0],v[1],_gf,p1,p2);
-	Pair<SVector3, SVector3> der = _gf->firstDer((p1+p2)*.5);
-	SVector3 t1 = der.first();
-	SVector3 t2 = der.second();
-	SVector3 n = crossprod(t1,t2);
-	n.normalize();
-	SVector3 d1(v[1]->x()-v[0]->x(),v[1]->y()-v[0]->y(),v[1]->z()-v[0]->z());
-	t1.normalize();
-	d1.normalize();
-	double _angle = myAngle (t1,d1,n);
+        Pair<SVector3, SVector3> der = _gf->firstDer((p1+p2)*.5);
+        SVector3 t1 = der.first();
+        SVector3 t2 = der.second();
+        SVector3 n = crossprod(t1,t2);
+        n.normalize();
+        SVector3 d1(v[1]->x()-v[0]->x(),v[1]->y()-v[0]->y(),v[1]->z()-v[0]->z());
+        t1.normalize();
+        d1.normalize();
+        double _angle = myAngle (t1,d1,n);
         crossField2d::normalizeAngle (_angle);
         for (int i=0;i<2;i++){
           std::map<MVertex*,double>::iterator itc = _cosines4.find(v[i]);
@@ -836,21 +837,21 @@ void backgroundMesh::updateSizes(GFace *_gf)
     MVertex *v = _2Dto3D[itv->first];
     double lc;
     if (v->onWhat()->dim() == 0){
-      lc = BGM_MeshSize(v->onWhat(), 0,0,v->x(),v->y(),v->z());
+      lc = sizeFactor * BGM_MeshSize(v->onWhat(), 0,0,v->x(),v->y(),v->z());
     }
     else if (v->onWhat()->dim() == 1){
       double u;
       v->getParameter(0, u);
-      lc = BGM_MeshSize(v->onWhat(), u, 0, v->x(), v->y(), v->z());
+      lc = sizeFactor * BGM_MeshSize(v->onWhat(), u, 0, v->x(), v->y(), v->z());
     }
     else{
       reparamMeshVertexOnFace(v, _gf, p);
-      lc = BGM_MeshSize(_gf, p.x(), p.y(), v->x(), v->y(), v->z());
+      lc = sizeFactor * BGM_MeshSize(_gf, p.x(), p.y(), v->x(), v->y(), v->z());
     }
     // printf("2D -- %g %g 3D -- %g %g\n",p.x(),p.y(),v->x(),v->y());
     itv->second = std::min(lc,itv->second);
-    itv->second = std::max(itv->second, CTX::instance()->mesh.lcMin);
-    itv->second = std::min(itv->second, CTX::instance()->mesh.lcMax);
+    itv->second = std::max(itv->second,  sizeFactor * CTX::instance()->mesh.lcMin);
+    itv->second = std::min(itv->second,  sizeFactor * CTX::instance()->mesh.lcMax);
   }
   // do not allow large variations in the size field
   // (Int. J. Numer. Meth. Engng. 43, 1143-1165 (1998) MESH GRADATION
@@ -979,7 +980,7 @@ double backgroundMesh::getAngle(double u, double v, double w) const
 }
 
 void backgroundMesh::print(const std::string &filename, GFace *gf,
-                           const std::map<MVertex*,double> &_whatToPrint) const
+    const std::map<MVertex*,double> &_whatToPrint) const
 {
   FILE *f = Fopen (filename.c_str(),"w");
   fprintf(f,"View \"Background Mesh\"{\n");
@@ -992,9 +993,9 @@ void backgroundMesh::print(const std::string &filename, GFace *gf,
     std::map<MVertex*,double>::const_iterator itv3 = _whatToPrint.find(v3);
     if (!gf){
       fprintf(f,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
-              v1->x(),v1->y(),v1->z(),
-              v2->x(),v2->y(),v2->z(),
-              v3->x(),v3->y(),v3->z(),itv1->second,itv2->second,itv3->second);
+          v1->x(),v1->y(),v1->z(),
+          v2->x(),v2->y(),v2->z(),
+          v3->x(),v3->y(),v3->z(),itv1->second,itv2->second,itv3->second);
     }
     else {
 
@@ -1002,9 +1003,9 @@ void backgroundMesh::print(const std::string &filename, GFace *gf,
       GPoint p2 = gf->point(SPoint2(v2->x(),v2->y()));
       GPoint p3 = gf->point(SPoint2(v3->x(),v3->y()));
       fprintf(f,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
-              p1.x(),p1.y(),p1.z(),
-              p2.x(),p2.y(),p2.z(),
-              p3.x(),p3.y(),p3.z(),itv1->second,itv2->second,itv3->second);
+          p1.x(),p1.y(),p1.z(),
+          p2.x(),p2.y(),p2.z(),
+          p3.x(),p3.y(),p3.z(),itv1->second,itv2->second,itv3->second);
     }
   }
   fprintf(f,"};\n");
@@ -1015,4 +1016,13 @@ MElementOctree* backgroundMesh::get_octree(){
   return _octree;
 }
 
+MElement *backgroundMesh::getMeshElementByCoord(double u, double v, double w, bool strict)
+{
+  if(!_octree){
+    Msg::Debug("Rebuilding BackgroundMesh element octree");
+    _octree = new MElementOctree(_triangles);
+  }
+  return _octree->find(u,v,w, 2, strict);
+}
+
 backgroundMesh* backgroundMesh::_current = 0;
diff --git a/Mesh/BackgroundMesh.h b/Mesh/BackgroundMesh.h
index 6550bf6..69526e3 100644
--- a/Mesh/BackgroundMesh.h
+++ b/Mesh/BackgroundMesh.h
@@ -41,6 +41,7 @@ struct crossField2d
 
 class backgroundMesh : public simpleFunction<double>
 {
+  static double sizeFactor;
   MElementOctree *_octree;
   std::vector<MVertex*> _vertices;
   std::vector<MElement*> _triangles;
@@ -66,6 +67,7 @@ class backgroundMesh : public simpleFunction<double>
   static void setCrossFieldsByDistance(GFace *);
   static void unset();
   static backgroundMesh *current () { return _current; }
+  static void setSizeFactor (double s) {sizeFactor = s;}
   void propagate1dMesh(GFace *);
   void propagateCrossField(GFace *);
   void propagateCrossFieldByDistance(GFace *);
@@ -83,6 +85,16 @@ class backgroundMesh : public simpleFunction<double>
     }
   }
   MElementOctree* get_octree();
+  MElement *getMeshElementByCoord(double u, double v, double w, bool strict=true);
+  int getNumMeshElements()const{return _triangles.size();}
+  std::vector<MVertex*>::iterator begin_vertices(){return _vertices.begin();}
+  std::vector<MVertex*>::iterator end_vertices(){return _vertices.end();}
+  std::vector<MVertex*>::const_iterator begin_vertices()const{return _vertices.begin();}
+  std::vector<MVertex*>::const_iterator end_vertices()const{return _vertices.end();}
+  std::vector<MElement*>::iterator begin_triangles(){return _triangles.begin();}
+  std::vector<MElement*>::iterator end_triangles(){return _triangles.end();}
+  std::vector<MElement*>::const_iterator begin_triangles()const{return _triangles.begin();}
+  std::vector<MElement*>::const_iterator end_triangles()const{return _triangles.end();}
 };
 
 SMetric3 buildMetricTangentToCurve (SVector3 &t, double l_t, double l_n);
diff --git a/Mesh/BoundaryLayers.cpp b/Mesh/BoundaryLayers.cpp
index f89a66e..741d67d 100644
--- a/Mesh/BoundaryLayers.cpp
+++ b/Mesh/BoundaryLayers.cpp
@@ -32,7 +32,7 @@ static double GetAveEdgeLength(std::vector<MVertex*> &elem_verts)
   if(!size)
     return 0.0;
   for( int i = 0; i < size-1; i++ )
-    ave += elem_verts[i]->distance(elem_verts[i+1]);    
+    ave += elem_verts[i]->distance(elem_verts[i+1]);
   ave += elem_verts[0]->distance(elem_verts[size-1]);
   ave /= size;
   return ave;
@@ -47,7 +47,7 @@ static void addExtrudeNormals(std::vector<T*> &elements, int invert,
     Msg::Error("Boundary layer index should be 0 or 1");
     return;
   }
- 
+
   if(octree && !gouraud){ // get extrusion direction from post-processing view
     // Trevor Strickler modified this section heavily
     std::set<MVertex*> verts;
@@ -117,10 +117,10 @@ static void addExtrudeNormals(std::vector<T*> &elements, int invert,
 typedef std::set<std::pair<bool, std::pair<int, int> > > infoset;
 
 // Trevor Strickler Modified this function
-//skipScaleCalcMap maps an entity tag to a flag telling whether to skip the 
+//skipScaleCalcMap maps an entity tag to a flag telling whether to skip the
 // scale calc when extruding only that entity.  The flag is false when an extrusion
 // is not scaleLast when in a boundary layer that has at least one scaleLast region.
-// Effectively, this makes the vertices on the boundary between a scaled and not 
+// Effectively, this makes the vertices on the boundary between a scaled and not
 // scaled region 'average' between being scaled and not scaled.
 template<class T>
 static void addExtrudeNormals(std::set<T*> &entities,
@@ -245,7 +245,7 @@ static void checkDepends(GModel *m, GFace *f, std::set<GFace*> &dep)
     dep.insert(from);
     checkDepends(m, from, dep);
   }
-  
+
   // Added by Trevor Strickler for compound face extrusion
   if( f->geomType() == GEntity::CompoundSurface ){
     std::list<GFace*> compounds = ((GFaceCompound*)(f))->getCompounds();
@@ -259,18 +259,19 @@ static void checkDepends(GModel *m, GFace *f, std::set<GFace*> &dep)
       checkDepends(m, *itgf, dep);
     }
   }
-  
+
 }
 
 // Trevor Strickler
-static unsigned int FixErasedExtrScaleFlags(GModel *m, std::map<int, bool> &faceSkipScaleCalc, std::map<int, bool> &edgeSkipScaleCalc)
+static unsigned int FixErasedExtrScaleFlags(GModel *m, std::map<int, bool> &faceSkipScaleCalc,
+                                            std::map<int, bool> &edgeSkipScaleCalc)
 {
   unsigned int num_changed = 0;
   std::set<GRegion *, GEntityLessThan>::iterator itreg;
   // fix all extruded faces bordering ScaleLast regions
   for( itreg = m->firstRegion(); itreg != m->lastRegion(); itreg++ ){
     ExtrudeParams *r_ep = (*itreg)->meshAttributes.extrude;
-    if(!r_ep || !r_ep->mesh.ExtrudeMesh || r_ep->geo.Mode != EXTRUDED_ENTITY 
+    if(!r_ep || !r_ep->mesh.ExtrudeMesh || r_ep->geo.Mode != EXTRUDED_ENTITY
         || !r_ep->mesh.ScaleLast )
       continue;
     std::list<GFace *> reg_faces = (*itreg)->faces();
@@ -308,7 +309,7 @@ static unsigned int FixErasedExtrScaleFlags(GModel *m, std::map<int, bool> &face
       }
     }
   }
-  
+
   return num_changed;
 }
 
@@ -320,7 +321,7 @@ int Mesh2DWithBoundaryLayers(GModel *m)
   std::map<int, bool> faceSkipScaleCalc, edgeSkipScaleCalc; // Trevor Strickler
   ExtrudeParams::calcLayerScaleFactor[0] = 0; // Trevor Strickler
   ExtrudeParams::calcLayerScaleFactor[1] = 0; // Trevor Strickler
-  
+
   // 2D boundary layers
   for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); it++){
     GEdge *ge = *it;
@@ -467,7 +468,7 @@ int Mesh2DWithBoundaryLayers(GModel *m)
           vdest = ge->getEndVertex();
         }
         GPoint p = vsrc->point();
-	
+
         ep->Extrude(ep->mesh.NbLayer - 1, ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1],
                     p.x(), p.y(), p.z());
         vdest->setPosition(p);
@@ -517,105 +518,3 @@ int Mesh2DWithBoundaryLayers(GModel *m)
   return 1;
 }
 
-// give it a try : add one quad layer on the
-  /*
-void addOneLayerOnContour(GFace *gf, GVertex *gv){
-, int nbLayers, double hplus, double factor){
-  // for each vertex
-  std::map<MVertex*,std::vector<MVertex*> >layers;
-  std::vector<MQuadrangle*> newQuads;
-  std::vector<MTriangle*> newTris;
-
-  std::list<GEdgeLoop>::iterator it = gf->edgeLoops.begin();
-  for (; it != gf->edgeLoops.end(); ++it){
-    bool found = false;
-    std::list<GEdge*> ed;
-    for (GEdgeLoop::iter it2 = it->begin(); it2 != it->end(); ++it2){
-      if (it2->ge->getBeginVertex() == gv || it2->ge->getEndVertex() == gv) {
-	found = true;
-      }
-      ed.push_back(it2->ge);
-    }
-    // we found an edge loop with the GVertex that was specified
-    if (found){
-      // compute model vertices that will produce fans
-      for (GEdgeLoop::iter it2 = it->begin(); it2 != it->end(); ++it2){
-	GEdgeLoop::iter it3 = it2; ++it3;
-	GVertex *gv = it2->getEndVertex();
-	GEdgeSigned *before,*after = *it2;
-	if (it3 == it->end()){
-	  before = *(it->begin());
-	}
-	else{
-	  before = *it2;
-	}
-      }
-
-      for (std::list<GEdge*>::iterator it = ed.begin(); it != ed.end(); ++it){
-	GEdge *ge = *it;
-	for (int i=0;i<ge->lines.size();i++){
-	  SPoint2 p[2];
-	  reparamMeshEdgeOnFace ( ge->lines[i]->getVertex(0), ge->lines[i]->getVertex(1),gf,p[0],p[1]);
-	  MVertex *vd[2];
-	  for (int j=0;j<2;j++){
-	    MVertex *v = ge->lines[i]->getVertex(j);
-	    std::map<MVertex*,MVertex*>::iterator itv = duplicates.find(v);
-	    if (itv == duplicates.end()){
-	      vd[j] = new MFaceVertex(v->x(),v->y(),v->z(),gf,p[j].x(),p[j].y());
-	      duplicates[v] = vd[j];
-	      gf->mesh_vertices.push_back(vd[j]);
-	    }
-	    else
-	      vd[j] = itv->second;
-	  }
-	  newQuads.push_back(new MQuadrangle(ge->lines[i]->getVertex(0), ge->lines[i]->getVertex(1),vd[1],vd[0]));
-	}
-      }
-      for (int i=0;i<gf->quadrangles.size();i++){
-	MQuadrangle *q = gf->quadrangles[i];
-	MVertex *vs[4];
-	for (int j=0;j<4;j++){
-	  MVertex *v = q->getVertex(j);
-	  std::map<MVertex*,MVertex*>::iterator itv = duplicates.find(v);
-	  if (itv == duplicates.end()){
-	    vs[j] = v;
-	  }
-	  else{
-	    vs[j] = itv->second;
-	  }
-	}
-	newQuads.push_back(new MQuadrangle(vs[0],vs[1],vs[2],vs[3]));
-	delete q;
-      }
-      for (int i=0;i<gf->triangles.size();i++){
-	MTriangle *t = gf->triangles[i];
-	MVertex *vs[3];
-	for (int j=0;j<3;j++){
-	  MVertex *v = t->getVertex(j);
-	  std::map<MVertex*,MVertex*>::iterator itv = duplicates.find(v);
-	  if (itv == duplicates.end()){
-	    vs[j] = v;
-	  }
-	  else{
-	    vs[j] = itv->second;
-	  }
-	}
-	newTris.push_back(new MTriangle(vs[0],vs[1],vs[2]));
-	delete t;
-      }
-
-      gf->triangles = newTris;
-      gf->quadrangles = newQuads;
-    }
-  }
-}
-*/
-
-void addBoundaryLayers(GFace *gf)
-{
-  //if (backgroundMesh::current()){
-  //}
-  // first compute the cross field if it is not computed yet
-  // start from a selection of edges and create points in the boundary layer
-  // connect everybody with delaunay 
-}
diff --git a/Mesh/CenterlineField.cpp b/Mesh/CenterlineField.cpp
index 56f5ad1..0326e0e 100644
--- a/Mesh/CenterlineField.cpp
+++ b/Mesh/CenterlineField.cpp
@@ -296,21 +296,18 @@ static void cutTriangle(MTriangle *tri,
 Centerline::Centerline(std::string fileName): kdtree(0), kdtreeR(0)
 {
   recombine = (CTX::instance()->mesh.recombineAll) || (CTX::instance()->mesh.recombine3DAll);
-
-  printf("centerline filename =%s \n", fileName.c_str());
-  importFile(fileName);
-  buildKdTree();
   nbPoints = 25;
   hLayer = 0.3;
   hSecondLayer = 0.3;
   nbElemLayer = 3;
   nbElemSecondLayer = 0;
-
-  update_needed = false;
   is_cut = 0;
   is_closed = 0;
   is_extruded = 0;
 
+  importFile(fileName);
+  buildKdTree();
+  update_needed = false;
 }
 
 Centerline::Centerline(): kdtree(0), kdtreeR(0)
@@ -1009,8 +1006,10 @@ bool Centerline::cutByDisk(SVector3 &PT, SVector3 &NORM, double &maxRad)
       double rdist = -V1/(V2-V1);
       if (inters && rdist > EPS && rdist < 1.-EPS){
 	SVector3 PZ = P1+rdist*(P2-P1);
-	MVertex *newv = new MVertex (PZ.x(), PZ.y(), PZ.z());
-	if (inDisk) cutEdges.insert(std::make_pair(me,newv));
+	if (inDisk){
+          MVertex *newv = new MVertex (PZ.x(), PZ.y(), PZ.z());
+          cutEdges.insert(std::make_pair(me,newv));
+        }
       }
       else if (inters && rdist <= EPS && inDisk )
 	cutVertices.push_back(me.getVertex(0));
diff --git a/Mesh/DivideAndConquer.cpp b/Mesh/DivideAndConquer.cpp
index 183da42..9794a33 100644
--- a/Mesh/DivideAndConquer.cpp
+++ b/Mesh/DivideAndConquer.cpp
@@ -162,8 +162,8 @@ Segment DocRecord::UpperCommonTangent(DT vl, DT vr)
 int DocRecord::Qtest(PointNumero h, PointNumero i, PointNumero j, PointNumero k)
 {
   if((h == i) && (h == j) && (h == k)) {
-    Msg::Error("Identical points in triangulation: increase element size "
-               "or Mesh.RandomFactor");
+    throw "Identical points in triangulation: increase element size "
+      "or Mesh.RandomFactor";
     return 0;
   }
 
@@ -535,6 +535,7 @@ void DocRecord::voronoiCell(PointNumero pt, std::vector<SPoint2> &pts) const
 {
   if (!_adjacencies){
     Msg::Error("No adjacencies were created");
+    return;
   }
   const int n = _adjacencies[pt].t_length;
   for(int j = 0; j < n; j++) {
@@ -958,7 +959,13 @@ void DocRecord::concave(double x,double y,GFace* gf)
     points[i].vicinity.clear();
   }
 
-  MakeMeshWithPoints();
+  try{
+    MakeMeshWithPoints();
+  }
+  catch(const char *err){
+    Msg::Error("%s", err);
+  }
+
   set = tagInterior(x,y);
   for(it2 = set.begin(); it2 != set.end(); it2++){
     index1 = triangles[*it2].a;
diff --git a/Mesh/DivideAndConquer.h b/Mesh/DivideAndConquer.h
index f7cd848..6e14346 100644
--- a/Mesh/DivideAndConquer.h
+++ b/Mesh/DivideAndConquer.h
@@ -9,8 +9,6 @@
 #include <vector>
 #include <algorithm>
 #include "fullMatrix.h"
-
-// FIXME: should not introduce dependencies to Geo/ code in Numeric!
 #include "SPoint2.h"
 #include "simpleFunction.h"
 #include "Octree.h"
@@ -32,7 +30,10 @@ struct PointRecord {
   int flag; //0:to be kept, 1:to be removed
   int identificator;
   std::vector<void*> vicinity;
-  PointRecord() : adjacent(0), data (0) {}
+  PointRecord() : adjacent(0), data(0), flag(0), identificator(0)
+  {
+    where.v = where.h = 0.;
+  }
 };
 
 struct _CDLIST{
@@ -92,9 +93,9 @@ class DocRecord{
   int numTriangles;     // number of triangles
   Triangle *triangles;  // 2D results
   DocRecord(int n);
-  double &x(int i){ return points[i].where.h; } 
-  double &y(int i){ return points[i].where.v; } 
-  void*  &data(int i){ return points[i].data; } 
+  double &x(int i){ return points[i].where.h; }
+  double &y(int i){ return points[i].where.v; }
+  void*  &data(int i){ return points[i].data; }
   void setPoints(fullMatrix<double> *p);
   ~DocRecord();
   void MakeMeshWithPoints();
@@ -105,7 +106,7 @@ class DocRecord{
   void printMedialAxis(Octree *_octree, std::string, GFace *gf=NULL, GEdge *ge=NULL);
   double Lloyd (int);
   void voronoiCell (PointNumero pt, std::vector<SPoint2> &pts) const;
- 
+
   std::set<std::pair<void*,void*> > boundaryEdges;
 
   void addBoundaryEdge(void* p1,void* p2)
@@ -118,11 +119,11 @@ class DocRecord{
   {
     void *a = (p1 < p2) ? p1 : p2;
     void *b = (p1 > p2) ? p1 : p2;
-    std::set<std::pair<void*,void*> >::iterator it = 
+    std::set<std::pair<void*,void*> >::iterator it =
       boundaryEdges.find(std::make_pair(a,b));
     return it != boundaryEdges.end();
-  } 	
- 
+  }
+
   void recur_tag_triangles(int, std::set<int>&, std::map<std::pair<void*,void*>,
                            std::pair<int,int> >&);
   std::set<int> tagInterior(double,double);
@@ -134,9 +135,9 @@ class DocRecord{
   bool remove_point(int);
   void remove_all();
   void add_point(double,double,GFace*);
-	
+
   std::set<std::pair<void*,void*> > mesh_edges;
-	
+
   void add_edge(void* p1,void* p2)
   {
     void *a = (p1 < p2) ? p1 : p2;
@@ -147,27 +148,27 @@ class DocRecord{
   {
     void *a = (p1 < p2) ? p1 : p2;
     void *b = (p1 > p2) ? p1 : p2;
-    std::set<std::pair<void*,void*> >::iterator it = 
+    std::set<std::pair<void*,void*> >::iterator it =
       mesh_edges.find(std::make_pair(a,b));
     return it != mesh_edges.end();
-  } 	
-	
+  }
+
   void build_edges();
   void clear_edges();
-  bool delaunay_conformity(GFace*);		
-	
+  bool delaunay_conformity(GFace*);
+
   PointNumero *ConvertDlistToArray(DListPeek *dlist, int *n);
 };
 
 void centroidOfOrientedBox(std::vector<SPoint2> &pts,
                            const double &angle,
-                           double &xc, 
-                           double &yc, 
-                           double &inertia, 
+                           double &xc,
+                           double &yc,
+                           double &inertia,
 			   double &area);
 void centroidOfPolygon(SPoint2 &pc,
                        std::vector<SPoint2> &pts,
-                       double &xc, 
+                       double &xc,
                        double &yc,
                        double &inertia,
 		       double &areaCell,
diff --git a/Mesh/Field.cpp b/Mesh/Field.cpp
index 6b55d14..988ed80 100644
--- a/Mesh/Field.cpp
+++ b/Mesh/Field.cpp
@@ -485,6 +485,55 @@ class CylinderField : public Field
   }
 };
 
+class SphereField : public Field
+{
+  double v_in, v_out;
+  double xc,yc,zc;
+  double R;
+
+ public:
+  std::string getDescription()
+  {
+    return "The value of this field is VIn inside a sphere, VOut outside. "
+      "The sphere is given by\n\n"
+      "  ||dX||^2 < R^2 &&\n"
+      "  dX = (X - XC)^2 + (Y-YC)^2 + (Z-ZC)^2";
+  }
+  SphereField()
+  {
+    v_in = v_out = xc = yc = zc = R = 0;
+
+    options["VIn"] = new FieldOptionDouble
+      (v_in, "Value inside the sphere");
+    options["VOut"] = new FieldOptionDouble
+      (v_out, "Value outside the sphere");
+
+    options["XCenter"] = new FieldOptionDouble
+      (xc, "X coordinate of the sphere center");
+    options["YCenter"] = new FieldOptionDouble
+      (yc, "Y coordinate of the sphere center");
+    options["ZCenter"] = new FieldOptionDouble
+      (zc, "Z coordinate of the sphere center");
+
+
+    options["Radius"] = new FieldOptionDouble
+      (R,"Radius");
+
+  }
+  const char *getName()
+  {
+    return "Sphere";
+  }
+  double operator() (double x, double y, double z, GEntity *ge=0)
+  {
+    double dx = x-xc;
+    double dy = y-yc;
+    double dz = z-zc;
+
+    return ( (dx*dx + dy*dy + dz*dz < R*R) ) ? v_in : v_out;
+  }
+};
+
 class FrustumField : public Field
 {
   double x1,y1,z1;
@@ -1026,15 +1075,17 @@ class MathEvalField : public Field
   std::string f;
 
  public:
-  void myAction(){
-    printf("doing sthg \n");
+  void myAction()
+  {
+    printf("doing sthg\n");
   }
   MathEvalField()
   {
     options["F"] = new FieldOptionString
       (f, "Mathematical function to evaluate.", &update_needed);
     f = "F2 + Sin(z)";
-    callbacks["test"] = new FieldCallbackGeneric<MathEvalField>(this, &MathEvalField::myAction, "description blabla");
+    callbacks["test"] = new FieldCallbackGeneric<MathEvalField>
+      (this, &MathEvalField::myAction, "description blabla");
   }
   double operator() (double x, double y, double z, GEntity *ge=0)
   {
@@ -1246,8 +1297,11 @@ class PostViewField : public Field
     // of finding an element
     if(!octree->searchTensorWithTol(x, y, z, l, 0, 0, 0.05))
       Msg::Info("No tensor element found containing point (%g,%g,%g)", x, y, z);
-    if(l <= 0 && crop_negative_values)
-      for(int i = 0; i < 9; i++) l[i] = MAX_LC;
+    if(crop_negative_values){
+      for(int i = 0; i < 9; i++){
+        if(l[i] <= 0) l[i] = MAX_LC;
+      }
+    }
     metr(0, 0) = l[0];
     metr(0, 1) = l[1];
     metr(0, 2) = l[2];
@@ -1334,6 +1388,76 @@ class MinAnisoField : public Field
   }
 };
 
+class IntersectAnisoField : public Field
+{
+  std::list<int> idlist;
+ public:
+  IntersectAnisoField()
+  {
+    options["FieldsList"] = new FieldOptionList
+      (idlist, "Field indices", &update_needed);
+  }
+  virtual bool isotropic () const {return false;}
+  std::string getDescription()
+  {
+    return "Take the intersection of 2 anisotropic fields according to Alauzet.";
+  }
+  virtual void operator() (double x, double y, double z, SMetric3 &metr, GEntity *ge=0)
+  {
+    // check if idlist contains 2 elements other error message
+    SMetric3 v;
+    for(std::list<int>::iterator it = idlist.begin(); it != idlist.end(); it++) {
+      Field *f = (GModel::current()->getFields()->get(*it));
+      SMetric3 ff;
+      if(f && *it != id) {
+	if (f->isotropic()){
+	  double l = (*f) (x, y, z, ge);
+	  ff = SMetric3(1./(l*l));
+	}
+	else{
+	  (*f) (x, y, z, ff, ge);
+	}
+	if (it == idlist.begin())
+          v = ff;
+	else
+          v = intersection_alauzet(v,ff);
+      }
+    }
+    metr = v;
+  }
+  double operator() (double x, double y, double z, GEntity *ge=0)
+  {
+    // check if idlist contains 2 elements other error message
+    SMetric3 metr;
+    for(std::list<int>::iterator it = idlist.begin(); it != idlist.end(); it++) {
+      Field *f = (GModel::current()->getFields()->get(*it));
+      SMetric3 m;
+      if(f && *it != id){
+        if (!f->isotropic()){
+          (*f)(x, y, z, m, ge);
+        }
+	else {
+          double L = (*f)(x, y, z, ge);
+          for (int i = 0; i < 3; i++)
+            m(i,i) = 1. / (L*L);
+	}
+      }
+      if (it == idlist.begin())
+        metr = m;
+      else
+        metr = intersection_alauzet(metr,m);
+    }
+    fullMatrix<double> V(3,3);
+    fullVector<double> S(3);
+    metr.eig(V, S, 1);
+    return sqrt(1./S(2)); //S(2) is largest eigenvalue
+  }
+  const char *getName()
+  {
+    return "IntersectAniso";
+  }
+};
+
 class MinField : public Field
 {
   std::list<int> idlist;
@@ -1352,7 +1476,18 @@ class MinField : public Field
     double v = MAX_LC;
     for(std::list<int>::iterator it = idlist.begin(); it != idlist.end(); it++) {
       Field *f = (GModel::current()->getFields()->get(*it));
-      if(f && *it != id) v = std::min(v, (*f) (x, y, z, ge));
+      if(f && *it != id) {
+        if (f->isotropic())
+	   v = std::min(v, (*f) (x, y, z, ge));
+	else{
+	   SMetric3 ff;
+	   (*f) (x, y, z, ff, ge);
+	   fullMatrix<double> V(3,3);
+	   fullVector<double> S(3);
+	   ff.eig(V, S, 1);
+	   v = std::min(v, sqrt(1./S(2))); //S(2) is largest eigenvalue
+	}
+      }
     }
     return v;
   }
@@ -1380,7 +1515,18 @@ class MaxField : public Field
     double v = -MAX_LC;
     for(std::list<int>::iterator it = idlist.begin(); it != idlist.end(); it++) {
       Field *f = (GModel::current()->getFields()->get(*it));
-      if(f && *it != id) v = std::max(v, (*f) (x, y, z, ge));
+      if(f && *it != id) {
+        if (f->isotropic())
+	   v = std::max(v, (*f) (x, y, z, ge));
+	else{
+	   SMetric3 ff;
+	   (*f) (x, y, z, ff, ge);
+	   fullMatrix<double> V(3,3);
+	   fullVector<double> S(3);
+	   ff.eig(V, S, 1);
+	   v = std::max(v, sqrt(1./S(0))); //S(0) is smallest eigenvalue
+	}
+      }
     }
     return v;
   }
@@ -1913,7 +2059,7 @@ void BoundaryLayerField::setupFor2d(int iF)
 	nodes_id.push_back ((*it)->getEndVertex()->tag());
       }
     }
-    printf("face %d %d BL Edges\n", iF, (int)edges_id.size());
+    //    printf("face %d %d BL Edges\n", iF, (int)edges_id.size());
 
     removeAttractors();
   }
@@ -2154,6 +2300,7 @@ FieldManager::FieldManager()
 #endif
   map_type_name["Box"] = new FieldFactoryT<BoxField>();
   map_type_name["Cylinder"] = new FieldFactoryT<CylinderField>();
+  map_type_name["Sphere"] = new FieldFactoryT<SphereField>();
   map_type_name["Frustum"] = new FieldFactoryT<FrustumField>();
   map_type_name["LonLat"] = new FieldFactoryT<LonLatField>();
 #if defined(HAVE_POST)
@@ -2163,6 +2310,7 @@ FieldManager::FieldManager()
   map_type_name["Restrict"] = new FieldFactoryT<RestrictField>();
   map_type_name["Min"] = new FieldFactoryT<MinField>();
   map_type_name["MinAniso"] = new FieldFactoryT<MinAnisoField>();
+  map_type_name["IntersectAniso"] = new FieldFactoryT<IntersectAnisoField>();
   map_type_name["Max"] = new FieldFactoryT<MaxField>();
   map_type_name["Laplacian"] = new FieldFactoryT<LaplacianField>();
   map_type_name["Mean"] = new FieldFactoryT<MeanField>();
diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp
index f2d0e0f..c1fc939 100644
--- a/Mesh/Generator.cpp
+++ b/Mesh/Generator.cpp
@@ -46,132 +46,6 @@
 #include "PViewData.h"
 #endif
 
-static MVertex* isEquivalentTo(std::multimap<MVertex*, MVertex*> &m, MVertex *v)
-{
-  std::multimap<MVertex*, MVertex*>::iterator it = m.lower_bound(v);
-  std::multimap<MVertex*, MVertex*>::iterator ite = m.upper_bound(v);
-  if (it == ite) return v;
-  MVertex *res = it->second; ++it;
-  while (it !=ite){
-    res = std::min(res,it->second); ++it;
-  }
-  if (res < v) return isEquivalentTo(m, res);
-  return res;
-}
-
-static void buildASetOfEquivalentMeshVertices(GFace *gf,
-                                              std::multimap<MVertex*, MVertex *> &equivalent,
-                                              std::map<GVertex*, MVertex*> &bm)
-{
-  // an edge is degenerated when is length is considered to be
-  // zero. In some cases, a model edge can be considered as too
-  // small an is ignored.
-
-  // for taking that into account, we loop over the edges
-  // and create pairs of MVertices that are considered as
-  // equal.
-
-  std::list<GEdge*> edges = gf->edges();
-  std::list<GEdge*> emb_edges = gf->embeddedEdges();
-  std::list<GEdge*>::iterator it = edges.begin();
-
-  while(it != edges.end()){
-    if((*it)->isMeshDegenerated()){
-      MVertex *va = *((*it)->getBeginVertex()->mesh_vertices.begin());
-      MVertex *vb = *((*it)->getEndVertex()->mesh_vertices.begin());
-      if (va != vb){
-        equivalent.insert(std::make_pair(va, vb));
-        equivalent.insert(std::make_pair(vb, va));
-        bm[(*it)->getBeginVertex()] = va;
-        bm[(*it)->getEndVertex()] = vb;
-        printf("%d equivalent to %d\n", va->getNum(), vb->getNum());
-      }
-    }
-    ++it;
-  }
-
-  it = emb_edges.begin();
-  while(it != emb_edges.end()){
-    if((*it)->isMeshDegenerated()){
-      MVertex *va = *((*it)->getBeginVertex()->mesh_vertices.begin());
-      MVertex *vb = *((*it)->getEndVertex()->mesh_vertices.begin());
-      if (va != vb){
-        equivalent.insert(std::make_pair(va, vb));
-        equivalent.insert(std::make_pair(vb, va));
-        bm[(*it)->getBeginVertex()] = va;
-        bm[(*it)->getEndVertex()] = vb;
-      }
-    }
-    ++it;
-  }
-}
-
-struct geomThresholdVertexEquivalence
-{
-  // Initial MVertex associated to one given MVertex
-  std::map<GVertex*, MVertex*> backward_map;
-  // initiate the forward and backward maps
-  geomThresholdVertexEquivalence(GModel *g);
-  // restores the initial state
-  ~geomThresholdVertexEquivalence ();
-};
-
-geomThresholdVertexEquivalence::geomThresholdVertexEquivalence(GModel *g)
-{
-  std::multimap<MVertex*, MVertex*> equivalenceMap;
-  for (GModel::fiter it = g->firstFace(); it != g->lastFace(); ++it)
-    buildASetOfEquivalentMeshVertices(*it, equivalenceMap, backward_map);
-  // build the structure that identifiate geometrically equivalent
-  // mesh vertices.
-  for (std::map<GVertex*, MVertex*>::iterator it = backward_map.begin();
-       it != backward_map.end(); ++it){
-    GVertex *g = it->first;
-    MVertex *v = it->second;
-    MVertex *other = isEquivalentTo(equivalenceMap, v);
-    if (v != other){
-      printf("Finally : %d equivalent to %d\n", v->getNum(), other->getNum());
-      g->mesh_vertices.clear();
-      g->mesh_vertices.push_back(other);
-      std::list<GEdge*> ed = g->edges();
-      for (std::list<GEdge*>::iterator ite = ed.begin() ; ite != ed.end() ; ++ite){
-        std::vector<MLine*> newl;
-        for (unsigned int i = 0; i < (*ite)->lines.size(); ++i){
-          MLine *l = (*ite)->lines[i];
-          MVertex *v1 = l->getVertex(0);
-          MVertex *v2 = l->getVertex(1);
-          if (v1 == v && v2 != other){
-            delete l;
-            l = new MLine(other,v2);
-            newl.push_back(l);
-          }
-          else if (v1 != other && v2 == v){
-            delete l;
-            l = new MLine(v1,other);
-            newl.push_back(l);
-          }
-          else if (v1 != v && v2 != v)
-            newl.push_back(l);
-          else
-            delete l;
-        }
-        (*ite)->lines = newl;
-      }
-    }
-  }
-}
-
-geomThresholdVertexEquivalence::~geomThresholdVertexEquivalence()
-{
-  // restore the initial data
-  for (std::map<GVertex*, MVertex*>::iterator it = backward_map.begin();
-       it != backward_map.end() ; ++it){
-    GVertex *g = it->first;
-    MVertex *v = it->second;
-    g->mesh_vertices.clear();
-    g->mesh_vertices.push_back(v);
-  }
-}
-
 template<class T>
 static void GetQualityMeasure(std::vector<T*> &ele,
                               double &gamma, double &gammaMin, double &gammaMax,
@@ -466,9 +340,6 @@ static void Mesh2D(GModel *m)
   for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it)
     (*it)->meshStatistics.status = GFace::PENDING;
 
-  // skip short mesh edges
-  //geomThresholdVertexEquivalence inst(m);
-
   // boundary layers are special: their generation (including vertices
   // and curve meshes) is global as it depends on a smooth normal
   // field generated from the surface mesh of the source surfaces
@@ -493,7 +364,7 @@ static void Mesh2D(GModel *m)
       for(size_t K = 0 ; K < temp.size() ; K++){
 	if (temp[K]->meshStatistics.status == GFace::PENDING){
           backgroundMesh::current()->unset();
-	  meshGFace mesher(true, CTX::instance()->mesh.multiplePasses);
+	  meshGFace mesher(true);
 	  mesher(temp[K]);
 
 #if defined(HAVE_BFGS)
@@ -532,7 +403,7 @@ static void Mesh2D(GModel *m)
           it != cf.end(); ++it){
         if ((*it)->meshStatistics.status == GFace::PENDING){
           backgroundMesh::current()->unset();
-          meshGFace mesher(true, CTX::instance()->mesh.multiplePasses);
+          meshGFace mesher(true);
           mesher(*it);
 
 #if defined(HAVE_BFGS)
@@ -671,6 +542,9 @@ static void Mesh3D(GModel *m)
     }
   }
 
+  // Ensure that all volume Jacobians are positive
+  m->setAllVolumesPositive();
+
   double t2 = Cpu();
   CTX::instance()->meshTimer[2] = t2 - t1;
   Msg::StatusBar(true, "Done meshing 3D (%g s)", CTX::instance()->meshTimer[2]);
@@ -683,6 +557,9 @@ void OptimizeMeshNetgen(GModel *m)
 
   std::for_each(m->firstRegion(), m->lastRegion(), optimizeMeshGRegionNetgen());
 
+  // Ensure that all volume Jacobians are positive
+  m->setAllVolumesPositive();
+
   double t2 = Cpu();
   Msg::StatusBar(true, "Done optimizing 3D mesh with Netgen (%g s)", t2 - t1);
 }
@@ -694,6 +571,9 @@ void OptimizeMesh(GModel *m)
 
   std::for_each(m->firstRegion(), m->lastRegion(), optimizeMeshGRegionGmsh());
 
+  // Ensure that all volume Jacobians are positive
+  m->setAllVolumesPositive();
+
   double t2 = Cpu();
   Msg::StatusBar(true, "Done optimizing 3D mesh (%g s)", t2 - t1);
 }
@@ -782,8 +662,6 @@ void GenerateMesh(GModel *m, int ask)
     }
   }
 
-  m->setAllVolumesPositive();
-
   // Subdivide into quads or hexas
   if(m->getMeshStatus() == 2 && CTX::instance()->mesh.algoSubdivide == 1)
     RefineMesh(m, CTX::instance()->mesh.secondOrderLinear, true);
@@ -802,7 +680,7 @@ void GenerateMesh(GModel *m, int ask)
   if(CTX::instance()->mesh.hoOptimize){
 #if defined(HAVE_OPTHOM)
     if(CTX::instance()->mesh.hoOptimize < 0){
-      ElasticAnalogy(GModel::current(), CTX::instance()->mesh.hoThresholdMin, false);
+      ElasticAnalogy(GModel::current(), false);
     }
     else{
       OptHomParameters p;
diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp
index d6cf536..2a5a988 100644
--- a/Mesh/HighOrder.cpp
+++ b/Mesh/HighOrder.cpp
@@ -22,6 +22,9 @@
 #include "fullMatrix.h"
 #include "BasisFactory.h"
 
+
+// --------- Functions that help optimizing placement of points on geometry -----------
+
 // The aim here is to build a polynomial representation that consist
 // in polynomial segments of equal length
 
@@ -119,269 +122,221 @@ static bool computeEquidistantParameters(GFace *gf, double u0, double uN,
   return true;
 }
 
-static void getEdgeVertices(GEdge *ge, MElement *ele, std::vector<MVertex*> &ve,
-                            edgeContainer &edgeVertices, bool linear,
-                            int nPts = 1)
+
+// --------- Creation of high-order edge vertices -----------
+
+static bool getEdgeVerticesonGeo(GEdge *ge, MVertex *v0, MVertex *v1, std::vector<MVertex*> &ve, int nPts = 1)
 {
-  if(ge->geomType() == GEntity::DiscreteCurve ||
-     ge->geomType() == GEntity::BoundaryLayerCurve)
-    linear = true;
+    double u0 = 0., u1 = 0., US[100];
+    bool reparamOK = reparamMeshVertexOnEdge(v0, ge, u0);
+    if(ge->periodic(0) && ge->getEndVertex()->getNumMeshVertices() > 0 &&
+       v1 == ge->getEndVertex()->mesh_vertices[0])
+      u1 = ge->parBounds(0).high();
+    else
+      reparamOK &= reparamMeshVertexOnEdge(v1, ge, u1);
 
-  for(int i = 0; i < ele->getNumEdges(); i++){
-    MEdge edge = ele->getEdge(i);
-    std::pair<MVertex*, MVertex*> p(edge.getMinVertex(), edge.getMaxVertex());
-    if(edgeVertices.count(p)){
-      if(edge.getVertex(0) == edge.getMinVertex())
-        ve.insert(ve.end(), edgeVertices[p].begin(), edgeVertices[p].end());
-      else
-        ve.insert(ve.end(), edgeVertices[p].rbegin(), edgeVertices[p].rend());
+    if(reparamOK){
+      double relax = 1.;
+      while (1){
+        if(computeEquidistantParameters(ge, std::min(u0,u1), std::max(u0,u1),
+                                        nPts + 2, US, relax))
+          break;
+
+        relax /= 2.0;
+        if(relax < 1.e-2) break;
+      }
+      if(relax < 1.e-2){
+        Msg::Warning
+          ("Failed to compute equidistant parameters (relax = %g, value = %g) "
+           "for edge %d-%d parametrized with %g %g on GEdge %d",
+           relax, US[1], v0->getNum(), v1->getNum(),u0,u1,ge->tag());
+        reparamOK = false;
+      }
     }
-    else{
-      MVertex *v0 = edge.getVertex(0), *v1 = edge.getVertex(1);
-      std::vector<MVertex*> temp;
-      double u0 = 0., u1 = 0., US[100];
-      bool reparamOK = true;
-      if(!linear) {
-        reparamOK &= reparamMeshVertexOnEdge(v0, ge, u0);
-        if(ge->periodic(0) && ge->getEndVertex()->getNumMeshVertices() > 0 &&
-           v1 == ge->getEndVertex()->mesh_vertices[0])
-          u1 = ge->parBounds(0).high();
-        else
-          reparamOK &= reparamMeshVertexOnEdge(v1, ge, u1);
-        if(reparamOK){
-          double relax = 1.;
-          while (1){
-            if(computeEquidistantParameters(ge, std::min(u0,u1), std::max(u0,u1),
-                                            nPts + 2, US, relax))
-              break;
-
-            relax /= 2.0;
-            if(relax < 1.e-2)
-              break;
-          }
-          if(relax < 1.e-2){
-            Msg::Warning
-              ("Failed to compute equidistant parameters (relax = %g, value = %g) "
-               "for edge %d-%d parametrized with %g %g on GEdge %d linear %d",
-               relax, US[1], v0->getNum(), v1->getNum(),u0,u1,ge->tag(), linear);
-            reparamOK = false;
+    else
+      Msg::Error("Cannot reparam a mesh Vertex in high order meshing");
+    if (!reparamOK) return false;
+
+    for(int j = 0; j < nPts; j++) {
+      MVertex *v;
+      int count = u0<u1? j + 1 : nPts + 1  - (j + 1);
+      GPoint pc = ge->point(US[count]);
+      v = new MEdgeVertex(pc.x(), pc.y(), pc.z(), ge,US[count]);
+      // this destroys the ordering of the mesh vertices on the edge
+      ve.push_back(v);
+    }
+
+    return true;
+}
+
+static bool getEdgeVerticesonGeo(GFace *gf, MVertex *v0, MVertex *v1, std::vector<MVertex*> &ve, int nPts = 1)
+{
+      SPoint2 p0, p1;
+      double US[100], VS[100];
+      bool reparamOK = reparamMeshEdgeOnFace(v0, v1, gf, p0, p1);
+      if(reparamOK) {
+        if (nPts >= 30)
+          computeEquidistantParameters(gf, p0[0], p1[0], p0[1], p1[1], nPts + 2, US, VS);
+        else {
+          US[0]      =  p0[0];
+          VS[0]      =  p0[1];
+          US[nPts+1] =  p1[0];
+          VS[nPts+1] =  p1[1];
+          for(int j = 0; j < nPts; j++){
+            const double t = (double)(j + 1) / (nPts + 1);
+            SPoint3 pc(t*v1->x()+(1.-t)*v0->x(),
+                       t*v1->y()+(1.-t)*v0->y(),
+                       t*v1->z()+(1.-t)*v0->z());
+            SPoint2 guess = p0 * (1.-t) + p1 * t;
+            GPoint gp = gf->closestPoint(pc, guess);
+            if(gp.succeeded()){
+              US[j+1] = gp.u();
+              VS[j+1] = gp.v();
+            }
+            else{
+              US[j+1] = guess.x();
+              VS[j+1] = guess.y();
+            }
           }
         }
-        else{
-          Msg::Error("Cannot reparam a mesh Vertex in high order meshing");
-        }
       }
+      else
+        Msg::Error("Cannot reparam a mesh Vertex in high order meshing");
+      if (!reparamOK) return false;
+
       for(int j = 0; j < nPts; j++){
-        const double t = (double)(j + 1)/(nPts + 1);
-        double uc = (1. - t) * u0 + t * u1; // can be wrong, that's ok
-        MVertex *v;
-        if(linear || !reparamOK || uc < std::min(u0,u1) || uc > std::max(u0,u1)){
-          if (!linear)
-            Msg::Warning("We don't have a valid parameter on curve %d-%d",
-                         v0->getNum(), v1->getNum());
-          // we don't have a (valid) parameter on the curve
-          SPoint3 pc = edge.interpolate(t);
-          v = new MVertex(pc.x(), pc.y(), pc.z(), ge);
-        }
-        else {
-          int count = u0<u1? j + 1 : nPts + 1  - (j + 1);
-          GPoint pc = ge->point(US[count]);
-          v = new MEdgeVertex(pc.x(), pc.y(), pc.z(), ge,US[count]);
-        }
-        temp.push_back(v);
-        // this destroys the ordering of the mesh vertices on the edge
-        ge->mesh_vertices.push_back(v);
+        GPoint pc = gf->point(US[j + 1], VS[j + 1]);
+        MVertex *v = new MFaceVertex(pc.x(), pc.y(), pc.z(), gf, US[j + 1], VS[j + 1]);
         ve.push_back(v);
       }
 
-      if(edge.getVertex(0) == edge.getMinVertex())
-        edgeVertices[p].insert(edgeVertices[p].end(), temp.begin(), temp.end());
-      else
-        edgeVertices[p].insert(edgeVertices[p].end(), temp.rbegin(), temp.rend());
-    }
+      return true;
+}
+
+static void interpVerticesInExistingEdge(GEntity *ge, const MElement *edgeEl,
+                                         std::vector<MVertex*> &veEdge, int nPts)
+{
+  fullMatrix<double> points;
+  points = edgeEl->getFunctionSpace(nPts+1)->points;
+  for(int k = 2; k < nPts+2; k++) {
+    SPoint3 pos;
+    edgeEl->pnt(points(k, 0), 0., 0., pos);
+    MVertex* v = new MVertex(pos.x(), pos.y(), pos.z(), ge);
+    veEdge.push_back(v);
+  }
+}
+
+inline static bool getMinMaxVert(MVertex *v0, MVertex *v1, MVertex *&vMin, MVertex *&vMax)
+{
+  const bool increasing = (v0->getNum() < v1->getNum());
+  if (increasing) {
+    vMin = v0; vMax = v1;
   }
+  else {
+    vMin = v1; vMax = v0;
+  }
+  return increasing;
 }
 
+// Get new interior vertices for a 1D element
+static void getEdgeVertices(GEdge *ge, MElement *ele, std::vector<MVertex*> &ve,
+                            std::vector<MVertex*> &newHOVert, edgeContainer &edgeVertices,
+                            bool linear, int nPts = 1)
+{
+  if(ge->geomType() == GEntity::DiscreteCurve ||
+     ge->geomType() == GEntity::BoundaryLayerCurve)
+    linear = true;
+
+  std::vector<MVertex*> veOld;
+  ele->getVertices(veOld);
+  MVertex *vMin, *vMax;
+  const bool increasing = getMinMaxVert(veOld[0], veOld[1], vMin, vMax);
+  std::pair<MVertex*, MVertex*> p(vMin, vMax);
+  std::vector<MVertex*> veEdge;
+  bool gotVertOnGeo = linear ? false :
+                      getEdgeVerticesonGeo(ge, veOld[0], veOld[1], veEdge, nPts);       // Get vertices on geometry if asked
+  if (!gotVertOnGeo)                                                                    // If not on geometry, create from mesh interpolation
+    interpVerticesInExistingEdge(ge, ele, veEdge, nPts);
+  newHOVert.insert(newHOVert.end(), veEdge.begin(), veEdge.end());
+  if(increasing)                                          // Add newly created vertices to list
+    edgeVertices[p].insert(edgeVertices[p].end(), veEdge.begin(), veEdge.end());
+  else
+    edgeVertices[p].insert(edgeVertices[p].end(), veEdge.rbegin(), veEdge.rend());
+  ve.insert(ve.end(), veEdge.begin(), veEdge.end());
+}
+
+// Get new interior vertices for an edge in a 2D element
 static void getEdgeVertices(GFace *gf, MElement *ele, std::vector<MVertex*> &ve,
-                            edgeContainer &edgeVertices, bool linear,
-                            int nPts = 1)
+                            std::vector<MVertex*> &newHOVert, edgeContainer &edgeVertices,
+                            bool linear, int nPts = 1)
 {
   if(gf->geomType() == GEntity::DiscreteSurface ||
      gf->geomType() == GEntity::BoundaryLayerSurface)
     linear = true;
 
-  for(int i = 0; i < ele->getNumEdges(); i++){
-    MEdge edge = ele->getEdge(i);
-    std::pair<MVertex*, MVertex*> p(edge.getMinVertex(), edge.getMaxVertex());
-    if(edgeVertices.count(p)){
-      if(edge.getVertex(0) == edge.getMinVertex())
-        ve.insert(ve.end(), edgeVertices[p].begin(), edgeVertices[p].end());
+  for(int i = 0; i < ele->getNumEdges(); i++) {
+    std::vector<MVertex*> veOld;
+    ele->getEdgeVertices(i,veOld);
+    MVertex *vMin, *vMax;
+    const bool increasing = getMinMaxVert(veOld[0], veOld[1], vMin, vMax);
+    std::pair<MVertex*, MVertex*> p(vMin, vMax);
+    std::vector<MVertex*> veEdge;
+    if(edgeVertices.count(p)) {                                                             // Vertices already exist
+      if(increasing)
+        veEdge.assign(edgeVertices[p].begin(), edgeVertices[p].end());
       else
-        ve.insert(ve.end(), edgeVertices[p].rbegin(), edgeVertices[p].rend());
+        veEdge.assign(edgeVertices[p].rbegin(), edgeVertices[p].rend());
     }
-    else{
-      MVertex *v0 = edge.getVertex(0), *v1 = edge.getVertex(1);
-      SPoint2 p0, p1;
-      double US[100], VS[100];
-      bool reparamOK = true;
-      if(!linear){
-        reparamOK = reparamMeshEdgeOnFace(v0, v1, gf, p0, p1);
-        if(reparamOK) {
-	  if (nPts >= 30)computeEquidistantParameters(gf, p0[0], p1[0], p0[1], p1[1], nPts + 2,
-						     US, VS);
-	  else {
-	    US[0]      =  p0[0];
-	    VS[0]      =  p0[1];
-	    US[nPts+1] =  p1[0];
-	    VS[nPts+1] =  p1[1];
-	    for(int j = 0; j < nPts; j++){
-	      const double t = (double)(j + 1) / (nPts + 1);
-	      SPoint3 pc = edge.interpolate(t);
-	      SPoint2 guess = p0 * (1.-t) + p1 * t;
-	      GPoint gp = gf->closestPoint(pc, guess);
-	      if(gp.succeeded()){
-		US[j+1] = gp.u();
-		VS[j+1] = gp.v();
-	      }
-	      else{
-		US[j+1] = guess.x();
-		VS[j+1] = guess.y();
-	      }
-	    }
-	  }
-	}
-      }
-      std::vector<MVertex*> temp;
-      for(int j = 0; j < nPts; j++){
-        const double t = (double)(j + 1) / (nPts + 1);
-        MVertex *v;
-        if(linear || !reparamOK){
-          // we don't have (valid) parameters on the surface
-          SPoint3 pc = edge.interpolate(t);
-          v = new MVertex(pc.x(), pc.y(), pc.z(), gf);
-        }
-        else{
-          GPoint pc = gf->point(US[j + 1], VS[j + 1]);
-          v = new MFaceVertex(pc.x(), pc.y(), pc.z(), gf, US[j + 1], VS[j + 1]);
-        }
-        temp.push_back(v);
-        gf->mesh_vertices.push_back(v);
-        ve.push_back(v);
+    else {                                                                                  // Vertices do not exist, create them
+      bool gotVertOnGeo = linear ? false :
+                          getEdgeVerticesonGeo(gf, veOld[0], veOld[1], veEdge, nPts);       // Get vertices on geometry if asked
+      if (!gotVertOnGeo) {                                                                   // If not on geometry, create from mesh interpolation
+        const MLineN edgeEl(veOld, ele->getPolynomialOrder());
+        interpVerticesInExistingEdge(gf, &edgeEl, veEdge, nPts);
       }
-      if(edge.getVertex(0) == edge.getMinVertex())
-        edgeVertices[p].insert(edgeVertices[p].end(), temp.begin(), temp.end());
+      newHOVert.insert(newHOVert.end(), veEdge.begin(), veEdge.end());
+      if(increasing)                                                                        // Add newly created vertices to list
+        edgeVertices[p].insert(edgeVertices[p].end(), veEdge.begin(), veEdge.end());
       else
-        edgeVertices[p].insert(edgeVertices[p].end(), temp.rbegin(), temp.rend());
+        edgeVertices[p].insert(edgeVertices[p].end(), veEdge.rbegin(), veEdge.rend());
     }
+    ve.insert(ve.end(), veEdge.begin(), veEdge.end());
   }
 }
 
+// Get new interior vertices for an edge in a 3D element
 static void getEdgeVertices(GRegion *gr, MElement *ele, std::vector<MVertex*> &ve,
-                            edgeContainer &edgeVertices, bool linear,
-                            int nPts = 1)
+                            std::vector<MVertex*> &newHOVert, edgeContainer &edgeVertices,
+                            bool linear, int nPts = 1)
 {
-  for(int i = 0; i < ele->getNumEdges(); i++){
-    MEdge edge = ele->getEdge(i);
-    std::pair<MVertex*, MVertex*> p(edge.getMinVertex(), edge.getMaxVertex());
-    if(edgeVertices.count(p)){
-      if(edge.getVertex(0) == edge.getMinVertex())
-        ve.insert(ve.end(), edgeVertices[p].begin(), edgeVertices[p].end());
+  for(int i = 0; i < ele->getNumEdges(); i++) {
+    std::vector<MVertex*> veOld;
+    ele->getEdgeVertices(i,veOld);
+    MVertex *vMin, *vMax;
+    const bool increasing = getMinMaxVert(veOld[0], veOld[1], vMin, vMax);
+    std::pair<MVertex*, MVertex*> p(vMin, vMax);
+    std::vector<MVertex*> veEdge;
+    if(edgeVertices.count(p)) {                                                             // Vertices already exist
+      if(increasing)
+        veEdge.assign(edgeVertices[p].begin(), edgeVertices[p].end());
       else
-        ve.insert(ve.end(), edgeVertices[p].rbegin(), edgeVertices[p].rend());
+        veEdge.assign(edgeVertices[p].rbegin(), edgeVertices[p].rend());
     }
-    else{
-      std::vector<MVertex*> temp;
-      for(int j = 0; j < nPts; j++){
-        double t = (double)(j + 1) / (nPts + 1);
-        SPoint3 pc = edge.interpolate(t);
-        MVertex *v = new MVertex(pc.x(), pc.y(), pc.z(), gr);
-        temp.push_back(v);
-        gr->mesh_vertices.push_back(v);
-        ve.push_back(v);
-      }
-      if(edge.getVertex(0) == edge.getMinVertex())
-        edgeVertices[p].insert(edgeVertices[p].end(), temp.begin(), temp.end());
+    else {                                                                                  // Vertices do not exist, create them
+      const MLineN edgeEl(veOld, ele->getPolynomialOrder());
+      interpVerticesInExistingEdge(gr, &edgeEl, veEdge, nPts);
+      newHOVert.insert(newHOVert.end(), veEdge.begin(), veEdge.end());
+      if(increasing)                                                                        // Add newly created vertices to list
+        edgeVertices[p].insert(edgeVertices[p].end(), veEdge.begin(), veEdge.end());
       else
-        edgeVertices[p].insert(edgeVertices[p].end(), temp.rbegin(), temp.rend());
+        edgeVertices[p].insert(edgeVertices[p].end(), veEdge.rbegin(), veEdge.rend());
     }
+    ve.insert(ve.end(), veEdge.begin(), veEdge.end());
   }
 }
 
-static void getFaceVertices(GFace *gf, MElement *incomplete, MElement *ele,
-                            std::vector<MVertex*> &vf, faceContainer &faceVertices,
-                            bool linear, int nPts = 1)
-{
-  if(gf->geomType() == GEntity::DiscreteSurface ||
-     gf->geomType() == GEntity::BoundaryLayerSurface)
-    linear = true;
 
-  for(int i = 0; i < ele->getNumFaces(); i++){
-    MFace face = ele->getFace(i);
-    faceContainer::iterator fIter = faceVertices.find(face);
-    if(fIter != faceVertices.end()){
-      vf.insert(vf.end(), fIter->second.begin(), fIter->second.end());
-    }
-    else{
-      std::vector<MVertex*> &vtcs = faceVertices[face];
-      SPoint2 pts[1000];
-      bool reparamOK = true;
-      if(!linear){
-        for(int k = 0; k < incomplete->getNumVertices(); k++)
-          reparamOK &= reparamMeshVertexOnFace(incomplete->getVertex(k), gf, pts[k]);
-      }
-      int start = face.getNumVertices() * (nPts + 1);
-      const fullMatrix<double> &points = ele->getFunctionSpace(nPts + 1)->points;
-      for(int k = start; k < points.size1(); k++){
-        MVertex *v;
-        const double t1 = points(k, 0);
-        const double t2 = points(k, 1);
-        if(linear){
-          SPoint3 pc = face.interpolate(t1, t2);
-          v = new MVertex(pc.x(), pc.y(), pc.z(), gf);
-        }
-        else{
-          double X(0), Y(0), Z(0), GUESS[2] = {0, 0};
-          double sf[1256];
-          incomplete->getShapeFunctions(t1, t2, 0, sf);
-          for (int j = 0; j < incomplete->getNumShapeFunctions(); j++){
-            MVertex *vt = incomplete->getShapeFunctionNode(j);
-            X += sf[j] * vt->x();
-            Y += sf[j] * vt->y();
-            Z += sf[j] * vt->z();
-            if (reparamOK){
-              GUESS[0] += sf[j] * pts[j][0];
-              GUESS[1] += sf[j] * pts[j][1];
-            }
-          }
-          if(reparamOK){
-            GPoint gp = gf->point(SPoint2(GUESS[0], GUESS[1]));
-            // closest point is not necessary (slow and for high quality HO
-            // meshes it should be optimized anyway afterwards + closest point
-            // is still buggy (e.g. BFGS for a plane Ruled Surface)
-            // GPoint gp = gf->closestPoint(SPoint3(X, Y, Z), GUESS);
-            if (gp.g()){
-              v = new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v());
-            }
-            else{
-              v = new MVertex(X, Y, Z, gf);
-            }
-          }
-          else{
-            GPoint gp = gf->closestPoint(SPoint3(X, Y, Z), GUESS);
-            if(gp.succeeded())
-              v = new MVertex(gp.x(), gp.y(), gp.z(), gf);
-            else
-              v = new MVertex(X, Y, Z, gf);
-          }
-        }
-        // should be expensive -> induces a new search each time
-        vtcs.push_back(v);
-        gf->mesh_vertices.push_back(v);
-        vf.push_back(v);
-      }
-    }
-  }
-}
+// --------- Creation of high-order face vertices -----------
 
 static void reorientTrianglePoints(std::vector<MVertex*> &vtcs, int orientation,
                                    bool swap)
@@ -486,136 +441,320 @@ static void reorientQuadPoints(std::vector<MVertex*> &vtcs, int orientation,
   }
 }
 
-static int getNewFacePoints(int numPrimaryFacePoints, int nPts, fullMatrix<double> &points)
+static int getNewFacePointsInVolume(MElement *incomplete, int nPts, fullMatrix<double> &points)
 {
-  int start = 0;
 
-  int tag = 0;
-  switch(numPrimaryFacePoints) {
-    case 3:
-      if (nPts < 2) break;
+  int startFace = 0;
 
-      tag = ElementType::getTag(TYPE_TRI, nPts+1);
-      if (!tag) {
-        Msg::Error("getFaceVertices not implemented for order %i", nPts +1);
-        break;
-      }
-      points = BasisFactory::getNodalBasis(tag)->points;
-      start = 3 * (1 + nPts);
+  switch (incomplete->getType()){
+  case TYPE_TET :
+    switch (nPts){
+    case 0:
+    case 1: return -1;
+    case 2: points = BasisFactory::getNodalBasis(MSH_TET_20)->points; break;
+    case 3: points = BasisFactory::getNodalBasis(MSH_TET_35)->points; break;
+    case 4: points = BasisFactory::getNodalBasis(MSH_TET_56)->points; break;
+    case 5: points = BasisFactory::getNodalBasis(MSH_TET_84)->points; break;
+    case 6: points = BasisFactory::getNodalBasis(MSH_TET_120)->points; break;
+    case 7: points = BasisFactory::getNodalBasis(MSH_TET_165)->points; break;
+    case 8: points = BasisFactory::getNodalBasis(MSH_TET_220)->points; break;
+    case 9: points = BasisFactory::getNodalBasis(MSH_TET_286)->points; break;
+    default:
+      Msg::Error("getFaceAndInteriorVertices not implemented for order %i", nPts+1);
       break;
+    }
+    startFace = 4 + nPts*6;
+    break;
+  case TYPE_HEX :
+    switch (nPts){
+    case 0: return -1;
+    case 1: points = BasisFactory::getNodalBasis(MSH_HEX_27)->points; break;
+    case 2: points = BasisFactory::getNodalBasis(MSH_HEX_64)->points; break;
+    case 3: points = BasisFactory::getNodalBasis(MSH_HEX_125)->points; break;
+    case 4: points = BasisFactory::getNodalBasis(MSH_HEX_216)->points; break;
+    case 5: points = BasisFactory::getNodalBasis(MSH_HEX_343)->points; break;
+    case 6: points = BasisFactory::getNodalBasis(MSH_HEX_512)->points; break;
+    case 7: points = BasisFactory::getNodalBasis(MSH_HEX_729)->points; break;
+    case 8: points = BasisFactory::getNodalBasis(MSH_HEX_1000)->points; break;
+    default :
+      Msg::Error("getFaceAndInteriorVertices not implemented for order %i", nPts+1);
+      break;
+    }
+    startFace = 8 + nPts*12 ;
+    break;
+  case TYPE_PRI :
+    switch (nPts){
+    case 0: return -1;
+    case 1: points = BasisFactory::getNodalBasis(MSH_PRI_18)->points; break;
+    case 2: points = BasisFactory::getNodalBasis(MSH_PRI_40)->points; break;
+    case 3: points = BasisFactory::getNodalBasis(MSH_PRI_75)->points; break;
+    case 4: points = BasisFactory::getNodalBasis(MSH_PRI_126)->points; break;
+    case 5: points = BasisFactory::getNodalBasis(MSH_PRI_196)->points; break;
+    case 6: points = BasisFactory::getNodalBasis(MSH_PRI_288)->points; break;
+    case 7: points = BasisFactory::getNodalBasis(MSH_PRI_405)->points; break;
+    case 8: points = BasisFactory::getNodalBasis(MSH_PRI_550)->points; break;
+    default:
+      Msg::Error("getFaceAndInteriorVertices not implemented for order %i", nPts+1);
+      break;
+    }
+    startFace = 6 + nPts*9;
+    break;
+  case TYPE_PYR:
+    switch (nPts){
+    case 0:
+    case 1: return -1;
+    case 2: points = BasisFactory::getNodalBasis(MSH_PYR_30)->points; break;
+    case 3: points = BasisFactory::getNodalBasis(MSH_PYR_55)->points; break;
+    case 4: points = BasisFactory::getNodalBasis(MSH_PYR_91)->points; break;
+    case 5: points = BasisFactory::getNodalBasis(MSH_PYR_140)->points; break;
+    case 6: points = BasisFactory::getNodalBasis(MSH_PYR_204)->points; break;
+    case 7: points = BasisFactory::getNodalBasis(MSH_PYR_285)->points; break;
+    case 8: points = BasisFactory::getNodalBasis(MSH_PYR_385)->points; break;
+    default :
+      Msg::Error("getFaceAndInteriorVertices not implemented for order %i", nPts+1);
+      break;
+    }
+    startFace = 5 + nPts*8;
+    break;
+
+  }
 
-    case 4:
-      if (nPts < 1) break;
+  return startFace;
+}
 
-      tag = ElementType::getTag(TYPE_QUA, nPts+1);
-      if (!tag) {
-        Msg::Error("getFaceVertices not implemented for order %i", nPts +1);
-        break;
+static void getFaceVerticesOnGeo(GFace *gf, MElement *incomplete, const MElement *faceEl,
+                                 std::vector<MVertex*> &vf, int nPts = 1)
+{
+  SPoint2 pts[1000];
+  bool reparamOK = true;
+  for(int k = 0; k < incomplete->getNumVertices(); k++)
+    reparamOK &= reparamMeshVertexOnFace(incomplete->getVertex(k), gf, pts[k]);
+  fullMatrix<double> points;
+  int start = (faceEl->getType() == 3) ? 3 * (1 + nPts) : 4 * (1 + nPts);
+  points = faceEl->getFunctionSpace(nPts+1)->points;
+  for(int k = start; k < points.size1(); k++) {
+    MVertex *v;
+    const double t1 = points(k, 0);
+    const double t2 = points(k, 1);
+    double X(0), Y(0), Z(0), GUESS[2] = {0, 0};
+    double sf[1256];
+    incomplete->getShapeFunctions(t1, t2, 0, sf);
+    for (int j = 0; j < incomplete->getNumShapeFunctions(); j++){
+      MVertex *vt = incomplete->getShapeFunctionNode(j);
+      X += sf[j] * vt->x();
+      Y += sf[j] * vt->y();
+      Z += sf[j] * vt->z();
+      if (reparamOK){
+        GUESS[0] += sf[j] * pts[j][0];
+        GUESS[1] += sf[j] * pts[j][1];
       }
-      points = BasisFactory::getNodalBasis(tag)->points;
-      start = 4 * (1 + nPts);
-      break;
+    }
+    if(reparamOK){
+      GPoint gp = gf->point(SPoint2(GUESS[0], GUESS[1]));
+      // closest point is not necessary (slow and for high quality HO
+      // meshes it should be optimized anyway afterwards + closest point
+      // is still buggy (e.g. BFGS for a plane Ruled Surface)
+      // GPoint gp = gf->closestPoint(SPoint3(X, Y, Z), GUESS);
+      if (gp.g()){
+        v = new MFaceVertex(gp.x(), gp.y(), gp.z(), gf, gp.u(), gp.v());
+      }
+      else{
+        v = new MVertex(X, Y, Z, gf);
+      }
+    }
+    else{
+      GPoint gp = gf->closestPoint(SPoint3(X, Y, Z), GUESS);
+      if(gp.succeeded())
+        v = new MVertex(gp.x(), gp.y(), gp.z(), gf);
+      else
+        v = new MVertex(X, Y, Z, gf);
+    }
+    vf.push_back(v);
+  }
+}
 
-    default:
-      Msg::Error("getFaceVertices not implemented for %d-node faces", numPrimaryFacePoints);
-      break;
+static void interpVerticesInExistingFace(GEntity *ge, const MElement *faceEl,
+                                         std::vector<MVertex*> &veFace, int nPts)
+{
+  fullMatrix<double> points;
+  int start = (faceEl->getType() == 3) ? 3 * (1 + nPts) : 4 * (1 + nPts);
+  points = faceEl->getFunctionSpace(nPts+1)->points;
+  for (int k = start; k < points.size1(); k++) {
+    double t1 = points(k, 0);
+    double t2 = points(k, 1);
+    SPoint3 pos;
+    faceEl->pnt(t1, t2, 0, pos);
+    MVertex* v = new MVertex(pos.x(), pos.y(), pos.z(), ge);
+    veFace.push_back(v);
   }
-  return start;
 }
 
-static void getFaceVertices(GRegion *gr, MElement *ele, std::vector<MVertex*> &vf,
+
+//static void interpVerticesInIncompleteFace(GRegion *gr, const MFace &face, const std::vector<MVertex*> &ve,
+//                                           std::vector<MVertex*> &veFace, int nPts)
+//{
+//  MElement *incomplete;
+//
+//  fullMatrix<double> points;
+//  int start = getNewFacePointsInFace(face.getNumVertices(), nPts, points);
+//  for (int k = start; k < points.size1(); k++) {
+//    double t1 = points(k, 0);
+//    double t2 = points(k, 1);
+//    SPoint3 pos;
+//    incomplete->pnt(t1, t2, 0, pos);
+//    MVertex* v = new MVertex(pos.x(), pos.y(), pos.z(), gr);
+//    veFace.push_back(v);
+//  }
+//  delete incomplete;
+//}
+
+// Get new interior vertices for a 2D element
+static void getFaceVertices(GFace *gf, MElement *incomplete, MElement *ele,
+                            std::vector<MVertex*> &vf, std::vector<MVertex*> &newHOVert,
+                            faceContainer &faceVertices, bool linear, int nPts = 1)
+{
+  if(gf->geomType() == GEntity::DiscreteSurface ||
+     gf->geomType() == GEntity::BoundaryLayerSurface)
+    linear = true;
+
+  MFace face = ele->getFace(0);
+  std::vector<MVertex*> veFace;
+  if (!linear)                                                                      // Get vertices on geometry if asked...
+    getFaceVerticesOnGeo(gf, incomplete, ele, veFace, nPts);
+  else                                                                              // ... otherwise, create from mesh interpolation
+    interpVerticesInExistingFace(gf, ele, veFace, nPts);
+  newHOVert.insert(newHOVert.end(), veFace.begin(), veFace.end());
+  faceVertices[face].insert(faceVertices[face].end(), veFace.begin(), veFace.end());
+  vf.insert(vf.end(), veFace.begin(), veFace.end());
+}
+
+// Get new face (excluding edge) vertices for a face of a 3D element
+static void getFaceVertices(GRegion *gr, MElement *incomplete, MElement *ele,
+                            std::vector<MVertex*> &vf, std::vector<MVertex*> &newHOVert,
                             faceContainer &faceVertices, edgeContainer &edgeVertices,
                             bool linear, int nPts = 1)
 {
-  // FIXME: MFace returned by getFace are of order 1
-  // Thus new face vertices are not positioned according to new edge vertices
-  for(int i = 0; i < ele->getNumFaces(); i++){
+  fullMatrix<double> points;
+  int startFace = incomplete ? getNewFacePointsInVolume(incomplete, nPts, points) : 0;
+  int index = startFace;
+  for(int i = 0; i < ele->getNumFaces(); i++) {
     MFace face = ele->getFace(i);
+    int numVert = (face.getNumVertices() == 3) ? nPts * (nPts-1) / 2 : nPts * nPts;
+    std::vector<MVertex*> veFace;
     faceContainer::iterator fIter = faceVertices.find(face);
-    if(fIter != faceVertices.end()) {
+    if(fIter != faceVertices.end()){                                                      // Vertices already exist
       std::vector<MVertex*> vtcs = fIter->second;
-      if(face.getNumVertices() == 3 && nPts > 1){ // tri face
-        int orientation;
-        bool swap;
-        if (fIter->first.computeCorrespondence(face, orientation, swap))
+      int orientation;
+      bool swap;
+      if (fIter->first.computeCorrespondence(face, orientation, swap)) {                  // Check correspondence and apply permutation if needed
+        if(face.getNumVertices() == 3 && nPts > 1)
           reorientTrianglePoints(vtcs, orientation, swap);
-        else
-          Msg::Error("Error in face lookup for recuperation of high order face nodes");
-      }
-      else if(face.getNumVertices() == 4){ // quad face
-        int orientation;
-        bool swap;
-        if (fIter->first.computeCorrespondence(face, orientation, swap)){
+        else if(face.getNumVertices() == 4)
           reorientQuadPoints(vtcs, orientation, swap, nPts-1);
-        }
-        else
-          Msg::Error("Error in face lookup for recuperation of high order face nodes");
       }
-      vf.insert(vf.end(), vtcs.begin(), vtcs.end());
+      else
+        Msg::Error("Error in face lookup for recuperation of high order face nodes");
+      veFace.assign(vtcs.begin(), vtcs.end());
     }
-    else{
-      std::vector<MVertex*> &vtcs = faceVertices[face];
-      fullMatrix<double> points;
-      int start = getNewFacePoints(face.getNumVertices(), nPts, points);
-      if(face.getNumVertices() == 3 && nPts > 1){ // tri face
-        // construct incomplete element to take into account curved
-        // edges on surface boundaries
-        std::vector<MVertex*> hoEdgeNodes;
-        for (int i = 0; i < 3; i++) {
-          MVertex* v0 = face.getVertex(i);
-          MVertex* v1 = face.getVertex((i + 1) % 3);
-          edgeContainer::iterator eIter = edgeVertices.find
-            (std::pair<MVertex*,MVertex*>(std::min(v0, v1), std::max(v0, v1)));
-          if (eIter == edgeVertices.end())
-            Msg::Error("Could not find ho nodes for an edge");
-          if (v0 == eIter->first.first)
-            hoEdgeNodes.insert(hoEdgeNodes.end(), eIter->second.begin(),
-                               eIter->second.end());
-          else
-            hoEdgeNodes.insert(hoEdgeNodes.end(), eIter->second.rbegin(),
-                               eIter->second.rend());
-        }
-        MTriangleN incomplete(face.getVertex(0), face.getVertex(1),
-                              face.getVertex(2), hoEdgeNodes, nPts + 1);
-        for (int k = start; k < points.size1(); k++) {
-          double t1 = points(k, 0);
-          double t2 = points(k, 1);
-          SPoint3 pos;
-          incomplete.pnt(t1, t2, 0, pos);
-          MVertex* v = new MVertex(pos.x(), pos.y(), pos.z(), gr);
-          vtcs.push_back(v);
-          gr->mesh_vertices.push_back(v);
-          vf.push_back(v);
-        }
+    else {                                                                                // Vertices do not exist, create them by interpolation
+      if (linear) {                                                                       // Interpolate on existing mesh
+        std::vector<MVertex*> vfOld;
+        ele->getFaceVertices(i,vfOld);
+        MElement *faceEl;
+        if (face.getNumVertices() == 3)
+          faceEl = new MTriangleN(vfOld, ele->getPolynomialOrder());
+        else
+          faceEl = new MQuadrangleN(vfOld, ele->getPolynomialOrder());
+        interpVerticesInExistingFace(gr, faceEl, veFace, nPts);
+        delete faceEl;
       }
-      else if(face.getNumVertices() == 4){ // quad face
-        for (int k = start; k < points.size1(); k++) {
-          double t1 = points(k, 0);
-          double t2 = points(k, 1);
-          SPoint3 pc = face.interpolate(t1, t2);
-          MVertex *v = new MVertex(pc.x(), pc.y(), pc.z(), gr);
-          vtcs.push_back(v);
-          gr->mesh_vertices.push_back(v);
-          vf.push_back(v);
+      else {
+        if (incomplete) {                                                                 // Interpolate in incomplete 3D element if given
+          for(int k = index; k < index + numVert; k++){
+            MVertex *v;
+            const double t1 = points(k, 0);
+            const double t2 = points(k, 1);
+            const double t3 = points(k, 2);
+            SPoint3 pos;
+            incomplete->pnt(t1, t2, t3, pos);
+            v = new MVertex(pos.x(), pos.y(), pos.z(), gr);
+            veFace.push_back(v);
+          }
+        }
+        else {                                                                            // TODO: Interpolate in incomplete face constructed on the fly
+//          std::vector<MVertex*> &vtcs = faceVertices[face];
+//          fullMatrix<double> points;
+//          int start = getNewFacePointsInFace(face.getNumVertices(), nPts, points);
+//          if(face.getNumVertices() == 3 && nPts > 1){ // tri face
+//            // construct incomplete element to take into account curved
+//            // edges on surface boundaries
+//            std::vector<MVertex*> hoEdgeNodes;
+//            for (int i = 0; i < 3; i++) {
+//              MVertex* v0 = face.getVertex(i);
+//              MVertex* v1 = face.getVertex((i + 1) % 3);
+//              edgeContainer::iterator eIter = edgeVertices.find
+//                (std::pair<MVertex*,MVertex*>(std::min(v0, v1), std::max(v0, v1)));
+//              if (eIter == edgeVertices.end())
+//                Msg::Error("Could not find ho nodes for an edge");
+//              if (v0 == eIter->first.first)
+//                hoEdgeNodes.insert(hoEdgeNodes.end(), eIter->second.begin(),
+//                                   eIter->second.end());
+//              else
+//                hoEdgeNodes.insert(hoEdgeNodes.end(), eIter->second.rbegin(),
+//                                   eIter->second.rend());
+//            }
+//            MTriangleN incomplete(face.getVertex(0), face.getVertex(1),
+//                                  face.getVertex(2), hoEdgeNodes, nPts + 1);
+//            for (int k = start; k < points.size1(); k++) {
+//              double t1 = points(k, 0);
+//              double t2 = points(k, 1);
+//              SPoint3 pos;
+//              incomplete.pnt(t1, t2, 0, pos);
+//              MVertex* v = new MVertex(pos.x(), pos.y(), pos.z(), gr);
+//              veFace.push_back(v);
+//            }
+//          }
+//          else if(face.getNumVertices() == 4){ // quad face
+//            for (int k = start; k < points.size1(); k++) {
+//              double t1 = points(k, 0);
+//              double t2 = points(k, 1);
+//              SPoint3 pc = face.interpolate(t1, t2);
+//              MVertex *v = new MVertex(pc.x(), pc.y(), pc.z(), gr);
+//              veFace.push_back(v);
+//            }
+//          }
+          std::vector<MVertex*> vfOld;
+          ele->getFaceVertices(i,vfOld);
+          MElement *faceEl;
+          if (face.getNumVertices() == 3)
+            faceEl = new MTriangleN(vfOld, nPts+1);
+          else
+            faceEl = new MQuadrangleN(vfOld, nPts+1);
+          interpVerticesInExistingFace(gr, faceEl, veFace, nPts);
+          delete faceEl;
         }
       }
+      newHOVert.insert(newHOVert.end(), veFace.begin(), veFace.end());
+      faceVertices[face].insert(faceVertices[face].end(), veFace.begin(), veFace.end());
     }
+    vf.insert(vf.end(), veFace.begin(), veFace.end());
+    index += numVert;
   }
 }
 
-static void getFaceAndInteriorVertices(GRegion *gr, MElement *incomplete, MElement *ele,
-                                       std::vector<MVertex*> &vr, faceContainer &faceVertices,
-                                       bool linear, int nPts = 1)
+
+// --------- Creation of high-order volume vertices -----------
+
+static int getNewVolumePoints(MElement *incomplete, int nPts, fullMatrix<double> &points)
 {
-  fullMatrix<double> points;
-  int startFace = 0;
+
   int startInter = 0;
 
   switch (incomplete->getType()){
   case TYPE_TET :
     switch (nPts){
-    case 0: return;
-    case 1: return;
+    case 0:
+    case 1: return -1;
     case 2: points = BasisFactory::getNodalBasis(MSH_TET_20)->points; break;
     case 3: points = BasisFactory::getNodalBasis(MSH_TET_35)->points; break;
     case 4: points = BasisFactory::getNodalBasis(MSH_TET_56)->points; break;
@@ -628,12 +767,11 @@ static void getFaceAndInteriorVertices(GRegion *gr, MElement *incomplete, MEleme
       Msg::Error("getFaceAndInteriorVertices not implemented for order %i", nPts+1);
       break;
     }
-    startFace = 4 + nPts*6;
     startInter = ((nPts+2)*(nPts+3)*(nPts+4)-(nPts-2)*(nPts-1)*(nPts))/6;  // = 4+6*(p-1)+4*(p-2)*(p-1)/2 = 4*(p+1)*(p+2)/2-6*(p-1)-2*4 = 2*p*p+2
     break;
   case TYPE_HEX :
     switch (nPts){
-    case 0: return;
+    case 0: return -1;
     case 1: points = BasisFactory::getNodalBasis(MSH_HEX_27)->points; break;
     case 2: points = BasisFactory::getNodalBasis(MSH_HEX_64)->points; break;
     case 3: points = BasisFactory::getNodalBasis(MSH_HEX_125)->points; break;
@@ -646,12 +784,11 @@ static void getFaceAndInteriorVertices(GRegion *gr, MElement *incomplete, MEleme
       Msg::Error("getFaceAndInteriorVertices not implemented for order %i", nPts+1);
       break;
     }
-    startFace = 8 + nPts*12 ;
     startInter = (nPts+2)*(nPts+2)*(nPts+2) - (nPts)*(nPts)*(nPts) ; // = 6*(p-1)*(p-1)+12*(p-1)+8 = 6*(p+1)*(p+1)-12*(p-1)-2*8 = 6*p*p+2
     break;
   case TYPE_PRI :
     switch (nPts){
-    case 0: return;
+    case 0: return -1;
     case 1: points = BasisFactory::getNodalBasis(MSH_PRI_18)->points; break;
     case 2: points = BasisFactory::getNodalBasis(MSH_PRI_40)->points; break;
     case 3: points = BasisFactory::getNodalBasis(MSH_PRI_75)->points; break;
@@ -664,13 +801,12 @@ static void getFaceAndInteriorVertices(GRegion *gr, MElement *incomplete, MEleme
       Msg::Error("getFaceAndInteriorVertices not implemented for order %i", nPts+1);
       break;
     }
-    startFace = 6 + nPts*9;
     startInter = 4*(nPts+1)*(nPts+1)+2;  // = 4*p*p+2 = 6+9*(p-1)+2*(p-2)*(p-1)/2+3*(p-1)*(p-1) = 2*(p+1)*(p+2)/2+3*(p+1)*(p+1)-9*(p-1)-2*6
     break;
   case TYPE_PYR:
     switch (nPts){
     case 0:
-    case 1: return;
+    case 1: return -1;
     case 2: points = BasisFactory::getNodalBasis(MSH_PYR_30)->points; break;
     case 3: points = BasisFactory::getNodalBasis(MSH_PYR_55)->points; break;
     case 4: points = BasisFactory::getNodalBasis(MSH_PYR_91)->points; break;
@@ -682,76 +818,163 @@ static void getFaceAndInteriorVertices(GRegion *gr, MElement *incomplete, MEleme
       Msg::Error("getFaceAndInteriorVertices not implemented for order %i", nPts+1);
       break;
     }
-    startFace = 5 + nPts*8;
     startInter = ( nPts+2) * ( (nPts+2) + 1) * (2*(nPts+2) + 1) / 6  -
       (nPts-1) * ( (nPts-1) + 1) * (2*(nPts-1) + 1) / 6;
     break;
 
   }
 
-  int index = startFace;
-  for(int i = 0; i < ele->getNumFaces(); i++){
-    MFace face = ele->getFace(i);
-    int numVert = (face.getNumVertices() == 3) ? nPts * (nPts-1) / 2 : nPts * nPts;
-    faceContainer::iterator fIter = faceVertices.find(face);
-    if(fIter != faceVertices.end()) {
-      std::vector<MVertex*> vtcs = fIter->second;
-      if(face.getNumVertices() == 3 && nPts > 1){ // tri face
-        int orientation;
-        bool swap;
-        if (fIter->first.computeCorrespondence(face, orientation, swap))
-          reorientTrianglePoints(vtcs, orientation, swap);
-        else
-          Msg::Error("Error in face lookup for recuperation of high order face nodes");
-      }
-      else if(face.getNumVertices() == 4){ // quad face
-        int orientation;
-        bool swap;
-        if (fIter->first.computeCorrespondence(face, orientation, swap)){
-          reorientQuadPoints(vtcs, orientation, swap, nPts-1);
-        }
-        else
-          Msg::Error("Error in face lookup for recuperation of high order face nodes");
-      }
-      vr.insert(vr.end(), vtcs.begin(), vtcs.end());
-    }
-    else {
-      for(int k = index; k < index + numVert; k++){
-        MVertex *v;
-        const double t1 = points(k, 0);
-        const double t2 = points(k, 1);
-        const double t3 = points(k, 2);
-        SPoint3 pos;
-        incomplete->pnt(t1, t2, t3, pos);
-        v = new MVertex(pos.x(), pos.y(), pos.z(), gr);
-        gr->mesh_vertices.push_back(v);
-        vr.push_back(v);
-      }
-    }
-    index += numVert;
-  }
+  return startInter;
+}
 
+// Get new interior vertices for a 3D element (except pyramid)
+static void getVolumeVertices(GRegion *gr, MElement *incomplete, MElement *ele,
+                              std::vector<MVertex*> &vr,  std::vector<MVertex*> &newHOVert,
+                              bool linear, int nPts = 1)
+{
+  fullMatrix<double> points;
+  int startInter = getNewVolumePoints(incomplete, nPts, points);
+  const MElement *interpEl = linear ? ele : incomplete;
   for(int k = startInter; k < points.size1(); k++){
     MVertex *v;
     const double t1 = points(k, 0);
     const double t2 = points(k, 1);
     const double t3 = points(k, 2);
     SPoint3 pos;
-    incomplete->pnt(t1, t2, t3, pos);
+    interpEl->pnt(t1, t2, t3, pos);
     v = new MVertex(pos.x(), pos.y(), pos.z(), gr);
-    gr->mesh_vertices.push_back(v);
+    newHOVert.push_back(v);
     vr.push_back(v);
   }
 }
 
-static void setHighOrder(GEdge *ge, edgeContainer &edgeVertices, bool linear,
-                         int nbPts = 1)
+// Get new interior vertices for a pyramid
+static void getVolumeVerticesPyramid(GRegion *gr, MElement *ele, const std::vector<MVertex*> &ve,
+                                     std::vector<MVertex*> &vr, std::vector<MVertex*> &newHOVert,
+                                     bool linear, int nPts = 1)
+{
+  vr.reserve((nPts-1)*(nPts)*(2*(nPts-1)+1)/6);
+  int verts_lvl3[12] = {37,40,38,43,46,44,49,52,50,55,58,56};
+  int verts_lvl2[8];
+  if (nPts == 4) {
+    verts_lvl2[0] = 42; verts_lvl2[1] = 41;
+    verts_lvl2[2] = 48; verts_lvl2[3] = 47;
+    verts_lvl2[4] = 54; verts_lvl2[5] = 53;
+    verts_lvl2[6] = 60; verts_lvl2[7] = 59;
+  }
+  else {
+    verts_lvl2[0] = 29; verts_lvl2[1] = 30;
+    verts_lvl2[2] = 35; verts_lvl2[3] = 36;
+    verts_lvl2[4] = 38; verts_lvl2[5] = 39;
+    verts_lvl2[6] = 32; verts_lvl2[7] = 33;
+  }
+  int verts_lvl1[4];
+  switch(nPts) {
+  case(4):
+    verts_lvl1[0] = 39;
+    verts_lvl1[1] = 45;
+    verts_lvl1[2] = 51;
+    verts_lvl1[3] = 57;
+    break;
+  case(3):
+    verts_lvl1[0] = 31;
+    verts_lvl1[1] = 37;
+    verts_lvl1[2] = 40;
+    verts_lvl1[3] = 34;
+    break;
+  case(2):
+    verts_lvl1[0] = 21;
+    verts_lvl1[1] = 23;
+    verts_lvl1[2] = 24;
+    verts_lvl1[3] = 22;
+    break;
+  }
+  for (int q = 0; q < nPts - 1; q++) {
+    std::vector<MVertex*> vq, veq;
+    vq.push_back(ve[2*nPts + q]);
+    vq.push_back(ve[4*nPts + q]);
+    vq.push_back(ve[6*nPts + q]);
+    vq.push_back(ve[7*nPts + q]);
+
+    if (nPts-q == 4)
+      for (int f = 0; f < 12; f++)
+        veq.push_back(ve[verts_lvl3[f]-5]);
+    else if (nPts-q == 3)
+      for (int f = 0; f < 8; f++)
+        veq.push_back(ve[verts_lvl2[f]-5]);
+    else if (nPts-q == 2)
+      for (int f = 0; f < 4; f++)
+        veq.push_back(ve[verts_lvl1[f]-5]);
+
+    if (nPts-q == 2) {
+      MQuadrangle8 incpl2(vq[0], vq[1], vq[2], vq[3],
+                          veq[0], veq[1], veq[2], veq[3]);
+      SPoint3 pointz;
+      incpl2.pnt(0,0,0,pointz);
+      MVertex *v = new MVertex(pointz.x(), pointz.y(), pointz.z(), gr);
+      newHOVert.push_back(v);
+      std::vector<MVertex*>::iterator cursor = vr.begin();
+      cursor += nPts == 2 ? 0 : 4;
+      vr.insert(cursor, v);
+    }
+    else if (nPts-q == 3) {
+      MQuadrangleN incpl2(vq[0], vq[1], vq[2], vq[3], veq, 3);
+      int offsets[4] = {nPts == 4 ? 7 : 0,
+                        nPts == 4 ? 9 : 1,
+                        nPts == 4 ? 11 : 2,
+                        nPts == 4 ? 12 : 3};
+      double quad_v [4][2] = {{-1.0/3.0, -1.0/3.0},
+                              { 1.0/3.0, -1.0/3.0},
+                              { 1.0/3.0,  1.0/3.0},
+                              {-1.0/3.0,  1.0/3.0}};
+      SPoint3 pointz;
+      for (int k = 0; k<4; k++) {
+        incpl2.pnt(quad_v[k][0], quad_v[k][1], 0, pointz);
+        MVertex *v = new MVertex(pointz.x(), pointz.y(), pointz.z(), gr);
+        newHOVert.push_back(v);
+        std::vector<MVertex*>::iterator cursor = vr.begin();
+        cursor += offsets[k];
+        vr.insert(cursor, v);
+      }
+    }
+    else if (nPts-q == 4) {
+      MQuadrangleN incpl2(vq[0], vq[1], vq[2], vq[3], veq, 4);
+      int offsets[9] = {0, 1, 2, 3, 5, 8, 10, 6, 13};
+      double quad_v [9][2] = {
+        { -0.5, -0.5},
+        {  0.5, -0.5},
+        {  0.5,  0.5},
+        { -0.5,  0.5},
+        {  0.0, -0.5},
+        {  0.5,  0.0},
+        {  0.0,  0.5},
+        { -0.5,  0.0},
+        {  0.0,  0.0}
+      };
+      SPoint3 pointz;
+      for (int k = 0; k<9; k++) {
+        incpl2.pnt(quad_v[k][0], quad_v[k][1], 0, pointz);
+        MVertex *v = new MVertex(pointz.x(), pointz.y(), pointz.z(), gr);
+        newHOVert.push_back(v);
+        std::vector<MVertex*>::iterator cursor = vr.begin();
+        cursor += offsets[k];
+        vr.insert(cursor, v);
+      }
+    }
+  }
+}
+
+
+// --------- Creation of high-order elements -----------
+
+static void setHighOrder(GEdge *ge, std::vector<MVertex*> &newHOVert,
+                         edgeContainer &edgeVertices, bool linear, int nbPts = 1)
 {
   std::vector<MLine*> lines2;
   for(unsigned int i = 0; i < ge->lines.size(); i++){
     MLine *l = ge->lines[i];
     std::vector<MVertex*> ve;
-    getEdgeVertices(ge, l, ve, edgeVertices, linear, nbPts);
+    getEdgeVertices(ge, l, ve, newHOVert, edgeVertices, linear, nbPts);
     if(nbPts == 1)
       lines2.push_back(new MLine3(l->getVertex(0), l->getVertex(1), ve[0], l->getPartition()));
     else
@@ -762,13 +985,13 @@ static void setHighOrder(GEdge *ge, edgeContainer &edgeVertices, bool linear,
   ge->deleteVertexArrays();
 }
 
-static MTriangle *setHighOrder(MTriangle *t, GFace *gf,
+static MTriangle *setHighOrder(MTriangle *t, GFace *gf, std::vector<MVertex*> &newHOVert,
                                edgeContainer &edgeVertices,
                                faceContainer &faceVertices,
                                bool linear, bool incomplete, int nPts)
 {
   std::vector<MVertex*> ve, vf;
-  getEdgeVertices(gf, t, ve, edgeVertices, linear, nPts);
+  getEdgeVertices(gf, t, ve, newHOVert, edgeVertices, linear, nPts);
   if(nPts == 1){
     return new MTriangle6(t->getVertex(0), t->getVertex(1), t->getVertex(2),
                           ve[0], ve[1], ve[2], 0, t->getPartition());
@@ -777,7 +1000,7 @@ static MTriangle *setHighOrder(MTriangle *t, GFace *gf,
     if(!incomplete){
       MTriangleN incpl(t->getVertex(0), t->getVertex(1), t->getVertex(2),
                        ve, nPts + 1, 0, t->getPartition());
-      getFaceVertices(gf, &incpl, t, vf, faceVertices, linear, nPts);
+      getFaceVertices(gf, &incpl, t, vf, newHOVert, faceVertices, linear, nPts);
       ve.insert(ve.end(), vf.begin(), vf.end());
     }
     return new MTriangleN(t->getVertex(0), t->getVertex(1), t->getVertex(2),
@@ -785,13 +1008,13 @@ static MTriangle *setHighOrder(MTriangle *t, GFace *gf,
   }
 }
 
-static MQuadrangle *setHighOrder(MQuadrangle *q, GFace *gf,
+static MQuadrangle *setHighOrder(MQuadrangle *q, GFace *gf, std::vector<MVertex*> &newHOVert,
                                  edgeContainer &edgeVertices,
                                  faceContainer &faceVertices,
                                  bool linear, bool incomplete, int nPts)
 {
   std::vector<MVertex*> ve, vf;
-  getEdgeVertices(gf, q, ve, edgeVertices, linear, nPts);
+  getEdgeVertices(gf, q, ve, newHOVert, edgeVertices, linear, nPts);
   if(incomplete){
     if(nPts == 1){
       return new MQuadrangle8(q->getVertex(0), q->getVertex(1), q->getVertex(2),
@@ -807,7 +1030,7 @@ static MQuadrangle *setHighOrder(MQuadrangle *q, GFace *gf,
   else {
     MQuadrangleN incpl(q->getVertex(0), q->getVertex(1), q->getVertex(2),
                        q->getVertex(3), ve, nPts + 1, 0, q->getPartition());
-    getFaceVertices(gf, &incpl, q, vf, faceVertices, linear, nPts);
+    getFaceVertices(gf, &incpl, q, vf, newHOVert, faceVertices, linear, nPts);
     ve.insert(ve.end(), vf.begin(), vf.end());
     if(nPts == 1){
       return new MQuadrangle9(q->getVertex(0), q->getVertex(1), q->getVertex(2),
@@ -822,15 +1045,15 @@ static MQuadrangle *setHighOrder(MQuadrangle *q, GFace *gf,
   }
 }
 
-static void setHighOrder(GFace *gf, edgeContainer &edgeVertices,
-                         faceContainer &faceVertices, bool linear, bool incomplete,
-                         int nPts = 1)
+static void setHighOrder(GFace *gf, std::vector<MVertex*> &newHOVert,
+                         edgeContainer &edgeVertices, faceContainer &faceVertices,
+                         bool linear, bool incomplete, int nPts = 1)
 {
   std::vector<MTriangle*> triangles2;
   for(unsigned int i = 0; i < gf->triangles.size(); i++){
     MTriangle *t = gf->triangles[i];
-    MTriangle *tNew = setHighOrder(t, gf, edgeVertices, faceVertices, linear,
-                                   incomplete, nPts);
+    MTriangle *tNew = setHighOrder(t, gf, newHOVert, edgeVertices,
+                                   faceVertices, linear, incomplete, nPts);
     triangles2.push_back(tNew);
     delete t;
   }
@@ -838,8 +1061,8 @@ static void setHighOrder(GFace *gf, edgeContainer &edgeVertices,
   std::vector<MQuadrangle*> quadrangles2;
   for(unsigned int i = 0; i < gf->quadrangles.size(); i++){
     MQuadrangle *q = gf->quadrangles[i];
-    MQuadrangle *qNew = setHighOrder(q, gf, edgeVertices, faceVertices, linear,
-                                     incomplete, nPts);
+    MQuadrangle *qNew = setHighOrder(q, gf, newHOVert, edgeVertices,
+                                     faceVertices, linear, incomplete, nPts);
     quadrangles2.push_back(qNew);
     delete q;
   }
@@ -848,12 +1071,13 @@ static void setHighOrder(GFace *gf, edgeContainer &edgeVertices,
 }
 
 static MTetrahedron *setHighOrder(MTetrahedron *t, GRegion *gr,
+                                  std::vector<MVertex*> &newHOVert,
                                   edgeContainer &edgeVertices,
                                   faceContainer &faceVertices,
                                   bool linear, bool incomplete, int nPts)
 {
   std::vector<MVertex*> ve, vf, vr;
-  getEdgeVertices(gr, t, ve, edgeVertices, linear, nPts);
+  getEdgeVertices(gr, t, ve, newHOVert, edgeVertices, linear, nPts);
   if(nPts == 1){
     return new MTetrahedron10(t->getVertex(0), t->getVertex(1), t->getVertex(2),
                               t->getVertex(3), ve[0], ve[1], ve[2], ve[3], ve[4], ve[5],
@@ -867,8 +1091,10 @@ static MTetrahedron *setHighOrder(MTetrahedron *t, GRegion *gr,
       // it either way)
       MTetrahedronN incpl(t->getVertex(0), t->getVertex(1), t->getVertex(2),
                           t->getVertex(3), ve, nPts + 1, 0, t->getPartition());
-      getFaceAndInteriorVertices(gr, &incpl, t, vf, faceVertices, linear, nPts);
+      getFaceVertices(gr, &incpl, t, vf, newHOVert, faceVertices, edgeVertices, linear, nPts);
       ve.insert(ve.end(), vf.begin(), vf.end());
+      getVolumeVertices(gr, &incpl, t, vr, newHOVert, linear, nPts);
+      ve.insert(ve.end(), vr.begin(), vr.end());
     }
     return new MTetrahedronN(t->getVertex(0), t->getVertex(1),
                              t->getVertex(2), t->getVertex(3), ve, nPts + 1,
@@ -877,12 +1103,13 @@ static MTetrahedron *setHighOrder(MTetrahedron *t, GRegion *gr,
 }
 
 static MHexahedron *setHighOrder(MHexahedron *h, GRegion *gr,
+                                 std::vector<MVertex*> &newHOVert,
                                  edgeContainer &edgeVertices,
                                  faceContainer &faceVertices,
                                  bool linear, bool incomplete, int nPts)
 {
   std::vector<MVertex*> ve, vf, vr;
-  getEdgeVertices(gr, h, ve, edgeVertices, linear, nPts);
+  getEdgeVertices(gr, h, ve, newHOVert, edgeVertices, linear, nPts);
   if(incomplete){
     if(nPts == 1){
       return new MHexahedron20(h->getVertex(0), h->getVertex(1), h->getVertex(2),
@@ -909,12 +1136,13 @@ static MHexahedron *setHighOrder(MHexahedron *h, GRegion *gr,
                           h->getVertex(6), h->getVertex(7), ve[0], ve[1], ve[2],
                           ve[3], ve[4], ve[5], ve[6], ve[7], ve[8], ve[9], ve[10],
                           ve[11], 0, h->getPartition());
-      getFaceAndInteriorVertices(gr, &incpl, h, vf, faceVertices, linear, nPts);
+      getFaceVertices(gr, &incpl, h, vf, newHOVert, faceVertices, edgeVertices, linear, nPts);
+      getVolumeVertices(gr, &incpl, h, vr, newHOVert, linear, nPts);
       return new MHexahedron27(h->getVertex(0), h->getVertex(1), h->getVertex(2),
                                h->getVertex(3), h->getVertex(4), h->getVertex(5),
                                h->getVertex(6), h->getVertex(7), ve[0], ve[1], ve[2],
                                ve[3], ve[4], ve[5], ve[6], ve[7], ve[8], ve[9], ve[10],
-                               ve[11], vf[0], vf[1], vf[2], vf[3], vf[4], vf[5], vf[6],
+                               ve[11], vf[0], vf[1], vf[2], vf[3], vf[4], vf[5], vr[0],
                                0, h->getPartition());
     }
     else {
@@ -922,8 +1150,10 @@ static MHexahedron *setHighOrder(MHexahedron *h, GRegion *gr,
                          h->getVertex(3), h->getVertex(4), h->getVertex(5),
                          h->getVertex(6), h->getVertex(7), ve, nPts + 1, 0,
                          h->getPartition());
-      getFaceAndInteriorVertices(gr, &incpl, h, vf, faceVertices, linear, nPts);
+      getFaceVertices(gr, &incpl, h, vf, newHOVert, faceVertices, edgeVertices, linear, nPts);
       ve.insert(ve.end(), vf.begin(), vf.end());
+      getVolumeVertices(gr, &incpl, h, vr, newHOVert, linear, nPts);
+      ve.insert(ve.end(), vr.begin(), vr.end());
       return new MHexahedronN(h->getVertex(0), h->getVertex(1), h->getVertex(2),
                               h->getVertex(3), h->getVertex(4), h->getVertex(5),
                               h->getVertex(6), h->getVertex(7), ve, nPts + 1,
@@ -933,12 +1163,13 @@ static MHexahedron *setHighOrder(MHexahedron *h, GRegion *gr,
 }
 
 static MPrism *setHighOrder(MPrism *p, GRegion *gr,
+                            std::vector<MVertex*> &newHOVert,
                             edgeContainer &edgeVertices,
                             faceContainer &faceVertices,
                             bool linear, bool incomplete, int nPts)
 {
   std::vector<MVertex*> ve, vf, vr;
-  getEdgeVertices(gr, p, ve, edgeVertices, linear, nPts);
+  getEdgeVertices(gr, p, ve, newHOVert, edgeVertices, linear, nPts);
   if(incomplete){
     if(nPts == 1){
       return new MPrism15(p->getVertex(0), p->getVertex(1), p->getVertex(2),
@@ -960,8 +1191,7 @@ static MPrism *setHighOrder(MPrism *p, GRegion *gr,
     MPrismN incpl(p->getVertex(0), p->getVertex(1), p->getVertex(2),
                   p->getVertex(3), p->getVertex(4), p->getVertex(5),
                   ve, nPts + 1, 0, p->getPartition());
-    getFaceAndInteriorVertices(gr, &incpl, p, vf, faceVertices, linear, nPts);
-
+    getFaceVertices(gr, &incpl, p, vf, newHOVert, faceVertices, edgeVertices, linear, nPts);
     if (nPts == 1) {
       return new MPrism18(p->getVertex(0), p->getVertex(1), p->getVertex(2),
                           p->getVertex(3), p->getVertex(4), p->getVertex(5),
@@ -971,6 +1201,8 @@ static MPrism *setHighOrder(MPrism *p, GRegion *gr,
     }
     else {
       ve.insert(ve.end(), vf.begin(), vf.end());
+      getVolumeVertices(gr, &incpl, p, vr, newHOVert, linear, nPts);
+      ve.insert(ve.end(), vr.begin(), vr.end());
       return new MPrismN(p->getVertex(0), p->getVertex(1), p->getVertex(2),
                          p->getVertex(3), p->getVertex(4), p->getVertex(5),
                          ve, nPts + 1, 0, p->getPartition());
@@ -979,124 +1211,19 @@ static MPrism *setHighOrder(MPrism *p, GRegion *gr,
 }
 
 static MPyramid *setHighOrder(MPyramid *p, GRegion *gr,
+                              std::vector<MVertex*> &newHOVert,
                               edgeContainer &edgeVertices,
                               faceContainer &faceVertices,
                               bool linear, bool incomplete, int nPts)
 {
   std::vector<MVertex*> ve, vf, vr;
-  getEdgeVertices(gr, p, ve, edgeVertices, linear, nPts);
-  getFaceVertices(gr, p, vf, faceVertices, edgeVertices, linear, nPts);
+  getEdgeVertices(gr, p, ve, newHOVert, edgeVertices, linear, nPts);
+//  MPyramidN incpl(p->getVertex(0), p->getVertex(1), p->getVertex(2),
+//                  p->getVertex(3), p->getVertex(4), ve, nPts + 1, 0, p->getPartition());
+//  getFaceVertices(gr, &incpl, p, vf, faceVertices, edgeVertices, linear, nPts);
+  getFaceVertices(gr, 0, p, vf, newHOVert, faceVertices, edgeVertices, linear, nPts);
   ve.insert(ve.end(), vf.begin(), vf.end());
-  vr.reserve((nPts-1)*(nPts)*(2*(nPts-1)+1)/6);
-  int verts_lvl3[12] = {37,40,38,43,46,44,49,52,50,55,58,56};
-  int verts_lvl2[8];
-  if (nPts == 4) {
-    verts_lvl2[0] = 42; verts_lvl2[1] = 41;
-    verts_lvl2[2] = 48; verts_lvl2[3] = 47;
-    verts_lvl2[4] = 54; verts_lvl2[5] = 53;
-    verts_lvl2[6] = 60; verts_lvl2[7] = 59;
-  }
-  else {
-    verts_lvl2[0] = 29; verts_lvl2[1] = 30;
-    verts_lvl2[2] = 35; verts_lvl2[3] = 36;
-    verts_lvl2[4] = 38; verts_lvl2[5] = 39;
-    verts_lvl2[6] = 32; verts_lvl2[7] = 33;
-  }
-  int verts_lvl1[4];
-  switch(nPts) {
-  case(4):
-    verts_lvl1[0] = 39;
-    verts_lvl1[1] = 45;
-    verts_lvl1[2] = 51;
-    verts_lvl1[3] = 57;
-    break;
-  case(3):
-    verts_lvl1[0] = 31;
-    verts_lvl1[1] = 37;
-    verts_lvl1[2] = 40;
-    verts_lvl1[3] = 34;
-    break;
-  case(2):
-    verts_lvl1[0] = 21;
-    verts_lvl1[1] = 23;
-    verts_lvl1[2] = 24;
-    verts_lvl1[3] = 22;
-    break;
-  }
-  for (int q = 0; q < nPts - 1; q++) {
-    std::vector<MVertex*> vq, veq;
-    vq.push_back(ve[2*nPts + q]);
-    vq.push_back(ve[4*nPts + q]);
-    vq.push_back(ve[6*nPts + q]);
-    vq.push_back(ve[7*nPts + q]);
-
-    if (nPts-q == 4)
-      for (int f = 0; f < 12; f++)
-        veq.push_back(ve[verts_lvl3[f]-5]);
-    else if (nPts-q == 3)
-      for (int f = 0; f < 8; f++)
-        veq.push_back(ve[verts_lvl2[f]-5]);
-    else if (nPts-q == 2)
-      for (int f = 0; f < 4; f++)
-        veq.push_back(ve[verts_lvl1[f]-5]);
-
-    if (nPts-q == 2) {
-      MQuadrangle8 incpl2(vq[0], vq[1], vq[2], vq[3],
-                          veq[0], veq[1], veq[2], veq[3]);
-      SPoint3 pointz;
-      incpl2.pnt(0,0,0,pointz);
-      MVertex *v = new MVertex(pointz.x(), pointz.y(), pointz.z(), gr);
-
-      gr->mesh_vertices.push_back(v);
-      std::vector<MVertex*>::iterator cursor = vr.begin();
-      cursor += nPts == 2 ? 0 : 4;
-      vr.insert(cursor, v);
-    }
-    else if (nPts-q == 3) {
-      MQuadrangleN incpl2(vq[0], vq[1], vq[2], vq[3], veq, 3);
-      int offsets[4] = {nPts == 4 ? 7 : 0,
-                        nPts == 4 ? 9 : 1,
-                        nPts == 4 ? 11 : 2,
-                        nPts == 4 ? 12 : 3};
-      double quad_v [4][2] = {{-1.0/3.0, -1.0/3.0},
-                              { 1.0/3.0, -1.0/3.0},
-                              { 1.0/3.0,  1.0/3.0},
-                              {-1.0/3.0,  1.0/3.0}};
-      SPoint3 pointz;
-      for (int k = 0; k<4; k++) {
-        incpl2.pnt(quad_v[k][0], quad_v[k][1], 0, pointz);
-        MVertex *v = new MVertex(pointz.x(), pointz.y(), pointz.z(), gr);
-        gr->mesh_vertices.push_back(v);
-        std::vector<MVertex*>::iterator cursor = vr.begin();
-        cursor += offsets[k];
-        vr.insert(cursor, v);
-      }
-    }
-    else if (nPts-q == 4) {
-      MQuadrangleN incpl2(vq[0], vq[1], vq[2], vq[3], veq, 4);
-      int offsets[9] = {0, 1, 2, 3, 5, 8, 10, 6, 13};
-      double quad_v [9][2] = {
-        { -0.5, -0.5},
-        {  0.5, -0.5},
-        {  0.5,  0.5},
-        { -0.5,  0.5},
-        {  0.0, -0.5},
-        {  0.5,  0.0},
-        {  0.0,  0.5},
-        { -0.5,  0.0},
-        {  0.0,  0.0}
-      };
-      SPoint3 pointz;
-      for (int k = 0; k<9; k++) {
-        incpl2.pnt(quad_v[k][0], quad_v[k][1], 0, pointz);
-        MVertex *v = new MVertex(pointz.x(), pointz.y(), pointz.z(), gr);
-        gr->mesh_vertices.push_back(v);
-        std::vector<MVertex*>::iterator cursor = vr.begin();
-        cursor += offsets[k];
-        vr.insert(cursor, v);
-      }
-    }
-  }
+  getVolumeVerticesPyramid(gr, p, ve, vr, newHOVert, linear, nPts);
   ve.insert(ve.end(), vr.begin(), vr.end());
   return new MPyramidN(p->getVertex(0), p->getVertex(1),
                        p->getVertex(2), p->getVertex(3),
@@ -1104,15 +1231,15 @@ static MPyramid *setHighOrder(MPyramid *p, GRegion *gr,
                        0, p->getPartition());
 }
 
-static void setHighOrder(GRegion *gr, edgeContainer &edgeVertices,
-                         faceContainer &faceVertices, bool linear, bool incomplete,
-                         int nPts = 1)
+static void setHighOrder(GRegion *gr, std::vector<MVertex*> &newHOVert,
+                         edgeContainer &edgeVertices, faceContainer &faceVertices,
+                         bool linear, bool incomplete, int nPts = 1)
 {
   std::vector<MTetrahedron*> tetrahedra2;
   for(unsigned int i = 0; i < gr->tetrahedra.size(); i++){
     MTetrahedron *t = gr->tetrahedra[i];
-    MTetrahedron *tNew = setHighOrder(t, gr, edgeVertices, faceVertices, linear,
-                                      incomplete, nPts);
+    MTetrahedron *tNew = setHighOrder(t, gr, newHOVert, edgeVertices,
+                                      faceVertices, linear, incomplete, nPts);
     tetrahedra2.push_back(tNew);
     delete t;
   }
@@ -1121,8 +1248,8 @@ static void setHighOrder(GRegion *gr, edgeContainer &edgeVertices,
   std::vector<MHexahedron*> hexahedra2;
   for(unsigned int i = 0; i < gr->hexahedra.size(); i++){
     MHexahedron *h = gr->hexahedra[i];
-    MHexahedron *hNew = setHighOrder(h, gr, edgeVertices, faceVertices, linear,
-                                     incomplete, nPts);
+    MHexahedron *hNew = setHighOrder(h, gr, newHOVert, edgeVertices,
+                                     faceVertices, linear, incomplete, nPts);
     hexahedra2.push_back(hNew);
     delete h;
   }
@@ -1131,8 +1258,8 @@ static void setHighOrder(GRegion *gr, edgeContainer &edgeVertices,
   std::vector<MPrism*> prisms2;
   for(unsigned int i = 0; i < gr->prisms.size(); i++){
     MPrism *p = gr->prisms[i];
-    MPrism *pNew = setHighOrder(p, gr, edgeVertices, faceVertices, linear,
-                                incomplete, nPts);
+    MPrism *pNew = setHighOrder(p, gr, newHOVert, edgeVertices,
+                                faceVertices, linear, incomplete, nPts);
     prisms2.push_back(pNew);
     delete p;
   }
@@ -1141,8 +1268,8 @@ static void setHighOrder(GRegion *gr, edgeContainer &edgeVertices,
   std::vector<MPyramid*> pyramids2;
   for(unsigned int i = 0; i < gr->pyramids.size(); i++) {
     MPyramid *p = gr->pyramids[i];
-    MPyramid *pNew = setHighOrder(p, gr, edgeVertices, faceVertices, linear,
-                                  incomplete, nPts);
+    MPyramid *pNew = setHighOrder(p, gr, newHOVert, edgeVertices,
+                                  faceVertices, linear, incomplete, nPts);
     pyramids2.push_back(pNew);
     delete p;
   }
@@ -1151,6 +1278,9 @@ static void setHighOrder(GRegion *gr, edgeContainer &edgeVertices,
   gr->deleteVertexArrays();
 }
 
+
+// --------- High-level functions -----------
+
 template<class T>
 static void setFirstOrder(GEntity *e, std::vector<T*> &elements, bool onlyVisible)
 {
@@ -1169,7 +1299,8 @@ static void setFirstOrder(GEntity *e, std::vector<T*> &elements, bool onlyVisibl
   e->deleteVertexArrays();
 }
 
-static void removeHighOrderVertices(GEntity *e, bool onlyVisible)
+static void updateHighOrderVertices(GEntity *e,
+                                    const std::vector<MVertex*> &newHOVert, bool onlyVisible)
 {
   if (onlyVisible && !e->getVisibility())return;
   std::vector<MVertex*> v1;
@@ -1179,7 +1310,9 @@ static void removeHighOrderVertices(GEntity *e, bool onlyVisible)
     else
       v1.push_back(e->mesh_vertices[i]);
   }
+  v1.insert(v1.end(), newHOVert.begin(), newHOVert.end());
   e->mesh_vertices = v1;
+  e->deleteVertexArrays();
 }
 
 void SetOrder1(GModel *m,  bool onlyVisible)
@@ -1202,12 +1335,13 @@ void SetOrder1(GModel *m,  bool onlyVisible)
   }
 
   // remove all high order vertices
+  std::vector<MVertex*> newHOVert;
   for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); ++it)
-    removeHighOrderVertices(*it, onlyVisible);
+    updateHighOrderVertices(*it, newHOVert, onlyVisible);
   for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it)
-    removeHighOrderVertices(*it, onlyVisible);
+    updateHighOrderVertices(*it, newHOVert, onlyVisible);
   for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it)
-    removeHighOrderVertices(*it, onlyVisible);
+    updateHighOrderVertices(*it, newHOVert, onlyVisible);
 }
 
 void checkHighOrderTriangles(const char* cc, GModel *m,
@@ -1334,12 +1468,12 @@ void SetOrderN(GModel *m, int order, bool linear, bool incomplete, bool onlyVisi
 
   double t1 = Cpu();
 
-  // first, make sure to remove any existsing second order vertices/elements
-  SetOrder1(m, onlyVisible);
+  m->destroyMeshCaches();
 
-  // then create new second order vertices/elements
+  // Keep track of vertex/entities created
   edgeContainer edgeVertices;
   faceContainer faceVertices;
+  std::map<GEntity*,std::vector<MVertex*> > newHOVert;
 
   Msg::ResetProgressMeter();
 
@@ -1349,23 +1483,31 @@ void SetOrderN(GModel *m, int order, bool linear, bool incomplete, bool onlyVisi
     Msg::Info("Meshing curve %d order %d", (*it)->tag(), order);
     Msg::ProgressMeter(++counter, nTot, false, msg);
     if (onlyVisible && !(*it)->getVisibility()) continue;
-    setHighOrder(*it, edgeVertices, linear, nPts);
+    setHighOrder(*it, newHOVert[*it], edgeVertices, linear, nPts);
   }
 
   for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it) {
     Msg::Info("Meshing surface %d order %d", (*it)->tag(), order);
     Msg::ProgressMeter(++counter, nTot, false, msg);
     if (onlyVisible && !(*it)->getVisibility()) continue;
-    setHighOrder(*it, edgeVertices, faceVertices, linear, incomplete, nPts);
+    setHighOrder(*it, newHOVert[*it], edgeVertices, faceVertices, linear, incomplete, nPts);
   }
 
   for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it) {
     Msg::Info("Meshing volume %d order %d", (*it)->tag(), order);
     Msg::ProgressMeter(++counter, nTot, false, msg);
     if (onlyVisible && !(*it)->getVisibility())continue;
-    setHighOrder(*it, edgeVertices, faceVertices, linear, incomplete, nPts);
+    setHighOrder(*it, newHOVert[*it], edgeVertices, faceVertices, linear, incomplete, nPts);
   }
 
+  // Update all high order vertices
+  for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); ++it)
+    updateHighOrderVertices(*it, newHOVert[*it], onlyVisible);
+  for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it)
+    updateHighOrderVertices(*it, newHOVert[*it], onlyVisible);
+  for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it)
+    updateHighOrderVertices(*it, newHOVert[*it], onlyVisible);
+
   double t2 = Cpu();
 
   std::vector<MElement*> bad;
@@ -1377,25 +1519,12 @@ void SetOrderN(GModel *m, int order, bool linear, bool incomplete, bool onlyVisi
   Msg::StatusBar(true, "Done meshing order %d (%g s)", order, t2 - t1);
 }
 
-void computeDistanceFromMeshToGeometry (GModel *m, distanceFromMeshToGeometry_t &dist)
-{
-  for (GModel::eiter itEdge = m->firstEdge(); itEdge != m->lastEdge(); ++itEdge) {
-    double d2,dmax;
-    (*itEdge)->computeDistanceFromMeshToGeometry(d2, dmax);
-    dist.d2[*itEdge] = d2;
-    dist.d_max[*itEdge] = dmax;
-  }
-
-  for (GModel::fiter itFace = m->firstFace(); itFace != m->lastFace(); ++itFace) {
-
-  }
-}
-
 void SetHighOrderComplete(GModel *m, bool onlyVisible)
 {
   faceContainer faceVertices;
   for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it) {
     if (onlyVisible && !(*it)->getVisibility()) continue;
+    std::vector<MVertex*> dumNewHOVert;
     std::vector<MTriangle*> newT;
     std::vector<MQuadrangle*> newQ;
     for (unsigned int i = 0; i < (*it)->triangles.size(); i++){
@@ -1403,7 +1532,7 @@ void SetHighOrderComplete(GModel *m, bool onlyVisible)
       std::vector<MVertex*> vf, vt;
       int nPts = t->getPolynomialOrder() - 1;
       MTriangle TEMP (t->getVertex(0), t->getVertex(1), t->getVertex(2), 0, t->getPartition());
-      getFaceVertices (*it, t, t, vf, faceVertices, false, nPts);
+      getFaceVertices (*it, t, t, vf, dumNewHOVert, faceVertices, false, nPts);
       for (int j=3;j<t->getNumVertices();j++)vt.push_back(t->getVertex(j));
       vt.insert(vt.end(), vf.begin(), vf.end());
       MTriangleN *newTr = new MTriangleN(t->getVertex(0), t->getVertex(1), t->getVertex(2),
@@ -1420,7 +1549,7 @@ void SetHighOrderComplete(GModel *m, bool onlyVisible)
       int nPts = t->getPolynomialOrder() - 1;
       MQuadrangle TEMP (t->getVertex(0), t->getVertex(1), t->getVertex(2),
                         t->getVertex(3), 0, t->getPartition());
-      getFaceVertices (*it, t, &TEMP, vf, faceVertices, false, nPts);
+      getFaceVertices (*it, t, &TEMP, vf, dumNewHOVert, faceVertices, false, nPts);
       for (int j=4;j<t->getNumVertices();j++)vt.push_back(t->getVertex(j));
       vt.insert(vt.end(), vf.begin(), vf.end());
       newQ.push_back(new MQuadrangleN(t->getVertex(0), t->getVertex(1),
diff --git a/Mesh/HighOrder.h b/Mesh/HighOrder.h
index 7164d06..5d2ccea 100644
--- a/Mesh/HighOrder.h
+++ b/Mesh/HighOrder.h
@@ -31,11 +31,6 @@ void checkHighOrderTriangles(const char* cc, GModel *m,
 void checkHighOrderTetrahedron(const char* cc, GModel *m,
                                std::vector<MElement*> &bad, double &minJGlob);
 
-struct distanceFromMeshToGeometry_t {
-  std::map<GEntity*, double> d_max, d2;
-};
-
-void computeDistanceFromMeshToGeometry (GModel *m, distanceFromMeshToGeometry_t &dist);
 void getMeshInfoForHighOrder(GModel *gm, int &meshOrder, bool &complete, bool &CAD);
 
 #endif
diff --git a/Mesh/QuadTriExtruded2D.cpp b/Mesh/QuadTriExtruded2D.cpp
index 1924aa6..0af4758 100644
--- a/Mesh/QuadTriExtruded2D.cpp
+++ b/Mesh/QuadTriExtruded2D.cpp
@@ -61,7 +61,7 @@ int IsValidQuadToTriLateral(GFace *face, int *tri_quad_flag, bool *detectQuadToT
 
   ExtrudeParams *ep = face->meshAttributes.extrude;
 
-  if( !ep || !ep->mesh.ExtrudeMesh || !ep->geo.Mode == EXTRUDED_ENTITY ){
+  if( !ep || !ep->mesh.ExtrudeMesh || !(ep->geo.Mode == EXTRUDED_ENTITY) ){
     Msg::Error("In IsValidQuadToTriLateral(), face %d is not a structured extrusion.",
                face->tag() );
     return 0;
@@ -213,7 +213,7 @@ int IsValidQuadToTriLateral(GFace *face, int *tri_quad_flag, bool *detectQuadToT
 // there are QuadToTri conflicts, return 0.
 // if the surface turns out to be the source of a toroidal loop extrusion (which will then
 // NOT have geo.Mode == COPIED_ENTITY), return 2 (this will require special meshing considerations).
-// Note that RemoveDuplicateSurfaces() makes this DIFFICULT. 
+// Note that RemoveDuplicateSurfaces() makes this DIFFICULT.
 // Also, the type of QuadToTri interface is placed into the
 // pointer argument quadToTri. .
 // Added 2010-12-09.
@@ -223,12 +223,12 @@ int IsValidQuadToTriTop(GFace *face, int *quadToTri, bool *detectQuadToTriTop)
   (*detectQuadToTriTop) = false;
 
   int is_toroidal_quadtri = 0;
-  
+
   GModel *model = face->model();
 
   // First thing is first: determine if this is a toroidal quadtri extrusion.  if so, can skip the  rest
-  
-  
+
+
   // It seems the member pointers to neighboring regions for extruded top faces are not set.
   // For now, have to loop through
   // ALL the regions to see if the presently considered face belongs to the region.
@@ -236,12 +236,12 @@ int IsValidQuadToTriTop(GFace *face, int *quadToTri, bool *detectQuadToTriTop)
   // whether the face is a top face of the region (including whether the region is even extruded).
   // After that information is determined, function can test for QuadToTri neighbor conflicts.
 
-  
 
-  
+
+
   // first determine if this is toroidal quadtotri
   is_toroidal_quadtri = IsInToroidalQuadToTri(face);
-  
+
   if( is_toroidal_quadtri )
     (*detectQuadToTriTop) = true;
   else{
@@ -289,9 +289,9 @@ int IsValidQuadToTriTop(GFace *face, int *quadToTri, bool *detectQuadToTriTop)
 	if( region->meshAttributes.extrude->mesh.QuadToTri )
 	  (*detectQuadToTriTop) = true;
       }
-	      
+
     }
- 
+
     // MAIN test of whether this is even a quadToTri extrusion lateral
     // the only return 0 path that is NOT an error
     if( !(*detectQuadToTriTop) )
@@ -346,7 +346,7 @@ int IsValidQuadToTriTop(GFace *face, int *quadToTri, bool *detectQuadToTriTop)
 
   }  // end of else that executes if NOT toroidal extrusion
 
-  
+
   // this is technically redundant...but if changes are made, it's good to keep this here at the end for safety
   if( !(*detectQuadToTriTop) )
     return 0;
@@ -357,7 +357,7 @@ int IsValidQuadToTriTop(GFace *face, int *quadToTri, bool *detectQuadToTriTop)
   { return 2;} // for toroidal extrusion
   else
     return 3;
-    
+
 }
 
 
@@ -474,13 +474,13 @@ int MeshQuadToTriTopSurface( GFace *from, GFace *to, std::set<MVertex*,
 		"extrude information for top face %d.", to->tag() );
     return 0;
   }
-  
+
   // is this a quadtri extrusion with added vertices?
   bool is_addverts = false;
   if( ep && (ep->mesh.QuadToTri == QUADTRI_ADDVERTS_1 || ep->mesh.QuadToTri == QUADTRI_ADDVERTS_1_RECOMB) )
     is_addverts = true;
 
-  // execute this section if 
+  // execute this section if
   // IF this is a 'no new vertices' quadToTri, mesh the surfaces according to this modified
   // least point value method: if a 3 boundary point quad, draw diagonals from middle corner toward
   // interior.  If a a 2- or 1- point boundary quad, draw toward lowest pointer number NOT on boundary.
diff --git a/Mesh/cross3D.h b/Mesh/cross3D.h
index a553159..d270090 100644
--- a/Mesh/cross3D.h
+++ b/Mesh/cross3D.h
@@ -285,8 +285,9 @@ Qtn cross3D::rotationToOnSurf(const cross3D &y) const{
 
   Qtn R1 = Qtn(axis, th1);
   xx.rotate(R1);
-  if(fabs(angle(xx.getFrst(), yy.getFrst())) > 1e-8){
-    std::cout << "This should not happen: not aligned "<< std::endl; 
+  double temp = fabs(angle(xx.getFrst(), yy.getFrst()));
+  if( (temp > 1e-8) && (temp < M_PI - 1e-8)){
+    std::cout << "This should not happen: not aligned= " << temp << std::endl; 
     exit(1);
   }
   
diff --git a/Mesh/directions3D.cpp b/Mesh/directions3D.cpp
index 67103d8..dcc1b3f 100644
--- a/Mesh/directions3D.cpp
+++ b/Mesh/directions3D.cpp
@@ -455,7 +455,7 @@ int Frame_field::findAnnIndex(SPoint3 p){
 }
 
 void Frame_field::initFace(GFace* gf){
-  // align crosses of gf with the normal (average on neighbour elements)
+  // align crosses of "gf" with the normal (average on neighbour elements)
   // at all vertices of the GFace gf
   build_vertex_to_elements(gf);
   for(std::map<MVertex*, std::set<MElement*> >::const_iterator it
@@ -489,7 +489,7 @@ void Frame_field::initFace(GFace* gf){
 
   std::cout << "Nodes in face = " << vertex_to_elements.size() << std::endl;
 
-  // compute cumulative cross-data vertices x elements for the whole contour of gf
+  // compute cumulative cross-data "vertices x elements" for the whole contour of gf
   std::list<GEdge*> edges = gf->edges();
   vertex_to_elements.clear();
   //Replace edges by their compounds
@@ -768,6 +768,8 @@ void Frame_field::save(const std::vector<std::pair<SPoint3, STensor3> > data,
   file.close();
 }
 
+// BARYCENTRIC End
+
 void Frame_field::recur_connect_vert(FILE *fi, int count,
 				     MVertex *v,
 				     STensor3 &cross,
@@ -1629,8 +1631,8 @@ void Nearest_point::clear(){
   field.clear();
   vicinity.clear();
 #if defined(HAVE_ANN)
-  delete kd_tree->thePoints();
-  delete kd_tree;
+   delete kd_tree->thePoints();
+   delete kd_tree;
   annClose();
 #endif
 }
diff --git a/Mesh/filterElements.cpp b/Mesh/filterElements.cpp
index 43c5234..fa25fc7 100644
--- a/Mesh/filterElements.cpp
+++ b/Mesh/filterElements.cpp
@@ -150,7 +150,7 @@ void filterColumns(std::vector<MElement*> &elem,
       //      delete c[i];
     }
   }
-  printf("%d --> %d\n",elem.size(),toKeep.size());
+  printf("%d --> %d\n", (int)elem.size(), (int)toKeep.size());
   elem = toKeep;
 }
 
diff --git a/Mesh/meshGEdge.cpp b/Mesh/meshGEdge.cpp
index 2ef1464..163daeb 100644
--- a/Mesh/meshGEdge.cpp
+++ b/Mesh/meshGEdge.cpp
@@ -317,6 +317,12 @@ static void printFandPrimitive(int tag, std::vector<IntPoint> &Points)
 }
 */
 
+// new algo for recombining + splitting
+static int increaseN (int N){
+  if (((N+1)/2 - 1) % 2 != 0) return N+2;
+  return N;
+}
+
 void meshGEdge::operator() (GEdge *ge)
 {
 #if defined(HAVE_ANN)
@@ -417,15 +423,19 @@ void meshGEdge::operator() (GEdge *ge)
   // force odd number of points if blossom is used for recombination
   if((ge->meshAttributes.method != MESH_TRANSFINITE ||
       CTX::instance()->mesh.flexibleTransfinite) &&
-     CTX::instance()->mesh.algoRecombine == 1 && N % 2 == 0){
+     CTX::instance()->mesh.algoRecombine != 0){
     if(CTX::instance()->mesh.recombineAll){
-      N++;
+      if (N % 2 == 0) N++;
+      if (CTX::instance()->mesh.algoRecombine == 2)
+	N = increaseN(N);
     }
     else{
       std::list<GFace*> faces = ge->faces();
       for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){
         if((*it)->meshAttributes.recombine){
-          N++;
+	  if (N % 2 == 0) N ++;
+	  if (CTX::instance()->mesh.algoRecombine == 2)
+	    N = increaseN(N);
           break;
         }
       }
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index 64c9792..ab3ef3a 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -46,6 +46,29 @@
 #include "boundaryLayersData.h"
 #include "filterElements.h"
 
+// define this to use the old initial delaunay
+#define OLD_CODE_DELAUNAY 1
+
+static void computeElementShapes(GFace *gf, double &worst, double &avg,
+                                 double &best, int &nT, int &greaterThan)
+{
+  worst = 1.e22;
+  avg = 0.0;
+  best = 0.0;
+  nT = 0;
+  greaterThan = 0;
+  for(unsigned int i = 0; i < gf->triangles.size(); i++){
+    double q = qmTriangle(gf->triangles[i], QMTRI_RHO);
+    if(q > .9) greaterThan++;
+    avg += q;
+    worst = std::min(worst, q);
+    best  = std::max(best, q);
+    nT++;
+  }
+  avg /= nT;
+}
+
+
 inline double myAngle(const SVector3 &a, const SVector3 &b, const SVector3 &d)
 {
   double cosTheta = dot(a, b);
@@ -53,6 +76,148 @@ inline double myAngle(const SVector3 &a, const SVector3 &b, const SVector3 &d)
   return atan2(sinTheta, cosTheta);
 }
 
+class quadMeshRemoveHalfOfOneDMesh
+{
+  GFace *_gf;
+public:
+  std::map<GEdge*,std::vector<MLine*> > _backup;
+  std::map<MEdge, MVertex*,Less_Edge> _middle;
+  // remove one point every two and remember middle points
+  quadMeshRemoveHalfOfOneDMesh (GFace* gf) : _gf(gf){
+    // only do it if a recombination has to be done
+    if((CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine) && CTX::instance()->mesh.algoRecombine == 2){
+      //      printf("GFace %d removing half of the points in the 1D mesh\n",gf->tag());
+      std::list<GEdge*> edges = gf->edges();
+      std::list<GEdge*>::iterator ite = edges.begin();
+      while(ite != edges.end()){
+	if(!(*ite)->isMeshDegenerated()){
+	  std::vector<MLine*> temp;
+	  (*ite)->mesh_vertices.clear();
+	  for(unsigned int i = 0; i< (*ite)->lines.size(); i+=2){
+	    if (i+1 >= (*ite)->lines.size())Msg::Fatal("1D mesh cannot be divided by 2");
+	    MVertex *v1 = (*ite)->lines[i]->getVertex(0);
+	    MVertex *v2 = (*ite)->lines[i]->getVertex(1);
+	    MVertex *v3 = (*ite)->lines[i+1]->getVertex(1);
+	    temp.push_back(new MLine(v1,v3));
+	    if (v1->onWhat() == *ite) (*ite)->mesh_vertices.push_back(v1);
+	    _middle[MEdge(v1,v3)] = v2;
+	  }
+	  _backup[*ite] = (*ite)->lines;
+	  //	  printf("line %d goes from %d to %d\n",(*ite)->tag(), (*ite)->lines.size()-1,temp.size()-1);
+	  (*ite)->lines = temp;
+	}
+	++ite;
+      }
+    }
+    backgroundMesh::setSizeFactor(2.0);
+  }
+  void subdivide (){
+    std::vector<MQuadrangle*> qnew;
+
+    std::map<MEdge,MVertex*,Less_Edge> eds;
+
+    for(unsigned int i=0;i<_gf->triangles.size();i++){
+      MVertex *v[3];
+      SPoint2 m[3];
+      for (int j=0;j<3;j++){
+	MEdge E = _gf->triangles[i]->getEdge(j);
+	SPoint2 p1, p2;
+	reparamMeshEdgeOnFace(E.getVertex(0),E.getVertex(1),_gf,p1,p2);
+	std::map<MEdge, MVertex *, Less_Edge>::iterator it = _middle.find(E);
+	std::map<MEdge, MVertex *, Less_Edge>::iterator it2 = eds.find(E);
+	m[j] = p1;
+	if (it == _middle.end() && it2 == eds.end()){
+	  GPoint gp = _gf->point((p1+p2)*0.5);
+	  v[j] = new MFaceVertex (gp.x(),gp.y(),gp.z(),_gf,gp.u(),gp.v());
+	  _gf->mesh_vertices.push_back(v[j]);
+	  eds[E] = v[j];
+	}
+	else if (it == _middle.end()){
+	  v[j] = it2->second;
+	}
+	else {
+	  v[j] = it->second;
+	  v[j]->onWhat()->mesh_vertices.push_back(v[j]);
+	}
+      }
+      GPoint gp    = _gf->point((m[0]+m[1]+m[2])*(1./3.));
+      MFaceVertex *vmid = new MFaceVertex (gp.x(),gp.y(),gp.z(),_gf,gp.u(),gp.v());
+      _gf->mesh_vertices.push_back(vmid);
+      qnew.push_back(new MQuadrangle(_gf->triangles[i]->getVertex(0),v[0],vmid,v[2]));
+      qnew.push_back(new MQuadrangle(_gf->triangles[i]->getVertex(1),v[1],vmid,v[0]));
+      qnew.push_back(new MQuadrangle(_gf->triangles[i]->getVertex(2),v[2],vmid,v[1]));
+      delete _gf->triangles[i];
+    }
+    _gf->triangles.clear();
+    for(unsigned int i=0;i<_gf->quadrangles.size();i++){
+      MVertex *v[4];
+      SPoint2 m[4];
+      for (int j=0;j<4;j++){
+	MEdge E = _gf->quadrangles[i]->getEdge(j);
+	SPoint2 p1, p2;
+	reparamMeshEdgeOnFace(E.getVertex(0),E.getVertex(1),_gf,p1,p2);
+	std::map<MEdge, MVertex *>::iterator it = _middle.find(E);
+	std::map<MEdge, MVertex *, Less_Edge>::iterator it2 = eds.find(E);
+	m[j] = p1;
+	if (it == _middle.end() && it2 == eds.end()){
+	  GPoint gp = _gf->point((p1+p2)*0.5);
+	  v[j] = new MFaceVertex (gp.x(),gp.y(),gp.z(),_gf,gp.u(),gp.v());
+	  _gf->mesh_vertices.push_back(v[j]);
+	  eds[E] = v[j];
+	}
+	else if (it == _middle.end()){
+	  v[j] = it2->second;
+	}
+	else {
+	  v[j] = it->second;
+	  v[j]->onWhat()->mesh_vertices.push_back(v[j]);
+	}
+      }
+      GPoint gp    = _gf->point((m[0]+m[1]+m[2]+m[3])*0.25);
+      MVertex *vmid = new MFaceVertex (gp.x(),gp.y(),gp.z(),_gf,gp.u(),gp.v());
+      _gf->mesh_vertices.push_back(vmid);
+      qnew.push_back(new MQuadrangle(_gf->quadrangles[i]->getVertex(0),v[0],vmid,v[3]));
+      qnew.push_back(new MQuadrangle(_gf->quadrangles[i]->getVertex(1),v[1],vmid,v[0]));
+      qnew.push_back(new MQuadrangle(_gf->quadrangles[i]->getVertex(2),v[2],vmid,v[1]));
+      qnew.push_back(new MQuadrangle(_gf->quadrangles[i]->getVertex(3),v[3],vmid,v[2]));
+      delete _gf->quadrangles[i];
+    }
+    _gf->quadrangles = qnew;
+    //    printf("%d triangles %d quads\n",_gf->triangles.size(),_gf->quadrangles.size());
+  }
+  void finish (){
+    backgroundMesh::setSizeFactor(1.0);
+    if((CTX::instance()->mesh.recombineAll || _gf->meshAttributes.recombine) && CTX::instance()->mesh.algoRecombine == 2){
+      // recombine the elements on the half mesh
+      recombineIntoQuads(_gf,true,true,.1);
+      Msg::Info("subdividing");
+      //      _gf->model()->writeMSH("hop1.msh");
+      subdivide();
+      //      _gf->model()->writeMSH("hop2.msh");
+      restore();
+      recombineIntoQuads(_gf,true,true,0.1);
+      computeElementShapes(_gf,
+			   _gf->meshStatistics.worst_element_shape,
+			   _gf->meshStatistics.average_element_shape,
+			   _gf->meshStatistics.best_element_shape,
+			   _gf->meshStatistics.nbTriangle,
+			   _gf->meshStatistics.nbGoodQuality);
+    }
+  }
+  void restore (){
+    std::list<GEdge*> edges = _gf->edges();
+    std::list<GEdge*>::iterator ite = edges.begin();
+    while(ite != edges.end()){
+      for(unsigned int i = 0; i< (*ite)->lines.size(); i++){
+	delete (*ite)->lines[i];
+      }
+      (*ite)->lines = _backup[*ite];
+      ++ite;
+    }
+  }
+};
+
+
 struct myPlane {
   SPoint3 p;
   SVector3 n;
@@ -464,25 +629,6 @@ static bool algoDelaunay2D(GFace *gf)
   return false;
 }
 
-static void computeElementShapes(GFace *gf, double &worst, double &avg,
-                                 double &best, int &nT, int &greaterThan)
-{
-  worst = 1.e22;
-  avg = 0.0;
-  best = 0.0;
-  nT = 0;
-  greaterThan = 0;
-  for(unsigned int i = 0; i < gf->triangles.size(); i++){
-    double q = qmTriangle(gf->triangles[i], QMTRI_RHO);
-    if(q > .9) greaterThan++;
-    avg += q;
-    worst = std::min(worst, q);
-    best  = std::max(best, q);
-    nT++;
-  }
-  avg /= nT;
-}
-
 static bool recoverEdge(BDS_Mesh *m, GEdge *ge,
                         std::map<MVertex*, BDS_Point*> &recoverMapInv,
                         std::set<EdgeToRecover> *e2r,
@@ -543,7 +689,8 @@ static bool recoverEdge(BDS_Mesh *m, GEdge *ge,
   return true;
 }
 
-void BDS2GMSH(BDS_Mesh *m, GFace *gf, std::map<BDS_Point*, MVertex*, PointLessThan> &recoverMap)
+void BDS2GMSH(BDS_Mesh *m, GFace *gf,
+              std::map<BDS_Point*, MVertex*, PointLessThan> &recoverMap)
 {
   {
     std::set<BDS_Point*,PointLessThan>::iterator itp = m->points.begin();
@@ -585,7 +732,6 @@ void BDS2GMSH(BDS_Mesh *m, GFace *gf, std::map<BDS_Point*, MVertex*, PointLessTh
   }
 }
 
-
 static void addOrRemove(MVertex *v1, MVertex *v2, std::set<MEdge,Less_Edge> & bedges)
 {
   MEdge e(v1,v2);
@@ -640,7 +786,6 @@ static void modifyInitialMeshForTakingIntoAccountBoundaryLayers(GFace *gf)
 	  if (dv2.length() < 0.03 * dv.length())break;
 	  MQuadrangle *qq = new MQuadrangle(v11,v21,v22,v12);
 	  myCol.push_back(qq);
-	  qq->setPartition(l);
 	  blQuads.push_back(qq);
 	  fprintf(ff2,"SQ (%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){1,1,1,1};\n",
 		  v11->x(),v11->y(),v11->z(),
@@ -681,7 +826,6 @@ static void modifyInitialMeshForTakingIntoAccountBoundaryLayers(GFace *gf)
 	if (v11 != v12){
 	  MQuadrangle *qq = new MQuadrangle(v11,v12,v22,v21);
 	  myCol.push_back(qq);
-	  qq->setPartition(l);
 	  blQuads.push_back(qq);
 	  fprintf(ff2,"SQ (%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g,%g){1,1,1,1};\n",
 		  v11->x(),v11->y(),v11->z(),
@@ -692,7 +836,6 @@ static void modifyInitialMeshForTakingIntoAccountBoundaryLayers(GFace *gf)
 	else {
 	  MTriangle *qq = new MTriangle(v,v22,v21);
 	  myCol.push_back(qq);
-	  qq->setPartition(l);
 	  blTris.push_back(qq);
 	  fprintf(ff2,"ST (%g,%g,%g,%g,%g,%g,%g,%g,%g){1,1,1,1};\n",
 		  v->x(),v->y(),v->z(),
@@ -708,7 +851,7 @@ static void modifyInitialMeshForTakingIntoAccountBoundaryLayers(GFace *gf)
   fprintf(ff2,"};\n");
   fclose(ff2);
 
-  filterOverlappingElements (blTris,blQuads,_columns->_elemColumns,_columns->_toFirst);
+  //  filterOverlappingElements (blTris,blQuads,_columns->_elemColumns,_columns->_toFirst);
 
   for (unsigned int i = 0; i < blQuads.size();i++){
     addOrRemove(blQuads[i]->getVertex(0),blQuads[i]->getVertex(1),bedges);
@@ -923,6 +1066,7 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
   std::map<MVertex*, BDS_Point*> recoverMapInv;
   std::list<GEdge*> edges = replacement_edges ? *replacement_edges : gf->edges();
   std::list<int> dir = gf->edgeOrientations();
+  std::vector<MEdge> medgesToRecover;
 
   // replace edges by their compounds
   // if necessary split compound and remesh parts
@@ -933,16 +1077,27 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
   }
 
   // build a set with all points of the boundaries
-  std::set<MVertex*> all_vertices;
+  std::set<MVertex*> all_vertices, boundary;
   std::list<GEdge*>::iterator ite = edges.begin();
   while(ite != edges.end()){
     if((*ite)->isSeam(gf)) return false;
     if(!(*ite)->isMeshDegenerated()){
+      for(unsigned int i = 0; i< (*ite)->lines.size(); i++)
+	medgesToRecover.push_back(MEdge((*ite)->lines[i]->getVertex(0),
+				       (*ite)->lines[i]->getVertex(1)));
       for(unsigned int i = 0; i< (*ite)->lines.size(); i++){
 	MVertex *v1 = (*ite)->lines[i]->getVertex(0);
 	MVertex *v2 = (*ite)->lines[i]->getVertex(1);
         all_vertices.insert(v1);
         all_vertices.insert(v2);
+        if(boundary.find(v1) == boundary.end())
+          boundary.insert(v1);
+        else
+          boundary.erase(v1);
+        if(boundary.find(v2) == boundary.end())
+          boundary.insert(v2);
+        else
+          boundary.erase(v2);
       }
     }
     else
@@ -950,9 +1105,18 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
     ++ite;
   }
 
+  if(boundary.size()){
+    Msg::Error("The 1D mesh seems not to be forming a closed loop");
+    gf->meshStatistics.status = GFace::FAILED;
+    return false;
+  }
+
   std::list<GEdge*> emb_edges = gf->embeddedEdges();
   ite = emb_edges.begin();
   while(ite != emb_edges.end()){
+    for(unsigned int i = 0; i< (*ite)->lines.size(); i++)
+      medgesToRecover.push_back(MEdge((*ite)->lines[i]->getVertex(0),
+				     (*ite)->lines[i]->getVertex(1)));
     if(!(*ite)->isMeshDegenerated()){
       all_vertices.insert((*ite)->mesh_vertices.begin(),
                           (*ite)->mesh_vertices.end() );
@@ -980,7 +1144,7 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
 
   if(all_vertices.size() < 3){
     Msg::Warning("Mesh Generation of Model Face %d Skipped: "
-                 "Only %d Mesh Vertices on The Contours",
+                 "Only %d mesh vertices on the contours",
                  gf->tag(), all_vertices.size());
     gf->meshStatistics.status = GFace::DONE;
     return true;
@@ -1022,26 +1186,25 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
     bbox += SPoint3(param[0], param[1], 0);
     count++;
   }
-  all_vertices.clear();
 
   // here check if some boundary layer nodes should be added
 
   bbox.makeCube();
 
-  // compute the bounding box in parametric space
-  SVector3 dd(bbox.max(), bbox.min());
-  double LC2D = norm(dd);
-
   // use a divide & conquer type algorithm to create a triangulation.
   // We add to the triangulation a box with 4 points that encloses the
   // domain.
-  DocRecord doc(points.size() + 4);
+#ifdef OLD_CODE_DELAUNAY
   {
+    // compute the bounding box in parametric space
+    SVector3 dd(bbox.max(), bbox.min());
+    double LC2D = norm(dd);
+    DocRecord doc(points.size() + 4);
     for(unsigned int i = 0; i < points.size(); i++){
       double XX = CTX::instance()->mesh.randFactor * LC2D * (double)rand() /
-        (double)RAND_MAX;
+	(double)RAND_MAX;
       double YY = CTX::instance()->mesh.randFactor * LC2D * (double)rand() /
-        (double)RAND_MAX;
+	(double)RAND_MAX;
       //      printf("%22.15E %22.15E \n",XX,YY);
       doc.points[i].where.h = points[i]->u + XX;
       doc.points[i].where.v = points[i]->v + YY;
@@ -1056,9 +1219,9 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
     // add 4 points than encloses the domain (use negative number to
     // distinguish those fake vertices)
     double bb[4][2] = {{bbox.min().x(), bbox.min().y()},
-                       {bbox.min().x(), bbox.max().y()},
-                       {bbox.max().x(), bbox.min().y()},
-                       {bbox.max().x(), bbox.max().y()}};
+		       {bbox.min().x(), bbox.max().y()},
+		       {bbox.max().x(), bbox.min().y()},
+		       {bbox.max().x(), bbox.max().y()}};
     for(int ip = 0; ip < 4; ip++){
       BDS_Point *pp = m->add_point(-ip - 1, bb[ip][0], bb[ip][1], gf);
       m->add_geom(gf->tag(), 2);
@@ -1073,10 +1236,15 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
     // Use "fast" inhouse recursive algo to generate the triangulation.
     // At this stage the triangulation is not what we need
     //   -) It does not necessary recover the boundaries
-    //   -) It contains triangles outside the domain (the first edge
-    //      loop is the outer one)
+      //   -) It contains triangles outside the domain (the first edge
+      //      loop is the outer one)
     Msg::Debug("Meshing of the convex hull (%d points)", points.size());
-    doc.MakeMeshWithPoints();
+    try{
+      doc.MakeMeshWithPoints();
+    }
+    catch(const char *err){
+      Msg::Error("%s", err);
+    }
     Msg::Debug("Meshing of the convex hull (%d points) done", points.size());
 
     for(int i = 0; i < doc.numTriangles; i++) {
@@ -1085,191 +1253,238 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
       int c = doc.triangles[i].c;
       int n = doc.numPoints;
       if(a < 0 || a >= n || b < 0 || b >= n || c < 0 || c >= n){
-        Msg::Warning("Skipping bad triangle %d", i);
-        continue;
+	Msg::Warning("Skipping bad triangle %d", i);
+	continue;
       }
       BDS_Point *p1 = (BDS_Point*)doc.points[doc.triangles[i].a].data;
       BDS_Point *p2 = (BDS_Point*)doc.points[doc.triangles[i].b].data;
       BDS_Point *p3 = (BDS_Point*)doc.points[doc.triangles[i].c].data;
       m->add_triangle(p1->iD, p2->iD, p3->iD);
     }
+  }
+#else
+  {
+    std::vector<MVertex*> v;
+    std::vector<MTriangle*> result;
+    v.insert(v.end(),all_vertices.begin(),all_vertices.end());
+
+    std::map<MVertex*,SPoint3> pos;
+    for(unsigned int i = 0; i < v.size(); i++) {
+      MVertex *v0 = v[i];
+      BDS_Point *p0  = recoverMapInv[v0];
+      pos[v0] = SPoint3(v0->x(),v0->y(),v0->z());
+      v0->setXYZ(p0->u,p0->v,0.0);
+    }
+    delaunayMeshIn2D(v, result, 0);
+    //    delaunayMeshIn2D(v, result, 0, & medgesToRecover);
 
-    if(debug && RECUR_ITER == 0){
-      char name[245];
-      sprintf(name, "surface%d-initial-real.pos", gf->tag());
-      outputScalarField(m->triangles, name, 0);
-      sprintf(name, "surface%d-initial-param.pos", gf->tag());
-      outputScalarField(m->triangles, name, 1);
-    }
-
-    // Recover the boundary edges and compute characteristic lenghts
-    // using mesh edge spacing. If two of these edges intersect, then
-    // the 1D mesh have to be densified
-    Msg::Debug("Recovering %d model Edges", edges.size());
-    std::set<EdgeToRecover> edgesToRecover;
-    std::set<EdgeToRecover> edgesNotRecovered;
-    ite = edges.begin();
-    while(ite != edges.end()){
-      if(!(*ite)->isMeshDegenerated())
-        recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 1);
-      ++ite;
+    for(unsigned int i = 0; i < v.size()-4; i++) {
+      MVertex *v0 = v[i];
+      SPoint3 pp = pos[v0];
+      v0->setXYZ(pp.x(),pp.y(),pp.z());
     }
-    ite = emb_edges.begin();
-    while(ite != emb_edges.end()){
-      if(!(*ite)->isMeshDegenerated())
-        recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 1);
-      ++ite;
+
+    // add the four corners
+    for(int ip = 0; ip < 4; ip++){
+      MVertex *vv = v[v.size()-ip-1];
+      BDS_Point *pp = m->add_point(-ip - 1, vv->x(),vv->y(), gf);
+      m->add_geom(gf->tag(), 2);
+      recoverMapInv[vv] = pp;
+      BDS_GeomEntity *g = m->get_geom(gf->tag(), 2);
+      pp->g = g;
+    }
+    // add the triangles
+    for(unsigned int i = 0; i < result.size(); i++) {
+      MVertex *v0 = result[i]->getVertex(0);
+      MVertex *v1 = result[i]->getVertex(1);
+      MVertex *v2 = result[i]->getVertex(2);
+      BDS_Point *p0  = recoverMapInv[v0];
+      BDS_Point *p1  = recoverMapInv[v1];
+      BDS_Point *p2  = recoverMapInv[v2];
+      m->add_triangle(p0->iD, p1->iD, p2->iD);
     }
+  }
+#endif
+
+  if(debug && RECUR_ITER == 0){
+    char name[245];
+    sprintf(name, "surface%d-initial-real.pos", gf->tag());
+    outputScalarField(m->triangles, name, 0);
+    sprintf(name, "surface%d-initial-param.pos", gf->tag());
+    outputScalarField(m->triangles, name, 1);
+  }
+
+  // Recover the boundary edges and compute characteristic lenghts
+  // using mesh edge spacing. If two of these edges intersect, then
+  // the 1D mesh have to be densified
+  Msg::Debug("Recovering %d model Edges", edges.size());
+  std::set<EdgeToRecover> edgesToRecover;
+  std::set<EdgeToRecover> edgesNotRecovered;
+  ite = edges.begin();
+  while(ite != edges.end()){
+    if(!(*ite)->isMeshDegenerated())
+      recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 1);
+    ++ite;
+  }
+  ite = emb_edges.begin();
+  while(ite != emb_edges.end()){
+    if(!(*ite)->isMeshDegenerated())
+      recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 1);
+    ++ite;
+  }
 
 
     // effectively recover the medge
-    ite = edges.begin();
-    while(ite != edges.end()){
-      if(!(*ite)->isMeshDegenerated()){
-        if (!recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2)){
-	  delete m;
-	  gf->meshStatistics.status = GFace::FAILED;
-	  return false;
-	}
+  ite = edges.begin();
+  while(ite != edges.end()){
+    if(!(*ite)->isMeshDegenerated()){
+      if (!recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2)){
+	delete m;
+	gf->meshStatistics.status = GFace::FAILED;
+	return false;
       }
-      ++ite;
     }
+    ++ite;
+  }
 
-    Msg::Debug("Recovering %d mesh Edges (%d not recovered)", edgesToRecover.size(),
-               edgesNotRecovered.size());
-
-    if(edgesNotRecovered.size()){
-      std::ostringstream sstream;
-      for(std::set<EdgeToRecover>::iterator itr = edgesNotRecovered.begin();
-          itr != edgesNotRecovered.end(); ++itr)
-        sstream << " " << itr->ge->tag();
-      Msg::Warning(":-( There are %d intersections in the 1D mesh (curves%s)",
-                   edgesNotRecovered.size(), sstream.str().c_str());
-      if (repairSelfIntersecting1dMesh)
-        Msg::Warning("8-| Gmsh splits those edges and tries again");
-
-      if(debug){
-        char name[245];
-        sprintf(name, "surface%d-not_yet_recovered-real-%d.msh", gf->tag(),
-                RECUR_ITER);
-        gf->model()->writeMSH(name);
-      }
+  Msg::Debug("Recovering %d mesh Edges (%d not recovered)", edgesToRecover.size(),
+	     edgesNotRecovered.size());
 
-      std::list<GFace *> facesToRemesh;
-      if(repairSelfIntersecting1dMesh)
-        remeshUnrecoveredEdges(recoverMapInv, edgesNotRecovered, facesToRemesh);
-      else{
-        std::set<EdgeToRecover>::iterator itr = edgesNotRecovered.begin();
-        //int *_error = new int[3 * edgesNotRecovered.size()];
-        int I = 0;
-        for(; itr != edgesNotRecovered.end(); ++itr){
-          int p1 = itr->p1;
-          int p2 = itr->p2;
-          int tag = itr->ge->tag();
-          Msg::Error("Edge not recovered: %d %d %d", p1, p2, tag);
-          //_error[3 * I + 0] = p1;
-          //_error[3 * I + 1] = p2;
-          //_error[3 * I + 2] = tag;
-          I++;
-        }
-        //throw _error;
-      }
+  if(edgesNotRecovered.size()){
+    std::ostringstream sstream;
+    for(std::set<EdgeToRecover>::iterator itr = edgesNotRecovered.begin();
+	itr != edgesNotRecovered.end(); ++itr)
+      sstream << " " << itr->ge->tag();
+    Msg::Warning(":-( There are %d intersections in the 1D mesh (curves%s)",
+		 edgesNotRecovered.size(), sstream.str().c_str());
+    if (repairSelfIntersecting1dMesh)
+      Msg::Warning("8-| Gmsh splits those edges and tries again");
 
-      // delete the mesh
-      delete m;
-      if(RECUR_ITER < 10 && facesToRemesh.size() == 0)
-        return meshGenerator
-          (gf, RECUR_ITER + 1, repairSelfIntersecting1dMesh, onlyInitialMesh,
-           debug, replacement_edges);
-      return false;
+    if(debug){
+      char name[245];
+      sprintf(name, "surface%d-not_yet_recovered-real-%d.msh", gf->tag(),
+	      RECUR_ITER);
+      gf->model()->writeMSH(name);
     }
 
-    if(RECUR_ITER > 0)
-      Msg::Warning(":-) Gmsh was able to recover all edges after %d iterations",
-                   RECUR_ITER);
+    std::list<GFace *> facesToRemesh;
+    if(repairSelfIntersecting1dMesh)
+      remeshUnrecoveredEdges(recoverMapInv, edgesNotRecovered, facesToRemesh);
+    else{
+      std::set<EdgeToRecover>::iterator itr = edgesNotRecovered.begin();
+      //int *_error = new int[3 * edgesNotRecovered.size()];
+      int I = 0;
+      for(; itr != edgesNotRecovered.end(); ++itr){
+	int p1 = itr->p1;
+	int p2 = itr->p2;
+	int tag = itr->ge->tag();
+	Msg::Error("Edge not recovered: %d %d %d", p1, p2, tag);
+	//_error[3 * I + 0] = p1;
+	//_error[3 * I + 1] = p2;
+	//_error[3 * I + 2] = tag;
+	I++;
+      }
+      //throw _error;
+    }
+
+    // delete the mesh
+    delete m;
+    if(RECUR_ITER < 10 && facesToRemesh.size() == 0)
+      return meshGenerator
+	(gf, RECUR_ITER + 1, repairSelfIntersecting1dMesh, onlyInitialMesh,
+	 debug, replacement_edges);
+    return false;
+  }
+
+  if(RECUR_ITER > 0)
+    Msg::Warning(":-) Gmsh was able to recover all edges after %d iterations",
+		 RECUR_ITER);
 
-    Msg::Debug("Boundary Edges recovered for surface %d", gf->tag());
+  Msg::Debug("Boundary Edges recovered for surface %d", gf->tag());
 
-    // look for a triangle that has a negative node and recursively
-    // tag all exterior triangles
-    {
-      std::list<BDS_Face*>::iterator itt = m->triangles.begin();
-      while (itt != m->triangles.end()){
-	(*itt)->g = 0;
-	++itt;
+  // look for a triangle that has a negative node and recursively
+  // tag all exterior triangles
+  {
+    std::list<BDS_Face*>::iterator itt = m->triangles.begin();
+    while (itt != m->triangles.end()){
+      (*itt)->g = 0;
+      ++itt;
+    }
+    itt = m->triangles.begin();
+    while (itt != m->triangles.end()){
+      BDS_Face *t = *itt;
+      BDS_Point *n[4];
+      t->getNodes(n);
+      if (n[0]->iD < 0 || n[1]->iD < 0 ||
+	  n[2]->iD < 0 ) {
+	recur_tag(t, &CLASS_EXTERIOR);
+	break;
       }
-      itt = m->triangles.begin();
-      while (itt != m->triangles.end()){
-        BDS_Face *t = *itt;
-	BDS_Point *n[4];
-	t->getNodes(n);
-	if (n[0]->iD < 0 || n[1]->iD < 0 ||
-	    n[2]->iD < 0 ) {
-	  recur_tag(t, &CLASS_EXTERIOR);
+      ++itt;
+    }
+  }
+
+  // now find an edge that has belongs to one of the exterior
+  // triangles
+  {
+    std::list<BDS_Edge*>::iterator ite = m->edges.begin();
+    while (ite != m->edges.end()){
+      BDS_Edge *e = *ite;
+      if(e->g  && e->numfaces() == 2){
+	if(e->faces(0)->g == &CLASS_EXTERIOR){
+	  recur_tag(e->faces(1), &CLASS_F);
+	  break;
+	}
+	else if(e->faces(1)->g == &CLASS_EXTERIOR){
+	  recur_tag(e->faces(0), &CLASS_F);
 	  break;
 	}
-	++itt;
       }
+      ++ite;
     }
-
-    // now find an edge that has belongs to one of the exterior
-    // triangles
-    {
-      std::list<BDS_Edge*>::iterator ite = m->edges.begin();
-      while (ite != m->edges.end()){
-        BDS_Edge *e = *ite;
-        if(e->g  && e->numfaces() == 2){
-          if(e->faces(0)->g == &CLASS_EXTERIOR){
-            recur_tag(e->faces(1), &CLASS_F);
-            break;
-          }
-          else if(e->faces(1)->g == &CLASS_EXTERIOR){
-            recur_tag(e->faces(0), &CLASS_F);
-            break;
-          }
-        }
-        ++ite;
-      }
-      std::list<BDS_Face*>::iterator itt = m->triangles.begin();
-      while (itt != m->triangles.end()){
-	if ((*itt)->g == &CLASS_EXTERIOR) (*itt)->g = 0;
-	++itt;
-      }
+    std::list<BDS_Face*>::iterator itt = m->triangles.begin();
+    while (itt != m->triangles.end()){
+      if ((*itt)->g == &CLASS_EXTERIOR) (*itt)->g = 0;
+      ++itt;
     }
+  }
 
-    {
-      std::list<BDS_Edge*>::iterator ite = m->edges.begin();
-      while (ite != m->edges.end()){
-        BDS_Edge *e = *ite;
-        if(e->g  && e->numfaces() == 2){
-          BDS_Point *oface[2];
-          e->oppositeof(oface);
-          if(oface[0]->iD < 0){
-            recur_tag(e->faces(1), &CLASS_F);
-            break;
-          }
-          else if(oface[1]->iD < 0){
-            recur_tag(e->faces(0), &CLASS_F);
-            break;
-          }
-        }
-        ++ite;
+  {
+    std::list<BDS_Edge*>::iterator ite = m->edges.begin();
+    while (ite != m->edges.end()){
+      BDS_Edge *e = *ite;
+      if(e->g  && e->numfaces() == 2){
+	BDS_Point *oface[2];
+	e->oppositeof(oface);
+	if(oface[0]->iD < 0){
+	  recur_tag(e->faces(1), &CLASS_F);
+	  break;
+	}
+	else if(oface[1]->iD < 0){
+	  recur_tag(e->faces(0), &CLASS_F);
+	  break;
+	}
       }
-    }
-
-    ite = emb_edges.begin();
-    while(ite != emb_edges.end()){
-      if(!(*ite)->isMeshDegenerated())
-        recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2);
       ++ite;
     }
+  }
+
+  ite = emb_edges.begin();
+  while(ite != emb_edges.end()){
+    if(!(*ite)->isMeshDegenerated())
+      recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2);
+    ++ite;
+  }
 
-    // compute characteristic lengths at vertices
-    if (!onlyInitialMesh){
+  // compute characteristic lengths at vertices
+  if (!onlyInitialMesh){
       Msg::Debug("Computing mesh size field at mesh vertices %d",
 		 edgesToRecover.size());
-      for(int i = 0; i < doc.numPoints; i++){
-	BDS_Point *pp = (BDS_Point*)doc.points[i].data;
+      std::set<BDS_Point*, PointLessThan>::iterator it = m->points.begin();
+      for(; it != m->points.end();++it){
+	//      for(int i = 0; i < doc.numPoints; i++){
+	//	BDS_Point *pp = (BDS_Point*)doc.points[i].data;
+	BDS_Point *pp = *it;
 	std::map<BDS_Point*, MVertex*,PointLessThan>::iterator itv = recoverMap.find(pp);
 	if(itv != recoverMap.end()){
 	  MVertex *here = itv->second;
@@ -1287,7 +1502,6 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
 	  pp->lc() = pp->lcBGM();
 	}
       }
-    }
   }
 
   // delete useless stuff
@@ -1353,42 +1567,35 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
     }
   }
 
-  if (Msg::GetVerbosity() == 10){
-    GEdge *ge = new discreteEdge(gf->model(), 1000, 0, 0);
-    MElementOctree octree(gf->model());
-    Msg::Info("Writing voronoi and skeleton.pos");
-    doc.Voronoi();
-    doc.makePosView("voronoi.pos", gf);
-    doc.printMedialAxis(octree.getInternalOctree(), "skeleton.pos", gf, ge);
-    //todo add corners with lines with closest point
-    ge->addPhysicalEntity(1000);
-    gf->model()->add(ge);
-  }
-
   {
     int nb_swap;
     Msg::Debug("Delaunizing the initial mesh");
     delaunayizeBDS(gf, *m, nb_swap);
   }
-  gf->triangles.clear();
-  gf->quadrangles.clear();
+  //gf->triangles.clear();
+  //gf->quadrangles.clear();
+
+  // only delete the mesh data stored in the base GFace class (calling
+  // gf->deleteMesh() would also destroy e.g. the data in a compound face, which
+  // we should not do)
+  gf->GFace::deleteMesh();
 
   Msg::Debug("Starting to add internal points");
   // start mesh generation
   if(!algoDelaunay2D(gf) && !onlyInitialMesh){
-       // if(CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine || 1) {
-       //   backgroundMesh::unset();
-       //   buildBackGroundMesh (gf);
-       // }
+    // if(CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine || 1) {
+    //   backgroundMesh::unset();
+    //   buildBackGroundMesh (gf);
+    // }
     refineMeshBDS(gf, *m, CTX::instance()->mesh.refineSteps, true,
                   &recoverMapInv);
     optimizeMeshBDS(gf, *m, 2);
     refineMeshBDS(gf, *m, CTX::instance()->mesh.refineSteps, false,
                 &recoverMapInv);
     optimizeMeshBDS(gf, *m, 2);
-       // if(CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine || 1) {
-       //   backgroundMesh::unset();
-       // }
+    // if(CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine || 1) {
+    //   backgroundMesh::unset();
+    // }
   }
 
   /*
@@ -1406,7 +1613,8 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
   BDS2GMSH(m, gf, recoverMap);
 
   bool infty = false;
-  if (gf->getMeshingAlgo() == ALGO_2D_FRONTAL_QUAD || gf->getMeshingAlgo() == ALGO_2D_PACK_PRLGRMS)
+  if (gf->getMeshingAlgo() == ALGO_2D_FRONTAL_QUAD ||
+      gf->getMeshingAlgo() == ALGO_2D_PACK_PRLGRMS)
     infty = true;
   if (!onlyInitialMesh) {
     if (infty)
@@ -1463,7 +1671,7 @@ bool meshGenerator(GFace *gf, int RECUR_ITER,
   delete m;
 
   if((CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine) &&
-     !CTX::instance()->mesh.optimizeLloyd && !onlyInitialMesh)
+     !CTX::instance()->mesh.optimizeLloyd && !onlyInitialMesh && CTX::instance()->mesh.algoRecombine != 2)
     recombineIntoQuads(gf);
 
   computeElementShapes(gf, gf->meshStatistics.worst_element_shape,
@@ -1802,8 +2010,8 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
       }
       if(!ok){
         gf->meshStatistics.status = GFace::FAILED;
-        Msg::Error("The 1D Mesh seems not to be forming a closed loop");
-        m->scalingU = m->scalingV = 1.0;
+        Msg::Error("The 1D mesh seems not to be forming a closed loop");
+        delete m;
         return false;
       }
       nbPointsTotal += nbPointsLocal;
@@ -1816,6 +2024,7 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
                  "Only %d Mesh Vertices on The Contours",
                  gf->tag(), nbPointsTotal);
     gf->meshStatistics.status = GFace::DONE;
+    delete m;
     return true;
   }
   if(nbPointsTotal == 3){
@@ -1827,6 +2036,7 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
     }
     gf->triangles.push_back(new MTriangle(vv[0], vv[1], vv[2]));
     gf->meshStatistics.status = GFace::DONE;
+    delete m;
     return true;
   }
 
@@ -1834,6 +2044,7 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
   // Use a divide & conquer type algorithm to create a triangulation.
   // We add to the triangulation a box with 4 points that encloses the
   // domain.
+#if 1 //OLD_CODE_DELAUNAY
   {
     DocRecord doc(nbPointsTotal + 4);
     int count = 0;
@@ -1884,7 +2095,13 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
     //   -) It contains triangles outside the domain (the first edge
     //      loop is the outer one)
     Msg::Debug("Meshing of the convex hull (%d points)", nbPointsTotal);
-    doc.MakeMeshWithPoints();
+
+    try{
+      doc.MakeMeshWithPoints();
+    }
+    catch(const char *err){
+      Msg::Error("%s", err);
+    }
 
     for(int i = 0; i < doc.numTriangles; i++){
       int a = doc.triangles[i].a;
@@ -1901,6 +2118,66 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
       m->add_triangle(p1->iD, p2->iD, p3->iD);
     }
   }
+#else
+  {
+    /// FIXME FOR PERIODIC : SOME MVERTices SHOULD BE DUPLICATED ...
+    /// Still to be done...
+    printf("coucou1\n");
+    std::vector<MVertex*> v;
+    std::map<MVertex*, BDS_Point*> recoverMapInv;
+    for(unsigned int i = 0; i < edgeLoops_BDS.size(); i++){
+      std::vector<BDS_Point*> &edgeLoop_BDS = edgeLoops_BDS[i];
+      for(unsigned int j = 0; j < edgeLoop_BDS.size(); j++){
+        BDS_Point *pp = edgeLoop_BDS[j];
+	v.push_back(recoverMap[pp]);
+	recoverMapInv[recoverMap[pp]] = pp;
+      }
+    }
+
+    printf("coucou2 %d verices\n",v.size());
+    std::map<MVertex*,SPoint3> pos;
+    for(unsigned int i = 0; i < v.size(); i++) {
+      MVertex *v0 = v[i];
+      BDS_Point *p0  = recoverMapInv[v0];
+      pos[v0] = SPoint3(v0->x(),v0->y(),v0->z());
+      v0->setXYZ(p0->u,p0->v,0.0);
+    }
+    printf("coucou3\n");
+    std::vector<MTriangle*> result;
+    delaunayMeshIn2D(v, result, 0);
+    printf("coucou4\n");
+    //    delaunayMeshIn2D(v, result, 0, & medgesToRecover);
+
+    for(unsigned int i = 0; i < v.size()-4; i++) {
+      MVertex *v0 = v[i];
+      SPoint3 pp = pos[v0];
+      v0->setXYZ(pp.x(),pp.y(),pp.z());
+    }
+    printf("coucou5\n");
+
+    // add the four corners
+    for(int ip = 0; ip < 4; ip++){
+      MVertex *vv = v[v.size()-ip-1];
+      BDS_Point *pp = m->add_point(-ip - 1, vv->x(),vv->y(), gf);
+      m->add_geom(gf->tag(), 2);
+      recoverMapInv[vv] = pp;
+      BDS_GeomEntity *g = m->get_geom(gf->tag(), 2);
+      pp->g = g;
+    }
+    printf("coucou6\n");
+    // add the triangles
+    for(unsigned int i = 0; i < result.size(); i++) {
+      MVertex *v0 = result[i]->getVertex(0);
+      MVertex *v1 = result[i]->getVertex(1);
+      MVertex *v2 = result[i]->getVertex(2);
+      BDS_Point *p0  = recoverMapInv[v0];
+      BDS_Point *p1  = recoverMapInv[v1];
+      BDS_Point *p2  = recoverMapInv[v2];
+      m->add_triangle(p0->iD, p1->iD, p2->iD);
+    }
+    printf("coucou7\n");
+  }
+#endif
 
   // Recover the boundary edges and compute characteristic lenghts
   // using mesh edge spacing
@@ -1927,6 +2204,7 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
         Msg::Error("Impossible to recover the edge %d %d", edgeLoop_BDS[j]->iD,
                    edgeLoop_BDS[(j + 1) % edgeLoop_BDS.size()]->iD);
         gf->meshStatistics.status = GFace::FAILED;
+        delete m;
         return false;
       }
       else e->g = &CLASS_E;
@@ -2179,8 +2457,8 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
   // delete the mesh
   delete m;
 
- if((CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine) &&
-    !CTX::instance()->mesh.optimizeLloyd)
+  if((CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine) &&
+     !CTX::instance()->mesh.optimizeLloyd && CTX::instance()->mesh.algoRecombine != 2)
     recombineIntoQuads(gf);
 
   computeElementShapes(gf, gf->meshStatistics.worst_element_shape,
@@ -2275,6 +2553,8 @@ void meshGFace::operator() (GFace *gf, bool print)
     return;
   }
 
+  quadMeshRemoveHalfOfOneDMesh halfmesh (gf);
+
   if ((gf->getNativeType() != GEntity::AcisModel ||
        (!gf->periodic(0) && !gf->periodic(1))) &&
       (noSeam(gf) || gf->getNativeType() == GEntity::GmshModel ||
@@ -2291,25 +2571,7 @@ void meshGFace::operator() (GFace *gf, bool print)
   Msg::Debug("Type %d %d triangles generated, %d internal vertices",
              gf->geomType(), gf->triangles.size(), gf->mesh_vertices.size());
 
-  // do the 2D mesh in several passes. For second and other passes,
-  // a background mesh is constructed with the previous mesh and
-  // nodal values of the metric are computed that take into account
-  // complex size fields that are tedious to evaluate on the fly
-  if (!twoPassesMesh)return;
-  twoPassesMesh--;
-  if (backgroundMesh::current()){
-    backgroundMesh::unset();
-    //backgroundMesh::set(gf);
-  }
-  if (CTX::instance()->mesh.saveAll){
-    backgroundMesh::set(gf);
-    char name[256];
-    sprintf(name,"bgm-%d.pos",gf->tag());
-    backgroundMesh::current()->print(name,gf);
-    sprintf(name,"cross-%d.pos",gf->tag());
-    backgroundMesh::current()->print(name,gf,1);
-  }
-  (*this)(gf);
+  halfmesh.finish();
 }
 
 bool checkMeshCompound(GFaceCompound *gf, std::list<GEdge*> &edges)
diff --git a/Mesh/meshGFace.h b/Mesh/meshGFace.h
index d1a2c2a..857e24e 100644
--- a/Mesh/meshGFace.h
+++ b/Mesh/meshGFace.h
@@ -21,11 +21,10 @@ class GFaceCompound;
 // Create the mesh of the face
 class meshGFace {
   const bool repairSelfIntersecting1dMesh;
-  int twoPassesMesh;
   bool onlyInitialMesh;
  public :
-  meshGFace(bool r = true, int t = 0)
-    : repairSelfIntersecting1dMesh(r), twoPassesMesh(t), onlyInitialMesh(false)
+  meshGFace(bool r = true)
+    : repairSelfIntersecting1dMesh(r), onlyInitialMesh(false)
   {
   }
   void operator()(GFace *, bool print=true);
diff --git a/Mesh/meshGFaceDelaunayInsertion.cpp b/Mesh/meshGFaceDelaunayInsertion.cpp
index 2b3088c..ed1e61a 100644
--- a/Mesh/meshGFaceDelaunayInsertion.cpp
+++ b/Mesh/meshGFaceDelaunayInsertion.cpp
@@ -24,6 +24,7 @@
 #include "GFaceCompound.h"
 #include "intersectCurveSurface.h"
 #include "surfaceFiller.h"
+#include "HilbertCurve.h"
 
 double LIMIT_ = 0.5 * sqrt(2.0) * 1;
 int  N_GLOBAL_SEARCH;
@@ -44,29 +45,29 @@ static bool isBoundary(MTri3 *t, double limit_, int &active)
 */
 
 template <class ITERATOR>
-void _printTris(char *name, ITERATOR it,  ITERATOR end, bidimMeshData & data, bool param=true)
+void _printTris(char *name, ITERATOR it,  ITERATOR end, bidimMeshData * data)
 {
   FILE *ff = Fopen (name,"w");
   fprintf(ff,"View\"test\"{\n");
   while ( it != end ){
     MTri3 *worst = *it;
     if (!worst->isDeleted()){
-      if (param)
+      if (data)
         fprintf(ff,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
-                data.Us[data.getIndex((worst)->tri()->getVertex(0))],
-                data.Vs[data.getIndex((worst)->tri()->getVertex(0))],
+                data->Us[data->getIndex((worst)->tri()->getVertex(0))],
+                data->Vs[data->getIndex((worst)->tri()->getVertex(0))],
                 0.0,
-                data.Us[data.getIndex((worst)->tri()->getVertex(1))],
-                data.Vs[data.getIndex((worst)->tri()->getVertex(1))],
+                data->Us[data->getIndex((worst)->tri()->getVertex(1))],
+                data->Vs[data->getIndex((worst)->tri()->getVertex(1))],
                 0.0,
-                data.Us[data.getIndex((worst)->tri()->getVertex(2))],
-                data.Vs[data.getIndex((worst)->tri()->getVertex(2))],
+                data->Us[data->getIndex((worst)->tri()->getVertex(2))],
+                data->Vs[data->getIndex((worst)->tri()->getVertex(2))],
                 0.0,
                 (worst)->getRadius(),
                 (worst)->getRadius(),
                 (worst)->getRadius());
       else
-        fprintf(ff,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%g,%g,%g};\n",
+        fprintf(ff,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g) {%d,%d,%d};\n",
                 (worst)->tri()->getVertex(0)->x(),
                 (worst)->tri()->getVertex(0)->y(),
                 (worst)->tri()->getVertex(0)->z(),
@@ -76,9 +77,9 @@ void _printTris(char *name, ITERATOR it,  ITERATOR end, bidimMeshData & data, bo
                 (worst)->tri()->getVertex(2)->x(),
                 (worst)->tri()->getVertex(2)->y(),
                 (worst)->tri()->getVertex(2)->z(),
-                (worst)->getRadius(),
-                (worst)->getRadius(),
-                (worst)->getRadius()
+                (worst)->tri()->getVertex(0)->getNum(),
+                (worst)->tri()->getVertex(1)->getNum(),
+                (worst)->tri()->getVertex(2)->getNum()
                 );
     }
     ++it;
@@ -411,65 +412,47 @@ int inCircumCircle(MTriangle *base,
 }
 
 template <class ITER>
-void connectTris(ITER beg, ITER end)
+void connectTris(ITER beg, ITER end, std::vector<edgeXface> &conn)
 {
-  std::set<edgeXface> conn;
+  conn.clear();
   while (beg != end){
     if (!(*beg)->isDeleted()){
-      for (int i = 0; i < 3; i++){
-        edgeXface fxt(*beg, i);
-	std::set<edgeXface>::iterator found = conn.find(fxt);
-        if (found == conn.end())
-	  conn.insert(fxt);
-        else if (found->t1 != *beg){
-          found->t1->setNeigh(found->i1, *beg);
-          (*beg)->setNeigh(i, found->t1);
-        }
+      for (int j = 0; j < 3; j++){
+	conn.push_back(edgeXface(*beg, j));
       }
     }
     ++beg;
   }
-}
-
-template <class ITER>
-void connectTris_vector(ITER beg, ITER end)
-{
-  std::vector<edgeXface> conn;
-  //  std::set<edgeXface> conn;
-  while (beg != end){
-    if (!(*beg)->isDeleted()){
-      for (int i = 0; i < 3; i++){
-        edgeXface fxt(*beg, i);
-	//        std::set<edgeXface>::iterator found = conn.find(fxt);
-	std::vector<edgeXface>::iterator found  = std::find(conn.begin(), conn.end(), fxt);
-        if (found == conn.end())
-	  conn.push_back(fxt);
-	  //          conn.insert(fxt);
-        else if (found->t1 != *beg){
-          found->t1->setNeigh(found->i1, *beg);
-          (*beg)->setNeigh(i, found->t1);
-        }
-      }
+  if (!conn.size())return;
+  std::sort(conn.begin(), conn.end());
+
+  for (unsigned int i=0;i<conn.size()-1;i++){
+    edgeXface &f1  = conn[i];
+    edgeXface &f2  = conn[i+1];
+    if (f1 == f2 && f1.t1 != f2.t1){
+      f1.t1->setNeigh(f1.i1, f2.t1);
+      f2.t1->setNeigh(f2.i1, f1.t1);
+      ++i;
     }
-    ++beg;
   }
 }
 
-
-
 void connectTriangles(std::list<MTri3*> &l)
 {
-  connectTris(l.begin(), l.end());
+  std::vector<edgeXface> conn;
+  connectTris(l.begin(), l.end(),conn);
 }
 
 void connectTriangles(std::vector<MTri3*> &l)
 {
-  connectTris(l.begin(), l.end());
+  std::vector<edgeXface> conn;
+  connectTris(l.begin(), l.end(),conn);
 }
 
 void connectTriangles(std::set<MTri3*, compareTri3Ptr> &l)
 {
-  connectTris(l.begin(), l.end());
+  std::vector<edgeXface> conn;
+  connectTris(l.begin(), l.end(),conn);
 }
 
 int inCircumCircleTangentPlane(MTriangle *t,
@@ -490,6 +473,20 @@ int inCircumCircleTangentPlane(MTriangle *t,
   return (result > 0) ? 1 : 0;
 }
 
+int inCircumCircleXY(MTriangle *t, MVertex *v)
+{
+  MVertex *v1 = t->getVertex(0);
+  MVertex *v2 = t->getVertex(1);
+  MVertex *v3 = t->getVertex(2);
+  double p1[2] = {v1->x(),v1->y()};
+  double p2[2] = {v2->x(),v2->y()};
+  double p3[2] = {v3->x(),v3->y()};
+  double pp[2] = {v->x(),v->y()};
+  double result = robustPredicates::incircle(p1, p2, p3, pp) *
+    robustPredicates::orient2d(p1, p2, p3);
+  return (result > 0) ? 1 : 0;
+}
+
 
 void recurFindCavityTangentPlane(std::list<edgeXface> &shell,
 				 std::list<MTri3*> &cavity,
@@ -567,6 +564,27 @@ bool findCavityTangentPlane(GFace *gf, double *center,
 }
 
 
+void recurFindCavity(std::vector<edgeXface> &shell, std::vector<MTri3*> &cavity,
+                     MVertex *v, MTri3 *t)
+{
+  t->setDeleted(true);
+  // the cavity that has to be removed because it violates delaunay
+  // criterion
+  cavity.push_back(t);
+
+  for (int i = 0; i < 3; i++){
+    MTri3 *neigh =  t->getNeigh(i) ;
+    if (!neigh)
+      shell.push_back(edgeXface(t, i));
+    else if (!neigh->isDeleted()){
+      int circ =  inCircumCircleXY(neigh->tri(), v);
+      if (circ)
+        recurFindCavity(shell, cavity, v, neigh);
+      else
+        shell.push_back(edgeXface(t, i));
+    }
+  }
+}
 
 void recurFindCavity(std::list<edgeXface> &shell, std::list<MTri3*> &cavity,
                      double *v, double *param, MTri3 *t,  bidimMeshData & data)
@@ -696,6 +714,7 @@ bool insertVertexB (std::list<edgeXface> &shell,
   if (shell.size() != cavity.size() + 2) return false;
 
   std::list<MTri3*> new_cavity;
+  std::vector<edgeXface> conn;
 
   // check that volume is conserved
   double newVolume = 0;
@@ -756,7 +775,7 @@ bool insertVertexB (std::list<edgeXface> &shell,
 
 
   if (fabs(oldVolume - newVolume) < 1.e-12 * oldVolume && !onePointIsTooClose){
-    connectTris_vector(new_cavity.begin(), new_cavity.end());
+    connectTris(new_cavity.begin(), new_cavity.end(),conn);
     //    printf("%d %d\n",shell.size(),cavity.size());
     //    clock_t t1 = clock();
     // 30 % of the time is spent here !!!
@@ -792,7 +811,7 @@ bool insertVertexB (std::list<edgeXface> &shell,
     //    _printTris("new_cavity.pos", new_cavity.begin(), new_cavity.end(), Us, Vs, false);
     //    _printTris("newTris.pos", &newTris[0], newTris+shell.size(), Us, Vs, false);
     //    _printTris("allTris.pos", allTets.begin(),allTets.end(), Us, Vs, false);
-    for (unsigned int i = 0; i < shell.size(); i++) delete newTris[i];
+    for (unsigned int i = 0; i < shell.size(); i++) {delete newTris[i]->tri(), delete newTris[i];}
     delete [] newTris;
     //    throw;
     //    double t2 = Cpu();
@@ -828,6 +847,59 @@ bool insertVertex(bool force, GFace *gf, MVertex *v, double *param , MTri3 *t,
 }
 
 
+bool invMapXY (MTriangle *t, MVertex *v){
+  MVertex *v0 = t->getVertex(0);
+  MVertex *v1 = t->getVertex(1);
+  MVertex *v2 = t->getVertex(2);
+  double mat[2][2],b[2],uv[2],tol=1.e-6;
+  mat[0][0] = v1->x() - v0->x();
+  mat[0][1] = v2->x() - v0->x();
+  mat[1][0] = v1->y() - v0->y();
+  mat[1][1] = v2->y() - v0->y();
+
+  b[0] = v->x() - v0->x();
+  b[1] = v->y() - v0->y();
+  sys2x2(mat, b, uv);
+
+  if(uv[0] >= -tol &&
+     uv[1] >= -tol &&
+     uv[0] <= 1. + tol &&
+     uv[1] <= 1. + tol &&
+     1. - uv[0] - uv[1] > -tol) {
+    return true;
+  }
+  return false;
+
+}
+
+static MTri3* search4Triangle (MTri3 *t, MVertex *v, int maxx, int &ITER) {
+  bool inside =  invMapXY(t->tri(), v);
+  SPoint3 q1 (v->x(),v->y(),0);
+  if (inside) return t;
+  while (1){
+    SPoint3 q2 = t->tri()->barycenter();
+    int i;
+    for (i = 0; i < 3; i++){
+      int i1 = i == 0 ? 2 : i-1;
+      int i2 = i;
+      MVertex *v1 = t->tri()->getVertex(i1);
+      MVertex *v2 = t->tri()->getVertex(i2);
+      SPoint3 p1 (v1->x(),v1->y(),0);
+      SPoint3 p2 (v2->x(),v2->y(),0);
+      double xcc[2];
+      if (intersection_segments(p1, p2, q1, q2, xcc)) break;
+    }
+    if (i >= 3) break;
+    t = t->getNeigh(i);
+    if (!t) break;
+    bool inside =  invMapXY(t->tri(), v);
+    //    printf("ITER %d %d\n",ITER,inside);
+    if (inside) return t;
+    if (ITER++ > .5*maxx) break;
+  }
+  return 0;
+}
+
 static MTri3* search4Triangle (MTri3 *t, double pt[2], bidimMeshData & data,
 			       std::set<MTri3*,compareTri3Ptr> &AllTris, double uv[2], bool force = false) {
 
@@ -1306,9 +1378,9 @@ void bowyerWatsonFrontal(GFace *gf,
     if(ITERATION % 10== 0 && CTX::instance()->mesh.saveAll){
       char name[245];
       sprintf(name,"delFrontal_GFace_%d_Layer_%d.pos",gf->tag(),ITERATION);
-      _printTris (name, AllTris.begin(), AllTris.end(), DATA,true);
+      _printTris (name, AllTris.begin(), AllTris.end(), &DATA);
       sprintf(name,"delFrontal_GFace_%d_Layer_%d_Active.pos",gf->tag(),ITERATION);
-      _printTris (name, ActiveTris.begin(), ActiveTris.end(), DATA,true);
+      _printTris (name, ActiveTris.begin(), ActiveTris.end(), &DATA);
     }
     /* if(ITER % 100== 0){
           char name[245];
@@ -1729,3 +1801,283 @@ void bowyerWatsonParallelograms(GFace *gf,
   }
 #endif
 }
+
+
+static void initialSquare(std::vector<MVertex*> &v,
+			  MVertex *box[4],
+			  std::vector<MTri3*> &t){
+  SBoundingBox3d bbox ;
+  for (size_t i=0;i<v.size();i++){
+    MVertex *pv = v[i];
+    bbox += SPoint3(pv->x(),pv->y(),pv->z());
+  }
+  bbox *= 1.3;
+  box[0] = new MVertex (bbox.min().x(),bbox.min().y(),0);
+  box[1] = new MVertex (bbox.max().x(),bbox.min().y(),0);
+  box[2] = new MVertex (bbox.max().x(),bbox.max().y(),0);
+  box[3] = new MVertex (bbox.min().x(),bbox.max().y(),0);
+  MTriangle *t0 = new MTriangle (box[0],box[1],box[2]);
+  MTriangle *t1 = new MTriangle (box[2],box[3],box[0]);
+  t.push_back(new MTri3(t0,0.0));
+  t.push_back(new MTri3(t1,0.0));
+  connectTriangles(t);
+}
+
+
+MTri3 * getTriToBreak (MVertex *v, std::vector<MTri3*> &t, int &NB_GLOBAL_SEARCH, int &ITER){
+  // last inserted is used as starting point
+  // we know it is not deleted
+  unsigned int k = t.size() - 1;
+  while(t[k]->isDeleted()){
+    k--;
+  }
+  MTri3 *start = t[k];
+  start = search4Triangle (start,v,(int)t.size(),ITER);
+  if (start)return start;
+  //  printf("Global Search has to be done\n");
+  NB_GLOBAL_SEARCH++;
+  for (size_t i = 0;i<t.size();i++){
+    if (!t[i]->isDeleted() && inCircumCircleXY(t[i]->tri(),v))return t[i];
+  }
+  return 0;
+}
+
+bool triOnBox (MTriangle *t, MVertex *box[4]){
+  for (size_t i = 0;i<3;i++){
+    for (size_t j = 0;j<4;j++){
+      if (t->getVertex(i) == box[j])
+	return true;
+    }
+  }
+  return false;
+}
+
+// vertices are supposed to be sitting in the XY plane !
+
+void recoverEdges (std::vector<MTri3*> &t, std::vector<MEdge> &edges);
+
+void delaunayMeshIn2D(std::vector<MVertex*> &v,
+		      std::vector<MTriangle*> &result,
+		      bool removeBox,
+		      std::vector<MEdge> *edgesToRecover,
+                      bool hilbertSort)
+{
+  std::vector<MTri3*> t;
+  t.reserve (v.size()*2);
+  std::vector<edgeXface> conn;
+  std::vector<edgeXface> shell;
+  std::vector<MTri3*> cavity;
+  MVertex *box[4];
+  initialSquare (v,box,t);
+
+  int NB_GLOBAL_SEARCH = 0;
+  double AVG_ITER = 0;
+  double AVG_CAVSIZE = 0;
+
+  double t1 = Cpu();
+
+  //  Msg::Info("Delaunay 2D SORTING");
+  if(hilbertSort) SortHilbert(v);
+
+  double ta=0,tb=0,tc=0,td=0,T;
+  //  Msg::Info("Delaunay 2D INSERTING");
+  for (size_t i=0;i<v.size();i++){
+    MVertex *pv = v[i];
+
+    int NITER = 0;
+    T = Cpu();
+    MTri3 * found = getTriToBreak (pv,t,NB_GLOBAL_SEARCH,NITER);
+    ta += Cpu()-T;
+    AVG_ITER += (double)NITER;
+    if(!found) {
+      Msg::Error("Cannot insert a point in 2D Delaunay");
+      continue;
+    }
+    shell.clear();
+    cavity.clear();
+
+    T = Cpu();
+    recurFindCavity(shell, cavity, pv, found);
+    AVG_CAVSIZE += (double)cavity.size();
+    tb += Cpu()-T;
+    //double V = 0.0;
+    //for (unsigned int k=0;k<cavity.size();k++)V+=fabs(cavity[k]->tri()->getVolume());
+
+    std::vector<MTri3*> extended_cavity;
+    //double Vb = 0.0;
+
+    T = Cpu();
+    for (unsigned int count = 0; count < shell.size(); count++){
+      const edgeXface &fxt = shell[count];
+      MTriangle *tr;
+      MTri3 *t3;
+      MVertex *v0 = fxt.v[0];
+      MVertex *v1 = fxt.v[1];
+      MTri3 *otherSide = fxt.t1->getNeigh(fxt.i1);
+      if (count < cavity.size()){
+	t3 = cavity[count];
+	tr = t3->tri() ;
+	tr->setVertex(0,v0);
+	tr->setVertex(1,v1);
+	tr->setVertex(2,pv);
+      }
+      else{
+	tr = new MTriangle(v0,v1,pv);
+	t3 = new MTri3(tr, 0.0);
+	t.push_back(t3);
+      }
+      //Vb+= fabs(tr->getVolume());
+      extended_cavity.push_back(t3);
+      if (otherSide)
+	extended_cavity.push_back(otherSide);
+    }
+    tc += Cpu()-T;
+    //if (fabs(Vb-V) > 1.e-8 * (Vb+V))printf("%12.5E %12.5E\n",Vb,V);
+
+    for (unsigned int k=0;k<std::min(cavity.size(),shell.size());k++){
+      cavity[k]->setDeleted(false);
+      for (unsigned int l=0;l<3;l++){
+    	cavity[k]->setNeigh(l,0);
+      }
+    }
+    T = Cpu();
+    connectTris(extended_cavity.begin(),extended_cavity.end(),conn);
+    td += Cpu()-T;
+  }
+
+  double t2 = Cpu();
+  Msg::Debug("Delaunay 2D done for %d points : CPU = %g, %d global searches, AVG walk size %g , AVG cavity size %g",
+	    v.size(), t2-t1,NB_GLOBAL_SEARCH,1.+AVG_ITER/v.size(),AVG_CAVSIZE/v.size());
+  //  printf("%g %g %g %g --> %g(%g)\n",ta,tb,tc,td,t2-t1,ta+tb+tc+td);
+
+  if (edgesToRecover)recoverEdges (t,*edgesToRecover);
+
+  //  FILE *f = fopen ("tri.pos","w");
+  //  fprintf(f,"View \"\"{\n");
+  for (size_t i = 0;i<t.size();i++){
+    if (t[i]->isDeleted() || (removeBox && triOnBox (t[i]->tri(),box))) delete t[i]->tri();
+    else {
+      result.push_back(t[i]->tri());
+      //      t[i]->tri()->writePOS (f, false,false,true,false,false,false);
+    }
+    delete t[i];
+  }
+  
+  if (removeBox){for (int i=0;i<4;i++)delete box[i];}
+  else {for (int i=0;i<4;i++)v.push_back(box[i]);}
+
+  //  fprintf(f,"};\n");
+  //  fclose(f);
+}
+
+bool swapedge (MVertex *v1 ,MVertex *v2, MVertex *v3, MVertex *v4, MTri3* t1, int iLocalEdge){
+  MTri3 *t2 = t1->getNeigh(iLocalEdge);
+  if(!t2) return false;
+
+  MTriangle *t1b = new MTriangle(v2, v3, v4);
+  MTriangle *t2b = new MTriangle(v4, v3, v1);
+  double BEFORE = t1->tri()->getVolume()+t2->tri()->getVolume();
+  double AFTER  = t1b->getVolume()+t2b->getVolume();
+  //  printf("swapping %d %d %d %d %g %g\n",v1->getNum(),v2->getNum(),v3->getNum(),v4->getNum(),BEFORE,AFTER);
+  if (fabs(BEFORE-AFTER)/BEFORE > 1.e-8){
+    delete t1b;
+    delete t2b;
+    return false;
+  }
+  //  printf("volumes ok\n");
+
+  delete t1->tri();
+  delete t2->tri();
+  t1->setTri(t1b);
+  t2->setTri(t2b);
+
+  std::set<MTri3*> cavity;
+  cavity.insert(t1);
+  cavity.insert(t2);
+  for(int i = 0; i < 3; i++){
+    if(t1->getNeigh(i))
+      cavity.insert(t1->getNeigh(i));
+    if(t2->getNeigh(i))
+      cavity.insert(t2->getNeigh(i));
+  }
+  std::vector<edgeXface> conn;
+  connectTris(cavity.begin(), cavity.end(), conn);
+  return true;
+}
+
+bool diffend (MVertex *v1, MVertex *v2, MVertex *p1, MVertex *p2){
+  if (v1 == p1 || v2 == p1 || v1 == p2 || v2 == p2)return false;
+  return true;
+}
+
+/*
+
+*/
+
+static bool recoverEdgeBySwaps (std::vector<MTri3*> &t, MVertex *mv1, MVertex *mv2, std::vector<MEdge> &edges){
+
+  SPoint3 pv1 (mv1->x(),mv1->y(),0);
+  SPoint3 pv2 (mv2->x(),mv2->y(),0);
+  double xcc[2];
+  for (unsigned int i=0;i<t.size();i++){
+    for (unsigned int j=0;j<3;j++){
+      MVertex *v1 = t[i]->tri()->getVertex((j+2)%3);
+      MVertex *v2 = t[i]->tri()->getVertex(j);
+      MVertex *v3 = t[i]->tri()->getVertex((j+1)%3);
+      MVertex *o  = t[i]->otherSide(j);
+      if (o){
+	SPoint3 p1 (v1->x(),v1->y(),0);
+	SPoint3 p2 (v2->x(),v2->y(),0);
+	SPoint3 p3 (v3->x(),v3->y(),0);
+	SPoint3 po (o->x(),o->y(),0);
+	if (diffend(v1,v2,mv1,mv2)){
+	  if (intersection_segments (p1, p2, pv1, pv2,xcc)){
+	    //	    if (std::binary_search(edges.begin(),edges.end(),MEdge(v1,v2),Less_Edge)){
+	    //	      Msg::Error("1D mesh self intersects");
+	    //	    }
+	    if (!intersection_segments(po, p3, pv1, pv2,xcc) || (v3 == mv1 || o == mv1 || v3 == mv2 || o == mv2)){
+	      if(swapedge (v1,v2,v3,o,t[i],j))return true;
+	    }
+	  }
+	}
+      }
+    }
+  }
+  return false;
+}
+
+// recover the edges by edge swapping in the triangulation.
+// edges are not supposed to
+
+void recoverEdges (std::vector<MTri3*> &t, std::vector<MEdge> &edges)
+{
+  Less_Edge le;
+  std::sort(edges.begin(),edges.end(),le);
+  std::set<MEdge,Less_Edge> setOfMeshEdges;
+  for (size_t i = 0;i<t.size();i++){
+    for (int j=0;j<3;j++){
+      setOfMeshEdges.insert(t[i]->tri()->getEdge(j));
+    }
+  }
+
+  std::vector<MEdge> edgesToRecover;
+  for (unsigned int i=0;i<edges.size();i++){
+    if (setOfMeshEdges.find(edges[i])==setOfMeshEdges.end())
+      edgesToRecover.push_back(edges[i]);
+  }
+
+  Msg::Info("%d edges to recover among %d edges",edgesToRecover.size(),edges.size());
+  //  int iter = 0;
+  //  char name[256];
+  //  sprintf(name,"iter%d.pos",iter++);
+  //  _printTris (name, t.begin(),t.end(),0);
+  for (unsigned int i=0;i<edgesToRecover.size();i++){
+    MVertex *mstart = edgesToRecover[i].getVertex(0);
+    MVertex *mend = edgesToRecover[i].getVertex(1);
+    Msg::Info("recovering edge %d %d",mstart->getNum(),mend->getNum());
+    //int iter;
+    while(recoverEdgeBySwaps (t, mstart, mend,edges)) {
+      //iter ++;
+    }
+  }
+}
diff --git a/Mesh/meshGFaceDelaunayInsertion.h b/Mesh/meshGFaceDelaunayInsertion.h
index 57f175b..5338e7d 100644
--- a/Mesh/meshGFaceDelaunayInsertion.h
+++ b/Mesh/meshGFaceDelaunayInsertion.h
@@ -90,8 +90,17 @@ class MTri3
   bool isDeleted() const { return deleted; }
   void forceRadius(double r) { circum_radius = r; }
   inline double getRadius() const { return circum_radius; }
-
+  inline MVertex *otherSide (int i){
+    MTri3 *n = neigh[i];
+    if (!n)return 0;
+    MVertex *v1 = base->getVertex((i+2)%3);
+    MVertex *v2 = base->getVertex(i);
+    for (int j=0;j<3;j++)
+      if (n->tri()->getVertex(j) != v1 && n->tri()->getVertex(j) != v2)return n->tri()->getVertex(j);
+    return 0;
+  }
   MTri3(MTriangle *t, double lc, SMetric3 *m = 0, bidimMeshData * data = 0, GFace *gf = 0);
+  inline void setTri(MTriangle *t) { base = t; }
   inline MTriangle *tri() const { return base; }
   inline void  setNeigh(int iN , MTri3 *n) { neigh[iN] = n; }
   inline MTri3 *getNeigh(int iN ) const { return neigh[iN]; }
@@ -152,6 +161,12 @@ void buildBackGroundMesh (GFace *gf,
 		  std::map<MVertex* , MVertex*>* equivalence= 0,
 		  std::map<MVertex*, SPoint2> * parametricCoordinates= 0);
 
+void delaunayMeshIn2D(std::vector<MVertex*> &,
+		      std::vector<MTriangle*> &,
+                      bool removeBox = true,
+		      std::vector<MEdge> *edgesToRecover = 0,
+                      bool hilbertSort = true);
+
 struct edgeXface
 {
   MVertex *v[2];
diff --git a/Mesh/meshGFaceElliptic.cpp b/Mesh/meshGFaceElliptic.cpp
index c26405f..0783398 100644
--- a/Mesh/meshGFaceElliptic.cpp
+++ b/Mesh/meshGFaceElliptic.cpp
@@ -600,8 +600,8 @@ static void updateFaceQuads(GFace *gf, std::vector<MQuadrangle*> &quads, std::ve
 static bool computeRingVertices(GFace *gf, Centerline *center,
 				std::vector<MVertex*> &vert1, std::vector<MVertex*> &vert2,
 				int &N, int &M, int &close_ind, int &sign2,
-				double &arc, double &length){
-
+				double &arc, double &length)
+{
 #if defined(HAVE_ANN)
   std::list<GEdge*> bedges = gf->edges();
   std::list<GEdge*>::iterator itb = bedges.begin();
@@ -690,8 +690,9 @@ static bool computeRingVertices(GFace *gf, Centerline *center,
   annDeallocPts(nodes);
 
   return true;
+#else
+  return false;
 #endif
-
 }
 
 //vert1 is the outer circle
@@ -705,7 +706,6 @@ static bool computeRingVertices(GFace *gf, Centerline *center,
 //         - - - -
 bool createRegularTwoCircleGridPeriodic (Centerline *center, GFace *gf)
 {
-
 #if defined(HAVE_ANN)
   std::vector<MVertex*> vert1, vert2;
   int N, M, close_ind, sign2;
@@ -756,11 +756,9 @@ bool createRegularTwoCircleGridPeriodic (Centerline *center, GFace *gf)
   //printParamGrid(gf, vert1, vert2, e00,e22,e02,e02,e02,e02, quads);
 
   return true;
-
 #else
   return false;
 #endif
-
 }
 
 //vert1 is the outer circle
@@ -860,11 +858,7 @@ bool createRegularTwoCircleGrid (Centerline *center, GFace *gf)
   printParamGrid(gf, vert1, vert2, e01,e10,e23,e32,e02,e13, quads);
 
   return true;
-
 #else
   return false;
 #endif
-
 }
-
-
diff --git a/Mesh/meshGFaceLloyd.cpp b/Mesh/meshGFaceLloyd.cpp
index eb3cd1c..6473be1 100644
--- a/Mesh/meshGFaceLloyd.cpp
+++ b/Mesh/meshGFaceLloyd.cpp
@@ -368,44 +368,40 @@ void callback(const alglib::real_1d_array& x,double& func,alglib::real_1d_array&
 }
 
 void verification(alglib::real_1d_array& x,void* ptr){
-  int num;
   int index;
   int dimension;
   double e;
   double func;
   double R,L,U,D;
   wrapper* w;
-  DocRecord* pointer;
-	
+
   w = static_cast<wrapper*>(ptr);
   dimension = w->get_dimension();
-  pointer = w->get_triangulator();
-  num = pointer->numPoints;
   srand(time(NULL));
   index = rand()%(dimension/2);
   e = 0.0000001;
-	
+
   alglib::real_1d_array grad;
   grad.setlength(dimension);
-	
+
   x[index] = x[index] + e;
   callback(x,R,grad,ptr);
   x[index] = x[index] - e;
-	
+
   x[index] = x[index] - e;
   callback(x,L,grad,ptr);
   x[index] = x[index] + e;
-	
+
   x[index + dimension/2] = x[index + dimension/2] + e;
   callback(x,U,grad,ptr);
   x[index + dimension/2] = x[index + dimension/2] - e;
-	
+
   x[index + dimension/2] = x[index + dimension/2] - e;
   callback(x,D,grad,ptr);
   x[index + dimension/2] = x[index + dimension/2] + e;
-	
+
   callback(x,func,grad,ptr);
-	
+
   printf("%f %f\n",(R-L)/(2.0*e),(U-D)/(2.0*e));
   printf("%f %f\n",grad[index],grad[index + dimension/2]);
 }
@@ -419,7 +415,7 @@ smoothing::smoothing(int param1,int param2){
 
 void smoothing::optimize_face(GFace* gf){
   if(gf->getNumMeshElements()==0 || gf->getCompound()) return;
-	
+
   std::set<MVertex*> all;
 
   // get all the points of the face ...
@@ -531,7 +527,7 @@ void smoothing::optimize_face(GFace* gf){
 
   /*if(num_interior>1){
     verification(x,&w);
-  }*/	
+  }*/
 
   if(num_interior>1){
     minlbfgscreate(2*num_interior,4,x,state);
@@ -580,19 +576,19 @@ void smoothing::optimize_face(GFace* gf){
   int option;
   option = gf->getMeshingAlgo();
   gf->setMeshingAlgo(ALGO_2D_MESHADAPT);
-	
+
   gf->additionalVertices = mesh_vertices;
   meshGFace mesher;
   mesher(gf);
-  
+
   gf->mesh_vertices.insert(gf->mesh_vertices.begin(),gf->additionalVertices.begin(),gf->additionalVertices.end()); //?
   gf->additionalVertices.clear();
 
-  gf->setMeshingAlgo(option);	
-	
+  gf->setMeshingAlgo(option);
+
   free(initial_conditions);
   free(variables_scales);
-	
+
   backgroundMesh::unset();
 }
 
diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp
index 25bbf4f..9263f66 100644
--- a/Mesh/meshGFaceOptimize.cpp
+++ b/Mesh/meshGFaceOptimize.cpp
@@ -911,6 +911,7 @@ static int _quadWithOneVertexOnBoundary (GFace *gf,
 // see paper from Bunin Guy Bunin (2006) Non-Local Topological Cleanup ,15th
 // International Meshing Roundtable. This is our interpretation of the
 // algorithm.
+/*
 static std::vector<MVertex*> closestPathBetweenTwoDefects (v2t_cont &adj,
                                                            v2t_cont :: iterator it)
 {
@@ -963,6 +964,7 @@ static std::vector<MVertex*> closestPathBetweenTwoDefects (v2t_cont &adj,
     }
   }
 }
+*/
 
 static MVertex * createNewVertex (GFace *gf, SPoint2 p){
   GPoint gp = gf->point(p);
@@ -1361,10 +1363,10 @@ struct  quadBlob {
   bool meshable (int iter)
   {
     int ncorners = 0;
-    MVertex *corners[5];
+    MVertex *corners[5] = {0, 0, 0, 0, 0};
     for (unsigned int i = 0; i < bnodes.size(); i++){
       if (topologicalAngle(bnodes[i]) > 0) ncorners ++;
-      if (ncorners > 5)return false;
+      if (ncorners > 5) return false;
     }
     if (ncorners != 3 && ncorners != 4 && ncorners != 5){
       return false;
@@ -1373,12 +1375,12 @@ struct  quadBlob {
 
     // look if it is possible to build a mesh with one defect only
     if (!orderBNodes () )return false;
-    int side = -1;
+    int side = 0;
     int count[5] = {0,0,0,0,0};
     for (unsigned int i = 0; i < bnodes.size(); i++){
       if (topologicalAngle(bnodes[i]) > 0){
-        side++;
         corners[side] = (bnodes[i]);
+        side++;
       }
       else count[side]++;
     }
@@ -1402,7 +1404,7 @@ struct  quadBlob {
       MVertex *v01 = bnodes[a1]; SPoint2 p01; reparamMeshVertexOnFace(v01, gf, p01);
       MVertex *v12 = bnodes[a1+a3+a2]; SPoint2 p12; reparamMeshVertexOnFace(v12, gf, p12);
       MVertex *v20 = bnodes[a1+a3+a2+a1+a3]; SPoint2 p20; reparamMeshVertexOnFace(v20, gf, p20);
-      SPoint2 p012 = (p01+p12+p20)*(1./3.0); MVertex *v012 = createNewVertex (gf, p012);
+      SPoint2 p012 = (p01+p12+p20)*(1./3.0);
 
       std::vector<MVertex*> e012_01 = saturateEdge (gf,p012,p01,a2);
       std::vector<MVertex*> e012_12 = saturateEdge (gf,p012,p12,a3);
@@ -1411,6 +1413,8 @@ struct  quadBlob {
       if (e012_12.size() == 0) return false;
       if (e012_20.size() == 0) return false;
 
+      MVertex *v012 = createNewVertex (gf, p012);
+
       std::vector<MVertex*> e0_01,e01_1,e1_12,e12_2,e2_20,e20_0;
       for (int i=0;i<a1-1;i++)e0_01.push_back(bnodes[i+1]);
       for (int i=0;i<a3-1;i++)e01_1.push_back(bnodes[i+1 + a1]);
@@ -1521,8 +1525,6 @@ struct  quadBlob {
            v0      v01        v1
                a1       a3
 
-
-
      */
     else if (ncorners == 5){
       printBlob(iter,5);
@@ -1552,7 +1554,7 @@ struct  quadBlob {
       MVertex *v23 = bnodes[a1+a3+a2+a4+a3]; SPoint2 p23; reparamMeshVertexOnFace(v23, gf, p23);
       MVertex *v34 = bnodes[a1+a3+a2+a4+a3+a5+a4]; SPoint2 p34; reparamMeshVertexOnFace(v34, gf, p34);
       MVertex *v40 = bnodes[a1+a3+a2+a4+a3+a5+a4+a1+a5]; SPoint2 p40; reparamMeshVertexOnFace(v40, gf, p40);
-      SPoint2 p01234 = (p01+p12+p23+p34+p40)*(1./5.0); MVertex *v01234 = createNewVertex (gf, p01234);
+      SPoint2 p01234 = (p01+p12+p23+p34+p40)*(1./5.0);
 
       std::vector<MVertex*> e01234_01 = saturateEdge (gf,p01234,p01,a2);
       std::vector<MVertex*> e01234_12 = saturateEdge (gf,p01234,p12,a3);
@@ -1565,6 +1567,8 @@ struct  quadBlob {
       if (e01234_34.size() == 0) return false;
       if (e01234_40.size() == 0) return false;
 
+      MVertex *v01234 = createNewVertex (gf, p01234);
+
       std::vector<MVertex*> e0_01,e01_1,e1_12,e12_2,e2_23,e23_3,e3_34,e34_4,e4_40,e40_0;
       for (int i=0;i<a1-1;i++)e0_01.push_back(bnodes[i+1]);
       for (int i=0;i<a3-1;i++)e01_1.push_back(bnodes[i+1 + a1]);
@@ -1652,10 +1656,12 @@ bool quadBlob::matricesDone = false;
 fullMatrix<double> quadBlob::M3;
 fullMatrix<double> quadBlob::M5;
 
+/*
 static int _defectsRemovalBunin(GFace *gf, int maxCavitySize)
 {
 
   if (maxCavitySize == 0)return 0;
+  printf("ARGH\n");
   v2t_cont adj;
   std::vector<MElement*> c;
   buildVertexToElement(gf->quadrangles, adj);
@@ -1700,6 +1706,7 @@ static int _defectsRemovalBunin(GFace *gf, int maxCavitySize)
 
   return iter;
 }
+*/
 
 // if a vertex (on boundary) is adjacent to one only quad
 // and if that quad is badly shaped, we split this
@@ -2830,7 +2837,6 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge,
   MTriangle *t1b = new MTriangle(v2, v3, v4);
   MTriangle *t2b = new MTriangle(v4, v3, v1);
 
-
   //  const double v1b = surfaceTriangleUV(v2, v3, v4, data);
   //  const double v2b = surfaceTriangleUV(v4, v3, v1, data);
   //  const double volume = v1b + v2b;
@@ -2856,7 +2862,6 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge,
 	  return false;
 	}
       }
-      //      printf("coucou\n");
       break;
     }
   case SWCR_DEL:
@@ -2879,6 +2884,8 @@ bool edgeSwap(std::set<swapquad> &configs, MTri3 *t1, GFace *gf, int iLocalEdge,
     break;
   default :
     Msg::Error("Unknown swapping criterion");
+    delete t1b;
+    delete t2b;
     return false;
   }
 
@@ -3162,7 +3169,7 @@ int recombineWithBlossom(GFace *gf, double dx, double dy,
   std::set<MElement*> touched;
   std::vector<std::pair<MElement*,MElement*> > toProcess;
 
-  if(CTX::instance()->mesh.algoRecombine == 1){
+  if(CTX::instance()->mesh.algoRecombine != 0){
 #if defined(HAVE_BLOSSOM)
     int ncount = gf->triangles.size();
     if (ncount % 2 == 0) {
@@ -3292,6 +3299,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1)
 {
   // never recombine a face that is part of a compound!
   if(gf->getCompound()) return 0;
+  if(gf->triangles.size() == 0) return 1;
 
   int success = 1;
 
@@ -3369,7 +3377,7 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1)
   std::set<MElement*> touched;
   std::vector<std::pair<MElement*,MElement*> > toProcess;
 
-  if(CTX::instance()->mesh.algoRecombine == 1){
+  if(CTX::instance()->mesh.algoRecombine != 0){
 #if defined(HAVE_BLOSSOM)
     int ncount = gf->triangles.size();
     if (ncount % 2 != 0) {
@@ -3584,15 +3592,16 @@ static double printStats(GFace *gf,const char *message)
     Qav += Q;
     Qmin = std::min(Q,Qmin);
   }
-  Msg::Info("%s : %5d quads %4d invalid quads %4d quads with Q < 0.1 "
-            "Avg Q = %12.5E Min %12.5E", message, gf->quadrangles.size(),
+  Msg::Info("%s : %5d quads %5d triangles %4d invalid quads %4d quads with Q < 0.1 "
+            "Avg Q = %12.5E Min %12.5E", message, gf->quadrangles.size(), gf->triangles.size(),
             nbInv, nbBad, Qav/gf->quadrangles.size(), Qmin);
   return Qmin;
 }
 
 void recombineIntoQuads(GFace *gf,
                         bool topologicalOpti,
-                        bool nodeRepositioning)
+                        bool nodeRepositioning,
+			double minqual)
 {
   double t1 = Cpu();
 
@@ -3606,7 +3615,7 @@ void recombineIntoQuads(GFace *gf,
   //    removeFourTrianglesNodes(gf, false);
 
   if (saveAll) gf->model()->writeMSH("before.msh");
-  int success = _recombineIntoQuads(gf, 0);
+  int success = _recombineIntoQuads(gf, minqual);
 
   if (saveAll) gf->model()->writeMSH("raw.msh");
   printStats (gf, "BEFORE OPTIMIZATION");
@@ -3614,35 +3623,32 @@ void recombineIntoQuads(GFace *gf,
     laplaceSmoothing(gf, CTX::instance()->mesh.nbSmoothing);
   }
   // blossom-quad algo
-  if(success && CTX::instance()->mesh.algoRecombine == 1){
+  if(success && CTX::instance()->mesh.algoRecombine != 0){
     if(topologicalOpti){
       if(haveParam){
         if (saveAll) gf->model()->writeMSH("smoothed.msh");
         int ITER=0;
-	int ITERB = 0;
-        int optistatus[6] = {0,0,0,0,0,0};
+	//        int optistatus[6] = {0,0,0,0,0,0};
 	std::set<MEdge,Less_Edge> prioritory;
+	double exbad = -100;
         while(1){
-          int maxCavitySize = CTX::instance()->mesh.bunin;
-	  optistatus[0] = (ITERB == 1) ?splitFlatQuads(gf, .01, prioritory) : 0;
-          optistatus[1] = removeTwoQuadsNodes(gf);
-          optistatus[4] = _defectsRemovalBunin(gf,maxCavitySize);
-          optistatus[2] = removeDiamonds(gf) ;
-	  laplaceSmoothing(gf,CTX::instance()->mesh.nbSmoothing,true);
-	  optistatus[3] = edgeSwapQuadsForBetterQuality(gf,.01, prioritory);
-	  optistatus[5] = optiSmoothing(gf,CTX::instance()->mesh.nbSmoothing,true);
-	  optistatus[5] = (ITERB == 1) ?
-            untangleInvalidQuads(gf, CTX::instance()->mesh.nbSmoothing) : 0;
+	  //          int maxCavitySize = CTX::instance()->mesh.bunin;
+	  //	  optistatus[0] = (ITERB == 1) ?splitFlatQuads(gf, .01, prioritory) : 0;
+          //optistatus[1] =
+	  removeTwoQuadsNodes(gf);
+	  //optistatus[4] = _defectsRemovalBunin(gf,36);
+	  //optistatus[2] =
+	  removeDiamonds(gf) ;
+	  if(haveParam)laplaceSmoothing(gf,CTX::instance()->mesh.nbSmoothing,true);
+	  //optistatus[3] =
+	  edgeSwapQuadsForBetterQuality(gf,minqual, prioritory);
+	  //optistatus[5] =
+	  optiSmoothing(gf,CTX::instance()->mesh.nbSmoothing,true);
+	  //	  optistatus[5] = untangleInvalidQuads(gf, CTX::instance()->mesh.nbSmoothing);
 	  double bad = printStats(gf, "IN OPTIMIZATION");
-	  if (bad > .1) break;
-          if (ITER == 10){
-	    ITERB = 1;
-	  }
+	  if (bad > minqual || exbad == bad) break;
+	  exbad = bad;
 	  if (ITER > 20) break;
-	  int nb = 0;
-	  for (int i=0;i<6;i++) nb += optistatus[i];
-	  if (!nb && ITERB == 0) ITERB = 1;
-	  else if (!nb) break;
 	  ITER ++;
         }
       }
@@ -3654,10 +3660,9 @@ void recombineIntoQuads(GFace *gf,
     }
     double t2 = Cpu();
     Msg::Info("Blossom recombination algorithm completed (%g s)", t2 - t1);
-    quadsToTriangles(gf, .01);
+    quadsToTriangles(gf, minqual);
     if(haveParam) {
       laplaceSmoothing(gf,CTX::instance()->mesh.nbSmoothing);
-      // optiSmoothing(gf,CTX::instance()->mesh.nbSmoothing,true);
     }
     // removeDiamonds(gf);
     // removeTwoQuadsNodes(gf);
diff --git a/Mesh/meshGFaceOptimize.h b/Mesh/meshGFaceOptimize.h
index 6cf8266..6dde944 100644
--- a/Mesh/meshGFaceOptimize.h
+++ b/Mesh/meshGFaceOptimize.h
@@ -81,7 +81,8 @@ void transferDataStructure(GFace *gf, std::set<MTri3*, compareTri3Ptr> &AllTris,
 void computeEquivalences(GFace *gf,bidimMeshData &DATA);
 void recombineIntoQuads(GFace *gf,
                         bool topologicalOpti   = true,
-                        bool nodeRepositioning = true);
+                        bool nodeRepositioning = true,
+			double minqual = 0.1);
 
 //used for meshGFaceRecombine development
 int recombineWithBlossom(GFace *gf, double dx, double dy,
@@ -130,6 +131,8 @@ struct RecombineTriangle
   {
     n1 = me.getVertex(0);
     n2 = me.getVertex(1);
+    n3 = 0;
+    n4 = 0;
 
     if(t1->getVertex(0) != n1 && t1->getVertex(0) != n2) n3 = t1->getVertex(0);
     else if(t1->getVertex(1) != n1 && t1->getVertex(1) != n2) n3 = t1->getVertex(1);
diff --git a/Mesh/meshGFaceRecombine.cpp b/Mesh/meshGFaceRecombine.cpp
index 718e413..7207826 100644
--- a/Mesh/meshGFaceRecombine.cpp
+++ b/Mesh/meshGFaceRecombine.cpp
@@ -228,7 +228,7 @@ Recombine2D::~Recombine2D()
 bool Recombine2D::construct()
 {
   if (!_iamCurrent()) {
-    Msg::Warning("[Recombine2D] I can't construct u_u");
+    Msg::Warning("[Recombine2D] I can't construct...");
     return false;
   }
   if (Rec2DData::hasInstance()) {
@@ -4204,7 +4204,7 @@ double Rec2DVertex::getGainRecomb(/*Rec2DQualCrit crit,*/
                  static_cast<int>(_elements.size())-1/*, crit*/)
          - getQual(/*crit*/);
          
-  //FIX v�rifier que c''est bien ce qui est demand� ! (renvoie bien ce que veux apply, compute reward, ...)
+  //FIX verifier que c'est bien ce qui est demande ! (renvoie bien ce que veux apply, compute reward, ...)
 }
 
 void Rec2DVertex::/*vertQual_*/addEdgeQual(double val, int num)
diff --git a/Mesh/meshGFaceTransfinite.cpp b/Mesh/meshGFaceTransfinite.cpp
index 671c031..696acf6 100644
--- a/Mesh/meshGFaceTransfinite.cpp
+++ b/Mesh/meshGFaceTransfinite.cpp
@@ -193,11 +193,11 @@ int MeshTransfiniteSurface(GFace *gf)
     MVertex *v = m_vertices[i];
     if(v == corners[0] || v == corners[1] || v == corners[2] ||
        (corners.size() == 4 && v == corners[3])){
-      N[iCorner++] = i;
-      if(iCorner > 4){
+      if(iCorner > 3){
         Msg::Error("Surface %d transfinite parameters are incoherent", gf->tag());
         return 0;
       }
+      N[iCorner++] = i;
     }
     SPoint2 param;
     reparamMeshVertexOnFace(v, gf, param);
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index 6314ff6..7bbe110 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -11,6 +11,7 @@
 #include "meshGFace.h"
 #include "meshGFaceOptimize.h"
 #include "boundaryLayersData.h"
+//#include "meshGRegionBoundaryRecovery.h"
 #include "meshGRegionDelaunayInsertion.h"
 #include "GModel.h"
 #include "GRegion.h"
@@ -44,6 +45,8 @@ class splitQuadRecovery {
   std::multimap<GEntity*, std::pair<MVertex*,MFace> >_data;
   bool _empty;
  public :
+  std::map<MFace, MVertex*, Less_Face>_invmap;
+  std::set<MFace, Less_Face>_toDelete;
   splitQuadRecovery() : _empty(true) {}
   bool empty(){ return _empty; }
   void setEmpty(bool val){ _empty = val; }
@@ -64,43 +67,49 @@ class splitQuadRecovery {
       (*it)->triangles.clear();
       for (std::multimap<GEntity*, std::pair<MVertex*,MFace> >::iterator it2 =
              _data.lower_bound(*it); it2 != _data.upper_bound(*it) ; ++it2){
-        MVertex *v = it2->second.first;
-        v->onWhat()->mesh_vertices.erase(std::find(v->onWhat()->mesh_vertices.begin(),
-                                                   v->onWhat()->mesh_vertices.end(), v));
         const MFace &f = it2->second.second;
-        std::set<MFace, Less_Face>::iterator itf0 = allFaces.find(MFace(f.getVertex(0),
-                                                                        f.getVertex(1),v));
-        std::set<MFace, Less_Face>::iterator itf1 = allFaces.find(MFace(f.getVertex(1),
-                                                                        f.getVertex(2),v));
-        std::set<MFace, Less_Face>::iterator itf2 = allFaces.find(MFace(f.getVertex(2),
-                                                                        f.getVertex(3),v));
-        std::set<MFace, Less_Face>::iterator itf3 = allFaces.find(MFace(f.getVertex(3),
-                                                                        f.getVertex(0),v));
-        if (itf0 != allFaces.end() && itf1 != allFaces.end() &&
-            itf2 != allFaces.end() && itf3 != allFaces.end()){
-          (*it)->quadrangles.push_back(new MQuadrangle(f.getVertex(0), f.getVertex(1),
-                                                       f.getVertex(2), f.getVertex(3)));
-	allFaces.erase(*itf0);
-	allFaces.erase(*itf1);
-	allFaces.erase(*itf2);
-	allFaces.erase(*itf3);
-	// printf("some pyramids should be created %d regions\n", (*it)->numRegions());
-	for (int iReg = 0; iReg < (*it)->numRegions(); iReg++){
-	  if (iReg == 1) {
-            Msg::Error("Cannot build pyramids on non manifold faces");
-            v = new MVertex(v->x(), v->y(), v->z(), (*it)->getRegion(iReg));
-          }
-	  else
-            v->setEntity ((*it)->getRegion(iReg));
-	  (*it)->getRegion(iReg)->pyramids.push_back
-            (new MPyramid(f.getVertex(0), f.getVertex(1), f.getVertex(2), f.getVertex(3), v));
-	  (*it)->getRegion(iReg)->mesh_vertices.push_back(v);
-	  NBPY++;
+	MVertex *v = it2->second.first;
+	v->onWhat()->mesh_vertices.erase(std::find(v->onWhat()->mesh_vertices.begin(),
+						   v->onWhat()->mesh_vertices.end(), v));
+	std::set<MFace, Less_Face>::iterator itf0 = allFaces.find(MFace(f.getVertex(0),
+									f.getVertex(1),v));
+	std::set<MFace, Less_Face>::iterator itf1 = allFaces.find(MFace(f.getVertex(1),
+									f.getVertex(2),v));
+	std::set<MFace, Less_Face>::iterator itf2 = allFaces.find(MFace(f.getVertex(2),
+									f.getVertex(3),v));
+	std::set<MFace, Less_Face>::iterator itf3 = allFaces.find(MFace(f.getVertex(3),
+									f.getVertex(0),v));
+	if (itf0 != allFaces.end() && itf1 != allFaces.end() &&
+	    itf2 != allFaces.end() && itf3 != allFaces.end()){
+	  (*it)->quadrangles.push_back(new MQuadrangle(f.getVertex(0), f.getVertex(1),
+						       f.getVertex(2), f.getVertex(3)));
+	  allFaces.erase(*itf0);
+	  allFaces.erase(*itf1);
+	  allFaces.erase(*itf2);
+	  allFaces.erase(*itf3);
+	  // printf("some pyramids should be created %d regions\n", (*it)->numRegions());
+	  for (int iReg = 0; iReg < (*it)->numRegions(); iReg++){
+	    if (iReg == 1) {
+	      Msg::Error("Cannot build pyramids on non manifold faces");
+	      v = new MVertex(v->x(), v->y(), v->z(), (*it)->getRegion(iReg));
+	    }
+	    else
+	      v->setEntity ((*it)->getRegion(iReg));
+	    // A quad face connected to an hex or a primsm --> leave the quad face as is
+	    if (_toDelete.find(f) == _toDelete.end()){
+	      (*it)->getRegion(iReg)->pyramids.push_back
+		(new MPyramid(f.getVertex(0), f.getVertex(1), f.getVertex(2), f.getVertex(3), v));
+	      (*it)->getRegion(iReg)->mesh_vertices.push_back(v);
+	      NBPY++;
+	    }
+	    else {
+	      delete v;
+	    }
+	  }
 	}
-        }
       }
       for (std::set<MFace, Less_Face>::iterator itf = allFaces.begin();
-           itf != allFaces.end(); ++itf){
+	   itf != allFaces.end(); ++itf){
         (*it)->triangles.push_back
           (new MTriangle(itf->getVertex(0), itf->getVertex(1), itf->getVertex(2)));
       }
@@ -257,6 +266,7 @@ void getBoundingInfoAndSplitQuads(GRegion *gr,
 				   (v0->y() + v1->y() + v2->y() + v3->y())*0.25,
 				   (v0->z() + v1->z() + v2->z() + v3->z())*0.25,itx->second);
       sqr.add(f,newv,itx->second);
+      sqr._invmap[f] = newv;
       allBoundingFaces[MFace(v0,v1,newv)] = itx->second;
       allBoundingFaces[MFace(v1,v2,newv)] = itx->second;
       allBoundingFaces[MFace(v2,v3,newv)] = itx->second;
@@ -278,7 +288,9 @@ void getBoundingInfoAndSplitQuads(GRegion *gr,
 }
 
 #if defined(HAVE_TETGEN)
+
 #include "tetgen.h"
+
 void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numberedV,
                           splitQuadRecovery &sqr)
 {
@@ -286,6 +298,15 @@ void buildTetgenStructure(GRegion *gr, tetgenio &in, std::vector<MVertex*> &numb
   std::map<MFace,GEntity*,Less_Face> allBoundingFaces;
   getBoundingInfoAndSplitQuads(gr, allBoundingFaces, allBoundingVertices, sqr);
 
+  //// TEST
+  {
+    std::vector<MVertex*>ALL;
+    std::vector<MTetrahedron*> MESH;
+    ALL.insert(ALL.begin(),allBoundingVertices.begin(),allBoundingVertices.end());
+    //    delaunayMeshIn3D (ALL,MESH);
+    //    exit(1);
+  }
+
   in.mesh_dim = 3;
   in.firstnumber = 1;
   in.numberofpoints = allBoundingVertices.size() + Filler::get_nbr_new_vertices() +
@@ -496,12 +517,25 @@ void TransferTetgenMesh(GRegion *gr, tetgenio &in, tetgenio &out,
     gr->tetrahedra.push_back(t);
   }
 }
+
 #endif
 
 static void addOrRemove(const MFace &f,
 			MElement *e,
-			std::map<MFace,MElement*,Less_Face> & bfaces)
+			std::map<MFace,MElement*,Less_Face> & bfaces,
+			splitQuadRecovery &sqr)
 {
+  {
+    std::map<MFace, MVertex*, Less_Face>::const_iterator it = sqr._invmap.find(f);
+    if (it != sqr._invmap.end()){
+      addOrRemove (MFace(it->second, f.getVertex(0),f.getVertex(1)),e,bfaces,sqr);
+      addOrRemove (MFace(it->second, f.getVertex(1),f.getVertex(2)),e,bfaces,sqr);
+      addOrRemove (MFace(it->second, f.getVertex(2),f.getVertex(3)),e,bfaces,sqr);
+      addOrRemove (MFace(it->second, f.getVertex(3),f.getVertex(0)),e,bfaces,sqr);
+      return;
+    }
+  }
+
   std::map<MFace,MElement*,Less_Face>::iterator it = bfaces.find(f);
   if (it == bfaces.end())bfaces.insert(std::make_pair(f,e));
   else bfaces.erase(it);
@@ -519,11 +553,12 @@ static void addOrRemove(const MFace &f,
 
 */
 
-bool AssociateElementsToModelRegionWithBoundaryLayers (GRegion *gr,
-						       std::vector<MTetrahedron*> &tets,
-						       std::vector<MHexahedron*> &hexes,
-						       std::vector<MPrism*> &prisms,
-						       std::vector<MPyramid*> &pyramids)
+static bool AssociateElementsToModelRegionWithBoundaryLayers (GRegion *gr,
+							      std::vector<MTetrahedron*> &tets,
+							      std::vector<MHexahedron*> &hexes,
+							      std::vector<MPrism*> &prisms,
+							      std::vector<MPyramid*> &pyramids,
+							      splitQuadRecovery & sqr)
 {
   std::set<MElement*> all;
   all.insert(hexes.begin(),hexes.end());
@@ -551,7 +586,7 @@ bool AssociateElementsToModelRegionWithBoundaryLayers (GRegion *gr,
       else {
 	// what to do ??????
 	// two tets and one prism --> the prism should be
-	// geometrically on the other side of the
+	// geometrically on the other side of the tet
 	if (itf->second.second) {
 	  MElement *prism=0, *t1=0, *t2=0;
 	  if (itf->second.second->getType () == TYPE_PRI || itf->second.second->getType () == TYPE_PYR) {
@@ -617,15 +652,21 @@ bool AssociateElementsToModelRegionWithBoundaryLayers (GRegion *gr,
     connected.insert(FIRST);
     for (int i=0;i<FIRST->getNumFaces();i++){
       MFace f = FIRST->getFace(i);
-      GFace* gfound = findInFaceSearchStructure (f.getVertex(0),
-						 f.getVertex(1),
-						 f.getVertex(2),
-						 search);
+      std::map<MFace, MVertex*, Less_Face>::iterator it = sqr._invmap.find(f);
+      GFace* gfound = 0;
+      if (it != sqr._invmap.end()){
+	gfound = (GFace*)it->second->onWhat();
+	// one pyramid is useless because one element with a quad face impacts the
+	// boundary of the domain.
+	sqr._toDelete.insert(f);
+      }
+      else gfound = findInFaceSearchStructure (f,search);
       if (!gfound){
 	std::map<MFace,std::pair<MElement*,MElement*>,Less_Face>::iterator
 	  itf = myGraph.find(f);
 	MElement *t_neigh = itf->second.first == FIRST ?
 	  itf->second.second :  itf->second.first;
+	if (!t_neigh)printf("oulalalalalalalala %d vertices\n",f.getNumVertices());
 	if (connected.find(t_neigh) == connected.end())myStack.push(t_neigh);
       }
       else {
@@ -634,6 +675,7 @@ bool AssociateElementsToModelRegionWithBoundaryLayers (GRegion *gr,
       }
     }
   }
+
   //  printf ("found a set of %d elements that are connected with %d bounding faces\n",connected.size(),faces_bound.size());
   GRegion *myGRegion = getRegionFromBoundingFaces(gr->model(), faces_bound);
   //  printf("REGION %d %d\n",myGRegion->tag(),gr->tag());
@@ -667,9 +709,8 @@ bool AssociateElementsToModelRegionWithBoundaryLayers (GRegion *gr,
   return true;
 }
 
-
-static int getWedge (BoundaryLayerColumns* _columns, MVertex *v1, MVertex *v2,
-		     int indicesVert1 [], int indicesVert2 [])
+static int getWedge(BoundaryLayerColumns* _columns, MVertex *v1, MVertex *v2,
+                    int indicesVert1 [], int indicesVert2 [])
 {
   int N1 = _columns->getNbColumns(v1) ;
   int N2 = _columns->getNbColumns(v2) ;
@@ -685,9 +726,6 @@ static int getWedge (BoundaryLayerColumns* _columns, MVertex *v1, MVertex *v2,
     if (c2._joint.size())NW2++;
   }
 
-
-
-
   std::map<int,int> one2two;
   for (int i=0;i<NW1;i++){
     const BoundaryLayerData & c1 = _columns->getColumn(v1,i);
@@ -734,7 +772,7 @@ static int getWedge (BoundaryLayerColumns* _columns, MVertex *v1, MVertex *v2,
   for (int i=0;i<NW2;i++){
     for (int j=i+1;j<NW2;j++){
       if ((vert2Start == i && vert2End == j) ||
-	  (vert2Start == i && vert2End == j))
+	  (vert2Start == j && vert2End == i))
 	{
 	  INDEX2 = count;
 	}
@@ -770,11 +808,12 @@ static int getWedge (BoundaryLayerColumns* _columns, MVertex *v1, MVertex *v2,
   return fanSize  + 2;
 }
 
-static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
+
+static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr, splitQuadRecovery & sqr)
 {
   if (getBLField(gr->model())) insertVerticesInRegion(gr,-1);
-  BoundaryLayerColumns* _columns = buildAdditionalPoints3D (gr);
-  if (!_columns)return false;
+  if (!buildAdditionalPoints3D (gr)) return false;
+  BoundaryLayerColumns* _columns = gr->getColumns();
   std::map<MFace,MElement*,Less_Face> bfaces;
 
   std::vector<MPrism*> blPrisms;
@@ -786,20 +825,34 @@ static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
   faces.insert(faces.begin(), embedded_faces.begin(),embedded_faces.end());
   std::set<MVertex*> verts;
 
+  {
+    std::list<GFace*>::iterator itf = faces.begin();
+    while(itf != faces.end()){
+      for(unsigned int i = 0; i< (*itf)->getNumMeshElements(); i++){
+	MElement *e = (*itf)->getMeshElement(i);
+	addOrRemove (e->getFace(0),0,bfaces,sqr);
+      }
+      ++itf;
+    }
+  }
+
   std::list<GFace*>::iterator itf = faces.begin();
   while(itf != faces.end()){
     for(unsigned int i = 0; i< (*itf)->triangles.size(); i++){
       MVertex *v1 = (*itf)->triangles[i]->getVertex(0);
       MVertex *v2 = (*itf)->triangles[i]->getVertex(1);
       MVertex *v3 = (*itf)->triangles[i]->getVertex(2);
-      MFace dv(v1,v2,v3);
-      addOrRemove (dv,0,bfaces);
+      MFace dv (v1,v2,v3);
       for (unsigned int SIDE = 0 ; SIDE < _columns->_normals3D.count(dv); SIDE ++){
 	faceColumn fc =  _columns->getColumns(*itf,v1, v2, v3, SIDE);
 	const BoundaryLayerData & c1 = fc._c1;
 	const BoundaryLayerData & c2 = fc._c2;
 	const BoundaryLayerData & c3 = fc._c3;
 	int N = std::min(c1._column.size(),std::min(c2._column.size(),c3._column.size()));
+
+	//	double distMax = getDistMax (v1, v2, v3, c1._n, c2._n, c3._n);
+	MFace f_low (v1,v2,v3);
+	SVector3 n_low = f_low.normal();
 	//	printf("%d Layers\n",N);
 	std::vector<MElement*> myCol;
 	for (int l=0;l < N ;++l){
@@ -817,12 +870,18 @@ static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
 	    v12 = c2._column[l-1];
 	    v13 = c3._column[l-1];
 	  }
-	  //	  printf("coucoucouc %p %p %p %p %p %p\n",v11,v12,v13,v21,v22,v23);
+	  MFace f_up (v21,v22,v23);
+	  SVector3 n_up = f_up.normal();
+	  double dotProd = dot(n_up,n_low);
 	  MPrism *prism = new MPrism(v11,v12,v13,v21,v22,v23);
-	  // store the layer the element belongs
-	  prism->setPartition(l+1);
-	  blPrisms.push_back(prism);
-	  myCol.push_back(prism);
+	  if (dotProd > 0.2 && prism->skewness() > 0.1){
+	    blPrisms.push_back(prism);
+	    myCol.push_back(prism);
+	  }
+	  else {
+	    delete prism;
+	    l = N+1;
+	  }
 	}
 	if (!myCol.empty()){
 	  for (unsigned int l=0;l<myCol.size();l++)_columns->_toFirst[myCol[l]] = myCol[0];
@@ -888,7 +947,6 @@ static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
 	  if (l == 0){
 	    MPrism *prism = new MPrism(v12,v21,v22,v13,v24,v23);
 	    // store the layer the element belongs
-	    prism->setPartition(l+1);
 	    myCol.push_back(prism);
 
 	    blPrisms.push_back(prism);
@@ -897,7 +955,6 @@ static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
 	    MHexahedron *hex = new MHexahedron(v11,v12,v13,v14,v21,v22,v23,v24);
 	    // store the layer the element belongs
 	    myCol.push_back(hex);
-	    hex->setPartition(l+1);
 	    blHexes.push_back(hex);
 	  }
 	}
@@ -909,8 +966,10 @@ static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
     }
     ++ite;
   }
-
-  //  filterOverlappingElements (blPrisms,blHexes,_columns->_elemColumns,_columns->_toFirst);
+  // ------------------------------------------------------------------------------------
+  // FIXME : NOT 100 % CORRECT
+  //    filterOverlappingElements (blPrisms,blHexes,_columns->_elemColumns,_columns->_toFirst);
+  // ------------------------------------------------------------------------------------
   {
     FILE *ff2 = fopen ("tato3D.pos","w");
     fprintf(ff2,"View \" \"{\n");
@@ -926,13 +985,13 @@ static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
 
   for (unsigned int i = 0; i < blPrisms.size();i++){
     for (unsigned int j=0;j<5;j++)
-      addOrRemove(blPrisms[i]->getFace(j),blPrisms[i],bfaces);
+      addOrRemove(blPrisms[i]->getFace(j),blPrisms[i],bfaces,sqr);
     for (int j = 0; j < 6; j++)
       if(blPrisms[i]->getVertex(j)->onWhat() == gr)verts.insert(blPrisms[i]->getVertex(j));
   }
   for (unsigned int i = 0; i < blHexes.size();i++){
     for (unsigned int j=0;j<6;j++)
-      addOrRemove(blHexes[i]->getFace(j),blHexes[i],bfaces);
+      addOrRemove(blHexes[i]->getFace(j),blHexes[i],bfaces, sqr);
     for (int j = 0; j < 8; j++)
       if(blHexes[i]->getVertex(j)->onWhat() == gr)verts.insert(blHexes[i]->getVertex(j));
   }
@@ -978,7 +1037,8 @@ static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
 	}
       }
       //      printf("counter = %d\n",counter);
-      opposite /= (double)counter;
+      if(counter)
+        opposite /= (double)counter;
 
       SVector3 dir = center - opposite;
       MTriangle temp (it->first.getVertex(0),it->first.getVertex(1),it->first.getVertex(2));
@@ -1037,15 +1097,19 @@ static bool modifyInitialMeshForTakingIntoAccountBoundaryLayers(GRegion *gr)
   printf("%d tets\n", (int)gr->tetrahedra.size());
   deMeshGFace _kill;
   _kill (nf);
-  delete nf;
+  //<<<<<<< .mine
   gr->model()->remove(nf);
+  //  delete nf;
+  //=======
+  //>>>>>>> .r18259
+  delete nf;
 
   gr->set(faces);
   gr->mesh_vertices.insert(gr->mesh_vertices.begin(),verts.begin(),verts.end());
 
   gr->model()->writeMSH("BL_start.msh");
 
-  AssociateElementsToModelRegionWithBoundaryLayers (gr, gr->tetrahedra , blHexes, blPrisms, blPyrs);
+  AssociateElementsToModelRegionWithBoundaryLayers (gr, gr->tetrahedra , blHexes, blPrisms, blPyrs, sqr);
 
   gr->model()->writeMSH("BL_start2.msh");
 
@@ -1080,7 +1144,8 @@ void _relocateVertex(MVertex *ver,
 }
 
 #if defined(HAVE_TETGEN)
-bool CreateAnEmptyVolumeMesh(GRegion *gr){
+bool CreateAnEmptyVolumeMesh(GRegion *gr)
+{
   printf("creating an empty volume mesh\n");
   splitQuadRecovery sqr;
   tetgenio in, out;
@@ -1102,14 +1167,18 @@ bool CreateAnEmptyVolumeMesh(GRegion *gr){
   TransferTetgenMesh(gr, in, out, numberedV);
   return true;
 }
+
 #else
-bool CreateAnEmptyVolumeMesh(GRegion *gr){
+
+bool CreateAnEmptyVolumeMesh(GRegion *gr)
+{
   Msg::Error("You should compile with TETGEN in order to create an empty volume mesh");
   return false;
 }
-#endif // HAVE_TETGEN#endif // HAVE_TETGEN#endif // HAVE_TETGEN
 
-void MeshDelaunayVolume(std::vector<GRegion*> &regions)
+#endif
+
+void MeshDelaunayVolumeTetgen(std::vector<GRegion*> &regions)
 {
   if(regions.empty()) return;
 
@@ -1218,7 +1287,7 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
   // restore the initial set of faces
   gr->set(faces);
 
-  bool _BL = modifyInitialMeshForTakingIntoAccountBoundaryLayers(gr);
+  bool _BL = modifyInitialMeshForTakingIntoAccountBoundaryLayers(gr,sqr);
 
   // now do insertion of points
   if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_DEL)
@@ -1267,6 +1336,77 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
 #endif
 }
 
+// uncomment this to test the new code
+//##define NEW_CODE
+
+void MeshDelaunayVolume(std::vector<GRegion*> &regions)
+{
+  if(regions.empty()) return;
+
+#if !defined(NEW_CODE) && defined(HAVE_TETGEN)
+  MeshDelaunayVolumeTetgen(regions);
+  return;
+#endif
+  /*
+  splitQuadRecovery sqr;
+
+  for(unsigned int i = 0; i < regions.size(); i++)
+    Msg::Info("Meshing volume %d (Delaunay)", regions[i]->tag());
+
+  // put all the faces in the same model
+  GRegion *gr = regions[0];
+  std::list<GFace*> faces = gr->faces();
+
+  std::set<GFace*> allFacesSet;
+  for(unsigned int i = 0; i < regions.size(); i++){
+    std::list<GFace*> f = regions[i]->faces();
+    allFacesSet.insert(f.begin(), f.end());
+    f = regions[i]->embeddedFaces();
+    allFacesSet.insert(f.begin(), f.end());
+  }
+  std::list<GFace*> allFaces;
+  for(std::set<GFace*>::iterator it = allFacesSet.begin();
+      it != allFacesSet.end(); it++){
+    allFaces.push_back(*it);
+  }
+  gr->set(allFaces);
+
+  try{
+    meshGRegionBoundaryRecovery *init = new meshGRegionBoundaryRecovery();
+    init->reconstructmesh(gr);
+    delete init;
+  }
+  catch(int err){
+    Msg::Error("Could not recover boundary: error %d", err);
+  }
+
+  // sort triangles in all model faces in order to be able to search in vectors
+  std::list<GFace*>::iterator itf =  allFaces.begin();
+  while(itf != allFaces.end()){
+    compareMTriangleLexicographic cmp;
+    std::sort((*itf)->triangles.begin(), (*itf)->triangles.end(), cmp);
+    ++itf;
+  }
+
+  // restore the initial set of faces
+  gr->set(faces);
+
+  bool _BL = modifyInitialMeshForTakingIntoAccountBoundaryLayers(gr,sqr);
+
+  // now do insertion of points
+  if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_DEL)
+    bowyerWatsonFrontalLayers(gr, false);
+  else if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL_HEX)
+    bowyerWatsonFrontalLayers(gr, true);
+  else if(CTX::instance()->mesh.algo3d == ALGO_3D_MMG3D){
+    refineMeshMMG(gr);
+  }
+  else if(!Filler::get_nbr_new_vertices() && !LpSmoother::get_nbr_interior_vertices()){
+    insertVerticesInRegion(gr,2000000000,!_BL);
+  }
+  */
+}
+
 #if defined(HAVE_NETGEN)
 
 namespace nglib {
@@ -1396,12 +1536,15 @@ void deMeshGRegion::operator() (GRegion *gr)
   gr->deleteMesh();
 }
 
+/// X_1 (1-u-v) + X_2 u + X_3 v = P_x + t N_x
+/// Y_1 (1-u-v) + Y_2 u + Y_3 v = P_y + t N_y
+/// Z_1 (1-u-v) + Z_2 u + Z_3 v = P_z + t N_z
+
 int intersect_line_triangle(double X[3], double Y[3], double Z[3] ,
-                            double P[3], double N[3])
+                            double P[3], double N[3], const double eps_prec)
 {
   double mat[3][3], det;
   double b[3], res[3];
-  const double eps_prec = 1.e-9;
 
   mat[0][0] = X[1] - X[0];
   mat[0][1] = X[2] - X[0];
@@ -1420,8 +1563,10 @@ int intersect_line_triangle(double X[3], double Y[3], double Z[3] ,
   b[2] = P[2] - Z[0];
 
   if(!sys3x3_with_tol(mat, b, res, &det))
-    return 0;
-
+    {
+      return 0;
+    }
+  //  printf("coucou %g %g %g\n",res[0],res[1],res[2]);
   if(res[0] >= eps_prec && res[0] <= 1.0 - eps_prec &&
      res[1] >= eps_prec && res[1] <= 1.0 - eps_prec &&
      1 - res[0] - res[1] >= eps_prec && 1 - res[0] - res[1] <= 1.0 - eps_prec){
@@ -1435,6 +1580,7 @@ int intersect_line_triangle(double X[3], double Y[3], double Z[3] ,
     return 0;
   }
   else{
+    printf("non robust stuff\n");
     // the intersection is not robust, try another triangle
     return -10000;
   }
@@ -1491,7 +1637,7 @@ void meshNormalsPointOutOfTheRegion(GRegion *gr)
                              t_b->getVertex(2)->y()};
             double Z_b[3] = {t_b->getVertex(0)->z(), t_b->getVertex(1)->z(),
                              t_b->getVertex(2)->z()};
-            int inters = intersect_line_triangle(X_b, Y_b, Z_b, P, N);
+            int inters = intersect_line_triangle(X_b, Y_b, Z_b, P, N, 1.e-9);
             nb_intersect += inters;
           }
         }
@@ -1544,20 +1690,18 @@ void meshGRegion::operator() (GRegion *gr)
 
   std::list<GFace*> faces = gr->faces();
 
-  // REMOVE SANITY CHECK FOR DELAUNAY : PYRAMIDS AVAILABLE
-  // sanity check
-
+  // sanity check for frontal algo
   if(CTX::instance()->mesh.algo3d == ALGO_3D_FRONTAL){
     for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){
       if((*it)->quadrangles.size()){
-	Msg::Error("Cannot tetrahedralize volume with quadrangles on boundary");
+	Msg::Error("Cannot use frontal 3D algorithm with quadrangles on boundary");
 	return;
       }
     }
   }
 
   // replace discreteFaces by their compounds
-  if( 1 || gr->geomType() == GEntity::CompoundVolume){
+  {
     std::set<GFace*> mySet;
     std::list<GFace*>::iterator it = faces.begin();
     while(it != faces.end()){
@@ -1572,8 +1716,6 @@ void meshGRegion::operator() (GRegion *gr)
     gr->set(faces);
   }
 
-  std::list<GFace*> myface = gr->faces();
-
   if(CTX::instance()->mesh.algo3d != ALGO_3D_FRONTAL){
     delaunay.push_back(gr);
   }
@@ -1639,6 +1781,7 @@ void optimizeMeshGRegionGmsh::operator() (GRegion *gr)
   optimizeMesh(gr, QMTET_2);
 }
 
+
 bool buildFaceSearchStructure(GModel *model, fs_cont &search)
 {
   search.clear();
@@ -1653,13 +1796,9 @@ bool buildFaceSearchStructure(GModel *model, fs_cont &search)
 
   std::set<GFace*>::iterator fit = faces_to_consider.begin();
   while(fit != faces_to_consider.end()){
-    for(unsigned int i = 0; i < (*fit)->triangles.size(); i++){
-      MVertex *p1 = (*fit)->triangles[i]->getVertex(0);
-      MVertex *p2 = (*fit)->triangles[i]->getVertex(1);
-      MVertex *p3 = (*fit)->triangles[i]->getVertex(2);
-      MVertex *p = std::min(p1, std::min(p2, p3));
-      search.insert(std::pair<MVertex*, std::pair<MTriangle*, GFace*> >
-                    (p, std::pair<MTriangle*, GFace*>((*fit)->triangles[i], *fit)));
+    for(unsigned int i = 0; i < (*fit)->getNumMeshElements(); i++){
+      MFace ff = (*fit)->getMeshElement(i)->getFace(0);
+      search[ff] = *fit;
     }
     ++fit;
   }
@@ -1687,21 +1826,21 @@ bool buildEdgeSearchStructure(GModel *model, es_cont &search)
 GFace *findInFaceSearchStructure(MVertex *p1, MVertex *p2, MVertex *p3,
                                  const fs_cont &search)
 {
-  MVertex *p = std::min(p1, std::min(p2, p3));
+  MFace ff(p1,p2,p3);
+  fs_cont::const_iterator it = search.find(ff);
+  if (it == search.end())return 0;
+  return it->second;
+}
 
-  for(fs_cont::const_iterator it = search.lower_bound(p);
-      it != search.upper_bound(p);
-      ++it){
-    MTriangle *t = it->second.first;
-    GFace *gf= it->second.second;
-    if((t->getVertex(0) == p1 || t->getVertex(0) == p2 || t->getVertex(0) == p3) &&
-       (t->getVertex(1) == p1 || t->getVertex(1) == p2 || t->getVertex(1) == p3) &&
-       (t->getVertex(2) == p1 || t->getVertex(2) == p2 || t->getVertex(2) == p3))
-      return gf;
-  }
-  return 0;
+GFace *findInFaceSearchStructure(const MFace &ff,
+                                 const fs_cont &search)
+{
+  fs_cont::const_iterator it = search.find(ff);
+  if (it == search.end())return 0;
+  return it->second;
 }
 
+
 GEdge *findInEdgeSearchStructure(MVertex *p1, MVertex *p2, const es_cont &search)
 {
   MVertex *p = std::min(p1, p2);
diff --git a/Mesh/meshGRegion.h b/Mesh/meshGRegion.h
index 2469a17..5e7ab28 100644
--- a/Mesh/meshGRegion.h
+++ b/Mesh/meshGRegion.h
@@ -9,6 +9,7 @@
 #include <list>
 #include <vector>
 #include <map>
+#include "MFace.h"
 
 class GModel;
 class GRegion;
@@ -55,10 +56,11 @@ int MeshTransfiniteVolume(GRegion *gr);
 int SubdivideExtrudedMesh(GModel *m);
 void carveHole(GRegion *gr, int num, double distance, std::vector<int> &surfaces);
 
-typedef std::multimap<MVertex*, std::pair<MTriangle*, GFace*> > fs_cont ;
+typedef std::map<MFace,GFace*,Less_Face > fs_cont ;
 typedef std::multimap<MVertex*, std::pair<MLine*, GEdge*> > es_cont ;
 GFace* findInFaceSearchStructure(MVertex *p1, MVertex *p2, MVertex *p3,
                                  const fs_cont &search);
+GFace* findInFaceSearchStructure(const MFace &f, const fs_cont &search);
 GEdge* findInEdgeSearchStructure(MVertex *p1, MVertex *p2, const es_cont &search);
 bool buildFaceSearchStructure(GModel *model, fs_cont &search);
 bool buildEdgeSearchStructure(GModel *model, es_cont &search);
diff --git a/Mesh/meshGRegionDelaunayInsertion.cpp b/Mesh/meshGRegionDelaunayInsertion.cpp
index c34c4a8..29d6c58 100644
--- a/Mesh/meshGRegionDelaunayInsertion.cpp
+++ b/Mesh/meshGRegionDelaunayInsertion.cpp
@@ -18,6 +18,7 @@
 #include "MTriangle.h"
 #include "Numeric.h"
 #include "Context.h"
+#include "HilbertCurve.h"
 
 int MTet4::radiusNorm = 2;
 static double LIMIT_ = 1;
@@ -66,18 +67,27 @@ int MTet4::inCircumSphere(const double *p) const
 static int faces[4][3] = {{0,1,2}, {0,2,3}, {0,3,1}, {1,3,2}};
 
 struct faceXtet{
-  MVertex *v[3];
+  MVertex *v[3],*unsorted[3];
   MTet4 *t1;
   int i1;
-  faceXtet(MTet4 *_t, int iFac) : t1(_t), i1(iFac)
+  faceXtet(MTet4 *_t=0, int iFac=0) : t1(_t), i1(iFac)
   {
-    v[0] = t1->tet()->getVertex(faces[iFac][0]);
-    v[1] = t1->tet()->getVertex(faces[iFac][1]);
-    v[2] = t1->tet()->getVertex(faces[iFac][2]);
-    std::sort(v, v + 3);
+    MVertex *v0 = t1->tet()->getVertex(faces[iFac][0]);
+    MVertex *v1 = t1->tet()->getVertex(faces[iFac][1]);
+    MVertex *v2 = t1->tet()->getVertex(faces[iFac][2]);
+
+    unsorted[0] = v0;
+    unsorted[1] = v1;
+    unsorted[2] = v2;
+    
+    v[0] = std::min(std::min(v0,v1),v2);
+    v[2] = std::max(std::max(v0,v1),v2);
+    v[1] = (v0 != v[0] && v0 != v[2]) ? v0 : (v1 != v[0] && v1 != v[2]) ? v1 : v2;
+    //
+    //    std::sort(v, v + 3);
   }
 
-  inline MVertex * getVertex (int i) const { return t1->tet()->getVertex(faces[i1][i]);}
+  inline MVertex * getVertex (int i) const { return unsorted[i];}
 
  inline bool operator < (const faceXtet & other) const
   {
@@ -107,30 +117,56 @@ struct faceXtet{
   }
 };
 
-template <class ITER>
-void connectTets_vector(ITER beg, ITER end)
+void connectTets_vector2(std::vector<MTet4*> &t, std::vector<faceXtet> &conn)
 {
-  //  std::set<faceXtet> conn;
-  std::vector<faceXtet> conn;
-  while (beg != end){
-    if (!(*beg)->isDeleted()){
-      for (int i = 0; i < 4; i++){
-        faceXtet fxt(*beg, i);
-	std::vector<faceXtet>::iterator found  = std::find(conn.begin(), conn.end(), fxt);
-	//        std::set<faceXtet>::iterator found = conn.find(fxt);
-        if (found == conn.end())
-	  conn.push_back(fxt);
-	// conn.insert(fxt);
-        else if (found->t1 != *beg){
-          found->t1->setNeigh(found->i1, *beg);
-          (*beg)->setNeigh(i, found->t1);
-        }
+  conn.clear();
+  //  unsigned int k = 0;
+  for (unsigned int i=0;i<t.size();i++){
+    if (!t[i]->isDeleted()){
+      for (int j = 0; j < 4; j++){
+	conn.push_back(faceXtet(t[i], j));
       }
     }
-    ++beg;
+  }
+  if (!conn.size())return;
+  std::sort(conn.begin(), conn.end());
+  
+  for (unsigned int i=0;i<conn.size()-1;i++){
+    faceXtet &f1  = conn[i];
+    faceXtet &f2  = conn[i+1];
+    if (f1 == f2 && f1.t1 != f2.t1){
+      f1.t1->setNeigh(f1.i1, f2.t1);
+      f2.t1->setNeigh(f2.i1, f1.t1);
+      ++i;
+    }
   }
 }
 
+
+// template <class ITER>
+// void connectTets_vector(ITER beg, ITER end)
+// {
+//   //  std::set<faceXtet> conn;
+//   std::vector<faceXtet> conn;
+//   while (beg != end){
+//     if (!(*beg)->isDeleted()){
+//       for (int i = 0; i < 4; i++){
+//         faceXtet fxt(*beg, i);
+// 	std::vector<faceXtet>::iterator found  = std::find(conn.begin(), conn.end(), fxt);
+// 	//        std::set<faceXtet>::iterator found = conn.find(fxt);
+//         if (found == conn.end())
+// 	  conn.push_back(fxt);
+// 	// conn.insert(fxt);
+//         else if (found->t1 != *beg){
+//           found->t1->setNeigh(found->i1, *beg);
+//           (*beg)->setNeigh(i, found->t1);
+//         }
+//       }
+//     }
+//     ++beg;
+//   }
+// }
+
 template <class ITER>
 void connectTets(ITER beg, ITER end, std::set<MFace, Less_Face> *allEmbeddedFaces = 0)
 {
@@ -295,19 +331,8 @@ void recurFindCavity(std::list<faceXtet> & shell,
                      MVertex *v ,
                      MTet4 *t)
 {
-  // Msg::Info("tet %d %d %d %d",t->tet()->getVertex(0)->getNum(),
-  //     t->tet()->getVertex(1)->getNum(),
-  //     t->tet()->getVertex(2)->getNum(),
-  //     t->tet()->getVertex(3)->getNum());
-
-  // invariant : this one has to be inserted in the cavity
-  // consider this tet deleted
-  // remove its reference to its neighbors
   t->setDeleted(true);
-  // the cavity that has to be removed
-  // because it violates delaunay criterion
   cavity.push_back(t);
-
   for (int i = 0; i < 4; i++){
     MTet4 *neigh = t->getNeigh(i) ;
     faceXtet fxt (t, i);
@@ -322,49 +347,64 @@ void recurFindCavity(std::list<faceXtet> & shell,
       }
     }
   }
-  //  printf("cavity size %d\n",cavity.size());
 }
 
-void nonrecurFindCavity(std::list<faceXtet> & shell,
-                     std::list<MTet4*> & cavity,
+void recurFindCavity(std::vector<faceXtet> & shell,
+                     std::vector<MTet4*> & cavity,
                      MVertex *v ,
                      MTet4 *t)
 {
-  // Msg::Info("tet %d %d %d %d",t->tet()->getVertex(0)->getNum(),
-  //     t->tet()->getVertex(1)->getNum(),
-  //     t->tet()->getVertex(2)->getNum(),
-  //     t->tet()->getVertex(3)->getNum());
-
-  // invariant : this one has to be inserted in the cavity
-  // consider this tet deleted
-  // remove its reference to its neighbors
-
-  std::stack<MTet4*> _stack;
-  _stack.push(t);
-  while(!_stack.empty()){
-    t = _stack.top();
-    _stack.pop();
-    t->setDeleted(true);
-    // the cavity that has to be removed
-    // because it violates delaunay criterion
-    cavity.push_back(t);
-
-    for (int i = 0; i < 4; i++){
-      MTet4 *neigh = t->getNeigh(i) ;
-      if (!neigh)
-	shell.push_back(faceXtet(t, i));
-      else  if (!neigh->isDeleted()){
-	int circ = neigh->inCircumSphere(v);
-	if (circ && (neigh->onWhat() == t->onWhat()))
-	  _stack.push(neigh);
-	else
-	  shell.push_back(faceXtet(t, i));
-      }
+  t->setDeleted(true);
+  cavity.push_back(t);
+  for (int i = 0; i < 4; i++){
+    MTet4 *neigh = t->getNeigh(i) ;
+    faceXtet fxt (t, i);
+    if (!neigh)
+      shell.push_back(fxt);
+    else  if (!neigh->isDeleted()){
+      int circ = neigh->inCircumSphere(v);
+      if (circ && (neigh->onWhat() == t->onWhat()))
+        recurFindCavity(shell, cavity, v, neigh);
+      else
+        shell.push_back(fxt);      
     }
   }
-  //  printf("cavity size %d\n",cavity.size());
 }
 
+
+// void nonrecurFindCavity(std::vector<faceXtet> & shell,
+// 			std::vector<MTet4*> & cavity,
+// 			MVertex *v ,
+// 			MTet4 *t,
+// 			std::stack<MTet4*> &_stack)
+// {
+  
+//   _stack.push(t);
+//   while(!_stack.empty()){
+//     t = _stack.top();
+//     _stack.pop();
+//     if (!t->isDeleted()){
+//       t->setDeleted(true);
+//       cavity.push_back(t);
+      
+//       for (int i = 0; i < 4; i++){
+// 	MTet4 *neigh = t->getNeigh(i) ;
+// 	faceXtet fxt (t, i);
+// 	if (!neigh)
+// 	  shell.push_back(fxt);
+// 	else  if (!neigh->isDeleted()){
+// 	  int circ = neigh->inCircumSphere(v);
+// 	  if (circ && (neigh->onWhat() == t->onWhat()))
+// 	    _stack.push(neigh);
+// 	  else
+// 	    shell.push_back(fxt);
+// 	}
+//       }
+//     }
+//   }
+//   //  printf("cavity size %d\n",cavity.size());
+// }
+
 void printTets (const char *fn, std::list<MTet4*> &cavity, bool force = false )
 {
   FILE *f = Fopen (fn,"w");
@@ -394,7 +434,8 @@ bool insertVertexB(std::list<faceXtet> &shell,
 		   std::vector<double> & vSizesBGM,
 		   std::set<MTet4*,compareTet4Ptr> *activeTets = 0 )
 {
-  std::list<MTet4*> new_cavity;
+  std::vector<faceXtet> conn;
+  std::vector<MTet4*> new_cavity;
   // check that volume is conserved
     double newVolume = 0;
     double oldVolume = 0;
@@ -415,19 +456,19 @@ bool insertVertexB(std::list<faceXtet> &shell,
   while (it != shell.end()){
     MTetrahedron *tr = new MTetrahedron(it->getVertex(0), it->getVertex(1), it->getVertex(2), v);
 
-    //    double lc = .25 * (vSizes[tr->getVertex(0)->getIndex()] +
-    //		       vSizes[tr->getVertex(1)->getIndex()] +
-    //		       vSizes[tr->getVertex(2)->getIndex()] +
-    //		       vSizes[tr->getVertex(3)->getIndex()]);
-    //    double lcBGM = .25 * (vSizesBGM[tr->getVertex(0)->getIndex()] +
-    //			  vSizesBGM[tr->getVertex(1)->getIndex()] +
-    //			  vSizesBGM[tr->getVertex(2)->getIndex()] +
-    //			  vSizesBGM[tr->getVertex(3)->getIndex()]);
-    //    double LL = std::min(lc, lcBGM);
+        double lc = .25 * (vSizes[tr->getVertex(0)->getIndex()] +
+    		       vSizes[tr->getVertex(1)->getIndex()] +
+    		       vSizes[tr->getVertex(2)->getIndex()] +
+    		       vSizes[tr->getVertex(3)->getIndex()]);
+        double lcBGM = .25 * (vSizesBGM[tr->getVertex(0)->getIndex()] +
+    			  vSizesBGM[tr->getVertex(1)->getIndex()] +
+    			  vSizesBGM[tr->getVertex(2)->getIndex()] +
+    			  vSizesBGM[tr->getVertex(3)->getIndex()]);
+        double LL = std::min(lc, lcBGM);
 
     MTet4 *t4 = myFactory.Create(tr, vSizes, vSizesBGM);
     t4->setOnWhat(t->onWhat());
-    /*
+    
     double d1 = sqrt((it->v[0]->x() - v->x()) * (it->v[0]->x() - v->x()) +
                      (it->v[0]->y() - v->y()) * (it->v[0]->y() - v->y()) +
                      (it->v[0]->z() - v->z()) * (it->v[0]->z() - v->z()));
@@ -438,8 +479,8 @@ bool insertVertexB(std::list<faceXtet> &shell,
                      (it->v[2]->y() - v->y()) * (it->v[2]->y() - v->y()) +
                      (it->v[2]->z() - v->z()) * (it->v[2]->z() - v->z()));
 
-    if (d1 < LL * .25 || d2 < LL * .25 || d3 < LL * .25) onePointIsTooClose = true;
-    */
+    if (d1 < LL * .05 || d2 < LL * .05 || d3 < LL * .05) onePointIsTooClose = true;
+    
     newTets[k++] = t4;
     // all new tets are pushed front in order to ba able to destroy
     // them if the cavity is not star shaped around the new vertex.
@@ -460,11 +501,11 @@ bool insertVertexB(std::list<faceXtet> &shell,
   //    if (!onePointIsTooClose){
       if (fabs(oldVolume - newVolume) < 1.e-10 * oldVolume &&
 	            !onePointIsTooClose){
-    connectTets_vector(new_cavity.begin(), new_cavity.end());
+	connectTets_vector2(new_cavity,conn);
     allTets.insert(newTets, newTets + shell.size());
 
     if (activeTets){
-      for (std::list<MTet4*>::iterator i = new_cavity.begin(); i != new_cavity.end(); ++i){
+      for (std::vector<MTet4*>::iterator i = new_cavity.begin(); i != new_cavity.end(); ++i){
         int active_face;
         if(isActive(*i, LIMIT_, active_face) && (*i)->getRadius() > LIMIT_){
           if ((*activeTets).find(*i) == (*activeTets).end())
@@ -656,11 +697,16 @@ void non_recursive_classify(MTet4 *t, std::list<MTet4*> &theRegion,
   std::stack<MTet4*> _stackounette;
   _stackounette.push(t);
 
+  bool touchesOutsideBox = false;
+
   while(!_stackounette.empty()){
     t = _stackounette.top();
     _stackounette.pop();
-    if (!t) Msg::Fatal("a tet is not connected by a boundary face");
-    if (!t->onWhat()) {
+    if (!t) {
+      //      Msg::Fatal("a tet is not connected by a boundary face");
+      touchesOutsideBox = true;
+    }
+    else if (!t->onWhat()) {
       theRegion.push_back(t);
       t->setOnWhat(bidon);
       bool FF[4] = {0,0,0,0};
@@ -681,6 +727,7 @@ void non_recursive_classify(MTet4 *t, std::list<MTet4*> &theRegion,
       }
     }
   }
+  if (touchesOutsideBox)faces_bound.clear();
 }
 
 
@@ -872,6 +919,7 @@ void adaptMeshGRegion::operator () (GRegion *gr)
 //template <class CONTAINER, class DATA>
 void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm)
 {
+  
   typedef std::list<MTet4 *> CONTAINER ;
   CONTAINER allTets;
   for(unsigned int i = 0; i < gr->tetrahedra.size(); i++){
@@ -926,6 +974,7 @@ void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm)
   int nbESwap = 0, nbFSwap = 0, nbReloc = 0;
 
   while (1){
+    //    printf("coucou\n");
     std::vector<MTet4*> newTets;
     for (CONTAINER::iterator it = allTets.begin(); it != allTets.end(); ++it){
       if (!(*it)->isDeleted()){
@@ -940,20 +989,30 @@ void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm)
         }
       }
     }
+    //    printf("coucou\n");
 
     illegals.clear();
     for (int i = 0; i < nbRanges; i++) quality_ranges[i] = 0;
 
+    //   printf("coucou\n");
     for (CONTAINER::iterator it = allTets.begin(); it != allTets.end(); ++it){
       if (!(*it)->isDeleted()){
+	for (int i=0;i<4;i++)
+	  for (int j=i+1;j<4;j++)
+	    if ((*it)->tet()->getVertex(i) == (*it)->tet()->getVertex(j))
+	      printf("argh\n");
+
         double qq = (*it)->getQuality();
-        if (qq < qMin)
+        if (qq < qMin){
+	  //	  printf("cacze\n");
           for (int i = 0; i < 6; i++){
+	    //	    printf("%d\n",i);
             if (edgeSwap(newTets, *it, i, qm)) {
               nbESwap++;
               break;
             }
           }
+	}
         if (!(*it)->isDeleted()){
           if (qq < sliverLimit) illegals.push_back(*it);
           for (int i = 0; i < nbRanges; i++){
@@ -964,6 +1023,7 @@ void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm)
         }
       }
     }
+    //    printf("coucou\n");
 
     if (0 && !newTets.size()){
       int nbSlivers = 0;
@@ -981,6 +1041,7 @@ void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm)
       break;
     }
 
+    //    printf("coucou\n");
     // add all the new tets in the container
     for(unsigned int i = 0; i < newTets.size(); i++){
       if(!newTets[i]->isDeleted()){
@@ -991,6 +1052,7 @@ void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm)
         delete newTets[i];
       }
     }
+    //    printf("coucou\n");
 
     // relocate vertices
     for (CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it){
@@ -1003,6 +1065,7 @@ void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm)
       }
     }
 
+    //    printf("coucou\n");
     double totalVolumeb = 0.0;
     double worst = 1.0;
     double avg = 0;
@@ -1017,16 +1080,17 @@ void optimizeMesh(GRegion *gr, const qualityMeasure4Tet &qm)
         totalVolumeb += vol;
       }
     }
+    //    printf("coucou\n");
     double t2 = Cpu();
     Msg::Info("Opti : (%d,%d,%d) = %12.5E QBAD %12.5E QAVG %12.5E (%8.3f sec)",
               nbESwap, nbFSwap, nbReloc, totalVolumeb, worst, avg / count, t2 - t1);
   }
 
   if (illegals.size()){
-    Msg::Info("Opti : %d illegal tets are still in the mesh", illegals.size());
+    Msg::Info("Opti : %d ill-shaped tets are still in the mesh", illegals.size());
   }
   else{
-    Msg::Info("Opti : no illegal tets in the mesh ;-)");
+    Msg::Info("Opti : no ill-shaped tets in the mesh ;-)");
   }
 
   for (int i = 0; i < nbRanges; i++){
@@ -1152,7 +1216,7 @@ void insertVerticesInRegion (GRegion *gr, int maxVert, bool _classify)
   MTet4Factory myFactory(1600000);
   std::set<MTet4*, compareTet4Ptr> &allTets = myFactory.getAllTets();
   int NUM = 0;
-  
+
 
   { // leave this in a block so the map gets deallocated directly
     std::map<MVertex*, double> vSizesMap;
@@ -1185,7 +1249,7 @@ void insertVerticesInRegion (GRegion *gr, int maxVert, bool _classify)
   // Msg::Info("reclassifying %d tets", allTets.size());
 
 
-  if (_classify) {    
+  if (_classify) {
     fs_cont search;
     buildFaceSearchStructure(gr->model(), search);
     for(MTet4Factory::iterator it = allTets.begin(); it != allTets.end(); ++it){
@@ -1213,7 +1277,7 @@ void insertVerticesInRegion (GRegion *gr, int maxVert, bool _classify)
     }
     search.clear();
   }
-  else {    
+  else {
     // FIXME ... too simple
     for(MTet4Factory::iterator it = allTets.begin(); it != allTets.end(); ++it)
       (*it)->setOnWhat(gr);
@@ -1230,9 +1294,9 @@ void insertVerticesInRegion (GRegion *gr, int maxVert, bool _classify)
   createAllEmbeddedFaces (gr, allEmbeddedFaces);
   connectTets(allTets.begin(), allTets.end(),&allEmbeddedFaces);
   Msg::Debug("All %d tets were connected", allTets.size());
-  
+
   // here the classification should be done
-  
+
   int ITER = 0, REALCOUNT = 0;
   int NB_CORRECTION_OF_CAVITY = 0;
   int COUNT_MISS_1 = 0;
@@ -1612,3 +1676,237 @@ void bowyerWatsonFrontalLayers(GRegion *gr, bool hex)
   MTet4::radiusNorm = 2;
   LIMIT_ = 1;
 }
+
+
+///// do a 3D delaunay mesh assuming a set of vertices
+
+static void initialCube (std::vector<MVertex*> &v,
+			 MVertex *box[8],
+			 std::vector<MTet4*> &t){
+  SBoundingBox3d bbox ;
+  for (size_t i=0;i<v.size();i++){
+    MVertex *pv = v[i];
+    bbox += SPoint3(pv->x(),pv->y(),pv->z());
+  }
+  bbox *= 1.3;
+  box[0] = new MVertex (bbox.min().x(),bbox.min().y(),bbox.min().z());
+  box[1] = new MVertex (bbox.max().x(),bbox.min().y(),bbox.min().z());
+  box[2] = new MVertex (bbox.max().x(),bbox.max().y(),bbox.min().z());
+  box[3] = new MVertex (bbox.min().x(),bbox.max().y(),bbox.min().z());
+  box[4] = new MVertex (bbox.min().x(),bbox.min().y(),bbox.max().z());
+  box[5] = new MVertex (bbox.max().x(),bbox.min().y(),bbox.max().z());
+  box[6] = new MVertex (bbox.max().x(),bbox.max().y(),bbox.max().z());
+  box[7] = new MVertex (bbox.min().x(),bbox.max().y(),bbox.max().z());
+  std::vector<MTetrahedron*> t_box;
+  MTetrahedron *t0 = new MTetrahedron (box[2],box[7],box[3],box[1]);
+  MTetrahedron *t1 = new MTetrahedron (box[0],box[7],box[1],box[3]);
+  MTetrahedron *t2 = new MTetrahedron (box[6],box[1],box[7],box[2]);
+  MTetrahedron *t3 = new MTetrahedron (box[0],box[1],box[7],box[4]);
+  MTetrahedron *t4 = new MTetrahedron (box[1],box[4],box[5],box[7]);
+  MTetrahedron *t5 = new MTetrahedron (box[1],box[7],box[5],box[6]);
+  t.push_back(new MTet4(t0,0.0));
+  t.push_back(new MTet4(t1,0.0));
+  t.push_back(new MTet4(t2,0.0));
+  t.push_back(new MTet4(t3,0.0));
+  t.push_back(new MTet4(t4,0.0));
+  t.push_back(new MTet4(t5,0.0));
+  connectTets(t);
+}
+
+int straddling_segment_intersects_triangle(SPoint3 &p1,SPoint3 &p2,
+					   SPoint3 &q1,SPoint3 &q2,
+					   SPoint3 &q3) 
+{
+  double s1 = robustPredicates::orient3d(p1, p2, q2, q3);
+  double s2 = robustPredicates::orient3d(p1, p2, q3, q1);
+  double s3 = robustPredicates::orient3d(p1, p2, q1, q2);
+
+  if (s1*s2 < 0.0 || s2 * s3 < 0.0) return false;
+
+
+  double s4 = robustPredicates::orient3d(q1, q2, q3, p1);
+  double s5 = robustPredicates::orient3d(q3, q2, q1, p2);
+
+  return (s4*s5 >= 0) ;
+}
+
+static MTet4* search4Tet (MTet4 *t, MVertex *v, int _size,int & ITER) {
+  if (t->inCircumSphere(v)) return t;
+  SPoint3 p2 (v->x(),v->y(),v->z());
+  std::set<MTet4*> path;
+  while (1){
+    path.insert(t);
+    SPoint3 p1 = t->tet()->barycenter();
+    int found = -1;
+    MTet4 *neighOK = 0;
+    for (int i = 0; i < 4; i++){
+      MTet4 *neigh = t->getNeigh(i);
+      if (neigh && path.find(neigh) == path.end()){
+	neighOK = neigh;
+	faceXtet fxt (t, i);
+
+	SPoint3 q1(fxt.v[0]->x(),fxt.v[0]->y(),fxt.v[0]->z());
+	SPoint3 q2(fxt.v[1]->x(),fxt.v[1]->y(),fxt.v[1]->z());
+	SPoint3 q3(fxt.v[2]->x(),fxt.v[2]->y(),fxt.v[2]->z());
+	
+
+	if ( straddling_segment_intersects_triangle (p1,p2,q1,q2,q3)){
+	  found = i;
+	  break;
+	}
+      }
+    }
+    if (found < 0){
+      if (neighOK)t = neighOK;
+      else return 0;
+    }
+    else{
+      t = t->getNeigh(found);
+    }
+    if (t->inCircumSphere(v)) {
+      return t;
+    }
+    if (ITER++ > .5*_size) {
+      break;
+    }
+  }
+  return 0;
+}
+
+MTet4 * getTetToBreak (MVertex *v, std::vector<MTet4*> &t, int &NB_GLOBAL_SEARCH, int &ITER){
+  // last inserted is used as starting point
+  // we know it is not deleted
+  unsigned int k = t.size() - 1;
+  while(t[k]->isDeleted()){
+    k--;
+  }
+  MTet4 *start = t[k];
+  start = search4Tet (start,v,(int)t.size(),ITER);
+  if (start)return start;
+  //  printf("Global Search has to be done\n");
+  NB_GLOBAL_SEARCH++;
+  for (size_t i = 0;i<t.size();i++){
+    if (!t[i]->isDeleted() && t[i]->inCircumSphere(v))return t[i];
+  }
+  return 0;
+}
+
+bool tetOnBox (MTetrahedron *t, MVertex *box[8]){
+  for (size_t i = 0;i<4;i++)
+    for (size_t j = 0;j<8;j++)
+      if (t->getVertex(i) == box[j])return true;
+  return false;
+}
+
+
+void sanityCheck1(MTet4 *t)
+{
+}
+
+
+
+ void delaunayMeshIn3D(std::vector<MVertex*> &v, std::vector<MTetrahedron*> &result, bool removeBox)
+{
+  std::vector<MTet4*> t;
+  t.reserve (v.size()*7);
+  std::vector<faceXtet> conn;
+  std::vector<faceXtet> shell;
+  std::vector<MTet4*> cavity;
+  MVertex *box[8];
+  initialCube (v,box,t);
+
+  int NB_GLOBAL_SEARCH = 0;
+  int AVG_ITER = 0;
+  SortHilbert(v);
+  double t1 = Cpu();
+
+  /// double ta=0,tb=0,tc=0,td=0,T;
+  
+  for (size_t i=0;i<v.size();i++){
+    MVertex *pv = v[i];
+
+    int NITER = 0;
+    //    T = Cpu();
+    MTet4 * found = getTetToBreak (pv,t,NB_GLOBAL_SEARCH,NITER);
+    //    ta += Cpu()-T;
+    AVG_ITER += NITER;
+    if(!found) {
+      Msg::Error("cannot insert a point in 3D Delaunay");
+      continue;
+    }
+    shell.clear();
+    cavity.clear();
+    //    T = Cpu();
+    recurFindCavity(shell, cavity, pv, found);
+    //    tb += Cpu()-T;
+    double V = 0.0;
+    for (unsigned int k=0;k<cavity.size();k++)V+=fabs(cavity[k]->tet()->getVolume());
+
+    std::vector<MTet4*> extended_cavity;
+    double Vb = 0.0;    
+
+    //    T = Cpu();
+    for (unsigned int count = 0; count < shell.size(); count++){
+      const faceXtet &fxt = shell[count];
+      MTetrahedron *tr;
+      MTet4 *t4;
+      MVertex *v0 = fxt.getVertex(0);
+      MVertex *v1 = fxt.getVertex(1);
+      MVertex *v2 = fxt.getVertex(2);
+      MTet4 *otherSide = fxt.t1->getNeigh(fxt.i1);
+      if (count < cavity.size()){
+	t4 = cavity[count];
+	tr = t4->tet() ;
+	tr->setVertex(0,v0);
+	tr->setVertex(1,v1);
+	tr->setVertex(2,v2);
+	tr->setVertex(3,pv);	
+      }
+      else{
+	tr = new MTetrahedron(v0,v1,v2,pv);
+	t4 = new MTet4(tr, 0.0);
+	t.push_back(t4);
+      }
+      Vb+= fabs(tr->getVolume());
+      extended_cavity.push_back(t4);
+      if (otherSide)
+	extended_cavity.push_back(otherSide);
+    }
+    //    tc += Cpu()-T;
+    
+    if (fabs(Vb-V) > 1.e-8 * (Vb+V))printf("%12.5E %12.5E\n",Vb,V);
+    
+    // reuse memory --> reinitialize MTet4s
+    for (unsigned int k=0;k<std::min(cavity.size(),shell.size());k++){
+      cavity[k]->setDeleted(false);
+      for (unsigned int l=0;l<4;l++){
+    	cavity[k]->setNeigh(l,0);
+      }
+    }
+    //    T = Cpu();
+    connectTets_vector2(extended_cavity,conn);
+    //    td += Cpu()-T;
+  }
+
+  double t2 = Cpu();
+  Msg::Info("Delaunay 3D done for %d points : CPU = %g, %d global searches, AVG walk size %g",v.size(), t2-t1,NB_GLOBAL_SEARCH,1.+(double)AVG_ITER/v.size());
+  //  printf("%d tets allocated (to compare with 7 #V = %d)\n",t.size(),7*v.size());
+  //  printf("%g %g %g %g --> %g(%g)\n",ta,tb,tc,td,t2-t1,ta+tb+tc+td);
+  
+  //  FILE *f = fopen ("tet.pos","w");
+  //  fprintf(f,"View \"\"{\n");
+  for (size_t i = 0;i<t.size();i++){
+    if (t[i]->isDeleted() || (removeBox && tetOnBox (t[i]->tet(),box))) delete t[i]->tet();
+    else {
+      result.push_back(t[i]->tet());
+      //      t[i]->tet()->writePOS (f, false,false,true,false,false,false);
+    }
+    delete t[i];
+  }
+  
+  if (removeBox)for (int i=0;i<8;i++)delete box[i];
+  else for (int i=0;i<8;i++)v.push_back(box[i]);
+
+  //    fprintf(f,"};\n");
+  //    fclose(f);
+}
diff --git a/Mesh/meshGRegionDelaunayInsertion.h b/Mesh/meshGRegionDelaunayInsertion.h
index 15a467c..996c8c7 100644
--- a/Mesh/meshGRegionDelaunayInsertion.h
+++ b/Mesh/meshGRegionDelaunayInsertion.h
@@ -124,6 +124,7 @@ class MTet4
   inline void setQuality(const double &q){ circum_radius = q; } 
   inline MTetrahedron *tet() const { return base; }
   inline MTetrahedron *&tet() { return base; }
+  inline void setTet(MTetrahedron *t) { base=t; }
   inline void setNeigh(int iN, MTet4 *n) { neigh[iN] = n; }
   inline MTet4 *getNeigh(int iN) const { return neigh[iN]; }
   int inCircumSphere(const double *p) const; 
@@ -173,6 +174,8 @@ class MTet4
 
 void connectTets(std::list<MTet4*> &);
 void connectTets(std::vector<MTet4*> &);
+// IN --> Vertices ----  OUT --> Tets
+void delaunayMeshIn3D(std::vector<MVertex*> &, std::vector<MTetrahedron*> &, bool removeBox = true);
 void insertVerticesInRegion(GRegion *gr, int maxVert = 2000000000, bool _classify = true);
 void bowyerWatsonFrontalLayers(GRegion *gr, bool hex);
 GRegion *getRegionFromBoundingFaces(GModel *model,
diff --git a/Mesh/meshGRegionLocalMeshMod.cpp b/Mesh/meshGRegionLocalMeshMod.cpp
index 0f29102..a89b892 100644
--- a/Mesh/meshGRegionLocalMeshMod.cpp
+++ b/Mesh/meshGRegionLocalMeshMod.cpp
@@ -60,16 +60,19 @@ bool buildEdgeCavity(MTet4 *t, int iLocalEdge, MVertex **v1, MVertex **v2,
   *v1 = t->tet()->getVertex(edges[iLocalEdge][0]);
   *v2 = t->tet()->getVertex(edges[iLocalEdge][1]);
 
+  // the 5 - i th edge contains the other 2 points of the tet
   MVertex *lastinring = t->tet()->getVertex(edges[5 - iLocalEdge][0]);
   ring.push_back(lastinring);
   cavity.push_back(t);
 
-  // a change here for hybrid meshes
-
-  //int ITER = 0;
   while (1){
     MVertex *ov1 = t->tet()->getVertex(edges[5 - iLocalEdge][0]);
     MVertex *ov2 = t->tet()->getVertex(edges[5 - iLocalEdge][1]);
+    //    printf("edge %d %d tet %d %d %d %d\n",(*v1)->getNum(),(*v2)->getNum(),
+    //	   t->tet()->getVertex(0)->getNum(),
+    //	   t->tet()->getVertex(1)->getNum(),
+    //	   t->tet()->getVertex(2)->getNum(),
+    //	   t->tet()->getVertex(3)->getNum());
     int K = ov1 == lastinring ? 1 : 0;
     lastinring = ov1 == lastinring ? ov2 : ov1;
     // look in the 2 faces sharing this edge the one that has vertex
@@ -104,7 +107,7 @@ bool buildEdgeCavity(MTet4 *t, int iLocalEdge, MVertex **v1, MVertex **v2,
       return false;
     }
     // FIXME when hybrid mesh, this loops for ever
-    //    if (cavity.size() > 10)return false;
+    if (cavity.size() > 1000) return false;
     //    printf("%d %d\n",ITER++, cavity.size());
   }
   computeNeighboringTetsOfACavity (cavity,outside);
@@ -214,7 +217,9 @@ bool edgeSwap(std::vector<MTet4 *> &newTets,
   std::vector<MVertex*> ring;
   MVertex *v1, *v2;
 
+  //  printf("a\n");
   bool closed = buildEdgeCavity(tet, iLocalEdge, &v1, &v2, cavity, outside, ring);
+  //  printf("b\n");
 
   if (!closed) return false;
 
@@ -448,8 +453,9 @@ void buildVertexCavity_recur(MTet4 *t, MVertex *v, std::vector<MTet4*> &cavity)
     }
   }
   if (iV == -1){
-    Msg::Fatal("trying to build a cavity of tets for a vertex that does not "
-        "belong to this tet");
+    Msg::Error("Trying to build a cavity of tets for a vertex that does not "
+               "belong to this tet");
+    return;
   }
   for (int i = 0; i < 3; i++){
     MTet4 *neigh = t->getNeigh(vFac[iV][i]);
diff --git a/Mesh/meshGRegionMMG3D.cpp b/Mesh/meshGRegionMMG3D.cpp
index 169bf55..7f14197 100644
--- a/Mesh/meshGRegionMMG3D.cpp
+++ b/Mesh/meshGRegionMMG3D.cpp
@@ -124,6 +124,8 @@ static void gmsh2MMG(GRegion *gr, MMG_pMesh mmg, MMG_pSol sol,
 
     MVertex *v = *it;
     double U = 0, V = 0;
+    if (!v->onWhat()) continue;
+
     if (v->onWhat()->dim() == 1){
       v->getParameter(0,U);
     }
@@ -131,6 +133,7 @@ static void gmsh2MMG(GRegion *gr, MMG_pMesh mmg, MMG_pSol sol,
       v->getParameter(0,U);
       v->getParameter(1,V);
     }
+
     //double lc = BGM_MeshSize(v->onWhat(), U,V,v->x(), v->y(), v->z());
     SMetric3 m = BGM_MeshMetric(v->onWhat(), U,V,v->x(), v->y(), v->z());
 
diff --git a/Mesh/meshPartition.cpp b/Mesh/meshPartition.cpp
index 19241e9..833609c 100644
--- a/Mesh/meshPartition.cpp
+++ b/Mesh/meshPartition.cpp
@@ -462,7 +462,7 @@ int PartitionGraph(Graph &graph, meshPartitionOptions &options)
           metisOptions[3] = options.refine_algorithm;
           metisOptions[4] = 0;
           for(int u=0;u<options.ncon;u++){
-           ubvec[u]=1.03;
+            ubvec[u] = (float)1.03;
           }
           graph.fillWithMultipleWeights(options.ncon,options.getWeightMapV(), options.getWeightMapE());
           if (options.num_partitions > 1) {
diff --git a/Mesh/meshRefine.cpp b/Mesh/meshRefine.cpp
index e12dd8f..48c13fe 100644
--- a/Mesh/meshRefine.cpp
+++ b/Mesh/meshRefine.cpp
@@ -31,6 +31,53 @@ class MVertexLessThanParam{
   }
 };
 
+// Set BM data on vertex
+static void setBLData(MVertex *v)
+{
+  switch (v->onWhat()->dim()) {
+    case 1: {
+      MEdgeVertex *ve = dynamic_cast<MEdgeVertex*>(v);
+      if (ve) ve->bl_data = new MVertexBoundaryLayerData();
+      break;
+    }
+    case 2: {
+      MFaceVertex *vf = dynamic_cast<MFaceVertex*>(v);
+      if (vf) vf->bl_data = new MVertexBoundaryLayerData();
+      break;
+    }
+  }
+}
+
+// If all low-order nodes in are marked as BL, then mark high-order nodes as BL (only works in 2D)
+static bool setBLData(MElement *el)
+{
+  // Check whether all low-order nodes are marked as BL nodes (only works in 2D)
+  for(int i=0; i<el->getNumPrimaryVertices(); i++) {
+    MVertex *v = el->getVertex(i);
+    bool isBL = false;
+    switch (v->onWhat()->dim()) {
+      case 0:
+        isBL = true;
+        break;
+      case 1: {
+        MEdgeVertex *ve = dynamic_cast<MEdgeVertex*>(v);
+        if (ve && ve->bl_data) isBL = true;
+        break;
+      }
+      case 2: {
+        MFaceVertex *vf = dynamic_cast<MFaceVertex*>(v);
+        if (vf && vf->bl_data) isBL = true;
+        break;
+      }
+    }
+    if (!isBL) return false;
+  }
+  // Mark high-order nodes as BL nodes (only works in 2D)
+  for(int i=el->getNumPrimaryVertices(); i<el->getNumVertices(); i++)
+    setBLData(el->getVertex(i));
+  return true;
+}
+
 static void Subdivide(GEdge *ge)
 {
   std::vector<MLine*> lines2;
@@ -39,6 +86,7 @@ static void Subdivide(GEdge *ge)
     if(l->getNumVertices() == 3){
       lines2.push_back(new MLine(l->getVertex(0), l->getVertex(2)));
       lines2.push_back(new MLine(l->getVertex(2), l->getVertex(1)));
+      setBLData(l);
     }
     delete l;
   }
@@ -69,6 +117,7 @@ static void Subdivide(GFace *gf, bool splitIntoQuads, bool splitIntoHexas,
           (new MTriangle(t->getVertex(3), t->getVertex(1), t->getVertex(4)));
         triangles2.push_back
           (new MTriangle(t->getVertex(5), t->getVertex(4), t->getVertex(2)));
+        setBLData(t);
       }
       delete t;
     }
@@ -87,6 +136,7 @@ static void Subdivide(GFace *gf, bool splitIntoQuads, bool splitIntoHexas,
         (new MQuadrangle(q->getVertex(8), q->getVertex(5), q->getVertex(2), q->getVertex(6)));
       quadrangles2.push_back
         (new MQuadrangle(q->getVertex(7), q->getVertex(8), q->getVertex(6), q->getVertex(3)));
+      setBLData(q);
     }
     delete q;
   }
@@ -119,6 +169,7 @@ static void Subdivide(GFace *gf, bool splitIntoQuads, bool splitIntoHexas,
           (new MQuadrangle(t->getVertex(3), t->getVertex(1), t->getVertex(4), newv));
         quadrangles2.push_back
           (new MQuadrangle(t->getVertex(5), newv,t->getVertex(4), t->getVertex(2)));
+        if (setBLData(t)) setBLData(newv);
         delete t;
       }
     }
@@ -137,6 +188,7 @@ static void Subdivide(GRegion *gr, bool splitIntoHexas, faceContainer &faceVerti
     std::vector<MTetrahedron*> tetrahedra2;
     for(unsigned int i = 0; i < gr->tetrahedra.size(); i++){
       MTetrahedron *t = gr->tetrahedra[i];
+      // FIXME: we should choose the template to maximize the quality
       if(t->getNumVertices() == 10){
         tetrahedra2.push_back
           (new MTetrahedron(t->getVertex(0), t->getVertex(4), t->getVertex(7), t->getVertex(6)));
@@ -154,6 +206,7 @@ static void Subdivide(GRegion *gr, bool splitIntoHexas, faceContainer &faceVerti
           (new MTetrahedron(t->getVertex(7), t->getVertex(8), t->getVertex(5), t->getVertex(6)));
         tetrahedra2.push_back
           (new MTetrahedron(t->getVertex(4), t->getVertex(7), t->getVertex(5), t->getVertex(6)));
+        setBLData(t);
       }
       delete t;
     }
@@ -188,9 +241,11 @@ static void Subdivide(GRegion *gr, bool splitIntoHexas, faceContainer &faceVerti
       hexahedra2.push_back
         (new MHexahedron(h->getVertex(26), h->getVertex(23), h->getVertex(14), h->getVertex(24),
                          h->getVertex(25), h->getVertex(18), h->getVertex(6), h->getVertex(19)));
+      setBLData(h);
     }
     delete h;
   }
+
   if(splitIntoHexas){
     for(unsigned int i = 0; i < gr->tetrahedra.size(); i++){
       MTetrahedron *t = gr->tetrahedra[i];
@@ -224,6 +279,10 @@ static void Subdivide(GRegion *gr, bool splitIntoHexas, faceContainer &faceVerti
         hexahedra2.push_back
           (new MHexahedron(t->getVertex(3),  t->getVertex(9), newv[1], t->getVertex(7),
                            t->getVertex(8), newv[3], newv[4], newv[2]));
+        if (setBLData(t)) {
+          setBLData(newv[0]); setBLData(newv[1]);
+          setBLData(newv[2]); setBLData(newv[3]); setBLData(newv[4]);
+        }
         delete t;
       }
     }
@@ -267,6 +326,9 @@ static void Subdivide(GRegion *gr, bool splitIntoHexas, faceContainer &faceVerti
         hexahedra2.push_back
           (new MHexahedron(p->getVertex(11), p->getVertex(16), newv[2], p->getVertex(17),
                            p->getVertex(5), p->getVertex(13), newv[1], p->getVertex(14)));
+        if (setBLData(p)) {
+          setBLData(newv[0]); setBLData(newv[1]); setBLData(newv[2]);
+        }
       }
     }
     gr->prisms.clear();
@@ -302,6 +364,7 @@ static void Subdivide(GRegion *gr, bool splitIntoHexas, faceContainer &faceVerti
       prisms2.push_back
         (new MPrism(p->getVertex(17), p->getVertex(16), p->getVertex(15),
                     p->getVertex(14), p->getVertex(13), p->getVertex(12)));
+      setBLData(p);
     }
     delete p;
   }
@@ -351,6 +414,7 @@ static void Subdivide(GRegion *gr, bool splitIntoHexas, faceContainer &faceVerti
         ((new MTetrahedron(p->getVertex(12), p->getVertex(10), p->getVertex(11), p->getVertex(13))));
       gr->tetrahedra.push_back
         ((new MTetrahedron(p->getVertex(7), p->getVertex(6), p->getVertex(12), p->getVertex(13))));
+      setBLData(p);
     }
     delete p;
   }
@@ -386,7 +450,8 @@ void RefineMesh(GModel *m, bool linear, bool splitIntoQuads, bool splitIntoHexas
   for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it)
     Subdivide(*it, splitIntoHexas, faceVertices);
 
-
+  // Check all 3D elements for negative volume and reverse if needed
+  m->setAllVolumesPositive();
 
   double t2 = Cpu();
   Msg::StatusBar(true, "Done refining mesh (%g s)", t2 - t1);
diff --git a/Mesh/periodical.cpp b/Mesh/periodical.cpp
index 6028889..b2b3d6b 100644
--- a/Mesh/periodical.cpp
+++ b/Mesh/periodical.cpp
@@ -185,8 +185,13 @@ void voroMetal3D::execute(std::vector<SPoint3>& vertices,std::vector<double>& ra
   delta = 0;
 
   container contA(min_x-delta,max_x+delta,min_y-delta,max_y+delta,min_z-delta,max_z+delta,6,6,6,true,true,true,vertices.size());
+  //container contA(min_x-delta,max_x+delta,min_y-delta,max_y+delta,min_z-delta,max_z+delta,6,6,6,false,false,false,vertices.size());
   container_poly contB(min_x-delta,max_x+delta,min_y-delta,max_y+delta,min_z-delta,max_z+delta,6,6,6,true,true,true,vertices.size());
 
+  //  wall_cylinder cyl(.5,.5,-3,0,0,6,.4);
+  //  contA.add_wall(cyl);
+
+
   for(i=0;i<vertices.size();i++){
     if(radical==0){
       contA.put(i,vertices[i].x(),vertices[i].y(),vertices[i].z());
@@ -196,8 +201,8 @@ void voroMetal3D::execute(std::vector<SPoint3>& vertices,std::vector<double>& ra
     }
   }
 
-  number = 0;	
-	
+  number = 0;
+
   c_loop_all loopA(contA);
   c_loop_all loopB(contB);
 
@@ -231,11 +236,11 @@ void voroMetal3D::execute(std::vector<SPoint3>& vertices,std::vector<double>& ra
   }
 
   std::ofstream file6("table.txt");
-	
+
   for(i=0;i<vertices.size();i++){
     file6 << i+1 << " " << table[i]+1 << "\n";
-  }	
-	
+  }
+
   initialize_counter();
 
   min_area = 1000000000.0;
@@ -553,7 +558,7 @@ void voroMetal3D::correspondance(double e, double xMax, double yMax, double zMax
   }
 
   for(i=0;i<faces.size();i++){
-    markings.insert(std::pair<GFace*,bool>(faces[i],0));
+    markings.insert(std::pair<GFace*,bool>(faces[i],false));
   }
 
   count = 0;
diff --git a/Mesh/surfaceFiller.cpp b/Mesh/surfaceFiller.cpp
index 0777ea7..a6d8d81 100644
--- a/Mesh/surfaceFiller.cpp
+++ b/Mesh/surfaceFiller.cpp
@@ -27,10 +27,17 @@
 #include "BackgroundMesh.h"
 #include "intersectCurveSurface.h"
 
+using namespace std;
+
 static const double FACTOR = .71;
 static const int NUMDIR = 3;
-//static const double DIRS [NUMDIR] = {0.0};
 static const double DIRS [NUMDIR] = {0.0, M_PI/20.,-M_PI/20.};
+//PE MODIF
+//static const int NUMDIR = 1;
+//static const double DIRS [NUMDIR] = {0.0};
+// END PE MODIF
+
+
 
 /// a rectangle in the tangent plane is transformed
 /// into a parallelogram. We define an exclusion zone
@@ -39,6 +46,7 @@ static const double DIRS [NUMDIR] = {0.0, M_PI/20.,-M_PI/20.};
 /// right spacing in the tangent plane
 
 #if defined(HAVE_RTREE)
+
 struct surfacePointWithExclusionRegion {
   MVertex *_v;
   SPoint2 _center;
@@ -119,6 +127,27 @@ struct my_wrapper {
   my_wrapper (SPoint2 sp) : _tooclose (false), _p(sp) {}
 };
 
+struct smoothness_point_pair{
+  double rank;
+  surfacePointWithExclusionRegion* ptr;
+};
+
+class compareSurfacePointWithExclusionRegionPtr_Smoothness
+{
+  public:
+    inline bool operator () (const smoothness_point_pair &a, const smoothness_point_pair &b)  const
+    {
+      if (a.rank == b.rank){
+        if(a.ptr->_distanceSummed > b.ptr->_distanceSummed) return false;
+        if(a.ptr->_distanceSummed < b.ptr->_distanceSummed) return true;
+        return a.ptr<b.ptr;
+      }
+      // else
+      return (a.rank < b.rank);
+    }
+};
+
+
 class compareSurfacePointWithExclusionRegionPtr
 {
  public:
@@ -388,16 +417,377 @@ bool compute4neighbors (GFace *gf,   // the surface
   }
   return true;
 }
+
+// ---------------------------------------------------------------------------------------------
+
+// recover element around vertex v and interpolate smoothness on this element...
+double get_smoothness(MVertex *v, GFace *gf, const map<MVertex*,double> &vertices2smoothness){
+  // recover element around MVertex v
+  //cout << "Looking for element around point (" << v->x() << "," << v->y() << "," << v->z() << ")" << endl;
+  SPoint3 sp3(v->x(), v->y(), v->z());
+  SPoint2 param_point;
+  reparamMeshVertexOnFace(v, gf, param_point);
+  MElement *elem = backgroundMesh::current()->getMeshElementByCoord(param_point[0], param_point[1], 0.);
+  if (!elem){
+    elem = backgroundMesh::current()->getMeshElementByCoord(param_point[0], param_point[1], 0., false);
+    if (!elem)
+      cout << " ------ WARNING !!! surfaceFiller : get_smoothness : No element found for coordinate (" << sp3.x() << "," << sp3.y() << "," << sp3.z() << ")" << endl;
+  }
+
+  // recover element's vertices:
+  vector<MVertex*> localvertices;
+  for (int ivert=0;ivert<elem->getNumVertices();ivert++){
+    MVertex *temp = elem->getVertex(ivert);
+    localvertices.push_back(temp);
+//    cout << " made of vertex " << temp->x() << "," << temp->y() << "," << temp->z() << endl;
+  }
+
+  // recover parametrisation uvw
+  double uvw[3],xyz[3];
+  xyz[0] = param_point[0];
+  xyz[1] = param_point[1];
+  xyz[2] = 0.;
+  elem->xyz2uvw(xyz, uvw);
+//  cout << "xyz is " << xyz[0] << ","  << xyz[1] << ","  << xyz[2] << endl;
+//  cout << "uvw is " << uvw[0] << ","  << uvw[1] << ","  << uvw[2] << endl;
+
+  // interpolate :
+  double val[3];
+  int i=0;
+  for (vector<MVertex*>::iterator it = localvertices.begin();it!=localvertices.end();it++){
+    MVertex *localv = *it;
+    map<MVertex*,double>::const_iterator itfind = vertices2smoothness.find(localv);
+    if (itfind==vertices2smoothness.end()){
+      cerr << "WARNING: surfaceFiller : get_smoothness : BACKGROUNDMESH VERTEX NOT FOUND IN SMOOTHNESS COMPUTATION !!! ABORTING..." << endl;
+      throw;
+    }
+//    cout << "nodal value: " << itfind->second << endl;
+    val[i++] = itfind->second;
+  }
+//  cout << "uvw is " << uvw[0] << "  " <<  uvw[1] << "  " <<  uvw[2] << endl;
+  double res = elem->interpolate(val, uvw[0], uvw[1], uvw[2]);
+//  cout << " THE VALUE = " << res << endl;
+  return res;
+}
+
+// ---------------------------------------------------------------------------------------------
+
+void print_nodal_info_int(string filename, map<MVertex*, int> &mapp){
+  ofstream out(filename.c_str());
+
+  out << "View \"\"{" << endl;
+  for (map<MVertex*, int>::iterator it = mapp.begin();it!=mapp.end();it++){
+    MVertex *v = it->first;
+    out << "SP( " << v->x() << "," << v->y() << "," << v->z() << "){" << it->second << "};" << endl;;
+  }
+  out << "};" << endl;
+
+  out.close();
+}
+
+// ---------------------------------------------------------------------------------------------
+
+void print_nodal_info_double(string filename, map<MVertex*, double> &mapp){
+  ofstream out(filename.c_str());
+
+  out << "View \"\"{" << endl;
+  for (map<MVertex*, double>::iterator it = mapp.begin();it!=mapp.end();it++){
+    MVertex *v = it->first;
+    out << "SP( " << v->x() << "," << v->y() << "," << v->z() << "){" << it->second << "};" << endl;;
+  }
+  out << "};" << endl;
+
+  out.close();
+}
+
+// ---------------------------------------------------------------------------------------------
+
+void export_point(surfacePointWithExclusionRegion *sp, int DIR, FILE *crossf, GFace *gf){
+  // get the unit normal at that point
+  Pair<SVector3, SVector3> der = gf->firstDer(sp->_center);
+  SVector3 s1 = der.first();
+  SVector3 s2 = der.second();
+  SVector3 n = crossprod(s1,s2);
+  n.normalize();
+  SVector3 basis_u = s1; basis_u.normalize();
+  SVector3 basis_v = crossprod(n,basis_u);
+
+  double quadAngle  = backgroundMesh::current()->getAngle (sp->_center[0],sp->_center[1],0) + DIRS[DIR];
+
+  // normalize vector t1 that is tangent to gf at midpoint
+  SVector3 t1 = basis_u * cos (quadAngle) + basis_v * sin (quadAngle) ;
+  t1.normalize();
+
+  // compute the second direction t2 and normalize (t1,t2,n) is the tangent frame
+  SVector3 t2 = crossprod(n,t1);
+  t2.normalize();
+
+  //  double scale = DIR+1.;
+  SMetric3 metricField;
+  double L = backgroundMesh::current()->operator()(sp->_center[0],sp->_center[1],0.0);
+  metricField = SMetric3(1./(L*L));
+  FieldManager *fields = gf->model()->getFields();
+  if(fields->getBackgroundField() > 0){
+    Field *f = fields->get(fields->getBackgroundField());
+    if (!f->isotropic()){
+      (*f)(sp->_v->x(),sp->_v->y(),sp->_v->z(), metricField,gf);
+    }
+    else {
+      L = (*f)(sp->_v->x(),sp->_v->y(),sp->_v->z(), gf);
+      metricField = SMetric3(1./(L*L));
+    }
+  }
+  double size_1 = sqrt(1. / dot(t1,metricField,t1));
+  double size_2 = sqrt(1. / dot(t2,metricField,t2));
+
+  //  fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",sp->_v->x(),sp->_v->y(),sp->_v->z(),t1.x()*scale,t1.y()*scale,t1.z()*scale);
+  //  fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",sp->_v->x(),sp->_v->y(),sp->_v->z(),t2.x()*scale,t2.y()*scale,t2.z()*scale);
+  //  fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",sp->_v->x(),sp->_v->y(),sp->_v->z(),-t1.x()*scale,-t1.y()*scale,-t1.z()*scale);
+  //  fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",sp->_v->x(),sp->_v->y(),sp->_v->z(),-t2.x()*scale,-t2.y()*scale,-t2.z()*scale);
+  fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",sp->_v->x(),sp->_v->y(),sp->_v->z(),t1.x()*size_1,t1.y()*size_1,t1.z()*size_1);
+  fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",sp->_v->x(),sp->_v->y(),sp->_v->z(),t2.x()*size_2,t2.y()*size_2,t2.z()*size_2);
+  fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",sp->_v->x(),sp->_v->y(),sp->_v->z(),-t1.x()*size_1,-t1.y()*size_1,-t1.z()*size_1);
+  fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",sp->_v->x(),sp->_v->y(),sp->_v->z(),-t2.x()*size_2,-t2.y()*size_2,-t2.z()*size_2);
+}
+
+// ---------------------------------------------------------------------------------------------
+
+bool get_local_sizes_and_directions(const MVertex *v_center, const SPoint2 &midpoint, const int DIR, GFace* gf, double (&covar1)[2], double (&covar2)[2], double &size_param_1, double &size_param_2, double &L, SVector3 &t1, SVector3 &t2, SVector3 &n, FILE *crossf=NULL){
+//bool get_RK_stuff(const MVertex *v_center, const SPoint2 &midpoint, const int DIR, GFace* gf, double (&covar1)[2], double (&covar2)[2], double &size_param_1, double &size_param_2, double &L, SVector3 &t1, SVector3 &t2, SVector3 &n, FILE *crossf, const SVector3 &previous_t1, const SVector3 &previous_t2, bool use_previous_basis=false, bool export_cross=true){
+
+  // !!!!!!!!!!!! check if point is in domain (for RK !!!)
+  if (!backgroundMesh::current()->inDomain(midpoint.x(),midpoint.y(),0)) return false;
+
+  SMetric3 metricField;
+  L = backgroundMesh::current()->operator()(midpoint[0],midpoint[1],0.0);
+  //  printf("L = %12.5E\n",L);
+  metricField = SMetric3(1./(L*L));
+  FieldManager *fields = gf->model()->getFields();
+  if(fields->getBackgroundField() > 0){
+    Field *f = fields->get(fields->getBackgroundField());
+    if (!f->isotropic()){
+      (*f)(v_center->x(),v_center->y(),v_center->z(), metricField,gf);
+    }
+    else {
+      L = (*f)(v_center->x(),v_center->y(),v_center->z(), gf);
+      metricField = SMetric3(1./(L*L));
+    }
+  }
+
+  // get the unit normal at that point
+  Pair<SVector3, SVector3> der = gf->firstDer(SPoint2(midpoint[0],midpoint[1]));
+  SVector3 s1 = der.first();
+  SVector3 s2 = der.second();
+  n = crossprod(s1,s2);
+  n.normalize();
+
+  double M = dot(s1,s1);
+  double N = dot(s2,s2);
+  double E = dot(s1,s2);
+
+  // compute the first fundamental form i.e. the metric tensor at the point
+  // M_{ij} = s_i \cdot s_j
+  double metric[2][2] = {{M,E},{E,N}};
+
+  //  printf("%d %g %g %g\n",gf->tag(),s1.x(),s1.y(),s1.z());
+
+  SVector3 basis_u = s1; basis_u.normalize();
+  SVector3 basis_v = crossprod(n,basis_u);
+
+  double quadAngle  = backgroundMesh::current()->getAngle (midpoint[0],midpoint[1],0) + DIRS[DIR];
+  //double quadAngle  = atan2(midpoint[0],midpoint[1]);
+
+  // normalize vector t1 that is tangent to gf at midpoint
+  t1 = basis_u * cos (quadAngle) + basis_v * sin (quadAngle) ;
+  t1.normalize();
+
+  // compute the second direction t2 and normalize (t1,t2,n) is the tangent frame
+  t2 = crossprod(n,t1);
+  t2.normalize();
+
+
+  //  std::cout << std::endl;
+  //  std::cout << "basis uv : (" << basis_u(0) << "," <<  basis_u(1) << ") (" << basis_v(0) << "," << basis_v(1) << std::endl;
+  //  std::cout << "t        : (" << t1(0) << "," <<  t1(1) << ") (" << t2(0) << "," << t2(1) << std::endl;
+
+//  if (use_previous_basis){
+//    std::map<double, double> angles;
+//    SVector3 temp = crossprod(previous_t1, t1);
+//    double a = atan2(dot(t1, previous_t1), sign(dot(temp,n))*temp.norm() );
+//    angles.insert(std::make_pair(abs(a),a));
+//    temp = crossprod(previous_t2, t1);
+//    a = atan2(dot(t1, previous_t2), sign(dot(temp,n))*temp.norm());
+//    angles.insert(std::make_pair(abs(a),a));
+//    temp = crossprod(-1.*previous_t1, t1);
+//    a = atan2(dot(t1, -1.*previous_t1), sign(dot(temp,n))*temp.norm());
+//    angles.insert(std::make_pair(abs(a),a));
+//    temp = crossprod(-1.*previous_t2, t1);
+//    a = atan2(dot(t1, -1.*previous_t2), sign(dot(temp,n))*temp.norm());
+//    angles.insert(std::make_pair(abs(a),a));
+//    //    std::cout << "angles: " << std::endl;
+//    //    for (int i=0;i<4;i++)  std::cout << angles[i] << "  " << std::endl;
+//    double min_angle = -(angles.begin()->second);
+//    //    std::cout << "min angle = " << min_angle << std::endl;
+//    t1 =  cos(min_angle)*previous_t1 + sin(min_angle)*previous_t2;
+//    t2 = -sin(min_angle)*previous_t1 + cos(min_angle)*previous_t2;
+//    //    std::cout << "new corrected t        : (" << t1(0) << "," <<  t1(1) << ") (" << t2(0) << "," << t2(1) << std::endl;
+//  }
+
+  double size_1 = sqrt(1. / dot(t1,metricField,t1));
+  double size_2 = sqrt(1. / dot(t2,metricField,t2));
+
+
+  if (crossf){
+    if (DIR == 0 && crossf)fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",v_center->x(),v_center->y(),v_center->z(),t1.x()*size_1,t1.y()*size_1,t1.z()*size_1);
+    if (DIR == 0 && crossf)fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",v_center->x(),v_center->y(),v_center->z(),t2.x()*size_2,t2.y()*size_2,t2.z()*size_2);
+    if (DIR == 0 && crossf)fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",v_center->x(),v_center->y(),v_center->z(),-t1.x()*size_1,-t1.y()*size_1,-t1.z()*size_1);
+    if (DIR == 0 && crossf)fprintf(crossf,"VP(%g,%g,%g) {%g,%g,%g};\n",v_center->x(),v_center->y(),v_center->z(),-t2.x()*size_2,-t2.y()*size_2,-t2.z()*size_2);
+  }
+
+  // compute covariant coordinates of t1 and t2
+  // t1 = a s1 + b s2 -->
+  // t1 . s1 = a M + b E
+  // t1 . s2 = a E + b N --> solve the 2 x 2 system
+  // and get covariant coordinates a and b
+  double rhs1[2] = {dot(t1,s1),dot(t1,s2)};
+  bool singular = false;
+  if (!sys2x2(metric,rhs1,covar1)){
+    Msg::Info("Argh surface %d %g %g %g -- %g %g %g -- %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z(),size_1,size_2);
+    covar1[1] = 1.0; covar1[0] = 0.0;
+    singular = true;
+  }
+  double rhs2[2] = {dot(t2,s1),dot(t2,s2)};
+  if (!sys2x2(metric,rhs2,covar2)){
+    Msg::Info("Argh surface %d %g %g %g -- %g %g %g",gf->tag(),s1.x(),s1.y(),s1.z(),s2.x(),s2.y(),s2.z());
+    covar2[0] = 1.0; covar2[1] = 0.0;
+    singular = true;
+  }
+
+  // transform the sizes with respect to the metric
+  // consider a vector v of size 1 in the parameter plane
+  // its length is sqrt (v^T M v) --> if I want a real size
+  // of size1 in direction v, it should be sqrt(v^T M v) * size1
+  double l1 = sqrt(covar1[0]*covar1[0]+covar1[1]*covar1[1]);
+  double l2 = sqrt(covar2[0]*covar2[0]+covar2[1]*covar2[1]);
+
+  covar1[0] /= l1;covar1[1] /= l1;
+  covar2[0] /= l2;covar2[1] /= l2;
+
+  size_param_1  = size_1 / sqrt (  M*covar1[0]*covar1[0]+
+      2*E*covar1[1]*covar1[0]+
+      N*covar1[1]*covar1[1]);
+  size_param_2  = size_2 / sqrt (  M*covar2[0]*covar2[0]+
+      2*E*covar2[1]*covar2[0]+
+      N*covar2[1]*covar2[1]);
+  if (singular){
+    size_param_1 = size_param_2 = std::min (size_param_1,size_param_2);
+  }
+
+
+  return true;
+}
+
 #endif
 
-// fills a surface with points in order to build a nice
-// quad mesh ------------
-void packingOfParallelograms(GFace* gf,  std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics){
-  #if defined(HAVE_RTREE)
+// ---------------------------------------------------------------------------------------------
 
+// using fifo based on smoothness criteria
+void packingOfParallelogramsSmoothness(GFace* gf,  std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics){
+  cout << endl << "------------------------------------------" << endl << "   PACKINGOFPARALLELOGRAMS: NEW ALGO BASED ON SMOOTHNESS" << endl << "------------------------------------------" << endl;
+#if defined(HAVE_RTREE)
   const bool goNonLinear = true;
 
-  //  FILE *f = Fopen ("parallelograms.pos","w");
+  const bool debug = false;
+
+  // build vertex -> neighbors table
+  multimap<MVertex*,MVertex*> vertex2vertex;
+  for (std::vector<MElement*>::iterator it = backgroundMesh::current()->begin_triangles();it!=backgroundMesh::current()->end_triangles();it++){
+    MElement *e = *it;
+    for (int i=0;i<e->getNumVertices();i++){
+      MVertex *current = e->getVertex(i);
+      for (int j=0;j<e->getNumVertices();j++){
+        if (i==j) continue;
+        MVertex *neighbor = e->getVertex(j);
+        vertex2vertex.insert(make_pair(current,neighbor));
+      }
+    }
+  }
+
+  // build table vertex->smoothness
+  map<MVertex*,double> vertices2smoothness;
+  map<MVertex*, double> smoothness_essai;
+  for (std::vector<MVertex*>::iterator it = backgroundMesh::current()->begin_vertices();it!=backgroundMesh::current()->end_vertices();it++){
+    MVertex *v = *it;
+
+    SPoint2 param_point(v->x(),v->y());GPoint gpt = gf->point(param_point); MVertex v_real(gpt.x(),gpt.y(),gpt.z());
+    SVector3 t1,t2,n;double covar1[2],covar2[2],L,size_param_1,size_param_2;
+    get_local_sizes_and_directions(&v_real, param_point, 0, gf, covar1, covar2, size_param_1, size_param_2, L, t1, t2, n);
+
+    // compare to all neighbors...
+    pair<multimap<MVertex*,MVertex*>::iterator, multimap<MVertex*,MVertex*>::iterator> range = vertex2vertex.equal_range(v);
+    SVector3 t1_nb,t2_nb,n_nb;double covar1_nb[2],covar2_nb[2],L_nb,size_param_1_nb,size_param_2_nb;
+    double maxprod,angle=0.;
+    int N=0;
+    for (multimap<MVertex*,MVertex*>::iterator itneighbor = range.first;itneighbor!=range.second;itneighbor++){
+      N++;
+      maxprod=0.;
+      MVertex *v_nb = itneighbor->second;
+      SPoint2 param_point_nb(v_nb->x(),v_nb->y());GPoint gpt_nb = gf->point(param_point_nb); MVertex v_real_nb(gpt_nb.x(),gpt_nb.y(),gpt_nb.z());
+      get_local_sizes_and_directions(&v_real_nb, param_point_nb, 0, gf, covar1_nb, covar2_nb, size_param_1_nb, size_param_2_nb, L_nb, t1_nb, t2_nb, n_nb);
+      // angle comparison...
+      maxprod = std::max(maxprod, fabs(t1[0]*t1_nb[0] + t1[1]*t1_nb[1]));
+      maxprod = std::max(maxprod, fabs(t1[0]*t2_nb[0] + t1[1]*t2_nb[1]));
+      angle += fabs(acos(max(min(maxprod,1.),-1.)));
+    }
+    angle /= N;
+    vertices2smoothness[v] = angle;
+  }
+
+//  if (debug){
+//    stringstream ss;
+//    ss << "backgroundmesh_smoothness_" << gf->tag() << ".pos";
+//    backgroundMesh::current()->print(ss.str().c_str(),gf, vertices2smoothness);
+//  }
+
+
+  // --------------- export de smoothness comme elements.... -----------------------
+  if (debug){
+    stringstream ss;
+    ss << "backgroundmesh_element_smoothness_" << gf->tag() << ".pos";
+    ofstream out(ss.str().c_str());
+    out << "View \"directions\" {" << endl;
+    for (std::vector<MElement*>::iterator it = backgroundMesh::current()->begin_triangles();it!=backgroundMesh::current()->end_triangles();it++){
+      MElement *e = *it;
+      vector<MVertex *> nodes;
+      vector<double> smoothtemp;
+      for (int i=0;i<3;i++){
+        MVertex *v = e->getVertex(i);
+        nodes.push_back(v);
+        smoothtemp.push_back(vertices2smoothness[v]);
+      }
+      out << "ST(";
+      for (int i=0;i<3;i++){
+        GPoint pp = gf->point(SPoint2(nodes[i]->x(),nodes[i]->y()));
+        out << pp.x() << "," << pp.y() << "," << pp.z();
+        if (i!=2) out << ",";
+      }
+      out << "){";
+      for (int i=0;i<3;i++){
+        out << (1.-(smoothtemp[i]/M_PI*4.));
+        if (i!=2) out << ",";
+      }
+      out << "};" << endl;
+
+    }
+    out << "};" << endl;
+    out.close();
+  }
+  //                   --------------- END ----------------
+
+
+  // for debug check...
+  int priority_counter=0;
+  map<MVertex*,int> vert_priority;
 
   // get all the boundary vertices
   std::set<MVertex*> bnd_vertices;
@@ -409,9 +799,8 @@ void packingOfParallelograms(GFace* gf,  std::vector<MVertex*> &packed, std::vec
     }
   }
 
-  // put boundary vertices in a fifo queue
-  // std::queue<surfacePointWithExclusionRegion*> fifo;
-  std::set<surfacePointWithExclusionRegion*,  compareSurfacePointWithExclusionRegionPtr> fifo;
+  //  --------- put boundary vertices in a fifo queue ---------------
+  std::set<smoothness_point_pair, compareSurfacePointWithExclusionRegionPtr_Smoothness> fifo;
   std::vector<surfacePointWithExclusionRegion*> vertices;
   // put the RTREE
   RTree<surfacePointWithExclusionRegion*,double,2,double> rtree;
@@ -420,65 +809,87 @@ void packingOfParallelograms(GFace* gf,  std::vector<MVertex*> &packed, std::vec
   std::set<MVertex*>::iterator it =  bnd_vertices.begin() ;
 
   char NAME[345]; sprintf(NAME,"crossReal%d.pos",gf->tag());
-  FILE *crossf = Fopen (NAME,"w");
+  FILE *crossf=NULL;
+  if (debug){
+    crossf = Fopen (NAME,"w");
+  }
   if (crossf)fprintf(crossf,"View \"\"{\n");
   for (; it !=  bnd_vertices.end() ; ++it){
     SPoint2 midpoint;
-    compute4neighbors (gf, *it, midpoint, goNonLinear, newp, metricField,crossf);
+    //compute4neighbors_RK2 (gf, *it, midpoint, goNonLinear, newp, metricField,crossf);
+    compute4neighbors(gf, *it, midpoint, goNonLinear, newp, metricField,crossf);
     surfacePointWithExclusionRegion *sp =
       new surfacePointWithExclusionRegion (*it, newp, midpoint,metricField);
-    //    fifo.push(sp);
-    fifo.insert(sp);
+    smoothness_point_pair mp;mp.ptr = sp;mp.rank=get_smoothness(*it,gf,vertices2smoothness);
+    fifo.insert(mp);
+
+    if (debug){
+      smoothness_essai[*it] = mp.rank;
+    }
+
     vertices.push_back(sp);
     double _min[2],_max[2];
     sp->minmax(_min,_max);
-    //    printf("%g %g .. %g %g\n",_min[0],_min[1],_max[0],_max[1]);
     rtree.Insert(_min,_max,sp);
-    //    sp->print(f);
+    if (crossf) export_point(sp, 0, crossf, gf);
   }
 
-  //  printf("initially : %d vertices in the domain\n",vertices.size());
-
-
+  // ---------- main loop -----------------
   while(!fifo.empty()){
-    //surfacePointWithExclusionRegion & parent = fifo.top();
-    //    surfacePointWithExclusionRegion * parent = fifo.front();
-    surfacePointWithExclusionRegion * parent = *fifo.begin();
-    //    fifo.pop();
+    if (debug) std::cout << " -------- fifo.size() = " << fifo.size() << std::endl;
+
+    surfacePointWithExclusionRegion * parent = (*fifo.begin()).ptr;
     fifo.erase(fifo.begin());
+    int count_nbaddedpt = 0;
     for (int dir=0;dir<NUMDIR;dir++){
-      //      printf("dir = %d\n",dir);
-      int countOK = 0;
       for (int i=0;i<4;i++){
-	//	printf("i = %d %12.5E %12.5E \n",i,parent._p[i][dir].x(),parent._p[i][dir].y());
-
-	//	if (!w._tooclose){
-	if (!inExclusionZone (parent->_p[i][dir], rtree, vertices) ){
-	  countOK++;
-	  GPoint gp = gf->point(parent->_p[i][dir]);
-	  MFaceVertex *v = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
-	  //	  	printf(" %g %g %g %g\n",parent._center.x(),parent._center.y(),gp.u(),gp.v());
-	  SPoint2 midpoint;
-	  compute4neighbors (gf, v, midpoint, goNonLinear, newp, metricField,crossf);
-	  surfacePointWithExclusionRegion *sp =
-	    new surfacePointWithExclusionRegion (v, newp, midpoint, metricField, parent);
-	  //	  fifo.push(sp);
-	  fifo.insert(sp);
-	  vertices.push_back(sp);
-	  double _min[2],_max[2];
-	  sp->minmax(_min,_max);
-	  rtree.Insert(_min,_max,sp);
-	}
+
+        if (!inExclusionZone (parent->_p[i][dir], rtree, vertices) ){
+          GPoint gp = gf->point(parent->_p[i][dir]);
+          MFaceVertex *v = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
+          SPoint2 midpoint;
+          //compute4neighbors_RK2 (gf, v, midpoint, goNonLinear, newp, metricField,crossf);
+          compute4neighbors(gf, v, midpoint, goNonLinear, newp, metricField,crossf);
+          surfacePointWithExclusionRegion *sp =
+            new surfacePointWithExclusionRegion (v, newp, midpoint, metricField, parent);
+          smoothness_point_pair mp;mp.ptr = sp;mp.rank=get_smoothness(v,gf,vertices2smoothness);
+
+          if (debug){
+            smoothness_essai[v] = mp.rank;
+            vert_priority[v] = priority_counter++;
+          }
+          fifo.insert(mp);
+          vertices.push_back(sp);
+          double _min[2],_max[2];
+          sp->minmax(_min,_max);
+          rtree.Insert(_min,_max,sp);
+          if (crossf) export_point(sp, dir, crossf, gf);
+
+          if (debug){
+            std::cout << "  adding node (" << sp->_v->x() << "," << sp->_v->y() << "," << sp->_v->z() << ")" << std::endl;
+            std::cout << "    ----------------------------- sub --- fifo.size() = " << fifo.size() << std::endl;
+          }
+          count_nbaddedpt++;
+        }
       }
-      if (countOK)break;
     }
-    //    printf("%d\n",vertices.size());
+    if (debug) std::cout << "////////// nbre of added point: " << count_nbaddedpt << std::endl;
   }
   if (crossf){
     fprintf(crossf,"};\n");
     fclose (crossf);
   }
-  //  printf("done\n");
+
+
+  if (debug){
+    stringstream ss;
+    ss << "priority_" << gf->tag() << ".pos";
+    print_nodal_info_int(ss.str().c_str(),vert_priority);
+    ss.clear();
+    ss << "smoothness_test_" << gf->tag() << ".pos";
+    print_nodal_info_double(ss.str().c_str(),smoothness_essai);
+  }
+
 
   // add the vertices as additional vertices in the
   // surface mesh
@@ -486,27 +897,142 @@ void packingOfParallelograms(GFace* gf,  std::vector<MVertex*> &packed, std::vec
   FILE *f = Fopen(ccc,"w");
   fprintf(f,"View \"\"{\n");
   for (unsigned int i=0;i<vertices.size();i++){
-    //    if(vertices[i]->_v->onWhat() != gf)
-      vertices[i]->print(f,i);
+    vertices[i]->print(f,i);
     if(vertices[i]->_v->onWhat() == gf) {
       packed.push_back(vertices[i]->_v);
       metrics.push_back(vertices[i]->_meshMetric);
       SPoint2 midpoint;
       reparamMeshVertexOnFace(vertices[i]->_v, gf, midpoint);
-      //      fprintf(f,"TP(%22.15E,%22.15E,%g){%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E};\n",vertices[i]->_v->x(),vertices[i]->_v->y(),vertices[i]->_v->z(),
-      //	      vertices[i]->_meshMetric(0,0),vertices[i]->_meshMetric(0,1),vertices[i]->_meshMetric(0,2),
-      //	      vertices[i]->_meshMetric(1,0),vertices[i]->_meshMetric(1,1),vertices[i]->_meshMetric(1,2),
-      //	      vertices[i]->_meshMetric(2,0),vertices[i]->_meshMetric(2,1),vertices[i]->_meshMetric(2,2));
-	    //fprintf(f,"SP(%22.15E,%22.15E,%g){1};\n",midpoint.x(),midpoint.y(),0.0);
     }
     delete  vertices[i];
   }
   fprintf(f,"};");
   fclose(f);
-  //  printf("packed.size = %d\n",packed.size());
-  //  delete rtree;
-  #endif
+#endif
 }
 
 
+// ---------------------------------------------------------------------------------------------
+
+
+// fills a surface with points in order to build a nice
+// quad mesh ------------
+void packingOfParallelograms(GFace* gf,  std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics){
+  //PE MODIF
+//  packingOfParallelogramsSmoothness(gf,packed,metrics);
+//  return;
+  // END PE MODIF
+#if defined(HAVE_RTREE)
+
+  const bool goNonLinear = true;
+
+  //  FILE *f = Fopen ("parallelograms.pos","w");
+
+  // get all the boundary vertices
+  std::set<MVertex*> bnd_vertices;
+  for(unsigned int i=0;i<gf->getNumMeshElements();i++){
+    MElement* element = gf->getMeshElement(i);
+    for(int j=0;j<element->getNumVertices();j++){
+      MVertex *vertex = element->getVertex(j);
+      if (vertex->onWhat()->dim() < 2)bnd_vertices.insert(vertex);
+    }
+  }
+
+  // put boundary vertices in a fifo queue
+  // std::queue<surfacePointWithExclusionRegion*> fifo;
+  std::set<surfacePointWithExclusionRegion*,  compareSurfacePointWithExclusionRegionPtr> fifo;
+  std::vector<surfacePointWithExclusionRegion*> vertices;
+  // put the RTREE
+  RTree<surfacePointWithExclusionRegion*,double,2,double> rtree;
+  SMetric3 metricField(1.0);
+  SPoint2 newp[4][NUMDIR];
+  std::set<MVertex*>::iterator it =  bnd_vertices.begin() ;
+
+  char NAME[345]; sprintf(NAME,"crossReal%d.pos",gf->tag());
+  FILE *crossf = Fopen (NAME,"w");
+  if (crossf)fprintf(crossf,"View \"\"{\n");
+  for (; it !=  bnd_vertices.end() ; ++it){
+    SPoint2 midpoint;
+    compute4neighbors (gf, *it, midpoint, goNonLinear, newp, metricField,crossf);
+    surfacePointWithExclusionRegion *sp =
+      new surfacePointWithExclusionRegion (*it, newp, midpoint,metricField);
+    //    fifo.push(sp);
+    fifo.insert(sp);
+    vertices.push_back(sp);
+    double _min[2],_max[2];
+    sp->minmax(_min,_max);
+    //    printf("%g %g .. %g %g\n",_min[0],_min[1],_max[0],_max[1]);
+    rtree.Insert(_min,_max,sp);
+    //    sp->print(f);
+  }
+
+  //  printf("initially : %d vertices in the domain\n",vertices.size());
 
+
+  while(!fifo.empty()){
+    //surfacePointWithExclusionRegion & parent = fifo.top();
+    //    surfacePointWithExclusionRegion * parent = fifo.front();
+    surfacePointWithExclusionRegion * parent = *fifo.begin();
+    //    fifo.pop();
+    fifo.erase(fifo.begin());
+    for (int dir=0;dir<NUMDIR;dir++){
+      //      printf("dir = %d\n",dir);
+      int countOK = 0;
+      for (int i=0;i<4;i++){
+        //	printf("i = %d %12.5E %12.5E \n",i,parent._p[i][dir].x(),parent._p[i][dir].y());
+
+        //	if (!w._tooclose){
+        if (!inExclusionZone (parent->_p[i][dir], rtree, vertices) ){
+          countOK++;
+          GPoint gp = gf->point(parent->_p[i][dir]);
+          MFaceVertex *v = new MFaceVertex(gp.x(),gp.y(),gp.z(),gf,gp.u(),gp.v());
+          //	  	printf(" %g %g %g %g\n",parent._center.x(),parent._center.y(),gp.u(),gp.v());
+          SPoint2 midpoint;
+          compute4neighbors (gf, v, midpoint, goNonLinear, newp, metricField,crossf);
+          surfacePointWithExclusionRegion *sp =
+            new surfacePointWithExclusionRegion (v, newp, midpoint, metricField, parent);
+          //	  fifo.push(sp);
+          fifo.insert(sp);
+          vertices.push_back(sp);
+          double _min[2],_max[2];
+          sp->minmax(_min,_max);
+          rtree.Insert(_min,_max,sp);
+        }
+      }
+      if (countOK)break;
+      }
+      //    printf("%d\n",vertices.size());
+    }
+    if (crossf){
+      fprintf(crossf,"};\n");
+      fclose (crossf);
+    }
+    //  printf("done\n");
+
+    // add the vertices as additional vertices in the
+    // surface mesh
+    char ccc[256]; sprintf(ccc,"points%d.pos",gf->tag());
+    FILE *f = Fopen(ccc,"w");
+    fprintf(f,"View \"\"{\n");
+    for (unsigned int i=0;i<vertices.size();i++){
+      //    if(vertices[i]->_v->onWhat() != gf)
+      vertices[i]->print(f,i);
+      if(vertices[i]->_v->onWhat() == gf) {
+        packed.push_back(vertices[i]->_v);
+        metrics.push_back(vertices[i]->_meshMetric);
+        SPoint2 midpoint;
+        reparamMeshVertexOnFace(vertices[i]->_v, gf, midpoint);
+        //      fprintf(f,"TP(%22.15E,%22.15E,%g){%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E};\n",vertices[i]->_v->x(),vertices[i]->_v->y(),vertices[i]->_v->z(),
+        //	      vertices[i]->_meshMetric(0,0),vertices[i]->_meshMetric(0,1),vertices[i]->_meshMetric(0,2),
+        //	      vertices[i]->_meshMetric(1,0),vertices[i]->_meshMetric(1,1),vertices[i]->_meshMetric(1,2),
+        //	      vertices[i]->_meshMetric(2,0),vertices[i]->_meshMetric(2,1),vertices[i]->_meshMetric(2,2));
+        //fprintf(f,"SP(%22.15E,%22.15E,%g){1};\n",midpoint.x(),midpoint.y(),0.0);
+      }
+      delete  vertices[i];
+    }
+    fprintf(f,"};");
+    fclose(f);
+    //  printf("packed.size = %d\n",packed.size());
+    //  delete rtree;
+#endif
+}
diff --git a/Mesh/surfaceFiller.h b/Mesh/surfaceFiller.h
index ae20a52..7c1c9c5 100644
--- a/Mesh/surfaceFiller.h
+++ b/Mesh/surfaceFiller.h
@@ -8,4 +8,5 @@
 #include <vector>
 class GFace;
 class MVertex;
+void packingOfParallelogramsSmoothness(GFace* gf, std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics );
 void packingOfParallelograms(GFace* gf, std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics );
diff --git a/Mesh/yamakawa.cpp b/Mesh/yamakawa.cpp
index f3e5ff8..0616f23 100644
--- a/Mesh/yamakawa.cpp
+++ b/Mesh/yamakawa.cpp
@@ -373,7 +373,7 @@ void Recombinator::init_markings(GRegion* gr){
 
   for(i=0;i<gr->getNumMeshElements();i++){
     element = gr->getMeshElement(i);
-    markings.insert(std::pair<MElement*,bool>(element,0));
+    markings.insert(std::pair<MElement*,bool>(element,false));
   }
 }
 
@@ -2425,7 +2425,7 @@ void Supplementary::init_markings(GRegion* gr){
   for(i=0;i<gr->getNumMeshElements();i++){
     element = gr->getMeshElement(i);
     if(four(element)){
-      markings.insert(std::pair<MElement*,bool>(element,0));
+      markings.insert(std::pair<MElement*,bool>(element,false));
     }
   }
 }
@@ -3698,7 +3698,7 @@ void PostOp::init_markings(GRegion* gr){
   for(i=0;i<gr->getNumMeshElements();i++){
     element = gr->getMeshElement(i);
     if(four(element) || five(element)){
-      markings.insert(std::pair<MElement*,bool>(element,0));
+      markings.insert(std::pair<MElement*,bool>(element,false));
     }
   }
 }
@@ -3882,7 +3882,7 @@ void PostOp::pyramids1(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){
   for(it=bin2.begin();it!=bin2.end();it++){
     bin.insert(*it);
   }
-	
+
   if(bin.size()==2){
     it = bin.begin();
     it1 = markings.find(*it);
@@ -3987,7 +3987,7 @@ void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){
 
     temp2 = new MPyramid(a,b,c,d,mid);
     gr->addPyramid(temp2);
-    markings.insert(std::pair<MElement*,bool>(temp2,0));
+    markings.insert(std::pair<MElement*,bool>(temp2,false));
     build_vertex_to_pyramids(temp2);
 
     for(it=tetrahedra.begin();it!=tetrahedra.end();it++){
@@ -4000,13 +4000,13 @@ void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){
 
         temp = new MTetrahedron(N1,N2,diagA,mid);
         gr->addTetrahedron(temp);
-        markings.insert(std::pair<MElement*,bool>(temp,0));
+        markings.insert(std::pair<MElement*,bool>(temp,false));
         build_vertex_to_tetrahedra(temp);
         movables.push_back(temp);
 
         temp = new MTetrahedron(N1,N2,diagB,mid);
         gr->addTetrahedron(temp);
-        markings.insert(std::pair<MElement*,bool>(temp,0));
+        markings.insert(std::pair<MElement*,bool>(temp,false));
         build_vertex_to_tetrahedra(temp);
         movables.push_back(temp);
 
@@ -4041,13 +4041,13 @@ void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){
 
       temp2 = new MPyramid(v1,v2,v3,v4,mid);
       gr->addPyramid(temp2);
-      markings.insert(std::pair<MElement*,bool>(temp2,0));
+      markings.insert(std::pair<MElement*,bool>(temp2,false));
       build_vertex_to_pyramids(temp2);
 
       if(different(v1,v2,diagA,diagB)){
         temp = new MTetrahedron(v1,v2,mid,v5);
         gr->addTetrahedron(temp);
-        markings.insert(std::pair<MElement*,bool>(temp,0));
+        markings.insert(std::pair<MElement*,bool>(temp,false));
         build_vertex_to_tetrahedra(temp);
         movables.push_back(temp);
       }
@@ -4055,7 +4055,7 @@ void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){
       if(different(v2,v3,diagA,diagB)){
         temp = new MTetrahedron(v2,v3,mid,v5);
         gr->addTetrahedron(temp);
-        markings.insert(std::pair<MElement*,bool>(temp,0));
+        markings.insert(std::pair<MElement*,bool>(temp,false));
         build_vertex_to_tetrahedra(temp);
         movables.push_back(temp);
       }
@@ -4063,7 +4063,7 @@ void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){
       if(different(v3,v4,diagA,diagB)){
         temp = new MTetrahedron(v3,v4,mid,v5);
         gr->addTetrahedron(temp);
-        markings.insert(std::pair<MElement*,bool>(temp,0));
+        markings.insert(std::pair<MElement*,bool>(temp,false));
         build_vertex_to_tetrahedra(temp);
         movables.push_back(temp);
       }
@@ -4071,7 +4071,7 @@ void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){
       if(different(v4,v1,diagA,diagB)){
         temp = new MTetrahedron(v4,v1,mid,v5);
         gr->addTetrahedron(temp);
-        markings.insert(std::pair<MElement*,bool>(temp,0));
+        markings.insert(std::pair<MElement*,bool>(temp,false));
         build_vertex_to_tetrahedra(temp);
         movables.push_back(temp);
       }
diff --git a/Numeric/BasisFactory.cpp b/Numeric/BasisFactory.cpp
index 1290110..d39b63f 100644
--- a/Numeric/BasisFactory.cpp
+++ b/Numeric/BasisFactory.cpp
@@ -5,6 +5,7 @@
 
 #include "GmshDefines.h"
 #include "GmshMessage.h"
+#include "miniBasis.h"
 #include "polynomialBasis.h"
 #include "pyramidalBasis.h"
 #include "pointsGenerators.h"
@@ -13,7 +14,9 @@
 
 std::map<int, nodalBasis*> BasisFactory::fs;
 std::map<int, JacobianBasis*> BasisFactory::js;
+std::map<int, MetricBasis*> BasisFactory::ms;
 BasisFactory::Cont_bezierBasis BasisFactory::bs;
+BasisFactory::Cont_gradBasis BasisFactory::gs;
 
 const nodalBasis* BasisFactory::getNodalBasis(int tag)
 {
@@ -24,30 +27,36 @@ const nodalBasis* BasisFactory::getNodalBasis(int tag)
   }
   // Get the parent type to see which kind of basis
   // we want to create
-  int parentType = ElementType::ParentTypeFromTag(tag);
   nodalBasis* F = NULL;
-
-  switch(parentType) {
-    case(TYPE_PNT):
-    case(TYPE_LIN):
-    case(TYPE_TRI):
-    case(TYPE_QUA):
-    case(TYPE_PRI):
-    case(TYPE_TET):
-    case(TYPE_HEX):
-      F = new polynomialBasis(tag);
-      break;
-    case(TYPE_PYR):
-      F = new pyramidalBasis(tag);
-      break;
-    default:
-      Msg::Error("Unknown type of element %d (in BasisFactory)", tag);
-      return NULL;
+  if (tag == MSH_TRI_MINI) {
+    F = new miniBasis();
+  }
+  else {
+    int parentType = ElementType::ParentTypeFromTag(tag);
+    switch(parentType) {
+      case(TYPE_PNT):
+      case(TYPE_LIN):
+      case(TYPE_TRI):
+      case(TYPE_QUA):
+      case(TYPE_PRI):
+      case(TYPE_TET):
+      case(TYPE_HEX):
+        F = new polynomialBasis(tag);
+        break;
+      case(TYPE_PYR):
+        F = new pyramidalBasis(tag);
+        break;
+      default:
+        Msg::Error("Unknown type of element %d (in BasisFactory)", tag);
+        return NULL;
+    }
   }
 
   std::pair<std::map<int, nodalBasis*>::const_iterator, bool> inserted;
 
+#if defined(_OPENMP)
   #pragma omp critical
+#endif
     {
       inserted = fs.insert(std::make_pair(tag, F));
 
@@ -69,14 +78,38 @@ const JacobianBasis* BasisFactory::getJacobianBasis(int tag)
   return J;
 }
 
+const MetricBasis* BasisFactory::getMetricBasis(int tag)
+{
+  std::map<int, MetricBasis*>::const_iterator it = ms.find(tag);
+  if (it != ms.end())
+    return it->second;
+
+  MetricBasis* M = new MetricBasis(tag);
+  ms.insert(std::make_pair(tag, M));
+  return M;
+}
+
+const GradientBasis* BasisFactory::getGradientBasis(int tag, int order)
+{
+  std::pair<int, int> key(tag, order);
+  Cont_gradBasis::const_iterator it = gs.find(key);
+  if (it != gs.end())
+    return it->second;
+
+  GradientBasis* G = new GradientBasis(tag, order);
+  gs.insert(std::make_pair(key, G));
+  return G;
+}
+
 const bezierBasis* BasisFactory::getBezierBasis(int parentType, int order)
 {
-  Cont_bezierBasis::iterator it = bs.find(std::make_pair(parentType, order));
+  std::pair<int, int> key(parentType, order);
+  Cont_bezierBasis::iterator it = bs.find(key);
   if (it != bs.end())
     return it->second;
 
   bezierBasis* B = new bezierBasis(parentType, order);
-  bs.insert(std::make_pair(std::make_pair(parentType, order), B));
+  bs.insert(std::make_pair(key, B));
   return B;
 }
 
diff --git a/Numeric/BasisFactory.h b/Numeric/BasisFactory.h
index d7b8e51..6c4e4e1 100644
--- a/Numeric/BasisFactory.h
+++ b/Numeric/BasisFactory.h
@@ -10,14 +10,18 @@
 #include "MPyramid.h"
 #include "nodalBasis.h"
 #include "JacobianBasis.h"
+#include "MetricBasis.h"
 
 class BasisFactory
 {
   typedef std::map<std::pair<int, int>, bezierBasis*> Cont_bezierBasis;
+  typedef std::map<std::pair<int, int>, GradientBasis*> Cont_gradBasis;
 
  private:
   static std::map<int, nodalBasis*> fs;
   static std::map<int, JacobianBasis*> js;
+  static std::map<int, MetricBasis*> ms;
+  static Cont_gradBasis gs;
   static Cont_bezierBasis bs;
   // store bezier bases by parentType and order (no serendipity..)
 
@@ -25,6 +29,9 @@ class BasisFactory
   // Caution: the returned pointer can be NULL
   static const nodalBasis* getNodalBasis(int tag);
   static const JacobianBasis* getJacobianBasis(int tag);
+  static const MetricBasis* getMetricBasis(int tag);
+
+  static const GradientBasis* getGradientBasis(int tag, int order);
   static const bezierBasis* getBezierBasis(int parentTag, int order);
   static inline const bezierBasis* getBezierBasis(int tag) {
       return getBezierBasis(ElementType::ParentTypeFromTag(tag),
diff --git a/Numeric/BergotBasis.h b/Numeric/BergotBasis.h
index 2de1375..e774038 100644
--- a/Numeric/BergotBasis.h
+++ b/Numeric/BergotBasis.h
@@ -12,9 +12,10 @@
 #include "legendrePolynomials.h"
 
 
-// Basis functios for pyramidal elements
-// cf. M. Bergot, G. Cohen, M. Durufle, HIGHER-ORDER FINITE ELEMENTS FOR HYBRID MESHES USING NEW
-// NODAL PYRAMIDAL ELEMENTS, J. Sci. Comput. 42, 3 (2010) 345-381", DOI: 10.1007/s10915-009-9334-9
+// Basis functios for pyramidal elements: cf. M. Bergot, G. Cohen, M. Durufle,
+// HIGHER-ORDER FINITE ELEMENTS FOR HYBRID MESHES USING NEW NODAL PYRAMIDAL
+// ELEMENTS, J. Sci. Comput. 42, 3 (2010) 345-381", DOI:
+// 10.1007/s10915-009-9334-9
 
 class BergotBasis {
  public:
diff --git a/Numeric/CMakeLists.txt b/Numeric/CMakeLists.txt
index a3382e8..6977d24 100644
--- a/Numeric/CMakeLists.txt
+++ b/Numeric/CMakeLists.txt
@@ -7,6 +7,8 @@ set(SRC
   Numeric.cpp
     fullMatrix.cpp
   BasisFactory.cpp
+  discreteFrechetDistance.cpp
+  miniBasis.cpp
     nodalBasis.cpp
 	polynomialBasis.cpp
 	pyramidalBasis.cpp
@@ -15,6 +17,7 @@ set(SRC
 	legendrePolynomials.cpp
     bezierBasis.cpp
     JacobianBasis.cpp
+    MetricBasis.cpp
     pointsGenerators.cpp
   ElementType.cpp
   GaussIntegration.cpp
@@ -27,7 +30,9 @@ set(SRC
     GaussQuadraturePyr.cpp
     GaussLegendreSimplex.cpp
   GaussJacobi1D.cpp
+  HilbertCurve.cpp
  robustPredicates.cpp
+ decasteljau.cpp
   mathEvaluator.cpp
   Iso.cpp
 )
diff --git a/Numeric/HilbertCurve.cpp b/Numeric/HilbertCurve.cpp
new file mode 100644
index 0000000..22720cb
--- /dev/null
+++ b/Numeric/HilbertCurve.cpp
@@ -0,0 +1,275 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
+#include "SBoundingBox3d.h"
+#include "MVertex.h"
+
+struct HilbertSort
+{
+// The code for generating table transgc
+// from: http://graphics.stanford.edu/~seander/bithacks.html.
+  int transgc[8][3][8];
+  int tsb1mod3[8];
+  int maxDepth;
+  int Limit;
+  SBoundingBox3d bbox ;
+  void ComputeGrayCode(int n);
+  int Split(MVertex** vertices,
+	    int arraysize,int GrayCode0,int GrayCode1,
+	    double BoundingBoxXmin, double BoundingBoxXmax,
+	    double BoundingBoxYmin, double BoundingBoxYmax,
+	    double BoundingBoxZmin, double BoundingBoxZmax);
+  void Sort(MVertex** vertices, int arraysize, int e, int d,
+	   double BoundingBoxXmin, double BoundingBoxXmax,
+            double BoundingBoxYmin, double BoundingBoxYmax,
+	   double BoundingBoxZmin, double BoundingBoxZmax, int depth);
+  HilbertSort (int m = 0, int l=2) : maxDepth(m),Limit(l)
+  {
+    ComputeGrayCode(3);
+  }
+  void MultiscaleSortHilbert(MVertex** vertices, int arraysize,
+			     int threshold, double ratio, int *depth)
+  {
+    int middle;
+
+    middle = 0;
+    if (arraysize >= threshold) {
+      (*depth)++;
+      middle = (int)(arraysize * ratio);
+      MultiscaleSortHilbert(vertices, middle, threshold, ratio, depth);
+    }
+    Sort (&(vertices[middle]),arraysize - middle,0,0,
+	  bbox.min().x(),bbox.max().x(),
+	  bbox.min().y(),bbox.max().y(),
+	  bbox.min().z(),bbox.max().z(),0);
+  }
+  void Apply (std::vector<MVertex*> &v)
+  {
+    for (size_t i=0;i<v.size();i++){
+      MVertex *pv = v[i];
+      bbox += SPoint3(pv->x(),pv->y(),pv->z());
+    }
+    bbox *= 1.01;
+    MVertex**pv = &v[0];
+    int depth;
+    MultiscaleSortHilbert(pv, (int)v.size(), 64, 0.125,&depth);
+  }
+};
+
+void HilbertSort::ComputeGrayCode(int n)
+{
+  int gc[8], N, mask, travel_bit;
+  int e, d, f, k, g;
+  int v, c;
+  int i;
+
+  N = (n == 2) ? 4 : 8;
+  mask = (n == 2) ? 3 : 7;
+
+  // Generate the Gray code sequence.
+  for (i = 0; i < N; i++) {
+    gc[i] = i ^ (i >> 1);
+  }
+
+  for (e = 0; e < N; e++) {
+    for (d = 0; d < n; d++) {
+      // Calculate the end point (f).
+      f = e ^ (1 << d);  // Toggle the d-th bit of 'e'.
+      // travel_bit = 2**p, the bit we want to travel.
+      travel_bit = e ^ f;
+      for (i = 0; i < N; i++) {
+        // // Rotate gc[i] left by (p + 1) % n bits.
+        k = gc[i] * (travel_bit * 2);
+        g = ((k | (k / N)) & mask);
+        // Calculate the permuted Gray code by xor with the start point (e).
+        transgc[e][d][i] = (g ^ e);
+      }
+      //      assert(transgc[e][d][0] == e);
+      //      assert(transgc[e][d][N - 1] == f);
+    } // d
+  } // e
+
+  // Count the consecutive '1' bits (trailing) on the right.
+  tsb1mod3[0] = 0;
+  for (i = 1; i < N; i++) {
+    v = ~i; // Count the 0s.
+    v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
+    for (c = 0; v; c++) {
+      v >>= 1;
+    }
+    tsb1mod3[i] = c % n;
+  }
+}
+
+
+int HilbertSort::Split(MVertex** vertices,
+		       int arraysize,int GrayCode0,int GrayCode1,
+		       double BoundingBoxXmin, double BoundingBoxXmax,
+                       double BoundingBoxYmin, double BoundingBoxYmax,
+		       double BoundingBoxZmin, double BoundingBoxZmax)
+{
+  MVertex* swapvert;
+  int axis, d;
+  double split;
+  int i, j;
+
+  // Find the current splitting axis. 'axis' is a value 0, or 1, or 2, which
+  //   correspoding to x-, or y- or z-axis.
+  axis = (GrayCode0 ^ GrayCode1) >> 1;
+
+  // Calulate the split position along the axis.
+  if (axis == 0) {
+    split = 0.5 * (BoundingBoxXmin + BoundingBoxXmax);
+  } else if (axis == 1) {
+    split = 0.5 * (BoundingBoxYmin + BoundingBoxYmax);
+  } else { // == 2
+    split = 0.5 * (BoundingBoxZmin + BoundingBoxZmax);
+  }
+
+  // Find the direction (+1 or -1) of the axis. If 'd' is +1, the direction
+  //   of the axis is to the positive of the axis, otherwise, it is -1.
+  d = ((GrayCode0 & (1<<axis)) == 0) ? 1 : -1;
+
+
+  // Partition the vertices into left- and right-arrays such that left points
+  //   have Hilbert indices lower than the right points.
+  i = 0;
+  j = arraysize - 1;
+
+  // Partition the vertices into left- and right-arrays.
+  if (d > 0) {
+    do {
+      for (; i < arraysize; i++) {
+        if (vertices[i]->point()[axis] >= split) break;
+      }
+      for (; j >= 0; j--) {
+        if (vertices[j]->point()[axis] < split) break;
+      }
+      // Is the partition finished?
+      if (i == (j + 1)) break;
+      // Swap i-th and j-th vertices.
+      swapvert = vertices[i];
+      vertices[i] = vertices[j];
+      vertices[j] = swapvert;
+      // Continue patitioning the array;
+    } while (true);
+  } else {
+    do {
+      for (; i < arraysize; i++) {
+        if (vertices[i]->point()[axis] <= split) break;
+      }
+      for (; j >= 0; j--) {
+        if (vertices[j]->point()[axis] > split) break;
+      }
+      // Is the partition finished?
+      if (i == (j + 1)) break;
+      // Swap i-th and j-th vertices.
+      swapvert = vertices[i];
+      vertices[i] = vertices[j];
+      vertices[j] = swapvert;
+      // Continue patitioning the array;
+    } while (true);
+  }
+
+  return i;
+}
+
+// The sorting code is inspired by Tetgen 1.5
+
+void HilbertSort::Sort(MVertex** vertices, int arraysize, int e, int d,
+		       double BoundingBoxXmin, double BoundingBoxXmax,
+                       double BoundingBoxYmin, double BoundingBoxYmax,
+		       double BoundingBoxZmin, double BoundingBoxZmax, int depth)
+{
+  double x1, x2, y1, y2, z1, z2;
+  int p[9], w, e_w, d_w, k, ei, di;
+  int n = 3, mask = 7;
+
+  p[0] = 0;
+  p[8] = arraysize;
+
+  p[4] = Split(vertices, p[8], transgc[e][d][3], transgc[e][d][4],
+	       BoundingBoxXmin, BoundingBoxXmax, BoundingBoxYmin,
+               BoundingBoxYmax, BoundingBoxZmin, BoundingBoxZmax);
+  p[2] = Split(vertices, p[4], transgc[e][d][1], transgc[e][d][2],
+	       BoundingBoxXmin, BoundingBoxXmax, BoundingBoxYmin,
+               BoundingBoxYmax, BoundingBoxZmin, BoundingBoxZmax);
+  p[1] = Split(vertices, p[2], transgc[e][d][0], transgc[e][d][1],
+	       BoundingBoxXmin, BoundingBoxXmax, BoundingBoxYmin,
+               BoundingBoxYmax, BoundingBoxZmin, BoundingBoxZmax);
+  p[3] = Split(&(vertices[p[2]]), p[4] - p[2],
+	       transgc[e][d][2], transgc[e][d][3],
+	       BoundingBoxXmin, BoundingBoxXmax, BoundingBoxYmin,
+               BoundingBoxYmax, BoundingBoxZmin, BoundingBoxZmax) + p[2];
+  p[6] = Split(&(vertices[p[4]]), p[8] - p[4],
+	       transgc[e][d][5], transgc[e][d][6],
+	       BoundingBoxXmin, BoundingBoxXmax, BoundingBoxYmin,
+               BoundingBoxYmax, BoundingBoxZmin, BoundingBoxZmax) + p[4];
+  p[5] = Split(&(vertices[p[4]]), p[6] - p[4],
+	       transgc[e][d][4], transgc[e][d][5],
+	       BoundingBoxXmin, BoundingBoxXmax, BoundingBoxYmin,
+               BoundingBoxYmax, BoundingBoxZmin, BoundingBoxZmax) + p[4];
+  p[7] = Split(&(vertices[p[6]]), p[8] - p[6],
+	       transgc[e][d][6], transgc[e][d][7],
+	       BoundingBoxXmin, BoundingBoxXmax, BoundingBoxYmin,
+               BoundingBoxYmax, BoundingBoxZmin, BoundingBoxZmax) + p[6];
+
+  if (maxDepth > 0) {
+    if ((depth + 1) == maxDepth) {
+      return;
+    }
+  }
+
+  // Recursively sort the points in sub-boxes.
+  for (w = 0; w < 8; w++) {
+    if ((p[w+1] - p[w]) > Limit) {
+      if (w == 0) {
+        e_w = 0;
+      } else {
+        k = 2 * ((w - 1) / 2);
+        e_w = k ^ (k >> 1);
+      }
+      k = e_w;
+      e_w = ((k << (d+1)) & mask) | ((k >> (n-d-1)) & mask);
+      ei = e ^ e_w;
+      if (w == 0) {
+        d_w = 0;
+      } else {
+        d_w = ((w % 2) == 0) ? tsb1mod3[w - 1] : tsb1mod3[w];
+      }
+      di = (d + d_w + 1) % n;
+      if (transgc[e][d][w] & 1) {
+        x1 = 0.5 * (BoundingBoxXmin + BoundingBoxXmax);
+        x2 = BoundingBoxXmax;
+      } else {
+        x1 = BoundingBoxXmin;
+        x2 = 0.5 * (BoundingBoxXmin + BoundingBoxXmax);
+      }
+      if (transgc[e][d][w] & 2) { // y-axis
+        y1 = 0.5 * (BoundingBoxYmin + BoundingBoxYmax);
+        y2 = BoundingBoxYmax;
+      } else {
+        y1 = BoundingBoxYmin;
+        y2 = 0.5 * (BoundingBoxYmin + BoundingBoxYmax);
+      }
+      if (transgc[e][d][w] & 4) { // z-axis
+        z1 = 0.5 * (BoundingBoxZmin + BoundingBoxZmax);
+        z2 = BoundingBoxZmax;
+      } else {
+        z1 = BoundingBoxZmin;
+        z2 = 0.5 * (BoundingBoxZmin + BoundingBoxZmax);
+      }
+      Sort(&(vertices[p[w]]), p[w+1] - p[w], ei, di,
+                    x1, x2, y1, y2, z1, z2, depth+1);
+    }
+  }
+}
+
+void SortHilbert (std::vector<MVertex*>& v)
+{
+  //HilbertSort h(1000);
+  HilbertSort h;
+  h.Apply(v);
+}
diff --git a/Mesh/surfaceFiller.h b/Numeric/HilbertCurve.h
similarity index 53%
copy from Mesh/surfaceFiller.h
copy to Numeric/HilbertCurve.h
index ae20a52..292fc57 100644
--- a/Mesh/surfaceFiller.h
+++ b/Numeric/HilbertCurve.h
@@ -2,10 +2,10 @@
 //
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
-//
 
-#include "STensor3.h"
-#include <vector>
-class GFace;
-class MVertex;
-void packingOfParallelograms(GFace* gf, std::vector<MVertex*> &packed, std::vector<SMetric3> &metrics );
+#ifndef _HILBERT_CURVE_
+#define _HILBERT_CURVE_
+
+void SortHilbert(std::vector<MVertex*>&);
+
+#endif
diff --git a/Numeric/JacobianBasis.cpp b/Numeric/JacobianBasis.cpp
index af719e9..402cddd 100644
--- a/Numeric/JacobianBasis.cpp
+++ b/Numeric/JacobianBasis.cpp
@@ -23,12 +23,81 @@ namespace {
   }
 }
 
-JacobianBasis::JacobianBasis(int tag)
+GradientBasis::GradientBasis(int tag, int order)
+{
+  const int type = ElementType::ParentTypeFromTag(tag);
+
+  fullMatrix<double> samplingPoints;
+
+  switch (type) {
+    case TYPE_PNT :
+      samplingPoints = gmshGeneratePointsLine(0);
+      break;
+    case TYPE_LIN :
+      samplingPoints = gmshGeneratePointsLine(order);
+      break;
+    case TYPE_TRI :
+      samplingPoints = gmshGeneratePointsTriangle(order,false);
+      break;
+    case TYPE_QUA :
+      samplingPoints = gmshGeneratePointsQuadrangle(order,false);
+      break;
+    case TYPE_TET :
+      samplingPoints = gmshGeneratePointsTetrahedron(order,false);
+      break;
+    case TYPE_PRI :
+      samplingPoints = gmshGeneratePointsPrism(order,false);
+      break;
+    case TYPE_HEX :
+      samplingPoints = gmshGeneratePointsHexahedron(order,false);
+      break;
+    case TYPE_PYR :
+      samplingPoints = JacobianBasis::generateJacPointsPyramid(order);
+      break;
+    default :
+      Msg::Error("Unknown Jacobian function space for element tag %d", tag);
+      return;
+  }
+  const int numSampPnts = samplingPoints.size1();
+
+  // Store shape function gradients of mapping at Jacobian nodes
+  fullMatrix<double> allDPsi;
+  const nodalBasis *mapBasis = BasisFactory::getNodalBasis(tag);
+  mapBasis->df(samplingPoints, allDPsi);
+  const int numMapNodes = allDPsi.size1();
+
+  gradShapeMatX.resize(numSampPnts, numMapNodes);
+  gradShapeMatY.resize(numSampPnts, numMapNodes);
+  gradShapeMatZ.resize(numSampPnts, numMapNodes);
+  for (int i=0; i<numSampPnts; i++) {
+    for (int j=0; j<numMapNodes; j++) {
+      gradShapeMatX(i, j) = allDPsi(j, 3*i);
+      gradShapeMatY(i, j) = allDPsi(j, 3*i+1);
+      gradShapeMatZ(i, j) = allDPsi(j, 3*i+2);
+    }
+  }
+}
+
+void GradientBasis::getGradientsFromNodes(const fullMatrix<double> &nodes,
+                                          fullMatrix<double> *dxyzdX,
+                                          fullMatrix<double> *dxyzdY,
+                                          fullMatrix<double> *dxyzdZ) const
+{
+  if (dxyzdX) gradShapeMatX.mult(nodes, *dxyzdX);
+  if (dxyzdY) gradShapeMatY.mult(nodes, *dxyzdY);
+  if (dxyzdZ) gradShapeMatZ.mult(nodes, *dxyzdZ);
+}
+
+JacobianBasis::JacobianBasis(int tag, int jacOrder)
 {
   const int parentType = ElementType::ParentTypeFromTag(tag);
   const int order = ElementType::OrderFromTag(tag);
-  const int jacobianOrder =  JacobianBasis::jacobianOrder(parentType, order);
-  const int primJacobianOrder =  JacobianBasis::jacobianOrder(parentType, 1);
+  int jacobianOrder;
+  if (jacOrder < 0)
+    jacobianOrder = JacobianBasis::jacobianOrder(parentType, order);
+  else
+    jacobianOrder = jacOrder;
+  const int primJacobianOrder = JacobianBasis::jacobianOrder(parentType, 1);
 
   fullMatrix<double> lagPoints;                                  // Sampling points
 
@@ -58,7 +127,7 @@ JacobianBasis::JacobianBasis(int tag)
       lagPoints = generateJacPointsPyramid(jacobianOrder);
       break;
     default :
-      Msg::Error("Unknown Jacobian function space for element type %d", tag);
+      Msg::Error("Unknown Jacobian function space for element tag %d", tag);
       return;
   }
   numJacNodes = lagPoints.size1();
@@ -67,22 +136,7 @@ JacobianBasis::JacobianBasis(int tag)
   bezier = BasisFactory::getBezierBasis(parentType, jacobianOrder);
 
   // Store shape function gradients of mapping at Jacobian nodes
-  fullMatrix<double> allDPsi;
-  const nodalBasis *mapBasis = BasisFactory::getNodalBasis(tag);
-
-  mapBasis->df(lagPoints, allDPsi);
-  numMapNodes = allDPsi.size1();
-
-  gradShapeMatX.resize(numJacNodes, numMapNodes);
-  gradShapeMatY.resize(numJacNodes, numMapNodes);
-  gradShapeMatZ.resize(numJacNodes, numMapNodes);
-  for (int i=0; i<numJacNodes; i++) {
-    for (int j=0; j<numMapNodes; j++) {
-      gradShapeMatX(i, j) = allDPsi(j, 3*i);
-      gradShapeMatY(i, j) = allDPsi(j, 3*i+1);
-      gradShapeMatZ(i, j) = allDPsi(j, 3*i+2);
-    }
-  }
+  _gradBasis = BasisFactory::getGradientBasis(tag, jacobianOrder);
 
   // Compute matrix for lifting from primary Jacobian basis to Jacobian basis
   int primJacType = ElementType::getTag(parentType, primJacobianOrder, false);
@@ -133,7 +187,9 @@ JacobianBasis::JacobianBasis(int tag)
   lagPointsFast(numPrimMapNodes,2) = barycenter[2];
 
   fullMatrix<double> allDPsiFast;
+  const nodalBasis *mapBasis = BasisFactory::getNodalBasis(tag);
   mapBasis->df(lagPointsFast, allDPsiFast);
+  numMapNodes = mapBasis->getNumShapeFunctions();
 
   gradShapeMatXFast.resize(numJacNodesFast, numMapNodes);
   gradShapeMatYFast.resize(numJacNodesFast, numMapNodes);
@@ -145,7 +201,6 @@ JacobianBasis::JacobianBasis(int tag)
       gradShapeMatZFast(i, j) = allDPsiFast(j, 3*i+2);
     }
   }
-
 }
 
 // Computes (unit) normals to straight line element at barycenter (with norm of gradient as return value)
@@ -224,27 +279,33 @@ double JacobianBasis::getPrimJac3D(const fullMatrix<double> &nodesXYZ) const
 
 }
 
-namespace {
-
-// Calculate (signed) Jacobian for one element, given the gradients of the shape functions
-// and vectors for regularization of line and surface Jacobians in 3D.
-inline void computeSignedJacobian(int dim, int numJacNodes, const fullMatrix<double> &gradShapeMatX,
-                                  const fullMatrix<double> &gradShapeMatY, const fullMatrix<double> &gradShapeMatZ,
-                                  const fullMatrix<double> &nodesXYZ, const fullMatrix<double> &normals,
-                                  fullVector<double> &jacobian)
+// Calculate (signed, possibly scaled) Jacobian for one element, with normal vectors to straight element
+// for regularization. Evaluation points depend on the given matrices for shape function gradients.
+template<bool scaling>
+inline void JacobianBasis::getJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                              const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                              const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const
 {
 
+  const int dim = bezier->getDim();
+
   switch (dim) {
 
     case 0 : {
-      for (int i = 0; i < numJacNodes; i++) jacobian(i) = 1.;
+      for (int i = 0; i < nJacNodes; i++) jacobian(i) = 1.;
       break;
     }
 
     case 1 : {
-      fullMatrix<double> dxyzdX(numJacNodes,3);
-      gradShapeMatX.mult(nodesXYZ, dxyzdX);
-      for (int i = 0; i < numJacNodes; i++) {
+      fullMatrix<double> normals(2,3);
+      const double invScale = getPrimNormals1D(nodesXYZ,normals);
+      if (scaling) {
+        const double scale = 1./invScale;
+        normals(0,0) *= scale; normals(0,1) *= scale; normals(0,2) *= scale;            // Faster to scale 1 normal than afterwards
+      }
+      fullMatrix<double> dxyzdX(nJacNodes,3);
+      gSMatX.mult(nodesXYZ, dxyzdX);
+      for (int i = 0; i < nJacNodes; i++) {
         const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2);
         const double &dxdY = normals(0,0), &dydY = normals(0,1), &dzdY = normals(0,2);
         const double &dxdZ = normals(1,0), &dydZ = normals(1,1), &dzdZ = normals(1,2);
@@ -254,29 +315,40 @@ inline void computeSignedJacobian(int dim, int numJacNodes, const fullMatrix<dou
     }
 
     case 2 : {
-      fullMatrix<double> dxyzdX(numJacNodes,3), dxyzdY(numJacNodes,3);
-      gradShapeMatX.mult(nodesXYZ, dxyzdX);
-      gradShapeMatY.mult(nodesXYZ, dxyzdY);
-      for (int i = 0; i < numJacNodes; i++) {
+      fullMatrix<double> normal(1,3);
+      const double invScale = getPrimNormal2D(nodesXYZ,normal);
+      if (scaling) {
+        const double scale = 1./invScale;
+        normal(0,0) *= scale; normal(0,1) *= scale; normal(0,2) *= scale;               // Faster to scale normal than afterwards
+      }
+      fullMatrix<double> dxyzdX(nJacNodes,3), dxyzdY(nJacNodes,3);
+      gSMatX.mult(nodesXYZ, dxyzdX);
+      gSMatY.mult(nodesXYZ, dxyzdY);
+      for (int i = 0; i < nJacNodes; i++) {
         const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2);
         const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2);
-        const double &dxdZ = normals(0,0), &dydZ = normals(0,1), &dzdZ = normals(0,2);
+        const double &dxdZ = normal(0,0), &dydZ = normal(0,1), &dzdZ = normal(0,2);
         jacobian(i) = calcDet3D(dxdX,dydX,dzdX,dxdY,dydY,dzdY,dxdZ,dydZ,dzdZ);
       }
       break;
     }
 
     case 3 : {
-      fullMatrix<double> dxyzdX(numJacNodes,3), dxyzdY(numJacNodes,3), dxyzdZ(numJacNodes,3);
-      gradShapeMatX.mult(nodesXYZ, dxyzdX);
-      gradShapeMatY.mult(nodesXYZ, dxyzdY);
-      gradShapeMatZ.mult(nodesXYZ, dxyzdZ);
-      for (int i = 0; i < numJacNodes; i++) {
+      fullMatrix<double> dum;
+      fullMatrix<double> dxyzdX(nJacNodes,3), dxyzdY(nJacNodes,3), dxyzdZ(nJacNodes,3);
+      gSMatX.mult(nodesXYZ, dxyzdX);
+      gSMatY.mult(nodesXYZ, dxyzdY);
+      gSMatZ.mult(nodesXYZ, dxyzdZ);
+      for (int i = 0; i < nJacNodes; i++) {
         const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2);
         const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2);
         const double &dxdZ = dxyzdZ(i,0), &dydZ = dxyzdZ(i,1), &dzdZ = dxyzdZ(i,2);
         jacobian(i) = calcDet3D(dxdX,dydX,dzdX,dxdY,dydY,dzdY,dxdZ,dydZ,dzdZ);
       }
+      if (scaling) {
+        const double scale = 1./getPrimJac3D(nodesXYZ);
+        jacobian.scale(scale);
+      }
       break;
     }
 
@@ -284,91 +356,32 @@ inline void computeSignedJacobian(int dim, int numJacNodes, const fullMatrix<dou
 
 }
 
-} // namespace
-
-// Calculate (signed) Jacobian for one element, with normal vectors to straight element for regularization.
-// Evaluation points depend on the given matrices for shape function gradients.
+// Calculate signed Jacobian for one element, with normal vectors to straight element for
+// regularization. Evaluation points depend on the given matrices for shape function gradients.
 void JacobianBasis::getSignedJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
                                              const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
                                              const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const
 {
-
-  const int dim = bezier->getDim();
-
-  switch (dim) {
-
-    case 1 : {
-      fullMatrix<double> normals(2,3);
-      getPrimNormals1D(nodesXYZ,normals);
-      computeSignedJacobian(dim,nJacNodes,gSMatX,gSMatY,gSMatZ,nodesXYZ,normals,jacobian);
-      break;
-    }
-
-    case 2 : {
-      fullMatrix<double> normal(1,3);
-      getPrimNormal2D(nodesXYZ,normal);
-      computeSignedJacobian(dim,nJacNodes,gSMatX,gSMatY,gSMatZ,nodesXYZ,normal,jacobian);
-      break;
-    }
-
-    case 0 :
-    case 3 : {
-      fullMatrix<double> dum;
-      computeSignedJacobian(dim,nJacNodes,gSMatX,gSMatY,gSMatZ,nodesXYZ,dum,jacobian);
-      break;
-    }
-
-  }
-
+  getJacobianGeneral<false>(nJacNodes, gSMatX,  gSMatY, gSMatZ, nodesXYZ, jacobian);
 }
 
-// Calculate scaled (signed) Jacobian for one element, with normal vectors to straight element for regularization
-// and scaling. Evaluation points depend on the given matrices for shape function gradients.
+// Calculate (signed) scaled Jacobian for one element, with normal vectors to straight element
+// for regularization. Evaluation points depend on the given matrices for shape function gradients.
 void JacobianBasis::getScaledJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
                                              const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
                                              const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const
 {
-
-  const int dim = bezier->getDim();
-
-  switch (dim) {
-
-    case 1 : {
-      fullMatrix<double> normals(2,3);
-      const double scale = 1./getPrimNormals1D(nodesXYZ,normals);
-      normals(0,0) *= scale; normals(0,1) *= scale; normals(0,2) *= scale;  // Faster to scale 1 normal than afterwards
-      computeSignedJacobian(dim,nJacNodes,gSMatX,gSMatY,gSMatZ,nodesXYZ,normals,jacobian);
-      break;
-    }
-
-    case 2 : {
-      fullMatrix<double> normal(1,3);
-      const double scale = 1./getPrimNormal2D(nodesXYZ,normal);
-      normal(0,0) *= scale; normal(0,1) *= scale; normal(0,2) *= scale;     // Faster to scale normal than afterwards
-      computeSignedJacobian(dim,nJacNodes,gSMatX,gSMatY,gSMatZ,nodesXYZ,normal,jacobian);
-      break;
-    }
-
-    case 0 :
-    case 3 : {
-      fullMatrix<double> dum;
-      const double scale = 1./getPrimJac3D(nodesXYZ);
-      computeSignedJacobian(dim,nJacNodes,gSMatX,gSMatY,gSMatZ,nodesXYZ,dum,jacobian);
-      jacobian.scale(scale);
-      break;
-    }
-
-  }
-
+  getJacobianGeneral<true>(nJacNodes, gSMatX,  gSMatY, gSMatZ, nodesXYZ, jacobian);
 }
 
-// Calculate (signed) Jacobian for several elements.
-// Evaluation points depend on the given matrices for shape function gradients.
+// Calculate (signed, possibly scaled) Jacobian for several elements, with normal vectors to straight
+// elements for regularization. Evaluation points depend on the given matrices for shape function gradients.
 // TODO: Optimize and test 1D & 2D
-void JacobianBasis::getSignedJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
-                                             const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
-                                             const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
-                                             const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const
+template<bool scaling>
+inline void JacobianBasis::getJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                              const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                              const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
+                                              const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const
 {
 
   switch (bezier->getDim()) {
@@ -385,14 +398,18 @@ void JacobianBasis::getSignedJacobianGeneral(int nJacNodes, const fullMatrix<dou
       fullMatrix<double> dxdX(nJacNodes,numEl), dydX(nJacNodes,numEl), dzdX(nJacNodes,numEl);
       gSMatX.mult(nodesX, dxdX); gSMatX.mult(nodesY, dydX); gSMatX.mult(nodesZ, dzdX);
       for (int iEl = 0; iEl < numEl; iEl++) {
-        fullMatrix<double> nodesXYZ(numPrimJacNodes,3);
-        for (int i = 0; i < numPrimJacNodes; i++) {
+        fullMatrix<double> nodesXYZ(numPrimMapNodes,3);
+        for (int i = 0; i < numPrimMapNodes; i++) {
           nodesXYZ(i,0) = nodesX(i,iEl);
           nodesXYZ(i,1) = nodesY(i,iEl);
           nodesXYZ(i,2) = nodesZ(i,iEl);
         }
         fullMatrix<double> normals(2,3);
-        getPrimNormals1D(nodesXYZ,normals);
+        const double invScale = getPrimNormals1D(nodesXYZ,normals);
+        if (scaling) {
+          const double scale = 1./invScale;
+          normals(0,0) *= scale; normals(0,1) *= scale; normals(0,2) *= scale;                // Faster to scale 1 normal than afterwards
+        }
         const double &dxdY = normals(0,0), &dydY = normals(0,1), &dzdY = normals(0,2);
         const double &dxdZ = normals(1,0), &dydZ = normals(1,1), &dzdZ = normals(1,2);
         for (int i = 0; i < nJacNodes; i++)
@@ -410,14 +427,18 @@ void JacobianBasis::getSignedJacobianGeneral(int nJacNodes, const fullMatrix<dou
       gSMatX.mult(nodesX, dxdX); gSMatX.mult(nodesY, dydX); gSMatX.mult(nodesZ, dzdX);
       gSMatY.mult(nodesX, dxdY); gSMatY.mult(nodesY, dydY); gSMatY.mult(nodesZ, dzdY);
       for (int iEl = 0; iEl < numEl; iEl++) {
-        fullMatrix<double> nodesXYZ(numPrimJacNodes,3);
-        for (int i = 0; i < numPrimJacNodes; i++) {
+        fullMatrix<double> nodesXYZ(numPrimMapNodes,3);
+        for (int i = 0; i < numPrimMapNodes; i++) {
           nodesXYZ(i,0) = nodesX(i,iEl);
           nodesXYZ(i,1) = nodesY(i,iEl);
           nodesXYZ(i,2) = nodesZ(i,iEl);
         }
         fullMatrix<double> normal(1,3);
-        getPrimNormal2D(nodesXYZ,normal);
+        const double invScale = getPrimNormal2D(nodesXYZ,normal);
+        if (scaling) {
+          const double scale = 1./invScale;
+          normal(0,0) *= scale; normal(0,1) *= scale; normal(0,2) *= scale;                   // Faster to scale normal than afterwards
+        }
         const double &dxdZ = normal(0,0), &dydZ = normal(0,1), &dzdZ = normal(0,2);
         for (int i = 0; i < nJacNodes; i++)
           jacobian(i,iEl) = calcDet3D(dxdX(i,iEl),dydX(i,iEl),dzdX(i,iEl),
@@ -435,11 +456,22 @@ void JacobianBasis::getSignedJacobianGeneral(int nJacNodes, const fullMatrix<dou
       gSMatX.mult(nodesX, dxdX); gSMatX.mult(nodesY, dydX); gSMatX.mult(nodesZ, dzdX);
       gSMatY.mult(nodesX, dxdY); gSMatY.mult(nodesY, dydY); gSMatY.mult(nodesZ, dzdY);
       gSMatZ.mult(nodesX, dxdZ); gSMatZ.mult(nodesY, dydZ); gSMatZ.mult(nodesZ, dzdZ);
-      for (int iEl = 0; iEl < numEl; iEl++)
+      for (int iEl = 0; iEl < numEl; iEl++) {
         for (int i = 0; i < nJacNodes; i++)
           jacobian(i,iEl) = calcDet3D(dxdX(i,iEl),dydX(i,iEl),dzdX(i,iEl),
                                       dxdY(i,iEl),dydY(i,iEl),dzdY(i,iEl),
                                       dxdZ(i,iEl),dydZ(i,iEl),dzdZ(i,iEl));
+        if (scaling) {
+          fullMatrix<double> nodesXYZ(numPrimMapNodes,3);
+          for (int i = 0; i < numPrimMapNodes; i++) {
+            nodesXYZ(i,0) = nodesX(i,iEl);
+            nodesXYZ(i,1) = nodesY(i,iEl);
+            nodesXYZ(i,2) = nodesZ(i,iEl);
+          }
+          const double scale = 1./getPrimJac3D(nodesXYZ);
+          for (int i = 0; i < nJacNodes; i++) jacobian(i,iEl) *= scale;
+        }
+      }
       break;
     }
 
@@ -447,6 +479,26 @@ void JacobianBasis::getSignedJacobianGeneral(int nJacNodes, const fullMatrix<dou
 
 }
 
+// Calculate signed Jacobian for several elements, with normal vectors to straight elements for
+// regularization. Evaluation points depend on the given matrices for shape function gradients.
+void JacobianBasis::getSignedJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                             const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                             const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
+                                             const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const
+{
+  getJacobianGeneral<false>(nJacNodes, gSMatX,  gSMatY, gSMatZ, nodesX, nodesY, nodesZ, jacobian);
+}
+
+// Calculate (signed) scaled Jacobian for several elements, with normal vectors to straight elements
+// for regularization. Evaluation points depend on the given matrices for shape function gradients.
+void JacobianBasis::getScaledJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                             const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                             const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
+                                             const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const
+{
+  getJacobianGeneral<true>(nJacNodes, gSMatX,  gSMatY, gSMatZ, nodesX, nodesY, nodesZ, jacobian);
+}
+
 // Calculate (signed) Jacobian and its gradients for one element, with normal vectors to straight element
 // for regularization. Evaluation points depend on the given matrices for shape function gradients.
 void JacobianBasis::getSignedJacAndGradientsGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
@@ -572,8 +624,8 @@ void JacobianBasis::getMetricMinAndGradients(const fullMatrix<double> &nodesXYZ,
   for (int l = 0; l < numJacNodes; l++) {
     double jac[2][2] = {{0., 0.}, {0., 0.}};
     for (int i = 0; i < numMapNodes; i++) {
-      const double &dPhidX = gradShapeMatX(l,i);
-      const double &dPhidY = gradShapeMatY(l,i);
+      const double &dPhidX = _gradBasis->gradShapeMatX(l,i);
+      const double &dPhidY = _gradBasis->gradShapeMatY(l,i);
       const double dpsidx = dPhidX * invJaci[0][0] + dPhidY * invJaci[1][0];
       const double dpsidy = dPhidX * invJaci[0][1] + dPhidY * invJaci[1][1];
       jac[0][0] += nodesXYZ(i,0) * dpsidx;
@@ -596,8 +648,8 @@ void JacobianBasis::getMetricMinAndGradients(const fullMatrix<double> &nodesXYZ,
     const double aetaxi  = ayx * invJaci[0][0] + ayy * invJaci[0][1];
     const double axieta  = axx * invJaci[1][0] + axy * invJaci[1][1];
     for (int i = 0; i < numMapNodes; i++) {
-      const double &dPhidX = gradShapeMatX(l,i);
-      const double &dPhidY = gradShapeMatY(l,i);
+      const double &dPhidX = _gradBasis->gradShapeMatX(l,i);
+      const double &dPhidY = _gradBasis->gradShapeMatY(l,i);
       gradLambdaJ(l, i + 0 * numMapNodes) = axixi * dPhidX + axieta * dPhidY;
       gradLambdaJ(l, i + 1 * numMapNodes) = aetaxi * dPhidX + aetaeta * dPhidY;
     }
@@ -605,9 +657,26 @@ void JacobianBasis::getMetricMinAndGradients(const fullMatrix<double> &nodesXYZ,
 
 }
 
+void JacobianBasis::interpolate(const fullVector<double> &jacobian,
+                                const fullMatrix<double> &uvw,
+                                fullMatrix<double> &result,
+                                bool areBezier) const
+{
+  fullMatrix<double> bezM(jacobian.size(), 1);
+  fullVector<double> bez;
+  bez.setAsProxy(bezM, 0);
+
+  if (areBezier)
+    bez.setAll(jacobian);
+  else
+    lag2Bez(jacobian, bez);
+
+  bezier->interpolate(bezM, uvw, result);
+}
+
 fullMatrix<double> JacobianBasis::generateJacMonomialsPyramid(int order)
 {
-  int nbMonomials = (order+3)*((order+3)+1)*(2*(order+3)+1)/6 - 5;
+  const int nbMonomials = (order+3)*(order+3)*(order+1);
   fullMatrix<double> monomials(nbMonomials, 3);
 
   if (order == 0) {
@@ -637,28 +706,28 @@ fullMatrix<double> JacobianBasis::generateJacMonomialsPyramid(int order)
   monomials(4, 1) = 0;
   monomials(4, 2) = order;
 
-  monomials(5, 0) = 2;
+  monomials(5, 0) = order+2;
   monomials(5, 1) = 0;
   monomials(5, 2) = order;
 
-  monomials(6, 0) = 2;
-  monomials(6, 1) = 2;
+  monomials(6, 0) = order+2;
+  monomials(6, 1) = order+2;
   monomials(6, 2) = order;
 
   monomials(7, 0) = 0;
-  monomials(7, 1) = 2;
+  monomials(7, 1) = order+2;
   monomials(7, 2) = order;
 
   int index = 8;
 
-  static const int bottom_edges[8][2] = {
+  static const int bottom_edges[4][2] = {
     {0, 1},
     {1, 2},
     {2, 3},
     {3, 0}
   };
 
-  // bottom "edges"
+  // bottom & top "edges"
   for (int iedge = 0; iedge < 4; ++iedge) {
     int i0 = bottom_edges[iedge][0];
     int i1 = bottom_edges[iedge][1];
@@ -671,22 +740,14 @@ fullMatrix<double> JacobianBasis::generateJacMonomialsPyramid(int order)
       monomials(index, 1) = monomials(i0, 1) + i * u_2;
       monomials(index, 2) = 0;
     }
+    for (int i = 1; i < order + 2; ++i, ++index) {
+      monomials(index, 0) = monomials(i0, 0) + i * u_1;
+      monomials(index, 1) = monomials(i0, 1) + i * u_2;
+      monomials(index, 2) = order;
+    }
   }
 
-  // top "edges"
-  for (int iedge = 0; iedge < 4; ++iedge, ++index) {
-    int i0 = bottom_edges[iedge][0] + 4;
-    int i1 = bottom_edges[iedge][1] + 4;
-
-    int u_1 = (monomials(i1,0)-monomials(i0,0)) / 2;
-    int u_2 = (monomials(i1,1)-monomials(i0,1)) / 2;
-
-    monomials(index, 0) = monomials(i0, 0) + u_1;
-    monomials(index, 1) = monomials(i0, 1) + u_2;
-    monomials(index, 2) = monomials(i0, 2);
-  }
-
-  // bottom "face"
+  // bottom & top "face"
   fullMatrix<double> uv = gmshGenerateMonomialsQuadrangle(order);
   uv.add(1);
   for (int i = 0; i < uv.size1(); ++i, ++index) {
@@ -694,16 +755,15 @@ fullMatrix<double> JacobianBasis::generateJacMonomialsPyramid(int order)
     monomials(index, 1) = uv(i, 1);
     monomials(index, 2) = 0;
   }
-
-  // top "face"
-  monomials(index, 0) = 1;
-  monomials(index, 1) = 1;
-  monomials(index, 2) = order;
-  ++index;
+  for (int i = 0; i < uv.size1(); ++i, ++index) {
+    monomials(index, 0) = uv(i, 0);
+    monomials(index, 1) = uv(i, 1);
+    monomials(index, 2) = order;
+  }
 
   // other monomials
+  uv = gmshGenerateMonomialsQuadrangle(order + 2);
   for (int k = 1; k < order; ++k) {
-    fullMatrix<double> uv = gmshGenerateMonomialsQuadrangle(order + 2 - k);
     for (int i = 0; i < uv.size1(); ++i, ++index) {
       monomials(index, 0) = uv(i, 0);
       monomials(index, 1) = uv(i, 1);
@@ -719,16 +779,17 @@ fullMatrix<double> JacobianBasis::generateJacPointsPyramid(int order)
 
   const double p = order + 2;
   for (int i = 0; i < points.size1(); ++i) {
-    points(i, 2) = points(i, 2) * 1. / p;
-    const double duv = -1. + points(i, 2);
-    points(i, 0) = duv + points(i, 0) * 2. / p;
-    points(i, 1) = duv + points(i, 1) * 2. / p;
+    points(i, 2) = points(i, 2) / p;
+    const double scale = 1. - points(i, 2);
+    points(i, 0) = (-1. + 2. * points(i, 0) / p) * scale;
+    points(i, 1) = (-1. + 2. * points(i, 1) / p) * scale;
   }
 
   return points;
 }
 
-int JacobianBasis::jacobianOrder(int parentType, int order) {
+int JacobianBasis::jacobianOrder(int parentType, int order)
+{
   switch (parentType) {
     case TYPE_PNT : return 0;
     case TYPE_LIN : return order - 1;
@@ -745,3 +806,5 @@ int JacobianBasis::jacobianOrder(int parentType, int order) {
       return 0;
   }
 }
+
+
diff --git a/Numeric/JacobianBasis.h b/Numeric/JacobianBasis.h
index f1655c2..9701cec 100644
--- a/Numeric/JacobianBasis.h
+++ b/Numeric/JacobianBasis.h
@@ -12,11 +12,27 @@
 #include "fullMatrix.h"
 
 
+class GradientBasis {
+ public:
+  fullMatrix<double> gradShapeMatX, gradShapeMatY, gradShapeMatZ;
+
+ public :
+
+  GradientBasis(int tag, int order);
+
+  int getNumSamplingPoints() const {return gradShapeMatX.size1();}
+  int getNumMapNodes() const {return gradShapeMatX.size2();}
+
+  void getGradientsFromNodes(const fullMatrix<double> &nodes,
+                             fullMatrix<double> *dxyzdX,
+                             fullMatrix<double> *dxyzdY,
+                             fullMatrix<double> *dxyzdZ) const;
+};
+
+
 class JacobianBasis {
  private:
-  const bezierBasis *bezier;
-
-  fullMatrix<double> gradShapeMatX, gradShapeMatY, gradShapeMatZ;
+  const GradientBasis *_gradBasis;
   fullMatrix<double> gradShapeMatXFast, gradShapeMatYFast, gradShapeMatZFast;
   fullVector<double> primGradShapeBarycenterX, primGradShapeBarycenterY, primGradShapeBarycenterZ;
   fullMatrix<double> matrixPrimJac2Jac;                                   // Lifts Lagrange basis of primary Jac. to Lagrange basis of Jac.
@@ -25,23 +41,10 @@ class JacobianBasis {
   int numMapNodes, numPrimMapNodes;
   int numJacNodesFast;
 
-  void getSignedJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
-                                const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
-                                const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const;
-  void getSignedJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
-                                const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
-                                const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
-                                const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const;
-  void getScaledJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
-                                const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
-                                const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const;
-  void getSignedJacAndGradientsGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
-                                       const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
-                                       const fullMatrix<double> &nodesXYZ, const fullMatrix<double> &normals,
-                                       fullMatrix<double> &JDJ) const;
-
  public :
-  JacobianBasis(int tag);
+  const bezierBasis *bezier;
+
+  JacobianBasis(int tag, int jacOrder = -1);
 
   // Get methods
   inline int getNumJacNodes() const { return numJacNodes; }
@@ -59,7 +62,8 @@ class JacobianBasis {
   double getPrimJac3D(const fullMatrix<double> &nodesXYZ) const;
   inline void getSignedJacAndGradients(const fullMatrix<double> &nodesXYZ,
                                        const fullMatrix<double> &normals, fullMatrix<double> &JDJ) const {
-    getSignedJacAndGradientsGeneral(numJacNodes,gradShapeMatX,gradShapeMatY,gradShapeMatZ,nodesXYZ,normals,JDJ);
+    getSignedJacAndGradientsGeneral(numJacNodes, _gradBasis->gradShapeMatX,
+        _gradBasis->gradShapeMatY, _gradBasis->gradShapeMatZ, nodesXYZ, normals, JDJ);
   }
   inline void getSignedJacAndGradientsFast(const fullMatrix<double> &nodesXYZ,
                                            const fullMatrix<double> &normals, fullMatrix<double> &JDJ) const {
@@ -70,23 +74,25 @@ class JacobianBasis {
                                 const fullMatrix<double> &nodesXYZStraight,
                                 fullVector<double> &lambdaJ , fullMatrix<double> &gradLambdaJ) const;
   inline void getSignedJacobian(const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const {
-    getSignedJacobianGeneral(numJacNodes,gradShapeMatX,gradShapeMatY,gradShapeMatZ,nodesXYZ,jacobian);
-  }
-  inline void getSignedJacobianFast(const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const {
-    getSignedJacobianGeneral(numJacNodesFast,gradShapeMatXFast,gradShapeMatYFast,gradShapeMatZFast,nodesXYZ,jacobian);
+    getSignedJacobianGeneral(numJacNodes, _gradBasis->gradShapeMatX,
+        _gradBasis->gradShapeMatY, _gradBasis->gradShapeMatZ,nodesXYZ,jacobian);
   }
   inline void getSignedJacobian(const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
                                 const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const {
-    getSignedJacobianGeneral(numJacNodes,gradShapeMatX,gradShapeMatY,
-                             gradShapeMatZ,nodesX,nodesY,nodesZ,jacobian);
-  }
-  inline void getSignedJacobianFast(const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
-                                    const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const {
-    getSignedJacobianGeneral(numJacNodesFast,gradShapeMatXFast,gradShapeMatYFast,
-                             gradShapeMatZFast,nodesX,nodesY,nodesZ,jacobian);
+    getSignedJacobianGeneral(numJacNodes, _gradBasis->gradShapeMatX,
+        _gradBasis->gradShapeMatY, _gradBasis->gradShapeMatZ,nodesX,nodesY,nodesZ,jacobian);
   }
   inline void getScaledJacobian(const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const {
-    getScaledJacobianGeneral(numJacNodes,gradShapeMatX,gradShapeMatY,gradShapeMatZ,nodesXYZ,jacobian);
+    getScaledJacobianGeneral(numJacNodes, _gradBasis->gradShapeMatX,
+        _gradBasis->gradShapeMatY, _gradBasis->gradShapeMatZ,nodesXYZ,jacobian);
+  }
+  inline void getScaledJacobian(const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
+                                const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const {
+    getScaledJacobianGeneral(numJacNodes, _gradBasis->gradShapeMatX,
+        _gradBasis->gradShapeMatY, _gradBasis->gradShapeMatZ,nodesX,nodesY,nodesZ,jacobian);
+  }
+  inline void getSignedJacobianFast(const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const {
+    getSignedJacobianGeneral(numJacNodesFast,gradShapeMatXFast,gradShapeMatYFast,gradShapeMatZFast,nodesXYZ,jacobian);
   }
   inline void getScaledJacobianFast(const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const {
     getScaledJacobianGeneral(numJacNodesFast,gradShapeMatXFast,gradShapeMatYFast,gradShapeMatZFast,nodesXYZ,jacobian);
@@ -104,11 +110,46 @@ class JacobianBasis {
   inline void subdivideBezierCoeff(const fullVector<double> &bez, fullVector<double> &result) const {
     bezier->subDivisor.mult(bez,result);
   }
+  //
+  void interpolate(const fullVector<double> &jacobian,
+                   const fullMatrix<double> &uvw,
+                   fullMatrix<double> &result, bool areBezier = false) const;
 
-  // Jacobian basis order and pyramidal basis
+  //
   static int jacobianOrder(int parentType, int order);
   static fullMatrix<double> generateJacMonomialsPyramid(int order);
   static fullMatrix<double> generateJacPointsPyramid(int order);
+
+
+ private :
+  template<bool scaling>
+  inline void getJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                 const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                 const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const;
+  template<bool scaling>
+  inline void getJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                 const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                 const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
+                                 const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const;
+  void getSignedJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const;
+  void getSignedJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
+                                const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const;
+  void getScaledJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                const fullMatrix<double> &nodesXYZ, fullVector<double> &jacobian) const;
+  void getScaledJacobianGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                const fullMatrix<double> &nodesX, const fullMatrix<double> &nodesY,
+                                const fullMatrix<double> &nodesZ, fullMatrix<double> &jacobian) const;
+
+  void getSignedJacAndGradientsGeneral(int nJacNodes, const fullMatrix<double> &gSMatX,
+                                       const fullMatrix<double> &gSMatY, const fullMatrix<double> &gSMatZ,
+                                       const fullMatrix<double> &nodesXYZ, const fullMatrix<double> &normals,
+                                       fullMatrix<double> &JDJ) const;
 };
 
 #endif
diff --git a/Numeric/MetricBasis.cpp b/Numeric/MetricBasis.cpp
new file mode 100644
index 0000000..c94a392
--- /dev/null
+++ b/Numeric/MetricBasis.cpp
@@ -0,0 +1,1628 @@
+// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
+#include "MetricBasis.h"
+#include "BasisFactory.h"
+#include "pointsGenerators.h"
+#include "BasisFactory.h"
+#include <queue>
+#include "OS.h"
+#include <sstream>
+
+double MetricBasis::_tol = 1e-2;
+int MetricBasis::_which = 0;
+
+namespace {
+  double cubicCardanoRoot(double p, double q)
+  {
+    double A = q*q/4 + p*p*p/27;
+    if (A > 0) {
+      double sq = std::sqrt(A);
+      return std::pow(-q/2+sq, 1/3.) + std::pow(-q/2-sq, 1/3.);
+    }
+    else {
+      double module = std::sqrt(-p*p*p/27);
+      double ang = std::acos(-q/2/module);
+      return 2 * std::pow(module, 1/3.) * std::cos(ang/3);
+    }
+  }
+
+  int nChoosek(int n, int k)
+  {
+    if (n < k || k < 0) {
+      Msg::Error("Wrong argument for combination. n %d k %d", n, k);
+      return 1;
+    }
+
+    if (k > n/2) k = n-k;
+    if (k == 1)
+      return n;
+    if (k == 0)
+      return 1;
+
+    int c = 1;
+    for (int i = 1; i <= k; i++, n--) (c *= n) /= i;
+    return c;
+  }
+}
+
+MetricBasis::MetricBasis(int tag)
+{
+  const int type = ElementType::ParentTypeFromTag(tag);
+  const int metOrder = metricOrder(tag);
+  if (type == TYPE_HEX || type == TYPE_PRI) {
+    int order = ElementType::OrderFromTag(tag);
+    _jacobian = new JacobianBasis(tag, 3*order);
+  }
+  else if (type == TYPE_TET)
+    _jacobian = BasisFactory::getJacobianBasis(tag);
+  else
+    Msg::Fatal("metric not implemented for element tag %d", tag);
+  _gradients = BasisFactory::getGradientBasis(tag, metOrder);
+  _bezier = BasisFactory::getBezierBasis(type, metOrder);
+
+  _fillInequalities(metOrder);
+  __TotSubdivision = 0;
+}
+
+double MetricBasis::boundMinR(MElement *el)
+{
+  MetricBasis *metric = (MetricBasis*)BasisFactory::getMetricBasis(el->getTypeForMSH());
+  MetricData *md = NULL;
+  fullMatrix<double> dummy;
+  return metric->getBoundRmin(el, md, dummy);
+}
+
+double MetricBasis::sampleR(MElement *el, int order)
+{
+  MetricBasis *metric = (MetricBasis*)BasisFactory::getMetricBasis(el->getTypeForMSH());
+  MetricData *md = NULL;
+  fullMatrix<double> dummy;
+  return metric->getMinR(el, md, order);
+}
+
+double MetricBasis::getMinR(MElement *el, MetricData *&md, int deg) const
+{
+  fullMatrix<double> samplingPoints;
+
+  switch (el->getType()) {
+    case TYPE_PNT :
+      samplingPoints = gmshGeneratePointsLine(0);
+      break;
+    case TYPE_LIN :
+      samplingPoints = gmshGeneratePointsLine(deg);
+      break;
+    case TYPE_TRI :
+      samplingPoints = gmshGeneratePointsTriangle(deg,false);
+      break;
+    case TYPE_QUA :
+      samplingPoints = gmshGeneratePointsQuadrangle(deg,false);
+      break;
+    case TYPE_TET :
+      samplingPoints = gmshGeneratePointsTetrahedron(deg,false);
+      break;
+    case TYPE_PRI :
+      samplingPoints = gmshGeneratePointsPrism(deg,false);
+      break;
+    case TYPE_HEX :
+      samplingPoints = gmshGeneratePointsHexahedron(deg,false);
+      break;
+    case TYPE_PYR :
+      samplingPoints = JacobianBasis::generateJacPointsPyramid(deg);
+      break;
+    default :
+      Msg::Error("Unknown Jacobian function space for element type %d", el->getType());
+      return -1;
+  }
+
+  if (!md) _getMetricData(el, md);
+
+  static unsigned int aa = 200;
+  bool write = false;
+  if (md->_num < 100000 && ++aa < 200) {
+    write = true;
+    std::stringstream name;
+    name << "HoleMetric_" << el->getNum() << "_";
+    name << (md->_num % 10);
+    name << (md->_num % 100)/10;
+    name << (md->_num % 1000)/100;
+    name << (md->_num % 10000)/1000;
+    name << (md->_num % 100000)/10000;
+    name << ".txt";
+    ((MetricBasis*)this)->file.open(name.str().c_str(), std::fstream::out);
+
+    {
+      fullMatrix<double> *coeff = md->_metcoeffs;
+      fullVector<double> *jac = md->_jaccoeffs;
+      double minp, minpp, maxp, minJ2, maxJ2, minK, mina, maxa, beta, minq, maxq, maxa2, maxa3, maxK2, maxK3, RminBez, RminLag;
+      minp = _minp(*coeff);
+      minpp = _minp2(*coeff);
+      maxp = _maxp(*coeff);
+      minq = _minq(*coeff);
+      maxq = _maxq(*coeff);
+      _minMaxJacobianSqr(*jac, minJ2, maxJ2);
+      _minJ2P3(*coeff, *jac, minK);
+      _minMaxA(*coeff, mina, maxa);
+
+      double phip, term1, dRda;
+      _computeTermBeta(mina, minK, dRda, term1, phip);
+      beta = -3 * mina*mina * term1 / dRda / 6;
+      if (beta*minK-mina*mina*mina < 0) {
+        _maxAstKneg(*coeff, *jac, minK, beta, maxa3);
+        _maxAstKpos(*coeff, *jac, minK, beta, maxa2);
+      }
+      else {
+        _maxAstKpos(*coeff, *jac, minK, beta, maxa3);
+        _maxAstKneg(*coeff, *jac, minK, beta, maxa2);
+        if (beta*minK-maxa3*maxa3*maxa3 < 0) {
+          _maxAstKneg(*coeff, *jac, minK, beta, maxa3);
+          _maxAstKpos(*coeff, *jac, minK, beta, maxa2);
+        }
+      }
+      _maxKstAfast(*coeff, *jac, mina, beta, maxK2);
+      _maxKstAsharp(*coeff, *jac, mina, beta, maxK3);
+
+      /*if (md->_num == 22)
+        _computeRmin(*coeff, *jac, RminLag, RminBez, 0, true);
+      else*/
+      _computeRmin(*coeff, *jac, RminLag, RminBez, 0, false);
+
+      double betaOpt = beta, minaOpt = mina, maxaOpt = maxa3, RminBezOpt;
+      {
+        /*const */double phi = std::acos(.5*(minK-maxa3*maxa3*maxa3+3*maxa3))/3;
+        RminBezOpt = (maxa3+2*std::cos(phi+2*M_PI/3))/(maxa3+2*std::cos(phi));
+        RminBezOpt = std::sqrt(RminBezOpt);
+
+        double RminBez0 = (mina+2*std::cos(phip+M_PI/3))/(mina+2*std::cos(phip-M_PI/3));
+        RminBez0 = std::sqrt(RminBez0);
+        double curmina = mina;
+        double curmaxa = maxa3;
+        while (std::min(RminLag, RminBez0)-RminBezOpt > MetricBasis::_tol) {
+          minaOpt = (curmina + curmaxa) / 2;
+          maxaOpt = curmina;
+          while (maxaOpt < minaOpt) {
+            _computeTermBeta(minaOpt, minK, dRda, term1, phip);
+            betaOpt = -3 * minaOpt*minaOpt * term1 / dRda / 6;
+            if (betaOpt*minK-minaOpt*minaOpt*minaOpt < 0)
+              _maxAstKneg(*coeff, *jac, minK, betaOpt, maxaOpt);
+            else {
+              _maxAstKpos(*coeff, *jac, minK, betaOpt, maxaOpt);
+              if (betaOpt*minK-maxaOpt*maxaOpt*maxaOpt < 0)
+                _maxAstKneg(*coeff, *jac, minK, betaOpt, maxaOpt);
+            }
+            minaOpt = (curmina + minaOpt) / 2;
+          }
+          curmina = minaOpt;
+          curmaxa = maxaOpt;
+          phi = std::acos(.5*(minK-curmaxa*curmaxa*curmaxa+3*curmaxa))/3;
+          RminBezOpt = (curmaxa+2*std::cos(phi+2*M_PI/3))/(curmaxa+2*std::cos(phi));
+          phi = std::acos(.5*(minK-curmina*curmina*curmina+3*curmina))/3;
+          RminBez0 = (curmina+2*std::cos(phi+2*M_PI/3))/(curmina+2*std::cos(phi));
+          RminBezOpt = std::sqrt(RminBezOpt);
+          RminBez0 = std::sqrt(RminBez0);
+        }
+      }
+
+      ((MetricBasis*)this)->file << minK << " ";
+      ((MetricBasis*)this)->file << maxJ2/minpp/minpp/minpp << " ";
+      ((MetricBasis*)this)->file << mina << " " << maxa << " ";
+      ((MetricBasis*)this)->file << beta << " ";
+      ((MetricBasis*)this)->file << minp << " " << maxp << " ";
+      ((MetricBasis*)this)->file << minJ2 << " " << maxJ2 << " ";
+      ((MetricBasis*)this)->file << minpp << " ";
+      ((MetricBasis*)this)->file << minq << " " << maxq << " ";
+      ((MetricBasis*)this)->file << maxa2 << " ";
+      ((MetricBasis*)this)->file << maxa3 << " ";
+      ((MetricBasis*)this)->file << maxK2 << " ";
+      ((MetricBasis*)this)->file << maxK3 << " ";
+      ((MetricBasis*)this)->file << RminBez << " " << RminLag << " ";
+      ((MetricBasis*)this)->file << betaOpt << " ";
+      ((MetricBasis*)this)->file << minaOpt << " " << maxaOpt << std::endl;
+    }
+  }
+
+  double uvw[3];
+  double minmaxQ[2];
+  uvw[0] = samplingPoints(0, 0);
+  uvw[1] = samplingPoints(0, 1);
+  uvw[2] = samplingPoints(0, 2);
+
+  interpolate(el, md, uvw, minmaxQ, write);
+  double min, max = min = std::sqrt(minmaxQ[0]/minmaxQ[1]);
+  for (int i = 1; i < samplingPoints.size1(); ++i) {
+    uvw[0] = samplingPoints(i, 0);
+    uvw[1] = samplingPoints(i, 1);
+    uvw[2] = samplingPoints(i, 2);
+    interpolate(el, md, uvw, minmaxQ, write);
+    double tmp = std::sqrt(minmaxQ[0]/minmaxQ[1]);
+    min = std::min(min, tmp);
+    max = std::max(max, tmp);
+    //Msg::Info("%g (%g, %g)", tmp, min, max);
+  }
+  if (write) {
+    ((MetricBasis*)this)->file.close();
+  }
+  return min;
+}
+
+bool MetricBasis::notStraight(MElement *el, double &metric, int deg) const
+{
+  fullMatrix<double> samplingPoints;
+
+  switch (el->getType()) {
+    case TYPE_PNT :
+      samplingPoints = gmshGeneratePointsLine(0);
+      break;
+    case TYPE_LIN :
+      samplingPoints = gmshGeneratePointsLine(deg);
+      break;
+    case TYPE_TRI :
+      samplingPoints = gmshGeneratePointsTriangle(deg,false);
+      break;
+    case TYPE_QUA :
+      samplingPoints = gmshGeneratePointsQuadrangle(deg,false);
+      break;
+    case TYPE_TET :
+      samplingPoints = gmshGeneratePointsTetrahedron(deg,false);
+      break;
+    case TYPE_PRI :
+      samplingPoints = gmshGeneratePointsPrism(deg,false);
+      break;
+    case TYPE_HEX :
+      samplingPoints = gmshGeneratePointsHexahedron(deg,false);
+      break;
+    case TYPE_PYR :
+      samplingPoints = JacobianBasis::generateJacPointsPyramid(deg);
+      break;
+    default :
+      Msg::Error("Unknown Jacobian function space for element type %d", el->getType());
+      return false;
+  }
+
+  MetricData *md;
+  _getMetricData(el, md);
+
+  double uvw[3];
+  double minmaxQ[2];
+  uvw[0] = samplingPoints(0, 0);
+  uvw[1] = samplingPoints(0, 1);
+  uvw[2] = samplingPoints(0, 2);
+
+  interpolate(el, md, uvw, minmaxQ);
+  double min, max = min = std::sqrt(minmaxQ[0]/minmaxQ[1]);
+  for (int i = 1; i < samplingPoints.size1(); ++i) {
+    uvw[0] = samplingPoints(i, 0);
+    uvw[1] = samplingPoints(i, 1);
+    uvw[2] = samplingPoints(i, 2);
+    interpolate(el, md, uvw, minmaxQ);
+    double tmp = std::sqrt(minmaxQ[0]/minmaxQ[1]);
+    min = std::min(min, tmp);
+    max = std::max(max, tmp);
+    //Msg::Info("%g (%g, %g)", tmp, min, max);
+  }
+
+  if (max-min < max*1e-12) {
+    metric = min;
+    return false;
+  }
+  else {
+    metric = -1;
+    return true;
+  }
+}
+
+double MetricBasis::getBoundRmin(MElement *el, MetricData *&md, fullMatrix<double> &lagCoeff)
+{
+  __curElem = el;
+  int nSampPnts = _gradients->getNumSamplingPoints();
+  int nMapping = _gradients->getNumMapNodes();
+  fullMatrix<double> nodes(nMapping, 3);
+  el->getNodesCoord(nodes);
+
+  // Metric coefficients
+  fullMatrix<double> metCoeffLag;
+
+  switch (el->getDim()) {
+  case 0 :
+    return -1.;
+  case 1 :
+  case 2 :
+    Msg::Fatal("not implemented");
+    break;
+
+  case 3 :
+    {
+      fullMatrix<double> dxyzdX(nSampPnts,3), dxyzdY(nSampPnts,3), dxyzdZ(nSampPnts,3);
+      _gradients->getGradientsFromNodes(nodes, &dxyzdX, &dxyzdY, &dxyzdZ);
+
+      metCoeffLag.resize(nSampPnts, 7);
+      for (int i = 0; i < nSampPnts; i++) {
+        const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2);
+        const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2);
+        const double &dxdZ = dxyzdZ(i,0), &dydZ = dxyzdZ(i,1), &dzdZ = dxyzdZ(i,2);
+        const double dvxdX = dxdX*dxdX + dydX*dydX + dzdX*dzdX;
+        const double dvxdY = dxdY*dxdY + dydY*dydY + dzdY*dzdY;
+        const double dvxdZ = dxdZ*dxdZ + dydZ*dydZ + dzdZ*dzdZ;
+        metCoeffLag(i, 0) = (dvxdX + dvxdY + dvxdZ) / 3;
+        metCoeffLag(i, 1) = dvxdX - metCoeffLag(i, 0);
+        metCoeffLag(i, 2) = dvxdY - metCoeffLag(i, 0);
+        metCoeffLag(i, 3) = dvxdZ - metCoeffLag(i, 0);
+        const double fact = std::sqrt(2);
+        metCoeffLag(i, 4) = fact * (dxdX*dxdY + dydX*dydY + dzdX*dzdY);
+        metCoeffLag(i, 5) = fact * (dxdZ*dxdY + dydZ*dydY + dzdZ*dzdY);
+        metCoeffLag(i, 6) = fact * (dxdX*dxdZ + dydX*dydZ + dzdX*dzdZ);
+      }
+    }
+    break;
+  }
+
+  lagCoeff = metCoeffLag;
+  fullMatrix<double> *metCoeff;
+  metCoeff = new fullMatrix<double>(nSampPnts, metCoeffLag.size2());
+  _bezier->matrixLag2Bez.mult(metCoeffLag, *metCoeff);
+
+  // Jacobian coefficients
+  fullVector<double> jacLag(_jacobian->getNumJacNodes());
+  fullVector<double> *jac = new fullVector<double>(_jacobian->getNumJacNodes());
+  _jacobian->getSignedJacobian(nodes, jacLag);
+  _jacobian->lag2Bez(jacLag, *jac);
+
+  //
+  double RminLag, RminBez;
+
+  /*Msg::Info("----------------");
+  Msg::Info("Jacobian");
+  for (int i = 0; i < jac->size(); ++i) {
+    Msg::Info("%g", (*jac)(i));
+  }
+  Msg::Info("----------------");
+  Msg::Info("Metric");
+  for (int i = 0; i < metCoeff->size1(); ++i) {
+    Msg::Info("%g %g %g %g %g %g %g", (*metCoeff)(i, 0), (*metCoeff)(i, 1), (*metCoeff)(i, 2), (*metCoeff)(i, 3), (*metCoeff)(i, 4), (*metCoeff)(i, 5), (*metCoeff)(i, 6));
+  }
+  Msg::Info("----------------");*/
+
+  _computeRmin(*metCoeff, *jac, RminLag, RminBez, 0);
+  //Msg::Info("el %d", el->getNum());
+  double mina, maxa;
+  _minMaxA(*metCoeff, mina, maxa);
+  static int cntRight = 0, cntTOT = 0;
+  ++cntTOT;
+  if (maxa-mina < 1e-10) {
+    ++cntRight;
+  }
+  //Msg::Info("right %d/%d", cntRight, cntTOT);
+
+
+    fullVector<double> *jjac = new fullVector<double>(*jac);
+    fullMatrix<double> *mmet = new fullMatrix<double>(*metCoeff);
+    /*for (int i = 0; i < jjac->size(); ++i) {
+      Msg::Info(":%g", (*jjac)(i));
+    }
+    for (int i = 0; i < mmet->size1(); ++i) {
+      Msg::Info(":%g | %g %g %g %g %g %g", (*mmet)(i, 0), (*mmet)(i, 1), (*mmet)(i, 2), (*mmet)(i, 3), (*mmet)(i, 4), (*mmet)(i, 5), (*mmet)(i, 6));
+    }*/
+    md = new MetricData(mmet, jjac, RminBez, 0, 0);
+      //Msg::Info("+1 %d", md);
+
+  if (RminLag-RminBez < MetricBasis::_tol) {
+    //Msg::Info("RETURNING %g", RminBez);
+    //Msg::Info("0 subdivision");
+    return RminBez;
+  }
+  else {
+    //MetricData md(metCoeff, jac, RminBez, 0);
+    MetricData *md2 = new MetricData(metCoeff, jac, RminBez, 0, 0);
+      //Msg::Info("+2 %d", md2);
+    ((MetricBasis*)this)->__numSubdivision = 0;
+    ((MetricBasis*)this)->__numSub.resize(20);
+    for (unsigned int i = 0; i < __numSub.size(); ++i) ((MetricBasis*)this)->__numSub[i] = 0;
+    ((MetricBasis*)this)->__maxdepth = 0;
+    //double time = Cpu();
+    static int maxsub = 0, elmax;
+    double tt = _subdivideForRmin(md2, RminLag, MetricBasis::_tol, MetricBasis::_which);
+    if (maxsub < __numSubdivision && tt > 10-10) {
+      maxsub = __numSubdivision;
+      elmax = el->getNum();
+    }
+    //Msg::Info("%d subdivisions (max %d, %d), el %d", __numSubdivision, maxsub, elmax, el->getNum());
+    /*//Msg::Info("> computation time %g", Cpu() - time);
+    Msg::Info("> maxDepth %d", __maxdepth);
+    Msg::Info("> numSubdivision %d", __numSubdivision);
+    int last = __numSub.size();
+    while (--last > 0 && __numSub[last] == 0);
+    for (unsigned int i = 0; i < last+1; ++i) {
+      Msg::Info("> depth %d: %d", i, __numSub[i]);
+    }
+    Msg::Info("RETURNING %g after subdivision", tt);*/
+    return tt;
+  }
+}
+
+void MetricBasis::_fillInequalities(int metricOrder)
+{
+  int dimSimplex = _bezier->_dimSimplex;
+  int dim = _bezier->getDim();
+  fullMatrix<int> exp(_bezier->_exponents.size1(), _bezier->_exponents.size2());
+  for (int i = 0; i < _bezier->_exponents.size1(); ++i) {
+    for (int j = 0; j < _bezier->_exponents.size2(); ++j) {
+      exp(i, j) = static_cast<int>(_bezier->_exponents(i, j) + .5);
+    }
+  }
+  int ncoeff = _gradients->getNumSamplingPoints();
+
+  int countP3 = 0, countJ2 = 0, countA = 0;
+  for (int i = 0; i < ncoeff; i++) {
+    for (int j = i; j < ncoeff; j++) {
+      double num = 1, den = 1;
+      {
+        int compl1 = metricOrder;
+        int compl2 = metricOrder;
+        int compltot = 2*metricOrder;
+        for (int k = 0; k < dimSimplex; k++) {
+          num *= nChoosek(compl1, exp(i, k))
+               * nChoosek(compl2, exp(j, k));
+          den *= nChoosek(compltot, exp(i, k) + exp(j, k));
+          compl1 -= exp(i, k);
+          compl2 -= exp(j, k);
+          compltot -= exp(i, k) + exp(j, k);
+        }
+        for (int k = dimSimplex; k < dim; k++) {
+          num *= nChoosek(metricOrder, exp(i, k))
+               * nChoosek(metricOrder, exp(j, k));
+          den *= nChoosek(2*metricOrder, exp(i, k) + exp(j, k));
+        }
+      }
+
+      if (i != j) num *= 2;
+
+      ++countA;
+      int hash = 0;
+      for (int l = 0; l < dim; l++) {
+        hash += (exp(i, l)+exp(j, l)) * pow_int(2*metricOrder+1, l);
+      }
+      _ineqA[hash].push_back(IneqData(num/den, i, j));
+
+      for (int k = j; k < ncoeff; ++k) {
+        double num = 1, den = 1;
+        {
+          int compl1 = metricOrder;
+          int compl2 = metricOrder;
+          int compl3 = metricOrder;
+          int compltot = 3*metricOrder;
+          for (int l = 0; l < dimSimplex; l++) {
+            num *= nChoosek(compl1, exp(i, l))
+                 * nChoosek(compl2, exp(j, l))
+                 * nChoosek(compl3, exp(k, l));
+            den *= nChoosek(compltot, exp(i, l) + exp(j, l) + exp(k, l));
+            compl1 -= exp(i, l);
+            compl2 -= exp(j, l);
+            compl3 -= exp(k, l);
+            compltot -= exp(i, l) + exp(j, l) + exp(k, l);
+          }
+          for (int l = dimSimplex; l < dim; l++) {
+            num *= nChoosek(metricOrder, exp(i, l))
+                 * nChoosek(metricOrder, exp(j, l))
+                 * nChoosek(metricOrder, exp(k, l));
+            den *= nChoosek(3*metricOrder, exp(i, l) + exp(j, l) + exp(k, l));
+          }
+        }
+
+        if (i == j) {
+          if (j != k) num *= 3;
+        }
+        else {
+          if (j == k || i == k) {
+            num *= 3;
+          }
+          else num *= 6;
+        }
+
+        ++countP3;
+        int hash = 0;
+        for (int l = 0; l < dim; l++) {
+          hash += (exp(i, l)+exp(j, l)+exp(k, l)) * pow_int(3*metricOrder+1, l);
+        }
+        if (j == k && j != i)
+          _ineqP3[hash].push_back(IneqData(num/den, k, j, i));
+        else
+          _ineqP3[hash].push_back(IneqData(num/den, i, j, k));
+      }
+    }
+  }
+
+  exp.resize(_jacobian->bezier->_exponents.size1(),
+             _jacobian->bezier->_exponents.size2());
+  for (int i = 0; i < _jacobian->bezier->_exponents.size1(); ++i) {
+    for (int j = 0; j < _jacobian->bezier->_exponents.size2(); ++j) {
+      exp(i, j) = static_cast<int>(_jacobian->bezier->_exponents(i, j) + .5);
+    }
+  }
+  int njac = _jacobian->getNumJacNodes();
+  for (int i = 0; i < njac; i++) {
+    for (int j = i; j < njac; j++) {
+      int order = metricOrder/2*3;
+      double num = 1, den = 1;
+      {
+        int compl1 = order;
+        int compl2 = order;
+        int compltot = 2*order;
+        for (int k = 0; k < dimSimplex; k++) {
+          num *= nChoosek(compl1, exp(i, k))
+               * nChoosek(compl2, exp(j, k));
+          den *= nChoosek(compltot, exp(i, k) + exp(j, k));
+          compl1 -= exp(i, k);
+          compl2 -= exp(j, k);
+          compltot -= exp(i, k) + exp(j, k);
+        }
+      }
+      for (int k = dimSimplex; k < dim; k++) {
+        num *= nChoosek(order, exp(i, k))
+             * nChoosek(order, exp(j, k));
+        den *= nChoosek(2*order, exp(i, k) + exp(j, k));
+      }
+
+      if (i != j) num *= 2;
+
+      ++countJ2;
+      int hash = 0;
+      for (int k = 0; k < dim; k++) {
+        hash += (exp(i, k)+exp(j, k)) * pow_int(2*order+1, k);
+      }
+      _ineqJ2[hash].push_back(IneqData(num/den, i, j));
+    }
+  }
+
+  _lightenInequalities(countJ2, countP3, countA);
+
+  /*Msg::Info("A : %d / %d", countA, ncoeff*(ncoeff+1)/2);
+  Msg::Info("J2 : %d / %d", countJ2, njac*(njac+1)/2);
+  Msg::Info("P3 : %d / %d", countP3, ncoeff*(ncoeff+1)*(ncoeff+2)/6);*/
+}
+
+void MetricBasis::_lightenInequalities(int &countj, int &countp, int &counta)
+{
+  double tol = .0;
+  std::map<int, std::vector<IneqData> >::iterator it, itbeg[3], itend[3];
+
+  int cnt[3] = {0,0,0};
+  itbeg[0] = _ineqJ2.begin();
+  itbeg[1] = _ineqP3.begin();
+  itbeg[2] = _ineqA.begin();
+  itend[0] = _ineqJ2.end();
+  itend[1] = _ineqP3.end();
+  itend[2] = _ineqA.end();
+  for (int k = 0; k < 3; ++k) {
+    it = itbeg[k];
+    while (it != itend[k]) {
+      std::sort(it->second.begin(), it->second.end(), gterIneq());
+
+      double rmved = .0;
+      while (it->second.size() && rmved + it->second.back().val <= tol) {
+        rmved += it->second.back().val;
+        it->second.pop_back();
+        ++cnt[k];
+      }
+      const double factor = 1-rmved;
+      for (unsigned int i = 0; i < it->second.size(); ++i) {
+        it->second[i].val /= factor;
+      }
+      ++it;
+    }
+  }
+  countj -= cnt[0];
+  countp -= cnt[1];
+  counta -= cnt[2];
+}
+
+void MetricBasis::interpolate(const MElement *el, const MetricData *md, const double *uvw, double *minmaxQ, bool write) const
+{
+  if (minmaxQ == NULL) {
+    Msg::Error("Cannot write solution of interpolation");
+    return;
+  }
+
+  int order = _bezier->getOrder();
+
+  int dimSimplex = 0;
+  fullMatrix<double> exponents;
+  double bezuvw[3];
+  switch (el->getType()) {
+  case TYPE_PYR:
+    bezuvw[0] = .5 * (1 + uvw[0]);
+    bezuvw[1] = .5 * (1 + uvw[1]);
+    bezuvw[2] = uvw[2];
+    //_interpolateBezierPyramid(uvw, minmaxQ);
+    return;
+
+  case TYPE_HEX:
+    bezuvw[0] = .5 * (1 + uvw[0]);
+    bezuvw[1] = .5 * (1 + uvw[1]);
+    bezuvw[2] = .5 * (1 + uvw[2]);
+    dimSimplex = 0;
+    exponents = gmshGenerateMonomialsHexahedron(order);
+    break;
+
+  case TYPE_TET:
+    bezuvw[0] = uvw[0];
+    bezuvw[1] = uvw[1];
+    bezuvw[2] = uvw[2];
+    dimSimplex = 3;
+    exponents = gmshGenerateMonomialsTetrahedron(order);
+    break;
+
+  case TYPE_PRI:
+    bezuvw[0] = uvw[0];
+    bezuvw[1] = uvw[1];
+    bezuvw[2] = .5 * (1 + uvw[2]);
+    dimSimplex = 2;
+    exponents = gmshGenerateMonomialsPrism(order);
+    break;
+  }
+
+  int numCoeff = exponents.size1();
+  int dim = exponents.size2();
+
+  fullMatrix<double> metcoeffs = *md->_metcoeffs;
+  fullVector<double> jaccoeffs = *md->_jaccoeffs;
+
+  double *terms = new double[metcoeffs.size2()];
+  for (int t = 0; t < metcoeffs.size2(); ++t) {
+    terms[t] = 0;
+    for (int i = 0; i < numCoeff; i++) {
+      double dd = 1;
+      double pointCompl = 1.;
+      int exponentCompl = order;
+      for (int k = 0; k < dimSimplex; k++) {
+        dd *= nChoosek(exponentCompl, (int) exponents(i, k))
+          * pow(bezuvw[k], exponents(i, k));
+        pointCompl -= bezuvw[k];
+        exponentCompl -= (int) exponents(i, k);
+      }
+      dd *= pow(pointCompl, exponentCompl);
+
+      for (int k = dimSimplex; k < dim; k++)
+        dd *= nChoosek(order, (int) exponents(i, k))
+            * pow(bezuvw[k], exponents(i, k))
+            * pow(1. - bezuvw[k], order - exponents(i, k));
+      terms[t] += metcoeffs(i, t) * dd;
+    }
+  }
+
+  switch (metcoeffs.size2()) {
+  case 1:
+    minmaxQ[0] = terms[0];
+    minmaxQ[1] = terms[0];
+    break;
+
+  case 3:
+  {
+    double tmp = pow(terms[1], 2);
+    tmp += pow(terms[2], 2);
+    tmp = std::sqrt(tmp);
+    minmaxQ[0] = terms[0] - tmp;
+    minmaxQ[1] = terms[0] + tmp;
+  }
+    break;
+
+  case 7:
+  {
+    double tmp = pow(terms[1], 2);
+    tmp += pow(terms[2], 2);
+    tmp += pow(terms[3], 2);
+    tmp += pow(terms[4], 2);
+    tmp += pow(terms[5], 2);
+    tmp += pow(terms[6], 2);
+    tmp = std::sqrt(tmp);
+    double factor = std::sqrt(6)/3;
+    if (tmp < 1e-3*terms[0]) {
+      minmaxQ[0] = terms[0] - factor * tmp;
+      minmaxQ[1] = terms[0] + factor * tmp;
+    }
+    else {
+      double phi;
+      //{
+        fullMatrix<double> nodes(1, 3);
+        nodes(0, 0) = uvw[0];
+        nodes(0, 1) = uvw[1];
+        nodes(0, 2) = uvw[2];
+
+        fullMatrix<double> result;
+        _jacobian->interpolate(jaccoeffs, nodes, result, true);
+        phi = result(0, 0)*result(0, 0);
+      //}
+      phi -= terms[0]*terms[0]*terms[0];
+      phi += .5*terms[0]*tmp*tmp;
+      phi /= tmp*tmp*tmp;
+      phi *= 3*std::sqrt(6);
+      if (phi >  1) phi =  1;
+      if (phi < -1) phi = -1;
+      phi = std::acos(phi)/3;
+      minmaxQ[0] = terms[0] + factor * tmp * std::cos(phi + 2*M_PI/3);
+      minmaxQ[1] = terms[0] + factor * tmp * std::cos(phi);
+      ((MetricBasis*)this)->file << terms[0] << " " << tmp/std::sqrt(6) << " " << result(0, 0) << std::endl;
+    }
+  }
+  break;
+
+  default:
+    Msg::Error("Wrong number of functions for metric: %d",
+               metcoeffs.size2());
+  }
+
+  delete[] terms;
+}
+
+int MetricBasis::metricOrder(int tag)
+{
+  const int parentType = ElementType::ParentTypeFromTag(tag);
+  const int order = ElementType::OrderFromTag(tag);
+
+  switch (parentType) {
+    case TYPE_PNT : return 0;
+
+    case TYPE_LIN : return order;
+
+    case TYPE_TRI :
+    case TYPE_TET : return 2*order-2;
+
+    case TYPE_QUA :
+    case TYPE_PRI :
+    case TYPE_HEX :
+    case TYPE_PYR : return 2*order;
+    default :
+      Msg::Error("Unknown element type %d, return order 0", parentType);
+      return 0;
+  }
+}
+
+void MetricBasis::_computeRmin(
+    const fullMatrix<double> &coeff, const fullVector<double> &jac,
+    double &RminLag, double &RminBez,
+    int depth, bool debug) const
+{
+  RminLag = 1.;
+
+  for (int i = 0; i < _bezier->getNumLagCoeff(); ++i) {
+    double q = coeff(i, 0);
+    double p = 0;
+    for (int k = 1; k < 7; ++k) {
+      p += pow_int(coeff(i, k), 2);
+    }
+    p = std::sqrt(p/6);
+    const double a = q/p;
+    if (a > 1e4) {
+      RminLag = std::min(RminLag, std::sqrt((a - std::sqrt(3)) / (a + std::sqrt(3))));
+    }
+    else {
+      const double x = .5 * (jac(i)/p/p*jac(i)/p - a*a*a + 3*a);
+      if (x >  1.1 || x < -1.1) {
+        if (!depth) {
+          Msg::Error("+ phi %g (jac %g, q %g, p %g)", x, jac(i), q, p);
+          Msg::Info("%g + %g - %g = %g", jac(i)*jac(i)/p/p/p, .5 * q/p, q*q*q/p/p/p, (jac(i)*jac(i)+.5 * q*p*p-q*q*q)/p/p/p);
+        }
+        else if (depth == 1)
+          Msg::Error("- phi %g @ %d(%d) (jac %g, q %g, p %g)", x, depth, i, jac(i), q, p);
+      }
+
+      double tmpR;
+      if (x >=  1)
+        tmpR = (a - 1) / (a + 2);
+      else if (x <= -1)
+        tmpR = (a - 2) / (a + 1);
+      else {
+        const double phi = std::acos(x)/3;
+        tmpR = (a + 2*std::cos(phi + 2*M_PI/3)) / (a + 2*std::cos(phi));
+      }
+      if (tmpR < 0) {
+        if (tmpR < -1e-7) Msg::Fatal("3 s normal ? %g (%g, %g, %g) or (%g, %g)",
+            tmpR, p/std::sqrt(6), q, jac(i)*jac(i),
+            q/p*std::sqrt(6), jac(i)*jac(i)/p/p/p*6*std::sqrt(6));
+        else tmpR = 0;
+      }
+      RminLag = std::min(RminLag, std::sqrt(tmpR));
+    }
+  }
+
+  //static int numtot = 0;
+  //++numtot;
+  double minK;
+  _minJ2P3(coeff, jac, minK);
+  if (minK < 1e-10) {
+    RminBez = 0;
+    return;
+  }
+
+  double mina, dummy;
+  _minMaxA(coeff, mina, dummy);
+
+  double term1, dRda, phip;
+  _computeTermBeta(mina, minK, dRda, term1, phip);
+
+  if (dRda < 0) {
+    // TODO : better am ?
+    double amApprox, da;
+    {
+      const double p = -3;
+      double q = -minK - 2;
+      const double a1 = cubicCardanoRoot(p, q);
+      const double phim = std::acos(-1/a1) - M_PI/3;
+      q = -minK + 2*std::cos(3*phim);
+      amApprox = cubicCardanoRoot(p, q);
+      if (minK < 10)
+        da = -.3;
+      else if (minK < 20)
+        da = -.25;
+      else if (minK < 35)
+        da = -.2;
+      else if (minK < 70)
+        da = -.15;
+      else if (minK < 175)
+        da = -.1;
+      else
+        da = -.05;
+    }
+
+    double beta = -3 * mina*mina * term1 / dRda / 6;
+    double maxa;
+    if (beta*minK-mina*mina*mina < 0)
+      _maxAstKneg(coeff, jac, minK, beta, maxa);
+    else {
+      _maxAstKpos(coeff, jac, minK, beta, maxa);
+      if (maxa < amApprox && beta*minK-maxa*maxa*maxa < 0)
+        _maxAstKneg(coeff, jac, minK, beta, maxa);
+    }
+
+    maxa = std::max(mina, maxa);
+    if (amApprox*amApprox*amApprox+da < maxa*maxa*maxa) {
+      // compute better am
+      //
+      double am0 = std::pow(amApprox*amApprox*amApprox+da, 1/3.);
+      double am1 = std::pow(amApprox*amApprox*amApprox+da+.05, 1/3.);
+      //double am0S = am0, am1S = am1;
+      double am = (am0 + am1)/2;
+      double R0 = _Rsafe(am0, minK);
+      double R1 = _Rsafe(am1, minK);
+      double Rnew = _Rsafe(am, minK);
+      if (_chkaK(am0, minK)) Msg::Error("chk am0: %d (%g, %g)", _chkaK(am0, minK), am0, minK);
+      if (_chkaK(am1, minK)) Msg::Error("chk am1: %d (%g, %g)", _chkaK(am1, minK), am1, minK);
+
+      int cnt = 0;
+      while (std::abs(R0-Rnew) > _tol*.01 || std::abs(R1-Rnew) > _tol*.01) {
+        ++cnt;
+        if (R0 > R1) {
+          am0 = am;
+          R0 = Rnew;
+        }
+        else {
+          am1 = am;
+          R1 = Rnew;
+        }
+        am = (am0 + am1)/2;
+        Rnew = _Rsafe(am, minK);
+      }
+      /*static int maxcnt = 0, numcnt = 0, totcnt = 0;
+      ++numcnt;
+      totcnt += cnt;
+      if (maxcnt < cnt) {
+        maxcnt = cnt;
+      }
+      Msg::Info("maxcnt %d (num %d/%d=%g average %g)", maxcnt, numcnt, numtot, (double)numcnt/numtot, (double)totcnt/numcnt);
+      double TESTdRda, dum0, dum1;
+      _computeTermBeta(am0, minK, TESTdRda, dum0, dum1);
+      if (TESTdRda > 1e12) Msg::Fatal("> 0 [%g %g %g] (%g, %g), %g -> [%g, %g] for el %d", R0, Rnew, R1, am, minK, amApprox, am0S, am1S, __curElem->getNum());
+      _computeTermBeta(am1, minK, TESTdRda, dum0, dum1);
+      if (TESTdRda < -1e12) Msg::Fatal("< 0 [%g %g %g] (%g, %g), %g -> [%g, %g] for el %d", R0, Rnew, R1, am, minK, amApprox, am0S, am1S, __curElem->getNum());*/
+      if (am < maxa) {
+        RminBez = _Rsafe(am, minK);
+        //Msg::Info("cpt 1: %d (%g, %g, %g)", _chkaKR(am, minK, RminBez), am, minK, RminBez);
+        if (_chkaKR(am, minK, RminBez)) Msg::Error("cpt 1: %d (%g, %g, %g)", _chkaKR(am, minK, RminBez), am, minK, RminBez);
+        RminBez = std::sqrt(RminBez);
+        return;
+      }
+    }
+
+    RminBez = _Rsafe(maxa, minK);
+    //Msg::Info("cpt 2: %d (%g, %g, %g)", _chkaKR(maxa, minK, RminBez), maxa, minK, RminBez);
+    if (_chkaKR(maxa, minK, RminBez)) Msg::Error("cpt 2: %d (%g, %g, %g)", _chkaKR(maxa, minK, RminBez), maxa, minK, RminBez);
+    RminBez = std::sqrt(RminBez);
+
+    /*double RminBez0 = (mina+2*std::cos(phip+M_PI/3))/(mina+2*std::cos(phip-M_PI/3));
+    RminBez0 = std::sqrt(RminBez0);
+    double curmina = mina;
+    double curmaxa = maxa;
+      //Msg::Info(" ");
+    while (std::min(RminLag, RminBez0)-RminBez > MetricBasis::_tol) {
+      //Msg::Info("%g vs %g", RminBez0, RminBez);
+      double a = (curmina + curmaxa) / 2;
+      double newa = curmina;
+      while (newa < a) {
+        _computeTermBeta(a, minK, dRda, term1, phip, sqrt);
+        beta = -3 * a*a * term1 / sqrt / dRda / 6;
+        if (beta*minK-a*a*a < 0)
+          _maxAstKneg(coeff, jac, minK, beta, newa);
+        else {
+          _maxAstKpos(coeff, jac, minK, beta, newa);
+          if (newa < am && beta*minK-newa*newa*newa < 0)
+            _maxAstKneg(coeff, jac, minK, beta, newa);
+        }
+        a = (curmina + a) / 2;
+      }
+      curmina = a;
+      curmaxa = newa;
+      phi = std::acos(.5*(minK-curmaxa*curmaxa*curmaxa+3*curmaxa))/3;
+      RminBez = (curmaxa+2*std::cos(phi+2*M_PI/3))/(curmaxa+2*std::cos(phi));
+      phi = std::acos(.5*(minK-curmina*curmina*curmina+3*curmina))/3;
+      RminBez0 = (curmina+2*std::cos(phi+2*M_PI/3))/(curmina+2*std::cos(phi));
+      RminBez = std::sqrt(RminBez);
+      RminBez0 = std::sqrt(RminBez0);
+    }*/
+    return;
+  }
+  else if (term1 < 0) {
+    double maxK;
+    double beta = -3 * mina*mina * term1 / dRda / 6;
+    if (beta*minK-mina*mina*mina > 0) Msg::Fatal("Arf pas prevu");
+    //_maxKstAsharp(coeff, jac, mina, beta, maxK);
+    _maxKstAfast(coeff, jac, mina, beta, maxK);
+    const double x = .5*(maxK-mina*mina*mina+3*mina);
+    const double phimin = std::acos(-1/mina) - M_PI/3;
+    double myphi;
+    int which = 0;
+    double tmpphi;
+    if (std::abs(x) > 1) {
+      myphi = phimin;
+      which = 2;
+    }
+    else {
+      const double phimaxK = std::acos(x)/3;
+      tmpphi = phimaxK;
+      myphi = std::max(phimin, phimaxK);
+      if (phimin > phimaxK)
+        which = 2;
+      else
+        which = 1;
+    }
+    RminBez = (mina+2*std::cos(myphi+2*M_PI/3))/(mina+2*std::cos(myphi));
+    //Msg::Info("cpt 3: %d", _chkaKR(mina, maxK, RminBez));
+    int check;
+    if (which == 1) {
+      check = _chkaKR(mina, maxK, RminBez);
+      if (check) {
+        Msg::Error("cpt 3.1: %d (%g, %g, %g)", check, mina, maxK, RminBez);
+        double Kphimin = 2 * std::cos(3*phimin) + mina*mina*mina - 3*mina;
+        Msg::Info("%g->%g %g->%g", maxK, tmpphi/M_PI, Kphimin, phimin/M_PI);
+      }
+    }
+    else {
+      double Kphimin = 2 * std::cos(3*phimin) + mina*mina*mina - 3*mina;
+      check = _chkaKR(mina, Kphimin, RminBez);
+      if (check) Msg::Error("cpt 3.2: %d (%g, %g, %g)", check, mina, Kphimin, RminBez);
+    }
+    RminBez = std::sqrt(RminBez);
+    return;
+  }
+  else {
+    RminBez = (mina+2*std::cos(phip+M_PI/3))/(mina+2*std::cos(phip-M_PI/3));
+    //Msg::Info("cpt 4: %d", _chkaKR(mina, minK, RminBez));
+    if (_chkaKR(mina, minK, RminBez)) Msg::Error("cpt 4: %d (%g, %g, %g) dRda %g", _chkaKR(mina, minK, RminBez), mina, minK, RminBez, dRda);
+    RminBez = std::sqrt(RminBez);
+    return;
+  }
+}
+
+void MetricBasis::_computeRmax(
+    const fullMatrix<double> &coeff, const fullVector<double> &jac,
+    double &RmaxLag) const
+{
+  RmaxLag = 0.;
+
+  for (int i = 0; i < _bezier->getNumLagCoeff(); ++i) {
+    double q = coeff(i, 0);
+    double p = 0;
+    for (int k = 1; k < 7; ++k) {
+      p += pow_int(coeff(i, k), 2);
+    }
+    p = std::sqrt(p/6);
+    const double a = q/p;
+    if (a > 1e4) {
+      RmaxLag = std::max(RmaxLag, std::sqrt((a - std::sqrt(3)) / (a + std::sqrt(3))));
+    }
+    else {
+      const double x = .5 * (jac(i)/p/p*jac(i)/p - a*a*a + 3*a);
+
+      double tmpR;
+      if (x >=  1)
+        tmpR = (a - 1) / (a + 2);
+      else if (x <= -1)
+        tmpR = (a - 2) / (a + 1);
+      else {
+        const double phi = std::acos(x)/3;
+        tmpR = (a + 2*std::cos(phi + 2*M_PI/3)) / (a + 2*std::cos(phi));
+      }
+      if (tmpR < 0) {
+        if (tmpR < -1e-7) Msg::Fatal("3 s normal ? %g (%g, %g, %g) or (%g, %g)",
+            tmpR, p/std::sqrt(6), q, jac(i)*jac(i),
+            q/p*std::sqrt(6), jac(i)*jac(i)/p/p/p*6*std::sqrt(6));
+        else tmpR = 0;
+      }
+      RmaxLag = std::max(RmaxLag, std::sqrt(tmpR));
+    }
+  }
+}
+
+double MetricBasis::_subdivideForRmin(
+    MetricData *md, double RminLag, double tol, int which) const
+{
+  std::priority_queue<MetricData*, std::vector<MetricData*>, lessMinB> subdomains;
+  const int numCoeff = md->_metcoeffs->size2();
+  const int numMetPnts = md->_metcoeffs->size1();
+  const int numJacPnts = md->_jaccoeffs->size();
+  const int numSub = _jacobian->getNumDivisions();
+  subdomains.push(md);
+
+  static unsigned int aa = 200;
+  //bool write = false;
+  if (++aa < 200) {
+    getMinR(__curElem, md, 16);
+  }
+
+  std::vector<fullVector<double>*> trash;
+
+  //Msg::Info("lagrange %g", RminLag);
+
+  while (RminLag - subdomains.top()->_RminBez > tol && subdomains.size() < 25000) {
+    //Msg::Info("%g - %g > %g && %d < %d", RminLag, subdomains.top()->_RminBez, tol, subdomains.size(), pow_int(8,8));
+    fullMatrix<double> *subcoeffs, *coeff;
+    fullVector<double> *subjac, *jac;
+
+    MetricData *current = subdomains.top();
+    subcoeffs = new fullMatrix<double>(numSub*numMetPnts, numCoeff);
+    subjac = new fullVector<double>(numSub*numJacPnts);
+    _bezier->subDivisor.mult(*current->_metcoeffs, *subcoeffs);
+    _jacobian->subdivideBezierCoeff(*current->_jaccoeffs, *subjac);
+    int depth = current->_depth;
+    int num = current->_num;
+      //Msg::Info("d %d RminBez %g / %g", depth, current->_RminBez, RminLag);
+
+    //Msg::Info("delete %d (%d)", current, depth);
+    //Msg::Info(" ");
+    delete current;
+    subdomains.pop();
+
+    ++((MetricBasis*)this)->__numSubdivision;
+    ++((MetricBasis*)this)->__TotSubdivision;
+    ++((MetricBasis*)this)->__numSub[depth];
+    ((MetricBasis*)this)->__maxdepth = std::max(__maxdepth, depth+1);
+      //Msg::Info("subdividing %d", current);
+
+    for (int i = 0; i < numSub; ++i) {
+      coeff = new fullMatrix<double>(numMetPnts, numCoeff);
+      coeff->copy(*subcoeffs, i * numMetPnts, numMetPnts, 0, numCoeff, 0, 0);
+      jac = new fullVector<double>;
+      jac->setAsProxy(*subjac, i * numJacPnts, numJacPnts);
+      double minLag, minBez;
+      _computeRmin(*coeff, *jac, minLag, minBez, depth+1);
+      //Msg::Info("new RminBez %g", minBez);
+      RminLag = std::min(RminLag, minLag);
+      int newNum = num + (i+1) * pow_int(10, depth);
+      MetricData *metData = new MetricData(coeff, jac, minBez, depth+1, newNum);
+
+      if (aa < 200) {
+        getMinR(__curElem, metData, 16);
+      }
+
+      //Msg::Info("    %g (%d)", minLag, metData);
+      //Msg::Info("+4 %d", metData);
+      subdomains.push(metData);
+    }
+    trash.push_back(subjac);
+    delete subcoeffs;
+
+    /*for (unsigned int i = 0; i < vect.size(); ++i) {
+      Msg::Info("v %g", vect[i]->_RminBez);
+    }
+    Msg::Info("top %g (RminLag %g)", subdomains.top()->_RminBez, RminLag);
+    return 0;*/
+    //Msg::Info("RminLag %g - RminBez %g  @ %d", RminLag, subdomains.top()->_RminBez, subdomains.top()->_depth);
+  }
+  //Msg::Info("%g - %g = %g >? %g", RminLag, subdomains.top()->_RminBez, RminLag - subdomains.top()->_RminBez, tol);
+  //Msg::Info("%d <? %d", subdomains.size(), 25000);
+
+  md = subdomains.top();
+  double ans = md->_RminBez;
+  if (_chknumber(ans)) Msg::Error("ISNAN %d", subdomains.size());
+
+  while (subdomains.size()) {
+    md = subdomains.top();
+    subdomains.pop();
+    //Msg::Info("del %d", md);
+    //Msg::Info(" ");
+    delete md;
+  }
+  for (unsigned int i = 0; i < trash.size(); ++i) {
+    delete trash[i];
+  }
+
+  //Msg::Info("bez%g lag%g", ans, RminLag);
+  return ans;
+}
+
+void MetricBasis::_computeTermBeta(double &a, double &K,
+                                   double &dRda, double &term1,
+                                   double &phip) const
+{
+  double x0 = .5 * (K - a*a*a + 3*a);
+  double sin, sqrt;
+  if (x0 > 1) {
+    const double p = -3;
+    double q = -K + 2;
+    a = cubicCardanoRoot(p, q);
+
+    x0 = 1;
+    phip = M_PI / 3;
+    term1 = 1 + .5 * a;
+    sin = std::sqrt(3) / 2;
+    sqrt = 0;
+  }
+  else if (x0 < -1) {
+    K = -2 + a*a*a - 3*a;
+
+    x0 = -1;
+    phip = 2 * M_PI / 3;
+    term1 = 1 - .5 * a;
+    sin = std::sqrt(3) / 2;
+    sqrt = 0;
+  }
+  else {
+    phip = (std::acos(x0) + M_PI) / 3;
+    term1 = 1 + a * std::cos(phip);
+    sin = std::sin(phip);
+    sqrt = std::sqrt(1-x0*x0);
+  }
+  dRda = sin * sqrt + .5 * term1 * (1-a*a);
+}
+
+void MetricBasis::_getMetricData(MElement *el, MetricData *&md) const
+{
+  int nSampPnts = _gradients->getNumSamplingPoints();
+  int nMapping = _gradients->getNumMapNodes();
+  fullMatrix<double> nodes(nMapping, 3);
+  el->getNodesCoord(nodes);
+
+  // Metric coefficients
+  fullMatrix<double> metCoeffLag;
+
+  switch (el->getDim()) {
+  case 0 :
+    md = NULL;
+    return;
+  case 1 :
+  case 2 :
+    Msg::Fatal("not implemented");
+    break;
+
+  case 3 :
+    {
+      fullMatrix<double> dxyzdX(nSampPnts,3), dxyzdY(nSampPnts,3), dxyzdZ(nSampPnts,3);
+      _gradients->getGradientsFromNodes(nodes, &dxyzdX, &dxyzdY, &dxyzdZ);
+
+      metCoeffLag.resize(nSampPnts, 7);
+      for (int i = 0; i < nSampPnts; i++) {
+        const double &dxdX = dxyzdX(i,0), &dydX = dxyzdX(i,1), &dzdX = dxyzdX(i,2);
+        const double &dxdY = dxyzdY(i,0), &dydY = dxyzdY(i,1), &dzdY = dxyzdY(i,2);
+        const double &dxdZ = dxyzdZ(i,0), &dydZ = dxyzdZ(i,1), &dzdZ = dxyzdZ(i,2);
+        const double dvxdX = dxdX*dxdX + dydX*dydX + dzdX*dzdX;
+        const double dvxdY = dxdY*dxdY + dydY*dydY + dzdY*dzdY;
+        const double dvxdZ = dxdZ*dxdZ + dydZ*dydZ + dzdZ*dzdZ;
+        metCoeffLag(i, 0) = (dvxdX + dvxdY + dvxdZ) / 3;
+        metCoeffLag(i, 1) = dvxdX - metCoeffLag(i, 0);
+        metCoeffLag(i, 2) = dvxdY - metCoeffLag(i, 0);
+        metCoeffLag(i, 3) = dvxdZ - metCoeffLag(i, 0);
+        const double fact = std::sqrt(2);
+        metCoeffLag(i, 4) = fact * (dxdX*dxdY + dydX*dydY + dzdX*dzdY);
+        metCoeffLag(i, 5) = fact * (dxdZ*dxdY + dydZ*dydY + dzdZ*dzdY);
+        metCoeffLag(i, 6) = fact * (dxdX*dxdZ + dydX*dydZ + dzdX*dzdZ);
+      }
+    }
+    break;
+  }
+
+  fullMatrix<double> *metCoeff;
+  metCoeff = new fullMatrix<double>(nSampPnts, metCoeffLag.size2());
+  _bezier->matrixLag2Bez.mult(metCoeffLag, *metCoeff);
+
+  // Jacobian coefficients
+  fullVector<double> jacLag(_jacobian->getNumJacNodes());
+  fullVector<double> *jac = new fullVector<double>(_jacobian->getNumJacNodes());
+  _jacobian->getSignedJacobian(nodes, jacLag);
+  _jacobian->lag2Bez(jacLag, *jac);
+
+  md = new MetricData(metCoeff, jac, -1, 0, 0);
+}
+
+double MetricBasis::_minp2(const fullMatrix<double> &coeff) const
+{
+  double min = 1e10;
+  std::map<int, std::vector<IneqData> >::const_iterator it = _ineqA.begin();
+  while (it != _ineqA.end()) {
+    double val = 0;
+    for (unsigned int k = 0; k < it->second.size(); ++k) {
+      const int i = it->second[k].i;
+      const int j = it->second[k].j;
+      double tmp = 0;
+      for (int l = 1; l < 7; ++l) {
+        tmp += coeff(i, l) * coeff(j, l);
+      }
+      val += it->second[k].val * tmp;
+    }
+    min = std::min(val, min);
+    ++it;
+  }
+
+  return min > 0 ? std::sqrt(min/6) : 0;
+}
+
+double MetricBasis::_minp(const fullMatrix<double> &coeff) const
+{
+  fullMatrix<double> minmaxCoeff(2, 6);
+  for (int j = 0; j < 6; ++j) {
+    minmaxCoeff(0, j) = coeff(0, j+1);
+    minmaxCoeff(1, j) = coeff(0, j+1);
+  }
+
+  for (int i = 1; i < coeff.size1(); ++i) {
+    for (int j = 0; j < 6; ++j) {
+      minmaxCoeff(0, j) = std::min(coeff(i, j+1), minmaxCoeff(0, j));
+      minmaxCoeff(1, j) = std::max(coeff(i, j+1), minmaxCoeff(1, j));
+    }
+  }
+
+  double ans = 0;
+  for (int j = 0; j < 6; ++j) {
+    if (minmaxCoeff(0, j) * minmaxCoeff(1, j) > 0) {
+      ans += minmaxCoeff(0, j) > 0 ?
+          pow_int(minmaxCoeff(0, j), 2) :
+          pow_int(minmaxCoeff(1, j), 2);
+    }
+  }
+  return std::sqrt(ans/6);
+}
+
+double MetricBasis::_minq(const fullMatrix<double> &coeff) const
+{
+  double ans = coeff(0, 0);
+  for (int i = 1; i < coeff.size1(); ++i) {
+    if (ans > coeff(i, 0)) ans = coeff(i, 0);
+  }
+  return ans;
+}
+
+double MetricBasis::_maxp(const fullMatrix<double> &coeff) const
+{
+  double ans = 0;
+  for (int i = 0; i < coeff.size1(); ++i) {
+    double tmp = 0;
+    for (int j = 1; j < 7; ++j) {
+      tmp += pow_int(coeff(i, j), 2);
+    }
+    ans = std::max(ans, tmp);
+  }
+  return std::sqrt(ans/6);
+}
+
+double MetricBasis::_maxq(const fullMatrix<double> &coeff) const
+{
+  double ans = coeff(0, 0);
+  for (int i = 1; i < coeff.size1(); ++i) {
+    if (ans < coeff(i, 0)) ans = coeff(i, 0);
+  }
+  return ans;
+}
+
+void MetricBasis::_minMaxA(
+    const fullMatrix<double> &coeff, double &min, double &max) const
+{
+  min = 1e10;
+  max = 0;
+  std::map<int, std::vector<IneqData> >::const_iterator it = _ineqA.begin();
+  while (it != _ineqA.end()) {
+    double num = 0;
+    double den = 0;
+    for (unsigned int k = 0; k < it->second.size(); ++k) {
+      const int i = it->second[k].i;
+      const int j = it->second[k].j;
+      double tmp = 0;
+      for (int l = 1; l < 7; ++l) {
+        tmp += coeff(i, l) * coeff(j, l);
+      }
+      den += it->second[k].val * tmp;
+      num += it->second[k].val * coeff(i, 0) * coeff(j, 0);
+    }
+    double val = num/den;
+    min = std::min(val, min);
+    max = std::max(val, max);
+    ++it;
+  }
+  min *= 6;
+  max *= 6;
+
+  min = min > 1 ? std::sqrt(min) : 1;
+  max = std::sqrt(max);
+}
+
+void MetricBasis::_minMaxJacobianSqr(
+    const fullVector<double> &jac, double &min, double &max) const
+{
+  static int a = 1;
+  if (++a == 1) {
+    for (int i = 1; i < jac.size(); ++i) {
+      Msg::Info("<%g>", jac(i));
+    }
+  }
+  min = max = jac(0);
+  for (int i = 1; i < jac.size(); ++i) {
+    if (min > jac(i)) min = jac(i);
+    if (max < jac(i)) max = jac(i);
+  }
+
+  if (a == 1) {
+      Msg::Info("%g %g", min, max);
+  }
+
+  if (min*max < 0) {
+    max = max > -min ? max*max : min*min;
+    min = 0;
+  }
+  else {
+    if (max > 0) {
+      max = max*max;
+      min = min*min;
+    }
+    else {
+      double tmp = max;
+      max = min*min;
+      min = tmp*tmp;
+    }
+  }
+}
+
+void MetricBasis::_minJ2P3(const fullMatrix<double> &coeff,
+    const fullVector<double> &jac, double &min) const
+{
+  fullVector<double> r(coeff.size1());
+  for (int i = 0; i < coeff.size1(); ++i) {
+    r(i) = 0;
+    for (int l = 1; l < 7; ++l) {
+      r(i) += coeff(i, l) * coeff(i, l);
+    }
+    r(i) = std::sqrt(r(i)/6);
+  }
+
+  min = 1e10;
+  std::map<int, std::vector<IneqData> >::const_iterator itJ, itP;
+  itJ = _ineqJ2.begin();
+  itP = _ineqP3.begin();
+
+  if (_ineqP3.size() != _ineqJ2.size()) Msg::Fatal("sizes P3 %d, J2 %d", _ineqP3.size(), _ineqJ2.size());
+  //Msg::Warning("sizes %d %d", _ineqJ2.size(), _ineqP3.size());
+  int count = 0;
+  while (itJ != _ineqJ2.end() && itP != _ineqP3.end()) {
+    if (count >= (int)_ineqJ2.size()) Msg::Fatal("aaargh");
+    if (itJ->first != itP->first) Msg::Fatal("not same hash %d %d", itJ->first, itP->first);
+
+    double num = 0;
+    //Msg::Info("sizej %d", itJ->second.size());
+    for (unsigned int l = 0; l < itJ->second.size(); ++l) {
+      const int i = itJ->second[l].i;
+      const int j = itJ->second[l].j;
+      num += itJ->second[l].val * jac(i) * jac(j);
+    }
+
+    double den = 0;
+    //Msg::Info("sizep %d", itP->second.size());
+    for (unsigned int l = 0; l < itP->second.size(); ++l) {
+      const int i = itP->second[l].i;
+      const int j = itP->second[l].j;
+      const int k = itP->second[l].k;
+      //Msg::Info("i%d j%d k%d", i, j, k);
+      if (l>=itP->second.size()) Msg::Error("l %d/%d", l, itP->second.size());
+      if (i>=r.size() || j>=r.size()||k>=r.size() ) Msg::Fatal("i%d j%d k%d /%d (%dl%d)", i, j, k, r.size(), count, l);
+      den += itP->second[l].val * r(i) * r(j) * r(k);
+    }
+    //Msg::Info("%g/%g = %g", num, den, num/den);
+    min = std::min(min, num/den);
+    ++itJ;
+    ++itP;
+    ++count;
+  }
+  min = std::max(min, 0.);
+}
+
+void MetricBasis::_maxAstKpos(const fullMatrix<double> &coeff,
+    const fullVector<double> &jac, double minK, double beta, double &maxa) const
+{
+  fullVector<double> P(coeff.size1());
+  for (int i = 0; i < coeff.size1(); ++i) {
+    P(i) = 0;
+    for (int l = 1; l < 7; ++l) {
+      P(i) += coeff(i, l) * coeff(i, l);
+    }
+    P(i) = std::sqrt(P(i)/6);
+  }
+
+  double min = 1e10;
+
+  std::map<int, std::vector<IneqData> >::const_iterator itJ, itP;
+  itJ = _ineqJ2.begin();
+  itP = _ineqP3.begin();
+
+  while (itJ != _ineqJ2.end() && itP != _ineqP3.end()) {
+    double num = 0, den = 0;
+    for (unsigned int l = 0; l < itJ->second.size(); ++l) {
+      const int i = itJ->second[l].i;
+      const int j = itJ->second[l].j;
+      num += itJ->second[l].val * jac(i) * jac(j);
+    }
+    num *= beta;
+    for (unsigned int l = 0; l < itP->second.size(); ++l) {
+      const int i = itP->second[l].i;
+      const int j = itP->second[l].j;
+      const int k = itP->second[l].k;
+      num -= itP->second[l].val * coeff(i, 0) * coeff(j, 0) * coeff(k, 0);
+      den += itP->second[l].val * P(i) * P(j) * P(k);
+    }
+    min = std::min(min, num/den);
+    ++itJ;
+    ++itP;
+  }
+
+  maxa = std::pow(beta*minK-min, 1/3.);
+}
+
+void MetricBasis::_maxAstKneg(const fullMatrix<double> &coeff,
+    const fullVector<double> &jac, double minK, double beta, double &maxa) const
+{
+  fullVector<double> P(coeff.size1());
+  fullMatrix<double> Q(coeff.size1(), coeff.size1());
+  for (int i = 0; i < coeff.size1(); ++i) {
+    P(i) = 0;
+    for (int l = 1; l < 7; ++l) {
+      P(i) += coeff(i, l) * coeff(i, l);
+    }
+    P(i) = std::sqrt(P(i)/6);
+    for (int j = 0; j < coeff.size1(); ++j) {
+      Q(i, j) = 0;
+      for (int l = 1; l < 7; ++l) {
+        Q(i, j) += coeff(i, l) * coeff(j, l);
+      }
+      Q(i, j) /= 6;
+    }
+  }
+
+  double min = 1e10;
+
+  std::map<int, std::vector<IneqData> >::const_iterator itJ, itP;
+  itJ = _ineqJ2.begin();
+  itP = _ineqP3.begin();
+
+  while (itJ != _ineqJ2.end() && itP != _ineqP3.end()) {
+    double num = 0, den = 0;
+    for (unsigned int l = 0; l < itJ->second.size(); ++l) {
+      const int i = itJ->second[l].i;
+      const int j = itJ->second[l].j;
+      num += itJ->second[l].val * jac(i) * jac(j);
+    }
+    num *= beta;
+    for (unsigned int l = 0; l < itP->second.size(); ++l) {
+      const int i = itP->second[l].i;
+      const int j = itP->second[l].j;
+      const int k = itP->second[l].k;
+      num -= itP->second[l].val * coeff(i, 0) * coeff(j, 0) * coeff(k, 0);
+      double tmp = P(i) * Q(j, k);
+      tmp = std::min(tmp, P(j) * Q(i, k));
+      tmp = std::min(tmp, P(k) * Q(i, j));
+      den += itP->second[l].val * tmp;
+    }
+    min = std::min(min, num/den);
+    ++itJ;
+    ++itP;
+  }
+
+  maxa = std::pow(beta*minK-min, 1/3.);
+}
+
+void MetricBasis::_maxKstAfast(const fullMatrix<double> &coeff,
+    const fullVector<double> &jac, double mina, double beta, double &maxK) const
+{
+  fullVector<double> r(coeff.size1());
+  for (int i = 0; i < coeff.size1(); ++i) {
+    r(i) = 0;
+    for (int l = 1; l < 7; ++l) {
+      r(i) += coeff(i, l) * coeff(i, l);
+    }
+    r(i) = std::sqrt(r(i)/6);
+  }
+
+  double min = 1e10;
+
+  std::map<int, std::vector<IneqData> >::const_iterator itJ, itP;
+  itJ = _ineqJ2.begin();
+  itP = _ineqP3.begin();
+
+  while (itJ != _ineqJ2.end() && itP != _ineqP3.end()) {
+    double num = 0, den = 0;
+    for (unsigned int l = 0; l < itJ->second.size(); ++l) {
+      const int i = itJ->second[l].i;
+      const int j = itJ->second[l].j;
+      num -= itJ->second[l].val * jac(i) * jac(j);
+    }
+    num *= beta;
+    for (unsigned int l = 0; l < itP->second.size(); ++l) {
+      const int i = itP->second[l].i;
+      const int j = itP->second[l].j;
+      const int k = itP->second[l].k;
+      num += itP->second[l].val * coeff(i, 0) * coeff(j, 0) * coeff(k, 0);
+      den += itP->second[l].val * r(i) * r(j) * r(k);
+    }
+    min = std::min(min, num/den);
+    ++itJ;
+    ++itP;
+  }
+
+  maxK = 1/beta*(mina*mina*mina-min);
+}
+
+void MetricBasis::_maxKstAsharp(const fullMatrix<double> &coeff,
+    const fullVector<double> &jac, double mina, double beta, double &maxK) const
+{
+  fullVector<double> P(coeff.size1());
+  fullMatrix<double> Q(coeff.size1(), coeff.size1());
+  for (int i = 0; i < coeff.size1(); ++i) {
+    P(i) = 0;
+    for (int l = 1; l < 7; ++l) {
+      P(i) += coeff(i, l) * coeff(i, l);
+    }
+    P(i) = std::sqrt(P(i)/6);
+    for (int j = 0; j < coeff.size1(); ++j) {
+      Q(i, j) = 0;
+      for (int l = 1; l < 7; ++l) {
+        Q(i, j) += coeff(i, l) * coeff(j, l);
+      }
+      Q(i, j) /= 6;
+    }
+  }
+
+  double min = 1e10;
+
+  std::map<int, std::vector<IneqData> >::const_iterator itJ, itP;
+  itJ = _ineqJ2.begin();
+  itP = _ineqP3.begin();
+
+  while (itJ != _ineqJ2.end() && itP != _ineqP3.end()) {
+    double num = 0, den = 0;
+    for (unsigned int l = 0; l < itJ->second.size(); ++l) {
+      const int i = itJ->second[l].i;
+      const int j = itJ->second[l].j;
+      num -= itJ->second[l].val * jac(i) * jac(j);
+    }
+    num *= beta;
+    for (unsigned int l = 0; l < itP->second.size(); ++l) {
+      const int i = itP->second[l].i;
+      const int j = itP->second[l].j;
+      const int k = itP->second[l].k;
+      num += itP->second[l].val * coeff(i, 0) * coeff(j, 0) * coeff(k, 0);
+      if (j == k)
+        den += itP->second[l].val * Q(i,i) * P(i);
+      else
+        den += itP->second[l].val * 1/3*(Q(i,j)*P(k)+Q(i,k)*P(j)+Q(k,j)*P(i));
+    }
+    min = std::min(min, num/den);
+    ++itJ;
+    ++itP;
+  }
+
+  maxK = 1/beta*(mina*mina*mina-min);
+}
diff --git a/Numeric/MetricBasis.h b/Numeric/MetricBasis.h
new file mode 100644
index 0000000..f1cf8e0
--- /dev/null
+++ b/Numeric/MetricBasis.h
@@ -0,0 +1,158 @@
+// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
+#ifndef _METRIC_BASIS_H_
+#define _METRIC_BASIS_H_
+
+#include "MElement.h"
+#include "JacobianBasis.h"
+#include "fullMatrix.h"
+#include <fstream>
+#include <cmath>
+
+class MetricBasis {
+  friend class MetricCoefficient;
+  friend class GMSH_AnalyseCurvedMeshPlugin;
+private:
+  const JacobianBasis *_jacobian;
+  const GradientBasis *_gradients;
+  const bezierBasis *_bezier;
+  static double _tol;
+  static int _which;
+
+  int __maxdepth, __numSubdivision, __TotSubdivision;
+  std::vector<int> __numSub;
+  MElement *__curElem;
+
+  std::fstream file;
+
+  class IneqData {
+  public:
+    int i, j, k;
+    double val;
+
+  public:
+    IneqData(double val, int i, int j, int k = -1) : i(i), j(j), k(k), val(val) {}
+  };
+
+  class MetricData {
+   public:
+    fullMatrix<double> *_metcoeffs;
+    fullVector<double> *_jaccoeffs;
+    double _RminBez;
+    int _depth, _num;
+
+   public:
+    MetricData(fullMatrix<double> *m, fullVector<double> *j, double r, int d, int num) :
+      _metcoeffs(m), _jaccoeffs(j), _RminBez(r), _depth(d), _num(num) {}
+    ~MetricData() {
+      delete _metcoeffs;
+      delete _jaccoeffs;
+    }
+  };
+
+  std::map<int, std::vector<IneqData> > _ineqJ2, _ineqP3, _ineqA;
+
+public:
+  MetricBasis(int elementTag);
+
+  static void setTol(double tol) {_tol = tol;}
+  static double getTol() {return _tol;}
+  static void setWhich(int which) {_which = which;}
+
+  double getBoundRmin(MElement*, MetricData*&, fullMatrix<double>&);
+  double getMinR(MElement*, MetricData*&, int) const;
+  bool notStraight(MElement*, double &metric, int order) const;
+  static double boundMinR(MElement *el);
+  static double sampleR(MElement *el, int order);
+  //double getBoundRmin(int, MElement**, double*);
+  //static double boundRmin(int, MElement**, double*, bool sameType = false);
+
+  void interpolate(const MElement*, const MetricData*, const double *uvw, double *minmaxQ, bool write = false) const;
+
+  static int metricOrder(int tag);
+  void printTotSubdiv(double n) const {
+    Msg::Info("SUBDIV %d, %g", __TotSubdivision, __TotSubdivision/2776.);
+  }
+
+private:
+  void _fillInequalities(int order);
+  void _lightenInequalities(int&, int&, int&); //TODO change
+
+  void _computeRmin(const fullMatrix<double>&, const fullVector<double>&,
+                    double &RminLag, double &RminBez, int depth, bool debug = false) const;
+  void _computeRmax(const fullMatrix<double>&, const fullVector<double>&,
+                    double &RmaxLag) const;
+  void _computeTermBeta(double &a, double &K, double &dRda,
+                        double &term1, double &phip) const;
+  void _getMetricData(MElement*, MetricData*&) const;
+
+  double _subdivideForRmin(MetricData*, double RminLag, double tol, int which) const;
+
+  double _minp(const fullMatrix<double>&) const;
+  double _minp2(const fullMatrix<double>&) const;
+  double _minq(const fullMatrix<double>&) const;
+  double _maxp(const fullMatrix<double>&) const;
+  double _maxq(const fullMatrix<double>&) const;
+  void _minMaxA(const fullMatrix<double>&, double &min, double &max) const;
+  void _minJ2P3(const fullMatrix<double>&, const fullVector<double>&, double &min) const;
+  void _maxAstKpos(const fullMatrix<double>&, const fullVector<double>&,
+                 double minK, double beta, double &maxa) const;
+  void _maxAstKneg(const fullMatrix<double>&, const fullVector<double>&,
+                 double minK, double beta, double &maxa) const;
+  void _maxKstAfast(const fullMatrix<double>&, const fullVector<double>&,
+                 double mina, double beta, double &maxK) const;
+  void _maxKstAsharp(const fullMatrix<double>&, const fullVector<double>&,
+                 double mina, double beta, double &maxK) const;
+  void _minMaxJacobianSqr(const fullVector<double>&, double &min, double &max) const;
+
+  double _Rsafe(double a, double K) const {
+    const double x = .5 * (K - a*a*a + 3*a);
+    const double phi = std::acos(x) / 3;
+    return (a + 2*std::cos(phi + 2*M_PI/3)) / (a + 2*std::cos(phi));
+  }
+  bool _chknumber(double val) const {
+#if defined(_MSC_VER)
+    return _isnan(val) || !_finite(val);
+#else
+    return std::isnan(val) || std::isinf(val);
+#endif
+  }
+  bool _chka(double a) const {return _chknumber(a) || a < 1;}
+  bool _chkK(double K) const {return _chknumber(K) || K < 0;}
+  int _chkaK(double a, double K) const {
+    if (_chka(a)) return 1;
+    if (_chkK(K)) return 2;
+    if (std::abs(K - a*a*a + 3*a) > 2) {
+      Msg::Warning("x = %g", .5 * (K - a*a*a + 3*a));
+      return 3;
+    }
+    return 0;
+  }
+  bool _chkR(double R) const {return _chknumber(R) || R < 0 || R > 1;}
+  int _chkaKR(double a, double K, double R) const {
+    const int aK = _chkaK(a, K);
+    if (aK) return aK;
+    if (_chkR(R)) return 4;
+    const double myR = _Rsafe(a, K);
+    if (std::abs(myR-R) > 1e-10) return 5;
+    return 0;
+  }
+
+private:
+  class gterIneq {
+   public:
+    bool operator()(const IneqData &id1, const IneqData &id2) const {
+      return id1.val > id2.val;
+    }
+  };
+  struct lessMinB {
+    bool operator()(const MetricData *md1, const MetricData *md2) const {
+      return md1->_RminBez > md2->_RminBez;
+    }
+  };
+};
+
+#endif
diff --git a/Numeric/Numeric.cpp b/Numeric/Numeric.cpp
index 5827e15..4748ba7 100644
--- a/Numeric/Numeric.cpp
+++ b/Numeric/Numeric.cpp
@@ -656,7 +656,7 @@ void invert_singular_matrix3x3(double MM[3][3], double II[3][3])
   }
 }
 
-bool newton_fd(void (*func)(fullVector<double> &, fullVector<double> &, void *),
+bool newton_fd(bool (*func)(fullVector<double> &, fullVector<double> &, void *),
                fullVector<double> &x, void *data, double relax, double tolx)
 {
   const int MAXIT = 10;
@@ -667,7 +667,7 @@ bool newton_fd(void (*func)(fullVector<double> &, fullVector<double> &, void *),
   fullVector<double> f(N), feps(N), dx(N);
 
   for (int iter = 0; iter < MAXIT; iter++){
-    func(x, f, data);
+    if(!func(x, f, data)) return false;
 
     bool isZero = false;
     for (int k=0; k<N; k++) {
@@ -681,10 +681,9 @@ bool newton_fd(void (*func)(fullVector<double> &, fullVector<double> &, void *),
       double h = EPS * fabs(x(j));
       if(h == 0.) h = EPS;
       x(j) += h;
-      func(x, feps, data);
+      if(!func(x, feps, data)) return false;
       for (int i = 0; i < N; i++){
         J(i, j) = (feps(i) - f(i)) / h;
-	//	printf("J(%d,%d) = %12.5E \n",i,j,J(i,j));
       }
       x(j) -= h;
     }
@@ -700,7 +699,6 @@ bool newton_fd(void (*func)(fullVector<double> &, fullVector<double> &, void *),
     for (int i = 0; i < N; i++)
       x(i) -= relax * dx(i);
 
-    //    printf("dx = %12.5E\n",dx.norm());
     if(dx.norm() < tolx) return true;
   }
   return false;
@@ -1284,8 +1282,8 @@ void signedDistancesPointsEllipseLine(std::vector<double>&distances,
   }
 }
 
-int intersection_segments(SPoint3 &p1, SPoint3 &p2,
-                          SPoint3 &q1, SPoint3 &q2,
+int intersection_segments(const SPoint3 &p1, const SPoint3 &p2,
+                          const SPoint3 &q1, const SPoint3 &q2,
                           double x[2])
 {
   double xp_max = std::max(p1.x(), p2.x());
diff --git a/Numeric/Numeric.h b/Numeric/Numeric.h
index 3e10053..bb05902 100644
--- a/Numeric/Numeric.h
+++ b/Numeric/Numeric.h
@@ -106,7 +106,7 @@ void gradSimplex(double *x, double *y, double *z, double *v, double *grad);
 double ComputeVonMises(double *val);
 double ComputeScalarRep(int numComp, double *val);
 void invert_singular_matrix3x3(double MM[3][3], double II[3][3]);
-bool newton_fd(void (*func)(fullVector<double> &, fullVector<double> &, void *),
+bool newton_fd(bool (*func)(fullVector<double> &, fullVector<double> &, void *),
                fullVector<double> &x, void *data, double relax=1., double tolx=1.e-6);
 double minimize_grad_fd(double (*func)(fullVector<double> &, void *),
                         fullVector<double> &x, void *data);
@@ -142,8 +142,8 @@ void signedDistancesPointsEllipseLine (std::vector<double>&distances,
                                        const std::vector<SPoint3> &pts,
                                        const SPoint3 &p1, const SPoint3 &p2);
 
-int intersection_segments (SPoint3 &p1, SPoint3 &p2,
-			   SPoint3 &q1, SPoint3 &q2,
+int intersection_segments (const SPoint3 &p1, const SPoint3 &p2,
+			   const SPoint3 &q1, const SPoint3 &q2,
 			   double x[2]);
 
 //tools for projection onto plane
diff --git a/Numeric/bezierBasis.cpp b/Numeric/bezierBasis.cpp
index ae93f04..0fd6fdb 100644
--- a/Numeric/bezierBasis.cpp
+++ b/Numeric/bezierBasis.cpp
@@ -15,182 +15,222 @@
 
 namespace {
 // Sub Control Points
-  std::vector< fullMatrix<double> > generateSubPointsLine(int order)
-  {
-    std::vector< fullMatrix<double> > subPoints(2);
+std::vector< fullMatrix<double> > generateSubPointsLine(int order)
+{
+  std::vector< fullMatrix<double> > subPoints(2);
 
-    subPoints[0] = gmshGenerateMonomialsLine(order);
-    subPoints[0].scale(.5/order);
+  subPoints[0] = gmshGenerateMonomialsLine(order);
+  subPoints[0].scale(.5/order);
 
-    subPoints[1].copy(subPoints[0]);
-    subPoints[1].add(.5);
+  subPoints[1].copy(subPoints[0]);
+  subPoints[1].add(.5);
 
-    return subPoints;
-  }
+  return subPoints;
+}
 
-  std::vector< fullMatrix<double> > generateSubPointsTriangle(int order)
-  {
-    std::vector< fullMatrix<double> > subPoints(4);
-    fullMatrix<double> prox;
+std::vector< fullMatrix<double> > generateSubPointsTriangle(int order)
+{
+  std::vector< fullMatrix<double> > subPoints(4);
+  fullMatrix<double> prox;
 
-    subPoints[0] = gmshGenerateMonomialsTriangle(order);
-    subPoints[0].scale(.5/order);
+  subPoints[0] = gmshGenerateMonomialsTriangle(order);
+  subPoints[0].scale(.5/order);
 
-    subPoints[1].copy(subPoints[0]);
-    prox.setAsProxy(subPoints[1], 0, 1);
-    prox.add(.5);
+  subPoints[1].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[1], 0, 1);
+  prox.add(.5);
 
-    subPoints[2].copy(subPoints[0]);
-    prox.setAsProxy(subPoints[2], 1, 1);
-    prox.add(.5);
+  subPoints[2].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[2], 1, 1);
+  prox.add(.5);
 
-    subPoints[3].copy(subPoints[0]);
-    subPoints[3].scale(-1.);
-    subPoints[3].add(.5);
+  subPoints[3].copy(subPoints[0]);
+  subPoints[3].scale(-1.);
+  subPoints[3].add(.5);
 
-    return subPoints;
-  }
+  return subPoints;
+}
 
-  std::vector< fullMatrix<double> > generateSubPointsQuad(int order)
-  {
-    std::vector< fullMatrix<double> > subPoints(4);
-    fullMatrix<double> prox;
+std::vector< fullMatrix<double> > generateSubPointsQuad(int order)
+{
+  std::vector< fullMatrix<double> > subPoints(4);
+  fullMatrix<double> prox;
 
-    subPoints[0] = gmshGenerateMonomialsQuadrangle(order);
-    subPoints[0].scale(.5/order);
+  subPoints[0] = gmshGenerateMonomialsQuadrangle(order);
+  subPoints[0].scale(.5/order);
 
-    subPoints[1].copy(subPoints[0]);
-    prox.setAsProxy(subPoints[1], 0, 1);
-    prox.add(.5);
+  subPoints[1].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[1], 0, 1);
+  prox.add(.5);
 
-    subPoints[2].copy(subPoints[0]);
-    prox.setAsProxy(subPoints[2], 1, 1);
-    prox.add(.5);
+  subPoints[2].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[2], 1, 1);
+  prox.add(.5);
 
-    subPoints[3].copy(subPoints[1]);
-    prox.setAsProxy(subPoints[3], 1, 1);
-    prox.add(.5);
+  subPoints[3].copy(subPoints[1]);
+  prox.setAsProxy(subPoints[3], 1, 1);
+  prox.add(.5);
 
-    return subPoints;
-  }
+  return subPoints;
+}
 
-  std::vector< fullMatrix<double> > generateSubPointsTetrahedron(int order)
-  {
-    std::vector< fullMatrix<double> > subPoints(8);
-    fullMatrix<double> prox1;
-    fullMatrix<double> prox2;
+std::vector< fullMatrix<double> > generateSubPointsTetrahedron(int order)
+{
+  std::vector< fullMatrix<double> > subPoints(8);
+  fullMatrix<double> prox1;
+  fullMatrix<double> prox2;
+
+  subPoints[0] = gmshGenerateMonomialsTetrahedron(order);
+  subPoints[0].scale(.5/order);
+
+  subPoints[1].copy(subPoints[0]);
+  prox1.setAsProxy(subPoints[1], 0, 1);
+  prox1.add(.5);
+
+  subPoints[2].copy(subPoints[0]);
+  prox1.setAsProxy(subPoints[2], 1, 1);
+  prox1.add(.5);
+
+  subPoints[3].copy(subPoints[0]);
+  prox1.setAsProxy(subPoints[3], 2, 1);
+  prox1.add(.5);
+
+  // u := .5-u-w
+  // v := .5-v-w
+  // w := w
+  subPoints[4].copy(subPoints[0]);
+  prox1.setAsProxy(subPoints[4], 0, 2);
+  prox1.scale(-1.);
+  prox1.add(.5);
+  prox1.setAsProxy(subPoints[4], 0, 1);
+  prox2.setAsProxy(subPoints[4], 2, 1);
+  prox1.add(prox2, -1.);
+  prox1.setAsProxy(subPoints[4], 1, 1);
+  prox1.add(prox2, -1.);
+
+  // u := u
+  // v := .5-v
+  // w := w+v
+  subPoints[5].copy(subPoints[0]);
+  prox1.setAsProxy(subPoints[5], 2, 1);
+  prox2.setAsProxy(subPoints[5], 1, 1);
+  prox1.add(prox2);
+  prox2.scale(-1.);
+  prox2.add(.5);
+
+  // u := .5-u
+  // v := v
+  // w := w+u
+  subPoints[6].copy(subPoints[0]);
+  prox1.setAsProxy(subPoints[6], 2, 1);
+  prox2.setAsProxy(subPoints[6], 0, 1);
+  prox1.add(prox2);
+  prox2.scale(-1.);
+  prox2.add(.5);
+
+  // u := u+w
+  // v := v+w
+  // w := .5-w
+  subPoints[7].copy(subPoints[0]);
+  prox1.setAsProxy(subPoints[7], 0, 1);
+  prox2.setAsProxy(subPoints[7], 2, 1);
+  prox1.add(prox2);
+  prox1.setAsProxy(subPoints[7], 1, 1);
+  prox1.add(prox2);
+  prox2.scale(-1.);
+  prox2.add(.5);
+
+
+  return subPoints;
+}
+
+std::vector< fullMatrix<double> > generateSubPointsPrism(int order)
+{
+  std::vector< fullMatrix<double> > subPoints(8);
+  fullMatrix<double> prox;
 
-    subPoints[0] = gmshGenerateMonomialsTetrahedron(order);
-    subPoints[0].scale(.5/order);
+  subPoints[0] = gmshGenerateMonomialsPrism(order);
+  subPoints[0].scale(.5/order);
 
-    subPoints[1].copy(subPoints[0]);
-    prox1.setAsProxy(subPoints[1], 0, 1);
-    prox1.add(.5);
+  subPoints[1].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[1], 0, 1);
+  prox.add(.5);
 
-    subPoints[2].copy(subPoints[0]);
-    prox1.setAsProxy(subPoints[2], 1, 1);
-    prox1.add(.5);
+  subPoints[2].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[2], 1, 1);
+  prox.add(.5);
 
-    subPoints[3].copy(subPoints[0]);
-    prox1.setAsProxy(subPoints[3], 2, 1);
-    prox1.add(.5);
+  subPoints[3].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[3], 0, 2);
+  prox.scale(-1.);
+  prox.add(.5);
 
-    // u := .5-u-w
-    // v := .5-v-w
-    // w := w
-    subPoints[4].copy(subPoints[0]);
-    prox1.setAsProxy(subPoints[4], 0, 2);
-    prox1.scale(-1.);
-    prox1.add(.5);
-    prox1.setAsProxy(subPoints[4], 0, 1);
-    prox2.setAsProxy(subPoints[4], 2, 1);
-    prox1.add(prox2, -1.);
-    prox1.setAsProxy(subPoints[4], 1, 1);
-    prox1.add(prox2, -1.);
-
-    // u := u
-    // v := .5-v
-    // w := w+v
-    subPoints[5].copy(subPoints[0]);
-    prox1.setAsProxy(subPoints[5], 2, 1);
-    prox2.setAsProxy(subPoints[5], 1, 1);
-    prox1.add(prox2);
-    prox2.scale(-1.);
-    prox2.add(.5);
-
-    // u := .5-u
-    // v := v
-    // w := w+u
-    subPoints[6].copy(subPoints[0]);
-    prox1.setAsProxy(subPoints[6], 2, 1);
-    prox2.setAsProxy(subPoints[6], 0, 1);
-    prox1.add(prox2);
-    prox2.scale(-1.);
-    prox2.add(.5);
-
-    // u := u+w
-    // v := v+w
-    // w := .5-w
-    subPoints[7].copy(subPoints[0]);
-    prox1.setAsProxy(subPoints[7], 0, 1);
-    prox2.setAsProxy(subPoints[7], 2, 1);
-    prox1.add(prox2);
-    prox1.setAsProxy(subPoints[7], 1, 1);
-    prox1.add(prox2);
-    prox2.scale(-1.);
-    prox2.add(.5);
+  subPoints[4].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[4], 2, 1);
+  prox.add(.5);
 
+  subPoints[5].copy(subPoints[1]);
+  prox.setAsProxy(subPoints[5], 2, 1);
+  prox.add(.5);
 
-    return subPoints;
-  }
+  subPoints[6].copy(subPoints[2]);
+  prox.setAsProxy(subPoints[6], 2, 1);
+  prox.add(.5);
 
-  std::vector< fullMatrix<double> > generateSubPointsPrism(int order)
-  {
-    std::vector< fullMatrix<double> > subPoints(8);
-    fullMatrix<double> prox;
+  subPoints[7].copy(subPoints[3]);
+  prox.setAsProxy(subPoints[7], 2, 1);
+  prox.add(.5);
 
-    subPoints[0] = gmshGenerateMonomialsPrism(order);
-    subPoints[0].scale(.5/order);
+  return subPoints;
+}
 
-    subPoints[1].copy(subPoints[0]);
-    prox.setAsProxy(subPoints[1], 0, 1);
-    prox.add(.5);
+std::vector< fullMatrix<double> > generateSubPointsHex(int order)
+{
+  std::vector< fullMatrix<double> > subPoints(8);
+  fullMatrix<double> prox;
 
-    subPoints[2].copy(subPoints[0]);
-    prox.setAsProxy(subPoints[2], 1, 1);
-    prox.add(.5);
+  subPoints[0] = gmshGenerateMonomialsHexahedron(order);
+  subPoints[0].scale(.5/order);
 
-    subPoints[3].copy(subPoints[0]);
-    prox.setAsProxy(subPoints[3], 0, 2);
-    prox.scale(-1.);
-    prox.add(.5);
+  subPoints[1].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[1], 0, 1);
+  prox.add(.5);
 
-    subPoints[4].copy(subPoints[0]);
-    prox.setAsProxy(subPoints[4], 2, 1);
-    prox.add(.5);
+  subPoints[2].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[2], 1, 1);
+  prox.add(.5);
 
-    subPoints[5].copy(subPoints[1]);
-    prox.setAsProxy(subPoints[5], 2, 1);
-    prox.add(.5);
+  subPoints[3].copy(subPoints[1]);
+  prox.setAsProxy(subPoints[3], 1, 1);
+  prox.add(.5);
 
-    subPoints[6].copy(subPoints[2]);
-    prox.setAsProxy(subPoints[6], 2, 1);
-    prox.add(.5);
+  subPoints[4].copy(subPoints[0]);
+  prox.setAsProxy(subPoints[4], 2, 1);
+  prox.add(.5);
 
-    subPoints[7].copy(subPoints[3]);
-    prox.setAsProxy(subPoints[7], 2, 1);
-    prox.add(.5);
+  subPoints[5].copy(subPoints[1]);
+  prox.setAsProxy(subPoints[5], 2, 1);
+  prox.add(.5);
 
-    return subPoints;
-  }
+  subPoints[6].copy(subPoints[2]);
+  prox.setAsProxy(subPoints[6], 2, 1);
+  prox.add(.5);
 
-  std::vector< fullMatrix<double> > generateSubPointsHex(int order)
-  {
-    std::vector< fullMatrix<double> > subPoints(8);
+  subPoints[7].copy(subPoints[3]);
+  prox.setAsProxy(subPoints[7], 2, 1);
+  prox.add(.5);
+
+  return subPoints;
+}
+
+std::vector< fullMatrix<double> > generateSubPointsPyr(int order)
+{
+  if (order == 0) {
+    std::vector< fullMatrix<double> > subPoints(4);
     fullMatrix<double> prox;
 
-    subPoints[0] = gmshGenerateMonomialsHexahedron(order);
-    subPoints[0].scale(.5/order);
+    subPoints[0] = JacobianBasis::generateJacMonomialsPyramid(0);
+    subPoints[0].scale(.5/(order+2));
 
     subPoints[1].copy(subPoints[0]);
     prox.setAsProxy(subPoints[1], 0, 1);
@@ -204,60 +244,14 @@ namespace {
     prox.setAsProxy(subPoints[3], 1, 1);
     prox.add(.5);
 
-    subPoints[4].copy(subPoints[0]);
-    prox.setAsProxy(subPoints[4], 2, 1);
-    prox.add(.5);
-
-    subPoints[5].copy(subPoints[1]);
-    prox.setAsProxy(subPoints[5], 2, 1);
-    prox.add(.5);
-
-    subPoints[6].copy(subPoints[2]);
-    prox.setAsProxy(subPoints[6], 2, 1);
-    prox.add(.5);
-
-    subPoints[7].copy(subPoints[3]);
-    prox.setAsProxy(subPoints[7], 2, 1);
-    prox.add(.5);
-
     return subPoints;
   }
-
-  std::vector< fullMatrix<double> > generateSubPointsPyr(int order)
-  {
-    if (order == 0) {
-      std::vector< fullMatrix<double> > subPoints(4);
-      fullMatrix<double> prox;
-
-      subPoints[0] = JacobianBasis::generateJacMonomialsPyramid(order);
-      subPoints[0].scale(.5/(order+2));
-
-      subPoints[1].copy(subPoints[0]);
-      prox.setAsProxy(subPoints[1], 0, 1);
-      prox.add(.5);
-
-      subPoints[2].copy(subPoints[0]);
-      prox.setAsProxy(subPoints[2], 1, 1);
-      prox.add(.5);
-
-      subPoints[3].copy(subPoints[1]);
-      prox.setAsProxy(subPoints[3], 1, 1);
-      prox.add(.5);
-
-      return subPoints;
-    }
-
+  else {
     std::vector< fullMatrix<double> > subPoints(8);
     fullMatrix<double> ref, prox;
 
     subPoints[0] = JacobianBasis::generateJacMonomialsPyramid(order);
-    int nPts = subPoints[0].size1();
-    for (int i = 0; i < nPts; ++i) {
-      const double factor = .5 / (order + 2 - subPoints[0](i, 2));
-      subPoints[0](i, 0) = subPoints[0](i, 0) * factor;
-      subPoints[0](i, 1) = subPoints[0](i, 1) * factor;
-      subPoints[0](i, 2) = subPoints[0](i, 2) * .5 / (order + 2);
-    }
+    subPoints[0].scale(.5/(order+2));
 
     subPoints[1].copy(subPoints[0]);
     prox.setAsProxy(subPoints[1], 0, 1);
@@ -287,6 +281,7 @@ namespace {
     prox.setAsProxy(subPoints[7], 2, 1);
     prox.add(.5);
 
+    const int nPts = subPoints[0].size1();
     for (int i = 0; i < 8; ++i) {
       for (int j = 0; j < nPts; ++j) {
         const double factor = (1. - subPoints[i](j, 2));
@@ -297,234 +292,306 @@ namespace {
 
     return subPoints;
   }
+}
+
+// Matrices generation
+int nChoosek(int n, int k)
+{
+  if (n < k || k < 0) {
+    Msg::Error("Wrong argument for combination. (%d, %d)", n, k);
+    return 1;
+  }
 
-  // Matrices generation
-  int nChoosek(int n, int k)
-  {
-    if (n < k || k < 0) {
-      Msg::Error("Wrong argument for combination.");
-      return 1;
-    }
+  if (k > n/2) k = n-k;
+  if (k == 1)
+    return n;
+  if (k == 0)
+    return 1;
 
-    if (k > n/2) k = n-k;
-    if (k == 1)
-      return n;
-    if (k == 0)
-      return 1;
+  int c = 1;
+  for (int i = 1; i <= k; i++, n--) (c *= n) /= i;
+  return c;
+}
 
-    int c = 1;
-    for (int i = 1; i <= k; i++, n--) (c *= n) /= i;
-    return c;
+fullMatrix<double> generateBez2LagMatrix
+  (const fullMatrix<double> &exponent, const fullMatrix<double> &point,
+   int order, int dimSimplex)
+{
+  if(exponent.size1() != point.size1() || exponent.size2() != point.size2()){
+    Msg::Fatal("Wrong sizes for bez2lag matrix generation %d %d -- %d %d",
+      exponent.size1(),point.size1(),
+      exponent.size2(),point.size2());
+    return fullMatrix<double>(1, 1);
   }
 
-  fullMatrix<double> generateBez2LagMatrix
-    (const fullMatrix<double> &exponent, const fullMatrix<double> &point,
-     int order, int dimSimplex)
-  {
-    if(exponent.size1() != point.size1() || exponent.size2() != point.size2()){
-      Msg::Fatal("Wrong sizes for bez2lag matrix generation %d %d -- %d %d",
-        exponent.size1(),point.size1(),
-        exponent.size2(),point.size2());
-      return fullMatrix<double>(1, 1);
-    }
-
-    int ndofs = exponent.size1();
-    int dim = exponent.size2();
-
-    fullMatrix<double> bez2Lag(ndofs, ndofs);
-    for (int i = 0; i < ndofs; i++) {
-      for (int j = 0; j < ndofs; j++) {
-        double dd = 1.;
-
-        {
-          double pointCompl = 1.;
-          int exponentCompl = order;
-          for (int k = 0; k < dimSimplex; k++) {
-            dd *= nChoosek(exponentCompl, (int) exponent(i, k))
-              * pow(point(j, k), exponent(i, k));
-            pointCompl -= point(j, k);
-            exponentCompl -= (int) exponent(i, k);
-          }
-          dd *= pow(pointCompl, exponentCompl);
+  int ndofs = exponent.size1();
+  int dim = exponent.size2();
+
+  fullMatrix<double> bez2Lag(ndofs, ndofs);
+  for (int i = 0; i < ndofs; i++) {
+    for (int j = 0; j < ndofs; j++) {
+      double dd = 1.;
+
+      {
+        double pointCompl = 1.;
+        int exponentCompl = order;
+        for (int k = 0; k < dimSimplex; k++) {
+          dd *= nChoosek(exponentCompl, (int) exponent(i, k))
+            * pow(point(j, k), exponent(i, k));
+          pointCompl -= point(j, k);
+          exponentCompl -= (int) exponent(i, k);
         }
+        dd *= pow(pointCompl, exponentCompl);
+      }
 
-        for (int k = dimSimplex; k < dim; k++)
-          dd *= nChoosek(order, (int) exponent(i, k))
-              * pow(point(j, k), exponent(i, k))
-              * pow(1. - point(j, k), order - exponent(i, k));
+      for (int k = dimSimplex; k < dim; k++)
+        dd *= nChoosek(order, (int) exponent(i, k))
+            * pow(point(j, k), exponent(i, k))
+            * pow(1. - point(j, k), order - exponent(i, k));
 
-        bez2Lag(j, i) = dd;
-      }
+      bez2Lag(j, i) = dd;
     }
-    return bez2Lag;
   }
+  return bez2Lag;
+}
 
-  fullMatrix<double> generateBez2LagMatrixPyramid
-    (const fullMatrix<double> &exponent, const fullMatrix<double> &point,
-     int order)
-  {
-    if(exponent.size1() != point.size1() || exponent.size2() != point.size2() ||
-        exponent.size2() != 3){
-      Msg::Fatal("Wrong sizes for bez2lag matrix generation %d %d -- %d %d",
-        exponent.size1(),point.size1(),
-        exponent.size2(),point.size2());
-      return fullMatrix<double>(1, 1);
-    }
+fullMatrix<double> generateBez2LagMatrixPyramid
+  (const fullMatrix<double> &exponent, const fullMatrix<double> &point,
+   int order)
+{
+  if(exponent.size1() != point.size1() || exponent.size2() != point.size2() ||
+      exponent.size2() != 3){
+    Msg::Fatal("Wrong sizes for bez2lag matrix generation %d %d -- %d %d",
+      exponent.size1(),point.size1(),
+      exponent.size2(),point.size2());
+    return fullMatrix<double>(1, 1);
+  }
 
-    int ndofs = exponent.size1();
-
-    fullMatrix<double> bez2Lag(ndofs, ndofs);
-    for (int i = 0; i < ndofs; i++) {
-      for (int j = 0; j < ndofs; j++) {
-        bez2Lag(i, j) =
-            nChoosek(order, exponent(j, 2))
-            * pow(point(i, 2), exponent(j, 2)) //FIXME use pow_int
-            * pow(1. - point(i, 2), order - exponent(j, 2));
-
-        double p = order + 2 - exponent(j, 2);
-        double denom = 1. - point(i, 2);
-        bez2Lag(i, j) *=
-              nChoosek(p, exponent(j, 0))
-            * nChoosek(p, exponent(j, 1))
-            * pow(point(i, 0) / denom, exponent(j, 0))
-            * pow(point(i, 1) / denom, exponent(j, 1))
-            * pow(1. - point(i, 0) / denom, p - exponent(j, 0))
-            * pow(1. - point(i, 1) / denom, p - exponent(j, 1));
-      }
+  const int ndofs = exponent.size1();
+
+  fullMatrix<double> bez2Lag(ndofs, ndofs);
+  for (int i = 0; i < ndofs; i++) {
+    for (int j = 0; j < ndofs; j++) {
+      double denom = 1. - point(i, 2);
+      bez2Lag(i, j) =
+            nChoosek(order + 2, exponent(j, 0))
+          * nChoosek(order + 2, exponent(j, 1))
+          * nChoosek(order, exponent(j, 2))
+          * pow_int(point(i, 0) / denom, exponent(j, 0))
+          * pow_int(point(i, 1) / denom, exponent(j, 1))
+          * pow_int(point(i, 2)        , exponent(j, 2))
+          * pow_int(1. - point(i, 0) / denom, order + 2 - exponent(j, 0))
+          * pow_int(1. - point(i, 1) / denom, order + 2 - exponent(j, 1))
+          * pow_int(1. - point(i, 2)        , order     - exponent(j, 2));
     }
-    return bez2Lag;
   }
+  return bez2Lag;
+}
 
-  fullMatrix<double> generateSubDivisor
-    (const fullMatrix<double> &exponents, const std::vector< fullMatrix<double> > &subPoints,
-     const fullMatrix<double> &lag2Bez, int order, int dimSimplex)
-  {
-    if (exponents.size1() != lag2Bez.size1() || exponents.size1() != lag2Bez.size2()){
-      Msg::Fatal("Wrong sizes for Bezier Divisor %d %d -- %d %d",
-        exponents.size1(), lag2Bez.size1(),
-        exponents.size1(), lag2Bez.size2());
-      return fullMatrix<double>(1, 1);
-    }
+fullMatrix<double> generateSubDivisor
+  (const fullMatrix<double> &exponents, const std::vector< fullMatrix<double> > &subPoints,
+   const fullMatrix<double> &lag2Bez, int order, int dimSimplex)
+{
+  if (exponents.size1() != lag2Bez.size1() || exponents.size1() != lag2Bez.size2()){
+    Msg::Fatal("Wrong sizes for Bezier Divisor %d %d -- %d %d",
+      exponents.size1(), lag2Bez.size1(),
+      exponents.size1(), lag2Bez.size2());
+    return fullMatrix<double>(1, 1);
+  }
 
-    int nbPts = lag2Bez.size1();
-    int nbSubPts = nbPts * subPoints.size();
+  int nbPts = lag2Bez.size1();
+  int nbSubPts = nbPts * subPoints.size();
 
-    fullMatrix<double> intermediate2(nbPts, nbPts);
-    fullMatrix<double> subDivisor(nbSubPts, nbPts);
+  fullMatrix<double> intermediate2(nbPts, nbPts);
+  fullMatrix<double> subDivisor(nbSubPts, nbPts);
 
-    for (unsigned int i = 0; i < subPoints.size(); i++) {
-      fullMatrix<double> intermediate1 =
-        generateBez2LagMatrix(exponents, subPoints[i], order, dimSimplex);
-      lag2Bez.mult(intermediate1, intermediate2);
-      subDivisor.copy(intermediate2, 0, nbPts, 0, nbPts, i*nbPts, 0);
-    }
-    return subDivisor;
+  for (unsigned int i = 0; i < subPoints.size(); i++) {
+    fullMatrix<double> intermediate1 =
+      generateBez2LagMatrix(exponents, subPoints[i], order, dimSimplex);
+    lag2Bez.mult(intermediate1, intermediate2);
+    subDivisor.copy(intermediate2, 0, nbPts, 0, nbPts, i*nbPts, 0);
   }
+  return subDivisor;
+}
 
-  fullMatrix<double> generateSubDivisorPyramid
-    (const fullMatrix<double> &exponents, const std::vector< fullMatrix<double> > &subPoints,
-     const fullMatrix<double> &lag2Bez, int order)
-  {
-    if (exponents.size1() != lag2Bez.size1() || exponents.size1() != lag2Bez.size2()){
-      Msg::Fatal("Wrong sizes for Bezier Divisor %d %d -- %d %d",
-        exponents.size1(), lag2Bez.size1(),
-        exponents.size1(), lag2Bez.size2());
-      return fullMatrix<double>(1, 1);
-    }
+fullMatrix<double> generateSubDivisorPyramid
+  (const fullMatrix<double> &exponents, const std::vector< fullMatrix<double> > &subPoints,
+   const fullMatrix<double> &lag2Bez, int order)
+{
+  if (exponents.size1() != lag2Bez.size1() || exponents.size1() != lag2Bez.size2()){
+    Msg::Fatal("Wrong sizes for Bezier Divisor %d %d -- %d %d",
+      exponents.size1(), lag2Bez.size1(),
+      exponents.size1(), lag2Bez.size2());
+    return fullMatrix<double>(1, 1);
+  }
 
-    int nbPts = lag2Bez.size1();
-    int nbSubPts = nbPts * subPoints.size();
+  int nbPts = lag2Bez.size1();
+  int nbSubPts = nbPts * subPoints.size();
 
-    fullMatrix<double> intermediate2(nbPts, nbPts);
-    fullMatrix<double> subDivisor(nbSubPts, nbPts);
+  fullMatrix<double> intermediate2(nbPts, nbPts);
+  fullMatrix<double> subDivisor(nbSubPts, nbPts);
 
-    for (unsigned int i = 0; i < subPoints.size(); i++) {
-      fullMatrix<double> intermediate1 =
-        generateBez2LagMatrixPyramid(exponents, subPoints[i], order);
-      lag2Bez.mult(intermediate1, intermediate2);
-      subDivisor.copy(intermediate2, 0, nbPts, 0, nbPts, i*nbPts, 0);
+  for (unsigned int i = 0; i < subPoints.size(); i++) {
+    fullMatrix<double> intermediate1 =
+      generateBez2LagMatrixPyramid(exponents, subPoints[i], order);
+    lag2Bez.mult(intermediate1, intermediate2);
+    subDivisor.copy(intermediate2, 0, nbPts, 0, nbPts, i*nbPts, 0);
+  }
+  return subDivisor;
+}
+}
+
+void bezierBasis::interpolate(const fullMatrix<double> &coeffs,
+                              const fullMatrix<double> &uvw,
+                              fullMatrix<double> &result,
+                              bool bezCoord) const
+{
+  result.resize(uvw.size1(), coeffs.size2());
+  int dimSimplex;
+  fullMatrix<double> bezuvw = uvw;
+  switch (type) {
+  case TYPE_HEX:
+    if (!bezCoord) {
+      bezuvw.add(1);
+      bezuvw.scale(.5);
+    }
+    dimSimplex = 0;
+    break;
+
+  case TYPE_TET:
+    dimSimplex = 3;
+    break;
+
+  case TYPE_PRI:
+    if (!bezCoord) {
+      fullMatrix<double> tmp;
+      tmp.setAsProxy(bezuvw, 3, 1);
+      tmp.add(1);
+      tmp.scale(.5);
+    }
+    dimSimplex = 2;
+    break;
+
+  default:
+  case TYPE_PYR:
+    Msg::Error("Bezier interpolation not implemented for type of element %d", type);
+    /*bezuvw[0] = .5 * (1 + uvw[0]);
+    bezuvw[1] = .5 * (1 + uvw[1]);
+    bezuvw[2] = uvw[2];
+    _interpolateBezierPyramid(uvw, minmaxQ);*/
+    return;
+  }
+
+  int numCoeff = _exponents.size1();
+
+  for (int m = 0; m < uvw.size1(); ++m) {
+    for (int n = 0; n < coeffs.size2(); ++n) result(m, n) = 0;
+    for (int i = 0; i < numCoeff; i++) {
+      double dd = 1;
+      double pointCompl = 1.;
+      int exponentCompl = order;
+      for (int k = 0; k < dimSimplex; k++) {
+        dd *= nChoosek(exponentCompl, (int) _exponents(i, k))
+          * pow(bezuvw(m, k), _exponents(i, k));
+        pointCompl -= bezuvw(m, k);
+        exponentCompl -= (int) _exponents(i, k);
+      }
+      dd *= pow_int(pointCompl, exponentCompl);
+
+      for (int k = dimSimplex; k < dim; k++) {
+        dd *= nChoosek(order, (int) _exponents(i, k))
+            * pow_int(bezuvw(m, k), _exponents(i, k))
+            * pow_int(1. - bezuvw(m, k), order - _exponents(i, k));
+      }
+      for (int n = 0; n < coeffs.size2(); ++n)
+        result(m, n) += coeffs(i, n) * dd;
     }
-    return subDivisor;
   }
 }
 
 void bezierBasis::_construct(int parentType, int p)
 {
   order = p;
-  fullMatrix<double> exponents;
+  type = parentType;
   std::vector< fullMatrix<double> > subPoints;
 
   if (parentType == TYPE_PYR) {
     dim = 3;
     numLagCoeff = 8;
-    exponents = JacobianBasis::generateJacMonomialsPyramid(order);
-    subPoints = generateSubPointsPyr(order);
+    _exponents = JacobianBasis::generateJacMonomialsPyramid(order);
 
+    subPoints = generateSubPointsPyr(order);
     numDivisions = static_cast<int>(subPoints.size());
 
-    fullMatrix<double> bezierPoints = exponents;
-    bezierPoints.scale(1. / (order + 2));
+    fullMatrix<double> bezierPoints;
+    bezierPoints.resize(_exponents.size1(), _exponents.size2());
+    const double p = order + 2;
+    for (int i = 0; i < bezierPoints.size1(); ++i) {
+      bezierPoints(i, 2) = _exponents(i, 2) / p;
+      const double scale = 1. - bezierPoints(i, 2);
+      bezierPoints(i, 0) = _exponents(i, 0) / p * scale;
+      bezierPoints(i, 1) = _exponents(i, 1) / p * scale;
+    }
 
-    matrixBez2Lag = generateBez2LagMatrixPyramid(exponents, bezierPoints, order);
+    matrixBez2Lag = generateBez2LagMatrixPyramid(_exponents, bezierPoints, order);
     matrixBez2Lag.invert(matrixLag2Bez);
-    subDivisor = generateSubDivisorPyramid(exponents, subPoints, matrixLag2Bez, order);
+    subDivisor = generateSubDivisorPyramid(_exponents, subPoints, matrixLag2Bez, order);
     return;
   }
 
-  int dimSimplex;
   switch (parentType) {
     case TYPE_PNT :
       dim = 0;
       numLagCoeff = 1;
-      dimSimplex = 0;
-      exponents = gmshGenerateMonomialsLine(0);
+      _dimSimplex = 0;
+      _exponents = gmshGenerateMonomialsLine(0);
       subPoints.push_back(gmshGeneratePointsLine(0));
       break;
     case TYPE_LIN : {
       dim = 1;
-      numLagCoeff = 2;
-      dimSimplex = 0;
-      exponents = gmshGenerateMonomialsLine(order);
+      numLagCoeff = order == 0 ? 1 : 2;
+      _dimSimplex = 0;
+      _exponents = gmshGenerateMonomialsLine(order);
       subPoints = generateSubPointsLine(order);
       break;
     }
     case TYPE_TRI : {
       dim = 2;
-      numLagCoeff = 3;
-      dimSimplex = 2;
-      exponents = gmshGenerateMonomialsTriangle(order);
+      numLagCoeff = order == 0 ? 1 : 3;
+      _dimSimplex = 2;
+      _exponents = gmshGenerateMonomialsTriangle(order);
       subPoints = generateSubPointsTriangle(order);
       break;
     }
     case TYPE_QUA : {
       dim = 2;
-      numLagCoeff = 4;
-      dimSimplex = 0;
-      exponents = gmshGenerateMonomialsQuadrangle(order);
+      numLagCoeff = order == 0 ? 1 : 4;
+      _dimSimplex = 0;
+      _exponents = gmshGenerateMonomialsQuadrangle(order);
       subPoints = generateSubPointsQuad(order);
       break;
     }
     case TYPE_TET : {
       dim = 3;
-      numLagCoeff = 4;
-      dimSimplex = 3;
-      exponents = gmshGenerateMonomialsTetrahedron(order);
+      numLagCoeff = order == 0 ? 1 : 4;
+      _dimSimplex = 3;
+      _exponents = gmshGenerateMonomialsTetrahedron(order);
       subPoints = generateSubPointsTetrahedron(order);
       break;
     }
     case TYPE_PRI : {
       dim = 3;
-      numLagCoeff = 6;
-      dimSimplex = 2;
-      exponents = gmshGenerateMonomialsPrism(order);
+      numLagCoeff = order == 0 ? 1 : 6;
+      _dimSimplex = 2;
+      _exponents = gmshGenerateMonomialsPrism(order);
       subPoints = generateSubPointsPrism(order);
       break;
     }
     case TYPE_HEX : {
       dim = 3;
-      numLagCoeff = 8;
-      dimSimplex = 0;
-      exponents = gmshGenerateMonomialsHexahedron(order);
+      numLagCoeff = order == 0 ? 1 : 8;
+      _dimSimplex = 0;
+      _exponents = gmshGenerateMonomialsHexahedron(order);
       subPoints = generateSubPointsHex(order);
       break;
     }
@@ -534,18 +601,18 @@ void bezierBasis::_construct(int parentType, int p)
       dim = 3;
       order = 0;
       numLagCoeff = 4;
-      dimSimplex = 3;
-      exponents = gmshGenerateMonomialsTetrahedron(order);
+      _dimSimplex = 3;
+      _exponents = gmshGenerateMonomialsTetrahedron(order);
       subPoints = generateSubPointsTetrahedron(order);
       break;
     }
   }
   numDivisions = static_cast<int>(subPoints.size());
 
-  fullMatrix<double> bezierPoints = exponents;
+  fullMatrix<double> bezierPoints = _exponents;
   bezierPoints.scale(1./order);
 
-  matrixBez2Lag = generateBez2LagMatrix(exponents, bezierPoints, order, dimSimplex);
+  matrixBez2Lag = generateBez2LagMatrix(_exponents, bezierPoints, order, _dimSimplex);
   matrixBez2Lag.invert(matrixLag2Bez);
-  subDivisor = generateSubDivisor(exponents, subPoints, matrixLag2Bez, order, dimSimplex);
+  subDivisor = generateSubDivisor(_exponents, subPoints, matrixLag2Bez, order, _dimSimplex);
 }
diff --git a/Numeric/bezierBasis.h b/Numeric/bezierBasis.h
index 3ecc178..257e54b 100644
--- a/Numeric/bezierBasis.h
+++ b/Numeric/bezierBasis.h
@@ -17,8 +17,11 @@ class bezierBasis {
  private :
   // the 'numLagCoeff' first exponents are related to 'Lagrangian' values
   int numLagCoeff;
-  int dim, order;
+  int dim, type, order;
   int numDivisions;
+ public:
+  int _dimSimplex;
+  fullMatrix<double> _exponents;
 
  public :
   fullMatrix<double> matrixLag2Bez;
@@ -39,6 +42,14 @@ class bezierBasis {
   inline int getNumLagCoeff() const {return numLagCoeff;}
   inline int getNumDivision() const {return numDivisions;}
 
+  // Interpolation of n functions on N points :
+  // coeffs(numCoeff, n) and uvw(N, dim)
+  // => result(N, n)
+  void interpolate(const fullMatrix<double> &coeffs,
+                   const fullMatrix<double> &uvw,
+                   fullMatrix<double> &result,
+                   bool bezCoord = false) const;
+
  private :
   void _construct(int parendtType, int order);
 };
diff --git a/Numeric/decasteljau.cpp b/Numeric/decasteljau.cpp
new file mode 100644
index 0000000..74cd872
--- /dev/null
+++ b/Numeric/decasteljau.cpp
@@ -0,0 +1,141 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+//
+// Contributed by J. Lambrechts
+
+#include "decasteljau.h"
+#include "SPoint3.h"
+#include "SVector3.h"
+
+typedef struct {
+  SPoint3 p;
+  double t;
+  int next;
+} sortedPoint;
+
+static int sortedPointInsert(const SPoint3 &p, const double t,
+                             std::vector<sortedPoint> &pts, int pos)
+{
+  sortedPoint pnt = {p, t, pts[pos].next};
+  pts.push_back(pnt);
+  int newp = (int)pts.size() - 1;
+  pts[pos].next = newp;
+  return newp;
+}
+
+static void sortedPointToVector(const std::vector<sortedPoint> &spts,
+                                std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  pts.clear();
+  pts.reserve(spts.size());
+  ts.clear();
+  ts.reserve(spts.size());
+  for (int p = 0; p != -1; p = spts[p].next) {
+    pts.push_back(spts[p].p);
+    ts.push_back(spts[p].t);
+  }
+}
+
+double sqDistPointSegment(const SPoint3 &p, const SPoint3 &s0, const SPoint3 &s1)
+{
+  SVector3 d(s1 - s0);
+  SVector3 d0(p - s0);
+  SVector3 d1(p - s1);
+  double dn2 = crossprod(d, d0).normSq();
+  double dt2 = std::max(0., std::max(-dot(d, d0), dot(d, d1)));
+  dt2 *= dt2;
+  return (dt2 + dn2) / d.normSq();
+}
+
+static void decasteljau(double tol, std::vector<sortedPoint> &discrete, int pos,
+                        const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2,
+                        double t0, double t2)
+{
+  if(sqDistPointSegment(p1, p0, p2) < tol * tol)
+    return;
+  SPoint3 p01((p0 + p1) * 0.5);
+  SPoint3 p12((p1 + p2) * 0.5);
+  SPoint3 p012((p01 + p12) * 0.5);
+  double t012 = 0.5 * (t0 + t2);
+  int newpos = sortedPointInsert(p012, t012, discrete, pos);
+  decasteljau(tol, discrete, pos, p0, p01, p012, t0, t012);
+  decasteljau(tol, discrete, newpos, p012, p12, p2, t012, t2);
+}
+
+void decasteljau(double tol, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2,
+                 std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  std::vector<sortedPoint> discrete;
+  sortedPoint pnt1 = {p0, 0., 1};
+  discrete.push_back(pnt1);
+  sortedPoint pnt2 = {p2, 1., -1};
+  discrete.push_back(pnt2);
+  decasteljau(tol, discrete, 0, p0, p1, p2, 0., 1);
+  sortedPointToVector(discrete, pts, ts);
+}
+
+static void decasteljau(double tol, std::vector<sortedPoint> &discrete,
+                        int pos, const SPoint3 &p0, const SPoint3 &p1,
+                        const SPoint3 &p2, const SPoint3 &p3, double t0, double t3)
+{
+  if (std::max(sqDistPointSegment(p1, p0, p3), sqDistPointSegment(p2, p0, p3)) < tol * tol)
+    return;
+  SPoint3 p01((p0 + p1) * 0.5);
+  SPoint3 p12((p1 + p2) * 0.5);
+  SPoint3 p23((p2 + p3) * 0.5);
+  SPoint3 p012((p01 + p12) * 0.5);
+  SPoint3 p123((p12 + p23) * 0.5);
+  SPoint3 p0123((p012 + p123) * 0.5);
+  double t0123 = 0.5 * (t0 + t3);
+  int newpos = sortedPointInsert(p0123, t0123, discrete, pos);
+  decasteljau(tol, discrete, pos, p0, p01, p012, p0123, t0, t0123);
+  decasteljau(tol, discrete, newpos, p0123, p123, p23, p3, t0123, t3);
+}
+
+void decasteljau(double tol, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2,
+                 const SPoint3 &p3, std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  std::vector<sortedPoint> discrete;
+  sortedPoint pnt1 = {p0, 0., 1};
+  discrete.push_back(pnt1);
+  sortedPoint pnt2 = {p3, 1., -1};
+  discrete.push_back(pnt2);
+  decasteljau(tol, discrete, 0, p0, p1, p2, p3, 0., 1);
+  sortedPointToVector(discrete, pts, ts);
+}
+
+static void decasteljau(double tol, std::vector<sortedPoint> &discrete, int pos,
+                        const std::vector<SPoint3> &pts, double t0, double te)
+{
+  int order = (int)pts.size() - 1;
+  double dmax2 = 0;
+  for (int i = 1; i < order ; ++i)
+    dmax2 = std::max(dmax2, sqDistPointSegment(pts[i], pts[0], pts[order]));
+  if(dmax2 < tol * tol)
+    return;
+  std::vector<SPoint3> sub0(pts.size());
+  std::vector<SPoint3> sub1(pts);
+  for (int l = 0; l < order + 1; ++l) {
+    sub0[l] = sub1[0];
+    for (int i = 0; i < order - l; ++i)
+      sub1[i] = (sub1[i] + sub1[i + 1]) * 0.5;
+  }
+  double tmid = 0.5 * (t0 + te);
+  int newpos = sortedPointInsert(sub1[0], tmid, discrete, pos);
+  decasteljau(tol, discrete, pos, sub0, t0, tmid);
+  decasteljau(tol, discrete, newpos, sub1, tmid, te);
+}
+
+void decasteljau(double tol, const std::vector<SPoint3> &controlPoints,
+                 std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  std::vector<sortedPoint> discrete;
+  sortedPoint pnt1 = {controlPoints[0], 0., 1};
+  discrete.push_back(pnt1);
+  sortedPoint pnt2 = {controlPoints.back(), 1., -1};
+  discrete.push_back(pnt2);
+  decasteljau(tol, discrete, 0, controlPoints, 0., 1);
+  sortedPointToVector(discrete, pts, ts);
+}
diff --git a/Numeric/decasteljau.h b/Numeric/decasteljau.h
new file mode 100644
index 0000000..b013592
--- /dev/null
+++ b/Numeric/decasteljau.h
@@ -0,0 +1,22 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+//
+// Contributed by J. Lambrechts
+
+#ifndef _DECASTELJAU_H_
+#define _DECASTELJAU_H_
+
+#include <vector>
+class SPoint3;
+void decasteljau(double tol, const SPoint3 &p0, const SPoint3 &p1,
+                 const SPoint3 &p2, std::vector<SPoint3> &pts,
+                 std::vector<double> &ts);
+void decasteljau(double tol, const SPoint3 &p0, const SPoint3 &p1,
+                 const SPoint3 &p2, const SPoint3 &p3, std::vector<SPoint3> &pts,
+                 std::vector<double> &ts);
+void decasteljau(double tol, const std::vector<SPoint3> &controlPoints,
+                 std::vector<SPoint3> &pts, std::vector<double> &ts);
+
+#endif
diff --git a/Numeric/discreteFrechetDistance.cpp b/Numeric/discreteFrechetDistance.cpp
new file mode 100644
index 0000000..94f4cad
--- /dev/null
+++ b/Numeric/discreteFrechetDistance.cpp
@@ -0,0 +1,54 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
+#include "discreteFrechetDistance.h"
+#include "fullMatrix.h"
+
+static double distance (const SPoint3 &p1, const SPoint3 &p2){
+  return p1.distance(p2);
+}
+
+static double c(int i, int j,
+		fullMatrix<double> &CA,
+		const std::vector<SPoint3> &P,
+		const std::vector<SPoint3> &Q)
+{
+  double CAij;
+  if (CA(i,j)>-1){
+    CAij = CA(i,j);
+  }
+  else if (i==0 && j==0){
+    CA(i,j) = distance(P[0],Q[0]);     // update the CA permanent
+    CAij = CA(i,j);                    // set the current relevant value
+  }
+  else if (i>0 && j==0){
+    CA(i,j) = std::max(c(i-1,0,CA,P,Q), distance(P[i],Q[1]) );
+    CAij = CA(i,j);
+  }
+  else if (i==0 && j>0){
+    CA(i,j) = std::max( c(0,j-1,CA,P,Q), distance(P[0],Q[j]) );
+    CAij = CA(i,j);
+  }
+  else if (i>0 && j>0){
+    double temp = std::min(std::min(c(i-1,j,CA,P,Q),c(i-1,j-1,CA,P,Q)),c(i,j-1,CA,P,Q));
+    CA(i,j) = std::max(temp,distance(P[i],Q[j]));
+    CAij = CA(i,j);
+  }
+  else{
+    CA(i,j) = 1.e22;
+    CAij = CA(i,j);
+  }
+  return CAij;
+}
+
+double discreteFrechetDistance (const std::vector<SPoint3> &P,
+				const std::vector<SPoint3> &Q){
+  const int sP = P.size();
+  const int sQ = Q.size();
+  fullMatrix<double> CA (sP,sQ);
+  CA.setAll(-1.0);
+  double cm = c(sP-1,sQ-1,CA,P,Q);
+  return cm;
+}
diff --git a/Numeric/discreteFrechetDistance.h b/Numeric/discreteFrechetDistance.h
new file mode 100644
index 0000000..439b0c9
--- /dev/null
+++ b/Numeric/discreteFrechetDistance.h
@@ -0,0 +1,7 @@
+#ifndef _DISCRETE_FRECHET_DISTANCE_
+#define _DISCRETE_FRECHET_DISTANCE_
+#include <vector>
+#include "SPoint3.h"
+double discreteFrechetDistance (const std::vector<SPoint3> &P, 
+				const std::vector<SPoint3> &Q);
+#endif
diff --git a/Numeric/fullMatrix.h b/Numeric/fullMatrix.h
index c1c03cd..e844ee7 100644
--- a/Numeric/fullMatrix.h
+++ b/Numeric/fullMatrix.h
@@ -112,6 +112,13 @@ class fullVector
   inline const scalar * getDataPtr() const { return _data; }
 
   /**
+     @return Returns a  pointer to this fullVector data. at n
+     This pointer will point to the following memory segment:
+     [(*this)(0), (*this)(1), ..., (*this)(this->size() - 1)].
+  */
+  inline scalar * getDataPtr() { return _data; }
+
+  /**
      @param i A vector index between 0 and size() - 1.
      @returns Returns the ith scalar of this fullVector.
   */
@@ -444,6 +451,9 @@ class fullMatrix
     return (*this)(r, c);
   }
 
+  inline const scalar * getDataPtr() const { return _data; }
+  inline scalar * getDataPtr() { return _data; }
+
   // operations
   inline void set(int r, int c, scalar v){
     #ifdef _DEBUG
diff --git a/Numeric/hausdorffDistance.cpp b/Numeric/hausdorffDistance.cpp
new file mode 100644
index 0000000..0c7ba1a
--- /dev/null
+++ b/Numeric/hausdorffDistance.cpp
@@ -0,0 +1,115 @@
+/*
+compute the hausdorff distance between two polygonal curves 
+in n*m time where n and m are the nb of points of the 
+polygonal curves
+*/
+#include "SVector3.h"
+#include "hausdorffDistance.h"
+
+static double intersect (SPoint3 &q, SVector3 &n, // a plane
+			 SPoint3 &p1, SPoint3 &p2, // a segment
+			 SPoint3 &result)
+{
+  // n * (x-q) = 0
+  // x = p1 + t (p2-p1)
+  // n *(p1 + t (p2-p1) - q) = 0
+  // t = n*(q-p1) / n*(p2-p1)
+
+  const double t = dot(n,q-p1)/dot(n,p2-p1);
+  result = p1 *(1.-t)+ p2*t;
+  return t;
+}
+
+static double projection (SPoint3 &p1, SPoint3 &p2, SPoint3 &q, SPoint3 &result){
+  // x = p1 + t (p2 - p1)
+  // (x - q) * (p2 - p1) = 0
+  // (p1 + t (p2 - p1) - q) (p2 - p1) = 0
+  // t = (q-p1) * (p2-p1) / (p2-p1)^2
+  SVector3 p21 = p2-p1;
+  const double t = dot(q-p1,p21)/dot(p21,p21);
+  result = p1 *(1.-t)+ p2*t;
+  return t;
+}  
+
+static SPoint3 closestPoint (SPoint3 &p1, SPoint3 &p2, SPoint3 &q){
+  double result;
+  const double t = projection (p1,p2,q,result);
+  if (t >= 0.0 && t <= 1.0)return result;
+  if (t < 0)return p1;
+  return p2;
+}  
+
+
+double closestPoint (const std::vector<SPoint3> &P, const SPoint3 &p, SPoint3 & result){
+  double closestDistance = 1.e22;
+  for (unsigned int i=1;i<P.size();i++){
+    SPoint3 q = closestPoint (P[i-1],P[i],p);
+    const double pq = p.distance(q);
+    if (pq < closestDistance){
+      closestDistance = pq;
+      result = q;
+    }   
+  }
+  return closestDistance;
+} 
+
+// we test all points of P plus all points that are the intersections
+// of angle bissectors of Q with P
+double oneSidedHausdorffDistance (const std::vector<SPoint3> &P, 
+				  const std::vector<SPoint3> &Q, 
+				  SPoint3 &p1, SPoint3 &p2){
+  const double hausdorffDistance = 0.0;
+  
+  // first test the points
+  for (unsigned int i=0;i<P.size();i++){
+    SPoint3 result;
+    double d = closestPoint (Q, P[i], result);
+    if (d > hausdorffDistance){
+      hausdorffDistance = d;
+      p1 = P[i];
+      p2 = result;
+    }
+  }
+  // compute angle bissectors intersections
+  std::vector<SPoint3> intersections;
+  for (unsigned int i=1;i<Q.size()-1;i++){
+    SPoint3 a = Q[i-1];
+    SPoint3 b = Q[i];
+    SPoint3 c = Q[i+1];
+    SVector3 ba = b-a;
+    SVector3 ca = c-a;
+    SVector3 bissector = (ba+ca);
+    SVector3 n; // normal to the bissector plane
+    if (bissector.norm == 0){
+      ba.normalize();
+      n = ba;
+    }
+    else{
+      SVector3 b = crossprod (bissector,ba);
+      n = crossprod (b,bissector);
+      n.normalize();
+    }
+    for (unsigned int i=1;i<P.size();i++){
+      SPoint3 result;
+      const double t = intersect (b, n, P[i-1],P[i],result);
+      if (t >=0 && t <=1)intersections.push_back(result);	
+    }
+  }
+
+  for (unsigned int i=0;i<intersections.size();i++){
+    SPoint3 result;
+    double d = closestPoint (Q, intersections[i], result);
+    if (d > hausdorffDistance){
+      hausdorffDistance = d;
+      p1 = P[i];
+      p2 = result;
+    }
+  }
+  return hausdorffDistance;
+}
+
+double hausdorffDistance (const std::vector<SPoint3> &P, 
+			  const std::vector<SPoint3> &Q){
+  return std::max(oneSidedHausdorffDistance (P,Q),
+		  oneSidedHausdorffDistance (Q,P));  
+}
diff --git a/Numeric/hausdorffDistance.h b/Numeric/hausdorffDistance.h
new file mode 100644
index 0000000..09f4ef3
--- /dev/null
+++ b/Numeric/hausdorffDistance.h
@@ -0,0 +1,7 @@
+#ifndef _HAUSDORFF_DISTANCE_H_
+#define _HAUSDORFF_DISTANCE_H_
+#include <vector>
+#include "SPoint3.h"
+double hausdorffDistance (const std::vector<SPoint3> &P, 
+			  const std::vector<SPoint3> &Q);
+#endif
diff --git a/Numeric/mathEvaluator.cpp b/Numeric/mathEvaluator.cpp
index f68fe7b..a3eef0d 100644
--- a/Numeric/mathEvaluator.cpp
+++ b/Numeric/mathEvaluator.cpp
@@ -8,7 +8,7 @@
 #if defined(HAVE_MATHEX)
 
 mathEvaluator::mathEvaluator(std::vector<std::string> &expressions,
-                             std::vector<std::string> &variables)                   
+                             std::vector<std::string> &variables)
 {
   _expressions.resize(expressions.size());
   _variables.resize(variables.size(), 0.);
@@ -30,7 +30,11 @@ mathEvaluator::mathEvaluator(std::vector<std::string> &expressions,
       error = true;
     }
   }
-  if(error) expressions.clear();
+  if(error){
+    for(unsigned int i = 0; i < _expressions.size(); i++)
+      delete(_expressions[i]);
+    _expressions.clear();
+  }
 }
 
 mathEvaluator::~mathEvaluator()
@@ -42,15 +46,15 @@ mathEvaluator::~mathEvaluator()
 bool mathEvaluator::eval(std::vector<double> &values, std::vector<double> &res)
 {
   if(values.size() != _variables.size()){
-    Msg::Error("Given %d values for %d variables", values.size(), _variables.size());
+    Msg::Error("Given %d value(s) for %d variable(s)", values.size(), _variables.size());
     return false;
   }
 
   if(res.size() != _expressions.size()){
-    Msg::Error("Given %d results for %d expressions", res.size(), _expressions.size());
+    Msg::Error("Given %d result(s) for %d expression(s)", res.size(), _expressions.size());
     return false;
   }
-  
+
   for(unsigned int i = 0; i < values.size(); i++)
     _variables[i] = values[i];
 
diff --git a/Numeric/miniBasis.cpp b/Numeric/miniBasis.cpp
new file mode 100644
index 0000000..b893ebc
--- /dev/null
+++ b/Numeric/miniBasis.cpp
@@ -0,0 +1,37 @@
+#include "miniBasis.h"
+#include "BasisFactory.h"
+miniBasis::miniBasis()
+{
+  type = MSH_TRI_MINI;
+  parentType = TYPE_TRI;
+  order = 3;
+  dimension = 2;
+  numFaces = 3;
+  serendip = false;
+  const nodalBasis &p1 = *BasisFactory::getNodalBasis(MSH_TRI_3);
+  closures = p1.closures;
+  fullClosures = p1.fullClosures;
+  for(size_t i = 0; i < fullClosures.size(); ++i) {
+    fullClosures[i].push_back(3);
+  }
+  closureRef = p1.closureRef;
+  points = p1.points;
+  points.resize(4, 2);
+  points(0, 0) = 0.; points(0, 1) = 0.;
+  points(1, 0) = 1.; points(1, 1) = 0.;
+  points(2, 0) = 0.; points(2, 1) = 1.;
+  points(3, 0) = 1./3; points(3, 1) = 1./3;
+  monomials.resize(6, 2);
+  monomials(0, 0) = 0.; monomials(0, 1) = 0.;
+  monomials(1, 0) = 1.; monomials(1, 1) = 0.;
+  monomials(2, 0) = 0.; monomials(2, 1) = 1.;
+  monomials(3, 0) = 1.; monomials(3, 1) = 1.;
+  monomials(4, 0) = 2.; monomials(4, 1) = 1.;
+  monomials(5, 0) = 1.; monomials(5, 1) = 2.;
+  coefficients.resize(4, 6);
+  coefficients.setAll(0.);
+  coefficients(0, 0) = 1.; coefficients(0, 1) = -1.; coefficients(0, 2) = -1.;
+  coefficients(1, 1) = 1.;
+  coefficients(2, 2) = 1.;
+  coefficients(3, 3) = 1.; coefficients(3, 4) = -1.; coefficients(3, 5) = -1.; 
+}
diff --git a/Numeric/miniBasis.h b/Numeric/miniBasis.h
new file mode 100644
index 0000000..631980a
--- /dev/null
+++ b/Numeric/miniBasis.h
@@ -0,0 +1,8 @@
+#ifndef _MINI_BASIS_H_
+#define _MINI_BASIS_H_
+#include "polynomialBasis.h"
+class miniBasis : public polynomialBasis { // mini is NOT a real nodal basis but in GMSH, only the nodal basis have closure and mini have closure so...
+  public:
+    miniBasis();
+};
+#endif
diff --git a/Numeric/nodalBasis.h b/Numeric/nodalBasis.h
index e35f948..25b8556 100644
--- a/Numeric/nodalBasis.h
+++ b/Numeric/nodalBasis.h
@@ -15,6 +15,7 @@ class nodalBasis {
   bool serendip;
   fullMatrix<double> points;
 
+  nodalBasis() {};
   nodalBasis(int tag);
   virtual ~nodalBasis() {}
 
diff --git a/Numeric/polynomialBasis.h b/Numeric/polynomialBasis.h
index 3ecc836..ef60d07 100644
--- a/Numeric/polynomialBasis.h
+++ b/Numeric/polynomialBasis.h
@@ -79,6 +79,7 @@ class polynomialBasis : public nodalBasis
   fullMatrix<double> monomials;
   fullMatrix<double> coefficients;
 
+  polynomialBasis() {};
   polynomialBasis(int tag);
   ~polynomialBasis();
 
diff --git a/Parser/FunctionManager.cpp b/Parser/FunctionManager.cpp
index f204692..d12d7bf 100644
--- a/Parser/FunctionManager.cpp
+++ b/Parser/FunctionManager.cpp
@@ -21,8 +21,8 @@ class File_Position
 {
  public:
   int lineno;
-  fpos_t position;
-  FILE *file;
+  gmshfpos_t position;
+  gmshFILE file;
   std::string filename;
 };
 
@@ -54,7 +54,7 @@ FunctionManager *FunctionManager::Instance()
   return instance;
 }
 
-int FunctionManager::enterFunction(char *name, FILE ** f, std::string &filename,
+int FunctionManager::enterFunction(char *name, gmshFILE * f, std::string &filename,
                                    int &lno) const
 {
   if(functions->m.find(name) == functions->m.end())
@@ -63,38 +63,38 @@ int FunctionManager::enterFunction(char *name, FILE ** f, std::string &filename,
   fpold.lineno = lno;
   fpold.filename = filename;
   fpold.file = *f;
-  fgetpos(fpold.file, &fpold.position);
+  gmshgetpos(fpold.file, &fpold.position);
   calls->s.push(fpold);
   File_Position fp = (functions->m)[name];
-  fsetpos(fp.file, &fp.position);
+  gmshsetpos(fp.file, &fp.position);
   *f = fp.file;
   filename = fp.filename;
   lno = fp.lineno;
   return 1;
 }
 
-int FunctionManager::leaveFunction(FILE ** f, std::string &filename, int &lno)
+int FunctionManager::leaveFunction(gmshFILE * f, std::string &filename, int &lno)
 {
   if(!calls->s.size())
     return 0;
   File_Position fp;
   fp = calls->s.top();
   calls->s.pop();
-  fsetpos(fp.file, &fp.position);
+  gmshsetpos(fp.file, &fp.position);
   *f = fp.file;
   filename = fp.filename;
   lno = fp.lineno;
   return 1;
 }
 
-int FunctionManager::createFunction(char *name, FILE * f, std::string &filename,
+int FunctionManager::createFunction(char *name, gmshFILE  f, std::string &filename,
                                     int lno)
 {
   File_Position fp;
   fp.file = f;
   fp.filename = filename;
   fp.lineno = lno;
-  fgetpos(fp.file, &fp.position);
+  gmshgetpos(fp.file, &fp.position);
   (functions->m)[name] = fp;
   return 1;
 }
diff --git a/Parser/FunctionManager.h b/Parser/FunctionManager.h
index 5594c65..8e6d33a 100644
--- a/Parser/FunctionManager.h
+++ b/Parser/FunctionManager.h
@@ -10,21 +10,21 @@ class mystack;
 class mymap;
 
 #include <string>
-#include <stdio.h>
+#include "GmshIO.h"
 
-// Singleton, one function manager for all parsers. 
+// Singleton, one function manager for all parsers.
 
 class FunctionManager
 {
   mymap *functions;
-  mystack *calls;  
+  mystack *calls;
   FunctionManager ();
   static FunctionManager *instance;
  public :
   static FunctionManager* Instance();
-  int createFunction(char *name, FILE *f, std::string &filename, int lineno);
-  int enterFunction(char *name, FILE **f, std::string &filename, int &lineno) const;
-  int leaveFunction(FILE **f, std::string &filename, int &lineno);
+  int createFunction(char *name, gmshFILE f, std::string &filename, int lineno);
+  int enterFunction(char *name, gmshFILE *f, std::string &filename, int &lineno) const;
+  int leaveFunction(gmshFILE *f, std::string &filename, int &lineno);
 };
 
 #endif
diff --git a/Parser/Gmsh.l b/Parser/Gmsh.l
index 9bf98eb..5253e2b 100644
--- a/Parser/Gmsh.l
+++ b/Parser/Gmsh.l
@@ -8,20 +8,42 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include "GmshConfig.h"
 #include "GmshMessage.h"
 #include "Geo.h"
 #include "Gmsh.tab.hpp"
+#include "GmshIO.h"
 
 void   parsestring(char endchar);
 char  *strsave(char *ptr);
 void   skipcomments(void);
 void   skipline(void);
 
+#if defined(HAVE_COMPRESSED_IO) && defined(HAVE_ZLIB)
+#define YY_INPUT(buf,result,max_size)                                   \
+     {                                                                  \
+       int c = '*', n;                                                  \
+       for ( n = 0; n < (int) max_size &&                               \
+               (c = gzgetc( yyin )) != EOF && c != '\n'; ++n )          \
+         buf[n] = (char) c;                                             \
+       if ( c == '\n' ){                                                \
+         buf[n++] = (char) c;                                           \
+         yylineno++;                                                    \
+       }                                                                \
+       if ( c == EOF )  {                                               \
+         int ernum;                                                     \
+         const char *msg=gzerror(yyin,&ernum);                          \
+         if (ernum)                                                     \
+            Msg::Fatal("Input in flex scanner failed");                 \
+       }                                                                \
+       result = n;                                                      \
+     }
+#else
 #define YY_INPUT(buf,result,max_size)					\
      {									\
        int c = '*', n;							\
-       for ( n = 0; n < max_size &&					\
-	       (c = getc( yyin )) != EOF && c != '\n'; ++n )		\
+       for ( n = 0; n < (int) max_size &&                               \
+	       (c = fgetc( yyin )) != EOF && c != '\n'; ++n )		\
 	 buf[n] = (char) c;						\
        if ( c == '\n' ){						\
 	 buf[n++] = (char) c;						\
@@ -30,7 +52,8 @@ void   skipline(void);
        if ( c == EOF && ferror( yyin ) )				\
 	 Msg::Fatal("Input in flex scanner failed");			\
        result = n;							\
-     }									\
+     }
+#endif
 
 #if defined(WIN32)
 #define isatty(arg) -1
@@ -118,6 +141,8 @@ CreateTopologyNoHoles   return tCreateTopologyNoHoles;
 Cpu                     return tCpu;
 
 DefineConstant          return tDefineConstant;
+DefineNumber            return tDefineNumber;
+DefineString            return tDefineString;
 Delete                  return tDelete;
 Degenerated             return tDegenerated;
 Dilate                  return tDilate;
@@ -134,9 +159,11 @@ EndIf                   return tEndIf;
 Euclidian               return tEuclidian;
 Error                   return tError;
 Exit                    return tExit;
+Exists                  return tExists;
 
 Fabs                    return tFabs;
 Field                   return tField;
+FileExists              return tFileExists;
 Floor                   return tFloor;
 Fmod                    return tFmod;
 For                     return tFor;
@@ -177,6 +204,7 @@ Memory                  return tMemory;
 
 Nurbs			return tNurbs;
 
+OnelabAction            return tOnelabAction;
 Order			return tNurbsOrder;
 
 Periodic                return tPeriodic;
@@ -239,6 +267,7 @@ Translate               return tTranslate;
 Tanh                    return tTanh;
 Tan                     return tTan;
 Today                   return tToday;
+TotalMemory             return tTotalMemory;
 
 UndefineConstant        return tUndefineConstant;
 Using                   return tUsing;
@@ -266,7 +295,7 @@ void skipcomments(void)
 
   while (1) {
     while ((c = yyinput()) != '*'){
-      if(feof(yyin)){
+      if(gmsheof(yyin)){
 	Msg::Error("End of file in commented region");
         return;
       }
@@ -286,7 +315,7 @@ void parsestring(char endchar)
   // etc.) "as is" in the output string: see yyinput() above
   int i = 0;
   while ((c = yyinput()) != endchar) {
-    if(feof(yyin)){
+    if(gmsheof(yyin)){
       Msg::Error("End of file in string");
       break;
     }
@@ -311,7 +340,7 @@ void skipline()
 {
   int c;
   while ((c = yyinput()) != '\n'){
-    if(feof(yyin)) return;
+    if(gmsheof(yyin)) return;
   }
 }
 
@@ -333,7 +362,7 @@ void skip_until(const char *skip, const char *until)
   while(1){
     while (1){
       chars[0] = yyinput();
-      if(feof(yyin)){
+      if(gmsheof(yyin)){
 	Msg::Error("Unexpected end of file");
 	return;
       }
@@ -348,7 +377,7 @@ void skip_until(const char *skip, const char *until)
     }
     for(i=1; i<l; i++){
       chars[i] = yyinput();
-      if(feof(yyin)){
+      if(gmsheof(yyin)){
 	l = i;
 	break;
       }
diff --git a/Parser/Gmsh.tab.cpp b/Parser/Gmsh.tab.cpp
index 35283b2..fdc4530 100644
--- a/Parser/Gmsh.tab.cpp
+++ b/Parser/Gmsh.tab.cpp
@@ -123,115 +123,121 @@
      tDraw = 304,
      tSetChanged = 305,
      tToday = 306,
-     tCpu = 307,
-     tMemory = 308,
-     tSyncModel = 309,
-     tCreateTopology = 310,
-     tCreateTopologyNoHoles = 311,
-     tDistanceFunction = 312,
-     tDefineConstant = 313,
-     tUndefineConstant = 314,
-     tPoint = 315,
-     tCircle = 316,
-     tEllipse = 317,
-     tLine = 318,
-     tSphere = 319,
-     tPolarSphere = 320,
-     tSurface = 321,
-     tSpline = 322,
-     tVolume = 323,
-     tCharacteristic = 324,
-     tLength = 325,
-     tParametric = 326,
-     tElliptic = 327,
-     tRefineMesh = 328,
-     tAdaptMesh = 329,
-     tRelocateMesh = 330,
-     tPlane = 331,
-     tRuled = 332,
-     tTransfinite = 333,
-     tComplex = 334,
-     tPhysical = 335,
-     tCompound = 336,
-     tPeriodic = 337,
-     tUsing = 338,
-     tPlugin = 339,
-     tDegenerated = 340,
-     tRecursive = 341,
-     tRotate = 342,
-     tTranslate = 343,
-     tSymmetry = 344,
-     tDilate = 345,
-     tExtrude = 346,
-     tLevelset = 347,
-     tRecombine = 348,
-     tSmoother = 349,
-     tSplit = 350,
-     tDelete = 351,
-     tCoherence = 352,
-     tIntersect = 353,
-     tMeshAlgorithm = 354,
-     tReverse = 355,
-     tLayers = 356,
-     tScaleLast = 357,
-     tHole = 358,
-     tAlias = 359,
-     tAliasWithOptions = 360,
-     tCopyOptions = 361,
-     tQuadTriAddVerts = 362,
-     tQuadTriNoNewVerts = 363,
-     tQuadTriSngl = 364,
-     tQuadTriDbl = 365,
-     tRecombLaterals = 366,
-     tTransfQuadTri = 367,
-     tText2D = 368,
-     tText3D = 369,
-     tInterpolationScheme = 370,
-     tTime = 371,
-     tCombine = 372,
-     tBSpline = 373,
-     tBezier = 374,
-     tNurbs = 375,
-     tNurbsOrder = 376,
-     tNurbsKnots = 377,
-     tColor = 378,
-     tColorTable = 379,
-     tFor = 380,
-     tIn = 381,
-     tEndFor = 382,
-     tIf = 383,
-     tEndIf = 384,
-     tExit = 385,
-     tAbort = 386,
-     tField = 387,
-     tReturn = 388,
-     tCall = 389,
-     tFunction = 390,
-     tShow = 391,
-     tHide = 392,
-     tGetValue = 393,
-     tGetEnv = 394,
-     tGetString = 395,
-     tHomology = 396,
-     tCohomology = 397,
-     tBetti = 398,
-     tSetOrder = 399,
-     tGMSH_MAJOR_VERSION = 400,
-     tGMSH_MINOR_VERSION = 401,
-     tGMSH_PATCH_VERSION = 402,
-     tAFFECTDIVIDE = 403,
-     tAFFECTTIMES = 404,
-     tAFFECTMINUS = 405,
-     tAFFECTPLUS = 406,
-     tOR = 407,
-     tAND = 408,
-     tNOTEQUAL = 409,
-     tEQUAL = 410,
-     tGREATEROREQUAL = 411,
-     tLESSOREQUAL = 412,
-     UNARYPREC = 413,
-     tMINUSMINUS = 414,
-     tPLUSPLUS = 415
+     tOnelabAction = 307,
+     tSyncModel = 308,
+     tCpu = 309,
+     tMemory = 310,
+     tTotalMemory = 311,
+     tCreateTopology = 312,
+     tCreateTopologyNoHoles = 313,
+     tDistanceFunction = 314,
+     tDefineConstant = 315,
+     tUndefineConstant = 316,
+     tDefineNumber = 317,
+     tDefineString = 318,
+     tPoint = 319,
+     tCircle = 320,
+     tEllipse = 321,
+     tLine = 322,
+     tSphere = 323,
+     tPolarSphere = 324,
+     tSurface = 325,
+     tSpline = 326,
+     tVolume = 327,
+     tCharacteristic = 328,
+     tLength = 329,
+     tParametric = 330,
+     tElliptic = 331,
+     tRefineMesh = 332,
+     tAdaptMesh = 333,
+     tRelocateMesh = 334,
+     tPlane = 335,
+     tRuled = 336,
+     tTransfinite = 337,
+     tComplex = 338,
+     tPhysical = 339,
+     tCompound = 340,
+     tPeriodic = 341,
+     tUsing = 342,
+     tPlugin = 343,
+     tDegenerated = 344,
+     tRecursive = 345,
+     tRotate = 346,
+     tTranslate = 347,
+     tSymmetry = 348,
+     tDilate = 349,
+     tExtrude = 350,
+     tLevelset = 351,
+     tRecombine = 352,
+     tSmoother = 353,
+     tSplit = 354,
+     tDelete = 355,
+     tCoherence = 356,
+     tIntersect = 357,
+     tMeshAlgorithm = 358,
+     tReverse = 359,
+     tLayers = 360,
+     tScaleLast = 361,
+     tHole = 362,
+     tAlias = 363,
+     tAliasWithOptions = 364,
+     tCopyOptions = 365,
+     tQuadTriAddVerts = 366,
+     tQuadTriNoNewVerts = 367,
+     tQuadTriSngl = 368,
+     tQuadTriDbl = 369,
+     tRecombLaterals = 370,
+     tTransfQuadTri = 371,
+     tText2D = 372,
+     tText3D = 373,
+     tInterpolationScheme = 374,
+     tTime = 375,
+     tCombine = 376,
+     tBSpline = 377,
+     tBezier = 378,
+     tNurbs = 379,
+     tNurbsOrder = 380,
+     tNurbsKnots = 381,
+     tColor = 382,
+     tColorTable = 383,
+     tFor = 384,
+     tIn = 385,
+     tEndFor = 386,
+     tIf = 387,
+     tEndIf = 388,
+     tExit = 389,
+     tAbort = 390,
+     tField = 391,
+     tReturn = 392,
+     tCall = 393,
+     tFunction = 394,
+     tShow = 395,
+     tHide = 396,
+     tGetValue = 397,
+     tGetEnv = 398,
+     tGetString = 399,
+     tHomology = 400,
+     tCohomology = 401,
+     tBetti = 402,
+     tSetOrder = 403,
+     tExists = 404,
+     tFileExists = 405,
+     tGMSH_MAJOR_VERSION = 406,
+     tGMSH_MINOR_VERSION = 407,
+     tGMSH_PATCH_VERSION = 408,
+     tAFFECTDIVIDE = 409,
+     tAFFECTTIMES = 410,
+     tAFFECTMINUS = 411,
+     tAFFECTPLUS = 412,
+     tOR = 413,
+     tAND = 414,
+     tNOTEQUAL = 415,
+     tEQUAL = 416,
+     tGREATEROREQUAL = 417,
+     tLESSOREQUAL = 418,
+     UNARYPREC = 419,
+     tMINUSMINUS = 420,
+     tPLUSPLUS = 421
    };
 #endif
 /* Tokens.  */
@@ -284,115 +290,121 @@
 #define tDraw 304
 #define tSetChanged 305
 #define tToday 306
-#define tCpu 307
-#define tMemory 308
-#define tSyncModel 309
-#define tCreateTopology 310
-#define tCreateTopologyNoHoles 311
-#define tDistanceFunction 312
-#define tDefineConstant 313
-#define tUndefineConstant 314
-#define tPoint 315
-#define tCircle 316
-#define tEllipse 317
-#define tLine 318
-#define tSphere 319
-#define tPolarSphere 320
-#define tSurface 321
-#define tSpline 322
-#define tVolume 323
-#define tCharacteristic 324
-#define tLength 325
-#define tParametric 326
-#define tElliptic 327
-#define tRefineMesh 328
-#define tAdaptMesh 329
-#define tRelocateMesh 330
-#define tPlane 331
-#define tRuled 332
-#define tTransfinite 333
-#define tComplex 334
-#define tPhysical 335
-#define tCompound 336
-#define tPeriodic 337
-#define tUsing 338
-#define tPlugin 339
-#define tDegenerated 340
-#define tRecursive 341
-#define tRotate 342
-#define tTranslate 343
-#define tSymmetry 344
-#define tDilate 345
-#define tExtrude 346
-#define tLevelset 347
-#define tRecombine 348
-#define tSmoother 349
-#define tSplit 350
-#define tDelete 351
-#define tCoherence 352
-#define tIntersect 353
-#define tMeshAlgorithm 354
-#define tReverse 355
-#define tLayers 356
-#define tScaleLast 357
-#define tHole 358
-#define tAlias 359
-#define tAliasWithOptions 360
-#define tCopyOptions 361
-#define tQuadTriAddVerts 362
-#define tQuadTriNoNewVerts 363
-#define tQuadTriSngl 364
-#define tQuadTriDbl 365
-#define tRecombLaterals 366
-#define tTransfQuadTri 367
-#define tText2D 368
-#define tText3D 369
-#define tInterpolationScheme 370
-#define tTime 371
-#define tCombine 372
-#define tBSpline 373
-#define tBezier 374
-#define tNurbs 375
-#define tNurbsOrder 376
-#define tNurbsKnots 377
-#define tColor 378
-#define tColorTable 379
-#define tFor 380
-#define tIn 381
-#define tEndFor 382
-#define tIf 383
-#define tEndIf 384
-#define tExit 385
-#define tAbort 386
-#define tField 387
-#define tReturn 388
-#define tCall 389
-#define tFunction 390
-#define tShow 391
-#define tHide 392
-#define tGetValue 393
-#define tGetEnv 394
-#define tGetString 395
-#define tHomology 396
-#define tCohomology 397
-#define tBetti 398
-#define tSetOrder 399
-#define tGMSH_MAJOR_VERSION 400
-#define tGMSH_MINOR_VERSION 401
-#define tGMSH_PATCH_VERSION 402
-#define tAFFECTDIVIDE 403
-#define tAFFECTTIMES 404
-#define tAFFECTMINUS 405
-#define tAFFECTPLUS 406
-#define tOR 407
-#define tAND 408
-#define tNOTEQUAL 409
-#define tEQUAL 410
-#define tGREATEROREQUAL 411
-#define tLESSOREQUAL 412
-#define UNARYPREC 413
-#define tMINUSMINUS 414
-#define tPLUSPLUS 415
+#define tOnelabAction 307
+#define tSyncModel 308
+#define tCpu 309
+#define tMemory 310
+#define tTotalMemory 311
+#define tCreateTopology 312
+#define tCreateTopologyNoHoles 313
+#define tDistanceFunction 314
+#define tDefineConstant 315
+#define tUndefineConstant 316
+#define tDefineNumber 317
+#define tDefineString 318
+#define tPoint 319
+#define tCircle 320
+#define tEllipse 321
+#define tLine 322
+#define tSphere 323
+#define tPolarSphere 324
+#define tSurface 325
+#define tSpline 326
+#define tVolume 327
+#define tCharacteristic 328
+#define tLength 329
+#define tParametric 330
+#define tElliptic 331
+#define tRefineMesh 332
+#define tAdaptMesh 333
+#define tRelocateMesh 334
+#define tPlane 335
+#define tRuled 336
+#define tTransfinite 337
+#define tComplex 338
+#define tPhysical 339
+#define tCompound 340
+#define tPeriodic 341
+#define tUsing 342
+#define tPlugin 343
+#define tDegenerated 344
+#define tRecursive 345
+#define tRotate 346
+#define tTranslate 347
+#define tSymmetry 348
+#define tDilate 349
+#define tExtrude 350
+#define tLevelset 351
+#define tRecombine 352
+#define tSmoother 353
+#define tSplit 354
+#define tDelete 355
+#define tCoherence 356
+#define tIntersect 357
+#define tMeshAlgorithm 358
+#define tReverse 359
+#define tLayers 360
+#define tScaleLast 361
+#define tHole 362
+#define tAlias 363
+#define tAliasWithOptions 364
+#define tCopyOptions 365
+#define tQuadTriAddVerts 366
+#define tQuadTriNoNewVerts 367
+#define tQuadTriSngl 368
+#define tQuadTriDbl 369
+#define tRecombLaterals 370
+#define tTransfQuadTri 371
+#define tText2D 372
+#define tText3D 373
+#define tInterpolationScheme 374
+#define tTime 375
+#define tCombine 376
+#define tBSpline 377
+#define tBezier 378
+#define tNurbs 379
+#define tNurbsOrder 380
+#define tNurbsKnots 381
+#define tColor 382
+#define tColorTable 383
+#define tFor 384
+#define tIn 385
+#define tEndFor 386
+#define tIf 387
+#define tEndIf 388
+#define tExit 389
+#define tAbort 390
+#define tField 391
+#define tReturn 392
+#define tCall 393
+#define tFunction 394
+#define tShow 395
+#define tHide 396
+#define tGetValue 397
+#define tGetEnv 398
+#define tGetString 399
+#define tHomology 400
+#define tCohomology 401
+#define tBetti 402
+#define tSetOrder 403
+#define tExists 404
+#define tFileExists 405
+#define tGMSH_MAJOR_VERSION 406
+#define tGMSH_MINOR_VERSION 407
+#define tGMSH_PATCH_VERSION 408
+#define tAFFECTDIVIDE 409
+#define tAFFECTTIMES 410
+#define tAFFECTMINUS 411
+#define tAFFECTPLUS 412
+#define tOR 413
+#define tAND 414
+#define tNOTEQUAL 415
+#define tEQUAL 416
+#define tGREATEROREQUAL 417
+#define tLESSOREQUAL 418
+#define UNARYPREC 419
+#define tMINUSMINUS 420
+#define tPLUSPLUS 421
 
 
 
@@ -405,6 +417,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
+#include <sstream>
 #include <string.h>
 #include <stdarg.h>
 #include <time.h>
@@ -471,7 +484,7 @@ static int curPhysDim = 0;
 static gmshSurface *myGmshSurface = 0;
 #define MAX_RECUR_LOOPS 100
 static int ImbricatedLoop = 0;
-static fpos_t yyposImbricatedLoopsTab[MAX_RECUR_LOOPS];
+static gmshfpos_t yyposImbricatedLoopsTab[MAX_RECUR_LOOPS];
 static int yylinenoImbricatedLoopsTab[MAX_RECUR_LOOPS];
 static double LoopControlVariablesTab[MAX_RECUR_LOOPS][3];
 static const char *LoopControlVariablesNameTab[MAX_RECUR_LOOPS];
@@ -481,7 +494,13 @@ static std::map<std::string, std::vector<std::string> > charOptions;
 void yyerror(const char *s);
 void yymsg(int level, const char *fmt, ...);
 void skip_until(const char *skip, const char *until);
+void assignVariable(const std::string &name, int index, int assignType,
+                    double value);
+void assignVariables(const std::string &name, List_T *indices, int assignType,
+                     List_T *values);
+void incrementVariable(const std::string &name, int index, double value);
 int PrintListOfDouble(char *format, List_T *list, char *buffer);
+void PrintParserSymbols(std::vector<std::string> &vec);
 fullMatrix<double> ListOfListOfDouble2Matrix(List_T *list);
 
 struct doubleXstring{
@@ -511,7 +530,7 @@ struct doubleXstring{
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 93 "Gmsh.y"
+#line 100 "Gmsh.y"
 {
   char *c;
   int i;
@@ -522,7 +541,7 @@ typedef union YYSTYPE
   List_T *l;
 }
 /* Line 193 of yacc.c.  */
-#line 526 "Gmsh.tab.cpp"
+#line 545 "Gmsh.tab.cpp"
 	YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -535,7 +554,7 @@ typedef union YYSTYPE
 
 
 /* Line 216 of yacc.c.  */
-#line 539 "Gmsh.tab.cpp"
+#line 558 "Gmsh.tab.cpp"
 
 #ifdef short
 # undef short
@@ -750,20 +769,20 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  5
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   8664
+#define YYLAST   8039
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  181
+#define YYNTOKENS  187
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  93
+#define YYNNTS  97
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  478
+#define YYNRULES  466
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  1664
+#define YYNSTATES  1613
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   415
+#define YYMAXUTOK   421
 
 #define YYTRANSLATE(YYX)						\
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -774,16 +793,16 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,   166,     2,   176,     2,   165,     2,     2,
-     171,   172,   163,   161,   177,   162,   175,   164,     2,     2,
+       2,     2,     2,   172,     2,   182,     2,   171,     2,     2,
+     177,   178,   169,   167,   183,   168,   181,   170,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-     157,     2,   158,   152,     2,     2,     2,     2,     2,     2,
+     163,     2,   164,   158,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,   173,     2,   174,   170,     2,     2,     2,     2,     2,
+       2,   179,     2,   180,   176,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,   178,     2,   179,   180,     2,     2,     2,
+       2,     2,     2,   184,     2,   185,   186,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -811,8 +830,9 @@ static const yytype_uint8 yytranslate[] =
      115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
      125,   126,   127,   128,   129,   130,   131,   132,   133,   134,
      135,   136,   137,   138,   139,   140,   141,   142,   143,   144,
-     145,   146,   147,   148,   149,   150,   151,   153,   154,   155,
-     156,   159,   160,   167,   168,   169
+     145,   146,   147,   148,   149,   150,   151,   152,   153,   154,
+     155,   156,   157,   159,   160,   161,   162,   165,   166,   173,
+     174,   175
 };
 
 #if YYDEBUG
@@ -826,376 +846,365 @@ static const yytype_uint16 yyprhs[] =
      100,   107,   114,   123,   124,   127,   130,   133,   136,   139,
      141,   145,   147,   151,   152,   153,   164,   166,   170,   171,
      185,   187,   191,   192,   208,   217,   232,   233,   240,   242,
-     244,   246,   248,   250,   252,   254,   260,   266,   271,   278,
-     286,   294,   304,   314,   318,   325,   330,   337,   347,   354,
-     364,   370,   379,   388,   400,   407,   417,   423,   431,   441,
-     451,   463,   471,   481,   491,   492,   494,   495,   499,   505,
-     506,   516,   522,   523,   533,   534,   538,   542,   548,   549,
-     552,   556,   562,   566,   567,   570,   574,   578,   584,   586,
-     588,   589,   595,   596,   599,   607,   608,   618,   625,   633,
-     638,   646,   655,   664,   672,   680,   692,   701,   710,   711,
-     721,   730,   740,   744,   749,   760,   768,   776,   785,   794,
-     807,   808,   818,   827,   835,   844,   845,   855,   861,   873,
-     879,   889,   899,   904,   914,   924,   926,   928,   929,   932,
-     939,   946,   953,   960,   969,   980,   995,  1012,  1025,  1034,
-    1043,  1050,  1065,  1070,  1077,  1084,  1088,  1093,  1099,  1106,
-    1110,  1114,  1119,  1125,  1130,  1136,  1140,  1148,  1156,  1160,
-    1168,  1172,  1175,  1178,  1181,  1184,  1200,  1203,  1206,  1209,
-    1212,  1215,  1232,  1236,  1243,  1252,  1261,  1272,  1274,  1277,
-    1279,  1283,  1288,  1290,  1296,  1308,  1322,  1323,  1331,  1332,
-    1346,  1347,  1363,  1364,  1371,  1380,  1389,  1398,  1411,  1424,
-    1437,  1452,  1467,  1482,  1483,  1496,  1497,  1510,  1511,  1524,
-    1525,  1542,  1543,  1560,  1561,  1578,  1579,  1598,  1599,  1618,
-    1619,  1638,  1640,  1643,  1649,  1657,  1667,  1670,  1673,  1676,
-    1680,  1683,  1687,  1690,  1694,  1697,  1701,  1711,  1718,  1719,
-    1723,  1724,  1726,  1727,  1730,  1731,  1734,  1742,  1749,  1758,
-    1764,  1768,  1776,  1782,  1787,  1794,  1801,  1814,  1825,  1836,
-    1847,  1858,  1869,  1874,  1879,  1884,  1889,  1894,  1897,  1901,
-    1908,  1910,  1912,  1914,  1917,  1923,  1931,  1942,  1944,  1948,
-    1951,  1954,  1957,  1961,  1965,  1969,  1973,  1977,  1981,  1985,
-    1989,  1993,  1997,  2001,  2005,  2009,  2013,  2019,  2024,  2029,
-    2034,  2039,  2044,  2049,  2054,  2059,  2064,  2069,  2076,  2081,
-    2086,  2091,  2096,  2101,  2106,  2111,  2118,  2125,  2132,  2137,
-    2142,  2147,  2152,  2157,  2162,  2167,  2172,  2177,  2182,  2187,
-    2194,  2199,  2204,  2209,  2214,  2219,  2224,  2229,  2236,  2243,
-    2250,  2255,  2257,  2259,  2261,  2263,  2265,  2267,  2269,  2271,
-    2273,  2275,  2280,  2285,  2288,  2294,  2298,  2305,  2310,  2318,
-    2325,  2332,  2339,  2344,  2346,  2349,  2352,  2356,  2360,  2372,
-    2382,  2390,  2398,  2400,  2404,  2406,  2408,  2411,  2415,  2420,
-    2426,  2428,  2430,  2433,  2437,  2441,  2447,  2452,  2455,  2458,
-    2461,  2464,  2470,  2476,  2482,  2488,  2490,  2492,  2496,  2500,
-    2505,  2512,  2519,  2521,  2523,  2527,  2531,  2541,  2549,  2551,
-    2557,  2561,  2568,  2570,  2574,  2576,  2578,  2582,  2589,  2591,
-    2593,  2598,  2605,  2612,  2619,  2624,  2629,  2638,  2643,  2648,
-    2653,  2658,  2665,  2672,  2674,  2678,  2684,  2690,  2692
+     244,   246,   248,   250,   252,   254,   256,   258,   260,   262,
+     268,   274,   279,   286,   294,   302,   310,   320,   330,   334,
+     341,   348,   353,   360,   370,   377,   387,   393,   402,   411,
+     423,   430,   440,   446,   454,   464,   474,   486,   494,   504,
+     514,   515,   517,   518,   522,   528,   529,   539,   545,   546,
+     556,   557,   561,   565,   571,   572,   575,   579,   585,   589,
+     590,   593,   597,   601,   607,   609,   611,   612,   618,   619,
+     622,   630,   631,   641,   648,   656,   661,   669,   678,   687,
+     695,   703,   715,   724,   733,   734,   744,   753,   763,   767,
+     772,   783,   791,   799,   808,   817,   830,   831,   841,   850,
+     858,   867,   868,   878,   884,   896,   902,   912,   922,   927,
+     937,   947,   949,   951,   952,   955,   962,   969,   976,   983,
+     992,  1003,  1018,  1035,  1048,  1057,  1066,  1073,  1088,  1093,
+    1100,  1107,  1111,  1116,  1122,  1129,  1133,  1137,  1142,  1148,
+    1153,  1159,  1163,  1171,  1179,  1183,  1191,  1195,  1198,  1201,
+    1204,  1207,  1223,  1226,  1229,  1232,  1235,  1238,  1255,  1259,
+    1266,  1275,  1284,  1295,  1297,  1300,  1302,  1306,  1311,  1313,
+    1319,  1331,  1345,  1346,  1354,  1355,  1369,  1370,  1386,  1387,
+    1394,  1403,  1412,  1421,  1434,  1447,  1460,  1475,  1490,  1505,
+    1506,  1519,  1520,  1533,  1534,  1547,  1548,  1565,  1566,  1583,
+    1584,  1601,  1602,  1621,  1622,  1641,  1642,  1661,  1663,  1666,
+    1672,  1680,  1690,  1693,  1696,  1699,  1703,  1706,  1710,  1713,
+    1717,  1720,  1724,  1734,  1741,  1742,  1746,  1747,  1749,  1750,
+    1753,  1754,  1757,  1765,  1772,  1781,  1787,  1791,  1799,  1805,
+    1810,  1817,  1824,  1837,  1848,  1859,  1870,  1881,  1892,  1897,
+    1902,  1907,  1912,  1917,  1920,  1924,  1931,  1933,  1935,  1937,
+    1940,  1946,  1954,  1965,  1967,  1971,  1974,  1977,  1980,  1984,
+    1988,  1992,  1996,  2000,  2004,  2008,  2012,  2016,  2020,  2024,
+    2028,  2032,  2036,  2042,  2047,  2052,  2057,  2062,  2067,  2072,
+    2077,  2082,  2087,  2092,  2099,  2104,  2109,  2114,  2119,  2124,
+    2129,  2134,  2141,  2148,  2155,  2160,  2162,  2164,  2166,  2168,
+    2170,  2172,  2174,  2176,  2178,  2180,  2181,  2188,  2190,  2195,
+    2200,  2205,  2210,  2215,  2218,  2224,  2230,  2234,  2241,  2246,
+    2254,  2261,  2268,  2275,  2280,  2282,  2285,  2288,  2292,  2296,
+    2308,  2318,  2326,  2334,  2336,  2340,  2342,  2344,  2347,  2351,
+    2356,  2362,  2364,  2366,  2369,  2373,  2377,  2383,  2388,  2391,
+    2394,  2397,  2400,  2406,  2412,  2418,  2424,  2426,  2428,  2432,
+    2437,  2444,  2446,  2448,  2452,  2456,  2466,  2474,  2476,  2482,
+    2486,  2493,  2495,  2499,  2501,  2503,  2507,  2514,  2516,  2518,
+    2520,  2525,  2532,  2539,  2544,  2549,  2558,  2563,  2568,  2575,
+    2576,  2583,  2585,  2589,  2595,  2601,  2603
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int16 yyrhs[] =
 {
-     182,     0,    -1,   183,    -1,     1,     6,    -1,    -1,   183,
-     184,    -1,   187,    -1,   186,    -1,   205,    -1,   219,    -1,
-     224,    -1,   228,    -1,   229,    -1,   230,    -1,   233,    -1,
-     253,    -1,   254,    -1,   232,    -1,   231,    -1,   227,    -1,
-     256,    -1,   158,    -1,   158,   158,    -1,    37,   171,   269,
-     172,     6,    -1,    38,   171,   269,   172,     6,    -1,    37,
-     171,   269,   172,   185,   269,     6,    -1,    37,   171,   269,
-     177,   265,   172,     6,    -1,    38,   171,   269,   177,   265,
-     172,     6,    -1,    37,   171,   269,   177,   265,   172,   185,
-     269,     6,    -1,     4,   269,   178,   188,   179,     6,    -1,
-     104,     4,   173,   257,   174,     6,    -1,   105,     4,   173,
-     257,   174,     6,    -1,   106,     4,   173,   257,   177,   257,
-     174,     6,    -1,    -1,   188,   191,    -1,   188,   195,    -1,
-     188,   198,    -1,   188,   200,    -1,   188,   201,    -1,   257,
-      -1,   189,   177,   257,    -1,   257,    -1,   190,   177,   257,
-      -1,    -1,    -1,     4,   192,   171,   189,   172,   193,   178,
-     190,   179,     6,    -1,   269,    -1,   194,   177,   269,    -1,
-      -1,   113,   171,   257,   177,   257,   177,   257,   172,   196,
-     178,   194,   179,     6,    -1,   269,    -1,   197,   177,   269,
-      -1,    -1,   114,   171,   257,   177,   257,   177,   257,   177,
-     257,   172,   199,   178,   197,   179,     6,    -1,   115,   178,
-     261,   179,   178,   261,   179,     6,    -1,   115,   178,   261,
-     179,   178,   261,   179,   178,   261,   179,   178,   261,   179,
-       6,    -1,    -1,   116,   202,   178,   190,   179,     6,    -1,
-       7,    -1,   151,    -1,   150,    -1,   149,    -1,   148,    -1,
-     169,    -1,   168,    -1,    58,   173,   207,   174,     6,    -1,
-      59,   173,   210,   174,     6,    -1,   273,   203,   262,     6,
-      -1,     4,   173,   174,   203,   262,     6,    -1,     4,   173,
-     257,   174,   203,   257,     6,    -1,     4,   171,   257,   172,
-     203,   257,     6,    -1,     4,   173,   178,   265,   179,   174,
-     203,   262,     6,    -1,     4,   171,   178,   265,   179,   172,
-     203,   262,     6,    -1,   273,   204,     6,    -1,     4,   173,
-     257,   174,   204,     6,    -1,   273,     7,   270,     6,    -1,
-       4,   175,     4,     7,   270,     6,    -1,     4,   173,   257,
-     174,   175,     4,     7,   270,     6,    -1,     4,   175,     4,
-     203,   257,     6,    -1,     4,   173,   257,   174,   175,     4,
-     203,   257,     6,    -1,     4,   175,     4,   204,     6,    -1,
-       4,   173,   257,   174,   175,     4,   204,     6,    -1,     4,
-     175,   123,   175,     4,     7,   266,     6,    -1,     4,   173,
-     257,   174,   175,   123,   175,     4,     7,   266,     6,    -1,
-       4,   175,   124,     7,   267,     6,    -1,     4,   173,   257,
-     174,   175,   124,     7,   267,     6,    -1,     4,   132,     7,
-     257,     6,    -1,   132,   173,   257,   174,     7,     4,     6,
-      -1,   132,   173,   257,   174,   175,     4,     7,   257,     6,
-      -1,   132,   173,   257,   174,   175,     4,     7,   270,     6,
-      -1,   132,   173,   257,   174,   175,     4,     7,   178,   265,
-     179,     6,    -1,   132,   173,   257,   174,   175,     4,     6,
-      -1,    84,   171,     4,   172,   175,     4,     7,   257,     6,
-      -1,    84,   171,     4,   172,   175,     4,     7,   270,     6,
-      -1,    -1,   177,    -1,    -1,   207,   206,   273,    -1,   207,
-     206,   273,     7,   257,    -1,    -1,   207,   206,   273,     7,
-     178,   257,   208,   212,   179,    -1,   207,   206,   273,     7,
-     270,    -1,    -1,   207,   206,   273,     7,   178,   270,   209,
-     214,   179,    -1,    -1,   210,   206,   269,    -1,   257,     7,
-     270,    -1,   211,   177,   257,     7,   270,    -1,    -1,   212,
-     213,    -1,   177,     4,   262,    -1,   177,     4,   178,   211,
-     179,    -1,   177,     4,   270,    -1,    -1,   214,   215,    -1,
-     177,     4,   257,    -1,   177,     4,   270,    -1,   177,     4,
-     178,   271,   179,    -1,   257,    -1,   270,    -1,    -1,   126,
-      64,   178,   257,   179,    -1,    -1,    76,   259,    -1,    60,
-     171,   257,   172,     7,   259,     6,    -1,    -1,    80,    60,
-     220,   171,   216,   172,     7,   262,     6,    -1,    69,    70,
-     262,     7,   257,     6,    -1,    63,   171,   257,   172,     7,
-     262,     6,    -1,    85,    63,   262,     6,    -1,    67,   171,
-     257,   172,     7,   262,     6,    -1,    61,   171,   257,   172,
-       7,   262,   218,     6,    -1,    62,   171,   257,   172,     7,
-     262,   218,     6,    -1,   118,   171,   257,   172,     7,   262,
-       6,    -1,   119,   171,   257,   172,     7,   262,     6,    -1,
-     120,   171,   257,   172,     7,   262,   122,   262,   121,   257,
-       6,    -1,    63,     4,   171,   257,   172,     7,   262,     6,
-      -1,    81,    63,   171,   257,   172,     7,   262,     6,    -1,
-      -1,    80,    63,   221,   171,   216,   172,     7,   262,     6,
-      -1,    76,    66,   171,   257,   172,     7,   262,     6,    -1,
-      77,    66,   171,   257,   172,     7,   262,   217,     6,    -1,
-      12,    13,     6,    -1,    13,    66,   257,     6,    -1,    71,
-      66,   171,   257,   172,     7,     5,     5,     5,     6,    -1,
-      64,   171,   257,   172,     7,   262,     6,    -1,    65,   171,
-     257,   172,     7,   262,     6,    -1,    66,     4,   171,   257,
-     172,     7,   262,     6,    -1,    81,    66,   171,   257,   172,
-       7,   262,     6,    -1,    81,    66,   171,   257,   172,     7,
-     262,     4,   178,   261,   179,     6,    -1,    -1,    80,    66,
-     222,   171,   216,   172,     7,   262,     6,    -1,    79,    68,
-     171,   257,   172,     7,   262,     6,    -1,    68,   171,   257,
-     172,     7,   262,     6,    -1,    81,    68,   171,   257,   172,
-       7,   262,     6,    -1,    -1,    80,    68,   223,   171,   216,
-     172,     7,   262,     6,    -1,    88,   259,   178,   225,   179,
-      -1,    87,   178,   259,   177,   259,   177,   257,   179,   178,
-     225,   179,    -1,    89,   259,   178,   225,   179,    -1,    90,
-     178,   259,   177,   257,   179,   178,   225,   179,    -1,    90,
-     178,   259,   177,   259,   179,   178,   225,   179,    -1,     4,
-     178,   225,   179,    -1,    98,    63,   178,   265,   179,    66,
-     178,   257,   179,    -1,    95,    63,   171,   257,   172,   178,
-     265,   179,     6,    -1,   226,    -1,   224,    -1,    -1,   226,
-     219,    -1,   226,    60,   178,   265,   179,     6,    -1,   226,
-      63,   178,   265,   179,     6,    -1,   226,    66,   178,   265,
-     179,     6,    -1,   226,    68,   178,   265,   179,     6,    -1,
-      92,    76,   171,   257,   172,     7,   262,     6,    -1,    92,
-      60,   171,   257,   172,     7,   178,   261,   179,     6,    -1,
-      92,    76,   171,   257,   172,     7,   178,   259,   177,   259,
-     177,   265,   179,     6,    -1,    92,    76,   171,   257,   172,
-       7,   178,   259,   177,   259,   177,   259,   177,   265,   179,
-       6,    -1,    92,    64,   171,   257,   172,     7,   178,   259,
-     177,   265,   179,     6,    -1,    92,     4,   171,   257,   172,
-       7,   262,     6,    -1,    92,     4,   171,   257,   172,     7,
-       5,     6,    -1,    92,     4,   178,   257,   179,     6,    -1,
-      92,     4,   171,   257,   172,     7,   178,   259,   177,   259,
-     177,   265,   179,     6,    -1,    96,   178,   226,   179,    -1,
-      96,   132,   173,   257,   174,     6,    -1,    96,     4,   173,
-     257,   174,     6,    -1,    96,     4,     6,    -1,    96,     4,
-       4,     6,    -1,   123,   266,   178,   226,   179,    -1,    86,
-     123,   266,   178,   226,   179,    -1,   136,     5,     6,    -1,
-     137,     5,     6,    -1,   136,   178,   226,   179,    -1,    86,
-     136,   178,   226,   179,    -1,   137,   178,   226,   179,    -1,
-      86,   137,   178,   226,   179,    -1,     4,   270,     6,    -1,
-       4,     4,   173,   257,   174,   269,     6,    -1,     4,     4,
-       4,   173,   257,   174,     6,    -1,     4,   257,     6,    -1,
-      84,   171,     4,   172,   175,     4,     6,    -1,   117,     4,
-       6,    -1,   130,     6,    -1,   131,     6,    -1,    54,     6,
-      -1,    48,     6,    -1,    48,   178,   257,   177,   257,   177,
-     257,   177,   257,   177,   257,   177,   257,   179,     6,    -1,
-      49,     6,    -1,    50,     6,    -1,    55,     6,    -1,    56,
-       6,    -1,    73,     6,    -1,    74,   178,   265,   179,   178,
-     265,   179,   178,   261,   179,   178,   257,   177,   257,   179,
-       6,    -1,   144,   257,     6,    -1,   125,   171,   257,     8,
-     257,   172,    -1,   125,   171,   257,     8,   257,     8,   257,
-     172,    -1,   125,     4,   126,   178,   257,     8,   257,   179,
-      -1,   125,     4,   126,   178,   257,     8,   257,     8,   257,
-     179,    -1,   127,    -1,   135,     4,    -1,   133,    -1,   134,
-       4,     6,    -1,   128,   171,   257,   172,    -1,   129,    -1,
-      91,   259,   178,   226,   179,    -1,    91,   178,   259,   177,
-     259,   177,   257,   179,   178,   226,   179,    -1,    91,   178,
-     259,   177,   259,   177,   259,   177,   257,   179,   178,   226,
-     179,    -1,    -1,    91,   259,   178,   226,   234,   247,   179,
-      -1,    -1,    91,   178,   259,   177,   259,   177,   257,   179,
-     178,   226,   235,   247,   179,    -1,    -1,    91,   178,   259,
-     177,   259,   177,   259,   177,   257,   179,   178,   226,   236,
-     247,   179,    -1,    -1,    91,   178,   226,   237,   247,   179,
-      -1,    91,    60,   178,   257,   177,   259,   179,     6,    -1,
-      91,    63,   178,   257,   177,   259,   179,     6,    -1,    91,
-      66,   178,   257,   177,   259,   179,     6,    -1,    91,    60,
-     178,   257,   177,   259,   177,   259,   177,   257,   179,     6,
-      -1,    91,    63,   178,   257,   177,   259,   177,   259,   177,
-     257,   179,     6,    -1,    91,    66,   178,   257,   177,   259,
-     177,   259,   177,   257,   179,     6,    -1,    91,    60,   178,
-     257,   177,   259,   177,   259,   177,   259,   177,   257,   179,
-       6,    -1,    91,    63,   178,   257,   177,   259,   177,   259,
-     177,   259,   177,   257,   179,     6,    -1,    91,    66,   178,
-     257,   177,   259,   177,   259,   177,   259,   177,   257,   179,
-       6,    -1,    -1,    91,    60,   178,   257,   177,   259,   179,
-     238,   178,   247,   179,     6,    -1,    -1,    91,    63,   178,
-     257,   177,   259,   179,   239,   178,   247,   179,     6,    -1,
-      -1,    91,    66,   178,   257,   177,   259,   179,   240,   178,
-     247,   179,     6,    -1,    -1,    91,    60,   178,   257,   177,
-     259,   177,   259,   177,   257,   179,   241,   178,   247,   179,
-       6,    -1,    -1,    91,    63,   178,   257,   177,   259,   177,
-     259,   177,   257,   179,   242,   178,   247,   179,     6,    -1,
-      -1,    91,    66,   178,   257,   177,   259,   177,   259,   177,
-     257,   179,   243,   178,   247,   179,     6,    -1,    -1,    91,
-      60,   178,   257,   177,   259,   177,   259,   177,   259,   177,
-     257,   179,   244,   178,   247,   179,     6,    -1,    -1,    91,
-      63,   178,   257,   177,   259,   177,   259,   177,   259,   177,
-     257,   179,   245,   178,   247,   179,     6,    -1,    -1,    91,
-      66,   178,   257,   177,   259,   177,   259,   177,   259,   177,
-     257,   179,   246,   178,   247,   179,     6,    -1,   248,    -1,
-     247,   248,    -1,   101,   178,   257,   179,     6,    -1,   101,
-     178,   262,   177,   262,   179,     6,    -1,   101,   178,   262,
-     177,   262,   177,   262,   179,     6,    -1,   102,     6,    -1,
-      93,     6,    -1,   109,     6,    -1,   109,   111,     6,    -1,
-     110,     6,    -1,   110,   111,     6,    -1,   107,     6,    -1,
-     107,   111,     6,    -1,   108,     6,    -1,   108,   111,     6,
-      -1,   103,   171,   257,   172,     7,   262,    83,   257,     6,
-      -1,    83,     4,   173,   257,   174,     6,    -1,    -1,    83,
-       4,   257,    -1,    -1,     4,    -1,    -1,     7,   262,    -1,
-      -1,     7,   257,    -1,    78,    63,   263,     7,   257,   249,
-       6,    -1,    78,    66,   263,   251,   250,     6,    -1,    72,
-      66,   178,   257,   179,     7,   262,     6,    -1,    78,    68,
-     263,   251,     6,    -1,   112,   263,     6,    -1,    99,    66,
-     178,   265,   179,   257,     6,    -1,    93,    66,   263,   252,
-       6,    -1,    93,    68,   263,     6,    -1,    94,    66,   262,
-       7,   257,     6,    -1,    82,    63,   262,     7,   262,     6,
-      -1,    82,    66,   257,   178,   265,   179,     7,   257,   178,
-     265,   179,     6,    -1,    60,   178,   265,   179,   126,    66,
-     178,   257,   179,     6,    -1,    63,   178,   265,   179,   126,
-      66,   178,   257,   179,     6,    -1,    60,   178,   265,   179,
-     126,    68,   178,   257,   179,     6,    -1,    63,   178,   265,
-     179,   126,    68,   178,   257,   179,     6,    -1,    66,   178,
-     265,   179,   126,    68,   178,   257,   179,     6,    -1,   100,
-      66,   263,     6,    -1,   100,    63,   263,     6,    -1,    75,
-      60,   263,     6,    -1,    75,    63,   263,     6,    -1,    75,
-      66,   263,     6,    -1,    97,     6,    -1,    97,     4,     6,
-      -1,    97,    60,   178,   265,   179,     6,    -1,   141,    -1,
-     142,    -1,   143,    -1,   255,     6,    -1,   255,   178,   262,
-     179,     6,    -1,   255,   178,   262,   177,   262,   179,     6,
-      -1,   255,   171,   262,   172,   178,   262,   177,   262,   179,
-       6,    -1,   258,    -1,   171,   257,   172,    -1,   162,   257,
-      -1,   161,   257,    -1,   166,   257,    -1,   257,   162,   257,
-      -1,   257,   161,   257,    -1,   257,   163,   257,    -1,   257,
-     164,   257,    -1,   257,   165,   257,    -1,   257,   170,   257,
-      -1,   257,   157,   257,    -1,   257,   158,   257,    -1,   257,
-     160,   257,    -1,   257,   159,   257,    -1,   257,   156,   257,
-      -1,   257,   155,   257,    -1,   257,   154,   257,    -1,   257,
-     153,   257,    -1,   257,   152,   257,     8,   257,    -1,    14,
-     171,   257,   172,    -1,    15,   171,   257,   172,    -1,    16,
-     171,   257,   172,    -1,    17,   171,   257,   172,    -1,    18,
-     171,   257,   172,    -1,    19,   171,   257,   172,    -1,    20,
-     171,   257,   172,    -1,    21,   171,   257,   172,    -1,    22,
-     171,   257,   172,    -1,    24,   171,   257,   172,    -1,    25,
-     171,   257,   177,   257,   172,    -1,    26,   171,   257,   172,
-      -1,    27,   171,   257,   172,    -1,    28,   171,   257,   172,
-      -1,    29,   171,   257,   172,    -1,    30,   171,   257,   172,
-      -1,    31,   171,   257,   172,    -1,    32,   171,   257,   172,
-      -1,    33,   171,   257,   177,   257,   172,    -1,    34,   171,
-     257,   177,   257,   172,    -1,    35,   171,   257,   177,   257,
-     172,    -1,    23,   171,   257,   172,    -1,    14,   173,   257,
-     174,    -1,    15,   173,   257,   174,    -1,    16,   173,   257,
-     174,    -1,    17,   173,   257,   174,    -1,    18,   173,   257,
-     174,    -1,    19,   173,   257,   174,    -1,    20,   173,   257,
-     174,    -1,    21,   173,   257,   174,    -1,    22,   173,   257,
-     174,    -1,    24,   173,   257,   174,    -1,    25,   173,   257,
-     177,   257,   174,    -1,    26,   173,   257,   174,    -1,    27,
-     173,   257,   174,    -1,    28,   173,   257,   174,    -1,    29,
-     173,   257,   174,    -1,    30,   173,   257,   174,    -1,    31,
-     173,   257,   174,    -1,    32,   173,   257,   174,    -1,    33,
-     173,   257,   177,   257,   174,    -1,    34,   173,   257,   177,
-     257,   174,    -1,    35,   173,   257,   177,   257,   174,    -1,
-      23,   173,   257,   174,    -1,     3,    -1,     9,    -1,    10,
-      -1,    11,    -1,   145,    -1,   146,    -1,   147,    -1,    52,
-      -1,    53,    -1,   273,    -1,     4,   173,   257,   174,    -1,
-     176,     4,   173,   174,    -1,   273,   204,    -1,     4,   173,
-     257,   174,   204,    -1,     4,   175,     4,    -1,     4,   173,
-     257,   174,   175,     4,    -1,     4,   175,     4,   204,    -1,
-       4,   173,   257,   174,   175,     4,   204,    -1,   138,   171,
-     269,   177,   257,   172,    -1,    45,   171,   269,   177,   269,
-     172,    -1,    46,   171,   269,   177,   269,   172,    -1,    47,
-     171,   271,   172,    -1,   260,    -1,   162,   259,    -1,   161,
-     259,    -1,   259,   162,   259,    -1,   259,   161,   259,    -1,
-     178,   257,   177,   257,   177,   257,   177,   257,   177,   257,
-     179,    -1,   178,   257,   177,   257,   177,   257,   177,   257,
-     179,    -1,   178,   257,   177,   257,   177,   257,   179,    -1,
-     171,   257,   177,   257,   177,   257,   172,    -1,   262,    -1,
-     261,   177,   262,    -1,   257,    -1,   264,    -1,   178,   179,
-      -1,   178,   265,   179,    -1,   162,   178,   265,   179,    -1,
-     257,   163,   178,   265,   179,    -1,   262,    -1,     5,    -1,
-     162,   264,    -1,   257,   163,   264,    -1,   257,     8,   257,
-      -1,   257,     8,   257,     8,   257,    -1,    60,   178,   257,
-     179,    -1,    60,     5,    -1,    63,     5,    -1,    66,     5,
-      -1,    68,     5,    -1,    80,    60,   178,   265,   179,    -1,
-      80,    63,   178,   265,   179,    -1,    80,    66,   178,   265,
-     179,    -1,    80,    68,   178,   265,   179,    -1,   224,    -1,
-     233,    -1,     4,   173,   174,    -1,     4,   171,   172,    -1,
-      36,   173,     4,   174,    -1,     4,   173,   178,   265,   179,
-     174,    -1,     4,   171,   178,   265,   179,   172,    -1,   257,
-      -1,   264,    -1,   265,   177,   257,    -1,   265,   177,   264,
-      -1,   178,   257,   177,   257,   177,   257,   177,   257,   179,
-      -1,   178,   257,   177,   257,   177,   257,   179,    -1,     4,
-      -1,     4,   175,   123,   175,     4,    -1,   178,   268,   179,
-      -1,     4,   173,   257,   174,   175,   124,    -1,   266,    -1,
-     268,   177,   266,    -1,   270,    -1,   273,    -1,     4,   175,
-       4,    -1,     4,   173,   257,   174,   175,     4,    -1,     5,
-      -1,    51,    -1,   139,   171,   269,   172,    -1,   140,   171,
-     269,   177,   269,   172,    -1,    41,   171,   269,   177,   269,
-     172,    -1,    41,   173,   269,   177,   269,   174,    -1,    42,
-     171,   269,   172,    -1,    43,   171,   269,   172,    -1,    44,
-     171,   269,   177,   269,   177,   269,   172,    -1,    39,   171,
-     271,   172,    -1,    39,   173,   271,   174,    -1,    40,   171,
-     269,   172,    -1,    40,   173,   269,   174,    -1,    40,   171,
-     269,   177,   265,   172,    -1,    40,   173,   269,   177,   265,
-     174,    -1,   269,    -1,   271,   177,   269,    -1,     4,   180,
-     178,   257,   179,    -1,   272,   180,   178,   257,   179,    -1,
-       4,    -1,   272,    -1
+     188,     0,    -1,   189,    -1,     1,     6,    -1,    -1,   189,
+     190,    -1,   193,    -1,   192,    -1,   213,    -1,   227,    -1,
+     232,    -1,   236,    -1,   237,    -1,   238,    -1,   241,    -1,
+     261,    -1,   262,    -1,   240,    -1,   239,    -1,   235,    -1,
+     264,    -1,   164,    -1,   164,   164,    -1,    37,   177,   278,
+     178,     6,    -1,    38,   177,   278,   178,     6,    -1,    37,
+     177,   278,   178,   191,   278,     6,    -1,    37,   177,   278,
+     183,   274,   178,     6,    -1,    38,   177,   278,   183,   274,
+     178,     6,    -1,    37,   177,   278,   183,   274,   178,   191,
+     278,     6,    -1,     4,   278,   184,   194,   185,     6,    -1,
+     108,     4,   179,   265,   180,     6,    -1,   109,     4,   179,
+     265,   180,     6,    -1,   110,     4,   179,   265,   183,   265,
+     180,     6,    -1,    -1,   194,   197,    -1,   194,   201,    -1,
+     194,   204,    -1,   194,   206,    -1,   194,   207,    -1,   265,
+      -1,   195,   183,   265,    -1,   265,    -1,   196,   183,   265,
+      -1,    -1,    -1,     4,   198,   177,   195,   178,   199,   184,
+     196,   185,     6,    -1,   278,    -1,   200,   183,   278,    -1,
+      -1,   117,   177,   265,   183,   265,   183,   265,   178,   202,
+     184,   200,   185,     6,    -1,   278,    -1,   203,   183,   278,
+      -1,    -1,   118,   177,   265,   183,   265,   183,   265,   183,
+     265,   178,   205,   184,   203,   185,     6,    -1,   119,   184,
+     270,   185,   184,   270,   185,     6,    -1,   119,   184,   270,
+     185,   184,   270,   185,   184,   270,   185,   184,   270,   185,
+       6,    -1,    -1,   120,   208,   184,   196,   185,     6,    -1,
+       7,    -1,   157,    -1,   156,    -1,   155,    -1,   154,    -1,
+     175,    -1,   174,    -1,   177,    -1,   179,    -1,   178,    -1,
+     180,    -1,    60,   179,   215,   180,     6,    -1,    61,   179,
+     218,   180,     6,    -1,   283,   209,   271,     6,    -1,     4,
+     179,   180,   209,   271,     6,    -1,     4,   179,   265,   180,
+     209,   265,     6,    -1,     4,   177,   265,   178,   209,   265,
+       6,    -1,   282,   179,   265,   180,   209,   265,     6,    -1,
+       4,   211,   184,   274,   185,   212,   209,   271,     6,    -1,
+     282,   177,   184,   274,   185,   178,   209,   271,     6,    -1,
+     283,   210,     6,    -1,     4,   179,   265,   180,   210,     6,
+      -1,   282,   179,   265,   180,   210,     6,    -1,   283,     7,
+     279,     6,    -1,     4,   181,     4,     7,   279,     6,    -1,
+       4,   179,   265,   180,   181,     4,     7,   279,     6,    -1,
+       4,   181,     4,   209,   265,     6,    -1,     4,   179,   265,
+     180,   181,     4,   209,   265,     6,    -1,     4,   181,     4,
+     210,     6,    -1,     4,   179,   265,   180,   181,     4,   210,
+       6,    -1,     4,   181,   127,   181,     4,     7,   275,     6,
+      -1,     4,   179,   265,   180,   181,   127,   181,     4,     7,
+     275,     6,    -1,     4,   181,   128,     7,   276,     6,    -1,
+       4,   179,   265,   180,   181,   128,     7,   276,     6,    -1,
+       4,   136,     7,   265,     6,    -1,   136,   179,   265,   180,
+       7,     4,     6,    -1,   136,   179,   265,   180,   181,     4,
+       7,   265,     6,    -1,   136,   179,   265,   180,   181,     4,
+       7,   279,     6,    -1,   136,   179,   265,   180,   181,     4,
+       7,   184,   274,   185,     6,    -1,   136,   179,   265,   180,
+     181,     4,     6,    -1,    88,   177,     4,   178,   181,     4,
+       7,   265,     6,    -1,    88,   177,     4,   178,   181,     4,
+       7,   279,     6,    -1,    -1,   183,    -1,    -1,   215,   214,
+     283,    -1,   215,   214,   283,     7,   265,    -1,    -1,   215,
+     214,   283,     7,   184,   265,   216,   220,   185,    -1,   215,
+     214,   283,     7,   279,    -1,    -1,   215,   214,   283,     7,
+     184,   279,   217,   222,   185,    -1,    -1,   218,   214,   278,
+      -1,   265,     7,   279,    -1,   219,   183,   265,     7,   279,
+      -1,    -1,   220,   221,    -1,   183,     4,   271,    -1,   183,
+       4,   184,   219,   185,    -1,   183,     4,   279,    -1,    -1,
+     222,   223,    -1,   183,     4,   265,    -1,   183,     4,   279,
+      -1,   183,     4,   184,   281,   185,    -1,   265,    -1,   279,
+      -1,    -1,   130,    68,   184,   265,   185,    -1,    -1,    80,
+     268,    -1,    64,   177,   265,   178,     7,   268,     6,    -1,
+      -1,    84,    64,   228,   177,   224,   178,     7,   271,     6,
+      -1,    73,    74,   271,     7,   265,     6,    -1,    67,   177,
+     265,   178,     7,   271,     6,    -1,    89,    67,   271,     6,
+      -1,    71,   177,   265,   178,     7,   271,     6,    -1,    65,
+     177,   265,   178,     7,   271,   226,     6,    -1,    66,   177,
+     265,   178,     7,   271,   226,     6,    -1,   122,   177,   265,
+     178,     7,   271,     6,    -1,   123,   177,   265,   178,     7,
+     271,     6,    -1,   124,   177,   265,   178,     7,   271,   126,
+     271,   125,   265,     6,    -1,    67,     4,   177,   265,   178,
+       7,   271,     6,    -1,    85,    67,   177,   265,   178,     7,
+     271,     6,    -1,    -1,    84,    67,   229,   177,   224,   178,
+       7,   271,     6,    -1,    80,    70,   177,   265,   178,     7,
+     271,     6,    -1,    81,    70,   177,   265,   178,     7,   271,
+     225,     6,    -1,    12,    13,     6,    -1,    13,    70,   265,
+       6,    -1,    75,    70,   177,   265,   178,     7,     5,     5,
+       5,     6,    -1,    68,   177,   265,   178,     7,   271,     6,
+      -1,    69,   177,   265,   178,     7,   271,     6,    -1,    70,
+       4,   177,   265,   178,     7,   271,     6,    -1,    85,    70,
+     177,   265,   178,     7,   271,     6,    -1,    85,    70,   177,
+     265,   178,     7,   271,     4,   184,   270,   185,     6,    -1,
+      -1,    84,    70,   230,   177,   224,   178,     7,   271,     6,
+      -1,    83,    72,   177,   265,   178,     7,   271,     6,    -1,
+      72,   177,   265,   178,     7,   271,     6,    -1,    85,    72,
+     177,   265,   178,     7,   271,     6,    -1,    -1,    84,    72,
+     231,   177,   224,   178,     7,   271,     6,    -1,    92,   268,
+     184,   233,   185,    -1,    91,   184,   268,   183,   268,   183,
+     265,   185,   184,   233,   185,    -1,    93,   268,   184,   233,
+     185,    -1,    94,   184,   268,   183,   265,   185,   184,   233,
+     185,    -1,    94,   184,   268,   183,   268,   185,   184,   233,
+     185,    -1,     4,   184,   233,   185,    -1,   102,    67,   184,
+     274,   185,    70,   184,   265,   185,    -1,    99,    67,   177,
+     265,   178,   184,   274,   185,     6,    -1,   234,    -1,   232,
+      -1,    -1,   234,   227,    -1,   234,    64,   184,   274,   185,
+       6,    -1,   234,    67,   184,   274,   185,     6,    -1,   234,
+      70,   184,   274,   185,     6,    -1,   234,    72,   184,   274,
+     185,     6,    -1,    96,    80,   177,   265,   178,     7,   271,
+       6,    -1,    96,    64,   177,   265,   178,     7,   184,   270,
+     185,     6,    -1,    96,    80,   177,   265,   178,     7,   184,
+     268,   183,   268,   183,   274,   185,     6,    -1,    96,    80,
+     177,   265,   178,     7,   184,   268,   183,   268,   183,   268,
+     183,   274,   185,     6,    -1,    96,    68,   177,   265,   178,
+       7,   184,   268,   183,   274,   185,     6,    -1,    96,     4,
+     177,   265,   178,     7,   271,     6,    -1,    96,     4,   177,
+     265,   178,     7,     5,     6,    -1,    96,     4,   184,   265,
+     185,     6,    -1,    96,     4,   177,   265,   178,     7,   184,
+     268,   183,   268,   183,   274,   185,     6,    -1,   100,   184,
+     234,   185,    -1,   100,   136,   179,   265,   180,     6,    -1,
+     100,     4,   179,   265,   180,     6,    -1,   100,     4,     6,
+      -1,   100,     4,     4,     6,    -1,   127,   275,   184,   234,
+     185,    -1,    90,   127,   275,   184,   234,   185,    -1,   140,
+       5,     6,    -1,   141,     5,     6,    -1,   140,   184,   234,
+     185,    -1,    90,   140,   184,   234,   185,    -1,   141,   184,
+     234,   185,    -1,    90,   141,   184,   234,   185,    -1,     4,
+     279,     6,    -1,     4,     4,   179,   265,   180,   278,     6,
+      -1,     4,     4,     4,   179,   265,   180,     6,    -1,     4,
+     265,     6,    -1,    88,   177,     4,   178,   181,     4,     6,
+      -1,   121,     4,     6,    -1,   134,     6,    -1,   135,     6,
+      -1,    53,     6,    -1,    48,     6,    -1,    48,   184,   265,
+     183,   265,   183,   265,   183,   265,   183,   265,   183,   265,
+     185,     6,    -1,    49,     6,    -1,    50,     6,    -1,    57,
+       6,    -1,    58,     6,    -1,    77,     6,    -1,    78,   184,
+     274,   185,   184,   274,   185,   184,   270,   185,   184,   265,
+     183,   265,   185,     6,    -1,   148,   265,     6,    -1,   129,
+     177,   265,     8,   265,   178,    -1,   129,   177,   265,     8,
+     265,     8,   265,   178,    -1,   129,     4,   130,   184,   265,
+       8,   265,   185,    -1,   129,     4,   130,   184,   265,     8,
+     265,     8,   265,   185,    -1,   131,    -1,   139,     4,    -1,
+     137,    -1,   138,     4,     6,    -1,   132,   177,   265,   178,
+      -1,   133,    -1,    95,   268,   184,   234,   185,    -1,    95,
+     184,   268,   183,   268,   183,   265,   185,   184,   234,   185,
+      -1,    95,   184,   268,   183,   268,   183,   268,   183,   265,
+     185,   184,   234,   185,    -1,    -1,    95,   268,   184,   234,
+     242,   255,   185,    -1,    -1,    95,   184,   268,   183,   268,
+     183,   265,   185,   184,   234,   243,   255,   185,    -1,    -1,
+      95,   184,   268,   183,   268,   183,   268,   183,   265,   185,
+     184,   234,   244,   255,   185,    -1,    -1,    95,   184,   234,
+     245,   255,   185,    -1,    95,    64,   184,   265,   183,   268,
+     185,     6,    -1,    95,    67,   184,   265,   183,   268,   185,
+       6,    -1,    95,    70,   184,   265,   183,   268,   185,     6,
+      -1,    95,    64,   184,   265,   183,   268,   183,   268,   183,
+     265,   185,     6,    -1,    95,    67,   184,   265,   183,   268,
+     183,   268,   183,   265,   185,     6,    -1,    95,    70,   184,
+     265,   183,   268,   183,   268,   183,   265,   185,     6,    -1,
+      95,    64,   184,   265,   183,   268,   183,   268,   183,   268,
+     183,   265,   185,     6,    -1,    95,    67,   184,   265,   183,
+     268,   183,   268,   183,   268,   183,   265,   185,     6,    -1,
+      95,    70,   184,   265,   183,   268,   183,   268,   183,   268,
+     183,   265,   185,     6,    -1,    -1,    95,    64,   184,   265,
+     183,   268,   185,   246,   184,   255,   185,     6,    -1,    -1,
+      95,    67,   184,   265,   183,   268,   185,   247,   184,   255,
+     185,     6,    -1,    -1,    95,    70,   184,   265,   183,   268,
+     185,   248,   184,   255,   185,     6,    -1,    -1,    95,    64,
+     184,   265,   183,   268,   183,   268,   183,   265,   185,   249,
+     184,   255,   185,     6,    -1,    -1,    95,    67,   184,   265,
+     183,   268,   183,   268,   183,   265,   185,   250,   184,   255,
+     185,     6,    -1,    -1,    95,    70,   184,   265,   183,   268,
+     183,   268,   183,   265,   185,   251,   184,   255,   185,     6,
+      -1,    -1,    95,    64,   184,   265,   183,   268,   183,   268,
+     183,   268,   183,   265,   185,   252,   184,   255,   185,     6,
+      -1,    -1,    95,    67,   184,   265,   183,   268,   183,   268,
+     183,   268,   183,   265,   185,   253,   184,   255,   185,     6,
+      -1,    -1,    95,    70,   184,   265,   183,   268,   183,   268,
+     183,   268,   183,   265,   185,   254,   184,   255,   185,     6,
+      -1,   256,    -1,   255,   256,    -1,   105,   184,   265,   185,
+       6,    -1,   105,   184,   271,   183,   271,   185,     6,    -1,
+     105,   184,   271,   183,   271,   183,   271,   185,     6,    -1,
+     106,     6,    -1,    97,     6,    -1,   113,     6,    -1,   113,
+     115,     6,    -1,   114,     6,    -1,   114,   115,     6,    -1,
+     111,     6,    -1,   111,   115,     6,    -1,   112,     6,    -1,
+     112,   115,     6,    -1,   107,   177,   265,   178,     7,   271,
+      87,   265,     6,    -1,    87,     4,   179,   265,   180,     6,
+      -1,    -1,    87,     4,   265,    -1,    -1,     4,    -1,    -1,
+       7,   271,    -1,    -1,     7,   265,    -1,    82,    67,   272,
+       7,   265,   257,     6,    -1,    82,    70,   272,   259,   258,
+       6,    -1,    76,    70,   184,   265,   185,     7,   271,     6,
+      -1,    82,    72,   272,   259,     6,    -1,   116,   272,     6,
+      -1,   103,    70,   184,   274,   185,   265,     6,    -1,    97,
+      70,   272,   260,     6,    -1,    97,    72,   272,     6,    -1,
+      98,    70,   271,     7,   265,     6,    -1,    86,    67,   271,
+       7,   271,     6,    -1,    86,    70,   265,   184,   274,   185,
+       7,   265,   184,   274,   185,     6,    -1,    64,   184,   274,
+     185,   130,    70,   184,   265,   185,     6,    -1,    67,   184,
+     274,   185,   130,    70,   184,   265,   185,     6,    -1,    64,
+     184,   274,   185,   130,    72,   184,   265,   185,     6,    -1,
+      67,   184,   274,   185,   130,    72,   184,   265,   185,     6,
+      -1,    70,   184,   274,   185,   130,    72,   184,   265,   185,
+       6,    -1,   104,    70,   272,     6,    -1,   104,    67,   272,
+       6,    -1,    79,    64,   272,     6,    -1,    79,    67,   272,
+       6,    -1,    79,    70,   272,     6,    -1,   101,     6,    -1,
+     101,     4,     6,    -1,   101,    64,   184,   274,   185,     6,
+      -1,   145,    -1,   146,    -1,   147,    -1,   263,     6,    -1,
+     263,   184,   271,   185,     6,    -1,   263,   184,   271,   183,
+     271,   185,     6,    -1,   263,   177,   271,   178,   184,   271,
+     183,   271,   185,     6,    -1,   266,    -1,   177,   265,   178,
+      -1,   168,   265,    -1,   167,   265,    -1,   172,   265,    -1,
+     265,   168,   265,    -1,   265,   167,   265,    -1,   265,   169,
+     265,    -1,   265,   170,   265,    -1,   265,   171,   265,    -1,
+     265,   176,   265,    -1,   265,   163,   265,    -1,   265,   164,
+     265,    -1,   265,   166,   265,    -1,   265,   165,   265,    -1,
+     265,   162,   265,    -1,   265,   161,   265,    -1,   265,   160,
+     265,    -1,   265,   159,   265,    -1,   265,   158,   265,     8,
+     265,    -1,    14,   211,   265,   212,    -1,    15,   211,   265,
+     212,    -1,    16,   211,   265,   212,    -1,    17,   211,   265,
+     212,    -1,    18,   211,   265,   212,    -1,    19,   211,   265,
+     212,    -1,    20,   211,   265,   212,    -1,    21,   211,   265,
+     212,    -1,    22,   211,   265,   212,    -1,    24,   211,   265,
+     212,    -1,    25,   211,   265,   183,   265,   212,    -1,    26,
+     211,   265,   212,    -1,    27,   211,   265,   212,    -1,    28,
+     211,   265,   212,    -1,    29,   211,   265,   212,    -1,    30,
+     211,   265,   212,    -1,    31,   211,   265,   212,    -1,    32,
+     211,   265,   212,    -1,    33,   211,   265,   183,   265,   212,
+      -1,    34,   211,   265,   183,   265,   212,    -1,    35,   211,
+     265,   183,   265,   212,    -1,    23,   211,   265,   212,    -1,
+       3,    -1,     9,    -1,    10,    -1,    11,    -1,   151,    -1,
+     152,    -1,   153,    -1,    54,    -1,    55,    -1,    56,    -1,
+      -1,    62,   211,   265,   267,   220,   212,    -1,   283,    -1,
+       4,   179,   265,   180,    -1,   282,   179,   265,   180,    -1,
+     149,   177,   283,   178,    -1,   150,   177,   279,   178,    -1,
+     182,   283,   179,   180,    -1,   283,   210,    -1,     4,   179,
+     265,   180,   210,    -1,   282,   179,   265,   180,   210,    -1,
+       4,   181,     4,    -1,     4,   179,   265,   180,   181,     4,
+      -1,     4,   181,     4,   210,    -1,     4,   179,   265,   180,
+     181,     4,   210,    -1,   142,   177,   278,   183,   265,   178,
+      -1,    45,   177,   278,   183,   278,   178,    -1,    46,   177,
+     278,   183,   278,   178,    -1,    47,   177,   281,   178,    -1,
+     269,    -1,   168,   268,    -1,   167,   268,    -1,   268,   168,
+     268,    -1,   268,   167,   268,    -1,   184,   265,   183,   265,
+     183,   265,   183,   265,   183,   265,   185,    -1,   184,   265,
+     183,   265,   183,   265,   183,   265,   185,    -1,   184,   265,
+     183,   265,   183,   265,   185,    -1,   177,   265,   183,   265,
+     183,   265,   178,    -1,   271,    -1,   270,   183,   271,    -1,
+     265,    -1,   273,    -1,   184,   185,    -1,   184,   274,   185,
+      -1,   168,   184,   274,   185,    -1,   265,   169,   184,   274,
+     185,    -1,   271,    -1,     5,    -1,   168,   273,    -1,   265,
+     169,   273,    -1,   265,     8,   265,    -1,   265,     8,   265,
+       8,   265,    -1,    64,   184,   265,   185,    -1,    64,     5,
+      -1,    67,     5,    -1,    70,     5,    -1,    72,     5,    -1,
+      84,    64,   184,   274,   185,    -1,    84,    67,   184,   274,
+     185,    -1,    84,    70,   184,   274,   185,    -1,    84,    72,
+     184,   274,   185,    -1,   232,    -1,   241,    -1,     4,   211,
+     212,    -1,    36,   179,     4,   180,    -1,     4,   211,   184,
+     274,   185,   212,    -1,   265,    -1,   273,    -1,   274,   183,
+     265,    -1,   274,   183,   273,    -1,   184,   265,   183,   265,
+     183,   265,   183,   265,   185,    -1,   184,   265,   183,   265,
+     183,   265,   185,    -1,     4,    -1,     4,   181,   127,   181,
+       4,    -1,   184,   277,   185,    -1,     4,   179,   265,   180,
+     181,   128,    -1,   275,    -1,   277,   183,   275,    -1,   279,
+      -1,   283,    -1,     4,   181,     4,    -1,     4,   179,   265,
+     180,   181,     4,    -1,     5,    -1,    51,    -1,    52,    -1,
+     143,   177,   278,   178,    -1,   144,   177,   278,   183,   278,
+     178,    -1,    41,   211,   278,   183,   278,   212,    -1,    42,
+     177,   278,   178,    -1,    43,   177,   278,   178,    -1,    44,
+     177,   278,   183,   278,   183,   278,   178,    -1,    39,   211,
+     281,   212,    -1,    40,   211,   278,   212,    -1,    40,   211,
+     278,   183,   274,   212,    -1,    -1,    63,   211,   279,   280,
+     222,   212,    -1,   278,    -1,   281,   183,   278,    -1,     4,
+     186,   184,   265,   185,    -1,   282,   186,   184,   265,   185,
+      -1,     4,    -1,   282,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   172,   172,   173,   178,   180,   184,   185,   186,   187,
-     188,   189,   190,   191,   192,   193,   194,   195,   196,   197,
-     198,   202,   206,   213,   218,   223,   237,   250,   263,   291,
-     305,   318,   331,   350,   355,   356,   357,   358,   359,   363,
-     365,   370,   372,   378,   482,   377,   500,   507,   518,   517,
-     535,   542,   553,   552,   569,   586,   609,   608,   622,   623,
-     624,   625,   626,   630,   631,   637,   639,   641,   703,   733,
-     768,   802,   850,   897,   912,   928,   937,   943,   952,   970,
-     988,   997,  1009,  1014,  1022,  1042,  1065,  1076,  1084,  1106,
-    1129,  1155,  1176,  1188,  1202,  1202,  1204,  1206,  1215,  1225,
-    1224,  1236,  1246,  1245,  1259,  1261,  1269,  1275,  1282,  1283,
-    1287,  1298,  1313,  1323,  1324,  1329,  1337,  1346,  1364,  1368,
-    1379,  1382,  1395,  1398,  1408,  1432,  1431,  1451,  1473,  1491,
-    1512,  1530,  1560,  1590,  1608,  1626,  1652,  1670,  1689,  1688,
-    1711,  1729,  1768,  1774,  1780,  1787,  1812,  1837,  1854,  1873,
-    1908,  1907,  1931,  1949,  1966,  1983,  1982,  2008,  2013,  2018,
-    2023,  2028,  2033,  2056,  2062,  2073,  2074,  2079,  2082,  2086,
-    2109,  2132,  2155,  2183,  2204,  2230,  2251,  2273,  2293,  2405,
-    2424,  2462,  2571,  2580,  2586,  2601,  2629,  2646,  2655,  2669,
-    2675,  2681,  2690,  2699,  2708,  2722,  2767,  2784,  2799,  2818,
-    2830,  2854,  2858,  2863,  2870,  2876,  2881,  2887,  2895,  2899,
-    2903,  2908,  2963,  2976,  2993,  3010,  3031,  3052,  3087,  3095,
-    3101,  3108,  3112,  3121,  3129,  3137,  3146,  3145,  3160,  3159,
-    3174,  3173,  3188,  3187,  3201,  3208,  3215,  3222,  3229,  3236,
-    3243,  3250,  3257,  3265,  3264,  3278,  3277,  3291,  3290,  3304,
-    3303,  3317,  3316,  3330,  3329,  3343,  3342,  3356,  3355,  3369,
-    3368,  3385,  3388,  3394,  3406,  3426,  3450,  3455,  3459,  3463,
-    3467,  3471,  3475,  3479,  3483,  3487,  3491,  3510,  3523,  3526,
-    3542,  3545,  3562,  3565,  3571,  3574,  3581,  3637,  3707,  3712,
-    3779,  3815,  3823,  3866,  3905,  3925,  3952,  3992,  4015,  4038,
-    4042,  4046,  4069,  4108,  4147,  4168,  4189,  4216,  4220,  4230,
-    4265,  4266,  4267,  4271,  4277,  4289,  4307,  4335,  4336,  4337,
-    4338,  4339,  4340,  4341,  4342,  4343,  4350,  4351,  4352,  4353,
-    4354,  4355,  4356,  4357,  4358,  4359,  4360,  4361,  4362,  4363,
-    4364,  4365,  4366,  4367,  4368,  4369,  4370,  4371,  4372,  4373,
-    4374,  4375,  4376,  4377,  4378,  4379,  4380,  4381,  4382,  4385,
-    4386,  4387,  4388,  4389,  4390,  4391,  4392,  4393,  4394,  4395,
-    4396,  4397,  4398,  4399,  4400,  4401,  4402,  4403,  4404,  4405,
-    4406,  4415,  4416,  4417,  4418,  4419,  4420,  4421,  4422,  4423,
-    4427,  4445,  4463,  4475,  4492,  4513,  4518,  4523,  4533,  4543,
-    4548,  4557,  4562,  4589,  4593,  4597,  4601,  4605,  4612,  4616,
-    4620,  4624,  4631,  4636,  4643,  4648,  4652,  4657,  4661,  4669,
-    4680,  4684,  4696,  4704,  4712,  4719,  4729,  4749,  4753,  4757,
-    4761,  4765,  4794,  4823,  4852,  4881,  4891,  4901,  4914,  4926,
-    4938,  4957,  4978,  4983,  4987,  4991,  5003,  5007,  5019,  5026,
-    5036,  5040,  5055,  5060,  5067,  5071,  5084,  5092,  5103,  5107,
-    5115,  5123,  5131,  5140,  5148,  5162,  5176,  5188,  5205,  5221,
-    5226,  5230,  5250,  5272,  5277,  5283,  5292,  5305,  5308
+       0,   182,   182,   183,   188,   190,   194,   195,   196,   197,
+     198,   199,   200,   201,   202,   203,   204,   205,   206,   207,
+     208,   212,   216,   223,   228,   233,   247,   260,   273,   301,
+     315,   328,   341,   360,   365,   366,   367,   368,   369,   373,
+     375,   380,   382,   388,   492,   387,   510,   517,   528,   527,
+     545,   552,   563,   562,   579,   596,   619,   618,   632,   633,
+     634,   635,   636,   640,   641,   647,   647,   648,   648,   654,
+     655,   656,   717,   746,   751,   756,   761,   768,   775,   790,
+     795,   800,   809,   815,   824,   842,   860,   869,   881,   886,
+     894,   914,   937,   948,   956,   978,  1001,  1027,  1048,  1060,
+    1074,  1074,  1076,  1078,  1087,  1097,  1096,  1108,  1118,  1117,
+    1131,  1133,  1141,  1147,  1154,  1155,  1159,  1170,  1185,  1195,
+    1196,  1201,  1209,  1218,  1236,  1240,  1251,  1254,  1267,  1270,
+    1280,  1304,  1303,  1323,  1345,  1363,  1384,  1402,  1432,  1462,
+    1480,  1498,  1525,  1543,  1562,  1561,  1584,  1602,  1641,  1647,
+    1653,  1660,  1685,  1710,  1727,  1746,  1781,  1780,  1804,  1822,
+    1839,  1856,  1855,  1881,  1886,  1891,  1896,  1901,  1906,  1929,
+    1935,  1946,  1947,  1952,  1955,  1959,  1982,  2005,  2028,  2056,
+    2077,  2103,  2124,  2146,  2166,  2278,  2297,  2335,  2444,  2453,
+    2459,  2474,  2502,  2519,  2528,  2542,  2548,  2554,  2563,  2572,
+    2581,  2595,  2648,  2665,  2680,  2699,  2711,  2735,  2739,  2744,
+    2751,  2757,  2762,  2768,  2776,  2780,  2784,  2789,  2844,  2857,
+    2874,  2891,  2912,  2933,  2968,  2976,  2982,  2989,  2993,  3002,
+    3010,  3018,  3027,  3026,  3041,  3040,  3055,  3054,  3069,  3068,
+    3082,  3089,  3096,  3103,  3110,  3117,  3124,  3131,  3138,  3146,
+    3145,  3159,  3158,  3172,  3171,  3185,  3184,  3198,  3197,  3211,
+    3210,  3224,  3223,  3237,  3236,  3250,  3249,  3266,  3269,  3275,
+    3287,  3307,  3331,  3335,  3339,  3343,  3347,  3353,  3359,  3363,
+    3367,  3371,  3375,  3394,  3407,  3410,  3426,  3429,  3446,  3449,
+    3455,  3458,  3465,  3521,  3591,  3596,  3663,  3699,  3707,  3750,
+    3789,  3809,  3836,  3876,  3899,  3922,  3926,  3930,  3953,  3992,
+    4031,  4052,  4073,  4100,  4104,  4114,  4149,  4150,  4151,  4155,
+    4161,  4173,  4191,  4219,  4220,  4221,  4222,  4223,  4224,  4225,
+    4226,  4227,  4234,  4235,  4236,  4237,  4238,  4239,  4240,  4241,
+    4242,  4243,  4244,  4245,  4246,  4247,  4248,  4249,  4250,  4251,
+    4252,  4253,  4254,  4255,  4256,  4257,  4258,  4259,  4260,  4261,
+    4262,  4263,  4264,  4265,  4266,  4275,  4276,  4277,  4278,  4279,
+    4280,  4281,  4282,  4283,  4284,  4289,  4288,  4296,  4313,  4331,
+    4349,  4354,  4360,  4372,  4389,  4407,  4428,  4433,  4438,  4448,
+    4458,  4463,  4472,  4477,  4504,  4508,  4512,  4516,  4520,  4527,
+    4531,  4535,  4539,  4546,  4551,  4558,  4563,  4567,  4572,  4576,
+    4584,  4595,  4599,  4611,  4619,  4627,  4634,  4644,  4664,  4668,
+    4672,  4676,  4680,  4709,  4738,  4767,  4796,  4806,  4816,  4828,
+    4840,  4861,  4866,  4870,  4874,  4886,  4890,  4902,  4909,  4919,
+    4923,  4938,  4943,  4950,  4954,  4967,  4975,  4986,  4990,  4998,
+    5004,  5012,  5020,  5028,  5042,  5056,  5068,  5084,  5088,  5108,
+    5107,  5120,  5125,  5131,  5140,  5153,  5156
 };
 #endif
 
@@ -1212,48 +1221,50 @@ static const char *const yytname[] =
   "tHypot", "tList", "tPrintf", "tError", "tStr", "tSprintf", "tStrCat",
   "tStrPrefix", "tStrRelative", "tStrReplace", "tStrFind", "tStrCmp",
   "tTextAttributes", "tBoundingBox", "tDraw", "tSetChanged", "tToday",
-  "tCpu", "tMemory", "tSyncModel", "tCreateTopology",
-  "tCreateTopologyNoHoles", "tDistanceFunction", "tDefineConstant",
-  "tUndefineConstant", "tPoint", "tCircle", "tEllipse", "tLine", "tSphere",
-  "tPolarSphere", "tSurface", "tSpline", "tVolume", "tCharacteristic",
-  "tLength", "tParametric", "tElliptic", "tRefineMesh", "tAdaptMesh",
-  "tRelocateMesh", "tPlane", "tRuled", "tTransfinite", "tComplex",
-  "tPhysical", "tCompound", "tPeriodic", "tUsing", "tPlugin",
-  "tDegenerated", "tRecursive", "tRotate", "tTranslate", "tSymmetry",
-  "tDilate", "tExtrude", "tLevelset", "tRecombine", "tSmoother", "tSplit",
-  "tDelete", "tCoherence", "tIntersect", "tMeshAlgorithm", "tReverse",
-  "tLayers", "tScaleLast", "tHole", "tAlias", "tAliasWithOptions",
-  "tCopyOptions", "tQuadTriAddVerts", "tQuadTriNoNewVerts", "tQuadTriSngl",
-  "tQuadTriDbl", "tRecombLaterals", "tTransfQuadTri", "tText2D", "tText3D",
+  "tOnelabAction", "tSyncModel", "tCpu", "tMemory", "tTotalMemory",
+  "tCreateTopology", "tCreateTopologyNoHoles", "tDistanceFunction",
+  "tDefineConstant", "tUndefineConstant", "tDefineNumber", "tDefineString",
+  "tPoint", "tCircle", "tEllipse", "tLine", "tSphere", "tPolarSphere",
+  "tSurface", "tSpline", "tVolume", "tCharacteristic", "tLength",
+  "tParametric", "tElliptic", "tRefineMesh", "tAdaptMesh", "tRelocateMesh",
+  "tPlane", "tRuled", "tTransfinite", "tComplex", "tPhysical", "tCompound",
+  "tPeriodic", "tUsing", "tPlugin", "tDegenerated", "tRecursive",
+  "tRotate", "tTranslate", "tSymmetry", "tDilate", "tExtrude", "tLevelset",
+  "tRecombine", "tSmoother", "tSplit", "tDelete", "tCoherence",
+  "tIntersect", "tMeshAlgorithm", "tReverse", "tLayers", "tScaleLast",
+  "tHole", "tAlias", "tAliasWithOptions", "tCopyOptions",
+  "tQuadTriAddVerts", "tQuadTriNoNewVerts", "tQuadTriSngl", "tQuadTriDbl",
+  "tRecombLaterals", "tTransfQuadTri", "tText2D", "tText3D",
   "tInterpolationScheme", "tTime", "tCombine", "tBSpline", "tBezier",
   "tNurbs", "tNurbsOrder", "tNurbsKnots", "tColor", "tColorTable", "tFor",
   "tIn", "tEndFor", "tIf", "tEndIf", "tExit", "tAbort", "tField",
   "tReturn", "tCall", "tFunction", "tShow", "tHide", "tGetValue",
   "tGetEnv", "tGetString", "tHomology", "tCohomology", "tBetti",
-  "tSetOrder", "tGMSH_MAJOR_VERSION", "tGMSH_MINOR_VERSION",
-  "tGMSH_PATCH_VERSION", "tAFFECTDIVIDE", "tAFFECTTIMES", "tAFFECTMINUS",
-  "tAFFECTPLUS", "'?'", "tOR", "tAND", "tNOTEQUAL", "tEQUAL", "'<'", "'>'",
-  "tGREATEROREQUAL", "tLESSOREQUAL", "'+'", "'-'", "'*'", "'/'", "'%'",
-  "'!'", "UNARYPREC", "tMINUSMINUS", "tPLUSPLUS", "'^'", "'('", "')'",
-  "'['", "']'", "'.'", "'#'", "','", "'{'", "'}'", "'~'", "$accept", "All",
-  "GeoFormatItems", "GeoFormatItem", "SendToFile", "Printf", "View",
-  "Views", "ElementCoords", "ElementValues", "Element", "@1", "@2",
-  "Text2DValues", "Text2D", "@3", "Text3DValues", "Text3D", "@4",
-  "InterpolationMatrix", "Time", "@5", "NumericAffectation",
-  "NumericIncrement", "Affectation", "Comma", "DefineConstants", "@6",
-  "@7", "UndefineConstants", "Enumeration", "FloatParameterOptions",
-  "FloatParameterOption", "CharParameterOptions", "CharParameterOption",
-  "PhysicalId", "InSphereCenter", "CircleOptions", "Shape", "@8", "@9",
-  "@10", "@11", "Transform", "MultipleShape", "ListOfShapes", "LevelSet",
-  "Delete", "Colorify", "Visibility", "Command", "Loop", "Extrude", "@12",
-  "@13", "@14", "@15", "@16", "@17", "@18", "@19", "@20", "@21", "@22",
-  "@23", "@24", "ExtrudeParameters", "ExtrudeParameter", "TransfiniteType",
+  "tSetOrder", "tExists", "tFileExists", "tGMSH_MAJOR_VERSION",
+  "tGMSH_MINOR_VERSION", "tGMSH_PATCH_VERSION", "tAFFECTDIVIDE",
+  "tAFFECTTIMES", "tAFFECTMINUS", "tAFFECTPLUS", "'?'", "tOR", "tAND",
+  "tNOTEQUAL", "tEQUAL", "'<'", "'>'", "tGREATEROREQUAL", "tLESSOREQUAL",
+  "'+'", "'-'", "'*'", "'/'", "'%'", "'!'", "UNARYPREC", "tMINUSMINUS",
+  "tPLUSPLUS", "'^'", "'('", "')'", "'['", "']'", "'.'", "'#'", "','",
+  "'{'", "'}'", "'~'", "$accept", "All", "GeoFormatItems", "GeoFormatItem",
+  "SendToFile", "Printf", "View", "Views", "ElementCoords",
+  "ElementValues", "Element", "@1", "@2", "Text2DValues", "Text2D", "@3",
+  "Text3DValues", "Text3D", "@4", "InterpolationMatrix", "Time", "@5",
+  "NumericAffectation", "NumericIncrement", "LP", "RP", "Affectation",
+  "Comma", "DefineConstants", "@6", "@7", "UndefineConstants",
+  "Enumeration", "FloatParameterOptions", "FloatParameterOption",
+  "CharParameterOptions", "CharParameterOption", "PhysicalId",
+  "InSphereCenter", "CircleOptions", "Shape", "@8", "@9", "@10", "@11",
+  "Transform", "MultipleShape", "ListOfShapes", "LevelSet", "Delete",
+  "Colorify", "Visibility", "Command", "Loop", "Extrude", "@12", "@13",
+  "@14", "@15", "@16", "@17", "@18", "@19", "@20", "@21", "@22", "@23",
+  "@24", "ExtrudeParameters", "ExtrudeParameter", "TransfiniteType",
   "TransfiniteArrangement", "TransfiniteCorners", "RecombineAngle",
   "Constraints", "Coherence", "HomologyCommand", "Homology", "FExpr",
-  "FExpr_Single", "VExpr", "VExpr_Single", "RecursiveListOfListOfDouble",
-  "ListOfDouble", "ListOfDoubleOrAll", "FExpr_Multi",
-  "RecursiveListOfDouble", "ColorExpr", "ListOfColor",
-  "RecursiveListOfColor", "StringExprVar", "StringExpr",
+  "FExpr_Single", "@25", "VExpr", "VExpr_Single",
+  "RecursiveListOfListOfDouble", "ListOfDouble", "ListOfDoubleOrAll",
+  "FExpr_Multi", "RecursiveListOfDouble", "ColorExpr", "ListOfColor",
+  "RecursiveListOfColor", "StringExprVar", "StringExpr", "@26",
   "RecursiveListOfStringExprVar", "StringIndex", "String__Index", 0
 };
 #endif
@@ -1278,64 +1289,63 @@ static const yytype_uint16 yytoknum[] =
      375,   376,   377,   378,   379,   380,   381,   382,   383,   384,
      385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
      395,   396,   397,   398,   399,   400,   401,   402,   403,   404,
-     405,   406,    63,   407,   408,   409,   410,    60,    62,   411,
-     412,    43,    45,    42,    47,    37,    33,   413,   414,   415,
-      94,    40,    41,    91,    93,    46,    35,    44,   123,   125,
-     126
+     405,   406,   407,   408,   409,   410,   411,   412,    63,   413,
+     414,   415,   416,    60,    62,   417,   418,    43,    45,    42,
+      47,    37,    33,   419,   420,   421,    94,    40,    41,    91,
+      93,    46,    35,    44,   123,   125,   126
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint16 yyr1[] =
 {
-       0,   181,   182,   182,   183,   183,   184,   184,   184,   184,
-     184,   184,   184,   184,   184,   184,   184,   184,   184,   184,
-     184,   185,   185,   186,   186,   186,   186,   186,   186,   187,
-     187,   187,   187,   188,   188,   188,   188,   188,   188,   189,
-     189,   190,   190,   192,   193,   191,   194,   194,   196,   195,
-     197,   197,   199,   198,   200,   200,   202,   201,   203,   203,
-     203,   203,   203,   204,   204,   205,   205,   205,   205,   205,
-     205,   205,   205,   205,   205,   205,   205,   205,   205,   205,
-     205,   205,   205,   205,   205,   205,   205,   205,   205,   205,
-     205,   205,   205,   205,   206,   206,   207,   207,   207,   208,
-     207,   207,   209,   207,   210,   210,   211,   211,   212,   212,
-     213,   213,   213,   214,   214,   215,   215,   215,   216,   216,
-     217,   217,   218,   218,   219,   220,   219,   219,   219,   219,
-     219,   219,   219,   219,   219,   219,   219,   219,   221,   219,
-     219,   219,   219,   219,   219,   219,   219,   219,   219,   219,
-     222,   219,   219,   219,   219,   223,   219,   224,   224,   224,
-     224,   224,   224,   224,   224,   225,   225,   226,   226,   226,
-     226,   226,   226,   227,   227,   227,   227,   227,   227,   227,
-     227,   227,   228,   228,   228,   228,   228,   229,   229,   230,
-     230,   230,   230,   230,   230,   231,   231,   231,   231,   231,
-     231,   231,   231,   231,   231,   231,   231,   231,   231,   231,
-     231,   231,   231,   232,   232,   232,   232,   232,   232,   232,
-     232,   232,   232,   233,   233,   233,   234,   233,   235,   233,
-     236,   233,   237,   233,   233,   233,   233,   233,   233,   233,
-     233,   233,   233,   238,   233,   239,   233,   240,   233,   241,
-     233,   242,   233,   243,   233,   244,   233,   245,   233,   246,
-     233,   247,   247,   248,   248,   248,   248,   248,   248,   248,
-     248,   248,   248,   248,   248,   248,   248,   248,   249,   249,
-     250,   250,   251,   251,   252,   252,   253,   253,   253,   253,
-     253,   253,   253,   253,   253,   253,   253,   253,   253,   253,
-     253,   253,   253,   253,   253,   253,   253,   254,   254,   254,
-     255,   255,   255,   256,   256,   256,   256,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   258,   258,   258,   258,   258,   258,   258,   258,   258,
-     258,   258,   258,   258,   258,   258,   258,   258,   258,   258,
-     258,   258,   258,   259,   259,   259,   259,   259,   260,   260,
-     260,   260,   261,   261,   262,   262,   262,   262,   262,   262,
-     263,   263,   264,   264,   264,   264,   264,   264,   264,   264,
-     264,   264,   264,   264,   264,   264,   264,   264,   264,   264,
-     264,   264,   265,   265,   265,   265,   266,   266,   266,   266,
-     267,   267,   268,   268,   269,   269,   269,   269,   270,   270,
-     270,   270,   270,   270,   270,   270,   270,   270,   270,   270,
-     270,   270,   270,   271,   271,   272,   272,   273,   273
+       0,   187,   188,   188,   189,   189,   190,   190,   190,   190,
+     190,   190,   190,   190,   190,   190,   190,   190,   190,   190,
+     190,   191,   191,   192,   192,   192,   192,   192,   192,   193,
+     193,   193,   193,   194,   194,   194,   194,   194,   194,   195,
+     195,   196,   196,   198,   199,   197,   200,   200,   202,   201,
+     203,   203,   205,   204,   206,   206,   208,   207,   209,   209,
+     209,   209,   209,   210,   210,   211,   211,   212,   212,   213,
+     213,   213,   213,   213,   213,   213,   213,   213,   213,   213,
+     213,   213,   213,   213,   213,   213,   213,   213,   213,   213,
+     213,   213,   213,   213,   213,   213,   213,   213,   213,   213,
+     214,   214,   215,   215,   215,   216,   215,   215,   217,   215,
+     218,   218,   219,   219,   220,   220,   221,   221,   221,   222,
+     222,   223,   223,   223,   224,   224,   225,   225,   226,   226,
+     227,   228,   227,   227,   227,   227,   227,   227,   227,   227,
+     227,   227,   227,   227,   229,   227,   227,   227,   227,   227,
+     227,   227,   227,   227,   227,   227,   230,   227,   227,   227,
+     227,   231,   227,   232,   232,   232,   232,   232,   232,   232,
+     232,   233,   233,   234,   234,   234,   234,   234,   234,   235,
+     235,   235,   235,   235,   235,   235,   235,   235,   236,   236,
+     236,   236,   236,   237,   237,   238,   238,   238,   238,   238,
+     238,   239,   239,   239,   239,   239,   239,   239,   239,   239,
+     239,   239,   239,   239,   239,   239,   239,   239,   239,   240,
+     240,   240,   240,   240,   240,   240,   240,   240,   240,   241,
+     241,   241,   242,   241,   243,   241,   244,   241,   245,   241,
+     241,   241,   241,   241,   241,   241,   241,   241,   241,   246,
+     241,   247,   241,   248,   241,   249,   241,   250,   241,   251,
+     241,   252,   241,   253,   241,   254,   241,   255,   255,   256,
+     256,   256,   256,   256,   256,   256,   256,   256,   256,   256,
+     256,   256,   256,   256,   257,   257,   258,   258,   259,   259,
+     260,   260,   261,   261,   261,   261,   261,   261,   261,   261,
+     261,   261,   261,   261,   261,   261,   261,   261,   261,   261,
+     261,   261,   261,   262,   262,   262,   263,   263,   263,   264,
+     264,   264,   264,   265,   265,   265,   265,   265,   265,   265,
+     265,   265,   265,   265,   265,   265,   265,   265,   265,   265,
+     265,   265,   265,   265,   265,   265,   265,   265,   265,   265,
+     265,   265,   265,   265,   265,   265,   265,   265,   265,   265,
+     265,   265,   265,   265,   265,   266,   266,   266,   266,   266,
+     266,   266,   266,   266,   266,   267,   266,   266,   266,   266,
+     266,   266,   266,   266,   266,   266,   266,   266,   266,   266,
+     266,   266,   266,   266,   268,   268,   268,   268,   268,   269,
+     269,   269,   269,   270,   270,   271,   271,   271,   271,   271,
+     271,   272,   272,   273,   273,   273,   273,   273,   273,   273,
+     273,   273,   273,   273,   273,   273,   273,   273,   273,   273,
+     273,   274,   274,   274,   274,   275,   275,   275,   275,   276,
+     276,   277,   277,   278,   278,   278,   278,   279,   279,   279,
+     279,   279,   279,   279,   279,   279,   279,   279,   279,   280,
+     279,   281,   281,   282,   282,   283,   283
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -1347,48 +1357,47 @@ static const yytype_uint8 yyr2[] =
        6,     6,     8,     0,     2,     2,     2,     2,     2,     1,
        3,     1,     3,     0,     0,    10,     1,     3,     0,    13,
        1,     3,     0,    15,     8,    14,     0,     6,     1,     1,
-       1,     1,     1,     1,     1,     5,     5,     4,     6,     7,
-       7,     9,     9,     3,     6,     4,     6,     9,     6,     9,
-       5,     8,     8,    11,     6,     9,     5,     7,     9,     9,
-      11,     7,     9,     9,     0,     1,     0,     3,     5,     0,
-       9,     5,     0,     9,     0,     3,     3,     5,     0,     2,
-       3,     5,     3,     0,     2,     3,     3,     5,     1,     1,
-       0,     5,     0,     2,     7,     0,     9,     6,     7,     4,
-       7,     8,     8,     7,     7,    11,     8,     8,     0,     9,
-       8,     9,     3,     4,    10,     7,     7,     8,     8,    12,
-       0,     9,     8,     7,     8,     0,     9,     5,    11,     5,
-       9,     9,     4,     9,     9,     1,     1,     0,     2,     6,
-       6,     6,     6,     8,    10,    14,    16,    12,     8,     8,
-       6,    14,     4,     6,     6,     3,     4,     5,     6,     3,
-       3,     4,     5,     4,     5,     3,     7,     7,     3,     7,
-       3,     2,     2,     2,     2,    15,     2,     2,     2,     2,
-       2,    16,     3,     6,     8,     8,    10,     1,     2,     1,
-       3,     4,     1,     5,    11,    13,     0,     7,     0,    13,
-       0,    15,     0,     6,     8,     8,     8,    12,    12,    12,
-      14,    14,    14,     0,    12,     0,    12,     0,    12,     0,
-      16,     0,    16,     0,    16,     0,    18,     0,    18,     0,
-      18,     1,     2,     5,     7,     9,     2,     2,     2,     3,
-       2,     3,     2,     3,     2,     3,     9,     6,     0,     3,
-       0,     1,     0,     2,     0,     2,     7,     6,     8,     5,
-       3,     7,     5,     4,     6,     6,    12,    10,    10,    10,
-      10,    10,     4,     4,     4,     4,     4,     2,     3,     6,
-       1,     1,     1,     2,     5,     7,    10,     1,     3,     2,
-       2,     2,     3,     3,     3,     3,     3,     3,     3,     3,
-       3,     3,     3,     3,     3,     3,     5,     4,     4,     4,
-       4,     4,     4,     4,     4,     4,     4,     6,     4,     4,
-       4,     4,     4,     4,     4,     6,     6,     6,     4,     4,
-       4,     4,     4,     4,     4,     4,     4,     4,     4,     6,
-       4,     4,     4,     4,     4,     4,     4,     6,     6,     6,
-       4,     1,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     4,     4,     2,     5,     3,     6,     4,     7,     6,
-       6,     6,     4,     1,     2,     2,     3,     3,    11,     9,
-       7,     7,     1,     3,     1,     1,     2,     3,     4,     5,
-       1,     1,     2,     3,     3,     5,     4,     2,     2,     2,
-       2,     5,     5,     5,     5,     1,     1,     3,     3,     4,
-       6,     6,     1,     1,     3,     3,     9,     7,     1,     5,
-       3,     6,     1,     3,     1,     1,     3,     6,     1,     1,
-       4,     6,     6,     6,     4,     4,     8,     4,     4,     4,
-       4,     6,     6,     1,     3,     5,     5,     1,     1
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     5,
+       5,     4,     6,     7,     7,     7,     9,     9,     3,     6,
+       6,     4,     6,     9,     6,     9,     5,     8,     8,    11,
+       6,     9,     5,     7,     9,     9,    11,     7,     9,     9,
+       0,     1,     0,     3,     5,     0,     9,     5,     0,     9,
+       0,     3,     3,     5,     0,     2,     3,     5,     3,     0,
+       2,     3,     3,     5,     1,     1,     0,     5,     0,     2,
+       7,     0,     9,     6,     7,     4,     7,     8,     8,     7,
+       7,    11,     8,     8,     0,     9,     8,     9,     3,     4,
+      10,     7,     7,     8,     8,    12,     0,     9,     8,     7,
+       8,     0,     9,     5,    11,     5,     9,     9,     4,     9,
+       9,     1,     1,     0,     2,     6,     6,     6,     6,     8,
+      10,    14,    16,    12,     8,     8,     6,    14,     4,     6,
+       6,     3,     4,     5,     6,     3,     3,     4,     5,     4,
+       5,     3,     7,     7,     3,     7,     3,     2,     2,     2,
+       2,    15,     2,     2,     2,     2,     2,    16,     3,     6,
+       8,     8,    10,     1,     2,     1,     3,     4,     1,     5,
+      11,    13,     0,     7,     0,    13,     0,    15,     0,     6,
+       8,     8,     8,    12,    12,    12,    14,    14,    14,     0,
+      12,     0,    12,     0,    12,     0,    16,     0,    16,     0,
+      16,     0,    18,     0,    18,     0,    18,     1,     2,     5,
+       7,     9,     2,     2,     2,     3,     2,     3,     2,     3,
+       2,     3,     9,     6,     0,     3,     0,     1,     0,     2,
+       0,     2,     7,     6,     8,     5,     3,     7,     5,     4,
+       6,     6,    12,    10,    10,    10,    10,    10,     4,     4,
+       4,     4,     4,     2,     3,     6,     1,     1,     1,     2,
+       5,     7,    10,     1,     3,     2,     2,     2,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
+       3,     3,     5,     4,     4,     4,     4,     4,     4,     4,
+       4,     4,     4,     6,     4,     4,     4,     4,     4,     4,
+       4,     6,     6,     6,     4,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     0,     6,     1,     4,     4,
+       4,     4,     4,     2,     5,     5,     3,     6,     4,     7,
+       6,     6,     6,     4,     1,     2,     2,     3,     3,    11,
+       9,     7,     7,     1,     3,     1,     1,     2,     3,     4,
+       5,     1,     1,     2,     3,     3,     5,     4,     2,     2,
+       2,     2,     5,     5,     5,     5,     1,     1,     3,     4,
+       6,     1,     1,     3,     3,     9,     7,     1,     5,     3,
+       6,     1,     3,     1,     1,     3,     6,     1,     1,     1,
+       4,     6,     6,     4,     4,     8,     4,     4,     6,     0,
+       6,     1,     3,     5,     5,     1,     1
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -1396,2297 +1405,2156 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint16 yydefact[] =
 {
-       0,     0,     0,     2,     3,     1,   477,     0,     0,     0,
+       0,     0,     0,     2,     3,     1,   465,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   217,     0,
-     222,     0,     0,     0,   219,     0,     0,     0,     0,   310,
-     311,   312,     0,     5,     7,     6,     8,     9,    10,    19,
+       0,     0,     0,     0,     0,     0,     0,     0,   223,     0,
+     228,     0,     0,     0,   225,     0,     0,     0,     0,   316,
+     317,   318,     0,     5,     7,     6,     8,     9,    10,    19,
       11,    12,    13,    18,    17,    14,    15,    16,     0,    20,
-     478,     0,   381,   477,   458,   382,   383,   384,     0,     0,
+     466,     0,   365,   465,   447,   366,   367,   368,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,   459,
-     388,   389,     0,     0,     0,     0,   385,   386,   387,     0,
-       0,     0,     0,     0,     0,     0,   167,     0,     0,   317,
-       0,   454,   390,     0,     0,     0,     0,   204,     0,   206,
-     207,   203,   208,   209,    96,   104,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   448,
+     449,   372,   373,   374,     0,     0,     0,     0,     0,     0,
+       0,     0,   369,   370,   371,     0,     0,     0,    65,    66,
+       0,     0,   173,     0,     0,     0,   323,     0,   443,   466,
+     377,     0,     0,     0,     0,   210,     0,   212,   213,   209,
+     214,   215,   102,   110,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   210,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   125,   138,   150,   155,     0,     0,     0,
+     216,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   131,   144,   156,   161,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   403,     0,     0,     0,     0,     0,   167,
+       0,   394,     0,     0,     0,     0,     0,   173,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   173,
+       0,   313,     0,     0,     0,     0,     0,     0,     0,     0,
+     465,   412,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   426,   427,   405,   411,     0,   406,   377,     0,     0,
+       0,     0,   437,     0,     0,     0,     0,     0,   207,   208,
+       0,     0,   224,     0,   173,     0,   173,   465,     0,   319,
+       0,     0,     0,     0,     0,    58,    62,    61,    60,    59,
+      64,    63,     0,     0,     0,     0,     0,    65,    66,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,   167,     0,   307,     0,     0,     0,     0,     0,     0,
-       0,     0,   477,   421,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   435,   436,   414,   420,     0,   415,   390,
-       0,     0,     0,     0,   448,     0,     0,     0,     0,     0,
-     201,   202,     0,     0,   218,     0,   167,     0,   167,   477,
-       0,   313,     0,     0,     0,    58,    62,    61,    60,    59,
-      64,    63,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   326,   325,
+     327,     0,     0,     0,     0,     0,     0,   465,   466,     0,
+       0,   172,     0,   171,     0,     0,   204,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    33,   201,     0,   383,   148,     0,   465,     0,
+     443,   444,     0,     0,   100,   100,     0,     0,   431,   432,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   320,   319,   321,
+       0,     0,   288,   288,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   173,   173,     0,
+     396,   395,     0,     0,     0,     0,   173,   173,     0,     0,
+       0,     0,     0,     0,     0,   238,     0,   173,     0,     0,
+       0,     0,     0,   290,     0,     0,     0,     0,   191,     0,
+       0,     0,   314,     0,     0,     0,     0,     0,     0,     0,
+       0,    66,     0,     0,     0,   418,     0,   419,   420,   421,
+       0,     0,     0,     0,     0,   325,   413,     0,   407,     0,
+       0,     0,   296,   206,     0,     0,     0,     0,     0,   173,
+       0,     0,     0,     0,   226,   195,     0,   196,     0,     0,
+     218,     0,     0,     0,     0,     0,     0,     0,    78,     0,
+       0,   386,     0,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     166,     0,   165,     0,   198,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   461,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   375,   459,     0,     0,     0,     0,
+       0,     0,   324,    58,     0,     0,    58,     0,     0,     0,
+       0,     0,   168,     0,     0,     0,     0,   174,     0,     0,
+       0,   341,   340,   339,   338,   334,   335,   337,   336,   329,
+     328,   330,   331,   332,   333,     0,     0,   149,     0,     0,
+       0,     0,     0,     0,     0,     0,   101,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-      33,   195,   393,   142,     0,   477,     0,   454,   455,     0,
-       0,    94,    94,     0,     0,   442,   443,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   310,
+     311,   312,     0,     0,     0,     0,   286,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   135,
+     173,     0,     0,     0,     0,     0,   398,   397,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   232,     0,     0,
+       0,     0,     0,     0,     0,   299,     0,     0,   192,     0,
+       0,   188,     0,     0,     0,   309,   308,     0,     0,     0,
+       0,   386,    67,    68,     0,   428,     0,     0,     0,     0,
+       0,     0,     0,   324,   408,   415,     0,   330,   414,     0,
+       0,     0,     0,     0,     0,     0,     0,   227,     0,   197,
+     199,     0,     0,     0,     0,     0,     0,    81,    71,     0,
+     378,   388,   343,   344,   345,   346,   347,   348,   349,   350,
+     351,   364,   352,     0,   354,   355,   356,   357,   358,   359,
+     360,     0,     0,     0,     0,   456,     0,   457,     0,   453,
+     454,     0,     0,     0,   393,   114,   119,    92,     0,   450,
+       0,   380,   381,     0,     0,     0,     0,     0,     0,     0,
+      86,     0,     0,     0,     0,   382,     0,     0,     0,     0,
+     463,     0,     0,    43,     0,     0,     0,    56,     0,    34,
+      35,    36,    37,    38,   379,     0,   445,    23,    21,     0,
+       0,    24,     0,     0,    69,   103,    70,   111,     0,   433,
+     434,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   284,
+     289,   287,     0,   295,     0,     0,   124,   125,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   198,   200,
+       0,     0,     0,   163,   165,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,   282,
-     282,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   167,   167,     0,   405,   404,     0,
-       0,     0,     0,   167,   167,     0,     0,     0,     0,     0,
-       0,     0,   232,     0,   167,     0,     0,     0,     0,     0,
-     284,     0,     0,     0,     0,   185,     0,     0,     0,   308,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   427,     0,   428,   429,   430,     0,     0,     0,
-       0,     0,   319,   422,     0,   416,     0,     0,     0,   290,
-     200,     0,     0,     0,     0,     0,   167,     0,     0,     0,
-       0,   220,   189,     0,   190,     0,     0,   212,     0,     0,
-       0,     0,     0,    73,     0,     0,   395,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,   473,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,   318,
-      58,     0,     0,     0,    58,     0,     0,     0,     0,     0,
-     162,     0,     0,     0,     0,   168,     0,     0,   335,   334,
-     333,   332,   328,   329,   331,   330,   323,   322,   324,   325,
-     326,   327,     0,   143,     0,     0,     0,     0,     0,     0,
-       0,     0,    95,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   304,   305,   306,     0,     0,
-       0,     0,   280,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   129,   167,     0,     0,     0,
-       0,     0,   407,   406,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   226,     0,     0,     0,     0,     0,     0,
-       0,   293,     0,     0,   186,     0,     0,   182,     0,     0,
-       0,   303,   302,     0,     0,     0,   438,     0,   437,     0,
-       0,   395,     0,     0,     0,     0,     0,     0,     0,   318,
-     417,   424,     0,   324,   423,     0,     0,     0,     0,     0,
-       0,     0,     0,   221,     0,   191,   193,     0,     0,     0,
-       0,    75,    67,     0,   391,   397,   337,   359,   338,   360,
-     339,   361,   340,   362,   341,   363,   342,   364,   343,   365,
-     344,   366,   345,   367,   358,   380,   346,   368,     0,     0,
-     348,   370,   349,   371,   350,   372,   351,   373,   352,   374,
-     353,   375,   354,   376,     0,     0,     0,     0,     0,     0,
-     467,     0,   468,   469,     0,   470,     0,     0,     0,   464,
-     465,     0,     0,     0,   402,    86,     0,   460,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    80,     0,
-       0,     0,     0,   392,     0,     0,     0,     0,   475,     0,
-      43,     0,     0,     0,    56,     0,    34,    35,    36,    37,
-      38,     0,   456,    23,    21,     0,     0,    24,     0,     0,
-      65,   477,    97,    66,   105,     0,   444,   445,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   278,   283,   281,     0,
-     289,     0,     0,   118,   119,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   192,   194,     0,     0,     0,
-     157,   159,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   261,     0,   223,
-       0,     0,     0,     0,     0,     0,   285,   292,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     391,   439,   426,     0,     0,     0,     0,   418,     0,     0,
-       0,     0,     0,     0,     0,   187,     0,     0,     0,     0,
-       0,     0,   314,   476,     0,     0,   394,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   474,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    68,     0,
-       0,     0,     0,     0,    74,    76,    78,     0,     0,   452,
-       0,    84,     0,     0,     0,     0,   336,     0,     0,     0,
-       0,     0,    29,     0,    22,     0,     0,     0,     0,     0,
-       0,     0,     0,   122,   122,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   127,     0,     0,     0,     0,
-       0,     0,     0,   287,     0,     0,     0,     0,     0,     0,
-       0,     0,   295,     0,     0,   188,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   267,     0,   266,     0,   272,
-       0,   274,     0,   268,     0,   270,     0,   233,   262,     0,
-       0,     0,   180,     0,     0,     0,   294,     0,   184,   183,
-     309,     0,     0,    30,    31,     0,     0,     0,     0,   431,
-     432,   433,   434,   425,   419,     0,     0,     0,   449,     0,
-       0,     0,   213,     0,     0,     0,     0,   197,   396,   196,
-     347,   369,   355,   377,   356,   378,   357,   379,   471,   472,
-     462,   463,     0,   400,   401,   399,   461,     0,    70,     0,
-      58,     0,     0,     0,     0,    69,     0,     0,     0,   450,
-       0,     0,     0,     0,     0,     0,     0,     0,   412,     0,
-       0,    25,    26,     0,    27,     0,     0,    98,   101,   124,
-       0,     0,     0,     0,     0,     0,   128,     0,     0,   145,
-     146,     0,     0,   130,   153,     0,     0,     0,     0,   120,
-       0,   286,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,   199,     0,     0,     0,     0,   167,   167,     0,   243,
-       0,   245,     0,   247,     0,   414,     0,     0,   273,   275,
-     269,   271,     0,     0,   227,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   291,     0,   441,   440,   396,   133,
-     134,     0,     0,     0,     0,    87,    91,     0,     0,   315,
-     398,     0,     0,     0,     0,     0,    81,     0,     0,    82,
-       0,   453,   169,   170,   171,   172,     0,    39,     0,     0,
-       0,     0,     0,    41,   457,     0,     0,    99,   102,     0,
-       0,   123,   131,   132,   136,     0,     0,   147,     0,     0,
-     288,     0,   140,     0,     0,   279,   152,     0,     0,     0,
-       0,   137,     0,   148,   154,     0,     0,     0,     0,   411,
-       0,   410,     0,     0,     0,   234,     0,     0,   235,     0,
-       0,   236,     0,     0,     0,     0,     0,     0,     0,   179,
-       0,     0,   178,     0,     0,     0,   173,     0,     0,    32,
-       0,     0,   447,     0,   215,   214,     0,     0,     0,     0,
-     466,    72,    71,    77,    79,     0,    85,     0,    44,     0,
-       0,     0,   413,     0,     0,     0,    28,     0,   108,   113,
-       0,     0,     0,     0,     0,     0,     0,     0,   141,   126,
-     139,   151,   156,     0,     0,    92,    93,   167,     0,   160,
-     161,     0,     0,     0,     0,     0,     0,     0,   263,     0,
-       0,   167,     0,     0,     0,     0,     0,   164,   163,     0,
-       0,     0,     0,    88,    89,     0,     0,   451,     0,    40,
-       0,     0,     0,    42,    57,     0,     0,     0,   297,   299,
-     298,   300,   301,   144,     0,     0,     0,     0,     0,     0,
-     409,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-     277,     0,     0,     0,   228,     0,     0,   174,     0,     0,
-       0,   446,   216,     0,   316,    83,     0,     0,     0,     0,
-       0,     0,   100,   109,     0,   103,   114,     0,     0,     0,
-       0,   158,     0,   249,     0,     0,   251,     0,     0,   253,
-       0,     0,     0,   264,     0,   224,     0,   167,     0,     0,
-       0,   135,    90,     0,    48,     0,    54,     0,     0,     0,
-       0,     0,   121,   149,   296,   408,   237,     0,     0,   244,
-     238,     0,     0,   246,   239,     0,     0,   248,     0,     0,
-       0,   230,     0,   177,     0,     0,     0,     0,     0,     0,
-       0,     0,   110,   112,     0,   115,   116,     0,     0,   255,
-       0,   257,     0,   259,   265,   276,   229,   225,     0,     0,
-       0,     0,    45,     0,    52,     0,     0,     0,   442,     0,
-       0,     0,   240,     0,     0,   241,     0,     0,   242,     0,
-       0,   181,     0,   175,     0,    46,     0,     0,   205,     0,
-     111,     0,   117,     0,     0,     0,     0,     0,     0,     0,
-     231,     0,     0,     0,     0,     0,     0,   106,   211,   250,
-       0,   252,     0,   254,     0,   176,    47,    49,     0,    50,
-       0,     0,     0,     0,     0,     0,     0,    55,   107,   256,
-     258,   260,    51,    53
+     267,     0,   229,     0,     0,     0,     0,     0,     0,   291,
+     298,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   378,     0,   429,   417,     0,     0,     0,     0,   409,
+       0,     0,     0,     0,     0,     0,     0,   193,     0,     0,
+       0,     0,     0,     0,   320,     0,     0,     0,   464,     0,
+       0,   384,     0,     0,     0,     0,     0,   462,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    72,     0,
+       0,     0,     0,    79,    82,    84,     0,     0,   441,     0,
+      90,     0,     0,     0,     0,     0,   342,     0,     0,     0,
+       0,     0,    29,   385,     0,    22,     0,     0,     0,     0,
+       0,     0,     0,     0,   128,   128,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   133,     0,     0,     0,
+       0,     0,     0,     0,   293,     0,     0,     0,     0,     0,
+       0,     0,     0,   301,     0,     0,   194,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   273,     0,   272,     0,
+     278,     0,   280,     0,   274,     0,   276,     0,   239,   268,
+       0,     0,     0,   186,     0,     0,     0,   300,     0,   190,
+     189,   315,     0,     0,    30,    31,     0,     0,     0,   422,
+     423,   424,   425,   416,   410,     0,     0,     0,   438,     0,
+       0,     0,   219,     0,     0,     0,     0,     0,     0,    80,
+     203,   387,   202,   353,   361,   362,   363,   458,   452,     0,
+     391,   392,     0,   376,   115,     0,   460,   120,   390,   451,
+      74,    58,     0,     0,     0,     0,    73,     0,     0,     0,
+     439,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     403,     0,     0,    25,    26,     0,    27,     0,     0,   104,
+     107,   130,     0,     0,     0,     0,     0,     0,   134,     0,
+       0,   151,   152,     0,     0,   136,   159,     0,     0,     0,
+       0,   126,     0,   292,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   205,     0,     0,     0,     0,   173,   173,
+       0,   249,     0,   251,     0,   253,     0,   405,     0,     0,
+     279,   281,   275,   277,     0,     0,   233,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   297,     0,   387,   430,
+     139,   140,     0,     0,     0,     0,    93,    97,     0,     0,
+     321,     0,    75,   389,     0,     0,     0,     0,     0,    87,
+       0,     0,    88,     0,   442,   175,   176,   177,   178,     0,
+       0,    39,     0,     0,     0,     0,     0,    41,   446,     0,
+       0,   105,   108,     0,     0,   129,   137,   138,   142,     0,
+       0,   153,     0,     0,   294,     0,   146,     0,     0,   285,
+     158,     0,     0,     0,     0,   143,     0,   154,   160,     0,
+       0,     0,     0,   402,     0,   401,     0,     0,     0,   240,
+       0,     0,   241,     0,     0,   242,     0,     0,     0,     0,
+       0,     0,     0,   185,     0,     0,   184,     0,     0,     0,
+     179,     0,     0,    32,     0,     0,   436,     0,   221,   220,
+       0,     0,     0,     0,     0,   455,     0,   116,   118,     0,
+     121,   122,    83,    85,     0,    91,     0,    76,    44,     0,
+       0,     0,   404,     0,     0,     0,    28,     0,   114,   119,
+       0,     0,     0,     0,     0,     0,     0,     0,   147,   132,
+     145,   157,   162,     0,     0,    98,    99,   173,     0,   166,
+     167,     0,     0,     0,     0,     0,     0,     0,   269,     0,
+       0,   173,     0,     0,     0,     0,     0,   170,   169,     0,
+       0,     0,     0,    94,    95,     0,    77,     0,   431,     0,
+       0,   440,     0,    40,     0,     0,     0,    42,    57,     0,
+       0,     0,   303,   305,   304,   306,   307,   150,     0,     0,
+       0,     0,     0,     0,   400,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   283,     0,     0,     0,   234,     0,
+       0,   180,     0,     0,     0,   435,   222,     0,   322,     0,
+     117,     0,   123,    89,     0,     0,     0,     0,     0,   106,
+     109,     0,     0,     0,     0,   164,     0,   255,     0,     0,
+     257,     0,     0,   259,     0,     0,     0,   270,     0,   230,
+       0,   173,     0,     0,     0,   141,    96,     0,   112,     0,
+      48,     0,    54,     0,     0,     0,   127,   155,   302,   399,
+     243,     0,     0,   250,   244,     0,     0,   252,   245,     0,
+       0,   254,     0,     0,     0,   236,     0,   183,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   261,     0,
+     263,     0,   265,   271,   282,   235,   231,     0,     0,     0,
+       0,   113,    45,     0,    52,     0,     0,     0,     0,   246,
+       0,     0,   247,     0,     0,   248,     0,     0,   187,     0,
+     181,     0,    46,     0,     0,   211,     0,     0,     0,     0,
+       0,     0,     0,   237,     0,     0,     0,     0,     0,   217,
+     256,     0,   258,     0,   260,     0,   182,    47,    49,     0,
+      50,     0,     0,     0,     0,     0,     0,    55,   262,   264,
+     266,    51,    53
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     2,     3,    83,   875,    84,    85,   642,  1296,  1302,
-     866,  1037,  1448,  1614,   867,  1567,  1648,   868,  1616,   869,
-     870,  1041,   302,   402,    86,   653,   411,  1398,  1399,   412,
-    1597,  1456,  1503,  1457,  1506,   912,  1324,  1203,   625,   442,
-     443,   444,   445,   263,   381,   382,    89,    90,    91,    92,
-      93,    94,   264,   950,  1526,  1588,   711,  1346,  1349,  1352,
-    1547,  1551,  1555,  1603,  1606,  1609,   946,   947,  1072,   909,
-     682,   720,    96,    97,    98,    99,   265,   159,   458,   223,
-    1187,   266,   267,   268,   516,   276,   852,  1030,   591,   407,
-     592,   100,   269
+      -1,     2,     3,    83,   829,    84,    85,   615,  1250,  1256,
+     819,   987,  1412,  1571,   820,  1532,  1599,   821,  1573,   822,
+     823,   991,   312,   395,   164,   715,    86,   627,   404,  1358,
+    1359,   405,  1407,   963,  1114,   964,  1117,   865,  1278,  1155,
+     597,   435,   436,   437,   438,   271,   372,   373,    89,    90,
+      91,    92,    93,    94,   272,   903,  1490,  1547,   685,  1300,
+    1303,  1306,  1511,  1515,  1519,  1560,  1563,  1566,   899,   900,
+    1023,   862,   656,   694,    96,    97,    98,    99,   273,   166,
+     785,   451,   231,  1139,   274,   275,   276,   509,   284,   804,
+     979,   564,   400,   786,   565,   169,   277
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -1244
+#define YYPACT_NINF -1191
 static const yytype_int16 yypact[] =
 {
-    4700,    52,   108,  4809, -1244, -1244,   101,   138,   -55,     0,
-      12,    26,   185,   212,   217,   316,   332,    79,   109,  -140,
-     224,   233,    16,   290,   296,    18,   304,   340,   448,   466,
-     485,   610,   454,   563,   582,   592,   347,   606,   609,   408,
-      37,   520,   636,   -67,   543,    88,    88,   554,   162,   265,
-     -16,   670,   666,     6,    47,   674,   675,   276,   729,   738,
-     742,  2755,   749,   586,   596,   601,    19,    22, -1244,   602,
-   -1244,   757,   772,   613, -1244,   775,   778,    23,    24, -1244,
-   -1244, -1244,  4072, -1244, -1244, -1244, -1244, -1244, -1244, -1244,
-   -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244,    29, -1244,
-     603,    87, -1244,     5, -1244, -1244, -1244, -1244,   -94,   -34,
-      56,   100,   321,   360,   379,   437,   536,   537,   549,   557,
-     583,   591,   616,   635,   638,   660,   663,   679,   693,   697,
-     700,   704,   707,   619,   623,   639,   643,   648,   649, -1244,
-   -1244, -1244,   830,   655,   669,   676, -1244, -1244, -1244,  4072,
-    4072,  4072,  3767,  1945,    44,   837,   209,   689,   859, -1244,
-     696,   878,  -102,   887,  4072,   818,   818, -1244,  4072, -1244,
-   -1244, -1244, -1244, -1244, -1244, -1244,  4072,  3982,  4072,  4072,
-     723,  4072,  3982,  4072,  4072,   746,  3982,  4072,  4072,  2949,
-     759,   764, -1244,  3982,  2755,  2755,  2755,   776,   788,  2755,
-    2755,  2755,   797, -1244, -1244, -1244, -1244,   805,   806,   834,
-    2949,  4072,   896,  2949,    19,   768,   811,    88,    88,    88,
-    4072,  4072,    -6, -1244,   122,    88,   812,   847,   864,  3812,
-     124,   -98,   877,   881,   902,  2755,  2755,  2949,   906,    39,
-     835, -1244,  1037, -1244,   900,   923,   963,  2755,  2755,   880,
-     909,   913,   322, -1244,   925,    25,  1085,  1116,  1132,   785,
-    3046,  4072,  2313, -1244, -1244,   384, -1244,  1140, -1244,   137,
-    1143,  4072,  4072,  4072,   982,  4072,   994,  1053,  4072,  4072,
-   -1244, -1244,  4072,  1182, -1244,  1186, -1244,  1188, -1244,    46,
-    1403, -1244,  2949,  2949,  1017,   940, -1244, -1244, -1244, -1244,
-   -1244, -1244,  2949,  1190,  1024,  4072,  1195,  4072,  4072,  4072,
-    4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,
-    4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,
-    4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,
-    4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,
-    4072,   818,   818,   818,   818,   818,   818,   818,   818,   818,
-     818,   818,   818,  4072,   818,   818,   818,  1028,  1028,  1028,
-    3982,  7318,    94,  3982,  6513,   294,  1025,  1196,  1029,  1023,
-   -1244,  1026,  4898,  4072, -1244,  4072,  4072,  4072,  4072,  4072,
-    4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,  4072,
-   -1244, -1244, -1244, -1244,  1781,    95,   234, -1244, -1244,   256,
-    5759,   -86,   240,  7339,  3982,  4451, -1244,    81,  7360,  7381,
-    4072,  7402,   702,  7423,  7444,  4072,   706,  7465,  7486,  1202,
-    4072,  4072,   722,  1204,  1205,  1207,  4072,  4072,  1209,  1210,
-    1210,  4072,  1043,  1047,  1048,  1049,  4072,  4072,  4072,  1214,
-    5679,  1050,  1217,  1052, -1244, -1244,   -63, -1244, -1244,  5785,
-    5811,    88,    88,   209,   209,    53,  4072,  4072,  4072,  3812,
-    3812,  4072,  4898,   103, -1244,  4072,  4072,  4072,  4072,  4072,
-    1218,  1226,  1221,  4072,  1228, -1244,  4072,  4072,   736, -1244,
-    3982,  3982,  3982,  1229,  1230,  4072,  4072,  4072,  -110,  2539,
-    1235,  1236, -1244,  4072, -1244, -1244, -1244,  1066,  1070,  1071,
-    1074,  3982,  1028, -1244,  7507, -1244,   733,  4072,  3143, -1244,
-   -1244,  7528,  7549,  7570,  1118,  5837, -1244,  1075,  4470,  7591,
-    6536, -1244, -1244,  1063, -1244,  1194,  4072, -1244,  1073,   734,
-    4072,  1237,  1258, -1244,  4072,  6559,   168,  7612,  6582,  7633,
-    6605,  7654,  6628,  7675,  6651,  7696,  6674,  7717,  6697,  7738,
-    6720,  7759,  6743,  7780,  6766,  7801,  6789,  7822,  6812,  5863,
-    5889,  7843,  6835,  7864,  6858,  7885,  6881,  7906,  6904,  7927,
-    6927,  7948,  6950,  7969,  6973,  5915,  5941,  5967,  5993,  6019,
-    6045, -1244,   352,   451,   477,   493,  1089,  1090,  1096,  1097,
-    1100,  1101,  1103,   484,  1869,  1104,  1110,  1106,   737,    94,
-   -1244,  2949,   741,   271,   940,  4072,  1278,  1281,    20,  1114,
-   -1244,   -69,    17,    21,     8, -1244,  4923,  4489,  1689,  1761,
-     875,   875,   726,   726,   726,   726,   449,   449,  1028,  1028,
-    1028,  1028,    45, -1244,  4072,  1285,    34,  3982,  1284,  3982,
-    4072,  1286, -1244,  1287,  1288,   818,  1291,  3982,  3982,  1167,
-    1292,  1293,  7990,  1294,  1169,  1295,  1296,  8011,  1180,  1300,
-    1301,  4072,  8032,  4951,  1131, -1244, -1244, -1244,  8053,  8074,
-    4072,  2949,  1306,  1305,  8095,  4146,  4146,  4146,  4146,  8116,
-    8137,  8158,  2949,  3982,  1141, -1244, -1244,  1315,  2401,    88,
-    4072,  4072, -1244, -1244,  1138,  1139,  3812,  6071,  6097,  6123,
-    5733,   948,    88,  3386,  8179,  4979,  8200,  8221,  8242,  4072,
-    1313, -1244,  4072,  8263, -1244,  6996,  7019, -1244,   744,   745,
-     752, -1244, -1244,  7042,  7065,  6149, -1244,  3982, -1244,  3982,
-    7088,   137,  1146,  5007,  3982,  3982,  3982,  3982,   760, -1244,
-   -1244,  4514,  3982,  1028, -1244,  1314,  1319,  1326,  1147,  4072,
-    4191,  4072,  4072, -1244,    -2, -1244, -1244,  1159,  2949,  1332,
-    5035, -1244, -1244,  7111,    42, -1244, -1244, -1244, -1244, -1244,
-   -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244,
-   -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244,  4072,  4072,
-   -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244,
-   -1244, -1244, -1244, -1244,  4072,  4072,  4072,  4072,  4072,  4072,
-   -1244,   818, -1244, -1244,  3982, -1244,  3982,   818,   818, -1244,
-   -1244,   818,   818,   818, -1244, -1244,  4072, -1244,   818,  1171,
-    4072,  1333,  1173,    51,  4072,  1335,  1342,  1893, -1244,  1343,
-    1178,    19,  1347, -1244,  3982,  3982,  3982,  3982, -1244,  4072,
-   -1244,  1183,  1192,  1181, -1244,  1358, -1244, -1244, -1244, -1244,
-   -1244,  7134, -1244, -1244,  1212,   818,   499, -1244,   515,  6175,
-   -1244,  1191,  1365, -1244, -1244,    88,  4451, -1244,   872,  2949,
-    2949,  1367,  2949,   884,  2949,  2949,  1378,  1322,  2949,  2949,
-    2079,  1386,  1390,  3982,  1391,  1392,  4833, -1244, -1244,  1396,
-   -1244,  1397,  1231,  8494, -1244,  1233,  1234,  1238,  1400,  1401,
-    1404,  1407,   774,  1411,  4265, -1244, -1244,   166,  6201,  6227,
-   -1244, -1244,  5063,   -66,    88,    88,    88,  1413,  1414,  1243,
-    1416,  1255,    38,    54,    55,    58,   667, -1244,   170, -1244,
-     948,  1422,  1424,  1429,  1432,  1433,  8494, -1244,  2098,  1253,
-    1435,  1436,  1437,  1379,  4072,  1440,  1444,  4072,   783,   786,
-     120, -1244, -1244,   787,   792,   795,   796, -1244,  4072,   809,
-    2949,  2949,  2949,  1447,  6253, -1244,  4533,   326,  1448,  1449,
-    2949,  1275, -1244, -1244,  1452,  1455, -1244,  1456,  8284,  7157,
-    8305,  7180,  8326,  7203,  8347,  7226, -1244,   516,   524,  1289,
-    1290,  1302,  1297,  1298,  8368,  1309,    94,  2283, -1244,    94,
-     366,  1307,  1476,  2344, -1244, -1244, -1244,    19,  4072, -1244,
-     819, -1244,   820,   824,   825,   849,  8494,  1316,  4072,  4072,
-    2949,  1308, -1244,  1310, -1244,  1457,    48,  1478,  4072,  3507,
-      28,  1311,  1312,  1412,  1412,  2949,  1485,  1317,  1321,  1487,
-    1494,  2949,  1323,  1496,  1497, -1244,  1492,  2949,   882,  2949,
-    2949,  1501,  1500, -1244,  2949,  1503,  1505,  1506,  1507,  2949,
-    2949,  2949, -1244,  1508,   442, -1244,  4072,  4072,  4072,  1329,
-    1338,  -120,   -90,   -87,  1344, -1244,  2949, -1244,  4072, -1244,
-    1512, -1244,  1513, -1244,  1514, -1244,  1516, -1244, -1244,  3812,
-    1067,  2852, -1244,  1345,  1346,  3240, -1244,  3982, -1244, -1244,
-   -1244,  1348,  3714, -1244, -1244,  7249,  1355,  1354,  1525, -1244,
-   -1244, -1244, -1244,  8494, -1244,  1524,  1526,  1409, -1244,  4072,
-    4072,  4072, -1244,  1531,   498,  1361,  1533, -1244,   269, -1244,
-   -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244,
-   -1244, -1244,   818, -1244, -1244, -1244, -1244,  2949, -1244,  2949,
-     940,  4072,  1534,  1537,    20, -1244,  1536,  7272,    19, -1244,
-    1538,  1539,  1542,  1543,  4072,  6279,  6305,   891, -1244,  4072,
-    1546, -1244, -1244,   818, -1244,  6331,  4146,  8494, -1244, -1244,
-    4072,  4072,    88,  1545,  1547,  1563, -1244,  4072,  4072, -1244,
-   -1244,  1564,  4072, -1244, -1244,  1567,  1569,  1374,  1570,  1453,
-    4072, -1244,  1572,  2949,  2949,  2949,  2949,  1574,  1065,  1575,
-    4072, -1244,  4146,  5091,  8389,  4562,   209,   209,    88,  1576,
-      88,  1577,    88,  1580,  4072,   156,  1410,  8410, -1244, -1244,
-   -1244, -1244,  5119,   183, -1244,  1583,  2131,  1585,  2949,    88,
-    2131,  1589,   904,  4072, -1244,  1590, -1244, -1244,   137, -1244,
-   -1244,  2949,  4867,   226,  8431, -1244, -1244,  3552,  2949, -1244,
-   -1244,  1425,  1596,  1597,  1599,  3733, -1244,  1600,  1603, -1244,
-    1438, -1244, -1244, -1244, -1244, -1244,   528,  8494,  4072,  4072,
-    2949,  1434,   908,  8494, -1244,  1604,  4072,  8494, -1244,  5147,
-    5175,   551, -1244, -1244, -1244,  5203,  5231, -1244,  5259,  1606,
-   -1244,  2949, -1244,  1550,  1609,  8494, -1244,  1611,  1612,  1614,
-    1616, -1244,  1445, -1244, -1244,  5706,  4234,  1619,  1450, -1244,
-    4072, -1244,  1451,  1454,   232, -1244,  1458,   241, -1244,  1460,
-     246, -1244,  1461,  7295,  1620,  2949,  1628,  1462,  4072, -1244,
-    3337,   289, -1244,   912,   293,   295, -1244,  1621,  5287, -1244,
-    1520,  4072, -1244,  4072, -1244, -1244,  3982,  4293,  1638,  1468,
-   -1244, -1244, -1244, -1244, -1244,    19, -1244,  1527, -1244,  4072,
-    6357,  6383, -1244,  2949,  4072,  1642, -1244,  6409, -1244, -1244,
-    1643,  1644,  1651,  1652,  1653,  1654,   916,  1483, -1244, -1244,
-   -1244, -1244, -1244,  2949,  3982, -1244, -1244,   209,  4895, -1244,
-   -1244,  3812,   948,  3812,   948,  3812,   948,  1657, -1244,   917,
-    2949, -1244,  5315,    88,  1658,  3982,    88, -1244, -1244,  4072,
-    5343,  5371,   920, -1244, -1244,  1659,  1661, -1244,  1490,  8494,
-    4072,  4072,   929,  8494, -1244,  4072,   934,   935, -1244, -1244,
-   -1244, -1244, -1244, -1244,  1498,  4072,   938,   939,  1477,  4072,
-   -1244,  5399,   345,  1222,  5427,   351,  1259,  5455,   438,  1364,
-   -1244,  2949,  1666,  1592,  4292,  1499,   440, -1244,   943,   443,
-    4329, -1244, -1244,  1673, -1244, -1244,  4072,  8452,  6435,    27,
-    6461,  1676, -1244, -1244,  1678, -1244, -1244,  4072,  5483,  1679,
-    1680, -1244,  5511,  1682,  4072,  1683,  1684,  4072,  1685,  1686,
-    4072,  1687,  1515, -1244,  4072, -1244,   948, -1244,  3982,  1690,
-    3337, -1244, -1244,   956, -1244,  4072, -1244,  2949,  4072,  2585,
-    3597,  6487, -1244, -1244, -1244, -1244, -1244,  1517,  5539, -1244,
-   -1244,  1519,  5567, -1244, -1244,  1522,  5595, -1244,  1695,  4356,
-    1491,  4354,   959, -1244,   445,   968,  1696,  1530,  8473,   975,
-    5623,  2313, -1244, -1244,   818,  8494, -1244,  4072,   948,  1698,
-     948,  1699,   948,  1704, -1244, -1244, -1244, -1244,   948,  1708,
-    3982,  1712, -1244,   818, -1244,  1541,  1714,   976,  4393,   979,
-    5651,  1650, -1244,  1548,  1725, -1244,  1549,  1900, -1244,  1556,
-    2105, -1244,   984, -1244,   987, -1244,  1557,  2949, -1244,  4072,
-   -1244,   940, -1244,  1715,  1717,   948,  1719,   948,  1722,   948,
-   -1244,  1730,   818,  1732,   818,  1007,  4417, -1244, -1244, -1244,
-    2211, -1244,  2559, -1244,  2619, -1244, -1244, -1244,  1010, -1244,
-    1733,   940,  1734,  1735,  1736,   818,  1739, -1244, -1244, -1244,
-   -1244, -1244, -1244, -1244
+    5150,    28,    47,  5263, -1191, -1191,  2575,    11,     6,   -81,
+     -47,    26,   142,   178,   188,   223,   241,    91,   108,  -149,
+     156,   209,     1,   233,   255,    15,   268,   271,   240,   267,
+     324,   455,   287,   476,   410,   465,    48,   490,   364,   535,
+      61,   403,   533,   100,   432,   101,   101,   447,   -18,    46,
+     -10,   587,   605,     9,    52,   615,   628,    72,   708,   712,
+     713,  3297,   734,   522,   525,   560,    17,    39, -1191,   569,
+   -1191,   753,   759,   594, -1191,   773,   777,    20,    21, -1191,
+   -1191, -1191,  2334, -1191, -1191, -1191, -1191, -1191, -1191, -1191,
+   -1191, -1191, -1191, -1191, -1191, -1191, -1191, -1191,    30, -1191,
+      96,   217, -1191,     0, -1191, -1191, -1191, -1191,   -93,   -93,
+     -93,   -93,   -93,   -93,   -93,   -93,   -93,   -93,   -93,   -93,
+     -93,   -93,   -93,   -93,   -93,   -93,   -93,   -93,   -93,   -93,
+     -93,   -93,   -93,   593,   613,   616,   617,   625,   630, -1191,
+   -1191, -1191, -1191, -1191,   -93,   -93,   804,   637,   638,   646,
+     650,   651, -1191, -1191, -1191,  2334,  2334,  2334,  2334,  2394,
+      34,   832,   129,   658,   681,   237, -1191,   682,   868,  -122,
+    -121,   876,  2334,   527,   527, -1191,  2334, -1191, -1191, -1191,
+   -1191, -1191, -1191, -1191,  2334,  4823,  2334,  2334,   709,  2334,
+    4823,  2334,  2334,   714,  4823,  2334,  2334,  3649,   731,   701,
+   -1191,  4823,  3297,  3297,  3297,   739,   740,  3297,  3297,  3297,
+     758, -1191, -1191, -1191, -1191,   763,   791,   797,  3649,  2334,
+     903,  3649,    17,   746,   789,   101,   101,   101,  2334,  2334,
+     -63, -1191,    58,   101,   793,   798,   802,  2001,   109,    90,
+     810,   811,   812,  3297,  3297,  3649,   813,    36,   742, -1191,
+     886, -1191,   808,   823,   824,  3297,  3297,   771,   830,   833,
+     577, -1191,   834,    22,  1009,  1013,  1014,   719,  3825,  2334,
+    2938, -1191, -1191,  2362, -1191,  1016, -1191,   201,  1017,  2334,
+    2334,  2334,   839,  2334,   840,   895,  2334,  2334, -1191, -1191,
+    2334,  1026, -1191,  1029, -1191,  1030, -1191,   137,   835, -1191,
+    3649,  3649,   854,  2334,   859,  1925, -1191, -1191, -1191, -1191,
+   -1191, -1191,  3649,  1038,   870,  2334,  1056, -1191, -1191,  2334,
+    2334,  2334,  2334,  2334,  2334,  2334,  2334,  2334,  2334,  2334,
+    2334,  2334,  2334,  2334,  2334,  2334,  2334,  2334,  2334,  2334,
+    2334,   527,   527,   527,   527,   527,   527,   527,   527,   527,
+    2334,  1925,  2334,   527,   527,   527,   832,  1925,   885,   885,
+     885,  7149,    80,  6804,   265,   882,  1058,   902,   908,   910,
+     911, -1191,   913,  5356,  2334,  4823, -1191,  2334,  2334,  2334,
+    2334,  2334,  2334,  2334,  2334,  2334,  2334,  2334,  2334,  2334,
+    2334,  2334, -1191, -1191,  2334, -1191, -1191,  1162,   263,   -86,
+   -1191, -1191,   171,  6131,   290,   378,  7170,  4823,  3777, -1191,
+     -76,  7191,  7212,  2334,  7233,   -29,  7254,  7275,  2334,    98,
+    7296,  7317,  1089,  2334,  2334,   139,  1095,  1096,  1097,  2334,
+    2334,  1098,  1104,  1104,  2334,   927,   935,   936,   941,  2334,
+    2334,  2334,  1113,  6051,   961,  1137,   963, -1191, -1191,   -16,
+   -1191, -1191,  6157,  6183,   101,   101,   129,   129,   143,  2334,
+    2334,  2334,  2001,  2001,  2334,  5356,   152, -1191,  2334,  2334,
+    2334,  2334,  2334,  1138,  1142,  1143,  2334,  1145, -1191,  2334,
+    2334,   453, -1191,  4823,  4823,  4823,  1146,  1147,  2334,  2334,
+    2334,  2334,  1151,    -4,  1153, -1191,  2334, -1191, -1191, -1191,
+     965,   974,   977,   978,  4823,   885, -1191,  7338, -1191,   202,
+    2334,  4001, -1191, -1191,  7359,  7380,  7401,  1036,  6209, -1191,
+     980,  3946,  7422,  6827, -1191, -1191,   787, -1191,  1228,  2334,
+   -1191,   988,   344,  4823,  6850,  2334,  1161,  1163, -1191,  2334,
+    6873,    -2,  6781,  6781,  6781,  6781,  6781,  6781,  6781,  6781,
+    6781,  6781,  6781,  6235,  6781,  6781,  6781,  6781,  6781,  6781,
+    6781,  6261,  6287,  6313, -1191,   231,   404,   989,   995,   996,
+     992,   999,  1000,   260,  7863, -1191,  1447,  1001,  1007,  1006,
+    1012,  1015,    80, -1191,  3649,   134,  1925,  2334,  1172,  1175,
+      18,  1018, -1191,   102,    12,    19,   148, -1191,  4792,   356,
+    3965,  2148,  2296,   888,   888,   160,   160,   160,   160,    75,
+      75,   885,   885,   885,   885,     5,  6896, -1191,  2334,  1190,
+      31,  4823,  1189,  4823,  2334,  1191, -1191,   832,  1193,   527,
+    1195,  4823,  4823,  1070,  1196,  1197,  7443,  1206,  1084,  1213,
+    1214,  7464,  1092,  1217,  1218,  2334,  7485,  5323,  1045, -1191,
+   -1191, -1191,  7506,  7527,  2334,  3649,  1229,  1233,  7548,  4993,
+    4993,  4993,  4993,  7569,  7590,  7611,  3649,  4823,  1053, -1191,
+   -1191,  1616,  1690,   101,  2334,  2334, -1191, -1191,  1059,  1060,
+    2001,  6339,  6365,  6391,  6105,  1003,   101,  1869,  7632,  5351,
+    7653,  7674,  7695,  2334,  1240, -1191,  2334,  7716, -1191,  6919,
+    6942, -1191,   389,   398,   408, -1191, -1191,  6965,  6988,  6417,
+    7011,   201, -1191, -1191,  4823, -1191,  1067,  5379,  4823,  4823,
+    4823,  4823,   427, -1191, -1191,  4129,  4823,   885, -1191,  1241,
+    1242,  1243,  1072,  2334,  2801,  2334,  2334, -1191,    37, -1191,
+   -1191,  1075,  3649,  1248,   459,   440,  5407, -1191, -1191,  7034,
+     411, -1191, -1191, -1191, -1191, -1191, -1191, -1191, -1191, -1191,
+   -1191, -1191, -1191,  2334, -1191, -1191, -1191, -1191, -1191, -1191,
+   -1191,  2334,  2334,  2334,   527, -1191,  4823, -1191,   527, -1191,
+   -1191,   527,   527,   527, -1191, -1191, -1191, -1191,  2334, -1191,
+     527, -1191, -1191,  2334,  1257,    41,  2334,  1259,  1264,  1486,
+   -1191,  1266,  1099,    17,  1265, -1191,  4823,  4823,  4823,  4823,
+   -1191,   315,  2334, -1191,  1100,  1106,  1090, -1191,  1269, -1191,
+   -1191, -1191, -1191, -1191,   201,  7057, -1191, -1191,  1120,   527,
+     374, -1191,   442,  6443, -1191,  1278, -1191, -1191,   101,  3777,
+   -1191,   128,  3649,  3649,  1280,  3649,   147,  3649,  3649,  1281,
+    1230,  3649,  3649,  1551,  1282,  1283,  4823,  1297,  1298,  4317,
+   -1191, -1191,  1300, -1191,  1303,  1129,  7863, -1191,  1136,  1140,
+    1141,  1308,  1332,  1334,  1338,   463,  1341,  2985, -1191, -1191,
+     250,  6469,  6495, -1191, -1191,  5435,   -56,   101,   101,   101,
+    1342,  1343,  1164,  1348,  1170,    25,    42,    45,    49,   516,
+   -1191,   289, -1191,  1003,  1349,  1353,  1354,  1355,  1356,  7863,
+   -1191,  1663,  1171,  1358,  1360,  1363,  1290,  2334,  1366,  1367,
+    2334,   310,   467, -1191, -1191,   482,   496,   537,   559, -1191,
+    2334,   572,  3649,  3649,  3649,  1370,  6521, -1191,  4298,   565,
+    1381,  1383,  3649,  1203, -1191,  1211,  2334,  1384, -1191,  1385,
+    1389, -1191,  1391,  6781,  6781,  6781,  6781, -1191,   428,   315,
+    1212,  1221,  1222,   509,   530,  7737,  1224,  1688, -1191,   540,
+    1223,  1396,  2094, -1191, -1191, -1191,    17,  2334, -1191,   591,
+   -1191,   599,   620,   623,   627,    80,  7863,  1234,  2334,  2334,
+    3649,  1226, -1191, -1191,  1236, -1191,  1399,    33,  1413,  2334,
+    4529,    24,  1239,  1244,  1340,  1340,  3649,  1418,  1245,  1246,
+    1420,  1425,  3649,  1249,  1426,  1429, -1191,  1432,  3649,   636,
+    3649,  3649,  1421,  1433, -1191,  3649,  1431,  1434,  1435,  1437,
+    3649,  3649,  3649, -1191,  1438,   417, -1191,  2334,  2334,  2334,
+    1262,  1263,   -77,   -66,   -30,  1271, -1191,  3649, -1191,  2334,
+   -1191,  1442, -1191,  1443, -1191,  1445, -1191,  1446, -1191, -1191,
+    2001,   733,  3473, -1191,  1272,  1274,  4177, -1191,  4823, -1191,
+   -1191, -1191,  1275,  2493, -1191, -1191,  7080,  1450,   315, -1191,
+   -1191, -1191, -1191,  7863, -1191,  1454,  1456,  1337, -1191,  2334,
+    2334,  2334, -1191,  1458,   544,  1286,  1464,    80,  2512, -1191,
+   -1191,    64, -1191, -1191, -1191, -1191, -1191, -1191, -1191,   527,
+   -1191, -1191,  1467, -1191, -1191,  1468, -1191, -1191, -1191, -1191,
+   -1191,  1925,  2334,  1469,  1470,    18, -1191,  1471,  7103,    17,
+   -1191,  1473,  1478,  1479,  1480,  3649,  2334,  6547,  6573,   639,
+   -1191,  2334,  1472, -1191, -1191,   527, -1191,  6599,  4993,  7863,
+   -1191, -1191,  2334,  2334,   101,  1481,  1482,  1483, -1191,  2334,
+    2334, -1191, -1191,  1484,  2334, -1191, -1191,  1488,  1491,  1314,
+    1493,  1371,  2334, -1191,  1494,  3649,  3649,  3649,  3649,  1496,
+     756,  1497,  2334, -1191,  4993,  5463,  7758,  4491,   129,   129,
+     101,  1498,   101,  1501,   101,  1502,  2334,    95,  1326,  7779,
+   -1191, -1191, -1191, -1191,  5491,   300, -1191,  1505,  2761,  1506,
+    3649,   101,  2761,  1507,   648,  2334, -1191,  1508,   201, -1191,
+   -1191, -1191,  3649,  4937,   136,  7800, -1191, -1191,  4584,  3649,
+   -1191,  3649, -1191, -1191,  1339,  3121,  4760,  1515,  2531, -1191,
+    1520,  1522, -1191,  1357, -1191, -1191, -1191, -1191, -1191,  1523,
+     454,  7863,  2334,  2334,  3649,  1350,   649,  7863, -1191,  1530,
+    2334,  7863, -1191,  5519,  5547,   321, -1191, -1191, -1191,  5575,
+    5603, -1191,  5631,  1532, -1191,  3649, -1191,  1474,  1533,  7863,
+   -1191,  1535,  1539,  1540,  1541, -1191,  1364, -1191, -1191,  6078,
+    3066,  1543,  1368, -1191,  2334, -1191,  1373,  1377,   329, -1191,
+    1379,   347, -1191,  1380,   377, -1191,  1382,  7126,  1545,  3649,
+    1558,  1386,  2334, -1191,  4353,   381, -1191,   652,   421,   451,
+   -1191,  1563,  5659, -1191,  1448,  2334, -1191,  2334, -1191, -1191,
+    4823,  3086,  1565,  1390,  1568, -1191,  2938, -1191, -1191,   527,
+    7863, -1191, -1191, -1191,    17, -1191,  1449, -1191, -1191,  2334,
+    6625,  6651, -1191,  3649,  2334,  1570, -1191,  6677, -1191, -1191,
+    1572,  1573,  1574,  1575,  1577,  1580,   665,  1406, -1191, -1191,
+   -1191, -1191, -1191,  3649,  4823, -1191, -1191,   129,  5288, -1191,
+   -1191,  2001,  1003,  2001,  1003,  2001,  1003,  1585, -1191,   678,
+    3649, -1191,  5687,   101,  1586,  4823,   101, -1191, -1191,  2334,
+    5715,  5743,   690, -1191, -1191,  1587, -1191,   695,   340,   698,
+    1588, -1191,  1411,  7863,  2334,  2334,   715,  7863, -1191,  2334,
+     716,   729, -1191, -1191, -1191, -1191, -1191, -1191,  1412,  2334,
+     730,   737,  1436,  2334, -1191,  5771,   468,   782,  5799,   486,
+     934,  5827,   508,  1155, -1191,  3649,  1592,  1537,  3336,  1441,
+     517, -1191,   741,   536,  3594, -1191, -1191,  1620, -1191,  2334,
+   -1191,  1925, -1191, -1191,  2334,  7821,  6703,    27,  6729, -1191,
+   -1191,  2334,  5855,  1621,  1624, -1191,  5883,  1625,  2334,  1627,
+    1629,  2334,  1630,  1632,  2334,  1633,  1475, -1191,  2334, -1191,
+    1003, -1191,  4823,  1635,  4353, -1191, -1191,   794, -1191,   744,
+   -1191,  2334, -1191,  3649,  2334,  6755, -1191, -1191, -1191, -1191,
+   -1191,  1477,  5911, -1191, -1191,  1487,  5939, -1191, -1191,  1489,
+    5967, -1191,  1652,  3613,  1270,  3512,   761, -1191,   538,   762,
+    1925,  1653,  1490,  7842,   766,  5995,  2334,  1003,  1657,  1003,
+    1659,  1003,  1660, -1191, -1191, -1191, -1191,  1003,  1662,  4823,
+    1664, -1191, -1191,   527, -1191,  1492,  1666,  6023,  1419, -1191,
+    1495,  1811, -1191,  1511,  1873, -1191,  1524,  1979, -1191,   786,
+   -1191,   795, -1191,  1542,  3649, -1191,  1669,  1684,  1003,  1686,
+    1003,  1698,  1003, -1191,  1700,   527,  1701,   527,   796, -1191,
+   -1191,  2012, -1191,  2102, -1191,  2192, -1191, -1191, -1191,   800,
+   -1191,  1717,  1722,  1727,  1728,   527,  1735, -1191, -1191, -1191,
+   -1191, -1191, -1191
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-   -1244, -1244, -1244, -1244,   701, -1244, -1244, -1244, -1244,   188,
-   -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244, -1244,
-   -1244, -1244,  -356,   -88, -1244,  1334, -1244, -1244, -1244, -1244,
-   -1244, -1244, -1244, -1244, -1244,  -395, -1244,   694,  1746, -1244,
-   -1244, -1244, -1244,     1,  -456,  -223, -1244, -1244, -1244, -1244,
-   -1244, -1244,  1747, -1244, -1244, -1244, -1244, -1244, -1244, -1244,
-   -1244, -1244, -1244, -1244, -1244, -1244,  -923,  -849, -1244, -1244,
-    1324, -1244, -1244, -1244, -1244, -1244,   248, -1244,    -9, -1244,
-   -1243,   817,   708,  1163,   985,  -200,   580, -1244,    11,    -5,
-    -350, -1244,    -3
+   -1191, -1191, -1191, -1191,   745, -1191, -1191, -1191, -1191,   279,
+   -1191, -1191, -1191, -1191, -1191, -1191, -1191, -1191, -1191, -1191,
+   -1191, -1191,  -352,   -72,  4949,  -477, -1191,  1344, -1191, -1191,
+   -1191, -1191, -1191,   386, -1191,   391, -1191,  -296, -1191,   743,
+    1742, -1191, -1191, -1191, -1191,     3,  -449,  -235, -1191, -1191,
+   -1191, -1191, -1191, -1191,  1748, -1191, -1191, -1191, -1191, -1191,
+   -1191, -1191, -1191, -1191, -1191, -1191, -1191, -1191,  -892,  -884,
+   -1191, -1191,  1319, -1191, -1191, -1191, -1191, -1191,   747, -1191,
+   -1191,   204, -1191, -1190,  1260,  -109,  1011,   -58,  -204,   641,
+   -1191,    35,   107, -1191,  -348,    14,    -3
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
    number is the opposite.  If zero, do what YYDEFACT says.
    If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -458
+#define YYTABLE_NINF -447
 static const yytype_int16 yytable[] =
 {
-     101,   161,   593,   162,    88,   988,   472,   704,   705,   304,
-     239,   164,   603,   303,   453,  1363,   611,   160,   488,   615,
-     180,   180,   185,   274,   850,   185,   277,  1110,   285,   287,
-     502,   176,   167,  1536,  1199,   291,   222,   224,   177,   230,
-     873,   461,   462,   484,  1099,   485,   405,   104,   375,   860,
-     235,   242,   236,   243,  1192,  1020,   214,  1238,     4,  1239,
-    1101,  1103,   736,   533,  1105,   535,   300,   301,   737,   215,
-     216,   461,   462,   475,   461,   462,  -455,   307,  1406,   308,
-     476,   130,   131,   132,   133,   134,   135,  1240,   651,  1241,
-    1242,   652,  1243,   139,   295,   461,   462,  1108,   461,   462,
-     210,   610,   176,   211,   102,   103,   104,   244,     5,   854,
-     105,   106,   107,  1090,   699,   108,   109,   110,   111,   112,
+     101,   573,   465,   170,   314,   188,    88,   678,   679,   813,
+     584,  1061,   587,   247,   481,  1059,   188,   100,   446,   193,
+    1317,   282,   802,   193,   171,   293,   295,   495,   184,   313,
+    1151,  1050,   175,  1502,     4,   185,   299,   827,   364,  1144,
+     477,   167,   478,   285,   940,   969,   234,     5,  1052,   235,
+     239,  1054,   236,   310,   311,  1056,   250,   394,   251,   526,
+     243,   528,   244,  -444,   304,   752,   753,   754,   755,   756,
+     757,   758,   759,   760,   761,   762,   172,   764,   765,   766,
+     767,   768,   769,   770,   317,  1366,   318,   583,   775,   777,
+     454,   455,   620,   426,   427,   428,   173,   621,   431,   432,
+     433,   454,   455,   510,   454,   455,  1190,   632,  1191,   633,
+     240,   454,   455,   168,   241,   207,   252,  1192,   208,  1193,
+     209,   456,   814,   815,   816,   817,   242,   410,   218,  1041,
+     174,   219,   415,   370,   473,   474,   419,   454,   455,   255,
+    1051,   583,   256,   425,  1327,   248,   486,   487,   177,   226,
+     227,   454,   455,  1194,   632,  1195,   638,  1053,   369,   228,
+    1055,   365,   366,  1416,  1057,   371,   237,   673,   970,   971,
+     401,   401,   310,   311,   712,   368,   713,  1059,   189,   315,
+     714,   316,  -445,  1430,   178,   190,   163,   368,   368,   189,
+     818,   454,   455,   249,   179,   828,   807,   828,  1002,   194,
+    1003,   283,   803,   808,   294,   296,   496,   300,   399,   402,
+     176,  1503,   671,   672,   301,   479,   286,  1008,   941,  1009,
+      44,    45,    46,    47,   305,   454,   455,   222,    52,   180,
+     793,    55,   687,   796,   306,   307,   308,   309,   310,   311,
+     223,   224,   457,   376,   388,   389,   390,   181,  -446,   230,
+     232,   391,   238,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   511,   389,   390,   468,   226,   227,
+     182,   391,   586,   302,   469,   303,   454,   455,   228,   184,
+    1308,   632,   304,   642,   734,   229,   806,   183,   306,   307,
+     308,   309,   588,   467,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,   310,   311,
+     454,   455,   391,  1534,   197,   795,   529,   599,   492,   454,
+     455,  1328,   632,   163,   648,   196,   680,   386,   387,   388,
+     389,   390,   809,   186,   985,   686,   391,   198,   401,   401,
+     401,   401,   401,   401,   401,   401,   401,  1461,   510,   622,
+     401,   401,   401,   580,   623,   368,   368,   368,   368,   368,
+     368,   368,   368,   368,   868,   869,   870,   368,   368,   368,
+     368,   306,   307,   308,   309,   310,   311,   566,   567,   568,
+     569,   570,   571,   572,  1588,   632,   187,   724,   577,   578,
+     579,   310,   311,   946,   199,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,   712,
+     191,   713,   536,   391,   774,   398,   104,   454,   455,   306,
+     307,   308,   309,  1183,  1184,   702,   703,   704,   211,   449,
+     450,   212,   192,  1037,   213,   877,   214,   458,   784,   310,
+     311,   466,   618,   774,   619,   195,   722,   583,   196,   163,
+     130,   131,   132,   133,   134,   135,   454,   455,   575,   371,
+     371,   200,   139,   140,   581,     7,     8,   454,   455,   751,
+     625,   201,  1060,   626,   145,   744,  1103,  1104,  1105,  1106,
+     205,  1107,  1108,  1312,   310,   311,  1113,  1116,   454,   455,
+    1437,  1077,  1440,   712,  1443,   713,   454,   455,   377,   378,
+     379,   380,   381,   382,   383,   384,   385,   386,   387,   631,
+     389,   390,  1381,   797,   454,   455,   391,   593,    20,    21,
+     594,    23,    24,   595,    26,   596,    28,   742,    29,   743,
+    1383,   398,   104,    34,    35,   206,    37,    38,    39,   632,
+     202,   811,    42,   203,   454,   455,   204,  1121,   454,   455,
+    1227,  1228,   997,  1059,   148,   149,  1059,   632,   628,  1059,
+    1385,   626,   210,   830,  1393,   832,   130,   131,   132,   133,
+     134,   135,   632,  1091,   915,    63,    64,    65,   139,   140,
+     220,   632,   712,   916,   713,   310,   311,   776,   454,   455,
+     145,   632,   950,   917,   306,   307,   308,   309,  1524,   978,
+     221,  1219,   215,   890,  1395,   216,   712,   217,   713,   875,
+     632,   632,   929,   891,   310,   311,   225,  1122,   454,   455,
+     998,   892,   893,   894,   835,   632,   401,   895,   896,   897,
+     898,   233,  1348,  1135,  1396,   454,   455,  1349,   701,   751,
+    1059,   368,   632,   368,   945,  1558,   632,  1561,  1034,  1564,
+     632,  1478,  1078,   454,   455,  1567,   922,   245,   676,   677,
+     925,   926,   927,   928,   837,   632,   450,  1079,   931,  1481,
+     148,   149,   246,   947,  1059,   454,   455,  1059,   951,   632,
+    1059,  1080,   253,  1059,   454,   455,  1591,   712,  1593,   713,
+    1595,  1484,  1112,   798,   306,   307,   308,   309,   254,   279,
+    1492,  1058,   280,   454,   455,   454,   455,  1059,   712,  1059,
+     713,  1059,   257,  1115,   310,   311,   258,   259,   958,  1494,
+     632,  1549,  1081,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,   281,   278,  1296,
+    1297,   391,   632,  1092,  1082,  1231,   287,   401,   981,   982,
+     983,   984,   993,   165,   317,   632,   491,  1084,   492,   288,
+    1286,   162,  1287,   163,   368,   289,   867,   867,   867,   867,
+     344,   401,  1127,   290,  1129,   401,  1130,   291,   401,   401,
+     401,   292,   632,   500,  1131,   952,   501,   401,   368,   502,
+     345,   503,   368,   346,   347,   368,   368,   368,  1019,     7,
+       8,  1530,   348,   632,   368,  1132,   632,   349,  1133,   957,
+     632,   352,  1134,   959,   353,   354,   960,   961,   962,   632,
+     890,  1169,  1254,   355,  1255,   966,   401,   356,   357,   298,
+     891,   632,  1354,  1321,  1355,  1254,   367,  1394,   892,   893,
+     894,   530,   374,   368,   895,   896,   897,   898,  1254,   951,
+    1428,   593,    20,    21,   594,    23,    24,   595,    26,   596,
+      28,  1445,    29,  1446,   996,   375,   392,    34,    35,   890,
+      37,    38,    39,   632,   393,  1457,    42,   880,  1459,   891,
+    1460,   774,   396,  1462,   886,   424,   413,   892,   893,   894,
+     901,   418,   482,   895,   896,   897,   898,  1123,  1254,  1112,
+    1467,  1469,   358,   359,   360,   361,   363,   444,   423,    63,
+      64,    65,  1115,  1254,  1470,  1473,   429,   430,  1206,   397,
+     632,   480,  1474,   403,   632,  1244,  1493,  1354,  1432,  1531,
+     447,   406,   408,   411,   412,   434,   414,   408,   416,   417,
+     439,   408,   420,   421,   632,   632,  1548,  1550,   408,  1254,
+     488,  1555,   377,   378,   379,   380,   381,   382,   383,   384,
+     385,   386,   387,   388,   389,   390,   443,  1479,   440,   632,
+     391,  1584,   739,   448,   441,   452,   453,   459,  1585,  1254,
+    1586,  1601,   460,  1605,   453,  1606,   461,   470,   471,   472,
+     476,  1409,   483,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,   484,   485,   489,
+    1214,   391,   490,   494,   497,   505,   507,   408,   498,   499,
+     517,   890,   512,   513,   519,   520,   514,   515,   516,  1233,
+     518,   891,   524,   521,   522,   525,   527,   523,   533,   892,
+     893,   894,  1001,   535,   538,   895,   896,   897,   898,   539,
+     534,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+     541,   391,   540,   589,   391,   590,   542,   543,   544,   545,
+     546,   547,   548,   549,   550,   551,   552,   553,   554,   555,
+     556,   557,   558,   559,   560,   561,   562,   563,   163,   591,
+     890,  1042,  1043,  1044,   304,   162,   645,   574,   592,   576,
+     891,   649,   650,   651,   659,   654,   401,  1150,   892,   893,
+     894,   655,   660,   661,   895,   896,   897,   898,   662,  1482,
+     666,   598,   408,   368,   600,   601,   602,   603,   604,   605,
+     606,   607,   608,   609,   610,   611,   612,   613,   614,   668,
+    1410,   616,   401,   669,  1234,   693,  1233,   670,   695,   718,
+     696,   698,   705,   706,   505,   711,  1448,   716,   719,   368,
+     636,   720,   721,   732,   735,   641,   741,   747,   617,   748,
+     646,   647,   778,   779,   780,   781,   652,   653,   800,   801,
+    1259,   658,   782,   783,   788,   789,   663,   664,   665,   790,
+     791,   371,   371,   792,   826,   831,   409,   834,   805,   836,
+     841,   409,   838,   842,   843,   409,   681,   682,   683,   358,
+     359,   684,   409,   845,   846,   688,   689,   690,   691,   692,
+     847,   848,   850,   697,   851,   852,   699,   700,  1237,   856,
+     408,   408,   408,   861,   876,   707,   708,   709,   710,   863,
+       7,     8,   890,   717,   883,   884,   910,   923,   932,   933,
+     934,   408,   891,   935,   944,  1262,  1525,   725,   727,   942,
+     892,   893,   894,   968,  1205,   973,   895,   896,   897,   898,
+     974,   980,  1402,   976,   990,   992,   710,   988,   977,   506,
+     408,   409,   746,   989,   995,  1000,   749,  1006,  1012,  1017,
+    1018,  1291,   593,    20,    21,   594,    23,    24,   595,    26,
+     596,    28,  1013,    29,  1020,  1021,  1024,  1026,    34,    35,
+    1025,    37,    38,    39,  1027,  1030,  1431,    42,  1028,  1029,
+     377,   378,   379,   380,   381,   382,   383,   384,   385,   386,
+     387,   388,   389,   390,   799,  1332,   401,  1452,   391,  1031,
+    1485,  1032,  1338,  1341,  1033,  1035,  1045,  1049,  1047,  1046,
+      63,    64,    65,   368,  1048,  1068,  1062,   890,  1265,  1063,
+    1072,  1064,  1065,  1066,  1069,   825,  1070,   891,   408,  1071,
+     408,   833,  1074,  1075,  1088,   892,   893,   894,   727,   839,
+     371,   895,   896,   897,   898,  1093,   409,  1094,  1096,  1097,
+    1099,  1100,   853,  1101,  1298,  1109,  1301,  1102,  1304,  1110,
+    1111,   859,  1119,  1125,  1124,  1143,   866,   866,   866,   866,
+    1141,  1136,  1315,   740,   408,  1318,  1319,  1142,   506,  1146,
+    1154,   881,   882,  1152,  1158,  1172,  1161,   885,  1153,  1159,
+    1160,  1162,  1165,  1164,  1526,  1166,  1529,  1167,  1175,  1173,
+     909,  1176,  1177,   911,  1178,  1182,  1188,  1189,  1200,  1201,
+    1196,  1202,  1203,   787,  1218,  1545,  1210,   422,  1211,  1215,
+    1220,   408,  1221,  1222,  1226,   408,   408,   408,   408,  1229,
+    1230,  1235,  1236,   408,  1240,  1239,  1258,  1242,   442,  1245,
+     936,   445,   938,   939,  1246,  1247,  1248,  1266,  1267,  1268,
+    1271,  1569,   975,  1273,   409,   409,   409,  1274,  1275,  1276,
+    1280,  1277,  1285,  1288,  1299,   475,   890,  1302,  1305,  1309,
+     953,  1313,  1316,  1320,  1323,   409,   891,  1335,   954,   955,
+     956,  1342,   728,   408,   892,   893,   894,  1344,  1345,  1347,
+     895,   896,   897,   898,  1353,   965,  1356,  1365,  1346,  1368,
+     967,  1369,  1367,   972,   409,  1370,  1371,  1372,  1373,  1376,
+     401,  1388,  1377,   408,   408,   408,   408,  1016,  1379,   986,
+     531,   532,  1380,  1382,  1384,  1390,  1386,   368,  1498,  1397,
+    1391,  1404,   537,  1399,  1406,  1405,  1418,  1411,  1422,  1423,
+    1424,  1425,   401,  1426,   401,  1436,  1427,  1439,  1572,  1442,
+    1429,  1444,  1451,  1458,  1463,  1464,  1471,  1450,  1487,   368,
+    1453,   368,   401,   408,  1577,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,   368,
+    1597,  1475,  1600,   391,  1488,  1491,  1496,  1507,     7,     8,
+    1508,  1510,   409,  1513,   409,  1514,  1517,  1551,  1518,  1521,
+    1611,  1527,   728,   840,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,  1543,  1552,
+    1522,  1537,   391,  1559,  1073,  1562,  1565,  1076,  1568,  1067,
+    1570,  1539,  1575,  1541,  1553,  1589,  1574,  1083,   409,  1578,
+     593,    20,    21,   594,    23,    24,   595,    26,   596,    28,
+    1590,    29,  1592,  1098,  1120,  1580,    34,    35,  1528,    37,
+      38,    39,     7,     8,  1594,    42,  1596,  1598,  1582,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,  1607,  1128,   409,  1587,   391,  1608,   409,
+     409,   409,   409,  1609,  1610,  1137,  1138,   409,    63,    64,
+      65,  1612,  1145,  1499,  1420,    87,  1147,  1149,  1156,   629,
+    1421,    95,   657,     0,   593,    20,    21,   594,    23,    24,
+     595,    26,   596,    28,     0,    29,  1241,     0,     0,     0,
+      34,    35,     0,    37,    38,    39,     0,     0,     0,    42,
+       0,     0,     0,     0,  1185,  1186,  1187,   409,     0,     0,
+       0,     0,     0,     0,  1197,     0,  1199,     0,     0,     0,
+       0,   878,     0,     0,     0,     0,     0,  1204,     0,     0,
+       0,     0,    63,    64,    65,   408,     0,   409,   409,   409,
+     409,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,  1223,  1224,  1225,   391,
+       0,     0,     0,     0,   794,     0,   377,   378,   379,   380,
+     381,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+       0,     0,     0,     0,   391,     0,     0,   409,     0,  1238,
+       0,     0,     0,     0,     0,   879,     0,     0,     0,     0,
+       0,     7,     8,  1251,     0,     0,     0,     0,  1257,     0,
+       0,     0,     0,     0,     0,  1261,     0,     0,   890,  1263,
+    1264,     0,     0,     0,     0,     0,  1269,  1270,   891,     0,
+       0,  1272,     0,     0,     0,   860,   892,   893,   894,  1279,
+       0,     0,   895,   896,   897,   898,   874,     0,     0,  1289,
+     104,  1290,     0,   593,    20,    21,   594,    23,    24,   595,
+      26,   596,    28,  1307,    29,     0,     0,     0,     0,    34,
+      35,     0,    37,    38,    39,   408,     0,     0,    42,   408,
+     890,     0,  1322,     0,   130,   131,   132,   133,   134,   135,
+     891,     0,     0,     0,     0,  1331,   139,   140,   892,   893,
+     894,     0,     0,  1340,   895,   896,   897,   898,   145,     0,
+       0,    63,    64,    65,     0,     0,  1579,     0,     0,  1350,
+    1351,     0,   943,     0,   102,   297,     0,  1357,     0,     0,
+     105,   106,   107,     0,     0,   108,   109,   110,   111,   112,
      113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
-     123,   124,   125,   126,   127,   128,   129,   309,   240,   310,
-     130,   131,   132,   133,   134,   135,   136,   137,   138,  1100,
-    1452,   163,   139,   140,   141,   461,   462,   380,   861,   862,
-     863,   864,   408,   408,   517,  1102,  1104,   376,   377,  1106,
-    1466,   165,   463,   989,  1021,  1022,   406,   409,   305,   188,
-     306,   144,   145,   166,   241,   157,   857,   181,   181,   461,
-     462,   169,   874,   278,   182,   855,   186,   275,   851,   856,
-     292,   286,   288,   503,   168,  1537,   874,   293,   456,   457,
-     300,   301,   486,   379,   461,   462,   465,   995,   170,   536,
-     473,   500,   226,   171,   865,   227,   157,   311,   228,   312,
-     706,   697,   698,   142,  1373,   296,   297,   298,   299,   143,
-     144,   145,   296,   297,   298,   299,   146,   147,   148,   218,
-     219,   713,   174,   840,   158,   300,   301,   844,   658,   220,
-     659,  1108,   149,   150,   461,   462,   221,   151,   644,   231,
-     645,   313,   152,   314,   153,   157,   154,   155,   610,   156,
-     712,   157,   175,   461,   462,   461,   462,   616,   300,   301,
-     541,   915,   916,   917,  1569,  1128,    44,    45,    46,    47,
-     464,   614,   474,   760,    52,   300,   301,    55,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   518,
-     397,   398,   172,   218,   219,   232,   399,   461,   462,   233,
-     290,   461,   462,   220,  1141,  1354,   300,   301,   173,   247,
-     229,   234,   248,  1086,   461,   462,  -456,  1109,   408,   408,
-     408,   408,   408,   408,   408,   408,   408,   408,   408,   408,
-    1358,   408,   408,   408,   594,   595,   596,   597,   598,   599,
-     600,   601,   602,  1170,  1635,   605,   606,   607,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,   517,   461,   462,   178,   399,   367,   368,   369,
-     371,   374,   461,   462,   179,  1374,   646,   461,   462,  1421,
-     199,   647,   404,   200,   654,   201,   410,   652,  1423,   296,
-     297,   298,   299,  1425,   413,   415,   418,   419,   648,   421,
-     415,   423,   424,   649,   415,   427,   428,   300,   301,   300,
-     301,   415,   296,   297,   298,   299,   843,  -457,  1231,  1232,
-     461,   462,   702,   703,   461,   462,   461,   462,   775,   450,
-     457,   183,   300,   301,   380,   380,  1433,   184,   459,   460,
-    1435,   207,  1436,   924,   208,   187,   209,   460,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,   315,   498,   316,   499,   399,   500,  1142,  1473,
-     156,  1476,   157,  1479,  1276,  1277,   461,   462,   512,   514,
-     415,   188,   461,   462,   296,   297,   298,   299,   189,   521,
-     522,   523,  1514,   525,   820,   845,   528,   529,  1517,   821,
-     530,   317,   190,   318,   300,   301,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   518,   397,   398,
-     319,   191,   320,   545,   399,   547,   548,   549,   550,   551,
-     552,   553,   554,   555,   556,   557,   558,   559,   560,   561,
-     562,   563,   564,   565,   566,   567,   568,   569,   570,   571,
-     572,   573,   574,   575,   576,   577,   578,   579,   580,   581,
-     582,   583,   584,   585,   586,   587,   588,   589,   590,   461,
-     462,   461,   462,  1560,   461,   462,   461,   462,   321,   846,
-     322,   604,   396,   397,   398,  1520,   192,  1528,   415,   399,
-    1530,   415,  1590,   194,  1108,   822,   195,  1108,   821,   196,
-    1108,   626,   193,   627,   628,   629,   630,   631,   632,   633,
-     634,   635,   636,   637,   638,   639,   640,   641,   197,   823,
-     882,  1029,   408,   775,   824,  1601,   834,  1604,   198,  1607,
-    1167,   821,   512,  1169,  1171,  1610,   884,   825,   662,   203,
-     826,  1046,   204,   667,   202,   205,   658,   206,   672,   673,
-     914,   914,   914,   914,   678,   679,   996,  1047,  1158,   684,
-     927,   212,   658,   658,   689,   690,   691,   933,  1159,   213,
-    1388,   658,  1640,   948,  1642,  1389,  1644,   323,   325,   324,
-     326,  1108,   461,   462,   707,   708,   709,   367,   368,   710,
-     327,   217,   328,   714,   715,   716,   717,   718,   329,   238,
-     330,   723,   225,   249,   725,   726,   237,   245,   415,   415,
-     415,   246,   250,   733,   734,   735,   251,   740,     7,     8,
-     937,   743,  1108,   270,   331,  1108,   332,   271,  1108,   415,
-     938,  1108,   333,   280,   334,   751,   753,   272,   939,   940,
-     941,   408,   273,   279,   942,   943,   944,   945,   281,   283,
-    1342,  1343,   284,   294,   740,   997,   282,   335,   770,   336,
-     357,  1108,   773,  1108,   358,  1108,   621,    20,    21,   622,
-      23,    24,   623,    26,   624,    28,   337,    29,   338,   339,
-     359,   340,    34,    35,   360,    37,    38,    39,   408,   361,
-     362,    42,   405,   104,   408,   408,   364,  1176,   408,   408,
-     408,   341,  1006,   342,   343,   408,   344,   363,  1009,  1010,
-     365,   378,  1011,  1012,  1013,   507,  1107,   366,   508,  1015,
-     345,   509,   346,   510,    63,    64,    65,   130,   131,   132,
-     133,   134,   135,   847,   347,   384,   348,   383,   349,   139,
-     350,   351,   408,   352,   400,   353,  1050,   354,   355,   658,
-     356,   664,   996,   658,   401,   668,  1045,   394,   395,   396,
-     397,   398,   871,   403,   420,   415,   399,   415,   879,   658,
-     451,   674,   433,   434,   435,   753,   886,   438,   439,   440,
-     658,   768,   750,   769,   658,   727,   839,   425,   658,   900,
-     842,   658,   658,   962,   963,  1091,  1092,  1093,   906,   658,
-     430,   964,  1172,   913,   913,   913,   913,   658,  1051,   977,
-    1052,   415,   431,   480,   481,   104,   454,   436,   928,   929,
-    1057,   658,  1058,  1083,   932,   493,   494,   144,   145,   437,
-     658,  1468,  1126,   658,   658,  1127,  1129,   956,   441,   658,
-     958,  1130,   658,   658,  1131,  1132,   446,   447,  1291,   130,
-     131,   132,   133,   134,   135,   415,   658,   415,  1134,   455,
-     466,   139,   415,   415,   415,   415,  1178,   658,  1179,  1180,
-     415,   658,   658,  1181,  1182,   448,   429,   984,   487,   986,
-     987,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,   467,   658,   449,  1183,   399,
-     452,   937,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,   938,   468,   489,  1198,   399,   998,   999,   477,   939,
-     940,   941,   478,   495,   482,   942,   943,   944,   945,   658,
-    1280,  1217,  1000,  1001,  1002,  1003,  1004,  1005,  1300,  1332,
-    1301,  1333,   415,   479,   415,     7,     8,   483,   490,   144,
-     145,   658,   496,  1367,  1014,  1394,   497,  1395,  1017,  1300,
-     504,  1434,  1023,  1300,  1481,  1464,  1482,   658,   501,  1493,
-    1253,   491,   415,   415,   415,   415,  1300,  1036,  1499,   538,
-     539,  1501,  1504,  1502,  1505,  1300,   658,  1509,  1510,   542,
-     658,   505,  1529,   621,    20,    21,   622,    23,    24,   623,
-      26,   624,    28,  1394,    29,  1566,   658,   506,  1589,    34,
-      35,   492,    37,    38,    39,   658,   519,  1591,    42,   520,
-     937,   415,  1300,  1619,  1595,  1620,   821,   524,  1622,   408,
-     938,   658,   417,  1631,  1632,  1284,  1633,   422,   939,   940,
-     941,   426,   526,  1281,   942,   943,   944,   945,   432,   527,
-    1280,    63,    64,    65,  1300,  1446,  1650,  1655,   531,  1656,
-     408,  1308,   532,  1311,   534,   540,   543,   544,   399,   546,
-     617,   156,   619,   618,  1305,   620,     7,     8,  1484,   671,
-     675,   676,  1122,   677,   685,  1125,   680,   681,   686,   687,
-     688,   692,   694,   695,  1599,   719,  1133,  1337,   722,  1344,
-     696,  1347,   721,  1350,   724,   731,   732,   380,   380,   741,
-     742,   758,   765,   771,   744,   767,  1254,  1361,   745,   746,
-    1364,  1365,   747,   761,   621,    20,    21,   622,    23,    24,
-     623,    26,   624,    28,   772,    29,   827,   828,   829,   830,
-      34,    35,  1378,    37,    38,    39,  1177,   831,   832,    42,
-     833,   836,   837,   838,   848,   849,  1185,  1186,   853,   872,
-     877,   881,   880,   888,   883,   893,  1195,  1197,   885,   889,
-     890,   892,   894,   895,  1561,   937,   897,   898,   899,   903,
-     908,   910,    63,    64,    65,   938,   923,   930,   931,   957,
-     971,   980,   983,   939,   940,   941,   981,     7,     8,   942,
-     943,   944,   945,   982,  1233,  1234,  1235,   990,   992,  1018,
-     416,  1024,   937,  1016,  1245,   416,  1247,  1019,  1025,   416,
-    1027,  1028,   938,  1031,  1038,   608,   416,  1252,   612,  1040,
-     939,   940,   941,  1039,  1042,   415,   942,   943,   944,   945,
-    1044,   157,  1049,   766,  1055,   621,    20,    21,   622,    23,
-      24,   623,    26,   624,    28,  1061,    29,  1272,  1273,  1274,
-    1062,    34,    35,  1066,    37,    38,    39,  1067,  1069,  1070,
-      42,  1515,  1073,  1075,  1074,  1076,  1077,  1079,  1080,   537,
-    1078,  1081,  1472,  1082,  1475,  1084,  1478,  1094,   380,  1285,
-    1095,  1096,  1097,   513,  1486,   416,  1098,  1489,   841,  1111,
-    1112,  1117,  1297,    63,    64,    65,  1113,  1303,  1518,  1114,
-    1115,  1118,  1119,  1120,  1307,  1121,  1123,   937,  1309,  1310,
-    1124,  1138,  1143,  1144,  1146,  1315,  1316,   938,  1147,  1148,
-    1318,  1160,  1149,  1191,  1161,   939,   940,   941,  1325,  1163,
-    1164,   942,   943,   944,   945,   728,   729,   730,  1335,  1162,
-    1336,  1166,  1173,  1174,  1194,  1190,  1189,  1184,  1202,  1200,
-    1201,  1206,  1353,  1209,   925,  1207,   748,  1215,   907,  1208,
-    1210,  1212,  1213,  1214,   415,  1220,  1221,  1236,   415,   921,
-    1223,  1368,  1224,  1225,  1226,  1230,  1237,  1244,  1248,  1249,
-    1250,  1564,  1251,  1258,  1259,  1377,  1263,  1266,  1267,  1268,
-    1269,  1271,  1270,   416,  1573,  1576,   416,  1275,  1278,  1279,
-    1286,  1287,  1289,  1521,  1292,  1293,  1390,  1391,  1294,  1295,
-    1304,  1312,  1321,  1313,  1397,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,  1314,
-    1317,   408,  1319,   399,   937,  1320,  1322,   513,  1326,  1323,
-    1331,  1334,  1345,  1348,   938,   991,  1351,  1355,  1418,  1359,
-     408,  1362,   939,   940,   941,  1366,  1369,  1380,   942,   943,
-     944,   945,  1381,  1382,  1615,  1383,  1432,  1385,   512,  1386,
-    1396,  1405,  1393,  1387,  1407,  1408,  1637,  1409,  1410,  1440,
-    1411,  1441,  1412,  1413,   415,  1416,  1428,  1437,  1417,   408,
-    1419,   408,   876,  1420,   878,  1430,  1422,  1449,  1424,  1426,
-    1431,  1439,  1453,  1646,  1444,  1649,  1658,  1445,  1454,  1458,
-    1459,  1447,   408,   416,   416,   416,  1511,  1460,  1461,  1462,
-    1463,  1465,   415,  1480,  1487,  1494,  1662,  1495,  1496,  1471,
-    1586,  1474,  1523,  1477,   416,  1524,  1507,  1527,   922,  1532,
-    1539,   754,  1540,   415,  1533,  1543,  1544,  1490,  1546,  1549,
-    1550,  1553,  1554,  1557,  1558,  1578,  1563,  1580,  1497,  1498,
-    1582,  1584,  1592,  1500,  1602,  1605,  1053,  1054,  1593,  1056,
-    1608,  1059,  1060,  1508,  1611,  1063,  1064,  1512,  1613,  1617,
-    1618,  1638,   968,  1639,   969,  1641,  1625,  1627,  1643,   973,
-     974,   975,   976,   937,  1629,  1634,  1645,   979,  1647,  1657,
-    1659,  1660,  1661,   938,  1303,  1663,   655,  1193,  1204,    87,
-      95,   939,   940,   941,  1288,  1541,     0,   942,   943,   944,
-     945,     0,  1548,     0,   683,  1552,     0,     0,  1556,     0,
-       0,     0,  1559,     0,     0,     0,   415,     0,   415,     0,
-       0,     0,     0,  1568,     0,     0,  1570,   643,  1575,     0,
-       0,     0,     0,     0,     0,     0,     0,  1135,  1136,  1137,
-       0,     0,     0,     0,     0,     0,     0,  1145,   937,  1007,
-     416,  1008,   416,     0,     0,     0,     0,     0,   938,  1598,
-     754,   887,     0,     0,     0,  1600,   939,   940,   941,  1624,
-       0,     0,   942,   943,   944,   945,     0,     0,   415,  1032,
-    1033,  1034,  1035,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,   416,  1188,     0,   399,
-       0,     0,     0,     0,     0,     0,     0,  1636,     0,     0,
-       0,     0,  1205,     0,     0,   835,     0,     0,  1211,     0,
-       0,     0,     0,     0,  1216,     0,  1218,  1219,  1068,     0,
-       0,  1222,     0,     0,     0,     0,  1227,  1228,  1229,  1026,
-     416,     0,   416,     0,  1626,     0,     0,   416,   416,   416,
-     416,     0,     0,  1246,     0,   416,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,  1257,     0,
-       0,   399,  1261,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,   102,   289,
-       0,   399,     0,     0,   105,   106,   107,     0,     0,   108,
+     123,   124,   125,   126,   127,   128,   129,     0,     0,     0,
+       0,  1378,     0,     0,     0,     0,   136,   137,   138,     0,
+       0,     0,     0,     0,   902,   141,   142,   143,  1581,  1392,
+       0,   505,     0,   144,     0,     0,   890,     0,   148,   149,
+       0,     0,  1400,     0,  1401,     0,   891,   408,     0,   409,
+       0,     0,     0,  1408,   892,   893,   894,     0,     0,     0,
+     895,   896,   897,   898,     0,     0,  1413,     0,     0,   890,
+    1126,  1417,  1004,  1005,     0,  1007,     0,  1010,  1011,   891,
+       0,  1014,  1015,     0,     0,     0,     0,   892,   893,   894,
+       0,   408,     0,   895,   896,   897,   898,     0,  1435,     0,
+    1438,     0,  1441,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   408,   147,     0,     0,  1454,     0,     0,     0,
+     150,   151,   152,   153,   154,     0,     0,     0,     0,     0,
+       0,  1465,  1466,     0,  1583,     0,  1468,     0,   462,   463,
+       0,     0,     0,   157,     0,     0,  1472,     0,   464,     0,
+    1476,     0,     0,   161,     0,   229,     0,     0,     0,   890,
+       0,     0,  1085,  1086,  1087,     0,     0,  1602,     0,   891,
+       0,     0,  1095,     0,     0,     0,  1497,   892,   893,   894,
+       0,  1257,     0,   895,   896,   897,   898,     0,  1505,   409,
+       0,     0,     0,   409,     0,  1512,     0,     0,  1516,     0,
+       0,  1520,     0,     0,     0,  1523,     0,     0,     0,   408,
+       0,   408,     0,     0,     0,     0,     0,     0,  1533,     0,
+    1140,  1535,   377,   378,   379,   380,   381,   382,   383,   384,
+     385,   386,   387,   388,   389,   390,  1157,     0,     0,     0,
+     391,     0,  1163,     0,     0,     0,     0,     0,  1168,   890,
+    1170,  1171,     0,  1557,     0,  1174,     0,  1603,     0,   891,
+    1179,  1180,  1181,     0,     0,     0,   408,   892,   893,   894,
+       0,     0,     0,   895,   896,   897,   898,  1198,   379,   380,
+     381,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+       0,     0,  1209,     0,   391,   506,  1213,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   102,   297,     0,
+       0,   409,     0,   105,   106,   107,     0,   409,   108,   109,
+     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
+     120,   121,   122,   123,   124,   125,   126,   127,   128,   129,
+     510,     0,     0,     0,     0,     0,     0,  1604,     0,   136,
+     137,   138,     0,     0,     0,   409,     0,     0,   141,   142,
+     143,     0,     0,     0,     0,  1249,   144,   102,   297,     0,
+       0,     0,     0,   105,   106,   107,   409,     0,   108,   109,
+     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
+     120,   121,   122,   123,   124,   125,   126,   127,   128,   129,
+       0,     0,     0,     0,     0,  1281,  1282,  1283,  1284,   136,
+     137,   138,     0,     0,     0,     0,     0,     0,   141,   142,
+     143,     0,     0,     0,     0,     0,   144,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,     0,     0,
+    1140,     0,   391,     0,     0,     0,   147,     0,     0,     0,
+       0,     0,  1324,   150,   151,   152,   153,   154,     0,  1333,
+       0,  1334,     0,     0,     0,  1337,     0,     0,     0,  1216,
+       0,   155,   156,   409,     0,   409,   157,     0,     0,     0,
+       0,   269,     0,     0,  1352,     0,   161,     0,  1232,     0,
+     377,   378,   379,   380,   381,   382,   383,   384,   385,   386,
+     387,   511,   389,   390,     0,  1140,   147,  1343,   391,     0,
+       0,     0,     0,   150,   151,   152,   153,   154,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     409,   155,   156,     0,     0,     0,   157,     0,     0,  1389,
+       0,   269,     0,     0,   362,     0,   161,     0,   102,   103,
+     104,     0,     0,     0,   105,   106,   107,     0,     0,   108,
      109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
      119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
-     129,     0,     0,   937,  1282,     0,  1283,   416,     0,   416,
-     136,   137,   138,   938,     0,     0,     0,   140,   141,     0,
-       0,   939,   940,   941,     0,     0,     0,   942,   943,   944,
-     945,     0,     0,     0,     0,     0,     0,   416,   416,   416,
-     416,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-    1327,  1328,  1329,  1330,     0,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,   416,     0,     0,     0,
-       0,     0,     0,     0,     0,  1188,     0,     0,     0,  1628,
-       0,     0,     0,   143,     0,  1065,     0,     0,  1370,     0,
-     146,   147,   148,     0,     0,  1379,     0,     0,     0,     0,
-       0,     0,  1262,     0,  1116,     0,   149,   150,     0,     0,
-       0,   151,     0,     0,     0,     0,   261,  1392,     0,   372,
-       0,   155,     0,   373,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   102,   252,     0,     0,  1188,     0,
+     129,     0,     0,  1140,   130,   131,   132,   133,   134,   135,
+     136,   137,   138,     0,     0,     0,   139,   140,     0,   141,
+     142,   143,     0,  1140,     0,     0,     0,   144,   145,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+    1447,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+     377,   378,   379,   380,   381,   382,   383,   384,   385,   386,
+     387,   388,   389,   390,     0,     0,     0,     0,   391,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,  1486,     0,   391,     0,     0,
+       0,   146,     0,     0,     0,     0,     0,   147,   148,   149,
+       0,     0,     0,     0,   150,   151,   152,   153,   154,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   155,   156,     0,     0,     0,   157,     0,     0,
+       0,     0,   158,     0,   159,     0,   160,   161,     0,   162,
+       0,   163,     0,  1140,   102,   260,     0,     0,     0,     0,
      105,   106,   107,     0,     0,   108,   109,   110,   111,   112,
      113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
-     123,   124,   125,   126,   127,   128,   129,   254,     0,     0,
-       0,     0,  1429,     0,     0,     0,   136,   137,   138,     0,
-       0,     0,     0,   140,   141,     0,     0,     0,   937,     0,
-       0,   255,     0,     0,   256,     0,     0,   257,   938,   258,
-       0,     0,     0,     0,     0,     0,   939,   940,   941,     0,
-    1188,   259,   942,   943,   944,   945,     0,     0,    44,    45,
-      46,    47,    48,     0,     0,     0,    52,     0,     0,    55,
-    1188,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,  1483,     0,   399,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,   143,
-       0,     0,     0,     0,     0,     0,   146,   147,   148,     0,
-     416,     0,     0,     0,  1630,     0,     0,     0,     0,  1168,
-       0,     0,   469,  1360,   937,     0,     0,   151,  1522,     0,
-       0,     0,   471,     0,   938,     0,     0,   155,     0,   221,
-     515,     0,   939,   940,   941,     0,   102,   252,   942,   943,
-     944,   945,   105,   106,   107,     0,     0,   108,   109,   110,
-     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
-     121,   122,   123,   124,   125,   126,   127,   128,   129,   254,
-    1175,     0,     0,     0,  1188,     0,  1572,     0,   136,   137,
-     138,  1442,     0,     0,     0,   140,   141,     0,     0,     0,
-       0,     0,     0,   255,     0,     0,   256,     0,     0,   257,
-       0,   258,     0,     0,     0,     0,     0,     0,     0,     0,
-    1652,     0,     0,   259,     0,     0,     0,     0,     0,  1467,
-      44,    45,    46,    47,    48,     0,     0,     0,    52,     0,
-       0,    55,     0,     7,     8,     0,     0,     0,     0,   416,
-    1488,     0,     0,   416,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,  1188,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,   143,     0,   399,     0,     0,     0,     0,   146,   147,
-     148,   621,    20,    21,   622,    23,    24,   623,    26,   624,
-      28,     0,    29,     0,   149,   414,     0,    34,    35,   151,
-      37,    38,    39,     0,   261,     0,    42,     0,     0,   155,
-       0,     0,   515,     0,     0,     0,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,  1562,   399,  1565,     0,     0,     0,    63,
-      64,    65,     0,   513,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,   416,
-       0,     0,   102,   289,     0,     0,     0,     0,   105,   106,
-     107,     0,     0,   108,   109,   110,   111,   112,   113,   114,
-     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
-     125,   126,   127,   128,   129,  1612,     0,   416,     0,     0,
-     926,     0,     0,     0,   136,   137,   138,     0,   102,   252,
-     104,   140,   141,     0,   105,   106,   107,     0,   416,   108,
-     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
-     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
-     129,   254,     0,     0,   130,   131,   132,   133,   134,   135,
-     136,   137,   138,     0,     0,     0,   139,   140,   141,     0,
-       0,     0,   937,     0,     0,   255,     0,     0,   256,     0,
-       0,   257,   938,   258,     0,     0,     0,     0,     0,     0,
-     939,   940,   941,     0,     0,   259,   942,   943,   944,   945,
-       0,     0,    44,    45,    46,    47,    48,   143,     0,     0,
-      52,     0,     0,    55,   146,   147,   148,     0,     0,     0,
-       0,   416,     0,   416,     0,     0,     0,     0,     0,     0,
-     149,   150,   937,     0,     0,   151,     0,     0,     0,     0,
-     261,     0,   938,   738,     0,   155,     0,   739,     0,     0,
-     939,   940,   941,   143,   144,   145,   942,   943,   944,   945,
-     146,   147,   148,     0,   416,     0,     0,     0,  1653,     0,
-       0,     0,     0,     0,     0,     0,   149,   260,     0,     0,
-       0,   151,     0,   416,     0,     0,   261,     0,   102,   252,
-     253,   155,     0,  1571,   105,   106,   107,     0,     0,   108,
-     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
-     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
-     129,   254,     0,     0,     0,     0,     0,     0,  1654,     0,
-     136,   137,   138,     0,     0,     0,     0,   140,   141,     0,
-       0,     0,     0,     0,     0,   255,     0,     0,   256,     0,
-       0,   257,     0,   258,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   259,     0,     0,     0,     0,
+     123,   124,   125,   126,   127,   128,   129,   262,     0,     0,
+       0,     0,     0,     0,     0,     0,   136,   137,   138,     0,
+       0,     0,     0,     7,     8,   141,   142,   143,     0,     0,
+       0,     0,     0,   144,     0,   263,     0,     0,   264,     0,
+       0,   265,     0,   266,  1140,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   267,     0,     0,     0,     0,
        0,     0,    44,    45,    46,    47,    48,     0,     0,     0,
-      52,     0,     0,    55,     0,   102,   252,  1255,     0,     0,
-       0,   105,   106,   107,     0,     0,   108,   109,   110,   111,
-     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
-     122,   123,   124,   125,   126,   127,   128,   129,   254,     0,
-       0,     0,     0,   143,     0,     0,     0,   136,   137,   138,
-     146,   147,   148,     0,   140,   141,     0,     0,     0,     0,
-       0,     0,   255,     0,     0,   256,   149,   260,   257,     0,
-     258,   151,     0,     0,     0,     0,   261,     0,     0,     0,
-       0,   155,   259,   262,     0,     0,     0,     0,     0,    44,
+      52,     0,     0,    55,     0,   593,    20,    21,   594,    23,
+      24,   595,    26,   596,    28,     0,    29,     0,     0,     0,
+       0,    34,    35,     0,    37,    38,    39,     0,     0,     0,
+      42,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   147,     0,     0,     0,     0,     0,     0,
+     150,   151,   152,   153,   154,     0,     0,     0,     0,     0,
+       0,     0,     0,    63,    64,    65,     0,     0,   462,  1314,
+       0,     0,     0,   157,     0,     0,     0,     0,   464,     0,
+       0,   102,   260,   161,     0,   229,   508,   105,   106,   107,
+       0,     0,   108,   109,   110,   111,   112,   113,   114,   115,
+     116,   117,   118,   119,   120,   121,   122,   123,   124,   125,
+     126,   127,   128,   129,   262,     0,     0,     0,     0,     0,
+       0,     0,     0,   136,   137,   138,   937,     0,     0,     0,
+       0,     0,   141,   142,   143,     0,     0,     7,     8,     0,
+     144,     0,   263,     0,     0,   264,     0,     0,   265,     0,
+     266,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,   267,     0,     0,     0,     0,     0,     0,    44,
       45,    46,    47,    48,     0,     0,     0,    52,     0,     0,
-      55,     0,   102,   252,     0,     0,     0,     0,   105,   106,
-     107,     0,     0,   108,   109,   110,   111,   112,   113,   114,
-     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
-     125,   126,   127,   128,   129,   254,     0,     0,     0,     0,
-     143,     0,     0,     0,   136,   137,   138,   146,   147,   148,
-       0,   140,   141,     0,     0,     0,     0,     0,     0,   255,
-       0,     0,   256,   149,   260,   257,     0,   258,   151,     0,
-       0,     0,     0,   261,     0,     0,     0,     0,   155,   259,
-    1256,     0,     0,     0,     0,     0,    44,    45,    46,    47,
-      48,     0,     0,     0,    52,     0,     0,    55,     0,   102,
-     252,     0,     0,     0,     0,   105,   106,   107,     0,     0,
-     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
-     118,   119,   120,   121,   122,   123,   124,   125,   126,   127,
-     128,   129,   254,     0,     0,     0,     0,   143,     0,     0,
-       0,   136,   137,   138,   146,   147,   148,     0,   140,   141,
-       0,     0,     0,     0,     0,     0,   255,     0,     0,   256,
-     149,   260,   257,     0,   258,   151,     0,     0,     0,     0,
-     261,     0,     0,     0,     0,   155,   259,   262,     0,     0,
-       0,     0,     0,    44,    45,    46,    47,    48,     0,     0,
-       0,    52,     0,     0,    55,     0,   102,   252,     0,     0,
-       0,     0,   105,   106,   107,     0,     0,   108,   109,   110,
-     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
-     121,   122,   123,   124,   125,   126,   127,   128,   129,   254,
-       0,     0,     0,     0,   143,     0,     0,     0,   136,   137,
-     138,   146,   147,   148,     0,   140,   141,     0,     0,     0,
-       0,     0,     0,   255,     0,     0,   256,   149,   414,   257,
-       0,   258,   151,     0,     0,     0,     0,   261,     0,     0,
-       0,     0,   155,   259,   511,     0,     0,     0,     0,     0,
-      44,    45,    46,    47,    48,     0,     0,     0,    52,     0,
-       0,    55,     0,   102,   252,     0,     0,     0,     0,   105,
-     106,   107,     0,     0,   108,   109,   110,   111,   112,   113,
-     114,   115,   116,   117,   118,   119,   120,   121,   122,   123,
-     124,   125,   126,   127,   128,   129,   254,     0,     0,     0,
-       0,   143,     0,     0,     0,   136,   137,   138,   146,   147,
-     148,     0,   140,   141,     0,     0,     0,     0,     0,     0,
-     255,     0,     0,   256,   149,   414,   257,     0,   258,   151,
-       0,     0,     0,     0,   261,     0,     0,     0,     0,   155,
-     259,   752,     0,     0,     0,     0,     0,    44,    45,    46,
-      47,    48,     0,     0,     0,    52,     0,     0,    55,     0,
-     102,   252,     0,     0,     0,     0,   105,   106,   107,     0,
+      55,     0,     0,     0,     0,     0,     0,     0,     0,   593,
+      20,    21,   594,    23,    24,   595,    26,   596,    28,     0,
+      29,     0,     0,     0,     0,    34,    35,     0,    37,    38,
+      39,     0,  1375,     0,    42,     0,     0,     0,     0,     0,
+     147,     0,     0,     0,     0,     0,     0,   150,   151,   152,
+     153,   154,  1403,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   155,   407,    63,    64,    65,
+     157,     0,     0,     0,     0,   269,     0,     0,     0,     0,
+     161,     0,     0,   508,   102,   260,   104,     0,     0,     0,
+     105,   106,   107,     0,     0,   108,   109,   110,   111,   112,
+     113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
+     123,   124,   125,   126,   127,   128,   129,   262,     0,     0,
+     130,   131,   132,   133,   134,   135,   136,   137,   138,     0,
+    1036,     0,   139,   140,     0,   141,   142,   143,     0,     0,
+       0,     0,     0,   144,   145,   263,     0,     0,   264,     0,
+       0,   265,     0,   266,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   267,     0,     0,     0,     0,
+       0,     0,    44,    45,    46,    47,    48,     0,     0,     0,
+      52,     0,     0,    55,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,     0,     0,
+       0,     0,   391,     0,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,     0,     0,
+       0,     0,   391,   147,   148,   149,     0,     0,     0,     0,
+     150,   151,   152,   153,   154,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   155,   268,
+       0,     0,     0,   157,     0,     0,     0,     0,   269,     0,
+     102,   260,   261,   161,     0,  1336,   105,   106,   107,     0,
        0,   108,   109,   110,   111,   112,   113,   114,   115,   116,
      117,   118,   119,   120,   121,   122,   123,   124,   125,   126,
-     127,   128,   129,   254,     0,     0,     0,     0,   143,     0,
-       0,     0,   136,   137,   138,   146,   147,   148,     0,   140,
-     141,     0,     0,     0,     0,     0,     0,   255,     7,     8,
-     256,   149,   260,   257,     0,   258,   151,     0,     0,     0,
-       0,   261,     0,     0,     0,     0,   155,   259,  1260,     0,
+     127,   128,   129,   262,     0,     0,     0,     0,     0,     0,
+       0,     0,   136,   137,   138,     0,     0,     0,     7,     8,
+       0,   141,   142,   143,     0,     0,     0,     0,     0,   144,
+       0,   263,     0,     0,   264,     0,     0,   265,     0,   266,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,   267,     0,     0,     0,     0,     0,     0,    44,    45,
+      46,    47,    48,     0,     0,     0,    52,     0,     0,    55,
+     593,    20,    21,   594,    23,    24,   595,    26,   596,    28,
+       0,    29,     0,     0,     0,     0,    34,    35,     0,    37,
+      38,    39,     0,     0,     0,    42,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   147,
+       0,     0,     0,     0,     0,     0,   150,   151,   152,   153,
+     154,     0,     0,     0,     0,     0,     0,     0,    63,    64,
+      65,     0,     0,     0,   155,   268,     0,     0,     0,   157,
+       0,     0,     0,     0,   269,     0,   102,   260,  1207,   161,
+       0,   270,   105,   106,   107,     0,     0,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,   262,
+       0,     0,     0,     0,     0,     0,     0,     0,   136,   137,
+     138,  1489,     0,     0,     7,     8,     0,   141,   142,   143,
+       0,     0,     0,     0,     0,   144,     0,   263,     0,     0,
+     264,     0,     0,   265,     0,   266,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   267,     0,     0,
        0,     0,     0,     0,    44,    45,    46,    47,    48,     0,
-       0,     0,    52,     0,     0,    55,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,   621,    20,    21,   622,
-      23,    24,   623,    26,   624,    28,     0,    29,     0,     0,
+       0,     0,    52,     0,     0,    55,   593,    20,    21,   594,
+      23,    24,   595,    26,   596,    28,     0,    29,     0,     0,
        0,     0,    34,    35,     0,    37,    38,    39,     0,     0,
-       0,    42,     0,     0,     0,   143,     0,     0,     0,     0,
-       0,     0,   146,   147,   148,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   469,  1360,
-       0,     0,     0,   151,    63,    64,    65,     0,   471,     0,
-     102,   289,   104,   155,     0,   221,   105,   106,   107,     0,
-       0,   108,   109,   110,   111,   112,   113,   114,   115,   116,
-     117,   118,   119,   120,   121,   122,   123,   124,   125,   126,
-     127,   128,   129,     0,     0,     0,   130,   131,   132,   133,
-     134,   135,   136,   137,   138,   102,   289,   104,   139,   140,
-     141,   105,   106,   107,     0,   949,   108,   109,   110,   111,
-     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
-     122,   123,   124,   125,   126,   127,   128,   129,     0,     0,
-       0,   130,   131,   132,   133,   134,   135,   136,   137,   138,
-     102,   289,   104,   139,   140,   141,   105,   106,   107,     0,
-       0,   108,   109,   110,   111,   112,   113,   114,   115,   116,
-     117,   118,   119,   120,   121,   122,   123,   124,   125,   126,
-     127,   128,   129,     0,     0,     0,   130,   131,   132,   133,
-     134,   135,   136,   137,   138,   143,   144,   145,   139,   140,
-     141,     0,   146,   147,   148,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   149,   150,
-       0,     0,     0,   151,     0,     0,     0,     0,   261,     0,
-       0,     0,     0,   155,     0,  1196,     0,     0,     0,     0,
-     143,   144,   145,     0,     0,     0,     0,   146,   147,   148,
+    1495,    42,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   147,     0,     0,     0,  1544,
+       0,     0,   150,   151,   152,   153,   154,     0,     0,     0,
+       0,     0,     0,     0,    63,    64,    65,     0,     0,     0,
+     155,   268,     0,     0,     0,   157,     0,     0,     0,     0,
+     269,     0,   102,   260,     0,   161,     0,  1208,   105,   106,
+     107,     0,     0,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
+     125,   126,   127,   128,   129,   262,     0,     0,     0,     0,
+       0,     0,     0,     0,   136,   137,   138,  1546,     0,     0,
+       0,     0,     0,   141,   142,   143,     0,     0,     0,     0,
+       0,   144,     0,   263,     0,     0,   264,     0,     0,   265,
+       0,   266,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   267,     0,     0,     0,     0,     0,     0,
+      44,    45,    46,    47,    48,     0,     0,     0,    52,     0,
+       0,    55,   377,   378,   379,   380,   381,   382,   383,   384,
+     385,   386,   387,   388,   389,   390,     0,     0,     0,     0,
+     391,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,   510,     0,     0,     0,   391,
+       0,   147,     0,     0,     0,     0,     0,     0,   150,   151,
+     152,   153,   154,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   155,   268,     0,     0,
+       0,   157,     0,     0,     0,     0,   269,     0,   102,   260,
+       0,   161,     0,   270,   105,   106,   107,     0,     0,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   122,   123,   124,   125,   126,   127,   128,
+     129,   262,     0,     0,     0,     0,     0,     0,     0,     0,
+     136,   137,   138,     0,     0,     0,     0,     0,     0,   141,
+     142,   143,     0,     0,     0,     0,     0,   144,     0,   263,
+       0,     0,   264,     0,     0,   265,     0,   266,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   267,
+       0,     0,     0,     0,     0,     0,    44,    45,    46,    47,
+      48,     0,     0,     0,    52,     0,     0,    55,     0,     0,
+       0,     0,     0,     0,     0,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   631,   389,   390,     0,
+       0,     0,     0,   391,   736,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   147,     0,     0,
+       0,     0,     0,   812,   150,   151,   152,   153,   154,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   149,   150,     0,     0,     0,   151,     0,
-    1264,     0,     0,   261,     0,     0,     0,     0,   155,     0,
-    1376,     0,     0,     0,     0,   143,   144,   145,     0,  1384,
-       0,     0,   146,   147,   148,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   149,   150,
-       0,     0,     0,   151,     0,     0,     0,     0,   261,     0,
-     102,   289,     0,   155,     0,  1574,   105,   106,   107,     0,
+       0,     0,   155,   407,     0,     0,     0,   157,     0,     0,
+       0,     0,   269,     0,   102,   260,     0,   161,     0,   504,
+     105,   106,   107,     0,     0,   108,   109,   110,   111,   112,
+     113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
+     123,   124,   125,   126,   127,   128,   129,   262,     0,     0,
+       0,     0,     0,     0,     0,     0,   136,   137,   138,     0,
+       0,     0,     0,     0,     0,   141,   142,   143,     0,     0,
+       0,     0,     0,   144,     0,   263,     0,     0,   264,     0,
+       0,   265,     0,   266,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   267,     0,     0,     0,     0,
+       0,     0,    44,    45,    46,    47,    48,     0,     0,     0,
+      52,     0,     0,    55,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,     0,     0,
+       0,     0,   391,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,   930,     0,     0,
+       0,   391,     0,   147,     0,     0,     0,     0,     0,     0,
+     150,   151,   152,   153,   154,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   155,   407,
+       0,     0,     0,   157,     0,     0,     0,     0,   269,     0,
+     102,   260,     0,   161,     0,   726,   105,   106,   107,     0,
        0,   108,   109,   110,   111,   112,   113,   114,   115,   116,
      117,   118,   119,   120,   121,   122,   123,   124,   125,   126,
-     127,   128,   129,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   136,   137,   138,   102,   289,     0,     0,   140,
-     141,   105,   106,   107,     0,     0,   108,   109,   110,   111,
-     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
-     122,   123,   124,   125,   126,   127,   128,   129,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   136,   137,   138,
-       0,     0,     0,     0,   140,   141,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,   143,     0,     0,     0,     0,
-       0,     0,   146,   147,   148,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   149,   150,
-       0,     0,     0,   151,     0,     0,     0,     0,   261,     0,
-       0,     0,     0,   155,     0,   370,     0,     0,     0,     0,
-     143,     0,     0,     0,     0,     0,     0,   146,   147,   148,
+     127,   128,   129,   262,     0,     0,     0,     0,     0,     0,
+       0,     0,   136,   137,   138,     0,     0,     0,     0,     0,
+       0,   141,   142,   143,     0,     0,     0,     0,     0,   144,
+       0,   263,     0,     0,   264,     0,     0,   265,     0,   266,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   469,   470,     0,     0,     0,   151,     0,
-       0,     0,     0,   471,     0,   102,   252,     0,   155,     0,
-     221,   105,   106,   107,     0,     0,   108,   109,   110,   111,
-     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
-     122,   123,   124,   125,   126,   127,   128,   129,   254,     0,
-       0,     0,     0,     0,     0,     0,     0,   136,   137,   138,
-       0,     0,     0,     0,   140,   141,     0,     0,     0,     0,
-       0,     0,   255,     0,     0,   256,     0,     0,   257,     0,
-     258,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,   259,     0,     0,     0,     0,     0,     0,    44,
-      45,    46,    47,    48,     0,   102,   289,    52,     0,     0,
-      55,   105,   106,   107,     0,     0,   108,   109,   110,   111,
-     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
-     122,   123,   124,   125,   126,   127,   128,   129,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   136,   137,   138,
-     143,     0,     0,     0,   140,   141,     0,   146,   147,   148,
+       0,   267,     0,     0,     0,     0,     0,     0,    44,    45,
+      46,    47,    48,     0,     0,     0,    52,     0,     0,    55,
+       0,     0,     0,     0,     0,     0,     0,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,  1090,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   147,
+       0,     0,     0,     0,     0,     0,   150,   151,   152,   153,
+     154,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   155,   268,     0,     0,     0,   157,
+       0,     0,     0,     0,   269,     0,   102,   260,     0,   161,
+       0,  1212,   105,   106,   107,     0,     0,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,   262,
+       0,     0,     0,     0,     0,     0,     0,     0,   136,   137,
+     138,     0,     0,     0,  1022,     0,     0,   141,   142,   143,
+       0,     0,     0,     0,     0,   144,     0,   263,     0,     0,
+     264,     0,     0,   265,     0,   266,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   267,     0,     0,
+       0,     0,     0,     0,    44,    45,    46,    47,    48,     0,
+       0,     0,    52,     0,     0,    55,   377,   378,   379,   380,
+     381,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+       0,     0,     0,     0,   391,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,   147,     0,     0,     0,     0,
+       0,     0,   150,   151,   152,   153,   154,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   149,   414,     0,     0,     0,   151,   102,
-     289,   104,     0,   261,     0,   105,   106,   107,   155,     0,
-     108,   109,   110,   111,   112,   113,   114,   115,   116,   117,
-     118,   119,   120,   121,   122,   123,   124,   125,   126,   127,
-     128,   129,     0,     0,     0,   130,   131,   132,   133,   134,
-     135,   136,   137,   138,     0,     0,     0,   139,   140,   141,
-       0,     0,     0,     7,     8,     0,     0,     0,     0,     0,
-     143,     0,     0,     0,     0,     0,     0,   146,   147,   148,
+     462,  1314,     0,     0,     0,   157,     0,     0,     0,     0,
+     464,     0,   102,   297,   104,   161,     0,   229,   105,   106,
+     107,     0,     0,   108,   109,   110,   111,   112,   113,   114,
+     115,   116,   117,   118,   119,   120,   121,   122,   123,   124,
+     125,   126,   127,   128,   129,     0,     0,     0,   130,   131,
+     132,   133,   134,   135,   136,   137,   138,     0,     0,     0,
+     139,   140,     0,   141,   142,   143,     0,   102,   297,   104,
+       0,   144,   145,   105,   106,   107,     0,     0,   108,   109,
+     110,   111,   112,   113,   114,   115,   116,   117,   118,   119,
+     120,   121,   122,   123,   124,   125,   126,   127,   128,   129,
+       0,     0,     0,   130,   131,   132,   133,   134,   135,   136,
+     137,   138,     0,     0,     0,   139,   140,     0,   141,   142,
+     143,     0,     0,     0,     0,     0,   144,   145,     0,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,   147,   148,   149,  1294,     0,  1295,     0,   150,   151,
+     152,   153,   154,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   155,   156,     0,     0,
+       0,   157,     0,     0,     0,     0,   269,     0,     0,     0,
+       0,   161,     0,  1148,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   147,   148,   149,     0,
+       0,     0,     0,   150,   151,   152,   153,   154,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   149,   150,     0,     0,     0,   151,     0,
-    1415,     0,     0,   261,     0,     0,     0,     0,   155,     0,
-       0,   621,    20,    21,   622,    23,    24,   623,    26,   624,
-      28,     0,    29,     0,     0,     0,     0,    34,    35,     0,
-      37,    38,    39,     0,     0,     0,    42,     7,     8,     0,
-       0,     0,     0,     0,   143,   144,   145,     0,     0,     0,
-       0,   146,   147,   148,     0,     0,     0,     0,     0,  1443,
-       0,     0,     0,     0,     7,     8,     0,   149,   150,    63,
-      64,    65,   151,     0,     0,     0,     0,   261,     0,     0,
-       0,     0,   155,     0,     0,   621,    20,    21,   622,    23,
-      24,   623,    26,   624,    28,  1531,    29,     0,     0,     0,
-       0,    34,    35,     0,    37,    38,    39,     0,     0,     0,
-      42,     0,   621,    20,    21,   622,    23,    24,   623,    26,
-     624,    28,  1585,    29,     0,     0,     7,     8,    34,    35,
-     985,    37,    38,    39,     0,     0,     0,    42,     0,     0,
-       0,     0,     0,    63,    64,    65,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-    1621,   517,     0,     0,   399,     0,     0,     0,     0,     0,
-      63,    64,    65,     0,   621,    20,    21,   622,    23,    24,
-     623,    26,   624,    28,  1651,    29,     0,     0,     0,     0,
-      34,    35,     0,    37,    38,    39,     0,     0,     0,    42,
-       0,     0,     0,     0,  1085,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,   517,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-       0,  1525,    63,    64,    65,     0,     0,     0,   762,     0,
-       0,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,   859,     0,   399,
-       0,     0,     0,     0,     0,     0,     0,     0,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,   978,     0,     0,     0,   399,     0,     0,     0,
-       0,     0,     0,  1587,     0,     0,     0,     0,     0,     0,
-       0,  1140,     0,     0,     0,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   657,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
+       0,   155,   156,     0,     0,     0,   157,     0,     0,     0,
+       0,   269,     0,   102,   297,   104,   161,     0,  1330,   105,
+     106,   107,     0,     0,   108,   109,   110,   111,   112,   113,
+     114,   115,   116,   117,   118,   119,   120,   121,   122,   123,
+     124,   125,   126,   127,   128,   129,     0,     0,     0,   130,
+     131,   132,   133,   134,   135,   136,   137,   138,     0,     0,
+       0,   139,   140,     0,   141,   142,   143,     0,     0,     0,
+       0,     0,   144,   145,     0,     0,   102,   260,     0,     0,
+       0,     0,   105,   106,   107,     0,     0,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,   262,
+       0,     0,     0,     0,     0,     0,     0,     0,   136,   137,
+     138,     0,     0,     0,     0,     0,     0,   141,   142,   143,
+       0,     0,     0,     0,     0,   144,     0,   263,     0,     0,
+     264,     0,     0,   265,     0,   266,     0,     0,     0,     0,
+       0,     0,   147,   148,   149,     0,     0,   267,     0,   150,
+     151,   152,   153,   154,    44,    45,    46,    47,    48,     0,
+       0,     0,    52,     0,     0,    55,     0,   155,   156,     0,
+       0,     0,   157,     0,     0,     0,     0,   269,     0,     0,
+       0,     0,   161,     0,  1339,     0,     0,     0,     0,     0,
+     377,   378,   379,   380,   381,   382,   383,   384,   385,   386,
+     387,   388,   389,   390,     0,   147,     0,     0,   391,     0,
+       0,     0,   150,   151,   152,   153,   154,   810,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   657,   397,   398,     0,     0,     0,
-       0,   399,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-      -4,     1,     0,   399,    -4,     0,     0,     0,     0,     0,
-       0,     0,    -4,    -4,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,     0,     0,     0,    -4,    -4,  1340,
-       0,  1341,     0,     0,     0,     0,     0,     0,    -4,    -4,
-      -4,     0,     0,     0,    -4,    -4,    -4,     0,    -4,    -4,
+     155,   407,     0,     0,     0,   157,   102,   297,   104,     0,
+     269,     0,   105,   106,   107,   161,     0,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,     0,
+       0,     0,   130,   131,   132,   133,   134,   135,   136,   137,
+     138,     0,     0,     0,   139,   140,     0,   141,   142,   143,
+       0,     0,     0,     0,     0,   144,   145,   319,   320,   321,
+     322,   323,   324,   325,   326,   327,   328,   329,   330,   331,
+     332,   333,   334,   335,   336,   337,   338,   339,   340,   341,
+     342,   343,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,   350,   351,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+    1325,     0,  1326,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   147,   148,   149,     0,     0,
+       0,     0,   150,   151,   152,   153,   154,     0,     0,     0,
+      -4,     1,     0,     0,    -4,     0,     0,     0,     0,     0,
+     155,   156,    -4,    -4,     0,   157,     0,     0,     0,     0,
+     269,     0,     0,     0,     0,   161,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,    -4,    -4,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    -4,    -4,
+      -4,     0,     0,    -4,     0,     0,     0,    -4,    -4,   493,
+      -4,    -4,     0,     0,    -4,    -4,    -4,    -4,    -4,    -4,
+      -4,    -4,    -4,    -4,     0,    -4,    -4,    -4,    -4,    -4,
+      -4,    -4,    -4,    -4,    -4,    -4,    -4,     0,    -4,    -4,
       -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4,
+      -4,    -4,    -4,    -4,    -4,     0,     0,     0,    -4,    -4,
+      -4,     0,     0,     0,     0,     0,    -4,     6,     0,     0,
+       0,    -4,    -4,    -4,    -4,     7,     8,    -4,     0,    -4,
        0,    -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4,
-      -4,    -4,    -4,     0,    -4,    -4,    -4,    -4,    -4,    -4,
-      -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4,
-      -4,     0,     0,     0,    -4,    -4,    -4,     0,     0,     0,
-       0,     0,    -4,     6,     0,     0,     0,    -4,    -4,    -4,
-      -4,     7,     8,    -4,     0,    -4,     0,    -4,    -4,    -4,
-      -4,    -4,    -4,    -4,    -4,    -4,    -4,    -4,     0,     0,
-       0,    -4,    -4,    -4,    -4,     0,     9,    10,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,    11,    12,    13,
-       0,     0,     0,    14,    15,    16,     0,    17,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,     0,
-      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
-      39,    40,     0,    41,    42,    43,    44,    45,    46,    47,
-      48,    49,    50,    51,    52,    53,    54,    55,    56,    57,
-       7,     8,     0,    58,    59,    60,  1071,     0,     0,     0,
-       0,    61,     0,     0,     0,     0,    62,    63,    64,    65,
-       0,     0,    66,     0,    67,     0,    68,    69,    70,    71,
-      72,    73,    74,    75,    76,    77,    78,     0,     0,     0,
-      79,    80,    81,    82,     0,     0,     0,     0,   621,    20,
-      21,   622,    23,    24,   623,    26,   624,    28,     0,    29,
-       0,     0,     0,     0,    34,    35,     0,    37,    38,    39,
-       0,     0,     0,    42,     0,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,    63,    64,    65,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,  1371,     0,  1372,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,  1469,     0,  1470,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-       0,     0,   858,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,     0,     0,
-     902,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,     0,     0,   952,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,     0,     0,   972,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,     0,     0,   993,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-       0,     0,  1089,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,     0,     0,
-    1338,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,     0,     0,  1357,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,     0,     0,  1400,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,     0,     0,  1401,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-       0,     0,  1402,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,     0,     0,
-    1403,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,     0,     0,  1404,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,     0,     0,  1438,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,     0,     0,  1485,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-       0,     0,  1491,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,     0,     0,
-    1492,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,     0,     0,  1513,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,     0,     0,  1516,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,     0,     0,  1519,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-       0,     0,  1542,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,     0,     0,
-    1545,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,     0,     0,  1579,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,     0,     0,  1581,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,     0,     0,  1583,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-       0,     0,  1596,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,     0,     0,
-    1623,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,     0,   693,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,     0,     0,
-       0,     0,     0,     0,  1414,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,   749,     0,     0,     0,     0,
-     700,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,   650,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,   700,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,   701,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,   759,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-     798,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,   799,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,   814,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,   815,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,   816,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-     817,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,   818,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,   819,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,   934,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,   935,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-     936,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,   967,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,  1048,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,  1087,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,  1088,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-    1139,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,  1298,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,  1299,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,  1306,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,  1450,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,     0,     0,     0,
-    1451,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,     0,     0,     0,  1455,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,     0,
-       0,     0,  1535,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,     0,     0,     0,  1538,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,     0,     0,     0,  1577,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,   613,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,     0,     0,
-     764,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,   774,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,     0,     0,   777,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,   779,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,     0,
-       0,     0,   781,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,   783,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,     0,     0,     0,   785,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,   787,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,     0,     0,     0,   789,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,   791,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,     0,     0,
-     793,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,   795,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,     0,     0,   797,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,   801,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,     0,
-       0,     0,   803,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,   805,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,     0,     0,     0,   807,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,   809,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,     0,     0,     0,   811,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,   813,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,     0,     0,
-     960,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,   961,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,     0,     0,   965,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,   966,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,     0,
-       0,     0,   970,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,     0,     0,   994,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,     0,     0,     0,  1043,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,     0,
-       0,  1151,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,     0,     0,     0,  1153,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,     0,     0,  1155,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,     0,     0,
-    1157,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,     0,     0,  1265,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,     0,     0,  1290,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,     0,     0,  1427,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,     0,
-     609,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,   656,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,     0,   660,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,   661,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,   663,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,   665,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,     0,   666,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,   669,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,   670,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,   749,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,     0,
-     755,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,   756,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,     0,   757,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,   763,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,   776,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,   778,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,     0,   780,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,   782,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,   784,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,   786,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,     0,
-     788,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,   790,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,     0,   792,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,   794,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,   796,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,   800,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,     0,   802,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,   804,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,   806,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,   808,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,     0,
-     810,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,   812,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,     0,   891,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,   896,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,   901,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,   904,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,     0,   905,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,   911,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,   918,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,   919,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,     0,
-     920,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,   951,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,     0,   953,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,   954,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,   955,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,   959,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399,     0,  1150,   385,   386,   387,
-     388,   389,   390,   391,   392,   393,   394,   395,   396,   397,
-     398,     0,     0,     0,     0,   399,     0,  1152,   385,   386,
-     387,   388,   389,   390,   391,   392,   393,   394,   395,   396,
-     397,   398,     0,     0,     0,     0,   399,     0,  1154,   385,
-     386,   387,   388,   389,   390,   391,   392,   393,   394,   395,
-     396,   397,   398,     0,     0,     0,     0,   399,     0,  1156,
-     385,   386,   387,   388,   389,   390,   391,   392,   393,   394,
-     395,   396,   397,   398,     0,     0,     0,     0,   399,     0,
-    1165,   385,   386,   387,   388,   389,   390,   391,   392,   393,
-     394,   395,   396,   397,   398,     0,     0,     0,     0,   399,
-       0,  1339,   385,   386,   387,   388,   389,   390,   391,   392,
-     393,   394,   395,   396,   397,   398,     0,     0,     0,     0,
-     399,     0,  1356,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,     0,     0,     0,
-       0,   399,     0,  1375,   385,   386,   387,   388,   389,   390,
-     391,   392,   393,   394,   395,   396,   397,   398,     0,     0,
-       0,     0,   399,     0,  1534,   385,   386,   387,   388,   389,
-     390,   391,   392,   393,   394,   395,   396,   397,   398,     0,
-       0,     0,     0,   399,     0,  1594,   385,   386,   387,   388,
-     389,   390,   391,   392,   393,   394,   395,   396,   397,   398,
-       0,     0,     0,     0,   399
+      -4,    -4,     0,     0,     0,    -4,    -4,    -4,    -4,     0,
+       9,    10,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    11,    12,    13,     0,     0,    14,     0,     0,     0,
+      15,    16,     0,    17,    18,     0,     0,    19,    20,    21,
+      22,    23,    24,    25,    26,    27,    28,     0,    29,    30,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+       0,    41,    42,    43,    44,    45,    46,    47,    48,    49,
+      50,    51,    52,    53,    54,    55,    56,    57,     7,     8,
+       0,    58,    59,    60,     0,     0,     0,     0,     0,    61,
+       0,     0,     0,     0,    62,    63,    64,    65,     0,     0,
+      66,     0,    67,     0,    68,    69,    70,    71,    72,    73,
+      74,    75,    76,    77,    78,     0,     0,     0,    79,    80,
+      81,    82,     0,     0,     0,     0,     0,     0,     0,     0,
+     593,    20,    21,   594,    23,    24,   595,    26,   596,    28,
+       0,    29,     0,     0,     0,     0,    34,    35,     0,    37,
+      38,    39,     0,     0,     0,    42,   377,   378,   379,   380,
+     381,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+       0,     0,     0,     0,   391,     0,     0,     0,     0,     0,
+       0,  1433,     0,  1434,     0,     0,     0,     0,    63,    64,
+      65,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,     0,     0,   855,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,     0,     0,   905,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,     0,     0,   924,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+       0,     0,   948,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,     0,     0,
+    1040,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,     0,     0,  1292,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,     0,     0,  1311,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,     0,     0,  1360,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+       0,     0,  1361,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,     0,     0,
+    1362,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,     0,     0,  1363,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,     0,     0,  1364,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,     0,     0,  1398,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+       0,     0,  1449,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,     0,     0,
+    1455,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,     0,     0,  1456,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,     0,     0,  1477,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,     0,     0,  1480,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+       0,     0,  1483,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,     0,     0,
+    1506,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,     0,     0,  1509,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,     0,     0,  1538,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,     0,     0,  1540,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+       0,     0,  1542,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,     0,     0,
+    1556,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,     0,     0,  1576,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,     0,   667,   377,   378,   379,   380,
+     381,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+       0,     0,     0,     0,   391,     0,     0,     0,     0,     0,
+       0,     0,  1374,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,   723,     0,     0,     0,     0,   674,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,   624,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+     674,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,   675,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,   733,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,   763,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,   771,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+     772,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,   773,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,   887,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,   888,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,   889,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+     920,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,   999,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,  1038,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,  1039,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,  1089,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+    1252,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,  1253,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,  1260,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,  1414,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,     0,     0,     0,  1415,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,     0,     0,     0,
+    1419,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,     0,     0,     0,  1501,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,     0,
+       0,     0,  1504,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,     0,     0,     0,  1536,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,   712,
+       0,   713,   377,   378,   379,   380,   381,   382,   383,   384,
+     385,   386,   387,   388,   389,   390,     0,     0,     0,     0,
+     391,     0,     0,     0,   585,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,   738,   377,   378,
+     379,   380,   381,   382,   383,   384,   385,   386,   387,   388,
+     389,   390,     0,     0,     0,     0,   391,     0,     0,     0,
+     745,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,   750,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,     0,     0,
+       0,     0,   391,     0,     0,     0,   824,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,     0,     0,   913,
+     377,   378,   379,   380,   381,   382,   383,   384,   385,   386,
+     387,   388,   389,   390,     0,     0,     0,     0,   391,     0,
+       0,     0,   914,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,     0,     0,   918,   377,   378,   379,   380,
+     381,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+       0,     0,     0,     0,   391,     0,     0,     0,   919,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,     0,
+       0,   921,   377,   378,   379,   380,   381,   382,   383,   384,
+     385,   386,   387,   388,   389,   390,     0,     0,     0,     0,
+     391,     0,     0,     0,   949,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,     0,     0,   994,   377,   378,
+     379,   380,   381,   382,   383,   384,   385,   386,   387,   388,
+     389,   390,     0,     0,     0,     0,   391,     0,     0,     0,
+    1217,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,     0,     0,  1243,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,     0,     0,
+       0,     0,   391,     0,     0,     0,  1387,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,   582,   377,   378,
+     379,   380,   381,   382,   383,   384,   385,   386,   387,   388,
+     389,   390,     0,     0,     0,     0,   391,     0,   630,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,   634,
+     377,   378,   379,   380,   381,   382,   383,   384,   385,   386,
+     387,   388,   389,   390,     0,     0,     0,     0,   391,     0,
+     635,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,   637,   377,   378,   379,   380,   381,   382,   383,   384,
+     385,   386,   387,   388,   389,   390,     0,     0,     0,     0,
+     391,     0,   639,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,   640,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,     0,     0,
+       0,     0,   391,     0,   643,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,   644,   377,   378,   379,   380,
+     381,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+       0,     0,     0,     0,   391,     0,   723,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,   729,   377,   378,
+     379,   380,   381,   382,   383,   384,   385,   386,   387,   388,
+     389,   390,     0,     0,     0,     0,   391,     0,   730,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,   731,
+     377,   378,   379,   380,   381,   382,   383,   384,   385,   386,
+     387,   388,   389,   390,     0,     0,     0,     0,   391,     0,
+     737,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,   844,   377,   378,   379,   380,   381,   382,   383,   384,
+     385,   386,   387,   388,   389,   390,     0,     0,     0,     0,
+     391,     0,   849,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,   854,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,     0,     0,
+       0,     0,   391,     0,   857,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,   858,   377,   378,   379,   380,
+     381,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+       0,     0,     0,     0,   391,     0,   864,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,   871,   377,   378,
+     379,   380,   381,   382,   383,   384,   385,   386,   387,   388,
+     389,   390,     0,     0,     0,     0,   391,     0,   872,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,   873,
+     377,   378,   379,   380,   381,   382,   383,   384,   385,   386,
+     387,   388,   389,   390,     0,     0,     0,     0,   391,     0,
+     904,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391,
+       0,   906,   377,   378,   379,   380,   381,   382,   383,   384,
+     385,   386,   387,   388,   389,   390,     0,     0,     0,     0,
+     391,     0,   907,   377,   378,   379,   380,   381,   382,   383,
+     384,   385,   386,   387,   388,   389,   390,     0,     0,     0,
+       0,   391,     0,   908,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,     0,     0,
+       0,     0,   391,     0,   912,   377,   378,   379,   380,   381,
+     382,   383,   384,   385,   386,   387,   388,   389,   390,     0,
+       0,     0,     0,   391,     0,  1118,   377,   378,   379,   380,
+     381,   382,   383,   384,   385,   386,   387,   388,   389,   390,
+       0,     0,     0,     0,   391,     0,  1293,   377,   378,   379,
+     380,   381,   382,   383,   384,   385,   386,   387,   388,   389,
+     390,     0,     0,     0,     0,   391,     0,  1310,   377,   378,
+     379,   380,   381,   382,   383,   384,   385,   386,   387,   388,
+     389,   390,     0,     0,     0,     0,   391,     0,  1329,   377,
+     378,   379,   380,   381,   382,   383,   384,   385,   386,   387,
+     388,   389,   390,     0,     0,     0,     0,   391,     0,  1500,
+     377,   378,   379,   380,   381,   382,   383,   384,   385,   386,
+     387,   388,   389,   390,     0,     0,     0,     0,   391,     0,
+    1554,   377,   378,   379,   380,   381,   382,   383,   384,   385,
+     386,   387,   388,   389,   390,     0,     0,     0,     0,   391
 };
 
 static const yytype_int16 yycheck[] =
 {
-       3,     6,   352,     6,     3,     7,   229,   463,   464,     4,
-       4,    66,   362,   101,   214,  1258,   372,     6,   241,   375,
-       4,     4,     4,     4,     4,     4,     4,   950,     5,     5,
-       5,   171,     6,     6,     6,     6,    45,    46,   178,    48,
-       6,   161,   162,     4,     6,     6,     4,     5,     4,     4,
-      66,     4,    68,     6,     6,     4,   123,   177,     6,   179,
-       6,     6,   172,   286,     6,   288,   168,   169,   178,   136,
-     137,   161,   162,   171,   161,   162,   178,   171,  1321,   173,
-     178,    39,    40,    41,    42,    43,    44,   177,   174,   179,
-     177,   177,   179,    51,     7,   161,   162,   946,   161,   162,
-      63,     7,   171,    66,     3,     4,     5,    60,     0,   178,
-       9,    10,    11,   179,   177,    14,    15,    16,    17,    18,
+       3,   349,   237,     6,     4,     4,     3,   456,   457,     4,
+     362,   903,   364,     4,   249,   899,     4,     3,   222,     4,
+    1210,     4,     4,     4,    13,     5,     5,     5,   177,   101,
+       6,     6,     6,     6,     6,   184,     6,     6,     4,     6,
+       4,     6,     6,     4,     7,     4,    64,     0,     6,    67,
+       4,     6,    70,   174,   175,     6,     4,   179,     6,   294,
+      70,   296,    72,   184,   186,   542,   543,   544,   545,   546,
+     547,   548,   549,   550,   551,   552,    70,   554,   555,   556,
+     557,   558,   559,   560,   177,  1275,   179,     7,   565,   566,
+     167,   168,   178,   202,   203,   204,   177,   183,   207,   208,
+     209,   167,   168,     8,   167,   168,   183,   183,   185,   185,
+      64,   167,   168,     6,    68,    67,    64,   183,    70,   185,
+      72,   184,   117,   118,   119,   120,    80,   185,    67,   185,
+     177,    70,   190,     4,   243,   244,   194,   167,   168,    67,
+     115,     7,    70,   201,     8,   136,   255,   256,     6,   167,
+     168,   167,   168,   183,   183,   185,   185,   115,   161,   177,
+     115,   127,   128,  1353,   115,   162,   184,   183,   127,   128,
+     173,   174,   174,   175,   178,   161,   180,  1061,   177,   179,
+     184,   181,   184,  1373,     6,   184,   186,   173,   174,   177,
+     185,   167,   168,   184,     6,   164,   184,   164,    70,   184,
+      72,   184,   184,   184,   184,   184,   184,   177,   173,   174,
+     184,   184,   447,   448,   184,   179,   177,    70,   181,    72,
+      91,    92,    93,    94,     7,   167,   168,   127,    99,     6,
+     582,   102,   467,   585,   154,   155,   156,   157,   174,   175,
+     140,   141,   184,     6,   169,   170,   171,     6,   184,    45,
+      46,   176,    48,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,   177,   167,   168,
+     179,   176,     7,   177,   184,   179,   167,   168,   177,   177,
+     185,   183,   186,   185,   519,   184,   184,   179,   154,   155,
+     156,   157,   364,   184,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,   174,   175,
+     167,   168,   176,  1503,    74,   181,   179,   375,   181,   167,
+     168,   185,   183,   186,   185,   177,   183,   167,   168,   169,
+     170,   171,   184,   177,   811,   183,   176,    70,   341,   342,
+     343,   344,   345,   346,   347,   348,   349,     7,     8,   178,
+     353,   354,   355,   356,   183,   341,   342,   343,   344,   345,
+     346,   347,   348,   349,   660,   661,   662,   353,   354,   355,
+     356,   154,   155,   156,   157,   174,   175,   342,   343,   344,
+     345,   346,   347,   348,  1574,   183,   177,   185,   353,   354,
+     355,   174,   175,   745,    70,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,   178,
+     177,   180,   305,   176,   183,     4,     5,   167,   168,   154,
+     155,   156,   157,     6,     7,   483,   484,   485,    64,   225,
+     226,    67,   177,   183,    70,   670,    72,   233,   178,   174,
+     175,   237,   179,   183,   181,   177,   504,     7,   177,   186,
+      39,    40,    41,    42,    43,    44,   167,   168,   351,   456,
+     457,     6,    51,    52,   357,    12,    13,   167,   168,   541,
+     180,   184,   183,   183,    63,   533,   953,   954,   955,   956,
+      70,   958,   959,   183,   174,   175,   963,   964,   167,   168,
+    1382,   181,  1384,   178,  1386,   180,   167,   168,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,   183,   585,   167,   168,   176,    64,    65,    66,
+      67,    68,    69,    70,    71,    72,    73,   183,    75,   185,
+     183,     4,     5,    80,    81,    70,    83,    84,    85,   183,
+      64,   185,    89,    67,   167,   168,    70,     7,   167,   168,
+       6,     7,   178,  1437,   143,   144,  1440,   183,   180,  1443,
+     183,   183,    72,   621,   183,   623,    39,    40,    41,    42,
+      43,    44,   183,     8,   185,   122,   123,   124,    51,    52,
+     177,   183,   178,   185,   180,   174,   175,   183,   167,   168,
+      63,   183,   181,   185,   154,   155,   156,   157,  1490,   803,
+      67,  1078,    67,    87,   183,    70,   178,    72,   180,   667,
+     183,   183,   185,    97,   174,   175,   184,   969,   167,   168,
+     178,   105,   106,   107,   627,   183,   629,   111,   112,   113,
+     114,   184,   178,   985,   183,   167,   168,   183,   185,   711,
+    1524,   627,   183,   629,   185,  1537,   183,  1539,   185,  1541,
+     183,   183,   185,   167,   168,  1547,   714,    70,   454,   455,
+     718,   719,   720,   721,   629,   183,   462,   185,   726,   183,
+     143,   144,    67,   745,  1558,   167,   168,  1561,   750,   183,
+    1564,   185,    67,  1567,   167,   168,  1578,   178,  1580,   180,
+    1582,   183,   183,   586,   154,   155,   156,   157,    70,   177,
+     183,   185,   177,   167,   168,   167,   168,  1591,   178,  1593,
+     180,  1595,     4,   183,   174,   175,     4,     4,   776,   183,
+     183,   183,   185,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,   177,     4,  1188,
+    1189,   176,   183,   178,   185,  1097,   177,   750,   806,   807,
+     808,   809,   824,     6,   177,   183,   179,   185,   181,     6,
+       4,   184,     6,   186,   750,     6,   659,   660,   661,   662,
+     177,   774,   976,   179,   183,   778,   185,     4,   781,   782,
+     783,     4,   183,    64,   185,   750,    67,   790,   774,    70,
+     177,    72,   778,   177,   177,   781,   782,   783,   856,    12,
+      13,     7,   177,   183,   790,   185,   183,   177,   185,   774,
+     183,     7,   185,   778,   177,   177,   781,   782,   783,   183,
+      87,   185,   183,   177,   185,   790,   829,   177,   177,    82,
+      97,   183,   183,   185,   185,   183,     4,   185,   105,   106,
+     107,     6,   184,   829,   111,   112,   113,   114,   183,   921,
+     185,    64,    65,    66,    67,    68,    69,    70,    71,    72,
+      73,   183,    75,   185,   829,   184,   184,    80,    81,    87,
+      83,    84,    85,   183,     6,   185,    89,   673,   183,    97,
+     185,   183,     6,   185,   680,   184,   177,   105,   106,   107,
+     686,   177,     6,   111,   112,   113,   114,   969,   183,   183,
+     185,   185,   155,   156,   157,   158,   159,     4,   177,   122,
+     123,   124,   183,   183,   185,   185,   177,   177,   185,   172,
+     183,   179,   185,   176,   183,  1129,   185,   183,  1377,   185,
+     184,   184,   185,   186,   187,   177,   189,   190,   191,   192,
+     177,   194,   195,   196,   183,   183,   185,   185,   201,   183,
+     179,   185,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,   219,   185,   177,   183,
+     176,   185,   185,   184,   177,   228,   229,   184,   183,   183,
+     185,   185,   184,   183,   237,   185,   184,   177,   177,   177,
+     177,  1339,   184,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,   184,   184,   179,
+    1068,   176,   179,   179,     5,   268,   269,   270,     5,     5,
+     181,    87,     6,     6,   184,   130,   279,   280,   281,  1101,
+     283,    97,     6,   286,   287,     6,     6,   290,   184,   105,
+     106,   107,   838,   184,     6,   111,   112,   113,   114,   179,
+     303,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+       4,   176,   315,   181,   176,     7,   319,   320,   321,   322,
+     323,   324,   325,   326,   327,   328,   329,   330,   331,   332,
+     333,   334,   335,   336,   337,   338,   339,   340,   186,   179,
+      87,   887,   888,   889,   186,   184,     7,   350,   185,   352,
+      97,     6,     6,     6,   177,     7,  1109,  1000,   105,   106,
+     107,     7,   177,   177,   111,   112,   113,   114,   177,   185,
+       7,   374,   375,  1109,   377,   378,   379,   380,   381,   382,
+     383,   384,   385,   386,   387,   388,   389,   390,   391,   178,
+    1344,   394,  1145,     6,  1109,     7,  1218,   184,     6,   184,
+       7,     6,     6,     6,   407,     4,  1391,     4,   184,  1145,
+     413,   184,   184,   127,   184,   418,   178,     6,     6,     6,
+     423,   424,   183,   178,   178,   183,   429,   430,     6,     4,
+    1145,   434,   183,   183,   183,   178,   439,   440,   441,   183,
+     178,  1188,  1189,   178,     4,     6,   185,     6,   180,     6,
+     130,   190,     7,     7,     7,   194,   459,   460,   461,   462,
+     463,   464,   201,     7,   130,   468,   469,   470,   471,   472,
+       7,     7,   130,   476,     7,     7,   479,   480,  1121,   184,
+     483,   484,   485,     4,   181,   488,   489,   490,   491,     6,
+      12,    13,    87,   496,   185,   185,     6,   180,     7,     7,
+       7,   504,    97,   181,     6,  1148,  1491,   510,   511,   184,
+     105,   106,   107,     6,  1060,     6,   111,   112,   113,   114,
+       6,     6,  1330,     7,   184,     6,   529,   177,   179,   268,
+     533,   270,   535,   177,   164,     7,   539,     7,     7,     7,
+       7,  1184,    64,    65,    66,    67,    68,    69,    70,    71,
+      72,    73,    72,    75,     7,     7,     6,   178,    80,    81,
+       7,    83,    84,    85,   178,     7,  1374,    89,   178,   178,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,   587,  1228,  1339,  1395,   176,     7,
+     185,     7,  1235,  1236,     6,     4,     4,   177,   184,     6,
+     122,   123,   124,  1339,     6,   184,     7,    87,  1154,     6,
+      70,     7,     7,     7,     6,   618,     6,    97,   621,     6,
+     623,   624,     6,     6,     4,   105,   106,   107,   631,   632,
+    1377,   111,   112,   113,   114,     4,   375,     4,   185,   178,
+       6,     6,   645,     4,  1190,   183,  1192,     6,  1194,   178,
+     178,   654,   178,     7,   181,     6,   659,   660,   661,   662,
+     184,   177,  1208,   185,   667,  1211,  1212,   181,   407,     6,
+      80,   674,   675,   184,     6,     4,     6,   680,   184,   184,
+     184,     6,     6,   184,  1492,     6,  1494,     5,     7,     6,
+     693,     7,     7,   696,     7,     7,   184,   184,     6,     6,
+     179,     6,     6,     6,     4,   185,   184,   197,   184,   184,
+       6,   714,     6,   126,     6,   718,   719,   720,   721,   183,
+       6,     4,     4,   726,     4,     6,     4,     6,   218,     6,
+     733,   221,   735,   736,     6,     6,     6,     6,     6,     6,
+       6,  1549,     6,     5,   483,   484,   485,     6,   184,     6,
+       6,   130,     6,     6,     6,   245,    87,     6,     6,   183,
+     763,     6,     6,     6,     6,   504,    97,   178,   771,   772,
+     773,     6,   511,   776,   105,   106,   107,     7,     6,     6,
+     111,   112,   113,   114,   184,   788,     6,     5,   181,     6,
+     793,     6,    68,   796,   533,     6,     6,     6,   184,     6,
+    1553,     6,   184,   806,   807,   808,   809,     6,   185,   812,
+     300,   301,   185,   184,   184,     7,   184,  1553,  1461,     6,
+     184,     6,   312,   125,     6,   185,     6,   128,     6,     6,
+       6,     6,  1585,     6,  1587,  1381,     6,  1383,  1553,  1385,
+     184,     6,     6,     6,     6,   184,   184,  1393,     6,  1585,
+    1396,  1587,  1605,   856,   185,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,  1605,
+    1585,   185,  1587,   176,    87,   184,     6,     6,    12,    13,
+       6,     6,   621,     6,   623,     6,     6,  1530,     6,     6,
+    1605,     6,   631,   632,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,     6,     6,
+     185,   184,   176,     6,   917,     6,     6,   920,     6,     6,
+       6,   184,     6,   184,   184,     6,   184,   930,   667,   184,
+      64,    65,    66,    67,    68,    69,    70,    71,    72,    73,
+       6,    75,     6,   946,     6,   184,    80,    81,  1494,    83,
+      84,    85,    12,    13,     6,    89,     6,     6,   184,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,     6,   977,   714,   184,   176,     6,   718,
+     719,   720,   721,     6,     6,   988,   989,   726,   122,   123,
+     124,     6,   997,  1464,  1358,     3,   999,  1000,  1005,   405,
+    1359,     3,   433,    -1,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,    73,    -1,    75,  1125,    -1,    -1,    -1,
+      80,    81,    -1,    83,    84,    85,    -1,    -1,    -1,    89,
+      -1,    -1,    -1,    -1,  1037,  1038,  1039,   776,    -1,    -1,
+      -1,    -1,    -1,    -1,  1047,    -1,  1049,    -1,    -1,    -1,
+      -1,   185,    -1,    -1,    -1,    -1,    -1,  1060,    -1,    -1,
+      -1,    -1,   122,   123,   124,  1068,    -1,   806,   807,   808,
+     809,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,  1089,  1090,  1091,   176,
+      -1,    -1,    -1,    -1,   584,    -1,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+      -1,    -1,    -1,    -1,   176,    -1,    -1,   856,    -1,  1122,
+      -1,    -1,    -1,    -1,    -1,   185,    -1,    -1,    -1,    -1,
+      -1,    12,    13,  1136,    -1,    -1,    -1,    -1,  1141,    -1,
+      -1,    -1,    -1,    -1,    -1,  1148,    -1,    -1,    87,  1152,
+    1153,    -1,    -1,    -1,    -1,    -1,  1159,  1160,    97,    -1,
+      -1,  1164,    -1,    -1,    -1,   655,   105,   106,   107,  1172,
+      -1,    -1,   111,   112,   113,   114,   666,    -1,    -1,  1182,
+       5,  1184,    -1,    64,    65,    66,    67,    68,    69,    70,
+      71,    72,    73,  1196,    75,    -1,    -1,    -1,    -1,    80,
+      81,    -1,    83,    84,    85,  1208,    -1,    -1,    89,  1212,
+      87,    -1,  1215,    -1,    39,    40,    41,    42,    43,    44,
+      97,    -1,    -1,    -1,    -1,  1228,    51,    52,   105,   106,
+     107,    -1,    -1,  1236,   111,   112,   113,   114,    63,    -1,
+      -1,   122,   123,   124,    -1,    -1,   185,    -1,    -1,  1252,
+    1253,    -1,   742,    -1,     3,     4,    -1,  1260,    -1,    -1,
+       9,    10,    11,    -1,    -1,    14,    15,    16,    17,    18,
       19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-      29,    30,    31,    32,    33,    34,    35,   171,   132,   173,
-      39,    40,    41,    42,    43,    44,    45,    46,    47,   111,
-    1393,    13,    51,    52,    53,   161,   162,   156,   113,   114,
-     115,   116,   165,   166,     8,   111,   111,   123,   124,   111,
-    1413,   171,   178,   175,   123,   124,   165,   166,   173,   171,
-     175,   139,   140,   171,   178,   180,   178,   171,   171,   161,
-     162,     6,   158,   171,   178,   178,   178,   178,   178,   178,
-     171,   178,   178,   178,   178,   178,   158,   178,   217,   218,
-     168,   169,   173,     4,   161,   162,   225,   175,     6,   173,
-     229,   175,    60,     6,   179,    63,   180,   171,    66,   173,
-     177,   454,   455,   132,     8,   148,   149,   150,   151,   138,
-     139,   140,   148,   149,   150,   151,   145,   146,   147,   161,
-     162,   474,   173,   609,     6,   168,   169,   613,   177,   171,
-     179,  1110,   161,   162,   161,   162,   178,   166,   173,     4,
-     175,   171,   171,   173,   173,   180,   175,   176,     7,   178,
-     177,   180,   173,   161,   162,   161,   162,   375,   168,   169,
-     295,   686,   687,   688,  1537,   175,    87,    88,    89,    90,
-     178,     7,   178,   526,    95,   168,   169,    98,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,     6,   161,   162,    60,   170,   161,   162,    64,
-      82,   161,   162,   171,     8,   179,   168,   169,     6,    63,
-     178,    76,    66,   177,   161,   162,   178,   177,   351,   352,
-     353,   354,   355,   356,   357,   358,   359,   360,   361,   362,
-     177,   364,   365,   366,   353,   354,   355,   356,   357,   358,
-     359,   360,   361,     7,  1617,   364,   365,   366,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,     8,   161,   162,   171,   170,   149,   150,   151,
-     152,   153,   161,   162,   171,   179,   172,   161,   162,   177,
-      63,   177,   164,    66,   174,    68,   168,   177,   177,   148,
-     149,   150,   151,   177,   176,   177,   178,   179,   172,   181,
-     182,   183,   184,   177,   186,   187,   188,   168,   169,   168,
-     169,   193,   148,   149,   150,   151,   175,   178,     6,     7,
-     161,   162,   461,   462,   161,   162,   161,   162,   546,   211,
-     469,   171,   168,   169,   463,   464,   177,   171,   220,   221,
-     177,    63,   177,   696,    66,   171,    68,   229,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,   171,   171,   173,   173,   170,   175,   172,  1422,
-     178,  1424,   180,  1426,     6,     7,   161,   162,   260,   261,
-     262,   171,   161,   162,   148,   149,   150,   151,    70,   271,
-     272,   273,   177,   275,   172,   613,   278,   279,   177,   177,
-     282,   171,    66,   173,   168,   169,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-     171,    66,   173,   305,   170,   307,   308,   309,   310,   311,
-     312,   313,   314,   315,   316,   317,   318,   319,   320,   321,
-     322,   323,   324,   325,   326,   327,   328,   329,   330,   331,
-     332,   333,   334,   335,   336,   337,   338,   339,   340,   341,
-     342,   343,   344,   345,   346,   347,   348,   349,   350,   161,
-     162,   161,   162,  1526,   161,   162,   161,   162,   171,   614,
-     173,   363,   163,   164,   165,   177,     6,   177,   370,   170,
-     177,   373,   177,    60,  1473,   174,    63,  1476,   177,    66,
-    1479,   383,   178,   385,   386,   387,   388,   389,   390,   391,
-     392,   393,   394,   395,   396,   397,   398,   399,    66,   172,
-     653,   851,   655,   741,   177,  1578,   172,  1580,    66,  1582,
-    1016,   177,   414,  1019,  1020,  1588,   655,   174,   420,    60,
-     177,   172,    63,   425,    68,    66,   177,    68,   430,   431,
-     685,   686,   687,   688,   436,   437,   774,   172,   172,   441,
-     699,   171,   177,   177,   446,   447,   448,   706,   174,    63,
-     172,   177,  1625,   712,  1627,   177,  1629,   171,   171,   173,
-     173,  1560,   161,   162,   466,   467,   468,   469,   470,   471,
-     171,   178,   173,   475,   476,   477,   478,   479,   171,    63,
-     173,   483,   178,     4,   486,   487,    66,    63,   490,   491,
-     492,    66,     4,   495,   496,   497,     4,   499,    12,    13,
-      83,   503,  1601,     4,   171,  1604,   173,   171,  1607,   511,
-      93,  1610,   171,     6,   173,   517,   518,   171,   101,   102,
-     103,   774,   171,   171,   107,   108,   109,   110,     6,     4,
-    1236,  1237,     4,   180,   536,   774,   173,   171,   540,   173,
-     171,  1640,   544,  1642,   171,  1644,    60,    61,    62,    63,
-      64,    65,    66,    67,    68,    69,   171,    71,   173,   171,
-     171,   173,    76,    77,   171,    79,    80,    81,   821,   171,
-     171,    85,     4,     5,   827,   828,   171,  1027,   831,   832,
-     833,   171,   821,   173,   171,   838,   173,     7,   827,   828,
-     171,     4,   831,   832,   833,    60,   179,   171,    63,   838,
-     171,    66,   173,    68,   118,   119,   120,    39,    40,    41,
-      42,    43,    44,   615,   171,     6,   173,   178,   171,    51,
-     173,   171,   875,   173,   178,   171,   885,   173,   171,   177,
-     173,   179,   970,   177,     6,   179,   875,   161,   162,   163,
-     164,   165,   644,     6,   171,   647,   170,   649,   650,   177,
-       4,   179,   194,   195,   196,   657,   658,   199,   200,   201,
-     177,   177,   179,   179,   177,   179,   179,   171,   177,   671,
-     179,   177,   177,   179,   179,   934,   935,   936,   680,   177,
-     171,   179,  1020,   685,   686,   687,   688,   177,    66,   179,
-      68,   693,   178,   235,   236,     5,   178,   171,   700,   701,
-      66,   177,    68,   179,   706,   247,   248,   139,   140,   171,
-     177,  1417,   179,   177,   177,   179,   179,   719,   171,   177,
-     722,   179,   177,   177,   179,   179,   171,   171,  1178,    39,
-      40,    41,    42,    43,    44,   737,   177,   739,   179,   178,
-     178,    51,   744,   745,   746,   747,   177,   177,   179,   179,
-     752,   177,   177,   179,   179,   171,   189,   759,   173,   761,
-     762,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,   178,   177,   210,   179,   170,
-     213,    83,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    93,   178,     6,  1049,   170,   798,   799,   171,   101,
-     102,   103,   171,   173,   237,   107,   108,   109,   110,   177,
-    1148,   179,   814,   815,   816,   817,   818,   819,   177,     4,
-     179,     6,   824,   171,   826,    12,    13,   171,   178,   139,
-     140,   177,   173,   179,   836,   177,   173,   179,   840,   177,
-       5,   179,   844,   177,   177,   179,   179,   177,   173,   179,
-    1109,   178,   854,   855,   856,   857,   177,   859,   179,   292,
-     293,   177,   177,   179,   179,   177,   177,   179,   179,   302,
-     177,     5,   179,    60,    61,    62,    63,    64,    65,    66,
-      67,    68,    69,   177,    71,   179,   177,     5,   179,    76,
-      77,   178,    79,    80,    81,   177,     6,   179,    85,     6,
-      83,   903,   177,   177,   179,   179,   177,   175,   179,  1162,
-      93,   177,   177,   179,   177,  1170,   179,   182,   101,   102,
-     103,   186,   178,  1162,   107,   108,   109,   110,   193,   126,
-    1268,   118,   119,   120,   177,  1385,   179,   177,     6,   179,
-    1193,  1196,     6,  1202,     6,   178,     6,   173,   170,     4,
-     175,   178,   173,     7,  1193,   179,    12,    13,  1431,     7,
-       6,     6,   964,     6,   171,   967,     7,     7,   171,   171,
-     171,     7,   172,     6,  1574,     7,   978,  1232,     7,  1238,
-     178,  1240,     6,  1242,     6,     6,     6,  1236,  1237,     4,
-       4,   123,   179,     6,   178,   172,   179,  1256,   178,   178,
-    1259,  1260,   178,   178,    60,    61,    62,    63,    64,    65,
-      66,    67,    68,    69,     6,    71,   177,   177,   172,   172,
-      76,    77,  1277,    79,    80,    81,  1028,   177,   177,    85,
-     177,   177,   172,   177,     6,     4,  1038,  1039,   174,     4,
-       6,     4,     6,   126,     6,   126,  1048,  1049,     7,     7,
-       7,     7,     7,     7,  1527,    83,   126,     7,     7,   178,
-       4,     6,   118,   119,   120,    93,   175,   179,   179,     6,
-     174,     7,   175,   101,   102,   103,     7,    12,    13,   107,
-     108,   109,   110,     7,  1086,  1087,  1088,   178,     6,     6,
-     177,     6,    83,   172,  1096,   182,  1098,   174,     6,   186,
-       7,   173,    93,     6,   171,   370,   193,  1109,   373,   178,
-     101,   102,   103,   171,     6,  1117,   107,   108,   109,   110,
-     158,   180,     7,   179,     7,    60,    61,    62,    63,    64,
-      65,    66,    67,    68,    69,     7,    71,  1139,  1140,  1141,
-      68,    76,    77,     7,    79,    80,    81,     7,     7,     7,
-      85,   179,     6,   172,     7,   172,   172,     7,     7,     6,
-     172,     7,  1421,     6,  1423,     4,  1425,     4,  1417,  1171,
-       6,   178,     6,   260,  1433,   262,   171,  1436,   611,     7,
-       6,   178,  1184,   118,   119,   120,     7,  1189,   179,     7,
-       7,     6,     6,     6,  1196,    66,     6,    83,  1200,  1201,
-       6,     4,     4,     4,   179,  1207,  1208,    93,     6,     4,
-    1212,   172,     6,     6,   174,   101,   102,   103,  1220,   172,
-     172,   107,   108,   109,   110,   490,   491,   492,  1230,   177,
-    1232,   172,   175,     7,     6,   175,   178,   171,    76,   178,
-     178,     6,  1244,     6,   179,   178,   511,     5,   681,   178,
-       6,   178,     6,     6,  1256,     4,     6,   178,  1260,   692,
-       7,  1263,     7,     7,     7,     7,   178,   173,     6,     6,
-       6,  1530,     6,   178,   178,  1277,   178,   172,   174,     4,
-       6,   122,     6,   370,  1539,  1540,   373,     6,   177,     6,
-       6,     4,     6,   179,     6,     6,  1298,  1299,     6,     6,
-       4,     6,   178,     6,  1306,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,     6,
-       6,  1574,     5,   170,    83,     6,     6,   414,     6,   126,
-       6,     6,     6,     6,    93,   768,     6,   177,  1340,     6,
-    1593,     6,   101,   102,   103,     6,     6,   172,   107,   108,
-     109,   110,     6,     6,  1593,     6,  1358,     7,  1360,     6,
-       6,     5,   178,   175,    64,     6,  1621,     6,     6,  1371,
-       6,  1373,     6,   178,  1376,     6,     6,     6,   178,  1632,
-     179,  1634,   647,   179,   649,     7,   178,  1389,   178,   178,
-     178,   121,  1394,  1632,     6,  1634,  1651,   179,     6,     6,
-       6,   124,  1655,   490,   491,   492,   179,     6,     6,     6,
-       6,   178,  1414,     6,     6,     6,  1655,     6,   178,  1421,
-     179,  1423,     6,  1425,   511,    83,   178,   178,   693,     6,
-       4,   518,     4,  1435,  1496,     6,     6,  1439,     6,     6,
-       6,     6,     6,     6,   179,   178,     6,   178,  1450,  1451,
-     178,     6,     6,  1455,     6,     6,   889,   890,   178,   892,
-       6,   894,   895,  1465,     6,   898,   899,  1469,     6,   178,
-       6,     6,   737,     6,   739,     6,   178,   178,     6,   744,
-     745,   746,   747,    83,   178,   178,     6,   752,     6,     6,
-       6,     6,     6,    93,  1496,     6,   412,  1046,  1054,     3,
-       3,   101,   102,   103,  1174,  1507,    -1,   107,   108,   109,
-     110,    -1,  1514,    -1,   440,  1517,    -1,    -1,  1520,    -1,
-      -1,    -1,  1524,    -1,    -1,    -1,  1528,    -1,  1530,    -1,
-      -1,    -1,    -1,  1535,    -1,    -1,  1538,     6,  1540,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,   980,   981,   982,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,   990,    83,   824,
-     647,   826,   649,    -1,    -1,    -1,    -1,    -1,    93,  1571,
-     657,   658,    -1,    -1,    -1,  1577,   101,   102,   103,   179,
-      -1,    -1,   107,   108,   109,   110,    -1,    -1,  1590,   854,
-     855,   856,   857,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,   693,  1040,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,  1619,    -1,    -1,
-      -1,    -1,  1055,    -1,    -1,     6,    -1,    -1,  1061,    -1,
-      -1,    -1,    -1,    -1,  1067,    -1,  1069,  1070,   903,    -1,
-      -1,  1074,    -1,    -1,    -1,    -1,  1079,  1080,  1081,     6,
-     737,    -1,   739,    -1,   179,    -1,    -1,   744,   745,   746,
-     747,    -1,    -1,  1096,    -1,   752,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,  1111,    -1,
-      -1,   170,  1115,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,     3,     4,
-      -1,   170,    -1,    -1,     9,    10,    11,    -1,    -1,    14,
+      29,    30,    31,    32,    33,    34,    35,    -1,    -1,    -1,
+      -1,  1294,    -1,    -1,    -1,    -1,    45,    46,    47,    -1,
+      -1,    -1,    -1,    -1,   185,    54,    55,    56,   185,  1312,
+      -1,  1314,    -1,    62,    -1,    -1,    87,    -1,   143,   144,
+      -1,    -1,  1325,    -1,  1327,    -1,    97,  1330,    -1,  1068,
+      -1,    -1,    -1,  1336,   105,   106,   107,    -1,    -1,    -1,
+     111,   112,   113,   114,    -1,    -1,  1349,    -1,    -1,    87,
+       6,  1354,   842,   843,    -1,   845,    -1,   847,   848,    97,
+      -1,   851,   852,    -1,    -1,    -1,    -1,   105,   106,   107,
+      -1,  1374,    -1,   111,   112,   113,   114,    -1,  1381,    -1,
+    1383,    -1,  1385,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,  1395,   142,    -1,    -1,  1399,    -1,    -1,    -1,
+     149,   150,   151,   152,   153,    -1,    -1,    -1,    -1,    -1,
+      -1,  1414,  1415,    -1,   185,    -1,  1419,    -1,   167,   168,
+      -1,    -1,    -1,   172,    -1,    -1,  1429,    -1,   177,    -1,
+    1433,    -1,    -1,   182,    -1,   184,    -1,    -1,    -1,    87,
+      -1,    -1,   932,   933,   934,    -1,    -1,   185,    -1,    97,
+      -1,    -1,   942,    -1,    -1,    -1,  1459,   105,   106,   107,
+      -1,  1464,    -1,   111,   112,   113,   114,    -1,  1471,  1208,
+      -1,    -1,    -1,  1212,    -1,  1478,    -1,    -1,  1481,    -1,
+      -1,  1484,    -1,    -1,    -1,  1488,    -1,    -1,    -1,  1492,
+      -1,  1494,    -1,    -1,    -1,    -1,    -1,    -1,  1501,    -1,
+     990,  1504,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,  1006,    -1,    -1,    -1,
+     176,    -1,  1012,    -1,    -1,    -1,    -1,    -1,  1018,    87,
+    1020,  1021,    -1,  1536,    -1,  1025,    -1,   185,    -1,    97,
+    1030,  1031,  1032,    -1,    -1,    -1,  1549,   105,   106,   107,
+      -1,    -1,    -1,   111,   112,   113,   114,  1047,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+      -1,    -1,  1062,    -1,   176,  1314,  1066,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,     3,     4,    -1,
+      -1,  1330,    -1,     9,    10,    11,    -1,  1336,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+       8,    -1,    -1,    -1,    -1,    -1,    -1,   185,    -1,    45,
+      46,    47,    -1,    -1,    -1,  1374,    -1,    -1,    54,    55,
+      56,    -1,    -1,    -1,    -1,  1135,    62,     3,     4,    -1,
+      -1,    -1,    -1,     9,    10,    11,  1395,    -1,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      -1,    -1,    -1,    -1,    -1,  1175,  1176,  1177,  1178,    45,
+      46,    47,    -1,    -1,    -1,    -1,    -1,    -1,    54,    55,
+      56,    -1,    -1,    -1,    -1,    -1,    62,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,    -1,    -1,
+    1210,    -1,   176,    -1,    -1,    -1,   142,    -1,    -1,    -1,
+      -1,    -1,  1222,   149,   150,   151,   152,   153,    -1,  1229,
+      -1,  1231,    -1,    -1,    -1,  1235,    -1,    -1,    -1,     6,
+      -1,   167,   168,  1492,    -1,  1494,   172,    -1,    -1,    -1,
+      -1,   177,    -1,    -1,  1254,    -1,   182,    -1,     6,    -1,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,    -1,  1275,   142,     6,   176,    -1,
+      -1,    -1,    -1,   149,   150,   151,   152,   153,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    1549,   167,   168,    -1,    -1,    -1,   172,    -1,    -1,  1309,
+      -1,   177,    -1,    -1,   180,    -1,   182,    -1,     3,     4,
+       5,    -1,    -1,    -1,     9,    10,    11,    -1,    -1,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
       25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    -1,    -1,    83,  1167,    -1,  1169,   824,    -1,   826,
-      45,    46,    47,    93,    -1,    -1,    -1,    52,    53,    -1,
-      -1,   101,   102,   103,    -1,    -1,    -1,   107,   108,   109,
-     110,    -1,    -1,    -1,    -1,    -1,    -1,   854,   855,   856,
-     857,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-    1223,  1224,  1225,  1226,    -1,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,   903,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,  1258,    -1,    -1,    -1,   179,
-      -1,    -1,    -1,   138,    -1,     6,    -1,    -1,  1271,    -1,
-     145,   146,   147,    -1,    -1,  1278,    -1,    -1,    -1,    -1,
-      -1,    -1,  1117,    -1,     6,    -1,   161,   162,    -1,    -1,
-      -1,   166,    -1,    -1,    -1,    -1,   171,  1300,    -1,   174,
-      -1,   176,    -1,   178,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,     3,     4,    -1,    -1,  1321,    -1,
+      35,    -1,    -1,  1353,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    -1,    -1,    -1,    51,    52,    -1,    54,
+      55,    56,    -1,  1373,    -1,    -1,    -1,    62,    63,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+    1390,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,  1445,    -1,   176,    -1,    -1,
+      -1,   136,    -1,    -1,    -1,    -1,    -1,   142,   143,   144,
+      -1,    -1,    -1,    -1,   149,   150,   151,   152,   153,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   167,   168,    -1,    -1,    -1,   172,    -1,    -1,
+      -1,    -1,   177,    -1,   179,    -1,   181,   182,    -1,   184,
+      -1,   186,    -1,  1503,     3,     4,    -1,    -1,    -1,    -1,
+       9,    10,    11,    -1,    -1,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    45,    46,    47,    -1,
+      -1,    -1,    -1,    12,    13,    54,    55,    56,    -1,    -1,
+      -1,    -1,    -1,    62,    -1,    64,    -1,    -1,    67,    -1,
+      -1,    70,    -1,    72,  1574,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    84,    -1,    -1,    -1,    -1,
+      -1,    -1,    91,    92,    93,    94,    95,    -1,    -1,    -1,
+      99,    -1,    -1,   102,    -1,    64,    65,    66,    67,    68,
+      69,    70,    71,    72,    73,    -1,    75,    -1,    -1,    -1,
+      -1,    80,    81,    -1,    83,    84,    85,    -1,    -1,    -1,
+      89,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   142,    -1,    -1,    -1,    -1,    -1,    -1,
+     149,   150,   151,   152,   153,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   122,   123,   124,    -1,    -1,   167,   168,
+      -1,    -1,    -1,   172,    -1,    -1,    -1,    -1,   177,    -1,
+      -1,     3,     4,   182,    -1,   184,   185,     9,    10,    11,
+      -1,    -1,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    35,    36,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    45,    46,    47,   185,    -1,    -1,    -1,
+      -1,    -1,    54,    55,    56,    -1,    -1,    12,    13,    -1,
+      62,    -1,    64,    -1,    -1,    67,    -1,    -1,    70,    -1,
+      72,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    84,    -1,    -1,    -1,    -1,    -1,    -1,    91,
+      92,    93,    94,    95,    -1,    -1,    -1,    99,    -1,    -1,
+     102,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    64,
+      65,    66,    67,    68,    69,    70,    71,    72,    73,    -1,
+      75,    -1,    -1,    -1,    -1,    80,    81,    -1,    83,    84,
+      85,    -1,     6,    -1,    89,    -1,    -1,    -1,    -1,    -1,
+     142,    -1,    -1,    -1,    -1,    -1,    -1,   149,   150,   151,
+     152,   153,     6,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   167,   168,   122,   123,   124,
+     172,    -1,    -1,    -1,    -1,   177,    -1,    -1,    -1,    -1,
+     182,    -1,    -1,   185,     3,     4,     5,    -1,    -1,    -1,
        9,    10,    11,    -1,    -1,    14,    15,    16,    17,    18,
       19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
       29,    30,    31,    32,    33,    34,    35,    36,    -1,    -1,
-      -1,    -1,  1355,    -1,    -1,    -1,    45,    46,    47,    -1,
-      -1,    -1,    -1,    52,    53,    -1,    -1,    -1,    83,    -1,
-      -1,    60,    -1,    -1,    63,    -1,    -1,    66,    93,    68,
-      -1,    -1,    -1,    -1,    -1,    -1,   101,   102,   103,    -1,
-    1393,    80,   107,   108,   109,   110,    -1,    -1,    87,    88,
-      89,    90,    91,    -1,    -1,    -1,    95,    -1,    -1,    98,
-    1413,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,  1430,    -1,   170,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,   138,
-      -1,    -1,    -1,    -1,    -1,    -1,   145,   146,   147,    -1,
-    1117,    -1,    -1,    -1,   179,    -1,    -1,    -1,    -1,     6,
-      -1,    -1,   161,   162,    83,    -1,    -1,   166,  1481,    -1,
-      -1,    -1,   171,    -1,    93,    -1,    -1,   176,    -1,   178,
-     179,    -1,   101,   102,   103,    -1,     3,     4,   107,   108,
-     109,   110,     9,    10,    11,    -1,    -1,    14,    15,    16,
+      39,    40,    41,    42,    43,    44,    45,    46,    47,    -1,
+     185,    -1,    51,    52,    -1,    54,    55,    56,    -1,    -1,
+      -1,    -1,    -1,    62,    63,    64,    -1,    -1,    67,    -1,
+      -1,    70,    -1,    72,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    84,    -1,    -1,    -1,    -1,
+      -1,    -1,    91,    92,    93,    94,    95,    -1,    -1,    -1,
+      99,    -1,    -1,   102,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,    -1,    -1,
+      -1,    -1,   176,    -1,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,    -1,    -1,
+      -1,    -1,   176,   142,   143,   144,    -1,    -1,    -1,    -1,
+     149,   150,   151,   152,   153,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   167,   168,
+      -1,    -1,    -1,   172,    -1,    -1,    -1,    -1,   177,    -1,
+       3,     4,     5,   182,    -1,   184,     9,    10,    11,    -1,
+      -1,    14,    15,    16,    17,    18,    19,    20,    21,    22,
+      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
+      33,    34,    35,    36,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    45,    46,    47,    -1,    -1,    -1,    12,    13,
+      -1,    54,    55,    56,    -1,    -1,    -1,    -1,    -1,    62,
+      -1,    64,    -1,    -1,    67,    -1,    -1,    70,    -1,    72,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    84,    -1,    -1,    -1,    -1,    -1,    -1,    91,    92,
+      93,    94,    95,    -1,    -1,    -1,    99,    -1,    -1,   102,
+      64,    65,    66,    67,    68,    69,    70,    71,    72,    73,
+      -1,    75,    -1,    -1,    -1,    -1,    80,    81,    -1,    83,
+      84,    85,    -1,    -1,    -1,    89,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   142,
+      -1,    -1,    -1,    -1,    -1,    -1,   149,   150,   151,   152,
+     153,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   122,   123,
+     124,    -1,    -1,    -1,   167,   168,    -1,    -1,    -1,   172,
+      -1,    -1,    -1,    -1,   177,    -1,     3,     4,     5,   182,
+      -1,   184,     9,    10,    11,    -1,    -1,    14,    15,    16,
       17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
       27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
-       6,    -1,    -1,    -1,  1537,    -1,  1539,    -1,    45,    46,
-      47,  1376,    -1,    -1,    -1,    52,    53,    -1,    -1,    -1,
-      -1,    -1,    -1,    60,    -1,    -1,    63,    -1,    -1,    66,
-      -1,    68,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-     179,    -1,    -1,    80,    -1,    -1,    -1,    -1,    -1,  1414,
-      87,    88,    89,    90,    91,    -1,    -1,    -1,    95,    -1,
-      -1,    98,    -1,    12,    13,    -1,    -1,    -1,    -1,  1256,
-    1435,    -1,    -1,  1260,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,  1617,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,   138,    -1,   170,    -1,    -1,    -1,    -1,   145,   146,
-     147,    60,    61,    62,    63,    64,    65,    66,    67,    68,
-      69,    -1,    71,    -1,   161,   162,    -1,    76,    77,   166,
-      79,    80,    81,    -1,   171,    -1,    85,    -1,    -1,   176,
-      -1,    -1,   179,    -1,    -1,    -1,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,  1528,   170,  1530,    -1,    -1,    -1,   118,
-     119,   120,    -1,  1360,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,  1376,
-      -1,    -1,     3,     4,    -1,    -1,    -1,    -1,     9,    10,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    45,    46,
+      47,   185,    -1,    -1,    12,    13,    -1,    54,    55,    56,
+      -1,    -1,    -1,    -1,    -1,    62,    -1,    64,    -1,    -1,
+      67,    -1,    -1,    70,    -1,    72,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    84,    -1,    -1,
+      -1,    -1,    -1,    -1,    91,    92,    93,    94,    95,    -1,
+      -1,    -1,    99,    -1,    -1,   102,    64,    65,    66,    67,
+      68,    69,    70,    71,    72,    73,    -1,    75,    -1,    -1,
+      -1,    -1,    80,    81,    -1,    83,    84,    85,    -1,    -1,
+       6,    89,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   142,    -1,    -1,    -1,     6,
+      -1,    -1,   149,   150,   151,   152,   153,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   122,   123,   124,    -1,    -1,    -1,
+     167,   168,    -1,    -1,    -1,   172,    -1,    -1,    -1,    -1,
+     177,    -1,     3,     4,    -1,   182,    -1,   184,     9,    10,
       11,    -1,    -1,    14,    15,    16,    17,    18,    19,    20,
       21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    33,    34,    35,  1590,    -1,  1414,    -1,    -1,
-     179,    -1,    -1,    -1,    45,    46,    47,    -1,     3,     4,
-       5,    52,    53,    -1,     9,    10,    11,    -1,  1435,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    -1,    -1,    39,    40,    41,    42,    43,    44,
-      45,    46,    47,    -1,    -1,    -1,    51,    52,    53,    -1,
-      -1,    -1,    83,    -1,    -1,    60,    -1,    -1,    63,    -1,
-      -1,    66,    93,    68,    -1,    -1,    -1,    -1,    -1,    -1,
-     101,   102,   103,    -1,    -1,    80,   107,   108,   109,   110,
-      -1,    -1,    87,    88,    89,    90,    91,   138,    -1,    -1,
-      95,    -1,    -1,    98,   145,   146,   147,    -1,    -1,    -1,
-      -1,  1528,    -1,  1530,    -1,    -1,    -1,    -1,    -1,    -1,
-     161,   162,    83,    -1,    -1,   166,    -1,    -1,    -1,    -1,
-     171,    -1,    93,   174,    -1,   176,    -1,   178,    -1,    -1,
-     101,   102,   103,   138,   139,   140,   107,   108,   109,   110,
-     145,   146,   147,    -1,  1571,    -1,    -1,    -1,   179,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   161,   162,    -1,    -1,
-      -1,   166,    -1,  1590,    -1,    -1,   171,    -1,     3,     4,
-       5,   176,    -1,   178,     9,    10,    11,    -1,    -1,    14,
+      31,    32,    33,    34,    35,    36,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    45,    46,    47,   185,    -1,    -1,
+      -1,    -1,    -1,    54,    55,    56,    -1,    -1,    -1,    -1,
+      -1,    62,    -1,    64,    -1,    -1,    67,    -1,    -1,    70,
+      -1,    72,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    84,    -1,    -1,    -1,    -1,    -1,    -1,
+      91,    92,    93,    94,    95,    -1,    -1,    -1,    99,    -1,
+      -1,   102,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,
+     176,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,     8,    -1,    -1,    -1,   176,
+      -1,   142,    -1,    -1,    -1,    -1,    -1,    -1,   149,   150,
+     151,   152,   153,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   167,   168,    -1,    -1,
+      -1,   172,    -1,    -1,    -1,    -1,   177,    -1,     3,     4,
+      -1,   182,    -1,   184,     9,    10,    11,    -1,    -1,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
       25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    -1,    -1,    -1,    -1,    -1,    -1,   179,    -1,
-      45,    46,    47,    -1,    -1,    -1,    -1,    52,    53,    -1,
-      -1,    -1,    -1,    -1,    -1,    60,    -1,    -1,    63,    -1,
-      -1,    66,    -1,    68,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    80,    -1,    -1,    -1,    -1,
-      -1,    -1,    87,    88,    89,    90,    91,    -1,    -1,    -1,
-      95,    -1,    -1,    98,    -1,     3,     4,     5,    -1,    -1,
-      -1,     9,    10,    11,    -1,    -1,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    35,    36,    -1,
-      -1,    -1,    -1,   138,    -1,    -1,    -1,    45,    46,    47,
-     145,   146,   147,    -1,    52,    53,    -1,    -1,    -1,    -1,
-      -1,    -1,    60,    -1,    -1,    63,   161,   162,    66,    -1,
-      68,   166,    -1,    -1,    -1,    -1,   171,    -1,    -1,    -1,
-      -1,   176,    80,   178,    -1,    -1,    -1,    -1,    -1,    87,
-      88,    89,    90,    91,    -1,    -1,    -1,    95,    -1,    -1,
-      98,    -1,     3,     4,    -1,    -1,    -1,    -1,     9,    10,
-      11,    -1,    -1,    14,    15,    16,    17,    18,    19,    20,
-      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    33,    34,    35,    36,    -1,    -1,    -1,    -1,
-     138,    -1,    -1,    -1,    45,    46,    47,   145,   146,   147,
-      -1,    52,    53,    -1,    -1,    -1,    -1,    -1,    -1,    60,
-      -1,    -1,    63,   161,   162,    66,    -1,    68,   166,    -1,
-      -1,    -1,    -1,   171,    -1,    -1,    -1,    -1,   176,    80,
-     178,    -1,    -1,    -1,    -1,    -1,    87,    88,    89,    90,
-      91,    -1,    -1,    -1,    95,    -1,    -1,    98,    -1,     3,
-       4,    -1,    -1,    -1,    -1,     9,    10,    11,    -1,    -1,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
-      34,    35,    36,    -1,    -1,    -1,    -1,   138,    -1,    -1,
-      -1,    45,    46,    47,   145,   146,   147,    -1,    52,    53,
-      -1,    -1,    -1,    -1,    -1,    -1,    60,    -1,    -1,    63,
-     161,   162,    66,    -1,    68,   166,    -1,    -1,    -1,    -1,
-     171,    -1,    -1,    -1,    -1,   176,    80,   178,    -1,    -1,
-      -1,    -1,    -1,    87,    88,    89,    90,    91,    -1,    -1,
-      -1,    95,    -1,    -1,    98,    -1,     3,     4,    -1,    -1,
-      -1,    -1,     9,    10,    11,    -1,    -1,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
-      -1,    -1,    -1,    -1,   138,    -1,    -1,    -1,    45,    46,
-      47,   145,   146,   147,    -1,    52,    53,    -1,    -1,    -1,
-      -1,    -1,    -1,    60,    -1,    -1,    63,   161,   162,    66,
-      -1,    68,   166,    -1,    -1,    -1,    -1,   171,    -1,    -1,
-      -1,    -1,   176,    80,   178,    -1,    -1,    -1,    -1,    -1,
-      87,    88,    89,    90,    91,    -1,    -1,    -1,    95,    -1,
-      -1,    98,    -1,     3,     4,    -1,    -1,    -1,    -1,     9,
-      10,    11,    -1,    -1,    14,    15,    16,    17,    18,    19,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      30,    31,    32,    33,    34,    35,    36,    -1,    -1,    -1,
-      -1,   138,    -1,    -1,    -1,    45,    46,    47,   145,   146,
-     147,    -1,    52,    53,    -1,    -1,    -1,    -1,    -1,    -1,
-      60,    -1,    -1,    63,   161,   162,    66,    -1,    68,   166,
-      -1,    -1,    -1,    -1,   171,    -1,    -1,    -1,    -1,   176,
-      80,   178,    -1,    -1,    -1,    -1,    -1,    87,    88,    89,
-      90,    91,    -1,    -1,    -1,    95,    -1,    -1,    98,    -1,
-       3,     4,    -1,    -1,    -1,    -1,     9,    10,    11,    -1,
-      -1,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-      33,    34,    35,    36,    -1,    -1,    -1,    -1,   138,    -1,
-      -1,    -1,    45,    46,    47,   145,   146,   147,    -1,    52,
-      53,    -1,    -1,    -1,    -1,    -1,    -1,    60,    12,    13,
-      63,   161,   162,    66,    -1,    68,   166,    -1,    -1,    -1,
-      -1,   171,    -1,    -1,    -1,    -1,   176,    80,   178,    -1,
-      -1,    -1,    -1,    -1,    87,    88,    89,    90,    91,    -1,
-      -1,    -1,    95,    -1,    -1,    98,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    60,    61,    62,    63,
-      64,    65,    66,    67,    68,    69,    -1,    71,    -1,    -1,
-      -1,    -1,    76,    77,    -1,    79,    80,    81,    -1,    -1,
-      -1,    85,    -1,    -1,    -1,   138,    -1,    -1,    -1,    -1,
-      -1,    -1,   145,   146,   147,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   161,   162,
-      -1,    -1,    -1,   166,   118,   119,   120,    -1,   171,    -1,
-       3,     4,     5,   176,    -1,   178,     9,    10,    11,    -1,
-      -1,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-      33,    34,    35,    -1,    -1,    -1,    39,    40,    41,    42,
-      43,    44,    45,    46,    47,     3,     4,     5,    51,    52,
-      53,     9,    10,    11,    -1,   179,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    35,    -1,    -1,
-      -1,    39,    40,    41,    42,    43,    44,    45,    46,    47,
-       3,     4,     5,    51,    52,    53,     9,    10,    11,    -1,
-      -1,    14,    15,    16,    17,    18,    19,    20,    21,    22,
-      23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-      33,    34,    35,    -1,    -1,    -1,    39,    40,    41,    42,
-      43,    44,    45,    46,    47,   138,   139,   140,    51,    52,
-      53,    -1,   145,   146,   147,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   161,   162,
-      -1,    -1,    -1,   166,    -1,    -1,    -1,    -1,   171,    -1,
-      -1,    -1,    -1,   176,    -1,   178,    -1,    -1,    -1,    -1,
-     138,   139,   140,    -1,    -1,    -1,    -1,   145,   146,   147,
+      35,    36,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      45,    46,    47,    -1,    -1,    -1,    -1,    -1,    -1,    54,
+      55,    56,    -1,    -1,    -1,    -1,    -1,    62,    -1,    64,
+      -1,    -1,    67,    -1,    -1,    70,    -1,    72,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    84,
+      -1,    -1,    -1,    -1,    -1,    -1,    91,    92,    93,    94,
+      95,    -1,    -1,    -1,    99,    -1,    -1,   102,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,     8,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   142,    -1,    -1,
+      -1,    -1,    -1,     8,   149,   150,   151,   152,   153,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,   161,   162,    -1,    -1,    -1,   166,    -1,
-       6,    -1,    -1,   171,    -1,    -1,    -1,    -1,   176,    -1,
-     178,    -1,    -1,    -1,    -1,   138,   139,   140,    -1,     6,
-      -1,    -1,   145,   146,   147,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   161,   162,
-      -1,    -1,    -1,   166,    -1,    -1,    -1,    -1,   171,    -1,
-       3,     4,    -1,   176,    -1,   178,     9,    10,    11,    -1,
+      -1,    -1,   167,   168,    -1,    -1,    -1,   172,    -1,    -1,
+      -1,    -1,   177,    -1,     3,     4,    -1,   182,    -1,   184,
+       9,    10,    11,    -1,    -1,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    45,    46,    47,    -1,
+      -1,    -1,    -1,    -1,    -1,    54,    55,    56,    -1,    -1,
+      -1,    -1,    -1,    62,    -1,    64,    -1,    -1,    67,    -1,
+      -1,    70,    -1,    72,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    84,    -1,    -1,    -1,    -1,
+      -1,    -1,    91,    92,    93,    94,    95,    -1,    -1,    -1,
+      99,    -1,    -1,   102,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,    -1,    -1,
+      -1,    -1,   176,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,     8,    -1,    -1,
+      -1,   176,    -1,   142,    -1,    -1,    -1,    -1,    -1,    -1,
+     149,   150,   151,   152,   153,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   167,   168,
+      -1,    -1,    -1,   172,    -1,    -1,    -1,    -1,   177,    -1,
+       3,     4,    -1,   182,    -1,   184,     9,    10,    11,    -1,
       -1,    14,    15,    16,    17,    18,    19,    20,    21,    22,
       23,    24,    25,    26,    27,    28,    29,    30,    31,    32,
-      33,    34,    35,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    45,    46,    47,     3,     4,    -1,    -1,    52,
-      53,     9,    10,    11,    -1,    -1,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    35,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    45,    46,    47,
-      -1,    -1,    -1,    -1,    52,    53,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,   138,    -1,    -1,    -1,    -1,
-      -1,    -1,   145,   146,   147,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   161,   162,
-      -1,    -1,    -1,   166,    -1,    -1,    -1,    -1,   171,    -1,
-      -1,    -1,    -1,   176,    -1,   178,    -1,    -1,    -1,    -1,
-     138,    -1,    -1,    -1,    -1,    -1,    -1,   145,   146,   147,
+      33,    34,    35,    36,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    45,    46,    47,    -1,    -1,    -1,    -1,    -1,
+      -1,    54,    55,    56,    -1,    -1,    -1,    -1,    -1,    62,
+      -1,    64,    -1,    -1,    67,    -1,    -1,    70,    -1,    72,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,   161,   162,    -1,    -1,    -1,   166,    -1,
-      -1,    -1,    -1,   171,    -1,     3,     4,    -1,   176,    -1,
-     178,     9,    10,    11,    -1,    -1,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    35,    36,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    45,    46,    47,
-      -1,    -1,    -1,    -1,    52,    53,    -1,    -1,    -1,    -1,
-      -1,    -1,    60,    -1,    -1,    63,    -1,    -1,    66,    -1,
-      68,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    80,    -1,    -1,    -1,    -1,    -1,    -1,    87,
-      88,    89,    90,    91,    -1,     3,     4,    95,    -1,    -1,
-      98,     9,    10,    11,    -1,    -1,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    35,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    45,    46,    47,
-     138,    -1,    -1,    -1,    52,    53,    -1,   145,   146,   147,
+      -1,    84,    -1,    -1,    -1,    -1,    -1,    -1,    91,    92,
+      93,    94,    95,    -1,    -1,    -1,    99,    -1,    -1,   102,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,     8,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   142,
+      -1,    -1,    -1,    -1,    -1,    -1,   149,   150,   151,   152,
+     153,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   167,   168,    -1,    -1,    -1,   172,
+      -1,    -1,    -1,    -1,   177,    -1,     3,     4,    -1,   182,
+      -1,   184,     9,    10,    11,    -1,    -1,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    45,    46,
+      47,    -1,    -1,    -1,    87,    -1,    -1,    54,    55,    56,
+      -1,    -1,    -1,    -1,    -1,    62,    -1,    64,    -1,    -1,
+      67,    -1,    -1,    70,    -1,    72,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    84,    -1,    -1,
+      -1,    -1,    -1,    -1,    91,    92,    93,    94,    95,    -1,
+      -1,    -1,    99,    -1,    -1,   102,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+      -1,    -1,    -1,    -1,   176,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,   142,    -1,    -1,    -1,    -1,
+      -1,    -1,   149,   150,   151,   152,   153,    -1,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,   161,   162,    -1,    -1,    -1,   166,     3,
-       4,     5,    -1,   171,    -1,     9,    10,    11,   176,    -1,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-      24,    25,    26,    27,    28,    29,    30,    31,    32,    33,
-      34,    35,    -1,    -1,    -1,    39,    40,    41,    42,    43,
-      44,    45,    46,    47,    -1,    -1,    -1,    51,    52,    53,
-      -1,    -1,    -1,    12,    13,    -1,    -1,    -1,    -1,    -1,
-     138,    -1,    -1,    -1,    -1,    -1,    -1,   145,   146,   147,
+     167,   168,    -1,    -1,    -1,   172,    -1,    -1,    -1,    -1,
+     177,    -1,     3,     4,     5,   182,    -1,   184,     9,    10,
+      11,    -1,    -1,    14,    15,    16,    17,    18,    19,    20,
+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    -1,    -1,    -1,    39,    40,
+      41,    42,    43,    44,    45,    46,    47,    -1,    -1,    -1,
+      51,    52,    -1,    54,    55,    56,    -1,     3,     4,     5,
+      -1,    62,    63,     9,    10,    11,    -1,    -1,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      -1,    -1,    -1,    39,    40,    41,    42,    43,    44,    45,
+      46,    47,    -1,    -1,    -1,    51,    52,    -1,    54,    55,
+      56,    -1,    -1,    -1,    -1,    -1,    62,    63,    -1,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,   142,   143,   144,   183,    -1,   185,    -1,   149,   150,
+     151,   152,   153,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   167,   168,    -1,    -1,
+      -1,   172,    -1,    -1,    -1,    -1,   177,    -1,    -1,    -1,
+      -1,   182,    -1,   184,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   142,   143,   144,    -1,
+      -1,    -1,    -1,   149,   150,   151,   152,   153,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,   161,   162,    -1,    -1,    -1,   166,    -1,
-       6,    -1,    -1,   171,    -1,    -1,    -1,    -1,   176,    -1,
-      -1,    60,    61,    62,    63,    64,    65,    66,    67,    68,
-      69,    -1,    71,    -1,    -1,    -1,    -1,    76,    77,    -1,
-      79,    80,    81,    -1,    -1,    -1,    85,    12,    13,    -1,
-      -1,    -1,    -1,    -1,   138,   139,   140,    -1,    -1,    -1,
-      -1,   145,   146,   147,    -1,    -1,    -1,    -1,    -1,     6,
-      -1,    -1,    -1,    -1,    12,    13,    -1,   161,   162,   118,
-     119,   120,   166,    -1,    -1,    -1,    -1,   171,    -1,    -1,
-      -1,    -1,   176,    -1,    -1,    60,    61,    62,    63,    64,
-      65,    66,    67,    68,    69,     6,    71,    -1,    -1,    -1,
-      -1,    76,    77,    -1,    79,    80,    81,    -1,    -1,    -1,
-      85,    -1,    60,    61,    62,    63,    64,    65,    66,    67,
-      68,    69,     6,    71,    -1,    -1,    12,    13,    76,    77,
-     179,    79,    80,    81,    -1,    -1,    -1,    85,    -1,    -1,
-      -1,    -1,    -1,   118,   119,   120,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-       7,     8,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,
-     118,   119,   120,    -1,    60,    61,    62,    63,    64,    65,
-      66,    67,    68,    69,     7,    71,    -1,    -1,    -1,    -1,
-      76,    77,    -1,    79,    80,    81,    -1,    -1,    -1,    85,
-      -1,    -1,    -1,    -1,   179,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,     8,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,   179,   118,   119,   120,    -1,    -1,    -1,     8,    -1,
-      -1,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,     8,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,     8,    -1,    -1,    -1,   170,    -1,    -1,    -1,
-      -1,    -1,    -1,   179,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,     8,    -1,    -1,    -1,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
+      -1,   167,   168,    -1,    -1,    -1,   172,    -1,    -1,    -1,
+      -1,   177,    -1,     3,     4,     5,   182,    -1,   184,     9,
+      10,    11,    -1,    -1,    14,    15,    16,    17,    18,    19,
+      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
+      30,    31,    32,    33,    34,    35,    -1,    -1,    -1,    39,
+      40,    41,    42,    43,    44,    45,    46,    47,    -1,    -1,
+      -1,    51,    52,    -1,    54,    55,    56,    -1,    -1,    -1,
+      -1,    -1,    62,    63,    -1,    -1,     3,     4,    -1,    -1,
+      -1,    -1,     9,    10,    11,    -1,    -1,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    36,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    45,    46,
+      47,    -1,    -1,    -1,    -1,    -1,    -1,    54,    55,    56,
+      -1,    -1,    -1,    -1,    -1,    62,    -1,    64,    -1,    -1,
+      67,    -1,    -1,    70,    -1,    72,    -1,    -1,    -1,    -1,
+      -1,    -1,   142,   143,   144,    -1,    -1,    84,    -1,   149,
+     150,   151,   152,   153,    91,    92,    93,    94,    95,    -1,
+      -1,    -1,    99,    -1,    -1,   102,    -1,   167,   168,    -1,
+      -1,    -1,   172,    -1,    -1,    -1,    -1,   177,    -1,    -1,
+      -1,    -1,   182,    -1,   184,    -1,    -1,    -1,    -1,    -1,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,    -1,   142,    -1,    -1,   176,    -1,
+      -1,    -1,   149,   150,   151,   152,   153,   185,    -1,    -1,
       -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-       0,     1,    -1,   170,     4,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    12,    13,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,    -1,    -1,    -1,    37,    38,   177,
-      -1,   179,    -1,    -1,    -1,    -1,    -1,    -1,    48,    49,
-      50,    -1,    -1,    -1,    54,    55,    56,    -1,    58,    59,
-      60,    61,    62,    63,    64,    65,    66,    67,    68,    69,
-      -1,    71,    72,    73,    74,    75,    76,    77,    78,    79,
-      80,    81,    82,    -1,    84,    85,    86,    87,    88,    89,
+     167,   168,    -1,    -1,    -1,   172,     3,     4,     5,    -1,
+     177,    -1,     9,    10,    11,   182,    -1,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35,    -1,
+      -1,    -1,    39,    40,    41,    42,    43,    44,    45,    46,
+      47,    -1,    -1,    -1,    51,    52,    -1,    54,    55,    56,
+      -1,    -1,    -1,    -1,    -1,    62,    63,   108,   109,   110,
+     111,   112,   113,   114,   115,   116,   117,   118,   119,   120,
+     121,   122,   123,   124,   125,   126,   127,   128,   129,   130,
+     131,   132,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,   144,   145,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+     183,    -1,   185,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   142,   143,   144,    -1,    -1,
+      -1,    -1,   149,   150,   151,   152,   153,    -1,    -1,    -1,
+       0,     1,    -1,    -1,     4,    -1,    -1,    -1,    -1,    -1,
+     167,   168,    12,    13,    -1,   172,    -1,    -1,    -1,    -1,
+     177,    -1,    -1,    -1,    -1,   182,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    37,    38,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    48,    49,
+      50,    -1,    -1,    53,    -1,    -1,    -1,    57,    58,   260,
+      60,    61,    -1,    -1,    64,    65,    66,    67,    68,    69,
+      70,    71,    72,    73,    -1,    75,    76,    77,    78,    79,
+      80,    81,    82,    83,    84,    85,    86,    -1,    88,    89,
       90,    91,    92,    93,    94,    95,    96,    97,    98,    99,
-     100,    -1,    -1,    -1,   104,   105,   106,    -1,    -1,    -1,
-      -1,    -1,   112,     4,    -1,    -1,    -1,   117,   118,   119,
-     120,    12,    13,   123,    -1,   125,    -1,   127,   128,   129,
-     130,   131,   132,   133,   134,   135,   136,   137,    -1,    -1,
-      -1,   141,   142,   143,   144,    -1,    37,    38,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    48,    49,    50,
-      -1,    -1,    -1,    54,    55,    56,    -1,    58,    59,    60,
-      61,    62,    63,    64,    65,    66,    67,    68,    69,    -1,
-      71,    72,    73,    74,    75,    76,    77,    78,    79,    80,
-      81,    82,    -1,    84,    85,    86,    87,    88,    89,    90,
-      91,    92,    93,    94,    95,    96,    97,    98,    99,   100,
-      12,    13,    -1,   104,   105,   106,    83,    -1,    -1,    -1,
-      -1,   112,    -1,    -1,    -1,    -1,   117,   118,   119,   120,
-      -1,    -1,   123,    -1,   125,    -1,   127,   128,   129,   130,
-     131,   132,   133,   134,   135,   136,   137,    -1,    -1,    -1,
-     141,   142,   143,   144,    -1,    -1,    -1,    -1,    60,    61,
-      62,    63,    64,    65,    66,    67,    68,    69,    -1,    71,
-      -1,    -1,    -1,    -1,    76,    77,    -1,    79,    80,    81,
-      -1,    -1,    -1,    85,    -1,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   118,   119,   120,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,   177,    -1,   179,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,   177,    -1,   179,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   179,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-     179,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   179,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   179,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,   179,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   179,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-     179,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   179,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   179,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,   179,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   179,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-     179,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   179,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   179,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,   179,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   179,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-     179,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   179,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   179,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,   179,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   179,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-     179,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   179,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,   179,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,   179,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   179,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-     179,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,   178,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,   178,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,   172,    -1,    -1,    -1,    -1,
-     177,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,   177,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,   177,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,   177,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,   177,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-     177,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,   177,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,   177,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,   177,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,   177,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-     177,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,   177,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,   177,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,   177,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,   177,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-     177,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,   177,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,   177,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,   177,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,   177,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-     177,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,   177,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,   177,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,   177,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,   177,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,
-     177,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,    -1,    -1,    -1,   177,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,    -1,
-      -1,    -1,   177,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,    -1,    -1,    -1,   177,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,    -1,    -1,    -1,   177,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,   174,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,
-     174,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,   174,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,    -1,    -1,   174,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,   174,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,
-      -1,    -1,   174,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,   174,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,   174,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,   174,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,    -1,    -1,    -1,   174,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,   174,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,
-     174,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,   174,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,    -1,    -1,   174,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,   174,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,
-      -1,    -1,   174,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,   174,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,   174,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,   174,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,    -1,    -1,    -1,   174,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,   174,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,
-     174,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,   174,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,    -1,    -1,   174,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,   174,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,
-      -1,    -1,   174,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,    -1,    -1,   174,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,   174,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,
-      -1,   174,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,    -1,    -1,    -1,   174,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,    -1,    -1,   174,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,
-     174,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,    -1,    -1,   174,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,    -1,    -1,   174,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,    -1,    -1,   174,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,
-     172,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,   172,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,    -1,   172,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,   172,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,   172,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,
-     172,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,   172,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,    -1,   172,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,   172,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,   172,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,
-     172,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,   172,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,    -1,   172,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,   172,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,   172,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,
-     172,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,   172,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,    -1,   172,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,   172,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,   172,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,
-     172,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,   172,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,    -1,   172,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,   172,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,   172,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,
-     155,   156,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,   153,
-     154,   155,   156,   157,   158,   159,   160,   161,   162,   163,
-     164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,   152,
-     153,   154,   155,   156,   157,   158,   159,   160,   161,   162,
-     163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,   172,
-     152,   153,   154,   155,   156,   157,   158,   159,   160,   161,
-     162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,    -1,
-     172,   152,   153,   154,   155,   156,   157,   158,   159,   160,
-     161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,   170,
-      -1,   172,   152,   153,   154,   155,   156,   157,   158,   159,
-     160,   161,   162,   163,   164,   165,    -1,    -1,    -1,    -1,
-     170,    -1,   172,   152,   153,   154,   155,   156,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,    -1,    -1,    -1,
-      -1,   170,    -1,   172,   152,   153,   154,   155,   156,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,    -1,    -1,
-      -1,    -1,   170,    -1,   172,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,    -1,
-      -1,    -1,    -1,   170,    -1,   172,   152,   153,   154,   155,
-     156,   157,   158,   159,   160,   161,   162,   163,   164,   165,
-      -1,    -1,    -1,    -1,   170
+     100,   101,   102,   103,   104,    -1,    -1,    -1,   108,   109,
+     110,    -1,    -1,    -1,    -1,    -1,   116,     4,    -1,    -1,
+      -1,   121,   122,   123,   124,    12,    13,   127,    -1,   129,
+      -1,   131,   132,   133,   134,   135,   136,   137,   138,   139,
+     140,   141,    -1,    -1,    -1,   145,   146,   147,   148,    -1,
+      37,    38,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    48,    49,    50,    -1,    -1,    53,    -1,    -1,    -1,
+      57,    58,    -1,    60,    61,    -1,    -1,    64,    65,    66,
+      67,    68,    69,    70,    71,    72,    73,    -1,    75,    76,
+      77,    78,    79,    80,    81,    82,    83,    84,    85,    86,
+      -1,    88,    89,    90,    91,    92,    93,    94,    95,    96,
+      97,    98,    99,   100,   101,   102,   103,   104,    12,    13,
+      -1,   108,   109,   110,    -1,    -1,    -1,    -1,    -1,   116,
+      -1,    -1,    -1,    -1,   121,   122,   123,   124,    -1,    -1,
+     127,    -1,   129,    -1,   131,   132,   133,   134,   135,   136,
+     137,   138,   139,   140,   141,    -1,    -1,    -1,   145,   146,
+     147,   148,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      64,    65,    66,    67,    68,    69,    70,    71,    72,    73,
+      -1,    75,    -1,    -1,    -1,    -1,    80,    81,    -1,    83,
+      84,    85,    -1,    -1,    -1,    89,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+      -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,
+      -1,   183,    -1,   185,    -1,    -1,    -1,    -1,   122,   123,
+     124,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   185,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   185,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   185,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   185,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     185,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   185,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   185,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   185,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   185,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     185,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   185,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   185,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   185,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   185,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     185,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   185,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   185,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   185,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   185,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     185,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   185,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,   185,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,   185,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   185,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+     185,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,   185,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,   184,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+      -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   184,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,   178,    -1,    -1,    -1,    -1,   183,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,   183,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+     183,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,   183,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,   183,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,   183,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,   183,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+     183,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,   183,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,   183,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,   183,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,   183,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+     183,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,   183,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,   183,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,   183,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,   183,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+     183,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,   183,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,   183,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,   183,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,    -1,    -1,    -1,   183,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,
+     183,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,    -1,    -1,    -1,   183,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,    -1,
+      -1,    -1,   183,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,    -1,    -1,    -1,   183,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,   178,
+      -1,   180,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,
+     176,    -1,    -1,    -1,   180,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,   180,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,
+     180,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,   180,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,    -1,    -1,
+      -1,    -1,   176,    -1,    -1,    -1,   180,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,   180,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,
+      -1,    -1,   180,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,    -1,    -1,   180,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+      -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,   180,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,
+      -1,   180,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,
+     176,    -1,    -1,    -1,   180,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,    -1,    -1,   180,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,    -1,    -1,    -1,    -1,   176,    -1,    -1,    -1,
+     180,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,    -1,    -1,   180,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,    -1,    -1,
+      -1,    -1,   176,    -1,    -1,    -1,   180,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,   178,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,    -1,    -1,    -1,    -1,   176,    -1,   178,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,   178,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,
+     178,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,   178,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,
+     176,    -1,   178,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,   178,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,    -1,    -1,
+      -1,    -1,   176,    -1,   178,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,   178,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+      -1,    -1,    -1,    -1,   176,    -1,   178,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,   178,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,    -1,    -1,    -1,    -1,   176,    -1,   178,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,   178,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,
+     178,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,   178,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,
+     176,    -1,   178,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,   178,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,    -1,    -1,
+      -1,    -1,   176,    -1,   178,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,   178,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+      -1,    -1,    -1,    -1,   176,    -1,   178,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,   178,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,    -1,    -1,    -1,    -1,   176,    -1,   178,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,   178,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,
+     178,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,
+      -1,   178,   158,   159,   160,   161,   162,   163,   164,   165,
+     166,   167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,
+     176,    -1,   178,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,   168,   169,   170,   171,    -1,    -1,    -1,
+      -1,   176,    -1,   178,   158,   159,   160,   161,   162,   163,
+     164,   165,   166,   167,   168,   169,   170,   171,    -1,    -1,
+      -1,    -1,   176,    -1,   178,   158,   159,   160,   161,   162,
+     163,   164,   165,   166,   167,   168,   169,   170,   171,    -1,
+      -1,    -1,    -1,   176,    -1,   178,   158,   159,   160,   161,
+     162,   163,   164,   165,   166,   167,   168,   169,   170,   171,
+      -1,    -1,    -1,    -1,   176,    -1,   178,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,    -1,    -1,    -1,    -1,   176,    -1,   178,   158,   159,
+     160,   161,   162,   163,   164,   165,   166,   167,   168,   169,
+     170,   171,    -1,    -1,    -1,    -1,   176,    -1,   178,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,   178,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,   169,   170,   171,    -1,    -1,    -1,    -1,   176,    -1,
+     178,   158,   159,   160,   161,   162,   163,   164,   165,   166,
+     167,   168,   169,   170,   171,    -1,    -1,    -1,    -1,   176
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint16 yystos[] =
 {
-       0,     1,   182,   183,     6,     0,     4,    12,    13,    37,
-      38,    48,    49,    50,    54,    55,    56,    58,    59,    60,
-      61,    62,    63,    64,    65,    66,    67,    68,    69,    71,
-      72,    73,    74,    75,    76,    77,    78,    79,    80,    81,
-      82,    84,    85,    86,    87,    88,    89,    90,    91,    92,
-      93,    94,    95,    96,    97,    98,    99,   100,   104,   105,
-     106,   112,   117,   118,   119,   120,   123,   125,   127,   128,
-     129,   130,   131,   132,   133,   134,   135,   136,   137,   141,
-     142,   143,   144,   184,   186,   187,   205,   219,   224,   227,
-     228,   229,   230,   231,   232,   233,   253,   254,   255,   256,
-     272,   273,     3,     4,     5,     9,    10,    11,    14,    15,
+       0,     1,   188,   189,     6,     0,     4,    12,    13,    37,
+      38,    48,    49,    50,    53,    57,    58,    60,    61,    64,
+      65,    66,    67,    68,    69,    70,    71,    72,    73,    75,
+      76,    77,    78,    79,    80,    81,    82,    83,    84,    85,
+      86,    88,    89,    90,    91,    92,    93,    94,    95,    96,
+      97,    98,    99,   100,   101,   102,   103,   104,   108,   109,
+     110,   116,   121,   122,   123,   124,   127,   129,   131,   132,
+     133,   134,   135,   136,   137,   138,   139,   140,   141,   145,
+     146,   147,   148,   190,   192,   193,   213,   227,   232,   235,
+     236,   237,   238,   239,   240,   241,   261,   262,   263,   264,
+     282,   283,     3,     4,     5,     9,    10,    11,    14,    15,
       16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
       26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
       39,    40,    41,    42,    43,    44,    45,    46,    47,    51,
-      52,    53,   132,   138,   139,   140,   145,   146,   147,   161,
-     162,   166,   171,   173,   175,   176,   178,   180,   257,   258,
-     269,   270,   273,    13,    66,   171,   171,     6,   178,     6,
-       6,     6,     6,     6,   173,   173,   171,   178,   171,   171,
-       4,   171,   178,   171,   171,     4,   178,   171,   171,    70,
-      66,    66,     6,   178,    60,    63,    66,    66,    66,    63,
-      66,    68,    68,    60,    63,    66,    68,    63,    66,    68,
-      63,    66,   171,    63,   123,   136,   137,   178,   161,   162,
-     171,   178,   259,   260,   259,   178,    60,    63,    66,   178,
-     259,     4,    60,    64,    76,    66,    68,    66,    63,     4,
-     132,   178,     4,     6,    60,    63,    66,    63,    66,     4,
-       4,     4,     4,     5,    36,    60,    63,    66,    68,    80,
-     162,   171,   178,   224,   233,   257,   262,   263,   264,   273,
-       4,   171,   171,   171,     4,   178,   266,     4,   171,   171,
-       6,     6,   173,     4,     4,     5,   178,     5,   178,     4,
-     257,     6,   171,   178,   180,     7,   148,   149,   150,   151,
-     168,   169,   203,   204,     4,   173,   175,   171,   173,   171,
-     173,   171,   173,   171,   173,   171,   173,   171,   173,   171,
-     173,   171,   173,   171,   173,   171,   173,   171,   173,   171,
-     173,   171,   173,   171,   173,   171,   173,   171,   173,   171,
-     173,   171,   173,   171,   173,   171,   173,   171,   173,   171,
-     173,   171,   173,   171,   173,   171,   173,   171,   171,   171,
-     171,   171,   171,     7,   171,   171,   171,   257,   257,   257,
-     178,   257,   174,   178,   257,     4,   123,   124,     4,     4,
-     224,   225,   226,   178,     6,   152,   153,   154,   155,   156,
-     157,   158,   159,   160,   161,   162,   163,   164,   165,   170,
-     178,     6,   204,     6,   257,     4,   269,   270,   273,   269,
-     257,   207,   210,   257,   162,   257,   264,   265,   257,   257,
-     171,   257,   265,   257,   257,   171,   265,   257,   257,   262,
-     171,   178,   265,   263,   263,   263,   171,   171,   263,   263,
-     263,   171,   220,   221,   222,   223,   171,   171,   171,   262,
-     257,     4,   262,   266,   178,   178,   259,   259,   259,   257,
-     257,   161,   162,   178,   178,   259,   178,   178,   178,   161,
-     162,   171,   226,   259,   178,   171,   178,   171,   171,   171,
-     263,   263,   262,   171,     4,     6,   173,   173,   226,     6,
-     178,   178,   178,   263,   263,   173,   173,   173,   171,   173,
-     175,   173,     5,   178,     5,     5,     5,    60,    63,    66,
-      68,   178,   257,   264,   257,   179,   265,     8,   163,     6,
-       6,   257,   257,   257,   175,   257,   178,   126,   257,   257,
-     257,     6,     6,   226,     6,   226,   173,     6,   262,   262,
-     178,   270,   262,     6,   173,   257,     4,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   269,   271,   271,   269,   269,   269,   269,   269,   269,
-     269,   269,   269,   271,   257,   269,   269,   269,   265,   172,
-       7,   203,   265,   174,     7,   203,   204,   175,     7,   173,
-     179,    60,    63,    66,    68,   219,   257,   257,   257,   257,
-     257,   257,   257,   257,   257,   257,   257,   257,   257,   257,
-     257,   257,   188,     6,   173,   175,   172,   177,   172,   177,
-     177,   174,   177,   206,   174,   206,   172,   163,   177,   179,
-     172,   172,   257,   172,   179,   172,   172,   257,   179,   172,
-     172,     7,   257,   257,   179,     6,     6,     6,   257,   257,
-       7,     7,   251,   251,   257,   171,   171,   171,   171,   257,
-     257,   257,     7,   178,   172,     6,   178,   226,   226,   177,
-     177,   177,   259,   259,   225,   225,   177,   257,   257,   257,
-     257,   237,   177,   226,   257,   257,   257,   257,   257,     7,
-     252,     6,     7,   257,     6,   257,   257,   179,   265,   265,
-     265,     6,     6,   257,   257,   257,   172,   178,   174,   178,
-     257,     4,     4,   257,   178,   178,   178,   178,   265,   172,
-     179,   257,   178,   257,   264,   172,   172,   172,   123,   177,
-     226,   178,     8,   172,   174,   179,   179,   172,   177,   179,
-     257,     6,     6,   257,   174,   204,   172,   174,   172,   174,
-     172,   174,   172,   174,   172,   174,   172,   174,   172,   174,
-     172,   174,   172,   174,   172,   174,   172,   174,   177,   177,
-     172,   174,   172,   174,   172,   174,   172,   174,   172,   174,
-     172,   174,   172,   174,   177,   177,   177,   177,   177,   177,
-     172,   177,   174,   172,   177,   174,   177,   177,   177,   172,
-     172,   177,   177,   177,   172,     6,   177,   172,   177,   179,
-     203,   262,   179,   175,   203,   204,   270,   257,     6,     4,
-       4,   178,   267,   174,   178,   178,   178,   178,   179,     8,
-       4,   113,   114,   115,   116,   179,   191,   195,   198,   200,
-     201,   257,     4,     6,   158,   185,   265,     6,   265,   257,
-       6,     4,   273,     6,   269,     7,   257,   264,   126,     7,
-       7,   172,     7,   126,     7,     7,   172,   126,     7,     7,
-     257,   172,   179,   178,   172,   172,   257,   262,     4,   250,
-       6,   172,   216,   257,   270,   216,   216,   216,   172,   172,
-     172,   262,   265,   175,   226,   179,   179,   259,   257,   257,
-     179,   179,   257,   259,   177,   177,   177,    83,    93,   101,
-     102,   103,   107,   108,   109,   110,   247,   248,   259,   179,
-     234,   172,   179,   172,   172,   172,   257,     6,   257,   172,
-     174,   174,   179,   179,   179,   174,   174,   177,   265,   265,
-     174,   174,   179,   265,   265,   265,   265,   179,     8,   265,
-       7,     7,     7,   175,   257,   179,   257,   257,     7,   175,
-     178,   262,     6,   179,   174,   175,   204,   269,   257,   257,
-     257,   257,   257,   257,   257,   257,   269,   265,   265,   269,
-     269,   269,   269,   269,   257,   269,   172,   257,     6,   174,
-       4,   123,   124,   257,     6,     6,     6,     7,   173,   266,
-     268,     6,   265,   265,   265,   265,   257,   192,   171,   171,
-     178,   202,     6,   174,   158,   269,   172,   172,   177,     7,
-     259,    66,    68,   262,   262,     7,   262,    66,    68,   262,
-     262,     7,    68,   262,   262,     6,     7,     7,   265,     7,
-       7,    83,   249,     6,     7,   172,   172,   172,   172,     7,
-       7,     7,     6,   179,     4,   179,   177,   177,   177,   179,
-     179,   259,   259,   259,     4,     6,   178,     6,   171,     6,
-     111,     6,   111,     6,   111,     6,   111,   179,   248,   177,
-     247,     7,     6,     7,     7,     7,     6,   178,     6,     6,
-       6,    66,   257,     6,     6,   257,   179,   179,   175,   179,
-     179,   179,   179,   257,   179,   262,   262,   262,     4,   177,
-       8,     8,   172,     4,     4,   262,   179,     6,     4,     6,
-     172,   174,   172,   174,   172,   174,   172,   174,   172,   174,
-     172,   174,   177,   172,   172,   172,   172,   203,     6,   203,
-       7,   203,   204,   175,     7,     6,   266,   257,   177,   179,
-     179,   179,   179,   179,   171,   257,   257,   261,   262,   178,
-     175,     6,     6,   185,     6,   257,   178,   257,   270,     6,
-     178,   178,    76,   218,   218,   262,     6,   178,   178,     6,
-       6,   262,   178,     6,     6,     5,   262,   179,   262,   262,
-       4,     6,   262,     7,     7,     7,     7,   262,   262,   262,
-       7,     6,     7,   257,   257,   257,   178,   178,   177,   179,
-     177,   179,   177,   179,   173,   257,   262,   257,     6,     6,
-       6,     6,   257,   259,   179,     5,   178,   262,   178,   178,
-     178,   262,   265,   178,     6,   174,   172,   174,     4,     6,
-       6,   122,   257,   257,   257,     6,     6,     7,   177,     6,
-     204,   269,   262,   262,   270,   257,     6,     4,   267,     6,
-     174,   266,     6,     6,     6,     6,   189,   257,   177,   177,
-     177,   179,   190,   257,     4,   269,   177,   257,   270,   257,
-     257,   259,     6,     6,     6,   257,   257,     6,   257,     5,
-       6,   178,     6,   126,   217,   257,     6,   262,   262,   262,
-     262,     6,     4,     6,     6,   257,   257,   270,   179,   172,
-     177,   179,   225,   225,   259,     6,   238,   259,     6,   239,
-     259,     6,   240,   257,   179,   177,   172,   179,   177,     6,
-     162,   259,     6,   261,   259,   259,     6,   179,   257,     6,
-     262,   177,   179,     8,   179,   172,   178,   257,   270,   262,
-     172,     6,     6,     6,     6,     7,     6,   175,   172,   177,
-     257,   257,   262,   178,   177,   179,     6,   257,   208,   209,
-     179,   179,   179,   179,   179,     5,   261,    64,     6,     6,
-       6,     6,     6,   178,   178,     6,     6,   178,   257,   179,
-     179,   177,   178,   177,   178,   177,   178,   174,     6,   262,
-       7,   178,   257,   177,   179,   177,   177,     6,   179,   121,
-     257,   257,   265,     6,     6,   179,   266,   124,   193,   257,
-     177,   177,   261,   257,     6,   177,   212,   214,     6,     6,
-       6,     6,     6,     6,   179,   178,   261,   265,   225,   177,
-     179,   257,   259,   247,   257,   259,   247,   257,   259,   247,
-       6,   177,   179,   262,   226,   179,   259,     6,   265,   259,
-     257,   179,   179,   179,     6,     6,   178,   257,   257,   179,
-     257,   177,   179,   213,   177,   179,   215,   178,   257,   179,
-     179,   179,   257,   179,   177,   179,   179,   177,   179,   179,
-     177,   179,   262,     6,    83,   179,   235,   178,   177,   179,
-     177,     6,     6,   190,   172,   177,     6,   178,   177,     4,
-       4,   257,   179,     6,     6,   179,     6,   241,   257,     6,
-       6,   242,   257,     6,     6,   243,   257,     6,   179,   257,
-     247,   226,   265,     6,   259,   265,   179,   196,   257,   261,
-     257,   178,   262,   270,   178,   257,   270,   177,   178,   179,
-     178,   179,   178,   179,     6,     6,   179,   179,   236,   179,
-     177,   179,     6,   178,   172,   179,   179,   211,   257,   271,
-     257,   247,     6,   244,   247,     6,   245,   247,     6,   246,
-     247,     6,   265,     6,   194,   269,   199,   178,     6,   177,
-     179,     7,   179,   179,   179,   178,   179,   178,   179,   178,
-     179,   179,   177,   179,   178,   261,   257,   270,     6,     6,
-     247,     6,   247,     6,   247,     6,   269,     6,   197,   269,
-     179,     7,   179,   179,   179,   177,   179,     6,   270,     6,
-       6,     6,   269,     6
+      52,    54,    55,    56,    62,    63,   136,   142,   143,   144,
+     149,   150,   151,   152,   153,   167,   168,   172,   177,   179,
+     181,   182,   184,   186,   211,   265,   266,   278,   279,   282,
+     283,    13,    70,   177,   177,     6,   184,     6,     6,     6,
+       6,     6,   179,   179,   177,   184,   177,   177,     4,   177,
+     184,   177,   177,     4,   184,   177,   177,    74,    70,    70,
+       6,   184,    64,    67,    70,    70,    70,    67,    70,    72,
+      72,    64,    67,    70,    72,    67,    70,    72,    67,    70,
+     177,    67,   127,   140,   141,   184,   167,   168,   177,   184,
+     268,   269,   268,   184,    64,    67,    70,   184,   268,     4,
+      64,    68,    80,    70,    72,    70,    67,     4,   136,   184,
+       4,     6,    64,    67,    70,    67,    70,     4,     4,     4,
+       4,     5,    36,    64,    67,    70,    72,    84,   168,   177,
+     184,   232,   241,   265,   271,   272,   273,   283,     4,   177,
+     177,   177,     4,   184,   275,     4,   177,   177,     6,     6,
+     179,     4,     4,     5,   184,     5,   184,     4,   265,     6,
+     177,   184,   177,   179,   186,     7,   154,   155,   156,   157,
+     174,   175,   209,   210,     4,   179,   181,   177,   179,   211,
+     211,   211,   211,   211,   211,   211,   211,   211,   211,   211,
+     211,   211,   211,   211,   211,   211,   211,   211,   211,   211,
+     211,   211,   211,   211,   177,   177,   177,   177,   177,   177,
+     211,   211,     7,   177,   177,   177,   177,   177,   265,   265,
+     265,   265,   180,   265,     4,   127,   128,     4,   282,   283,
+       4,   232,   233,   234,   184,   184,     6,   158,   159,   160,
+     161,   162,   163,   164,   165,   166,   167,   168,   169,   170,
+     171,   176,   184,     6,   179,   210,     6,   265,     4,   278,
+     279,   283,   278,   265,   215,   218,   265,   168,   265,   273,
+     274,   265,   265,   177,   265,   274,   265,   265,   177,   274,
+     265,   265,   271,   177,   184,   274,   272,   272,   272,   177,
+     177,   272,   272,   272,   177,   228,   229,   230,   231,   177,
+     177,   177,   271,   265,     4,   271,   275,   184,   184,   268,
+     268,   268,   265,   265,   167,   168,   184,   184,   268,   184,
+     184,   184,   167,   168,   177,   234,   268,   184,   177,   184,
+     177,   177,   177,   272,   272,   271,   177,     4,     6,   179,
+     179,   234,     6,   184,   184,   184,   272,   272,   179,   179,
+     179,   179,   181,   211,   179,     5,   184,     5,     5,     5,
+      64,    67,    70,    72,   184,   265,   273,   265,   185,   274,
+       8,   169,     6,     6,   265,   265,   265,   181,   265,   184,
+     130,   265,   265,   265,     6,     6,   234,     6,   234,   179,
+       6,   271,   271,   184,   265,   184,   279,   271,     6,   179,
+     265,     4,   265,   265,   265,   265,   265,   265,   265,   265,
+     265,   265,   265,   265,   265,   265,   265,   265,   265,   265,
+     265,   265,   265,   265,   278,   281,   278,   278,   278,   278,
+     278,   278,   278,   281,   265,   279,   265,   278,   278,   278,
+     283,   279,   178,     7,   209,   180,     7,   209,   210,   181,
+       7,   179,   185,    64,    67,    70,    72,   227,   265,   274,
+     265,   265,   265,   265,   265,   265,   265,   265,   265,   265,
+     265,   265,   265,   265,   265,   194,   265,     6,   179,   181,
+     178,   183,   178,   183,   183,   180,   183,   214,   180,   214,
+     178,   169,   183,   185,   178,   178,   265,   178,   185,   178,
+     178,   265,   185,   178,   178,     7,   265,   265,   185,     6,
+       6,     6,   265,   265,     7,     7,   259,   259,   265,   177,
+     177,   177,   177,   265,   265,   265,     7,   184,   178,     6,
+     184,   234,   234,   183,   183,   183,   268,   268,   233,   233,
+     183,   265,   265,   265,   265,   245,   183,   234,   265,   265,
+     265,   265,   265,     7,   260,     6,     7,   265,     6,   265,
+     265,   185,   274,   274,   274,     6,     6,   265,   265,   265,
+     265,     4,   178,   180,   184,   212,     4,   265,   184,   184,
+     184,   184,   274,   178,   185,   265,   184,   265,   273,   178,
+     178,   178,   127,   183,   234,   184,     8,   178,   180,   185,
+     185,   178,   183,   185,   274,   180,   265,     6,     6,   265,
+     180,   210,   212,   212,   212,   212,   212,   212,   212,   212,
+     212,   212,   212,   183,   212,   212,   212,   212,   212,   212,
+     212,   183,   183,   183,   183,   212,   183,   212,   183,   178,
+     178,   183,   183,   183,   178,   267,   280,     6,   183,   178,
+     183,   178,   178,   209,   271,   181,   209,   210,   279,   265,
+       6,     4,     4,   184,   276,   180,   184,   184,   184,   184,
+     185,   185,     8,     4,   117,   118,   119,   120,   185,   197,
+     201,   204,   206,   207,   180,   265,     4,     6,   164,   191,
+     274,     6,   274,   265,     6,   283,     6,   278,     7,   265,
+     273,   130,     7,     7,   178,     7,   130,     7,     7,   178,
+     130,     7,     7,   265,   178,   185,   184,   178,   178,   265,
+     271,     4,   258,     6,   178,   224,   265,   279,   224,   224,
+     224,   178,   178,   178,   271,   274,   181,   234,   185,   185,
+     268,   265,   265,   185,   185,   265,   268,   183,   183,   183,
+      87,    97,   105,   106,   107,   111,   112,   113,   114,   255,
+     256,   268,   185,   242,   178,   185,   178,   178,   178,   265,
+       6,   265,   178,   180,   180,   185,   185,   185,   180,   180,
+     183,   180,   274,   180,   185,   274,   274,   274,   274,   185,
+       8,   274,     7,     7,     7,   181,   265,   185,   265,   265,
+       7,   181,   184,   271,     6,   185,   209,   210,   185,   180,
+     181,   210,   278,   265,   265,   265,   265,   278,   274,   278,
+     278,   278,   278,   220,   222,   265,   278,   265,     6,     4,
+     127,   128,   265,     6,     6,     6,     7,   179,   275,   277,
+       6,   274,   274,   274,   274,   212,   265,   198,   177,   177,
+     184,   208,     6,   210,   180,   164,   278,   178,   178,   183,
+       7,   268,    70,    72,   271,   271,     7,   271,    70,    72,
+     271,   271,     7,    72,   271,   271,     6,     7,     7,   274,
+       7,     7,    87,   257,     6,     7,   178,   178,   178,   178,
+       7,     7,     7,     6,   185,     4,   185,   183,   183,   183,
+     185,   185,   268,   268,   268,     4,     6,   184,     6,   177,
+       6,   115,     6,   115,     6,   115,     6,   115,   185,   256,
+     183,   255,     7,     6,     7,     7,     7,     6,   184,     6,
+       6,     6,    70,   265,     6,     6,   265,   181,   185,   185,
+     185,   185,   185,   265,   185,   271,   271,   271,     4,   183,
+       8,     8,   178,     4,     4,   271,   185,   178,   265,     6,
+       6,     4,     6,   212,   212,   212,   212,   212,   212,   183,
+     178,   178,   183,   212,   221,   183,   212,   223,   178,   178,
+       6,     7,   209,   210,   181,     7,     6,   275,   265,   183,
+     185,   185,   185,   185,   185,   209,   177,   265,   265,   270,
+     271,   184,   181,     6,     6,   191,     6,   265,   184,   265,
+     279,     6,   184,   184,    80,   226,   226,   271,     6,   184,
+     184,     6,     6,   271,   184,     6,     6,     5,   271,   185,
+     271,   271,     4,     6,   271,     7,     7,     7,     7,   271,
+     271,   271,     7,     6,     7,   265,   265,   265,   184,   184,
+     183,   185,   183,   185,   183,   185,   179,   265,   271,   265,
+       6,     6,     6,     6,   265,   268,   185,     5,   184,   271,
+     184,   184,   184,   271,   274,   184,     6,   180,     4,   212,
+       6,     6,   126,   265,   265,   265,     6,     6,     7,   183,
+       6,   209,     6,   210,   278,     4,     4,   279,   265,     6,
+       4,   276,     6,   180,   275,     6,     6,     6,     6,   271,
+     195,   265,   183,   183,   183,   185,   196,   265,     4,   278,
+     183,   265,   279,   265,   265,   268,     6,     6,     6,   265,
+     265,     6,   265,     5,     6,   184,     6,   130,   225,   265,
+       6,   271,   271,   271,   271,     6,     4,     6,     6,   265,
+     265,   279,   185,   178,   183,   185,   233,   233,   268,     6,
+     246,   268,     6,   247,   268,     6,   248,   265,   185,   183,
+     178,   185,   183,     6,   168,   268,     6,   270,   268,   268,
+       6,   185,   265,     6,   271,   183,   185,     8,   185,   178,
+     184,   265,   279,   271,   271,   178,   184,   271,   279,   184,
+     265,   279,     6,     6,     7,     6,   181,     6,   178,   183,
+     265,   265,   271,   184,   183,   185,     6,   265,   216,   217,
+     185,   185,   185,   185,   185,     5,   270,    68,     6,     6,
+       6,     6,     6,   184,   184,     6,     6,   184,   265,   185,
+     185,   183,   184,   183,   184,   183,   184,   180,     6,   271,
+       7,   184,   265,   183,   185,   183,   183,     6,   185,   125,
+     265,   265,   274,     6,     6,   185,     6,   219,   265,   281,
+     275,   128,   199,   265,   183,   183,   270,   265,     6,   183,
+     220,   222,     6,     6,     6,     6,     6,     6,   185,   184,
+     270,   274,   233,   183,   185,   265,   268,   255,   265,   268,
+     255,   265,   268,   255,     6,   183,   185,   271,   234,   185,
+     268,     6,   274,   268,   265,   185,   185,   185,     6,   183,
+     185,     7,   185,     6,   184,   265,   265,   185,   265,   185,
+     185,   184,   265,   185,   185,   185,   265,   185,   183,   185,
+     185,   183,   185,   185,   183,   185,   271,     6,    87,   185,
+     243,   184,   183,   185,   183,     6,     6,   265,   279,   196,
+     178,   183,     6,   184,   183,   265,   185,     6,     6,   185,
+       6,   249,   265,     6,     6,   250,   265,     6,     6,   251,
+     265,     6,   185,   265,   255,   234,   274,     6,   268,   274,
+       7,   185,   202,   265,   270,   265,   183,   184,   185,   184,
+     185,   184,   185,     6,     6,   185,   185,   244,   185,   183,
+     185,   279,     6,   184,   178,   185,   185,   265,   255,     6,
+     252,   255,     6,   253,   255,     6,   254,   255,     6,   274,
+       6,   200,   278,   205,   184,     6,   185,   185,   184,   185,
+     184,   185,   184,   185,   185,   183,   185,   184,   270,     6,
+       6,   255,     6,   255,     6,   255,     6,   278,     6,   203,
+     278,   185,   185,   185,   185,   183,   185,     6,     6,     6,
+       6,   278,     6
 };
 
 #define yyerrok		(yyerrstatus = 0)
@@ -4501,101 +4369,101 @@ yyreduce:
   switch (yyn)
     {
         case 3:
-#line 173 "Gmsh.y"
+#line 183 "Gmsh.y"
     { yyerrok; return 1; ;}
     break;
 
   case 6:
-#line 184 "Gmsh.y"
+#line 194 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 7:
-#line 185 "Gmsh.y"
+#line 195 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 8:
-#line 186 "Gmsh.y"
+#line 196 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 9:
-#line 187 "Gmsh.y"
+#line 197 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 10:
-#line 188 "Gmsh.y"
+#line 198 "Gmsh.y"
     { List_Delete((yyvsp[(1) - (1)].l)); return 1; ;}
     break;
 
   case 11:
-#line 189 "Gmsh.y"
+#line 199 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 12:
-#line 190 "Gmsh.y"
+#line 200 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 13:
-#line 191 "Gmsh.y"
+#line 201 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 14:
-#line 192 "Gmsh.y"
+#line 202 "Gmsh.y"
     { List_Delete((yyvsp[(1) - (1)].l)); return 1; ;}
     break;
 
   case 15:
-#line 193 "Gmsh.y"
+#line 203 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 16:
-#line 194 "Gmsh.y"
+#line 204 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 17:
-#line 195 "Gmsh.y"
+#line 205 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 18:
-#line 196 "Gmsh.y"
+#line 206 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 19:
-#line 197 "Gmsh.y"
+#line 207 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 20:
-#line 198 "Gmsh.y"
+#line 208 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 21:
-#line 203 "Gmsh.y"
+#line 213 "Gmsh.y"
     {
       (yyval.c) = (char*)"w";
     ;}
     break;
 
   case 22:
-#line 207 "Gmsh.y"
+#line 217 "Gmsh.y"
     {
       (yyval.c) = (char*)"a";
     ;}
     break;
 
   case 23:
-#line 214 "Gmsh.y"
+#line 224 "Gmsh.y"
     {
       Msg::Direct((yyvsp[(3) - (5)].c));
       Free((yyvsp[(3) - (5)].c));
@@ -4603,7 +4471,7 @@ yyreduce:
     break;
 
   case 24:
-#line 219 "Gmsh.y"
+#line 229 "Gmsh.y"
     {
       Msg::Error((yyvsp[(3) - (5)].c));
       Free((yyvsp[(3) - (5)].c));
@@ -4611,7 +4479,7 @@ yyreduce:
     break;
 
   case 25:
-#line 224 "Gmsh.y"
+#line 234 "Gmsh.y"
     {
       std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(6) - (7)].c));
       FILE *fp = Fopen(tmp.c_str(), (yyvsp[(5) - (7)].c));
@@ -4628,7 +4496,7 @@ yyreduce:
     break;
 
   case 26:
-#line 238 "Gmsh.y"
+#line 248 "Gmsh.y"
     {
       char tmpstring[5000];
       int i = PrintListOfDouble((yyvsp[(3) - (7)].c), (yyvsp[(5) - (7)].l), tmpstring);
@@ -4644,7 +4512,7 @@ yyreduce:
     break;
 
   case 27:
-#line 251 "Gmsh.y"
+#line 261 "Gmsh.y"
     {
       char tmpstring[5000];
       int i = PrintListOfDouble((yyvsp[(3) - (7)].c), (yyvsp[(5) - (7)].l), tmpstring);
@@ -4660,7 +4528,7 @@ yyreduce:
     break;
 
   case 28:
-#line 264 "Gmsh.y"
+#line 274 "Gmsh.y"
     {
       char tmpstring[5000];
       int i = PrintListOfDouble((yyvsp[(3) - (9)].c), (yyvsp[(5) - (9)].l), tmpstring);
@@ -4686,7 +4554,7 @@ yyreduce:
     break;
 
   case 29:
-#line 292 "Gmsh.y"
+#line 302 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(1) - (6)].c), "View") && ViewData->finalize()){
@@ -4703,7 +4571,7 @@ yyreduce:
     break;
 
   case 30:
-#line 306 "Gmsh.y"
+#line 316 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (6)].c), "View")){
@@ -4719,7 +4587,7 @@ yyreduce:
     break;
 
   case 31:
-#line 319 "Gmsh.y"
+#line 329 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (6)].c), "View")){
@@ -4735,7 +4603,7 @@ yyreduce:
     break;
 
   case 32:
-#line 332 "Gmsh.y"
+#line 342 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (8)].c), "View")){
@@ -4753,7 +4621,7 @@ yyreduce:
     break;
 
   case 33:
-#line 350 "Gmsh.y"
+#line 360 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData = new PViewDataList();
@@ -4762,27 +4630,27 @@ yyreduce:
     break;
 
   case 39:
-#line 364 "Gmsh.y"
+#line 374 "Gmsh.y"
     { ViewCoord.push_back((yyvsp[(1) - (1)].d)); ;}
     break;
 
   case 40:
-#line 366 "Gmsh.y"
+#line 376 "Gmsh.y"
     { ViewCoord.push_back((yyvsp[(3) - (3)].d)); ;}
     break;
 
   case 41:
-#line 371 "Gmsh.y"
+#line 381 "Gmsh.y"
     { if(ViewValueList) ViewValueList->push_back((yyvsp[(1) - (1)].d)); ;}
     break;
 
   case 42:
-#line 373 "Gmsh.y"
+#line 383 "Gmsh.y"
     { if(ViewValueList) ViewValueList->push_back((yyvsp[(3) - (3)].d)); ;}
     break;
 
   case 43:
-#line 378 "Gmsh.y"
+#line 388 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strncmp((yyvsp[(1) - (1)].c), "SP", 2)){
@@ -4889,7 +4757,7 @@ yyreduce:
     break;
 
   case 44:
-#line 482 "Gmsh.y"
+#line 492 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(ViewValueList){
@@ -4902,7 +4770,7 @@ yyreduce:
     break;
 
   case 45:
-#line 492 "Gmsh.y"
+#line 502 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(ViewValueList) (*ViewNumList)++;
@@ -4911,7 +4779,7 @@ yyreduce:
     break;
 
   case 46:
-#line 501 "Gmsh.y"
+#line 511 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       for(int i = 0; i < (int)strlen((yyvsp[(1) - (1)].c)) + 1; i++) ViewData->T2C.push_back((yyvsp[(1) - (1)].c)[i]);
@@ -4921,7 +4789,7 @@ yyreduce:
     break;
 
   case 47:
-#line 508 "Gmsh.y"
+#line 518 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       for(int i = 0; i < (int)strlen((yyvsp[(3) - (3)].c)) + 1; i++) ViewData->T2C.push_back((yyvsp[(3) - (3)].c)[i]);
@@ -4931,7 +4799,7 @@ yyreduce:
     break;
 
   case 48:
-#line 518 "Gmsh.y"
+#line 528 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData->T2D.push_back((yyvsp[(3) - (8)].d));
@@ -4943,7 +4811,7 @@ yyreduce:
     break;
 
   case 49:
-#line 527 "Gmsh.y"
+#line 537 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData->NbT2++;
@@ -4952,7 +4820,7 @@ yyreduce:
     break;
 
   case 50:
-#line 536 "Gmsh.y"
+#line 546 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       for(int i = 0; i < (int)strlen((yyvsp[(1) - (1)].c)) + 1; i++) ViewData->T3C.push_back((yyvsp[(1) - (1)].c)[i]);
@@ -4962,7 +4830,7 @@ yyreduce:
     break;
 
   case 51:
-#line 543 "Gmsh.y"
+#line 553 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       for(int i = 0; i < (int)strlen((yyvsp[(3) - (3)].c)) + 1; i++) ViewData->T3C.push_back((yyvsp[(3) - (3)].c)[i]);
@@ -4972,7 +4840,7 @@ yyreduce:
     break;
 
   case 52:
-#line 553 "Gmsh.y"
+#line 563 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData->T3D.push_back((yyvsp[(3) - (10)].d)); ViewData->T3D.push_back((yyvsp[(5) - (10)].d));
@@ -4983,7 +4851,7 @@ yyreduce:
     break;
 
   case 53:
-#line 561 "Gmsh.y"
+#line 571 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData->NbT3++;
@@ -4992,7 +4860,7 @@ yyreduce:
     break;
 
   case 54:
-#line 571 "Gmsh.y"
+#line 581 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       int type =
@@ -5011,7 +4879,7 @@ yyreduce:
     break;
 
   case 55:
-#line 590 "Gmsh.y"
+#line 600 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       int type =
@@ -5030,7 +4898,7 @@ yyreduce:
     break;
 
   case 56:
-#line 609 "Gmsh.y"
+#line 619 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewValueList = &ViewData->Time;
@@ -5039,48 +4907,68 @@ yyreduce:
     break;
 
   case 57:
-#line 615 "Gmsh.y"
+#line 625 "Gmsh.y"
     {
     ;}
     break;
 
   case 58:
-#line 622 "Gmsh.y"
+#line 632 "Gmsh.y"
     { (yyval.i) = 0; ;}
     break;
 
   case 59:
-#line 623 "Gmsh.y"
+#line 633 "Gmsh.y"
     { (yyval.i) = 1; ;}
     break;
 
   case 60:
-#line 624 "Gmsh.y"
+#line 634 "Gmsh.y"
     { (yyval.i) = 2; ;}
     break;
 
   case 61:
-#line 625 "Gmsh.y"
+#line 635 "Gmsh.y"
     { (yyval.i) = 3; ;}
     break;
 
   case 62:
-#line 626 "Gmsh.y"
+#line 636 "Gmsh.y"
     { (yyval.i) = 4; ;}
     break;
 
   case 63:
-#line 630 "Gmsh.y"
+#line 640 "Gmsh.y"
     { (yyval.i) = 1; ;}
     break;
 
   case 64:
-#line 631 "Gmsh.y"
+#line 641 "Gmsh.y"
     { (yyval.i) = -1; ;}
     break;
 
+  case 65:
+#line 647 "Gmsh.y"
+    { (yyval.c) = (char*)"("; ;}
+    break;
+
+  case 66:
+#line 647 "Gmsh.y"
+    { (yyval.c) = (char*)"["; ;}
+    break;
+
   case 67:
-#line 642 "Gmsh.y"
+#line 648 "Gmsh.y"
+    { (yyval.c) = (char*)")"; ;}
+    break;
+
+  case 68:
+#line 648 "Gmsh.y"
+    { (yyval.c) = (char*)"]"; ;}
+    break;
+
+  case 71:
+#line 657 "Gmsh.y"
     {
       if(!gmsh_yysymbols.count((yyvsp[(1) - (4)].c)) && (yyvsp[(2) - (4)].i) && List_Nbr((yyvsp[(3) - (4)].l)) == 1){
         yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (4)].c));
@@ -5142,8 +5030,8 @@ yyreduce:
     ;}
     break;
 
-  case 68:
-#line 704 "Gmsh.y"
+  case 72:
+#line 718 "Gmsh.y"
     {
       gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (6)].c)]);
       s.list = true;
@@ -5174,178 +5062,52 @@ yyreduce:
     ;}
     break;
 
-  case 69:
-#line 734 "Gmsh.y"
+  case 73:
+#line 747 "Gmsh.y"
     {
-      int index = (int)(yyvsp[(3) - (7)].d);
-      if(!gmsh_yysymbols.count((yyvsp[(1) - (7)].c))){
-	if(!(yyvsp[(5) - (7)].i)){
-          gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (7)].c)]);
-          s.list = true;
-	  s.value.resize(index + 1, 0.);
-	  s.value[index] = (yyvsp[(6) - (7)].d);
-	}
-	else
-	  yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (7)].c));
-      }
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (7)].c)]);
-        if(s.list){
-          if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-          switch((yyvsp[(5) - (7)].i)){
-          case 0 : s.value[index] = (yyvsp[(6) - (7)].d); break;
-          case 1 : s.value[index] += (yyvsp[(6) - (7)].d); break;
-          case 2 : s.value[index] -= (yyvsp[(6) - (7)].d); break;
-          case 3 : s.value[index] *= (yyvsp[(6) - (7)].d); break;
-          case 4 :
-            if((yyvsp[(6) - (7)].d)) s.value[index] /= (yyvsp[(6) - (7)].d);
-            else yymsg(0, "Division by zero in '%s[%d] /= %g'", (yyvsp[(1) - (7)].c), index, (yyvsp[(6) - (7)].d));
-            break;
-          }
-        }
-        else
-          yymsg(0, "Variable '%s' is not a list", (yyvsp[(1) - (7)].c));
-      }
+      assignVariable((yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(5) - (7)].i), (yyvsp[(6) - (7)].d));
       Free((yyvsp[(1) - (7)].c));
     ;}
     break;
 
-  case 70:
-#line 769 "Gmsh.y"
+  case 74:
+#line 752 "Gmsh.y"
     {
-      int index = (int)(yyvsp[(3) - (7)].d);
-      if(!gmsh_yysymbols.count((yyvsp[(1) - (7)].c))){
-	if(!(yyvsp[(5) - (7)].i)){
-          gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (7)].c)]);
-          s.list = true;
-	  s.value.resize(index + 1, 0.);
-	  s.value[index] = (yyvsp[(6) - (7)].d);
-	}
-	else
-	  yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (7)].c));
-      }
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (7)].c)]);
-        if(s.list){
-          if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-          switch((yyvsp[(5) - (7)].i)){
-          case 0 : s.value[index] = (yyvsp[(6) - (7)].d); break;
-          case 1 : s.value[index] += (yyvsp[(6) - (7)].d); break;
-          case 2 : s.value[index] -= (yyvsp[(6) - (7)].d); break;
-          case 3 : s.value[index] *= (yyvsp[(6) - (7)].d); break;
-          case 4 :
-            if((yyvsp[(6) - (7)].d)) s.value[index] /= (yyvsp[(6) - (7)].d);
-            else yymsg(0, "Division by zero in '%s[%d] /= %g'", (yyvsp[(1) - (7)].c), index, (yyvsp[(6) - (7)].d));
-            break;
-          }
-        }
-        else
-          yymsg(0, "Variable '%s' is not a list", (yyvsp[(1) - (7)].c));
-      }
+      assignVariable((yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(5) - (7)].i), (yyvsp[(6) - (7)].d));
       Free((yyvsp[(1) - (7)].c));
     ;}
     break;
 
-  case 71:
-#line 803 "Gmsh.y"
+  case 75:
+#line 757 "Gmsh.y"
     {
-      if(List_Nbr((yyvsp[(4) - (9)].l)) != List_Nbr((yyvsp[(8) - (9)].l))){
-	yymsg(0, "Incompatible array dimensions in affectation");
-      }
-      else{
-	if(!gmsh_yysymbols.count((yyvsp[(1) - (9)].c))){
-	  if(!(yyvsp[(7) - (9)].i)){
-            gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (9)].c)]);
-            s.list = true;
-	    for(int i = 0; i < List_Nbr((yyvsp[(4) - (9)].l)); i++){
-	      int index = (int)(*(double*)List_Pointer((yyvsp[(4) - (9)].l), i));
-	      s.value.resize(index + 1, 0.);
-	      s.value[index] = *(double*)List_Pointer((yyvsp[(8) - (9)].l), i);
-	    }
-	  }
-	  else
-	    yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (9)].c));
-	}
-	else{
-          gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (9)].c)]);
-          if(s.list){
-            for(int i = 0; i < List_Nbr((yyvsp[(4) - (9)].l)); i++){
-              int index = (int)(*(double*)List_Pointer((yyvsp[(4) - (9)].l), i));
-              double d = *(double*)List_Pointer((yyvsp[(8) - (9)].l), i);
-              if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-              switch((yyvsp[(7) - (9)].i)){
-              case 0 : s.value[index] = d; break;
-              case 1 : s.value[index] += d; break;
-              case 2 : s.value[index] -= d; break;
-              case 3 : s.value[index] *= d; break;
-              case 4 :
-                if((yyvsp[(8) - (9)].l)) s.value[index] /= d;
-                else yymsg(0, "Division by zero in '%s[%d] /= %g'", (yyvsp[(1) - (9)].c), index, d);
-                break;
-              }
-            }
-          }
-          else
-            yymsg(0, "Variable '%s' is not a list", (yyvsp[(1) - (9)].c));
-        }
-      }
+      assignVariable((yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(5) - (7)].i), (yyvsp[(6) - (7)].d));
+      Free((yyvsp[(1) - (7)].c));
+    ;}
+    break;
+
+  case 76:
+#line 762 "Gmsh.y"
+    {
+      assignVariables((yyvsp[(1) - (9)].c), (yyvsp[(4) - (9)].l), (yyvsp[(7) - (9)].i), (yyvsp[(8) - (9)].l));
       Free((yyvsp[(1) - (9)].c));
       List_Delete((yyvsp[(4) - (9)].l));
       List_Delete((yyvsp[(8) - (9)].l));
     ;}
     break;
 
-  case 72:
-#line 851 "Gmsh.y"
+  case 77:
+#line 769 "Gmsh.y"
     {
-      if(List_Nbr((yyvsp[(4) - (9)].l)) != List_Nbr((yyvsp[(8) - (9)].l))){
-	yymsg(0, "Incompatible array dimensions in affectation");
-      }
-      else{
-	if(!gmsh_yysymbols.count((yyvsp[(1) - (9)].c))){
-	  if(!(yyvsp[(7) - (9)].i)){
-            gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (9)].c)]);
-            s.list = true;
-	    for(int i = 0; i < List_Nbr((yyvsp[(4) - (9)].l)); i++){
-	      int index = (int)(*(double*)List_Pointer((yyvsp[(4) - (9)].l), i));
-	      s.value.resize(index + 1, 0.);
-	      s.value[index] = *(double*)List_Pointer((yyvsp[(8) - (9)].l), i);
-	    }
-	  }
-	  else
-	    yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (9)].c));
-	}
-	else{
-          gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (9)].c)]);
-          if(s.list){
-            for(int i = 0; i < List_Nbr((yyvsp[(4) - (9)].l)); i++){
-              int index = (int)(*(double*)List_Pointer((yyvsp[(4) - (9)].l), i));
-              double d = *(double*)List_Pointer((yyvsp[(8) - (9)].l), i);
-              if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-              switch((yyvsp[(7) - (9)].i)){
-              case 0 : s.value[index] = d; break;
-              case 1 : s.value[index] += d; break;
-              case 2 : s.value[index] -= d; break;
-              case 3 : s.value[index] *= d; break;
-              case 4 :
-                if((yyvsp[(8) - (9)].l)) s.value[index] /= d;
-                else yymsg(0, "Division by zero in '%s[%d] /= %g'", (yyvsp[(1) - (9)].c), index, d);
-                break;
-              }
-            }
-          }
-          else
-            yymsg(0, "Variable '%s' is not a list", (yyvsp[(1) - (9)].c));
-        }
-      }
+      assignVariables((yyvsp[(1) - (9)].c), (yyvsp[(4) - (9)].l), (yyvsp[(7) - (9)].i), (yyvsp[(8) - (9)].l));
       Free((yyvsp[(1) - (9)].c));
       List_Delete((yyvsp[(4) - (9)].l));
       List_Delete((yyvsp[(8) - (9)].l));
     ;}
     break;
 
-  case 73:
-#line 898 "Gmsh.y"
+  case 78:
+#line 776 "Gmsh.y"
     {
       if(!gmsh_yysymbols.count((yyvsp[(1) - (3)].c)))
 	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (3)].c));
@@ -5362,27 +5124,24 @@ yyreduce:
     ;}
     break;
 
-  case 74:
-#line 913 "Gmsh.y"
+  case 79:
+#line 791 "Gmsh.y"
     {
-      if(!gmsh_yysymbols.count((yyvsp[(1) - (6)].c)))
-	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (6)].c));
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (6)].c)]);
-        if(s.list){
-          int index = (int)(yyvsp[(3) - (6)].d);
-          if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-          s.value[index] += (yyvsp[(5) - (6)].i);
-        }
-        else
-          yymsg(0, "Variable '%s' is not a list", (yyvsp[(1) - (6)].c));
-      }
+      incrementVariable((yyvsp[(1) - (6)].c), (yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].i));
       Free((yyvsp[(1) - (6)].c));
     ;}
     break;
 
-  case 75:
-#line 929 "Gmsh.y"
+  case 80:
+#line 796 "Gmsh.y"
+    {
+      incrementVariable((yyvsp[(1) - (6)].c), (yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].i));
+      Free((yyvsp[(1) - (6)].c));
+    ;}
+    break;
+
+  case 81:
+#line 801 "Gmsh.y"
     {
       gmsh_yystringsymbols[(yyvsp[(1) - (4)].c)] = std::string((yyvsp[(3) - (4)].c));
       Free((yyvsp[(1) - (4)].c));
@@ -5390,8 +5149,8 @@ yyreduce:
     ;}
     break;
 
-  case 76:
-#line 938 "Gmsh.y"
+  case 82:
+#line 810 "Gmsh.y"
     {
       std::string tmp((yyvsp[(5) - (6)].c));
       StringOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (6)].c), 0, (yyvsp[(3) - (6)].c), tmp);
@@ -5399,8 +5158,8 @@ yyreduce:
     ;}
     break;
 
-  case 77:
-#line 944 "Gmsh.y"
+  case 83:
+#line 816 "Gmsh.y"
     {
       std::string tmp((yyvsp[(8) - (9)].c));
       StringOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c), tmp);
@@ -5408,8 +5167,8 @@ yyreduce:
     ;}
     break;
 
-  case 78:
-#line 953 "Gmsh.y"
+  case 84:
+#line 825 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (6)].c), 0, (yyvsp[(3) - (6)].c), d)){
@@ -5429,8 +5188,8 @@ yyreduce:
     ;}
     break;
 
-  case 79:
-#line 971 "Gmsh.y"
+  case 85:
+#line 843 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c), d)){
@@ -5450,8 +5209,8 @@ yyreduce:
     ;}
     break;
 
-  case 80:
-#line 989 "Gmsh.y"
+  case 86:
+#line 861 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (5)].c), 0, (yyvsp[(3) - (5)].c), d)){
@@ -5462,8 +5221,8 @@ yyreduce:
     ;}
     break;
 
-  case 81:
-#line 998 "Gmsh.y"
+  case 87:
+#line 870 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (8)].c), (int)(yyvsp[(3) - (8)].d), (yyvsp[(6) - (8)].c), d)){
@@ -5474,24 +5233,24 @@ yyreduce:
     ;}
     break;
 
-  case 82:
-#line 1010 "Gmsh.y"
+  case 88:
+#line 882 "Gmsh.y"
     {
       ColorOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (8)].c), 0, (yyvsp[(5) - (8)].c), (yyvsp[(7) - (8)].u));
       Free((yyvsp[(1) - (8)].c)); Free((yyvsp[(5) - (8)].c));
     ;}
     break;
 
-  case 83:
-#line 1015 "Gmsh.y"
+  case 89:
+#line 887 "Gmsh.y"
     {
       ColorOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (11)].c), (int)(yyvsp[(3) - (11)].d), (yyvsp[(8) - (11)].c), (yyvsp[(10) - (11)].u));
       Free((yyvsp[(1) - (11)].c)); Free((yyvsp[(8) - (11)].c));
     ;}
     break;
 
-  case 84:
-#line 1023 "Gmsh.y"
+  case 90:
+#line 895 "Gmsh.y"
     {
       GmshColorTable *ct = GetColorTable(0);
       if(!ct)
@@ -5513,8 +5272,8 @@ yyreduce:
     ;}
     break;
 
-  case 85:
-#line 1043 "Gmsh.y"
+  case 91:
+#line 915 "Gmsh.y"
     {
       GmshColorTable *ct = GetColorTable((int)(yyvsp[(3) - (9)].d));
       if(!ct)
@@ -5536,8 +5295,8 @@ yyreduce:
     ;}
     break;
 
-  case 86:
-#line 1066 "Gmsh.y"
+  case 92:
+#line 938 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       if(!strcmp((yyvsp[(1) - (5)].c),"Background"))
@@ -5550,8 +5309,8 @@ yyreduce:
     ;}
     break;
 
-  case 87:
-#line 1077 "Gmsh.y"
+  case 93:
+#line 949 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       if(!GModel::current()->getFields()->newField((int)(yyvsp[(3) - (7)].d), (yyvsp[(6) - (7)].c)))
@@ -5561,8 +5320,8 @@ yyreduce:
     ;}
     break;
 
-  case 88:
-#line 1085 "Gmsh.y"
+  case 94:
+#line 957 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (9)].d));
@@ -5586,8 +5345,8 @@ yyreduce:
     ;}
     break;
 
-  case 89:
-#line 1107 "Gmsh.y"
+  case 95:
+#line 979 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (9)].d));
@@ -5612,8 +5371,8 @@ yyreduce:
     ;}
     break;
 
-  case 90:
-#line 1130 "Gmsh.y"
+  case 96:
+#line 1002 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (11)].d));
@@ -5641,8 +5400,8 @@ yyreduce:
     ;}
     break;
 
-  case 91:
-#line 1156 "Gmsh.y"
+  case 97:
+#line 1028 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (7)].d));
@@ -5662,8 +5421,8 @@ yyreduce:
     ;}
     break;
 
-  case 92:
-#line 1177 "Gmsh.y"
+  case 98:
+#line 1049 "Gmsh.y"
     {
 #if defined(HAVE_PLUGINS)
       try {
@@ -5677,8 +5436,8 @@ yyreduce:
     ;}
     break;
 
-  case 93:
-#line 1189 "Gmsh.y"
+  case 99:
+#line 1061 "Gmsh.y"
     {
 #if defined(HAVE_PLUGINS)
       try {
@@ -5692,8 +5451,8 @@ yyreduce:
     ;}
     break;
 
-  case 97:
-#line 1207 "Gmsh.y"
+  case 103:
+#line 1079 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (3)].c));
       std::vector<double> val(1, 0.);
@@ -5704,8 +5463,8 @@ yyreduce:
     ;}
     break;
 
-  case 98:
-#line 1216 "Gmsh.y"
+  case 104:
+#line 1088 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (5)].c));
       std::vector<double> val(1, (yyvsp[(5) - (5)].d));
@@ -5716,13 +5475,13 @@ yyreduce:
     ;}
     break;
 
-  case 99:
-#line 1225 "Gmsh.y"
+  case 105:
+#line 1097 "Gmsh.y"
     { floatOptions.clear(); charOptions.clear(); ;}
     break;
 
-  case 100:
-#line 1227 "Gmsh.y"
+  case 106:
+#line 1099 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (9)].c));
       std::vector<double> val(1, (yyvsp[(6) - (9)].d));
@@ -5734,8 +5493,8 @@ yyreduce:
     ;}
     break;
 
-  case 101:
-#line 1237 "Gmsh.y"
+  case 107:
+#line 1109 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (5)].c)), val((yyvsp[(5) - (5)].c));
       if(!gmsh_yystringsymbols.count(key)){
@@ -5746,13 +5505,13 @@ yyreduce:
     ;}
     break;
 
-  case 102:
-#line 1246 "Gmsh.y"
+  case 108:
+#line 1118 "Gmsh.y"
     { floatOptions.clear(); charOptions.clear(); ;}
     break;
 
-  case 103:
-#line 1248 "Gmsh.y"
+  case 109:
+#line 1120 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (9)].c)), val((yyvsp[(6) - (9)].c));
       if(!gmsh_yysymbols.count(key)){
@@ -5764,8 +5523,8 @@ yyreduce:
     ;}
     break;
 
-  case 105:
-#line 1262 "Gmsh.y"
+  case 111:
+#line 1134 "Gmsh.y"
     {
       std::string name((yyvsp[(3) - (3)].c));
       Msg::UndefineOnelabParameter(name);
@@ -5773,8 +5532,8 @@ yyreduce:
     ;}
     break;
 
-  case 106:
-#line 1270 "Gmsh.y"
+  case 112:
+#line 1142 "Gmsh.y"
     {
       (yyval.l) = List_Create(20,20,sizeof(doubleXstring));
       doubleXstring v = {(yyvsp[(1) - (3)].d), (yyvsp[(3) - (3)].c)};
@@ -5782,16 +5541,16 @@ yyreduce:
     ;}
     break;
 
-  case 107:
-#line 1276 "Gmsh.y"
+  case 113:
+#line 1148 "Gmsh.y"
     {
       doubleXstring v = {(yyvsp[(3) - (5)].d), (yyvsp[(5) - (5)].c)};
       List_Add((yyval.l), &v);
     ;}
     break;
 
-  case 110:
-#line 1288 "Gmsh.y"
+  case 116:
+#line 1160 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (3)].c));
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (3)].l)); i++){
@@ -5804,8 +5563,8 @@ yyreduce:
     ;}
     break;
 
-  case 111:
-#line 1299 "Gmsh.y"
+  case 117:
+#line 1171 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (5)].c));
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
@@ -5821,8 +5580,8 @@ yyreduce:
     ;}
     break;
 
-  case 112:
-#line 1314 "Gmsh.y"
+  case 118:
+#line 1186 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (3)].c));
       std::string val((yyvsp[(3) - (3)].c));
@@ -5832,8 +5591,8 @@ yyreduce:
     ;}
     break;
 
-  case 115:
-#line 1330 "Gmsh.y"
+  case 121:
+#line 1202 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (3)].c));
       double val = (yyvsp[(3) - (3)].d);
@@ -5842,8 +5601,8 @@ yyreduce:
     ;}
     break;
 
-  case 116:
-#line 1338 "Gmsh.y"
+  case 122:
+#line 1210 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (3)].c));
       std::string val((yyvsp[(3) - (3)].c));
@@ -5853,8 +5612,8 @@ yyreduce:
     ;}
     break;
 
-  case 117:
-#line 1347 "Gmsh.y"
+  case 123:
+#line 1219 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (5)].c));
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
@@ -5869,15 +5628,15 @@ yyreduce:
     ;}
     break;
 
-  case 118:
-#line 1365 "Gmsh.y"
+  case 124:
+#line 1237 "Gmsh.y"
     {
       (yyval.i) = (int)(yyvsp[(1) - (1)].d);
     ;}
     break;
 
-  case 119:
-#line 1369 "Gmsh.y"
+  case 125:
+#line 1241 "Gmsh.y"
     {
       (yyval.i) = GModel::current()->setPhysicalName
         (std::string((yyvsp[(1) - (1)].c)), curPhysDim,
@@ -5886,15 +5645,15 @@ yyreduce:
     ;}
     break;
 
-  case 120:
-#line 1379 "Gmsh.y"
+  case 126:
+#line 1251 "Gmsh.y"
     {
       (yyval.l) = 0;
     ;}
     break;
 
-  case 121:
-#line 1383 "Gmsh.y"
+  case 127:
+#line 1255 "Gmsh.y"
     {
       (yyval.l) = List_Create(1, 1, sizeof(Vertex*));
       Vertex *v = FindPoint((int)(yyvsp[(4) - (5)].d));
@@ -5906,22 +5665,22 @@ yyreduce:
     ;}
     break;
 
-  case 122:
-#line 1395 "Gmsh.y"
+  case 128:
+#line 1267 "Gmsh.y"
     {
       for(int i = 0; i < 4; i++) (yyval.v)[i] = 0.;
     ;}
     break;
 
-  case 123:
-#line 1399 "Gmsh.y"
+  case 129:
+#line 1271 "Gmsh.y"
     {
       for(int i = 0; i < 4; i++) (yyval.v)[i] = (yyvsp[(2) - (2)].v)[i];
     ;}
     break;
 
-  case 124:
-#line 1409 "Gmsh.y"
+  case 130:
+#line 1281 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindPoint(num)){
@@ -5946,15 +5705,15 @@ yyreduce:
     ;}
     break;
 
-  case 125:
-#line 1432 "Gmsh.y"
+  case 131:
+#line 1304 "Gmsh.y"
     {
       curPhysDim = 0;
     ;}
     break;
 
-  case 126:
-#line 1436 "Gmsh.y"
+  case 132:
+#line 1308 "Gmsh.y"
     {
       int num = (int)(yyvsp[(5) - (9)].i);
       if(FindPhysicalGroup(num, MSH_PHYSICAL_POINT)){
@@ -5972,8 +5731,8 @@ yyreduce:
     ;}
     break;
 
-  case 127:
-#line 1452 "Gmsh.y"
+  case 133:
+#line 1324 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (6)].l)); i++){
 	double d;
@@ -5994,8 +5753,8 @@ yyreduce:
     ;}
     break;
 
-  case 128:
-#line 1474 "Gmsh.y"
+  case 134:
+#line 1346 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -6015,8 +5774,8 @@ yyreduce:
     ;}
     break;
 
-  case 129:
-#line 1492 "Gmsh.y"
+  case 135:
+#line 1364 "Gmsh.y"
     {
       for (int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
 	double dnum;
@@ -6039,8 +5798,8 @@ yyreduce:
     ;}
     break;
 
-  case 130:
-#line 1513 "Gmsh.y"
+  case 136:
+#line 1385 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -6060,8 +5819,8 @@ yyreduce:
     ;}
     break;
 
-  case 131:
-#line 1531 "Gmsh.y"
+  case 137:
+#line 1403 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (8)].d);
       if(FindCurve(num)){
@@ -6093,8 +5852,8 @@ yyreduce:
     ;}
     break;
 
-  case 132:
-#line 1561 "Gmsh.y"
+  case 138:
+#line 1433 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (8)].d);
       if(FindCurve(num)){
@@ -6126,8 +5885,8 @@ yyreduce:
     ;}
     break;
 
-  case 133:
-#line 1591 "Gmsh.y"
+  case 139:
+#line 1463 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -6147,8 +5906,8 @@ yyreduce:
     ;}
     break;
 
-  case 134:
-#line 1609 "Gmsh.y"
+  case 140:
+#line 1481 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -6168,8 +5927,8 @@ yyreduce:
     ;}
     break;
 
-  case 135:
-#line 1627 "Gmsh.y"
+  case 141:
+#line 1500 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (11)].d);
       if(List_Nbr((yyvsp[(6) - (11)].l)) + (int)(yyvsp[(10) - (11)].d) + 1 != List_Nbr((yyvsp[(8) - (11)].l))){
@@ -6197,8 +5956,8 @@ yyreduce:
     ;}
     break;
 
-  case 136:
-#line 1653 "Gmsh.y"
+  case 142:
+#line 1526 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       if(FindEdgeLoop(num)){
@@ -6218,8 +5977,8 @@ yyreduce:
     ;}
     break;
 
-  case 137:
-#line 1671 "Gmsh.y"
+  case 143:
+#line 1544 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       if(FindCurve(num)){
@@ -6239,15 +5998,15 @@ yyreduce:
     ;}
     break;
 
-  case 138:
-#line 1689 "Gmsh.y"
+  case 144:
+#line 1562 "Gmsh.y"
     {
       curPhysDim = 1;
     ;}
     break;
 
-  case 139:
-#line 1693 "Gmsh.y"
+  case 145:
+#line 1566 "Gmsh.y"
     {
       int num = (int)(yyvsp[(5) - (9)].i);
       if(FindPhysicalGroup(num, MSH_PHYSICAL_LINE)){
@@ -6265,8 +6024,8 @@ yyreduce:
     ;}
     break;
 
-  case 140:
-#line 1712 "Gmsh.y"
+  case 146:
+#line 1585 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       if(FindSurface(num)){
@@ -6286,8 +6045,8 @@ yyreduce:
     ;}
     break;
 
-  case 141:
-#line 1730 "Gmsh.y"
+  case 147:
+#line 1603 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (9)].d), type = 0;
       if(FindSurface(num)){
@@ -6328,8 +6087,8 @@ yyreduce:
     ;}
     break;
 
-  case 142:
-#line 1769 "Gmsh.y"
+  case 148:
+#line 1642 "Gmsh.y"
     {
       myGmshSurface = 0;
       (yyval.s).Type = 0;
@@ -6337,8 +6096,8 @@ yyreduce:
     ;}
     break;
 
-  case 143:
-#line 1775 "Gmsh.y"
+  case 149:
+#line 1648 "Gmsh.y"
     {
       myGmshSurface = gmshSurface::getSurface((int)(yyvsp[(3) - (4)].d));
       (yyval.s).Type = 0;
@@ -6346,8 +6105,8 @@ yyreduce:
     ;}
     break;
 
-  case 144:
-#line 1781 "Gmsh.y"
+  case 150:
+#line 1654 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (10)].d);
       myGmshSurface = gmshParametricSurface::NewParametricSurface(num, (yyvsp[(7) - (10)].c), (yyvsp[(8) - (10)].c), (yyvsp[(9) - (10)].c));
@@ -6356,8 +6115,8 @@ yyreduce:
     ;}
     break;
 
-  case 145:
-#line 1788 "Gmsh.y"
+  case 151:
+#line 1661 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if (List_Nbr((yyvsp[(6) - (7)].l)) != 2){
@@ -6384,8 +6143,8 @@ yyreduce:
     ;}
     break;
 
-  case 146:
-#line 1813 "Gmsh.y"
+  case 152:
+#line 1686 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if (List_Nbr((yyvsp[(6) - (7)].l)) != 2){
@@ -6412,8 +6171,8 @@ yyreduce:
     ;}
     break;
 
-  case 147:
-#line 1838 "Gmsh.y"
+  case 153:
+#line 1711 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       if(FindSurfaceLoop(num)){
@@ -6432,8 +6191,8 @@ yyreduce:
     ;}
     break;
 
-  case 148:
-#line 1855 "Gmsh.y"
+  case 154:
+#line 1728 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       if(FindSurface(num)){
@@ -6454,8 +6213,8 @@ yyreduce:
     ;}
     break;
 
-  case 149:
-#line 1875 "Gmsh.y"
+  case 155:
+#line 1748 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (12)].d);
       if(FindSurface(num)){
@@ -6490,15 +6249,15 @@ yyreduce:
     ;}
     break;
 
-  case 150:
-#line 1908 "Gmsh.y"
+  case 156:
+#line 1781 "Gmsh.y"
     {
       curPhysDim = 2;
     ;}
     break;
 
-  case 151:
-#line 1912 "Gmsh.y"
+  case 157:
+#line 1785 "Gmsh.y"
     {
       int num = (int)(yyvsp[(5) - (9)].i);
       if(FindPhysicalGroup(num, MSH_PHYSICAL_SURFACE)){
@@ -6516,8 +6275,8 @@ yyreduce:
     ;}
     break;
 
-  case 152:
-#line 1932 "Gmsh.y"
+  case 158:
+#line 1805 "Gmsh.y"
     {
       yymsg(0, "'Complex Volume' command is deprecated: use 'Volume' instead");
       int num = (int)(yyvsp[(4) - (8)].d);
@@ -6537,8 +6296,8 @@ yyreduce:
     ;}
     break;
 
-  case 153:
-#line 1950 "Gmsh.y"
+  case 159:
+#line 1823 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindVolume(num)){
@@ -6557,8 +6316,8 @@ yyreduce:
     ;}
     break;
 
-  case 154:
-#line 1967 "Gmsh.y"
+  case 160:
+#line 1840 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       if(FindVolume(num)){
@@ -6576,15 +6335,15 @@ yyreduce:
     ;}
     break;
 
-  case 155:
-#line 1983 "Gmsh.y"
+  case 161:
+#line 1856 "Gmsh.y"
     {
       curPhysDim = 3;
     ;}
     break;
 
-  case 156:
-#line 1987 "Gmsh.y"
+  case 162:
+#line 1860 "Gmsh.y"
     {
       int num = (int)(yyvsp[(5) - (9)].i);
       if(FindPhysicalGroup(num, MSH_PHYSICAL_VOLUME)){
@@ -6602,48 +6361,48 @@ yyreduce:
     ;}
     break;
 
-  case 157:
-#line 2009 "Gmsh.y"
+  case 163:
+#line 1882 "Gmsh.y"
     {
       TranslateShapes((yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], (yyvsp[(4) - (5)].l));
       (yyval.l) = (yyvsp[(4) - (5)].l);
     ;}
     break;
 
-  case 158:
-#line 2014 "Gmsh.y"
+  case 164:
+#line 1887 "Gmsh.y"
     {
       RotateShapes((yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2], (yyvsp[(7) - (11)].d), (yyvsp[(10) - (11)].l));
       (yyval.l) = (yyvsp[(10) - (11)].l);
     ;}
     break;
 
-  case 159:
-#line 2019 "Gmsh.y"
+  case 165:
+#line 1892 "Gmsh.y"
     {
       SymmetryShapes((yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], (yyvsp[(2) - (5)].v)[3], (yyvsp[(4) - (5)].l));
       (yyval.l) = (yyvsp[(4) - (5)].l);
     ;}
     break;
 
-  case 160:
-#line 2024 "Gmsh.y"
+  case 166:
+#line 1897 "Gmsh.y"
     {
       DilatShapes((yyvsp[(3) - (9)].v)[0], (yyvsp[(3) - (9)].v)[1], (yyvsp[(3) - (9)].v)[2], (yyvsp[(5) - (9)].d), (yyvsp[(5) - (9)].d), (yyvsp[(5) - (9)].d), (yyvsp[(8) - (9)].l));
       (yyval.l) = (yyvsp[(8) - (9)].l);
     ;}
     break;
 
-  case 161:
-#line 2029 "Gmsh.y"
+  case 167:
+#line 1902 "Gmsh.y"
     {
       DilatShapes((yyvsp[(3) - (9)].v)[0], (yyvsp[(3) - (9)].v)[1], (yyvsp[(3) - (9)].v)[2], (yyvsp[(5) - (9)].v)[0], (yyvsp[(5) - (9)].v)[1], (yyvsp[(5) - (9)].v)[2], (yyvsp[(8) - (9)].l));
       (yyval.l) = (yyvsp[(8) - (9)].l);
     ;}
     break;
 
-  case 162:
-#line 2034 "Gmsh.y"
+  case 168:
+#line 1907 "Gmsh.y"
     {
       (yyval.l) = List_Create(3, 3, sizeof(Shape));
       if(!strcmp((yyvsp[(1) - (4)].c), "Duplicata")){
@@ -6668,8 +6427,8 @@ yyreduce:
     ;}
     break;
 
-  case 163:
-#line 2057 "Gmsh.y"
+  case 169:
+#line 1930 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       IntersectCurvesWithSurface((yyvsp[(4) - (9)].l), (int)(yyvsp[(8) - (9)].d), (yyval.l));
@@ -6677,8 +6436,8 @@ yyreduce:
     ;}
     break;
 
-  case 164:
-#line 2063 "Gmsh.y"
+  case 170:
+#line 1936 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape*));
       List_T *tmp = ListOfDouble2ListOfInt((yyvsp[(7) - (9)].l));
@@ -6688,32 +6447,32 @@ yyreduce:
     ;}
     break;
 
-  case 165:
-#line 2073 "Gmsh.y"
+  case 171:
+#line 1946 "Gmsh.y"
     { (yyval.l) = (yyvsp[(1) - (1)].l); ;}
     break;
 
-  case 166:
-#line 2074 "Gmsh.y"
+  case 172:
+#line 1947 "Gmsh.y"
     { (yyval.l) = (yyvsp[(1) - (1)].l); ;}
     break;
 
-  case 167:
-#line 2079 "Gmsh.y"
+  case 173:
+#line 1952 "Gmsh.y"
     {
       (yyval.l) = List_Create(3, 3, sizeof(Shape));
     ;}
     break;
 
-  case 168:
-#line 2083 "Gmsh.y"
+  case 174:
+#line 1956 "Gmsh.y"
     {
       List_Add((yyval.l), &(yyvsp[(2) - (2)].s));
     ;}
     break;
 
-  case 169:
-#line 2087 "Gmsh.y"
+  case 175:
+#line 1960 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -6738,8 +6497,8 @@ yyreduce:
     ;}
     break;
 
-  case 170:
-#line 2110 "Gmsh.y"
+  case 176:
+#line 1983 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -6764,8 +6523,8 @@ yyreduce:
     ;}
     break;
 
-  case 171:
-#line 2133 "Gmsh.y"
+  case 177:
+#line 2006 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -6790,8 +6549,8 @@ yyreduce:
     ;}
     break;
 
-  case 172:
-#line 2156 "Gmsh.y"
+  case 178:
+#line 2029 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -6816,8 +6575,8 @@ yyreduce:
     ;}
     break;
 
-  case 173:
-#line 2184 "Gmsh.y"
+  case 179:
+#line 2057 "Gmsh.y"
     {
 #if defined(HAVE_DINTEGRATION)
       if(List_Nbr((yyvsp[(7) - (8)].l)) == 4){
@@ -6840,8 +6599,8 @@ yyreduce:
     ;}
     break;
 
-  case 174:
-#line 2205 "Gmsh.y"
+  case 180:
+#line 2078 "Gmsh.y"
     {
 #if defined(HAVE_DINTEGRATION)
       int t = (int)(yyvsp[(4) - (10)].d);
@@ -6869,8 +6628,8 @@ yyreduce:
     ;}
     break;
 
-  case 175:
-#line 2232 "Gmsh.y"
+  case 181:
+#line 2105 "Gmsh.y"
     {
 #if defined(HAVE_DINTEGRATION)
       if(List_Nbr((yyvsp[(12) - (14)].l)) == 0){
@@ -6892,8 +6651,8 @@ yyreduce:
     ;}
     break;
 
-  case 176:
-#line 2253 "Gmsh.y"
+  case 182:
+#line 2126 "Gmsh.y"
     {
 #if defined(HAVE_DINTEGRATION)
       if(List_Nbr((yyvsp[(14) - (16)].l)) == 0){
@@ -6916,8 +6675,8 @@ yyreduce:
     ;}
     break;
 
-  case 177:
-#line 2274 "Gmsh.y"
+  case 183:
+#line 2147 "Gmsh.y"
     {
 #if defined(HAVE_DINTEGRATION)
       if(List_Nbr((yyvsp[(10) - (12)].l)) == 1){
@@ -6939,8 +6698,8 @@ yyreduce:
     ;}
     break;
 
-  case 178:
-#line 2294 "Gmsh.y"
+  case 184:
+#line 2167 "Gmsh.y"
     {
 #if defined(HAVE_DINTEGRATION)
       if(!strcmp((yyvsp[(2) - (8)].c), "Union")){
@@ -7054,8 +6813,8 @@ yyreduce:
     ;}
     break;
 
-  case 179:
-#line 2406 "Gmsh.y"
+  case 185:
+#line 2279 "Gmsh.y"
     {
 #if defined(HAVE_DINTEGRATION)
       if(!strcmp((yyvsp[(2) - (8)].c), "MathEval")){
@@ -7076,8 +6835,8 @@ yyreduce:
     ;}
     break;
 
-  case 180:
-#line 2425 "Gmsh.y"
+  case 186:
+#line 2298 "Gmsh.y"
     {
 #if defined(HAVE_DINTEGRATION)
       if(!strcmp((yyvsp[(2) - (6)].c), "CutMesh")){
@@ -7117,8 +6876,8 @@ yyreduce:
     ;}
     break;
 
-  case 181:
-#line 2464 "Gmsh.y"
+  case 187:
+#line 2337 "Gmsh.y"
     {
 #if defined(HAVE_DINTEGRATION)
       if(!strcmp((yyvsp[(2) - (14)].c), "Cylinder") && List_Nbr((yyvsp[(12) - (14)].l)) == 1){
@@ -7223,8 +6982,8 @@ yyreduce:
     ;}
     break;
 
-  case 182:
-#line 2572 "Gmsh.y"
+  case 188:
+#line 2445 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
 	Shape TheShape;
@@ -7235,8 +6994,8 @@ yyreduce:
     ;}
     break;
 
-  case 183:
-#line 2581 "Gmsh.y"
+  case 189:
+#line 2454 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       GModel::current()->getFields()->deleteField((int)(yyvsp[(4) - (6)].d));
@@ -7244,8 +7003,8 @@ yyreduce:
     ;}
     break;
 
-  case 184:
-#line 2587 "Gmsh.y"
+  case 190:
+#line 2460 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (6)].c), "View")){
@@ -7262,14 +7021,14 @@ yyreduce:
     ;}
     break;
 
-  case 185:
-#line 2602 "Gmsh.y"
+  case 191:
+#line 2475 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (3)].c), "Meshes") || !strcmp((yyvsp[(2) - (3)].c), "All")){
         ClearProject();
       }
       else if(!strcmp((yyvsp[(2) - (3)].c), "Model")){
-	GModel::current()->destroy();
+	GModel::current()->destroy(true); // destroy, but keep name/filename
 	GModel::current()->getGEOInternals()->destroy();
       }
       else if(!strcmp((yyvsp[(2) - (3)].c), "Physicals")){
@@ -7293,8 +7052,8 @@ yyreduce:
     ;}
     break;
 
-  case 186:
-#line 2630 "Gmsh.y"
+  case 192:
+#line 2503 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (4)].c), "Empty") && !strcmp((yyvsp[(3) - (4)].c), "Views")){
@@ -7308,8 +7067,8 @@ yyreduce:
     ;}
     break;
 
-  case 187:
-#line 2647 "Gmsh.y"
+  case 193:
+#line 2520 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
 	Shape TheShape;
@@ -7320,8 +7079,8 @@ yyreduce:
     ;}
     break;
 
-  case 188:
-#line 2656 "Gmsh.y"
+  case 194:
+#line 2529 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(5) - (6)].l)); i++){
 	Shape TheShape;
@@ -7332,8 +7091,8 @@ yyreduce:
     ;}
     break;
 
-  case 189:
-#line 2670 "Gmsh.y"
+  case 195:
+#line 2543 "Gmsh.y"
     {
       for(int i = 0; i < 4; i++)
 	VisibilityShape((yyvsp[(2) - (3)].c), i, 1, false);
@@ -7341,8 +7100,8 @@ yyreduce:
     ;}
     break;
 
-  case 190:
-#line 2676 "Gmsh.y"
+  case 196:
+#line 2549 "Gmsh.y"
     {
       for(int i = 0; i < 4; i++)
 	VisibilityShape((yyvsp[(2) - (3)].c), i, 0, false);
@@ -7350,8 +7109,8 @@ yyreduce:
     ;}
     break;
 
-  case 191:
-#line 2682 "Gmsh.y"
+  case 197:
+#line 2555 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
 	Shape TheShape;
@@ -7362,8 +7121,8 @@ yyreduce:
     ;}
     break;
 
-  case 192:
-#line 2691 "Gmsh.y"
+  case 198:
+#line 2564 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
 	Shape TheShape;
@@ -7374,8 +7133,8 @@ yyreduce:
     ;}
     break;
 
-  case 193:
-#line 2700 "Gmsh.y"
+  case 199:
+#line 2573 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
 	Shape TheShape;
@@ -7386,8 +7145,8 @@ yyreduce:
     ;}
     break;
 
-  case 194:
-#line 2709 "Gmsh.y"
+  case 200:
+#line 2582 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
 	Shape TheShape;
@@ -7398,8 +7157,8 @@ yyreduce:
     ;}
     break;
 
-  case 195:
-#line 2723 "Gmsh.y"
+  case 201:
+#line 2596 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (3)].c), "Include")){
         std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(2) - (3)].c));
@@ -7434,20 +7193,28 @@ yyreduce:
         std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(2) - (3)].c));
 	MergeFile(tmp, true);
       }
-      else if(!strcmp((yyvsp[(1) - (3)].c), "NonBlockingSystemCall"))
+      else if(!strcmp((yyvsp[(1) - (3)].c), "NonBlockingSystemCall")){
 	SystemCall((yyvsp[(2) - (3)].c));
-      else if(!strcmp((yyvsp[(1) - (3)].c), "System") || !strcmp((yyvsp[(1) - (3)].c), "SystemCall"))
+      }
+      else if(!strcmp((yyvsp[(1) - (3)].c), "System") || !strcmp((yyvsp[(1) - (3)].c), "SystemCall")){
 	SystemCall((yyvsp[(2) - (3)].c), true);
-      else if(!strcmp((yyvsp[(1) - (3)].c), "SetName"))
+      }
+      else if(!strcmp((yyvsp[(1) - (3)].c), "SetName")){
 	GModel::current()->setName((yyvsp[(2) - (3)].c));
-      else
+      }
+      else if(!strcmp((yyvsp[(1) - (3)].c), "CreateDir")){
+        std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(2) - (3)].c));
+	CreateSingleDir(tmp);
+      }
+      else{
 	yymsg(0, "Unknown command '%s'", (yyvsp[(1) - (3)].c));
+      }
       Free((yyvsp[(1) - (3)].c)); Free((yyvsp[(2) - (3)].c));
     ;}
     break;
 
-  case 196:
-#line 2768 "Gmsh.y"
+  case 202:
+#line 2649 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(1) - (7)].c), "Save") && !strcmp((yyvsp[(2) - (7)].c), "View")){
@@ -7466,8 +7233,8 @@ yyreduce:
     ;}
     break;
 
-  case 197:
-#line 2785 "Gmsh.y"
+  case 203:
+#line 2666 "Gmsh.y"
     {
 #if defined(HAVE_POST) && defined(HAVE_MESH)
       if(!strcmp((yyvsp[(1) - (7)].c), "Background") && !strcmp((yyvsp[(2) - (7)].c), "Mesh")  && !strcmp((yyvsp[(3) - (7)].c), "View")){
@@ -7484,8 +7251,8 @@ yyreduce:
     ;}
     break;
 
-  case 198:
-#line 2800 "Gmsh.y"
+  case 204:
+#line 2681 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (3)].c), "Sleep")){
 	SleepInSeconds((yyvsp[(2) - (3)].d));
@@ -7506,8 +7273,8 @@ yyreduce:
     ;}
     break;
 
-  case 199:
-#line 2819 "Gmsh.y"
+  case 205:
+#line 2700 "Gmsh.y"
     {
 #if defined(HAVE_PLUGINS)
        try {
@@ -7521,8 +7288,8 @@ yyreduce:
      ;}
     break;
 
-  case 200:
-#line 2831 "Gmsh.y"
+  case 206:
+#line 2712 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (3)].c), "ElementsFromAllViews"))
@@ -7548,23 +7315,23 @@ yyreduce:
     ;}
     break;
 
-  case 201:
-#line 2855 "Gmsh.y"
+  case 207:
+#line 2736 "Gmsh.y"
     {
       Msg::Exit(0);
     ;}
     break;
 
-  case 202:
-#line 2859 "Gmsh.y"
+  case 208:
+#line 2740 "Gmsh.y"
     {
       gmsh_yyerrorstate = 999; // this will be checked when yyparse returns
       YYABORT;
     ;}
     break;
 
-  case 203:
-#line 2864 "Gmsh.y"
+  case 209:
+#line 2745 "Gmsh.y"
     {
       // FIXME: this is a hack to force a transfer from the old DB to
       // the new DB. This will become unnecessary if/when we fill the
@@ -7573,8 +7340,8 @@ yyreduce:
     ;}
     break;
 
-  case 204:
-#line 2871 "Gmsh.y"
+  case 210:
+#line 2752 "Gmsh.y"
     {
       CTX::instance()->forcedBBox = 0;
       GModel::current()->importGEOInternals();
@@ -7582,16 +7349,16 @@ yyreduce:
     ;}
     break;
 
-  case 205:
-#line 2877 "Gmsh.y"
+  case 211:
+#line 2758 "Gmsh.y"
     {
       CTX::instance()->forcedBBox = 1;
       SetBoundingBox((yyvsp[(3) - (15)].d), (yyvsp[(5) - (15)].d), (yyvsp[(7) - (15)].d), (yyvsp[(9) - (15)].d), (yyvsp[(11) - (15)].d), (yyvsp[(13) - (15)].d));
     ;}
     break;
 
-  case 206:
-#line 2882 "Gmsh.y"
+  case 212:
+#line 2763 "Gmsh.y"
     {
 #if defined(HAVE_OPENGL)
       drawContext::global()->draw();
@@ -7599,8 +7366,8 @@ yyreduce:
     ;}
     break;
 
-  case 207:
-#line 2888 "Gmsh.y"
+  case 213:
+#line 2769 "Gmsh.y"
     {
 #if defined(HAVE_OPENGL)
      CTX::instance()->mesh.changed = ENT_ALL;
@@ -7610,30 +7377,30 @@ yyreduce:
     ;}
     break;
 
-  case 208:
-#line 2896 "Gmsh.y"
+  case 214:
+#line 2777 "Gmsh.y"
     {
       GModel::current()->createTopologyFromMesh();
     ;}
     break;
 
-  case 209:
-#line 2900 "Gmsh.y"
+  case 215:
+#line 2781 "Gmsh.y"
     {
       GModel::current()->createTopologyFromMesh(1);
     ;}
     break;
 
-  case 210:
-#line 2904 "Gmsh.y"
+  case 216:
+#line 2785 "Gmsh.y"
     {
       GModel::current()->importGEOInternals();
       GModel::current()->refineMesh(CTX::instance()->mesh.secondOrderLinear);
     ;}
     break;
 
-  case 211:
-#line 2910 "Gmsh.y"
+  case 217:
+#line 2791 "Gmsh.y"
     {
       int lock = CTX::instance()->lock;
       CTX::instance()->lock = 0;
@@ -7689,8 +7456,8 @@ yyreduce:
     ;}
     break;
 
-  case 212:
-#line 2964 "Gmsh.y"
+  case 218:
+#line 2845 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       SetOrderN(GModel::current(), (yyvsp[(2) - (3)].d), CTX::instance()->mesh.secondOrderLinear,
@@ -7700,14 +7467,14 @@ yyreduce:
     ;}
     break;
 
-  case 213:
-#line 2977 "Gmsh.y"
+  case 219:
+#line 2858 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(3) - (6)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(5) - (6)].d);
       LoopControlVariablesTab[ImbricatedLoop][2] = 1.0;
       LoopControlVariablesNameTab[ImbricatedLoop] = NULL;
-      fgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
+      gmshgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
       yylinenoImbricatedLoopsTab[ImbricatedLoop] = gmsh_yylineno;
       if((yyvsp[(3) - (6)].d) > (yyvsp[(5) - (6)].d))
 	skip_until("For", "EndFor");
@@ -7720,14 +7487,14 @@ yyreduce:
     ;}
     break;
 
-  case 214:
-#line 2994 "Gmsh.y"
+  case 220:
+#line 2875 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(3) - (8)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(5) - (8)].d);
       LoopControlVariablesTab[ImbricatedLoop][2] = (yyvsp[(7) - (8)].d);
       LoopControlVariablesNameTab[ImbricatedLoop] = NULL;
-      fgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
+      gmshgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
       yylinenoImbricatedLoopsTab[ImbricatedLoop] = gmsh_yylineno;
       if(((yyvsp[(7) - (8)].d) > 0. && (yyvsp[(3) - (8)].d) > (yyvsp[(5) - (8)].d)) || ((yyvsp[(7) - (8)].d) < 0. && (yyvsp[(3) - (8)].d) < (yyvsp[(5) - (8)].d)))
 	skip_until("For", "EndFor");
@@ -7740,8 +7507,8 @@ yyreduce:
     ;}
     break;
 
-  case 215:
-#line 3011 "Gmsh.y"
+  case 221:
+#line 2892 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(5) - (8)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(7) - (8)].d);
@@ -7751,7 +7518,7 @@ yyreduce:
       s.list = false;
       s.value.resize(1);
       s.value[0] = (yyvsp[(5) - (8)].d);
-      fgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
+      gmshgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
       yylinenoImbricatedLoopsTab[ImbricatedLoop] = gmsh_yylineno;
       if((yyvsp[(5) - (8)].d) > (yyvsp[(7) - (8)].d))
 	skip_until("For", "EndFor");
@@ -7764,8 +7531,8 @@ yyreduce:
     ;}
     break;
 
-  case 216:
-#line 3032 "Gmsh.y"
+  case 222:
+#line 2913 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(5) - (10)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(7) - (10)].d);
@@ -7775,7 +7542,7 @@ yyreduce:
       s.list = false;
       s.value.resize(1);
       s.value[0] = (yyvsp[(5) - (10)].d);
-      fgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
+      gmshgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
       yylinenoImbricatedLoopsTab[ImbricatedLoop] = gmsh_yylineno;
       if(((yyvsp[(9) - (10)].d) > 0. && (yyvsp[(5) - (10)].d) > (yyvsp[(7) - (10)].d)) || ((yyvsp[(9) - (10)].d) < 0. && (yyvsp[(5) - (10)].d) < (yyvsp[(7) - (10)].d)))
 	skip_until("For", "EndFor");
@@ -7788,8 +7555,8 @@ yyreduce:
     ;}
     break;
 
-  case 217:
-#line 3053 "Gmsh.y"
+  case 223:
+#line 2934 "Gmsh.y"
     {
       if(ImbricatedLoop <= 0){
 	yymsg(0, "Invalid For/EndFor loop");
@@ -7817,7 +7584,7 @@ yyreduce:
 	double x0 = LoopControlVariablesTab[ImbricatedLoop - 1][0];
 	double x1 = LoopControlVariablesTab[ImbricatedLoop - 1][1];
         if((step > 0. && x0 <= x1) || (step < 0. && x0 >= x1)){
-	  fsetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop - 1]);
+	  gmshsetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop - 1]);
 	  gmsh_yylineno = yylinenoImbricatedLoopsTab[ImbricatedLoop - 1];
 	}
 	else
@@ -7826,8 +7593,8 @@ yyreduce:
     ;}
     break;
 
-  case 218:
-#line 3088 "Gmsh.y"
+  case 224:
+#line 2969 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->createFunction
          ((yyvsp[(2) - (2)].c), gmsh_yyin, gmsh_yyname, gmsh_yylineno))
@@ -7837,8 +7604,8 @@ yyreduce:
     ;}
     break;
 
-  case 219:
-#line 3096 "Gmsh.y"
+  case 225:
+#line 2977 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->leaveFunction
          (&gmsh_yyin, gmsh_yyname, gmsh_yylineno))
@@ -7846,8 +7613,8 @@ yyreduce:
     ;}
     break;
 
-  case 220:
-#line 3102 "Gmsh.y"
+  case 226:
+#line 2983 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->enterFunction
          ((yyvsp[(2) - (3)].c), &gmsh_yyin, gmsh_yyname, gmsh_yylineno))
@@ -7856,21 +7623,21 @@ yyreduce:
     ;}
     break;
 
-  case 221:
-#line 3109 "Gmsh.y"
+  case 227:
+#line 2990 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].d)) skip_until("If", "EndIf");
     ;}
     break;
 
-  case 222:
-#line 3113 "Gmsh.y"
+  case 228:
+#line 2994 "Gmsh.y"
     {
     ;}
     break;
 
-  case 223:
-#line 3122 "Gmsh.y"
+  case 229:
+#line 3003 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(TRANSLATE, (yyvsp[(4) - (5)].l),
@@ -7880,8 +7647,8 @@ yyreduce:
     ;}
     break;
 
-  case 224:
-#line 3130 "Gmsh.y"
+  case 230:
+#line 3011 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(ROTATE, (yyvsp[(10) - (11)].l),
@@ -7891,8 +7658,8 @@ yyreduce:
     ;}
     break;
 
-  case 225:
-#line 3138 "Gmsh.y"
+  case 231:
+#line 3019 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(TRANSLATE_ROTATE, (yyvsp[(12) - (13)].l),
@@ -7902,8 +7669,8 @@ yyreduce:
     ;}
     break;
 
-  case 226:
-#line 3146 "Gmsh.y"
+  case 232:
+#line 3027 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -7911,8 +7678,8 @@ yyreduce:
     ;}
     break;
 
-  case 227:
-#line 3152 "Gmsh.y"
+  case 233:
+#line 3033 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(TRANSLATE, (yyvsp[(4) - (7)].l),
@@ -7922,8 +7689,8 @@ yyreduce:
     ;}
     break;
 
-  case 228:
-#line 3160 "Gmsh.y"
+  case 234:
+#line 3041 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -7931,8 +7698,8 @@ yyreduce:
     ;}
     break;
 
-  case 229:
-#line 3166 "Gmsh.y"
+  case 235:
+#line 3047 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(ROTATE, (yyvsp[(10) - (13)].l),
@@ -7942,8 +7709,8 @@ yyreduce:
     ;}
     break;
 
-  case 230:
-#line 3174 "Gmsh.y"
+  case 236:
+#line 3055 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -7951,8 +7718,8 @@ yyreduce:
     ;}
     break;
 
-  case 231:
-#line 3180 "Gmsh.y"
+  case 237:
+#line 3061 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(TRANSLATE_ROTATE, (yyvsp[(12) - (15)].l),
@@ -7962,8 +7729,8 @@ yyreduce:
     ;}
     break;
 
-  case 232:
-#line 3188 "Gmsh.y"
+  case 238:
+#line 3069 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -7971,8 +7738,8 @@ yyreduce:
     ;}
     break;
 
-  case 233:
-#line 3194 "Gmsh.y"
+  case 239:
+#line 3075 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(BOUNDARY_LAYER, (yyvsp[(3) - (6)].l), 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
@@ -7981,8 +7748,8 @@ yyreduce:
     ;}
     break;
 
-  case 234:
-#line 3202 "Gmsh.y"
+  case 240:
+#line 3083 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_POINT, (int)(yyvsp[(4) - (8)].d),
@@ -7991,8 +7758,8 @@ yyreduce:
     ;}
     break;
 
-  case 235:
-#line 3209 "Gmsh.y"
+  case 241:
+#line 3090 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (8)].d),
@@ -8001,8 +7768,8 @@ yyreduce:
     ;}
     break;
 
-  case 236:
-#line 3216 "Gmsh.y"
+  case 242:
+#line 3097 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (8)].d),
@@ -8011,8 +7778,8 @@ yyreduce:
     ;}
     break;
 
-  case 237:
-#line 3223 "Gmsh.y"
+  case 243:
+#line 3104 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_POINT, (int)(yyvsp[(4) - (12)].d),
@@ -8021,8 +7788,8 @@ yyreduce:
     ;}
     break;
 
-  case 238:
-#line 3230 "Gmsh.y"
+  case 244:
+#line 3111 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (12)].d),
@@ -8031,8 +7798,8 @@ yyreduce:
     ;}
     break;
 
-  case 239:
-#line 3237 "Gmsh.y"
+  case 245:
+#line 3118 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (12)].d),
@@ -8041,8 +7808,8 @@ yyreduce:
     ;}
     break;
 
-  case 240:
-#line 3244 "Gmsh.y"
+  case 246:
+#line 3125 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_POINT, (int)(yyvsp[(4) - (14)].d),
@@ -8051,8 +7818,8 @@ yyreduce:
     ;}
     break;
 
-  case 241:
-#line 3251 "Gmsh.y"
+  case 247:
+#line 3132 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (14)].d),
@@ -8061,8 +7828,8 @@ yyreduce:
     ;}
     break;
 
-  case 242:
-#line 3258 "Gmsh.y"
+  case 248:
+#line 3139 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (14)].d),
@@ -8071,8 +7838,8 @@ yyreduce:
     ;}
     break;
 
-  case 243:
-#line 3265 "Gmsh.y"
+  case 249:
+#line 3146 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -8080,8 +7847,8 @@ yyreduce:
     ;}
     break;
 
-  case 244:
-#line 3271 "Gmsh.y"
+  case 250:
+#line 3152 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_POINT, (int)(yyvsp[(4) - (12)].d),
@@ -8090,8 +7857,8 @@ yyreduce:
     ;}
     break;
 
-  case 245:
-#line 3278 "Gmsh.y"
+  case 251:
+#line 3159 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -8099,8 +7866,8 @@ yyreduce:
     ;}
     break;
 
-  case 246:
-#line 3284 "Gmsh.y"
+  case 252:
+#line 3165 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (12)].d),
@@ -8109,8 +7876,8 @@ yyreduce:
     ;}
     break;
 
-  case 247:
-#line 3291 "Gmsh.y"
+  case 253:
+#line 3172 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -8118,8 +7885,8 @@ yyreduce:
     ;}
     break;
 
-  case 248:
-#line 3297 "Gmsh.y"
+  case 254:
+#line 3178 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (12)].d),
@@ -8128,8 +7895,8 @@ yyreduce:
     ;}
     break;
 
-  case 249:
-#line 3304 "Gmsh.y"
+  case 255:
+#line 3185 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -8137,8 +7904,8 @@ yyreduce:
     ;}
     break;
 
-  case 250:
-#line 3310 "Gmsh.y"
+  case 256:
+#line 3191 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_POINT, (int)(yyvsp[(4) - (16)].d),
@@ -8147,8 +7914,8 @@ yyreduce:
     ;}
     break;
 
-  case 251:
-#line 3317 "Gmsh.y"
+  case 257:
+#line 3198 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -8156,8 +7923,8 @@ yyreduce:
     ;}
     break;
 
-  case 252:
-#line 3323 "Gmsh.y"
+  case 258:
+#line 3204 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (16)].d),
@@ -8166,8 +7933,8 @@ yyreduce:
     ;}
     break;
 
-  case 253:
-#line 3330 "Gmsh.y"
+  case 259:
+#line 3211 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -8175,8 +7942,8 @@ yyreduce:
     ;}
     break;
 
-  case 254:
-#line 3336 "Gmsh.y"
+  case 260:
+#line 3217 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (16)].d),
@@ -8185,8 +7952,8 @@ yyreduce:
     ;}
     break;
 
-  case 255:
-#line 3343 "Gmsh.y"
+  case 261:
+#line 3224 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -8194,8 +7961,8 @@ yyreduce:
     ;}
     break;
 
-  case 256:
-#line 3349 "Gmsh.y"
+  case 262:
+#line 3230 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_POINT, (int)(yyvsp[(4) - (18)].d),
@@ -8204,8 +7971,8 @@ yyreduce:
     ;}
     break;
 
-  case 257:
-#line 3356 "Gmsh.y"
+  case 263:
+#line 3237 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -8213,8 +7980,8 @@ yyreduce:
     ;}
     break;
 
-  case 258:
-#line 3362 "Gmsh.y"
+  case 264:
+#line 3243 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (18)].d),
@@ -8223,8 +7990,8 @@ yyreduce:
     ;}
     break;
 
-  case 259:
-#line 3369 "Gmsh.y"
+  case 265:
+#line 3250 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -8232,8 +7999,8 @@ yyreduce:
     ;}
     break;
 
-  case 260:
-#line 3375 "Gmsh.y"
+  case 266:
+#line 3256 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (18)].d),
@@ -8242,20 +8009,20 @@ yyreduce:
     ;}
     break;
 
-  case 261:
-#line 3386 "Gmsh.y"
+  case 267:
+#line 3267 "Gmsh.y"
     {
     ;}
     break;
 
-  case 262:
-#line 3389 "Gmsh.y"
+  case 268:
+#line 3270 "Gmsh.y"
     {
     ;}
     break;
 
-  case 263:
-#line 3395 "Gmsh.y"
+  case 269:
+#line 3276 "Gmsh.y"
     {
       int n = (int)fabs((yyvsp[(3) - (5)].d));
       if(n){ // we accept n==0 to easily disable layers
@@ -8269,8 +8036,8 @@ yyreduce:
     ;}
     break;
 
-  case 264:
-#line 3407 "Gmsh.y"
+  case 270:
+#line 3288 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = true;
       extr.mesh.NbLayer = List_Nbr((yyvsp[(3) - (7)].l));
@@ -8292,8 +8059,8 @@ yyreduce:
     ;}
     break;
 
-  case 265:
-#line 3427 "Gmsh.y"
+  case 271:
+#line 3308 "Gmsh.y"
     {
       yymsg(0, "Explicit region numbers in layers are deprecated");
       extr.mesh.ExtrudeMesh = true;
@@ -8318,78 +8085,82 @@ yyreduce:
     ;}
     break;
 
-  case 266:
-#line 3451 "Gmsh.y"
+  case 272:
+#line 3332 "Gmsh.y"
     {
       extr.mesh.ScaleLast = true;
     ;}
     break;
 
-  case 267:
-#line 3456 "Gmsh.y"
+  case 273:
+#line 3336 "Gmsh.y"
     {
       extr.mesh.Recombine = true;
     ;}
     break;
 
-  case 268:
-#line 3460 "Gmsh.y"
+  case 274:
+#line 3340 "Gmsh.y"
     {
       yymsg(0, "Keyword 'QuadTriSngl' deprecated. Use 'QuadTriNoNewVerts' instead.");
     ;}
     break;
 
-  case 269:
-#line 3464 "Gmsh.y"
+  case 275:
+#line 3344 "Gmsh.y"
     {
       yymsg(0, "Keyword 'QuadTriSngl' deprecated. Use 'QuadTriNoNewVerts' instead.");
     ;}
     break;
 
-  case 270:
-#line 3468 "Gmsh.y"
+  case 276:
+#line 3348 "Gmsh.y"
     {
-      yymsg(0, "Method 'QuadTriDbl' deprecated. Use 'QuadTriAddVerts' instead, which has no requirement for the number of extrusion layers and meshes with body-centered vertices.");
+      yymsg(0, "Method 'QuadTriDbl' deprecated. Use 'QuadTriAddVerts' instead, "
+            "which has no requirement for the number of extrusion layers and meshes "
+            "with body-centered vertices.");
     ;}
     break;
 
-  case 271:
-#line 3472 "Gmsh.y"
+  case 277:
+#line 3354 "Gmsh.y"
     {
-      yymsg(0, "Method 'QuadTriDbl' deprecated. Use 'QuadTriAddVerts' instead, which has no requirement for the number of extrusion layers and meshes with body-centered vertices.");
+      yymsg(0, "Method 'QuadTriDbl' deprecated. Use 'QuadTriAddVerts' instead, "
+            "which has no requirement for the number of extrusion layers and meshes "
+            "with body-centered vertices.");
     ;}
     break;
 
-  case 272:
-#line 3476 "Gmsh.y"
+  case 278:
+#line 3360 "Gmsh.y"
     {
       extr.mesh.QuadToTri = QUADTRI_ADDVERTS_1;
     ;}
     break;
 
-  case 273:
-#line 3480 "Gmsh.y"
+  case 279:
+#line 3364 "Gmsh.y"
     {
       extr.mesh.QuadToTri = QUADTRI_ADDVERTS_1_RECOMB;
     ;}
     break;
 
-  case 274:
-#line 3484 "Gmsh.y"
+  case 280:
+#line 3368 "Gmsh.y"
     {
       extr.mesh.QuadToTri = QUADTRI_NOVERTS_1;
     ;}
     break;
 
-  case 275:
-#line 3488 "Gmsh.y"
+  case 281:
+#line 3372 "Gmsh.y"
     {
       extr.mesh.QuadToTri = QUADTRI_NOVERTS_1_RECOMB;
     ;}
     break;
 
-  case 276:
-#line 3492 "Gmsh.y"
+  case 282:
+#line 3376 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (9)].d);
       if(FindSurface(num)){
@@ -8410,8 +8181,8 @@ yyreduce:
     ;}
     break;
 
-  case 277:
-#line 3511 "Gmsh.y"
+  case 283:
+#line 3395 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (6)].c), "Index"))
         extr.mesh.BoundaryLayerIndex = (yyvsp[(4) - (6)].d);
@@ -8421,15 +8192,15 @@ yyreduce:
     ;}
     break;
 
-  case 278:
-#line 3523 "Gmsh.y"
+  case 284:
+#line 3407 "Gmsh.y"
     {
       (yyval.v)[0] = (yyval.v)[1] = 1.;
     ;}
     break;
 
-  case 279:
-#line 3527 "Gmsh.y"
+  case 285:
+#line 3411 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (3)].c), "Progression") || !strcmp((yyvsp[(2) - (3)].c), "Power"))
         (yyval.v)[0] = 1.;
@@ -8444,15 +8215,15 @@ yyreduce:
     ;}
     break;
 
-  case 280:
-#line 3542 "Gmsh.y"
+  case 286:
+#line 3426 "Gmsh.y"
     {
       (yyval.i) = -1; // left
     ;}
     break;
 
-  case 281:
-#line 3546 "Gmsh.y"
+  case 287:
+#line 3430 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (1)].c), "Right"))
         (yyval.i) = 1;
@@ -8468,36 +8239,36 @@ yyreduce:
     ;}
     break;
 
-  case 282:
-#line 3562 "Gmsh.y"
+  case 288:
+#line 3446 "Gmsh.y"
     {
      (yyval.l) = List_Create(1, 1, sizeof(double));
    ;}
     break;
 
-  case 283:
-#line 3566 "Gmsh.y"
+  case 289:
+#line 3450 "Gmsh.y"
     {
      (yyval.l) = (yyvsp[(2) - (2)].l);
    ;}
     break;
 
-  case 284:
-#line 3571 "Gmsh.y"
+  case 290:
+#line 3455 "Gmsh.y"
     {
       (yyval.i) = 45;
     ;}
     break;
 
-  case 285:
-#line 3575 "Gmsh.y"
+  case 291:
+#line 3459 "Gmsh.y"
     {
       (yyval.i) = (int)(yyvsp[(2) - (2)].d);
     ;}
     break;
 
-  case 286:
-#line 3582 "Gmsh.y"
+  case 292:
+#line 3466 "Gmsh.y"
     {
       int type = (int)(yyvsp[(6) - (7)].v)[0];
       double coef = fabs((yyvsp[(6) - (7)].v)[1]);
@@ -8555,8 +8326,8 @@ yyreduce:
     ;}
     break;
 
-  case 287:
-#line 3638 "Gmsh.y"
+  case 293:
+#line 3522 "Gmsh.y"
     {
       int k = List_Nbr((yyvsp[(4) - (6)].l));
       if(k != 0 && k != 3 && k != 4){
@@ -8628,16 +8399,16 @@ yyreduce:
     ;}
     break;
 
-  case 288:
-#line 3708 "Gmsh.y"
+  case 294:
+#line 3592 "Gmsh.y"
     {
       yymsg(1, "Elliptic Surface is deprecated: use Transfinite instead (with smoothing)");
       List_Delete((yyvsp[(7) - (8)].l));
     ;}
     break;
 
-  case 289:
-#line 3713 "Gmsh.y"
+  case 295:
+#line 3597 "Gmsh.y"
     {
       int k = List_Nbr((yyvsp[(4) - (5)].l));
       if(k != 0 && k != 6 && k != 8){
@@ -8706,8 +8477,8 @@ yyreduce:
     ;}
     break;
 
-  case 290:
-#line 3780 "Gmsh.y"
+  case 296:
+#line 3664 "Gmsh.y"
     {
       if(!(yyvsp[(2) - (3)].l)){
   	  List_T *tmp = Tree2List(GModel::current()->getGEOInternals()->Volumes);
@@ -8745,8 +8516,8 @@ yyreduce:
     ;}
     break;
 
-  case 291:
-#line 3816 "Gmsh.y"
+  case 297:
+#line 3700 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (7)].l)); i++){
 	double d;
@@ -8756,8 +8527,8 @@ yyreduce:
     ;}
     break;
 
-  case 292:
-#line 3824 "Gmsh.y"
+  case 298:
+#line 3708 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (5)].l)){
 	List_T *tmp = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
@@ -8802,8 +8573,8 @@ yyreduce:
     ;}
     break;
 
-  case 293:
-#line 3867 "Gmsh.y"
+  case 299:
+#line 3751 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].l)){
 	List_T *tmp = Tree2List(GModel::current()->getGEOInternals()->Volumes);
@@ -8844,8 +8615,8 @@ yyreduce:
     ;}
     break;
 
-  case 294:
-#line 3906 "Gmsh.y"
+  case 300:
+#line 3790 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (6)].l)); i++){
 	double d;
@@ -8867,8 +8638,8 @@ yyreduce:
     ;}
     break;
 
-  case 295:
-#line 3926 "Gmsh.y"
+  case 301:
+#line 3810 "Gmsh.y"
     {
       if(List_Nbr((yyvsp[(5) - (6)].l)) != List_Nbr((yyvsp[(3) - (6)].l))){
 	yymsg(0, "Number of master (%d) different from number of slave (%d) lines",
@@ -8897,8 +8668,8 @@ yyreduce:
     ;}
     break;
 
-  case 296:
-#line 3954 "Gmsh.y"
+  case 302:
+#line 3838 "Gmsh.y"
     {
       if (List_Nbr((yyvsp[(5) - (12)].l)) != List_Nbr((yyvsp[(10) - (12)].l))){
 	yymsg(0, "Number of master surface edges (%d) different from number of "
@@ -8939,8 +8710,8 @@ yyreduce:
     ;}
     break;
 
-  case 297:
-#line 3993 "Gmsh.y"
+  case 303:
+#line 3877 "Gmsh.y"
     {
       Surface *s = FindSurface((int)(yyvsp[(8) - (10)].d));
       if(s){
@@ -8965,8 +8736,8 @@ yyreduce:
     ;}
     break;
 
-  case 298:
-#line 4016 "Gmsh.y"
+  case 304:
+#line 3900 "Gmsh.y"
     {
       Surface *s = FindSurface((int)(yyvsp[(8) - (10)].d));
       if(s){
@@ -8991,22 +8762,22 @@ yyreduce:
     ;}
     break;
 
-  case 299:
-#line 4039 "Gmsh.y"
+  case 305:
+#line 3923 "Gmsh.y"
     {
       Msg::Error("Point in Volume not implemented yet");
     ;}
     break;
 
-  case 300:
-#line 4043 "Gmsh.y"
+  case 306:
+#line 3927 "Gmsh.y"
     {
       Msg::Error("Line in Volume not implemented yet");
     ;}
     break;
 
-  case 301:
-#line 4047 "Gmsh.y"
+  case 307:
+#line 3931 "Gmsh.y"
     {
       Volume *v = FindVolume((int)(yyvsp[(8) - (10)].d));
       if(v){
@@ -9031,8 +8802,8 @@ yyreduce:
     ;}
     break;
 
-  case 302:
-#line 4070 "Gmsh.y"
+  case 308:
+#line 3954 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].l)){
 	List_T *tmp = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
@@ -9073,8 +8844,8 @@ yyreduce:
     ;}
     break;
 
-  case 303:
-#line 4109 "Gmsh.y"
+  case 309:
+#line 3993 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].l)){
 	List_T *tmp = Tree2List(GModel::current()->getGEOInternals()->Curves);
@@ -9115,8 +8886,8 @@ yyreduce:
     ;}
     break;
 
-  case 304:
-#line 4148 "Gmsh.y"
+  case 310:
+#line 4032 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].l)){
         for(GModel::viter it = GModel::current()->firstVertex();
@@ -9139,8 +8910,8 @@ yyreduce:
     ;}
     break;
 
-  case 305:
-#line 4169 "Gmsh.y"
+  case 311:
+#line 4053 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].l)){
         for(GModel::eiter it = GModel::current()->firstEdge();
@@ -9163,8 +8934,8 @@ yyreduce:
     ;}
     break;
 
-  case 306:
-#line 4190 "Gmsh.y"
+  case 312:
+#line 4074 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].l)){
         for(GModel::fiter it = GModel::current()->firstFace();
@@ -9187,15 +8958,15 @@ yyreduce:
     ;}
     break;
 
-  case 307:
-#line 4217 "Gmsh.y"
+  case 313:
+#line 4101 "Gmsh.y"
     {
       ReplaceAllDuplicates();
     ;}
     break;
 
-  case 308:
-#line 4221 "Gmsh.y"
+  case 314:
+#line 4105 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (3)].c), "Geometry"))
         ReplaceAllDuplicates();
@@ -9207,8 +8978,8 @@ yyreduce:
     ;}
     break;
 
-  case 309:
-#line 4231 "Gmsh.y"
+  case 315:
+#line 4115 "Gmsh.y"
     {
       if(List_Nbr((yyvsp[(4) - (6)].l)) >= 2){
         double d;
@@ -9240,23 +9011,23 @@ yyreduce:
     ;}
     break;
 
-  case 310:
-#line 4265 "Gmsh.y"
+  case 316:
+#line 4149 "Gmsh.y"
     { (yyval.c) = (char*)"Homology"; ;}
     break;
 
-  case 311:
-#line 4266 "Gmsh.y"
+  case 317:
+#line 4150 "Gmsh.y"
     { (yyval.c) = (char*)"Cohomology"; ;}
     break;
 
-  case 312:
-#line 4267 "Gmsh.y"
+  case 318:
+#line 4151 "Gmsh.y"
     { (yyval.c) = (char*)"Betti"; ;}
     break;
 
-  case 313:
-#line 4272 "Gmsh.y"
+  case 319:
+#line 4156 "Gmsh.y"
     {
       std::vector<int> domain, subdomain, dim;
       for(int i = 0; i < 4; i++) dim.push_back(i);
@@ -9264,8 +9035,8 @@ yyreduce:
     ;}
     break;
 
-  case 314:
-#line 4278 "Gmsh.y"
+  case 320:
+#line 4162 "Gmsh.y"
     {
       std::vector<int> domain, subdomain, dim;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (5)].l)); i++){
@@ -9279,8 +9050,8 @@ yyreduce:
     ;}
     break;
 
-  case 315:
-#line 4290 "Gmsh.y"
+  case 321:
+#line 4174 "Gmsh.y"
     {
       std::vector<int> domain, subdomain, dim;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (7)].l)); i++){
@@ -9300,8 +9071,8 @@ yyreduce:
     ;}
     break;
 
-  case 316:
-#line 4308 "Gmsh.y"
+  case 322:
+#line 4192 "Gmsh.y"
     {
       std::vector<int> domain, subdomain, dim;
       for(int i = 0; i < List_Nbr((yyvsp[(6) - (10)].l)); i++){
@@ -9326,48 +9097,48 @@ yyreduce:
     ;}
     break;
 
-  case 317:
-#line 4335 "Gmsh.y"
+  case 323:
+#line 4219 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (1)].d);           ;}
     break;
 
-  case 318:
-#line 4336 "Gmsh.y"
+  case 324:
+#line 4220 "Gmsh.y"
     { (yyval.d) = (yyvsp[(2) - (3)].d);           ;}
     break;
 
-  case 319:
-#line 4337 "Gmsh.y"
+  case 325:
+#line 4221 "Gmsh.y"
     { (yyval.d) = -(yyvsp[(2) - (2)].d);          ;}
     break;
 
-  case 320:
-#line 4338 "Gmsh.y"
+  case 326:
+#line 4222 "Gmsh.y"
     { (yyval.d) = (yyvsp[(2) - (2)].d);           ;}
     break;
 
-  case 321:
-#line 4339 "Gmsh.y"
+  case 327:
+#line 4223 "Gmsh.y"
     { (yyval.d) = !(yyvsp[(2) - (2)].d);          ;}
     break;
 
-  case 322:
-#line 4340 "Gmsh.y"
+  case 328:
+#line 4224 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) - (yyvsp[(3) - (3)].d);      ;}
     break;
 
-  case 323:
-#line 4341 "Gmsh.y"
+  case 329:
+#line 4225 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) + (yyvsp[(3) - (3)].d);      ;}
     break;
 
-  case 324:
-#line 4342 "Gmsh.y"
+  case 330:
+#line 4226 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) * (yyvsp[(3) - (3)].d);      ;}
     break;
 
-  case 325:
-#line 4344 "Gmsh.y"
+  case 331:
+#line 4228 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (3)].d))
 	yymsg(0, "Division by zero in '%g / %g'", (yyvsp[(1) - (3)].d), (yyvsp[(3) - (3)].d));
@@ -9376,328 +9147,237 @@ yyreduce:
     ;}
     break;
 
-  case 326:
-#line 4350 "Gmsh.y"
-    { (yyval.d) = (int)(yyvsp[(1) - (3)].d) % (int)(yyvsp[(3) - (3)].d);  ;}
-    break;
-
-  case 327:
-#line 4351 "Gmsh.y"
-    { (yyval.d) = pow((yyvsp[(1) - (3)].d), (yyvsp[(3) - (3)].d));  ;}
-    break;
-
-  case 328:
-#line 4352 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (3)].d) < (yyvsp[(3) - (3)].d);      ;}
-    break;
-
-  case 329:
-#line 4353 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (3)].d) > (yyvsp[(3) - (3)].d);      ;}
-    break;
-
-  case 330:
-#line 4354 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (3)].d) <= (yyvsp[(3) - (3)].d);     ;}
-    break;
-
-  case 331:
-#line 4355 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (3)].d) >= (yyvsp[(3) - (3)].d);     ;}
-    break;
-
   case 332:
-#line 4356 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (3)].d) == (yyvsp[(3) - (3)].d);     ;}
+#line 4234 "Gmsh.y"
+    { (yyval.d) = (int)(yyvsp[(1) - (3)].d) % (int)(yyvsp[(3) - (3)].d);  ;}
     break;
 
   case 333:
-#line 4357 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (3)].d) != (yyvsp[(3) - (3)].d);     ;}
+#line 4235 "Gmsh.y"
+    { (yyval.d) = pow((yyvsp[(1) - (3)].d), (yyvsp[(3) - (3)].d));  ;}
     break;
 
   case 334:
-#line 4358 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (3)].d) && (yyvsp[(3) - (3)].d);     ;}
+#line 4236 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (3)].d) < (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 335:
-#line 4359 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (3)].d) || (yyvsp[(3) - (3)].d);     ;}
+#line 4237 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (3)].d) > (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 336:
-#line 4360 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (5)].d) ? (yyvsp[(3) - (5)].d) : (yyvsp[(5) - (5)].d); ;}
+#line 4238 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (3)].d) <= (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 337:
-#line 4361 "Gmsh.y"
-    { (yyval.d) = exp((yyvsp[(3) - (4)].d));      ;}
+#line 4239 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (3)].d) >= (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 338:
-#line 4362 "Gmsh.y"
-    { (yyval.d) = log((yyvsp[(3) - (4)].d));      ;}
+#line 4240 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (3)].d) == (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 339:
-#line 4363 "Gmsh.y"
-    { (yyval.d) = log10((yyvsp[(3) - (4)].d));    ;}
+#line 4241 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (3)].d) != (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 340:
-#line 4364 "Gmsh.y"
-    { (yyval.d) = sqrt((yyvsp[(3) - (4)].d));     ;}
+#line 4242 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (3)].d) && (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 341:
-#line 4365 "Gmsh.y"
-    { (yyval.d) = sin((yyvsp[(3) - (4)].d));      ;}
+#line 4243 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (3)].d) || (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 342:
-#line 4366 "Gmsh.y"
-    { (yyval.d) = asin((yyvsp[(3) - (4)].d));     ;}
+#line 4244 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (5)].d) ? (yyvsp[(3) - (5)].d) : (yyvsp[(5) - (5)].d); ;}
     break;
 
   case 343:
-#line 4367 "Gmsh.y"
-    { (yyval.d) = cos((yyvsp[(3) - (4)].d));      ;}
+#line 4245 "Gmsh.y"
+    { (yyval.d) = exp((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 344:
-#line 4368 "Gmsh.y"
-    { (yyval.d) = acos((yyvsp[(3) - (4)].d));     ;}
+#line 4246 "Gmsh.y"
+    { (yyval.d) = log((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 345:
-#line 4369 "Gmsh.y"
-    { (yyval.d) = tan((yyvsp[(3) - (4)].d));      ;}
+#line 4247 "Gmsh.y"
+    { (yyval.d) = log10((yyvsp[(3) - (4)].d));    ;}
     break;
 
   case 346:
-#line 4370 "Gmsh.y"
-    { (yyval.d) = atan((yyvsp[(3) - (4)].d));     ;}
+#line 4248 "Gmsh.y"
+    { (yyval.d) = sqrt((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 347:
-#line 4371 "Gmsh.y"
-    { (yyval.d) = atan2((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d));;}
+#line 4249 "Gmsh.y"
+    { (yyval.d) = sin((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 348:
-#line 4372 "Gmsh.y"
-    { (yyval.d) = sinh((yyvsp[(3) - (4)].d));     ;}
+#line 4250 "Gmsh.y"
+    { (yyval.d) = asin((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 349:
-#line 4373 "Gmsh.y"
-    { (yyval.d) = cosh((yyvsp[(3) - (4)].d));     ;}
+#line 4251 "Gmsh.y"
+    { (yyval.d) = cos((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 350:
-#line 4374 "Gmsh.y"
-    { (yyval.d) = tanh((yyvsp[(3) - (4)].d));     ;}
+#line 4252 "Gmsh.y"
+    { (yyval.d) = acos((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 351:
-#line 4375 "Gmsh.y"
-    { (yyval.d) = fabs((yyvsp[(3) - (4)].d));     ;}
+#line 4253 "Gmsh.y"
+    { (yyval.d) = tan((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 352:
-#line 4376 "Gmsh.y"
-    { (yyval.d) = floor((yyvsp[(3) - (4)].d));    ;}
+#line 4254 "Gmsh.y"
+    { (yyval.d) = atan((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 353:
-#line 4377 "Gmsh.y"
-    { (yyval.d) = ceil((yyvsp[(3) - (4)].d));     ;}
+#line 4255 "Gmsh.y"
+    { (yyval.d) = atan2((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d));;}
     break;
 
   case 354:
-#line 4378 "Gmsh.y"
-    { (yyval.d) = floor((yyvsp[(3) - (4)].d) + 0.5); ;}
+#line 4256 "Gmsh.y"
+    { (yyval.d) = sinh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 355:
-#line 4379 "Gmsh.y"
-    { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
+#line 4257 "Gmsh.y"
+    { (yyval.d) = cosh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 356:
-#line 4380 "Gmsh.y"
-    { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
+#line 4258 "Gmsh.y"
+    { (yyval.d) = tanh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 357:
-#line 4381 "Gmsh.y"
-    { (yyval.d) = sqrt((yyvsp[(3) - (6)].d) * (yyvsp[(3) - (6)].d) + (yyvsp[(5) - (6)].d) * (yyvsp[(5) - (6)].d)); ;}
+#line 4259 "Gmsh.y"
+    { (yyval.d) = fabs((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 358:
-#line 4382 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(3) - (4)].d) * (double)rand() / (double)RAND_MAX; ;}
+#line 4260 "Gmsh.y"
+    { (yyval.d) = floor((yyvsp[(3) - (4)].d));    ;}
     break;
 
   case 359:
-#line 4385 "Gmsh.y"
-    { (yyval.d) = exp((yyvsp[(3) - (4)].d));      ;}
+#line 4261 "Gmsh.y"
+    { (yyval.d) = ceil((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 360:
-#line 4386 "Gmsh.y"
-    { (yyval.d) = log((yyvsp[(3) - (4)].d));      ;}
+#line 4262 "Gmsh.y"
+    { (yyval.d) = floor((yyvsp[(3) - (4)].d) + 0.5); ;}
     break;
 
   case 361:
-#line 4387 "Gmsh.y"
-    { (yyval.d) = log10((yyvsp[(3) - (4)].d));    ;}
+#line 4263 "Gmsh.y"
+    { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 362:
-#line 4388 "Gmsh.y"
-    { (yyval.d) = sqrt((yyvsp[(3) - (4)].d));     ;}
+#line 4264 "Gmsh.y"
+    { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 363:
-#line 4389 "Gmsh.y"
-    { (yyval.d) = sin((yyvsp[(3) - (4)].d));      ;}
+#line 4265 "Gmsh.y"
+    { (yyval.d) = sqrt((yyvsp[(3) - (6)].d) * (yyvsp[(3) - (6)].d) + (yyvsp[(5) - (6)].d) * (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 364:
-#line 4390 "Gmsh.y"
-    { (yyval.d) = asin((yyvsp[(3) - (4)].d));     ;}
+#line 4266 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(3) - (4)].d) * (double)rand() / (double)RAND_MAX; ;}
     break;
 
   case 365:
-#line 4391 "Gmsh.y"
-    { (yyval.d) = cos((yyvsp[(3) - (4)].d));      ;}
+#line 4275 "Gmsh.y"
+    { (yyval.d) = (yyvsp[(1) - (1)].d); ;}
     break;
 
   case 366:
-#line 4392 "Gmsh.y"
-    { (yyval.d) = acos((yyvsp[(3) - (4)].d));     ;}
+#line 4276 "Gmsh.y"
+    { (yyval.d) = 3.141592653589793; ;}
     break;
 
   case 367:
-#line 4393 "Gmsh.y"
-    { (yyval.d) = tan((yyvsp[(3) - (4)].d));      ;}
+#line 4277 "Gmsh.y"
+    { (yyval.d) = Msg::GetCommRank(); ;}
     break;
 
   case 368:
-#line 4394 "Gmsh.y"
-    { (yyval.d) = atan((yyvsp[(3) - (4)].d));     ;}
+#line 4278 "Gmsh.y"
+    { (yyval.d) = Msg::GetCommSize(); ;}
     break;
 
   case 369:
-#line 4395 "Gmsh.y"
-    { (yyval.d) = atan2((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d));;}
+#line 4279 "Gmsh.y"
+    { (yyval.d) = GetGmshMajorVersion(); ;}
     break;
 
   case 370:
-#line 4396 "Gmsh.y"
-    { (yyval.d) = sinh((yyvsp[(3) - (4)].d));     ;}
+#line 4280 "Gmsh.y"
+    { (yyval.d) = GetGmshMinorVersion(); ;}
     break;
 
   case 371:
-#line 4397 "Gmsh.y"
-    { (yyval.d) = cosh((yyvsp[(3) - (4)].d));     ;}
+#line 4281 "Gmsh.y"
+    { (yyval.d) = GetGmshPatchVersion(); ;}
     break;
 
   case 372:
-#line 4398 "Gmsh.y"
-    { (yyval.d) = tanh((yyvsp[(3) - (4)].d));     ;}
+#line 4282 "Gmsh.y"
+    { (yyval.d) = Cpu(); ;}
     break;
 
   case 373:
-#line 4399 "Gmsh.y"
-    { (yyval.d) = fabs((yyvsp[(3) - (4)].d));     ;}
+#line 4283 "Gmsh.y"
+    { (yyval.d) = GetMemoryUsage()/1024./1024.; ;}
     break;
 
   case 374:
-#line 4400 "Gmsh.y"
-    { (yyval.d) = floor((yyvsp[(3) - (4)].d));    ;}
+#line 4284 "Gmsh.y"
+    { (yyval.d) = TotalRam(); ;}
     break;
 
   case 375:
-#line 4401 "Gmsh.y"
-    { (yyval.d) = ceil((yyvsp[(3) - (4)].d));     ;}
+#line 4289 "Gmsh.y"
+    { floatOptions.clear(); charOptions.clear(); ;}
     break;
 
   case 376:
-#line 4402 "Gmsh.y"
-    { (yyval.d) = floor((yyvsp[(3) - (4)].d) + 0.5);    ;}
+#line 4291 "Gmsh.y"
+    {
+      std::vector<double> val(1, (yyvsp[(3) - (6)].d));
+      Msg::ExchangeOnelabParameter("", val, floatOptions, charOptions);
+      (yyval.d) = val[0];
+    ;}
     break;
 
   case 377:
-#line 4403 "Gmsh.y"
-    { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
-    break;
-
-  case 378:
-#line 4404 "Gmsh.y"
-    { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
-    break;
-
-  case 379:
-#line 4405 "Gmsh.y"
-    { (yyval.d) = sqrt((yyvsp[(3) - (6)].d) * (yyvsp[(3) - (6)].d) + (yyvsp[(5) - (6)].d) * (yyvsp[(5) - (6)].d)); ;}
-    break;
-
-  case 380:
-#line 4406 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(3) - (4)].d) * (double)rand() / (double)RAND_MAX; ;}
-    break;
-
-  case 381:
-#line 4415 "Gmsh.y"
-    { (yyval.d) = (yyvsp[(1) - (1)].d); ;}
-    break;
-
-  case 382:
-#line 4416 "Gmsh.y"
-    { (yyval.d) = 3.141592653589793; ;}
-    break;
-
-  case 383:
-#line 4417 "Gmsh.y"
-    { (yyval.d) = Msg::GetCommRank(); ;}
-    break;
-
-  case 384:
-#line 4418 "Gmsh.y"
-    { (yyval.d) = Msg::GetCommSize(); ;}
-    break;
-
-  case 385:
-#line 4419 "Gmsh.y"
-    { (yyval.d) = GetGmshMajorVersion(); ;}
-    break;
-
-  case 386:
-#line 4420 "Gmsh.y"
-    { (yyval.d) = GetGmshMinorVersion(); ;}
-    break;
-
-  case 387:
-#line 4421 "Gmsh.y"
-    { (yyval.d) = GetGmshPatchVersion(); ;}
-    break;
-
-  case 388:
-#line 4422 "Gmsh.y"
-    { (yyval.d) = Cpu(); ;}
-    break;
-
-  case 389:
-#line 4423 "Gmsh.y"
-    { (yyval.d) = GetMemoryUsage()/1024./1024.; ;}
-    break;
-
-  case 390:
-#line 4428 "Gmsh.y"
+#line 4297 "Gmsh.y"
     {
       if(!gmsh_yysymbols.count((yyvsp[(1) - (1)].c))){
 	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (1)].c));
@@ -9716,8 +9396,8 @@ yyreduce:
     ;}
     break;
 
-  case 391:
-#line 4446 "Gmsh.y"
+  case 378:
+#line 4314 "Gmsh.y"
     {
       int index = (int)(yyvsp[(3) - (4)].d);
       if(!gmsh_yysymbols.count((yyvsp[(1) - (4)].c))){
@@ -9737,8 +9417,46 @@ yyreduce:
     ;}
     break;
 
-  case 392:
-#line 4464 "Gmsh.y"
+  case 379:
+#line 4332 "Gmsh.y"
+    {
+      int index = (int)(yyvsp[(3) - (4)].d);
+      if(!gmsh_yysymbols.count((yyvsp[(1) - (4)].c))){
+	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (4)].c));
+	(yyval.d) = 0.;
+      }
+      else{
+        gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (4)].c)]);
+        if((int)s.value.size() < index + 1){
+          yymsg(0, "Uninitialized variable '%s[%d]'", (yyvsp[(1) - (4)].c), index);
+          (yyval.d) = 0.;
+        }
+        else
+          (yyval.d) = s.value[index];
+      }
+      Free((yyvsp[(1) - (4)].c));
+    ;}
+    break;
+
+  case 380:
+#line 4350 "Gmsh.y"
+    {
+      (yyval.d) = gmsh_yysymbols.count((yyvsp[(3) - (4)].c));
+      Free((yyvsp[(3) - (4)].c));
+    ;}
+    break;
+
+  case 381:
+#line 4355 "Gmsh.y"
+    {
+      std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(3) - (4)].c));
+      (yyval.d) = !StatFile(tmp);
+      Free((yyvsp[(3) - (4)].c));
+    ;}
+    break;
+
+  case 382:
+#line 4361 "Gmsh.y"
     {
       if(!gmsh_yysymbols.count((yyvsp[(2) - (4)].c))){
 	yymsg(0, "Unknown variable '%s'", (yyvsp[(2) - (4)].c));
@@ -9752,8 +9470,8 @@ yyreduce:
     ;}
     break;
 
-  case 393:
-#line 4476 "Gmsh.y"
+  case 383:
+#line 4373 "Gmsh.y"
     {
       if(!gmsh_yysymbols.count((yyvsp[(1) - (2)].c))){
 	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (2)].c));
@@ -9772,8 +9490,8 @@ yyreduce:
     ;}
     break;
 
-  case 394:
-#line 4493 "Gmsh.y"
+  case 384:
+#line 4390 "Gmsh.y"
     {
       int index = (int)(yyvsp[(3) - (5)].d);
       if(!gmsh_yysymbols.count((yyvsp[(1) - (5)].c))){
@@ -9793,24 +9511,45 @@ yyreduce:
     ;}
     break;
 
-  case 395:
-#line 4514 "Gmsh.y"
+  case 385:
+#line 4408 "Gmsh.y"
+    {
+      int index = (int)(yyvsp[(3) - (5)].d);
+      if(!gmsh_yysymbols.count((yyvsp[(1) - (5)].c))){
+	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (5)].c));
+	(yyval.d) = 0.;
+      }
+      else{
+        gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (5)].c)]);
+        if((int)s.value.size() < index + 1){
+          yymsg(0, "Uninitialized variable '%s[%d]'", (yyvsp[(1) - (5)].c), index);
+          (yyval.d) = 0.;
+        }
+        else
+          (yyval.d) = (s.value[index] += (yyvsp[(5) - (5)].i));
+      }
+      Free((yyvsp[(1) - (5)].c));
+    ;}
+    break;
+
+  case 386:
+#line 4429 "Gmsh.y"
     {
       NumberOption(GMSH_GET, (yyvsp[(1) - (3)].c), 0, (yyvsp[(3) - (3)].c), (yyval.d));
       Free((yyvsp[(1) - (3)].c)); Free((yyvsp[(3) - (3)].c));
     ;}
     break;
 
-  case 396:
-#line 4519 "Gmsh.y"
+  case 387:
+#line 4434 "Gmsh.y"
     {
       NumberOption(GMSH_GET, (yyvsp[(1) - (6)].c), (int)(yyvsp[(3) - (6)].d), (yyvsp[(6) - (6)].c), (yyval.d));
       Free((yyvsp[(1) - (6)].c)); Free((yyvsp[(6) - (6)].c));
     ;}
     break;
 
-  case 397:
-#line 4524 "Gmsh.y"
+  case 388:
+#line 4439 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (4)].c), 0, (yyvsp[(3) - (4)].c), d)){
@@ -9822,8 +9561,8 @@ yyreduce:
     ;}
     break;
 
-  case 398:
-#line 4534 "Gmsh.y"
+  case 389:
+#line 4449 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(6) - (7)].c), d)){
@@ -9835,16 +9574,16 @@ yyreduce:
     ;}
     break;
 
-  case 399:
-#line 4544 "Gmsh.y"
+  case 390:
+#line 4459 "Gmsh.y"
     {
       (yyval.d) = Msg::GetValue((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].d));
       Free((yyvsp[(3) - (6)].c));
     ;}
     break;
 
-  case 400:
-#line 4549 "Gmsh.y"
+  case 391:
+#line 4464 "Gmsh.y"
     {
       std::string s((yyvsp[(3) - (6)].c)), substr((yyvsp[(5) - (6)].c));
       if(s.find(substr) != std::string::npos)
@@ -9855,16 +9594,16 @@ yyreduce:
     ;}
     break;
 
-  case 401:
-#line 4558 "Gmsh.y"
+  case 392:
+#line 4473 "Gmsh.y"
     {
       (yyval.d) = strcmp((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].c));
       Free((yyvsp[(3) - (6)].c)); Free((yyvsp[(5) - (6)].c));
     ;}
     break;
 
-  case 402:
-#line 4563 "Gmsh.y"
+  case 393:
+#line 4478 "Gmsh.y"
     {
       int align = 0, font = 0, fontsize = CTX::instance()->glFontSize;
       if(List_Nbr((yyvsp[(3) - (4)].l)) % 2){
@@ -9890,116 +9629,116 @@ yyreduce:
     ;}
     break;
 
-  case 403:
-#line 4590 "Gmsh.y"
+  case 394:
+#line 4505 "Gmsh.y"
     {
       memcpy((yyval.v), (yyvsp[(1) - (1)].v), 5*sizeof(double));
     ;}
     break;
 
-  case 404:
-#line 4594 "Gmsh.y"
+  case 395:
+#line 4509 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = -(yyvsp[(2) - (2)].v)[i];
     ;}
     break;
 
-  case 405:
-#line 4598 "Gmsh.y"
+  case 396:
+#line 4513 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = (yyvsp[(2) - (2)].v)[i];
     ;}
     break;
 
-  case 406:
-#line 4602 "Gmsh.y"
+  case 397:
+#line 4517 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = (yyvsp[(1) - (3)].v)[i] - (yyvsp[(3) - (3)].v)[i];
     ;}
     break;
 
-  case 407:
-#line 4606 "Gmsh.y"
+  case 398:
+#line 4521 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = (yyvsp[(1) - (3)].v)[i] + (yyvsp[(3) - (3)].v)[i];
     ;}
     break;
 
-  case 408:
-#line 4613 "Gmsh.y"
+  case 399:
+#line 4528 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (11)].d);  (yyval.v)[1] = (yyvsp[(4) - (11)].d);  (yyval.v)[2] = (yyvsp[(6) - (11)].d);  (yyval.v)[3] = (yyvsp[(8) - (11)].d); (yyval.v)[4] = (yyvsp[(10) - (11)].d);
     ;}
     break;
 
-  case 409:
-#line 4617 "Gmsh.y"
+  case 400:
+#line 4532 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (9)].d);  (yyval.v)[1] = (yyvsp[(4) - (9)].d);  (yyval.v)[2] = (yyvsp[(6) - (9)].d);  (yyval.v)[3] = (yyvsp[(8) - (9)].d); (yyval.v)[4] = 1.0;
     ;}
     break;
 
-  case 410:
-#line 4621 "Gmsh.y"
+  case 401:
+#line 4536 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (7)].d);  (yyval.v)[1] = (yyvsp[(4) - (7)].d);  (yyval.v)[2] = (yyvsp[(6) - (7)].d);  (yyval.v)[3] = 0.0; (yyval.v)[4] = 1.0;
     ;}
     break;
 
-  case 411:
-#line 4625 "Gmsh.y"
+  case 402:
+#line 4540 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (7)].d);  (yyval.v)[1] = (yyvsp[(4) - (7)].d);  (yyval.v)[2] = (yyvsp[(6) - (7)].d);  (yyval.v)[3] = 0.0; (yyval.v)[4] = 1.0;
     ;}
     break;
 
-  case 412:
-#line 4632 "Gmsh.y"
+  case 403:
+#line 4547 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(List_T*));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].l)));
     ;}
     break;
 
-  case 413:
-#line 4637 "Gmsh.y"
+  case 404:
+#line 4552 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].l)));
     ;}
     break;
 
-  case 414:
-#line 4644 "Gmsh.y"
+  case 405:
+#line 4559 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].d)));
     ;}
     break;
 
-  case 415:
-#line 4649 "Gmsh.y"
+  case 406:
+#line 4564 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(1) - (1)].l);
     ;}
     break;
 
-  case 416:
-#line 4653 "Gmsh.y"
+  case 407:
+#line 4568 "Gmsh.y"
     {
       // creates an empty list
       (yyval.l) = List_Create(2, 1, sizeof(double));
     ;}
     break;
 
-  case 417:
-#line 4658 "Gmsh.y"
+  case 408:
+#line 4573 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (3)].l);
     ;}
     break;
 
-  case 418:
-#line 4662 "Gmsh.y"
+  case 409:
+#line 4577 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(3) - (4)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -10009,8 +9748,8 @@ yyreduce:
     ;}
     break;
 
-  case 419:
-#line 4670 "Gmsh.y"
+  case 410:
+#line 4585 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(4) - (5)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -10020,15 +9759,15 @@ yyreduce:
     ;}
     break;
 
-  case 420:
-#line 4681 "Gmsh.y"
+  case 411:
+#line 4596 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(1) - (1)].l);
     ;}
     break;
 
-  case 421:
-#line 4685 "Gmsh.y"
+  case 412:
+#line 4600 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (1)].c), "*") || !strcmp((yyvsp[(1) - (1)].c), "all"))
         (yyval.l) = 0;
@@ -10039,8 +9778,8 @@ yyreduce:
     ;}
     break;
 
-  case 422:
-#line 4697 "Gmsh.y"
+  case 413:
+#line 4612 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (2)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -10050,8 +9789,8 @@ yyreduce:
     ;}
     break;
 
-  case 423:
-#line 4705 "Gmsh.y"
+  case 414:
+#line 4620 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(3) - (3)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -10061,8 +9800,8 @@ yyreduce:
     ;}
     break;
 
-  case 424:
-#line 4713 "Gmsh.y"
+  case 415:
+#line 4628 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       for(double d = (yyvsp[(1) - (3)].d); ((yyvsp[(1) - (3)].d) < (yyvsp[(3) - (3)].d)) ? (d <= (yyvsp[(3) - (3)].d)) : (d >= (yyvsp[(3) - (3)].d));
@@ -10071,8 +9810,8 @@ yyreduce:
     ;}
     break;
 
-  case 425:
-#line 4720 "Gmsh.y"
+  case 416:
+#line 4635 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       if(!(yyvsp[(5) - (5)].d)){  //|| ($1 < $3 && $5 < 0) || ($1 > $3 && $5 > 0)
@@ -10084,8 +9823,8 @@ yyreduce:
    ;}
     break;
 
-  case 426:
-#line 4730 "Gmsh.y"
+  case 417:
+#line 4645 "Gmsh.y"
     {
       // Returns the coordinates of a point and fills a list with it.
       // This allows to ensure e.g. that relative point positions are
@@ -10107,36 +9846,36 @@ yyreduce:
     ;}
     break;
 
-  case 427:
-#line 4750 "Gmsh.y"
+  case 418:
+#line 4665 "Gmsh.y"
     {
       (yyval.l) = GetAllEntityNumbers(0);
     ;}
     break;
 
-  case 428:
-#line 4754 "Gmsh.y"
+  case 419:
+#line 4669 "Gmsh.y"
     {
       (yyval.l) = GetAllEntityNumbers(1);
     ;}
     break;
 
-  case 429:
-#line 4758 "Gmsh.y"
+  case 420:
+#line 4673 "Gmsh.y"
     {
       (yyval.l) = GetAllEntityNumbers(2);
     ;}
     break;
 
-  case 430:
-#line 4762 "Gmsh.y"
+  case 421:
+#line 4677 "Gmsh.y"
     {
       (yyval.l) = GetAllEntityNumbers(3);
     ;}
     break;
 
-  case 431:
-#line 4766 "Gmsh.y"
+  case 422:
+#line 4681 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
@@ -10167,8 +9906,8 @@ yyreduce:
     ;}
     break;
 
-  case 432:
-#line 4795 "Gmsh.y"
+  case 423:
+#line 4710 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
@@ -10199,8 +9938,8 @@ yyreduce:
     ;}
     break;
 
-  case 433:
-#line 4824 "Gmsh.y"
+  case 424:
+#line 4739 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
@@ -10231,8 +9970,8 @@ yyreduce:
     ;}
     break;
 
-  case 434:
-#line 4853 "Gmsh.y"
+  case 425:
+#line 4768 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
@@ -10263,8 +10002,8 @@ yyreduce:
     ;}
     break;
 
-  case 435:
-#line 4882 "Gmsh.y"
+  case 426:
+#line 4797 "Gmsh.y"
     {
       (yyval.l) = List_Create(List_Nbr((yyvsp[(1) - (1)].l)), 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(1) - (1)].l)); i++){
@@ -10276,8 +10015,8 @@ yyreduce:
     ;}
     break;
 
-  case 436:
-#line 4892 "Gmsh.y"
+  case 427:
+#line 4807 "Gmsh.y"
     {
       (yyval.l) = List_Create(List_Nbr((yyvsp[(1) - (1)].l)), 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(1) - (1)].l)); i++){
@@ -10289,23 +10028,8 @@ yyreduce:
     ;}
     break;
 
-  case 437:
-#line 4902 "Gmsh.y"
-    {
-      (yyval.l) = List_Create(2, 1, sizeof(double));
-      if(!gmsh_yysymbols.count((yyvsp[(1) - (3)].c)))
-	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (3)].c));
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (3)].c)]);
-	for(unsigned int i = 0; i < s.value.size(); i++)
-	  List_Add((yyval.l), &s.value[i]);
-      }
-      Free((yyvsp[(1) - (3)].c));
-    ;}
-    break;
-
-  case 438:
-#line 4915 "Gmsh.y"
+  case 428:
+#line 4817 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       if(!gmsh_yysymbols.count((yyvsp[(1) - (3)].c)))
@@ -10319,8 +10043,8 @@ yyreduce:
     ;}
     break;
 
-  case 439:
-#line 4927 "Gmsh.y"
+  case 429:
+#line 4829 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       if(!gmsh_yysymbols.count((yyvsp[(3) - (4)].c)))
@@ -10334,29 +10058,8 @@ yyreduce:
     ;}
     break;
 
-  case 440:
-#line 4939 "Gmsh.y"
-    {
-      (yyval.l) = List_Create(2, 1, sizeof(double));
-      if(!gmsh_yysymbols.count((yyvsp[(1) - (6)].c)))
-	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (6)].c));
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (6)].c)]);
-	for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
-	  int index = (int)(*(double*)List_Pointer_Fast((yyvsp[(4) - (6)].l), i));
-	  if((int)s.value.size() < index + 1)
-	    yymsg(0, "Uninitialized variable '%s[%d]'", (yyvsp[(1) - (6)].c), index);
-	  else
-	    List_Add((yyval.l), &s.value[index]);
-	}
-      }
-      Free((yyvsp[(1) - (6)].c));
-      List_Delete((yyvsp[(4) - (6)].l));
-    ;}
-    break;
-
-  case 441:
-#line 4958 "Gmsh.y"
+  case 430:
+#line 4841 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       if(!gmsh_yysymbols.count((yyvsp[(1) - (6)].c)))
@@ -10376,30 +10079,30 @@ yyreduce:
     ;}
     break;
 
-  case 442:
-#line 4979 "Gmsh.y"
+  case 431:
+#line 4862 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].d)));
     ;}
     break;
 
-  case 443:
-#line 4984 "Gmsh.y"
+  case 432:
+#line 4867 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(1) - (1)].l);
     ;}
     break;
 
-  case 444:
-#line 4988 "Gmsh.y"
+  case 433:
+#line 4871 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].d)));
     ;}
     break;
 
-  case 445:
-#line 4992 "Gmsh.y"
+  case 434:
+#line 4875 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (3)].l)); i++){
 	double d;
@@ -10410,22 +10113,22 @@ yyreduce:
     ;}
     break;
 
-  case 446:
-#line 5004 "Gmsh.y"
+  case 435:
+#line 4887 "Gmsh.y"
     {
       (yyval.u) = CTX::instance()->packColor((int)(yyvsp[(2) - (9)].d), (int)(yyvsp[(4) - (9)].d), (int)(yyvsp[(6) - (9)].d), (int)(yyvsp[(8) - (9)].d));
     ;}
     break;
 
-  case 447:
-#line 5008 "Gmsh.y"
+  case 436:
+#line 4891 "Gmsh.y"
     {
       (yyval.u) = CTX::instance()->packColor((int)(yyvsp[(2) - (7)].d), (int)(yyvsp[(4) - (7)].d), (int)(yyvsp[(6) - (7)].d), 255);
     ;}
     break;
 
-  case 448:
-#line 5020 "Gmsh.y"
+  case 437:
+#line 4903 "Gmsh.y"
     {
       int flag;
       (yyval.u) = GetColorForString(-1, (yyvsp[(1) - (1)].c), &flag);
@@ -10434,8 +10137,8 @@ yyreduce:
     ;}
     break;
 
-  case 449:
-#line 5027 "Gmsh.y"
+  case 438:
+#line 4910 "Gmsh.y"
     {
       unsigned int val = 0;
       ColorOption(GMSH_GET, (yyvsp[(1) - (5)].c), 0, (yyvsp[(5) - (5)].c), val);
@@ -10444,15 +10147,15 @@ yyreduce:
     ;}
     break;
 
-  case 450:
-#line 5037 "Gmsh.y"
+  case 439:
+#line 4920 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (3)].l);
     ;}
     break;
 
-  case 451:
-#line 5041 "Gmsh.y"
+  case 440:
+#line 4924 "Gmsh.y"
     {
       (yyval.l) = List_Create(256, 10, sizeof(unsigned int));
       GmshColorTable *ct = GetColorTable((int)(yyvsp[(3) - (6)].d));
@@ -10466,30 +10169,30 @@ yyreduce:
     ;}
     break;
 
-  case 452:
-#line 5056 "Gmsh.y"
+  case 441:
+#line 4939 "Gmsh.y"
     {
       (yyval.l) = List_Create(256, 10, sizeof(unsigned int));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].u)));
     ;}
     break;
 
-  case 453:
-#line 5061 "Gmsh.y"
+  case 442:
+#line 4944 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].u)));
     ;}
     break;
 
-  case 454:
-#line 5068 "Gmsh.y"
+  case 443:
+#line 4951 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(1) - (1)].c);
     ;}
     break;
 
-  case 455:
-#line 5072 "Gmsh.y"
+  case 444:
+#line 4955 "Gmsh.y"
     {
       if(!gmsh_yystringsymbols.count((yyvsp[(1) - (1)].c))){
 	yymsg(0, "Unknown string variable '%s'", (yyvsp[(1) - (1)].c));
@@ -10504,8 +10207,8 @@ yyreduce:
     ;}
     break;
 
-  case 456:
-#line 5085 "Gmsh.y"
+  case 445:
+#line 4968 "Gmsh.y"
     {
       std::string out;
       StringOption(GMSH_GET, (yyvsp[(1) - (3)].c), 0, (yyvsp[(3) - (3)].c), out);
@@ -10515,8 +10218,8 @@ yyreduce:
     ;}
     break;
 
-  case 457:
-#line 5093 "Gmsh.y"
+  case 446:
+#line 4976 "Gmsh.y"
     {
       std::string out;
       StringOption(GMSH_GET, (yyvsp[(1) - (6)].c), (int)(yyvsp[(3) - (6)].d), (yyvsp[(6) - (6)].c), out);
@@ -10526,15 +10229,15 @@ yyreduce:
     ;}
     break;
 
-  case 458:
-#line 5104 "Gmsh.y"
+  case 447:
+#line 4987 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(1) - (1)].c);
     ;}
     break;
 
-  case 459:
-#line 5108 "Gmsh.y"
+  case 448:
+#line 4991 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc(32 * sizeof(char));
       time_t now;
@@ -10544,8 +10247,17 @@ yyreduce:
     ;}
     break;
 
-  case 460:
-#line 5116 "Gmsh.y"
+  case 449:
+#line 4999 "Gmsh.y"
+    {
+      std::string action = Msg::GetGmshOnelabAction();
+      (yyval.c) = (char *)Malloc(action.size() + 1);
+      strcpy((yyval.c), action.c_str());
+    ;}
+    break;
+
+  case 450:
+#line 5005 "Gmsh.y"
     {
       const char *env = GetEnvironmentVar((yyvsp[(3) - (4)].c));
       if(!env) env = "";
@@ -10555,8 +10267,8 @@ yyreduce:
     ;}
     break;
 
-  case 461:
-#line 5124 "Gmsh.y"
+  case 451:
+#line 5013 "Gmsh.y"
     {
       std::string s = Msg::GetString((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].c));
       (yyval.c) = (char *)Malloc((s.size() + 1) * sizeof(char));
@@ -10566,19 +10278,8 @@ yyreduce:
     ;}
     break;
 
-  case 462:
-#line 5132 "Gmsh.y"
-    {
-      (yyval.c) = (char *)Malloc((strlen((yyvsp[(3) - (6)].c)) + strlen((yyvsp[(5) - (6)].c)) + 1) * sizeof(char));
-      strcpy((yyval.c), (yyvsp[(3) - (6)].c));
-      strcat((yyval.c), (yyvsp[(5) - (6)].c));
-      Free((yyvsp[(3) - (6)].c));
-      Free((yyvsp[(5) - (6)].c));
-    ;}
-    break;
-
-  case 463:
-#line 5141 "Gmsh.y"
+  case 452:
+#line 5021 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc((strlen((yyvsp[(3) - (6)].c)) + strlen((yyvsp[(5) - (6)].c)) + 1) * sizeof(char));
       strcpy((yyval.c), (yyvsp[(3) - (6)].c));
@@ -10588,8 +10289,8 @@ yyreduce:
     ;}
     break;
 
-  case 464:
-#line 5149 "Gmsh.y"
+  case 453:
+#line 5029 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc((strlen((yyvsp[(3) - (4)].c)) + 1) * sizeof(char));
       int i;
@@ -10605,8 +10306,8 @@ yyreduce:
     ;}
     break;
 
-  case 465:
-#line 5163 "Gmsh.y"
+  case 454:
+#line 5043 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc((strlen((yyvsp[(3) - (4)].c)) + 1) * sizeof(char));
       int i;
@@ -10622,8 +10323,8 @@ yyreduce:
     ;}
     break;
 
-  case 466:
-#line 5177 "Gmsh.y"
+  case 455:
+#line 5057 "Gmsh.y"
     {
       std::string input = (yyvsp[(3) - (8)].c);
       std::string substr_old = (yyvsp[(5) - (8)].c);
@@ -10637,27 +10338,8 @@ yyreduce:
     ;}
     break;
 
-  case 467:
-#line 5189 "Gmsh.y"
-    {
-      int size = 0;
-      for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++)
-        size += strlen(*(char**)List_Pointer((yyvsp[(3) - (4)].l), i)) + 1;
-      (yyval.c) = (char*)Malloc(size * sizeof(char));
-      (yyval.c)[0] = '\0';
-      for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
-        char *s;
-        List_Read((yyvsp[(3) - (4)].l), i, &s);
-        strcat((yyval.c), s);
-        Free(s);
-        if(i != List_Nbr((yyvsp[(3) - (4)].l)) - 1) strcat((yyval.c), "\n");
-      }
-      List_Delete((yyvsp[(3) - (4)].l));
-    ;}
-    break;
-
-  case 468:
-#line 5206 "Gmsh.y"
+  case 456:
+#line 5069 "Gmsh.y"
     {
       int size = 0;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++)
@@ -10675,22 +10357,15 @@ yyreduce:
     ;}
     break;
 
-  case 469:
-#line 5222 "Gmsh.y"
-    {
-      (yyval.c) = (yyvsp[(3) - (4)].c);
-    ;}
-    break;
-
-  case 470:
-#line 5227 "Gmsh.y"
+  case 457:
+#line 5085 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(3) - (4)].c);
     ;}
     break;
 
-  case 471:
-#line 5231 "Gmsh.y"
+  case 458:
+#line 5089 "Gmsh.y"
     {
       char tmpstring[5000];
       int i = PrintListOfDouble((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].l), tmpstring);
@@ -10711,43 +10386,37 @@ yyreduce:
     ;}
     break;
 
-  case 472:
-#line 5251 "Gmsh.y"
+  case 459:
+#line 5108 "Gmsh.y"
+    { floatOptions.clear(); charOptions.clear(); ;}
+    break;
+
+  case 460:
+#line 5110 "Gmsh.y"
     {
-      char tmpstring[5000];
-      int i = PrintListOfDouble((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].l), tmpstring);
-      if(i < 0){
-	yymsg(0, "Too few arguments in Sprintf");
-	(yyval.c) = (yyvsp[(3) - (6)].c);
-      }
-      else if(i > 0){
-	yymsg(0, "%d extra argument%s in Sprintf", i, (i > 1) ? "s" : "");
-	(yyval.c) = (yyvsp[(3) - (6)].c);
-      }
-      else{
-	(yyval.c) = (char*)Malloc((strlen(tmpstring) + 1) * sizeof(char));
-	strcpy((yyval.c), tmpstring);
-	Free((yyvsp[(3) - (6)].c));
-      }
-      List_Delete((yyvsp[(5) - (6)].l));
+      std::string val((yyvsp[(3) - (6)].c));
+      Msg::ExchangeOnelabParameter("", val, floatOptions, charOptions);
+      (yyval.c) = (char*)Malloc((val.size() + 1) * sizeof(char));
+      strcpy((yyval.c), val.c_str());
+      Free((yyvsp[(3) - (6)].c));
     ;}
     break;
 
-  case 473:
-#line 5273 "Gmsh.y"
+  case 461:
+#line 5121 "Gmsh.y"
     {
       (yyval.l) = List_Create(20,20,sizeof(char*));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].c)));
     ;}
     break;
 
-  case 474:
-#line 5278 "Gmsh.y"
+  case 462:
+#line 5126 "Gmsh.y"
     { List_Add((yyval.l), &((yyvsp[(3) - (3)].c))); ;}
     break;
 
-  case 475:
-#line 5284 "Gmsh.y"
+  case 463:
+#line 5132 "Gmsh.y"
     {
       char tmpstr[256];
       sprintf(tmpstr, "_%d", (int)(yyvsp[(4) - (5)].d));
@@ -10757,8 +10426,8 @@ yyreduce:
     ;}
     break;
 
-  case 476:
-#line 5293 "Gmsh.y"
+  case 464:
+#line 5141 "Gmsh.y"
     {
       char tmpstr[256];
       sprintf(tmpstr, "_%d", (int)(yyvsp[(4) - (5)].d));
@@ -10768,19 +10437,19 @@ yyreduce:
     ;}
     break;
 
-  case 477:
-#line 5306 "Gmsh.y"
+  case 465:
+#line 5154 "Gmsh.y"
     { (yyval.c) = (yyvsp[(1) - (1)].c); ;}
     break;
 
-  case 478:
-#line 5309 "Gmsh.y"
+  case 466:
+#line 5157 "Gmsh.y"
     { (yyval.c) = (yyvsp[(1) - (1)].c); ;}
     break;
 
 
 /* Line 1267 of yacc.c.  */
-#line 10784 "Gmsh.tab.cpp"
+#line 10453 "Gmsh.tab.cpp"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -10994,8 +10663,102 @@ yyreturn:
 }
 
 
-#line 5313 "Gmsh.y"
+#line 5161 "Gmsh.y"
+
+
+void assignVariable(const std::string &name, int index, int assignType,
+                    double value)
+{
+  if(!gmsh_yysymbols.count(name)){
+    if(!assignType){
+      gmsh_yysymbol &s(gmsh_yysymbols[name]);
+      s.list = true;
+      s.value.resize(index + 1, 0.);
+      s.value[index] = value;
+    }
+    else
+      yymsg(0, "Unknown variable '%s'", name.c_str());
+  }
+  else{
+    gmsh_yysymbol &s(gmsh_yysymbols[name]);
+    if(s.list){
+      if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
+      switch(assignType){
+      case 0 : s.value[index] = value; break;
+      case 1 : s.value[index] += value; break;
+      case 2 : s.value[index] -= value; break;
+      case 3 : s.value[index] *= value; break;
+      case 4 :
+        if(value) s.value[index] /= value;
+        else yymsg(0, "Division by zero in '%s[%d] /= %g'",
+                   name.c_str(), index, value);
+        break;
+      }
+    }
+    else
+      yymsg(0, "Variable '%s' is not a list", name.c_str());
+  }
+}
+
+void assignVariables(const std::string &name, List_T *indices, int assignType,
+                     List_T *values)
+{
+  if(List_Nbr(indices) != List_Nbr(values)){
+    yymsg(0, "Incompatible array dimensions in affectation");
+  }
+  else{
+    if(!gmsh_yysymbols.count(name)){
+      if(!assignType){
+        gmsh_yysymbol &s(gmsh_yysymbols[name]);
+        s.list = true;
+        for(int i = 0; i < List_Nbr(indices); i++){
+          int index = (int)(*(double*)List_Pointer(indices, i));
+          s.value.resize(index + 1, 0.);
+          s.value[index] = *(double*)List_Pointer(values, i);
+        }
+      }
+      else
+        yymsg(0, "Unknown variable '%s'", name.c_str());
+    }
+    else{
+      gmsh_yysymbol &s(gmsh_yysymbols[name]);
+      if(s.list){
+        for(int i = 0; i < List_Nbr(indices); i++){
+          int index = (int)(*(double*)List_Pointer(indices, i));
+          double d = *(double*)List_Pointer(values, i);
+          if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
+          switch(assignType){
+          case 0 : s.value[index] = d; break;
+          case 1 : s.value[index] += d; break;
+          case 2 : s.value[index] -= d; break;
+          case 3 : s.value[index] *= d; break;
+          case 4 :
+            if(d) s.value[index] /= d;
+            else yymsg(0, "Division by zero in '%s[%d] /= %g'", name.c_str(), index, d);
+            break;
+          }
+        }
+      }
+      else
+        yymsg(0, "Variable '%s' is not a list", name.c_str());
+    }
+  }
+}
 
+void incrementVariable(const std::string &name, int index, double value)
+{
+  if(!gmsh_yysymbols.count(name))
+    yymsg(0, "Unknown variable '%s'", name.c_str());
+  else{
+    gmsh_yysymbol &s(gmsh_yysymbols[name]);
+    if(s.list){
+      if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
+      s.value[index] += value;
+    }
+    else
+      yymsg(0, "Variable '%s' is not a list", name.c_str());
+  }
+}
 
 int PrintListOfDouble(char *format, List_T *list, char *buffer)
 {
@@ -11047,6 +10810,42 @@ int PrintListOfDouble(char *format, List_T *list, char *buffer)
   return 0;
 }
 
+void PrintParserSymbols(bool help, std::vector<std::string> &vec)
+{
+  if(help){
+    vec.push_back("//");
+    vec.push_back("// Numbers");
+    vec.push_back("//");
+  }
+  for(std::map<std::string, gmsh_yysymbol>::iterator it = gmsh_yysymbols.begin();
+      it != gmsh_yysymbols.end(); it++){
+    gmsh_yysymbol s(it->second);
+    std::ostringstream sstream;
+    sstream << it->first;
+    if(s.list){
+      sstream << "[] = {";
+      for(unsigned int i = 0; i < s.value.size(); i++){
+        if(i) sstream << ", ";
+        sstream << s.value[i];
+      }
+      sstream << "}";
+    }
+    else
+      sstream << " = " << s.value[0];
+    sstream << ";";
+    vec.push_back(sstream.str());
+  }
+  if(help){
+    vec.push_back("//");
+    vec.push_back("// Strings");
+    vec.push_back("//");
+  }
+  for(std::map<std::string, std::string>::iterator it = gmsh_yystringsymbols.begin();
+      it != gmsh_yystringsymbols.end(); it++){
+    vec.push_back(it->first + " = \"" + it->second + "\";");
+  }
+}
+
 fullMatrix<double> ListOfListOfDouble2Matrix(List_T *list)
 {
   int M = List_Nbr(list);
diff --git a/Parser/Gmsh.tab.hpp b/Parser/Gmsh.tab.hpp
index 7fea35a..4d0de63 100644
--- a/Parser/Gmsh.tab.hpp
+++ b/Parser/Gmsh.tab.hpp
@@ -88,115 +88,121 @@
      tDraw = 304,
      tSetChanged = 305,
      tToday = 306,
-     tCpu = 307,
-     tMemory = 308,
-     tSyncModel = 309,
-     tCreateTopology = 310,
-     tCreateTopologyNoHoles = 311,
-     tDistanceFunction = 312,
-     tDefineConstant = 313,
-     tUndefineConstant = 314,
-     tPoint = 315,
-     tCircle = 316,
-     tEllipse = 317,
-     tLine = 318,
-     tSphere = 319,
-     tPolarSphere = 320,
-     tSurface = 321,
-     tSpline = 322,
-     tVolume = 323,
-     tCharacteristic = 324,
-     tLength = 325,
-     tParametric = 326,
-     tElliptic = 327,
-     tRefineMesh = 328,
-     tAdaptMesh = 329,
-     tRelocateMesh = 330,
-     tPlane = 331,
-     tRuled = 332,
-     tTransfinite = 333,
-     tComplex = 334,
-     tPhysical = 335,
-     tCompound = 336,
-     tPeriodic = 337,
-     tUsing = 338,
-     tPlugin = 339,
-     tDegenerated = 340,
-     tRecursive = 341,
-     tRotate = 342,
-     tTranslate = 343,
-     tSymmetry = 344,
-     tDilate = 345,
-     tExtrude = 346,
-     tLevelset = 347,
-     tRecombine = 348,
-     tSmoother = 349,
-     tSplit = 350,
-     tDelete = 351,
-     tCoherence = 352,
-     tIntersect = 353,
-     tMeshAlgorithm = 354,
-     tReverse = 355,
-     tLayers = 356,
-     tScaleLast = 357,
-     tHole = 358,
-     tAlias = 359,
-     tAliasWithOptions = 360,
-     tCopyOptions = 361,
-     tQuadTriAddVerts = 362,
-     tQuadTriNoNewVerts = 363,
-     tQuadTriSngl = 364,
-     tQuadTriDbl = 365,
-     tRecombLaterals = 366,
-     tTransfQuadTri = 367,
-     tText2D = 368,
-     tText3D = 369,
-     tInterpolationScheme = 370,
-     tTime = 371,
-     tCombine = 372,
-     tBSpline = 373,
-     tBezier = 374,
-     tNurbs = 375,
-     tNurbsOrder = 376,
-     tNurbsKnots = 377,
-     tColor = 378,
-     tColorTable = 379,
-     tFor = 380,
-     tIn = 381,
-     tEndFor = 382,
-     tIf = 383,
-     tEndIf = 384,
-     tExit = 385,
-     tAbort = 386,
-     tField = 387,
-     tReturn = 388,
-     tCall = 389,
-     tFunction = 390,
-     tShow = 391,
-     tHide = 392,
-     tGetValue = 393,
-     tGetEnv = 394,
-     tGetString = 395,
-     tHomology = 396,
-     tCohomology = 397,
-     tBetti = 398,
-     tSetOrder = 399,
-     tGMSH_MAJOR_VERSION = 400,
-     tGMSH_MINOR_VERSION = 401,
-     tGMSH_PATCH_VERSION = 402,
-     tAFFECTDIVIDE = 403,
-     tAFFECTTIMES = 404,
-     tAFFECTMINUS = 405,
-     tAFFECTPLUS = 406,
-     tOR = 407,
-     tAND = 408,
-     tNOTEQUAL = 409,
-     tEQUAL = 410,
-     tGREATEROREQUAL = 411,
-     tLESSOREQUAL = 412,
-     UNARYPREC = 413,
-     tMINUSMINUS = 414,
-     tPLUSPLUS = 415
+     tOnelabAction = 307,
+     tSyncModel = 308,
+     tCpu = 309,
+     tMemory = 310,
+     tTotalMemory = 311,
+     tCreateTopology = 312,
+     tCreateTopologyNoHoles = 313,
+     tDistanceFunction = 314,
+     tDefineConstant = 315,
+     tUndefineConstant = 316,
+     tDefineNumber = 317,
+     tDefineString = 318,
+     tPoint = 319,
+     tCircle = 320,
+     tEllipse = 321,
+     tLine = 322,
+     tSphere = 323,
+     tPolarSphere = 324,
+     tSurface = 325,
+     tSpline = 326,
+     tVolume = 327,
+     tCharacteristic = 328,
+     tLength = 329,
+     tParametric = 330,
+     tElliptic = 331,
+     tRefineMesh = 332,
+     tAdaptMesh = 333,
+     tRelocateMesh = 334,
+     tPlane = 335,
+     tRuled = 336,
+     tTransfinite = 337,
+     tComplex = 338,
+     tPhysical = 339,
+     tCompound = 340,
+     tPeriodic = 341,
+     tUsing = 342,
+     tPlugin = 343,
+     tDegenerated = 344,
+     tRecursive = 345,
+     tRotate = 346,
+     tTranslate = 347,
+     tSymmetry = 348,
+     tDilate = 349,
+     tExtrude = 350,
+     tLevelset = 351,
+     tRecombine = 352,
+     tSmoother = 353,
+     tSplit = 354,
+     tDelete = 355,
+     tCoherence = 356,
+     tIntersect = 357,
+     tMeshAlgorithm = 358,
+     tReverse = 359,
+     tLayers = 360,
+     tScaleLast = 361,
+     tHole = 362,
+     tAlias = 363,
+     tAliasWithOptions = 364,
+     tCopyOptions = 365,
+     tQuadTriAddVerts = 366,
+     tQuadTriNoNewVerts = 367,
+     tQuadTriSngl = 368,
+     tQuadTriDbl = 369,
+     tRecombLaterals = 370,
+     tTransfQuadTri = 371,
+     tText2D = 372,
+     tText3D = 373,
+     tInterpolationScheme = 374,
+     tTime = 375,
+     tCombine = 376,
+     tBSpline = 377,
+     tBezier = 378,
+     tNurbs = 379,
+     tNurbsOrder = 380,
+     tNurbsKnots = 381,
+     tColor = 382,
+     tColorTable = 383,
+     tFor = 384,
+     tIn = 385,
+     tEndFor = 386,
+     tIf = 387,
+     tEndIf = 388,
+     tExit = 389,
+     tAbort = 390,
+     tField = 391,
+     tReturn = 392,
+     tCall = 393,
+     tFunction = 394,
+     tShow = 395,
+     tHide = 396,
+     tGetValue = 397,
+     tGetEnv = 398,
+     tGetString = 399,
+     tHomology = 400,
+     tCohomology = 401,
+     tBetti = 402,
+     tSetOrder = 403,
+     tExists = 404,
+     tFileExists = 405,
+     tGMSH_MAJOR_VERSION = 406,
+     tGMSH_MINOR_VERSION = 407,
+     tGMSH_PATCH_VERSION = 408,
+     tAFFECTDIVIDE = 409,
+     tAFFECTTIMES = 410,
+     tAFFECTMINUS = 411,
+     tAFFECTPLUS = 412,
+     tOR = 413,
+     tAND = 414,
+     tNOTEQUAL = 415,
+     tEQUAL = 416,
+     tGREATEROREQUAL = 417,
+     tLESSOREQUAL = 418,
+     UNARYPREC = 419,
+     tMINUSMINUS = 420,
+     tPLUSPLUS = 421
    };
 #endif
 /* Tokens.  */
@@ -249,122 +255,128 @@
 #define tDraw 304
 #define tSetChanged 305
 #define tToday 306
-#define tCpu 307
-#define tMemory 308
-#define tSyncModel 309
-#define tCreateTopology 310
-#define tCreateTopologyNoHoles 311
-#define tDistanceFunction 312
-#define tDefineConstant 313
-#define tUndefineConstant 314
-#define tPoint 315
-#define tCircle 316
-#define tEllipse 317
-#define tLine 318
-#define tSphere 319
-#define tPolarSphere 320
-#define tSurface 321
-#define tSpline 322
-#define tVolume 323
-#define tCharacteristic 324
-#define tLength 325
-#define tParametric 326
-#define tElliptic 327
-#define tRefineMesh 328
-#define tAdaptMesh 329
-#define tRelocateMesh 330
-#define tPlane 331
-#define tRuled 332
-#define tTransfinite 333
-#define tComplex 334
-#define tPhysical 335
-#define tCompound 336
-#define tPeriodic 337
-#define tUsing 338
-#define tPlugin 339
-#define tDegenerated 340
-#define tRecursive 341
-#define tRotate 342
-#define tTranslate 343
-#define tSymmetry 344
-#define tDilate 345
-#define tExtrude 346
-#define tLevelset 347
-#define tRecombine 348
-#define tSmoother 349
-#define tSplit 350
-#define tDelete 351
-#define tCoherence 352
-#define tIntersect 353
-#define tMeshAlgorithm 354
-#define tReverse 355
-#define tLayers 356
-#define tScaleLast 357
-#define tHole 358
-#define tAlias 359
-#define tAliasWithOptions 360
-#define tCopyOptions 361
-#define tQuadTriAddVerts 362
-#define tQuadTriNoNewVerts 363
-#define tQuadTriSngl 364
-#define tQuadTriDbl 365
-#define tRecombLaterals 366
-#define tTransfQuadTri 367
-#define tText2D 368
-#define tText3D 369
-#define tInterpolationScheme 370
-#define tTime 371
-#define tCombine 372
-#define tBSpline 373
-#define tBezier 374
-#define tNurbs 375
-#define tNurbsOrder 376
-#define tNurbsKnots 377
-#define tColor 378
-#define tColorTable 379
-#define tFor 380
-#define tIn 381
-#define tEndFor 382
-#define tIf 383
-#define tEndIf 384
-#define tExit 385
-#define tAbort 386
-#define tField 387
-#define tReturn 388
-#define tCall 389
-#define tFunction 390
-#define tShow 391
-#define tHide 392
-#define tGetValue 393
-#define tGetEnv 394
-#define tGetString 395
-#define tHomology 396
-#define tCohomology 397
-#define tBetti 398
-#define tSetOrder 399
-#define tGMSH_MAJOR_VERSION 400
-#define tGMSH_MINOR_VERSION 401
-#define tGMSH_PATCH_VERSION 402
-#define tAFFECTDIVIDE 403
-#define tAFFECTTIMES 404
-#define tAFFECTMINUS 405
-#define tAFFECTPLUS 406
-#define tOR 407
-#define tAND 408
-#define tNOTEQUAL 409
-#define tEQUAL 410
-#define tGREATEROREQUAL 411
-#define tLESSOREQUAL 412
-#define UNARYPREC 413
-#define tMINUSMINUS 414
-#define tPLUSPLUS 415
+#define tOnelabAction 307
+#define tSyncModel 308
+#define tCpu 309
+#define tMemory 310
+#define tTotalMemory 311
+#define tCreateTopology 312
+#define tCreateTopologyNoHoles 313
+#define tDistanceFunction 314
+#define tDefineConstant 315
+#define tUndefineConstant 316
+#define tDefineNumber 317
+#define tDefineString 318
+#define tPoint 319
+#define tCircle 320
+#define tEllipse 321
+#define tLine 322
+#define tSphere 323
+#define tPolarSphere 324
+#define tSurface 325
+#define tSpline 326
+#define tVolume 327
+#define tCharacteristic 328
+#define tLength 329
+#define tParametric 330
+#define tElliptic 331
+#define tRefineMesh 332
+#define tAdaptMesh 333
+#define tRelocateMesh 334
+#define tPlane 335
+#define tRuled 336
+#define tTransfinite 337
+#define tComplex 338
+#define tPhysical 339
+#define tCompound 340
+#define tPeriodic 341
+#define tUsing 342
+#define tPlugin 343
+#define tDegenerated 344
+#define tRecursive 345
+#define tRotate 346
+#define tTranslate 347
+#define tSymmetry 348
+#define tDilate 349
+#define tExtrude 350
+#define tLevelset 351
+#define tRecombine 352
+#define tSmoother 353
+#define tSplit 354
+#define tDelete 355
+#define tCoherence 356
+#define tIntersect 357
+#define tMeshAlgorithm 358
+#define tReverse 359
+#define tLayers 360
+#define tScaleLast 361
+#define tHole 362
+#define tAlias 363
+#define tAliasWithOptions 364
+#define tCopyOptions 365
+#define tQuadTriAddVerts 366
+#define tQuadTriNoNewVerts 367
+#define tQuadTriSngl 368
+#define tQuadTriDbl 369
+#define tRecombLaterals 370
+#define tTransfQuadTri 371
+#define tText2D 372
+#define tText3D 373
+#define tInterpolationScheme 374
+#define tTime 375
+#define tCombine 376
+#define tBSpline 377
+#define tBezier 378
+#define tNurbs 379
+#define tNurbsOrder 380
+#define tNurbsKnots 381
+#define tColor 382
+#define tColorTable 383
+#define tFor 384
+#define tIn 385
+#define tEndFor 386
+#define tIf 387
+#define tEndIf 388
+#define tExit 389
+#define tAbort 390
+#define tField 391
+#define tReturn 392
+#define tCall 393
+#define tFunction 394
+#define tShow 395
+#define tHide 396
+#define tGetValue 397
+#define tGetEnv 398
+#define tGetString 399
+#define tHomology 400
+#define tCohomology 401
+#define tBetti 402
+#define tSetOrder 403
+#define tExists 404
+#define tFileExists 405
+#define tGMSH_MAJOR_VERSION 406
+#define tGMSH_MINOR_VERSION 407
+#define tGMSH_PATCH_VERSION 408
+#define tAFFECTDIVIDE 409
+#define tAFFECTTIMES 410
+#define tAFFECTMINUS 411
+#define tAFFECTPLUS 412
+#define tOR 413
+#define tAND 414
+#define tNOTEQUAL 415
+#define tEQUAL 416
+#define tGREATEROREQUAL 417
+#define tLESSOREQUAL 418
+#define UNARYPREC 419
+#define tMINUSMINUS 420
+#define tPLUSPLUS 421
 
 
 
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 93 "Gmsh.y"
+#line 100 "Gmsh.y"
 {
   char *c;
   int i;
@@ -375,7 +387,7 @@ typedef union YYSTYPE
   List_T *l;
 }
 /* Line 1529 of yacc.c.  */
-#line 379 "Gmsh.tab.hpp"
+#line 391 "Gmsh.tab.hpp"
 	YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
diff --git a/Parser/Gmsh.y b/Parser/Gmsh.y
index 6a91aa5..e557d10 100644
--- a/Parser/Gmsh.y
+++ b/Parser/Gmsh.y
@@ -4,6 +4,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
+#include <sstream>
 #include <string.h>
 #include <stdarg.h>
 #include <time.h>
@@ -70,7 +71,7 @@ static int curPhysDim = 0;
 static gmshSurface *myGmshSurface = 0;
 #define MAX_RECUR_LOOPS 100
 static int ImbricatedLoop = 0;
-static fpos_t yyposImbricatedLoopsTab[MAX_RECUR_LOOPS];
+static gmshfpos_t yyposImbricatedLoopsTab[MAX_RECUR_LOOPS];
 static int yylinenoImbricatedLoopsTab[MAX_RECUR_LOOPS];
 static double LoopControlVariablesTab[MAX_RECUR_LOOPS][3];
 static const char *LoopControlVariablesNameTab[MAX_RECUR_LOOPS];
@@ -80,7 +81,13 @@ static std::map<std::string, std::vector<std::string> > charOptions;
 void yyerror(const char *s);
 void yymsg(int level, const char *fmt, ...);
 void skip_until(const char *skip, const char *until);
+void assignVariable(const std::string &name, int index, int assignType,
+                    double value);
+void assignVariables(const std::string &name, List_T *indices, int assignType,
+                     List_T *values);
+void incrementVariable(const std::string &name, int index, double value);
 int PrintListOfDouble(char *format, List_T *list, char *buffer);
+void PrintParserSymbols(std::vector<std::string> &vec);
 fullMatrix<double> ListOfListOfDouble2Matrix(List_T *list);
 
 struct doubleXstring{
@@ -110,9 +117,11 @@ struct doubleXstring{
 %token tPrintf tError tStr tSprintf tStrCat tStrPrefix tStrRelative tStrReplace
 %token tStrFind tStrCmp
 %token tTextAttributes
-%token tBoundingBox tDraw tSetChanged tToday tCpu tMemory tSyncModel
+%token tBoundingBox tDraw tSetChanged tToday tOnelabAction tSyncModel
+%token tCpu tMemory tTotalMemory
 %token tCreateTopology tCreateTopologyNoHoles
 %token tDistanceFunction tDefineConstant tUndefineConstant
+%token tDefineNumber tDefineString
 %token tPoint tCircle tEllipse tLine tSphere tPolarSphere tSurface tSpline tVolume
 %token tCharacteristic tLength tParametric tElliptic tRefineMesh tAdaptMesh
 %token tRelocateMesh
@@ -128,7 +137,7 @@ struct doubleXstring{
 %token tBSpline tBezier tNurbs tNurbsOrder tNurbsKnots
 %token tColor tColorTable tFor tIn tEndFor tIf tEndIf tExit tAbort
 %token tField tReturn tCall tFunction tShow tHide tGetValue tGetEnv tGetString
-%token tHomology tCohomology tBetti tSetOrder
+%token tHomology tCohomology tBetti tSetOrder tExists tFileExists
 %token tGMSH_MAJOR_VERSION tGMSH_MINOR_VERSION tGMSH_PATCH_VERSION
 
 %type <d> FExpr FExpr_Single
@@ -137,6 +146,7 @@ struct doubleXstring{
 %type <i> TransfiniteArrangement RecombineAngle
 %type <u> ColorExpr
 %type <c> StringExpr StringExprVar SendToFile HomologyCommand
+%type <c> LP RP
 %type <c> StringIndex String__Index
 %type <l> RecursiveListOfStringExprVar
 %type <l> FExpr_Multi ListOfDouble ListOfDoubleOrAll RecursiveListOfDouble
@@ -631,13 +641,18 @@ NumericIncrement :
   | tMINUSMINUS    { $$ = -1; }
 ;
 
+// these are for either compatibility with getdp syntax (square brackets instead
+// of parentheses)
+
+LP : '(' { $$ = (char*)"("; } | '[' { $$ = (char*)"["; } ;
+RP : ')' { $$ = (char*)")"; } | ']' { $$ = (char*)"]"; } ;
+
 Affectation :
 
   // Variables
-    tDefineConstant '[' DefineConstants ']' tEND
 
+    tDefineConstant '[' DefineConstants ']' tEND
   | tUndefineConstant '[' UndefineConstants ']' tEND
-
   | String__Index NumericAffectation ListOfDouble tEND
     {
       if(!gmsh_yysymbols.count($1) && $2 && List_Nbr($3) == 1){
@@ -698,7 +713,6 @@ Affectation :
       Free($1);
       List_Delete($3);
     }
-
   // This variant can be used to force the variable type to "list"
   | tSTRING '[' ']' NumericAffectation ListOfDouble tEND
     {
@@ -729,171 +743,35 @@ Affectation :
       Free($1);
       List_Delete($5);
     }
-
   | tSTRING '[' FExpr ']' NumericAffectation FExpr tEND
     {
-      int index = (int)$3;
-      if(!gmsh_yysymbols.count($1)){
-	if(!$5){
-          gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-          s.list = true;
-	  s.value.resize(index + 1, 0.);
-	  s.value[index] = $6;
-	}
-	else
-	  yymsg(0, "Unknown variable '%s'", $1);
-      }
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-        if(s.list){
-          if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-          switch($5){
-          case 0 : s.value[index] = $6; break;
-          case 1 : s.value[index] += $6; break;
-          case 2 : s.value[index] -= $6; break;
-          case 3 : s.value[index] *= $6; break;
-          case 4 :
-            if($6) s.value[index] /= $6;
-            else yymsg(0, "Division by zero in '%s[%d] /= %g'", $1, index, $6);
-            break;
-          }
-        }
-        else
-          yymsg(0, "Variable '%s' is not a list", $1);
-      }
+      assignVariable($1, (int)$3, $5, $6);
       Free($1);
     }
-
-  // for compatibility with GetDP
   | tSTRING '(' FExpr ')' NumericAffectation FExpr tEND
     {
-      int index = (int)$3;
-      if(!gmsh_yysymbols.count($1)){
-	if(!$5){
-          gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-          s.list = true;
-	  s.value.resize(index + 1, 0.);
-	  s.value[index] = $6;
-	}
-	else
-	  yymsg(0, "Unknown variable '%s'", $1);
-      }
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-        if(s.list){
-          if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-          switch($5){
-          case 0 : s.value[index] = $6; break;
-          case 1 : s.value[index] += $6; break;
-          case 2 : s.value[index] -= $6; break;
-          case 3 : s.value[index] *= $6; break;
-          case 4 :
-            if($6) s.value[index] /= $6;
-            else yymsg(0, "Division by zero in '%s[%d] /= %g'", $1, index, $6);
-            break;
-          }
-        }
-        else
-          yymsg(0, "Variable '%s' is not a list", $1);
-      }
+      assignVariable($1, (int)$3, $5, $6);
       Free($1);
     }
-
-  | tSTRING '[' '{' RecursiveListOfDouble '}' ']' NumericAffectation ListOfDouble tEND
+  | StringIndex '[' FExpr ']' NumericAffectation FExpr tEND
     {
-      if(List_Nbr($4) != List_Nbr($8)){
-	yymsg(0, "Incompatible array dimensions in affectation");
-      }
-      else{
-	if(!gmsh_yysymbols.count($1)){
-	  if(!$7){
-            gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-            s.list = true;
-	    for(int i = 0; i < List_Nbr($4); i++){
-	      int index = (int)(*(double*)List_Pointer($4, i));
-	      s.value.resize(index + 1, 0.);
-	      s.value[index] = *(double*)List_Pointer($8, i);
-	    }
-	  }
-	  else
-	    yymsg(0, "Unknown variable '%s'", $1);
-	}
-	else{
-          gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-          if(s.list){
-            for(int i = 0; i < List_Nbr($4); i++){
-              int index = (int)(*(double*)List_Pointer($4, i));
-              double d = *(double*)List_Pointer($8, i);
-              if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-              switch($7){
-              case 0 : s.value[index] = d; break;
-              case 1 : s.value[index] += d; break;
-              case 2 : s.value[index] -= d; break;
-              case 3 : s.value[index] *= d; break;
-              case 4 :
-                if($8) s.value[index] /= d;
-                else yymsg(0, "Division by zero in '%s[%d] /= %g'", $1, index, d);
-                break;
-              }
-            }
-          }
-          else
-            yymsg(0, "Variable '%s' is not a list", $1);
-        }
-      }
+      assignVariable($1, (int)$3, $5, $6);
+      Free($1);
+    }
+  | tSTRING LP '{' RecursiveListOfDouble '}' RP NumericAffectation ListOfDouble tEND
+    {
+      assignVariables($1, $4, $7, $8);
       Free($1);
       List_Delete($4);
       List_Delete($8);
     }
-
-  // for compatibility with GetDP
-  | tSTRING '(' '{' RecursiveListOfDouble '}' ')' NumericAffectation ListOfDouble tEND
+  | StringIndex '(' '{' RecursiveListOfDouble '}' ')' NumericAffectation ListOfDouble tEND
     {
-      if(List_Nbr($4) != List_Nbr($8)){
-	yymsg(0, "Incompatible array dimensions in affectation");
-      }
-      else{
-	if(!gmsh_yysymbols.count($1)){
-	  if(!$7){
-            gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-            s.list = true;
-	    for(int i = 0; i < List_Nbr($4); i++){
-	      int index = (int)(*(double*)List_Pointer($4, i));
-	      s.value.resize(index + 1, 0.);
-	      s.value[index] = *(double*)List_Pointer($8, i);
-	    }
-	  }
-	  else
-	    yymsg(0, "Unknown variable '%s'", $1);
-	}
-	else{
-          gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-          if(s.list){
-            for(int i = 0; i < List_Nbr($4); i++){
-              int index = (int)(*(double*)List_Pointer($4, i));
-              double d = *(double*)List_Pointer($8, i);
-              if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-              switch($7){
-              case 0 : s.value[index] = d; break;
-              case 1 : s.value[index] += d; break;
-              case 2 : s.value[index] -= d; break;
-              case 3 : s.value[index] *= d; break;
-              case 4 :
-                if($8) s.value[index] /= d;
-                else yymsg(0, "Division by zero in '%s[%d] /= %g'", $1, index, d);
-                break;
-              }
-            }
-          }
-          else
-            yymsg(0, "Variable '%s' is not a list", $1);
-        }
-      }
+      assignVariables($1, $4, $7, $8);
       Free($1);
       List_Delete($4);
       List_Delete($8);
     }
-
   | String__Index NumericIncrement tEND
     {
       if(!gmsh_yysymbols.count($1))
@@ -911,18 +789,12 @@ Affectation :
     }
   | tSTRING '[' FExpr ']' NumericIncrement tEND
     {
-      if(!gmsh_yysymbols.count($1))
-	yymsg(0, "Unknown variable '%s'", $1);
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-        if(s.list){
-          int index = (int)$3;
-          if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
-          s.value[index] += $5;
-        }
-        else
-          yymsg(0, "Variable '%s' is not a list", $1);
-      }
+      incrementVariable($1, $3, $5);
+      Free($1);
+    }
+  | StringIndex '[' FExpr ']' NumericIncrement tEND
+    {
+      incrementVariable($1, $3, $5);
       Free($1);
     }
   | String__Index tAFFECT StringExpr tEND
@@ -1623,7 +1495,8 @@ Shape :
       $$.Type = MSH_SEGM_BEZIER;
       $$.Num = num;
     }
-  | tNurbs  '(' FExpr ')' tAFFECT ListOfDouble tNurbsKnots ListOfDouble tNurbsOrder FExpr tEND
+  | tNurbs  '(' FExpr ')' tAFFECT ListOfDouble tNurbsKnots ListOfDouble
+      tNurbsOrder FExpr tEND
     {
       int num = (int)$3;
       if(List_Nbr($6) + (int)$10 + 1 != List_Nbr($8)){
@@ -2604,7 +2477,7 @@ Delete :
         ClearProject();
       }
       else if(!strcmp($2, "Model")){
-	GModel::current()->destroy();
+	GModel::current()->destroy(true); // destroy, but keep name/filename
 	GModel::current()->getGEOInternals()->destroy();
       }
       else if(!strcmp($2, "Physicals")){
@@ -2754,14 +2627,22 @@ Command :
         std::string tmp = FixRelativePath(gmsh_yyname, $2);
 	MergeFile(tmp, true);
       }
-      else if(!strcmp($1, "NonBlockingSystemCall"))
+      else if(!strcmp($1, "NonBlockingSystemCall")){
 	SystemCall($2);
-      else if(!strcmp($1, "System") || !strcmp($1, "SystemCall"))
+      }
+      else if(!strcmp($1, "System") || !strcmp($1, "SystemCall")){
 	SystemCall($2, true);
-      else if(!strcmp($1, "SetName"))
+      }
+      else if(!strcmp($1, "SetName")){
 	GModel::current()->setName($2);
-      else
+      }
+      else if(!strcmp($1, "CreateDir")){
+        std::string tmp = FixRelativePath(gmsh_yyname, $2);
+	CreateSingleDir(tmp);
+      }
+      else{
 	yymsg(0, "Unknown command '%s'", $1);
+      }
       Free($1); Free($2);
     }
   | tSTRING tSTRING '[' FExpr ']' StringExprVar tEND
@@ -2979,7 +2860,7 @@ Loop :
       LoopControlVariablesTab[ImbricatedLoop][1] = $5;
       LoopControlVariablesTab[ImbricatedLoop][2] = 1.0;
       LoopControlVariablesNameTab[ImbricatedLoop] = NULL;
-      fgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
+      gmshgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
       yylinenoImbricatedLoopsTab[ImbricatedLoop] = gmsh_yylineno;
       if($3 > $5)
 	skip_until("For", "EndFor");
@@ -2996,7 +2877,7 @@ Loop :
       LoopControlVariablesTab[ImbricatedLoop][1] = $5;
       LoopControlVariablesTab[ImbricatedLoop][2] = $7;
       LoopControlVariablesNameTab[ImbricatedLoop] = NULL;
-      fgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
+      gmshgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
       yylinenoImbricatedLoopsTab[ImbricatedLoop] = gmsh_yylineno;
       if(($7 > 0. && $3 > $5) || ($7 < 0. && $3 < $5))
 	skip_until("For", "EndFor");
@@ -3017,7 +2898,7 @@ Loop :
       s.list = false;
       s.value.resize(1);
       s.value[0] = $5;
-      fgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
+      gmshgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
       yylinenoImbricatedLoopsTab[ImbricatedLoop] = gmsh_yylineno;
       if($5 > $7)
 	skip_until("For", "EndFor");
@@ -3038,7 +2919,7 @@ Loop :
       s.list = false;
       s.value.resize(1);
       s.value[0] = $5;
-      fgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
+      gmshgetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop]);
       yylinenoImbricatedLoopsTab[ImbricatedLoop] = gmsh_yylineno;
       if(($9 > 0. && $5 > $7) || ($9 < 0. && $5 < $7))
 	skip_until("For", "EndFor");
@@ -3077,7 +2958,7 @@ Loop :
 	double x0 = LoopControlVariablesTab[ImbricatedLoop - 1][0];
 	double x1 = LoopControlVariablesTab[ImbricatedLoop - 1][1];
         if((step > 0. && x0 <= x1) || (step < 0. && x0 >= x1)){
-	  fsetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop - 1]);
+	  gmshsetpos(gmsh_yyin, &yyposImbricatedLoopsTab[ImbricatedLoop - 1]);
 	  gmsh_yylineno = yylinenoImbricatedLoopsTab[ImbricatedLoop - 1];
 	}
 	else
@@ -3446,12 +3327,11 @@ ExtrudeParameter :
       List_Delete($5);
       List_Delete($7);
     }
-//Added by Trevor Strickler 07/07/2013
+  //Added by Trevor Strickler 07/07/2013
   | tScaleLast tEND
     {
       extr.mesh.ScaleLast = true;
     }
-
   | tRecombine tEND
     {
       extr.mesh.Recombine = true;
@@ -3466,11 +3346,15 @@ ExtrudeParameter :
     }
   | tQuadTriDbl tEND
     {
-      yymsg(0, "Method 'QuadTriDbl' deprecated. Use 'QuadTriAddVerts' instead, which has no requirement for the number of extrusion layers and meshes with body-centered vertices.");
+      yymsg(0, "Method 'QuadTriDbl' deprecated. Use 'QuadTriAddVerts' instead, "
+            "which has no requirement for the number of extrusion layers and meshes "
+            "with body-centered vertices.");
     }
   | tQuadTriDbl tRecombLaterals tEND
     {
-      yymsg(0, "Method 'QuadTriDbl' deprecated. Use 'QuadTriAddVerts' instead, which has no requirement for the number of extrusion layers and meshes with body-centered vertices.");
+      yymsg(0, "Method 'QuadTriDbl' deprecated. Use 'QuadTriAddVerts' instead, "
+            "which has no requirement for the number of extrusion layers and meshes "
+            "with body-centered vertices.");
     }
   | tQuadTriAddVerts tEND
     {
@@ -4332,14 +4216,14 @@ Homology :
 //  G E N E R A L
 
 FExpr :
-    FExpr_Single                     { $$ = $1;           }
-  | '(' FExpr ')'                    { $$ = $2;           }
-  | '-' FExpr %prec UNARYPREC        { $$ = -$2;          }
-  | '+' FExpr %prec UNARYPREC        { $$ = $2;           }
-  | '!' FExpr                        { $$ = !$2;          }
-  | FExpr '-' FExpr                  { $$ = $1 - $3;      }
-  | FExpr '+' FExpr                  { $$ = $1 + $3;      }
-  | FExpr '*' FExpr                  { $$ = $1 * $3;      }
+    FExpr_Single                  { $$ = $1;           }
+  | '(' FExpr ')'                 { $$ = $2;           }
+  | '-' FExpr %prec UNARYPREC     { $$ = -$2;          }
+  | '+' FExpr %prec UNARYPREC     { $$ = $2;           }
+  | '!' FExpr                     { $$ = !$2;          }
+  | FExpr '-' FExpr               { $$ = $1 - $3;      }
+  | FExpr '+' FExpr               { $$ = $1 + $3;      }
+  | FExpr '*' FExpr               { $$ = $1 * $3;      }
   | FExpr '/' FExpr
     {
       if(!$3)
@@ -4347,63 +4231,39 @@ FExpr :
       else
 	$$ = $1 / $3;
     }
-  | FExpr '%' FExpr                  { $$ = (int)$1 % (int)$3;  }
-  | FExpr '^' FExpr                  { $$ = pow($1, $3);  }
-  | FExpr '<' FExpr                  { $$ = $1 < $3;      }
-  | FExpr '>' FExpr                  { $$ = $1 > $3;      }
-  | FExpr tLESSOREQUAL FExpr         { $$ = $1 <= $3;     }
-  | FExpr tGREATEROREQUAL FExpr      { $$ = $1 >= $3;     }
-  | FExpr tEQUAL FExpr               { $$ = $1 == $3;     }
-  | FExpr tNOTEQUAL FExpr            { $$ = $1 != $3;     }
-  | FExpr tAND FExpr                 { $$ = $1 && $3;     }
-  | FExpr tOR FExpr                  { $$ = $1 || $3;     }
-  | FExpr '?' FExpr tDOTS FExpr      { $$ = $1 ? $3 : $5; }
-  | tExp    '(' FExpr ')'            { $$ = exp($3);      }
-  | tLog    '(' FExpr ')'            { $$ = log($3);      }
-  | tLog10  '(' FExpr ')'            { $$ = log10($3);    }
-  | tSqrt   '(' FExpr ')'            { $$ = sqrt($3);     }
-  | tSin    '(' FExpr ')'            { $$ = sin($3);      }
-  | tAsin   '(' FExpr ')'            { $$ = asin($3);     }
-  | tCos    '(' FExpr ')'            { $$ = cos($3);      }
-  | tAcos   '(' FExpr ')'            { $$ = acos($3);     }
-  | tTan    '(' FExpr ')'            { $$ = tan($3);      }
-  | tAtan   '(' FExpr ')'            { $$ = atan($3);     }
-  | tAtan2  '(' FExpr ',' FExpr ')'  { $$ = atan2($3, $5);}
-  | tSinh   '(' FExpr ')'            { $$ = sinh($3);     }
-  | tCosh   '(' FExpr ')'            { $$ = cosh($3);     }
-  | tTanh   '(' FExpr ')'            { $$ = tanh($3);     }
-  | tFabs   '(' FExpr ')'            { $$ = fabs($3);     }
-  | tFloor  '(' FExpr ')'            { $$ = floor($3);    }
-  | tCeil   '(' FExpr ')'            { $$ = ceil($3);     }
-  | tRound  '(' FExpr ')'            { $$ = floor($3 + 0.5); }
-  | tFmod   '(' FExpr ',' FExpr ')'  { $$ = fmod($3, $5); }
-  | tModulo '(' FExpr ',' FExpr ')'  { $$ = fmod($3, $5); }
-  | tHypot  '(' FExpr ',' FExpr ')'  { $$ = sqrt($3 * $3 + $5 * $5); }
-  | tRand   '(' FExpr ')'            { $$ = $3 * (double)rand() / (double)RAND_MAX; }
-
-  // for compatibility with GetDP
-  | tExp    '[' FExpr ']'            { $$ = exp($3);      }
-  | tLog    '[' FExpr ']'            { $$ = log($3);      }
-  | tLog10  '[' FExpr ']'            { $$ = log10($3);    }
-  | tSqrt   '[' FExpr ']'            { $$ = sqrt($3);     }
-  | tSin    '[' FExpr ']'            { $$ = sin($3);      }
-  | tAsin   '[' FExpr ']'            { $$ = asin($3);     }
-  | tCos    '[' FExpr ']'            { $$ = cos($3);      }
-  | tAcos   '[' FExpr ']'            { $$ = acos($3);     }
-  | tTan    '[' FExpr ']'            { $$ = tan($3);      }
-  | tAtan   '[' FExpr ']'            { $$ = atan($3);     }
-  | tAtan2  '[' FExpr ',' FExpr ']'  { $$ = atan2($3, $5);}
-  | tSinh   '[' FExpr ']'            { $$ = sinh($3);     }
-  | tCosh   '[' FExpr ']'            { $$ = cosh($3);     }
-  | tTanh   '[' FExpr ']'            { $$ = tanh($3);     }
-  | tFabs   '[' FExpr ']'            { $$ = fabs($3);     }
-  | tFloor  '[' FExpr ']'            { $$ = floor($3);    }
-  | tCeil   '[' FExpr ']'            { $$ = ceil($3);     }
-  | tRound  '[' FExpr ']'            { $$ = floor($3 + 0.5);    }
-  | tFmod   '[' FExpr ',' FExpr ']'  { $$ = fmod($3, $5); }
-  | tModulo '[' FExpr ',' FExpr ']'  { $$ = fmod($3, $5); }
-  | tHypot  '[' FExpr ',' FExpr ']'  { $$ = sqrt($3 * $3 + $5 * $5); }
-  | tRand   '[' FExpr ']'            { $$ = $3 * (double)rand() / (double)RAND_MAX; }
+  | FExpr '%' FExpr                { $$ = (int)$1 % (int)$3;  }
+  | FExpr '^' FExpr                { $$ = pow($1, $3);  }
+  | FExpr '<' FExpr                { $$ = $1 < $3;      }
+  | FExpr '>' FExpr                { $$ = $1 > $3;      }
+  | FExpr tLESSOREQUAL FExpr       { $$ = $1 <= $3;     }
+  | FExpr tGREATEROREQUAL FExpr    { $$ = $1 >= $3;     }
+  | FExpr tEQUAL FExpr             { $$ = $1 == $3;     }
+  | FExpr tNOTEQUAL FExpr          { $$ = $1 != $3;     }
+  | FExpr tAND FExpr               { $$ = $1 && $3;     }
+  | FExpr tOR FExpr                { $$ = $1 || $3;     }
+  | FExpr '?' FExpr tDOTS FExpr    { $$ = $1 ? $3 : $5; }
+  | tExp    LP FExpr RP            { $$ = exp($3);      }
+  | tLog    LP FExpr RP            { $$ = log($3);      }
+  | tLog10  LP FExpr RP            { $$ = log10($3);    }
+  | tSqrt   LP FExpr RP            { $$ = sqrt($3);     }
+  | tSin    LP FExpr RP            { $$ = sin($3);      }
+  | tAsin   LP FExpr RP            { $$ = asin($3);     }
+  | tCos    LP FExpr RP            { $$ = cos($3);      }
+  | tAcos   LP FExpr RP            { $$ = acos($3);     }
+  | tTan    LP FExpr RP            { $$ = tan($3);      }
+  | tAtan   LP FExpr RP            { $$ = atan($3);     }
+  | tAtan2  LP FExpr ',' FExpr RP  { $$ = atan2($3, $5);}
+  | tSinh   LP FExpr RP            { $$ = sinh($3);     }
+  | tCosh   LP FExpr RP            { $$ = cosh($3);     }
+  | tTanh   LP FExpr RP            { $$ = tanh($3);     }
+  | tFabs   LP FExpr RP            { $$ = fabs($3);     }
+  | tFloor  LP FExpr RP            { $$ = floor($3);    }
+  | tCeil   LP FExpr RP            { $$ = ceil($3);     }
+  | tRound  LP FExpr RP            { $$ = floor($3 + 0.5); }
+  | tFmod   LP FExpr ',' FExpr RP  { $$ = fmod($3, $5); }
+  | tModulo LP FExpr ',' FExpr RP  { $$ = fmod($3, $5); }
+  | tHypot  LP FExpr ',' FExpr RP  { $$ = sqrt($3 * $3 + $5 * $5); }
+  | tRand   LP FExpr RP            { $$ = $3 * (double)rand() / (double)RAND_MAX; }
 ;
 
 // FIXME: add +=, -=, *= et /=
@@ -4421,9 +4281,18 @@ FExpr_Single :
   | tGMSH_PATCH_VERSION { $$ = GetGmshPatchVersion(); }
   | tCpu { $$ = Cpu(); }
   | tMemory { $$ = GetMemoryUsage()/1024./1024.; }
+  | tTotalMemory { $$ = TotalRam(); }
 
   // Variables
 
+  | tDefineNumber LP FExpr
+    { floatOptions.clear(); charOptions.clear(); }
+    FloatParameterOptions RP
+    {
+      std::vector<double> val(1, $3);
+      Msg::ExchangeOnelabParameter("", val, floatOptions, charOptions);
+      $$ = val[0];
+    }
   | String__Index
     {
       if(!gmsh_yysymbols.count($1)){
@@ -4441,7 +4310,6 @@ FExpr_Single :
       }
       Free($1);
     }
-
   | tSTRING '[' FExpr ']'
     {
       int index = (int)$3;
@@ -4460,7 +4328,36 @@ FExpr_Single :
       }
       Free($1);
     }
-  | '#' tSTRING '[' ']'
+  | StringIndex '[' FExpr ']'
+    {
+      int index = (int)$3;
+      if(!gmsh_yysymbols.count($1)){
+	yymsg(0, "Unknown variable '%s'", $1);
+	$$ = 0.;
+      }
+      else{
+        gmsh_yysymbol &s(gmsh_yysymbols[$1]);
+        if((int)s.value.size() < index + 1){
+          yymsg(0, "Uninitialized variable '%s[%d]'", $1, index);
+          $$ = 0.;
+        }
+        else
+          $$ = s.value[index];
+      }
+      Free($1);
+    }
+  | tExists '(' String__Index ')'
+    {
+      $$ = gmsh_yysymbols.count($3);
+      Free($3);
+    }
+  | tFileExists '(' StringExpr ')'
+    {
+      std::string tmp = FixRelativePath(gmsh_yyname, $3);
+      $$ = !StatFile(tmp);
+      Free($3);
+    }
+  | '#' String__Index '[' ']'
     {
       if(!gmsh_yysymbols.count($2)){
 	yymsg(0, "Unknown variable '%s'", $2);
@@ -4507,6 +4404,24 @@ FExpr_Single :
       }
       Free($1);
     }
+  | StringIndex '[' FExpr ']' NumericIncrement
+    {
+      int index = (int)$3;
+      if(!gmsh_yysymbols.count($1)){
+	yymsg(0, "Unknown variable '%s'", $1);
+	$$ = 0.;
+      }
+      else{
+        gmsh_yysymbol &s(gmsh_yysymbols[$1]);
+        if((int)s.value.size() < index + 1){
+          yymsg(0, "Uninitialized variable '%s[%d]'", $1, index);
+          $$ = 0.;
+        }
+        else
+          $$ = (s.value[index] += $5);
+      }
+      Free($1);
+    }
 
   // Option Strings
 
@@ -4898,20 +4813,7 @@ FExpr_Multi :
       }
       List_Delete($1);
     }
-  | tSTRING '[' ']'
-    {
-      $$ = List_Create(2, 1, sizeof(double));
-      if(!gmsh_yysymbols.count($1))
-	yymsg(0, "Unknown variable '%s'", $1);
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-	for(unsigned int i = 0; i < s.value.size(); i++)
-	  List_Add($$, &s.value[i]);
-      }
-      Free($1);
-    }
-  // for compatibility with GetDP
-  | tSTRING '(' ')'
+  | tSTRING LP RP
     {
       $$ = List_Create(2, 1, sizeof(double));
       if(!gmsh_yysymbols.count($1))
@@ -4935,26 +4837,7 @@ FExpr_Multi :
       }
       Free($3);
     }
-  | tSTRING '[' '{' RecursiveListOfDouble '}' ']'
-    {
-      $$ = List_Create(2, 1, sizeof(double));
-      if(!gmsh_yysymbols.count($1))
-	yymsg(0, "Unknown variable '%s'", $1);
-      else{
-        gmsh_yysymbol &s(gmsh_yysymbols[$1]);
-	for(int i = 0; i < List_Nbr($4); i++){
-	  int index = (int)(*(double*)List_Pointer_Fast($4, i));
-	  if((int)s.value.size() < index + 1)
-	    yymsg(0, "Uninitialized variable '%s[%d]'", $1, index);
-	  else
-	    List_Add($$, &s.value[index]);
-	}
-      }
-      Free($1);
-      List_Delete($4);
-    }
-  // for compatibility with GetDP
-  | tSTRING '(' '{' RecursiveListOfDouble '}' ')'
+  | tSTRING LP '{' RecursiveListOfDouble '}' RP
     {
       $$ = List_Create(2, 1, sizeof(double));
       if(!gmsh_yysymbols.count($1))
@@ -5112,6 +4995,12 @@ StringExpr :
       strcpy($$, ctime(&now));
       $$[strlen($$) - 1] = '\0';
     }
+  | tOnelabAction
+    {
+      std::string action = Msg::GetGmshOnelabAction();
+      $$ = (char *)Malloc(action.size() + 1);
+      strcpy($$, action.c_str());
+    }
   | tGetEnv '(' StringExprVar ')'
     {
       const char *env = GetEnvironmentVar($3);
@@ -5128,16 +5017,7 @@ StringExpr :
       Free($3);
       Free($5);
     }
-  | tStrCat '(' StringExprVar ',' StringExprVar ')'
-    {
-      $$ = (char *)Malloc((strlen($3) + strlen($5) + 1) * sizeof(char));
-      strcpy($$, $3);
-      strcat($$, $5);
-      Free($3);
-      Free($5);
-    }
-  // for compatibility with GetDP
-  | tStrCat '[' StringExprVar ',' StringExprVar ']'
+  | tStrCat LP StringExprVar ',' StringExprVar RP
     {
       $$ = (char *)Malloc((strlen($3) + strlen($5) + 1) * sizeof(char));
       strcpy($$, $3);
@@ -5185,7 +5065,7 @@ StringExpr :
       Free($5);
       Free($7);
     }
-  | tStr '(' RecursiveListOfStringExprVar ')'
+  | tStr LP RecursiveListOfStringExprVar RP
     {
       int size = 0;
       for(int i = 0; i < List_Nbr($3); i++)
@@ -5201,33 +5081,11 @@ StringExpr :
       }
       List_Delete($3);
     }
-  // for compatibility with GetDP
-  | tStr '[' RecursiveListOfStringExprVar ']'
-    {
-      int size = 0;
-      for(int i = 0; i < List_Nbr($3); i++)
-        size += strlen(*(char**)List_Pointer($3, i)) + 1;
-      $$ = (char*)Malloc(size * sizeof(char));
-      $$[0] = '\0';
-      for(int i = 0; i < List_Nbr($3); i++){
-        char *s;
-        List_Read($3, i, &s);
-        strcat($$, s);
-        Free(s);
-        if(i != List_Nbr($3) - 1) strcat($$, "\n");
-      }
-      List_Delete($3);
-    }
-  | tSprintf '(' StringExprVar ')'
+  | tSprintf LP StringExprVar RP
     {
       $$ = $3;
     }
-  // for compatibility with GetDP
-  | tSprintf '[' StringExprVar ']'
-    {
-      $$ = $3;
-    }
-  | tSprintf '(' StringExprVar ',' RecursiveListOfDouble ')'
+  | tSprintf LP StringExprVar ',' RecursiveListOfDouble RP
     {
       char tmpstring[5000];
       int i = PrintListOfDouble($3, $5, tmpstring);
@@ -5246,25 +5104,15 @@ StringExpr :
       }
       List_Delete($5);
     }
-  // for compatibility with GetDP
-  | tSprintf '[' StringExprVar ',' RecursiveListOfDouble ']'
+  | tDefineString LP StringExpr
+    { floatOptions.clear(); charOptions.clear(); }
+    CharParameterOptions RP
     {
-      char tmpstring[5000];
-      int i = PrintListOfDouble($3, $5, tmpstring);
-      if(i < 0){
-	yymsg(0, "Too few arguments in Sprintf");
-	$$ = $3;
-      }
-      else if(i > 0){
-	yymsg(0, "%d extra argument%s in Sprintf", i, (i > 1) ? "s" : "");
-	$$ = $3;
-      }
-      else{
-	$$ = (char*)Malloc((strlen(tmpstring) + 1) * sizeof(char));
-	strcpy($$, tmpstring);
-	Free($3);
-      }
-      List_Delete($5);
+      std::string val($3);
+      Msg::ExchangeOnelabParameter("", val, floatOptions, charOptions);
+      $$ = (char*)Malloc((val.size() + 1) * sizeof(char));
+      strcpy($$, val.c_str());
+      Free($3);
     }
 ;
 
@@ -5312,6 +5160,100 @@ String__Index :
 
 %%
 
+void assignVariable(const std::string &name, int index, int assignType,
+                    double value)
+{
+  if(!gmsh_yysymbols.count(name)){
+    if(!assignType){
+      gmsh_yysymbol &s(gmsh_yysymbols[name]);
+      s.list = true;
+      s.value.resize(index + 1, 0.);
+      s.value[index] = value;
+    }
+    else
+      yymsg(0, "Unknown variable '%s'", name.c_str());
+  }
+  else{
+    gmsh_yysymbol &s(gmsh_yysymbols[name]);
+    if(s.list){
+      if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
+      switch(assignType){
+      case 0 : s.value[index] = value; break;
+      case 1 : s.value[index] += value; break;
+      case 2 : s.value[index] -= value; break;
+      case 3 : s.value[index] *= value; break;
+      case 4 :
+        if(value) s.value[index] /= value;
+        else yymsg(0, "Division by zero in '%s[%d] /= %g'",
+                   name.c_str(), index, value);
+        break;
+      }
+    }
+    else
+      yymsg(0, "Variable '%s' is not a list", name.c_str());
+  }
+}
+
+void assignVariables(const std::string &name, List_T *indices, int assignType,
+                     List_T *values)
+{
+  if(List_Nbr(indices) != List_Nbr(values)){
+    yymsg(0, "Incompatible array dimensions in affectation");
+  }
+  else{
+    if(!gmsh_yysymbols.count(name)){
+      if(!assignType){
+        gmsh_yysymbol &s(gmsh_yysymbols[name]);
+        s.list = true;
+        for(int i = 0; i < List_Nbr(indices); i++){
+          int index = (int)(*(double*)List_Pointer(indices, i));
+          s.value.resize(index + 1, 0.);
+          s.value[index] = *(double*)List_Pointer(values, i);
+        }
+      }
+      else
+        yymsg(0, "Unknown variable '%s'", name.c_str());
+    }
+    else{
+      gmsh_yysymbol &s(gmsh_yysymbols[name]);
+      if(s.list){
+        for(int i = 0; i < List_Nbr(indices); i++){
+          int index = (int)(*(double*)List_Pointer(indices, i));
+          double d = *(double*)List_Pointer(values, i);
+          if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
+          switch(assignType){
+          case 0 : s.value[index] = d; break;
+          case 1 : s.value[index] += d; break;
+          case 2 : s.value[index] -= d; break;
+          case 3 : s.value[index] *= d; break;
+          case 4 :
+            if(d) s.value[index] /= d;
+            else yymsg(0, "Division by zero in '%s[%d] /= %g'", name.c_str(), index, d);
+            break;
+          }
+        }
+      }
+      else
+        yymsg(0, "Variable '%s' is not a list", name.c_str());
+    }
+  }
+}
+
+void incrementVariable(const std::string &name, int index, double value)
+{
+  if(!gmsh_yysymbols.count(name))
+    yymsg(0, "Unknown variable '%s'", name.c_str());
+  else{
+    gmsh_yysymbol &s(gmsh_yysymbols[name]);
+    if(s.list){
+      if((int)s.value.size() < index + 1) s.value.resize(index + 1, 0.);
+      s.value[index] += value;
+    }
+    else
+      yymsg(0, "Variable '%s' is not a list", name.c_str());
+  }
+}
+
 int PrintListOfDouble(char *format, List_T *list, char *buffer)
 {
   // if format does not contain formatting characters, dump the list (useful for
@@ -5362,6 +5304,42 @@ int PrintListOfDouble(char *format, List_T *list, char *buffer)
   return 0;
 }
 
+void PrintParserSymbols(bool help, std::vector<std::string> &vec)
+{
+  if(help){
+    vec.push_back("//");
+    vec.push_back("// Numbers");
+    vec.push_back("//");
+  }
+  for(std::map<std::string, gmsh_yysymbol>::iterator it = gmsh_yysymbols.begin();
+      it != gmsh_yysymbols.end(); it++){
+    gmsh_yysymbol s(it->second);
+    std::ostringstream sstream;
+    sstream << it->first;
+    if(s.list){
+      sstream << "[] = {";
+      for(unsigned int i = 0; i < s.value.size(); i++){
+        if(i) sstream << ", ";
+        sstream << s.value[i];
+      }
+      sstream << "}";
+    }
+    else
+      sstream << " = " << s.value[0];
+    sstream << ";";
+    vec.push_back(sstream.str());
+  }
+  if(help){
+    vec.push_back("//");
+    vec.push_back("// Strings");
+    vec.push_back("//");
+  }
+  for(std::map<std::string, std::string>::iterator it = gmsh_yystringsymbols.begin();
+      it != gmsh_yystringsymbols.end(); it++){
+    vec.push_back(it->first + " = \"" + it->second + "\";");
+  }
+}
+
 fullMatrix<double> ListOfListOfDouble2Matrix(List_T *list)
 {
   int M = List_Nbr(list);
diff --git a/Parser/Gmsh.yy.cpp b/Parser/Gmsh.yy.cpp
index e65ea60..4bd14b2 100644
--- a/Parser/Gmsh.yy.cpp
+++ b/Parser/Gmsh.yy.cpp
@@ -380,8 +380,8 @@ static void yy_fatal_error (yyconst char msg[]  );
 	*yy_cp = '\0'; \
 	(yy_c_buf_p) = yy_cp;
 
-#define YY_NUM_RULES 181
-#define YY_END_OF_BUFFER 182
+#define YY_NUM_RULES 187
+#define YY_END_OF_BUFFER 188
 /* This struct is not used in this scanner,
    but its presence is necessary. */
 struct yy_trans_info
@@ -389,103 +389,108 @@ struct yy_trans_info
 	flex_int32_t yy_verify;
 	flex_int32_t yy_nxt;
 	};
-static yyconst flex_int16_t yy_accept[866] =
+static yyconst flex_int16_t yy_accept[909] =
     {   0,
-        0,    0,  182,  180,    1,    1,  180,    5,  180,    6,
-      180,  180,  180,  180,  180,  175,   21,    2,  180,   16,
-      180,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  180,   28,   24,   19,   25,   17,
-       26,   18,    0,  177,    3,    4,   20,  176,  175,    0,
-       29,   27,   30,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-
-      179,   99,   98,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  119,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  162,  163,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,   23,   22,    0,  176,
-        0,    0,  178,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,   54,   65,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,   72,  179,  179,
-      179,  179,  179,   86,  179,  179,  179,  179,  179,  179,
-
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  106,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  145,  179,  179,
-      179,  179,  179,  151,  179,  179,  179,  179,  170,  179,
-      179,  179,  179,  179,  179,  179,    0,  177,    0,    0,
-      176,  179,   32,  179,  179,  179,  179,  179,   37,   39,
-      179,  179,  179,  179,   62,  179,   47,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,   53,  179,  179,  179,
-      179,  179,   70,  179,  179,  179,  179,  179,   81,  179,
-
-       82,  179,  179,   85,  179,  179,  179,  179,  179,   94,
-       95,  179,  179,  179,  179,  179,  179,  179,  179,  104,
-      105,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  136,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      159,  146,  179,  179,  179,  179,  144,  179,  179,  179,
-      179,  179,  179,  179,  165,  169,  179,  179,  179,  179,
-      179,  179,   10,   15,    9,    8,  179,   12,   14,    0,
-      176,   31,  179,   35,  179,  179,  179,   41,  179,   43,
-      179,  179,  179,  179,  179,  179,  179,   57,  179,  179,
-
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-       78,   80,  179,  179,   83,   84,  179,  179,  179,  179,
-      179,  179,   97,  179,  179,  102,  179,  179,  179,  107,
-      179,  179,  179,  179,  179,  115,  116,  179,  179,  179,
-      120,  179,  121,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  134,  135,  179,  179,  179,  179,  179,
-      179,  149,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  171,  179,  179,  173,  179,   11,  179,   13,
-      179,  179,   34,   38,   40,  179,   44,  179,  179,  179,
-       48,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-
-      179,  179,   67,   69,  179,  179,   77,  179,  179,  179,
-      179,  179,   88,  179,  179,  179,  179,  179,  108,  103,
-      179,  179,  179,  114,  179,  111,  179,  179,  179,  125,
-      179,  124,  179,  179,  179,  179,  179,  139,  179,  133,
-      179,  179,  179,  179,  147,  148,  179,  153,  158,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      174,    7,  179,  179,   42,   45,  179,  179,  179,  179,
-      179,  179,   52,   56,  179,  179,  179,  179,  179,  179,
-       74,  179,  179,  179,   75,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-
-      179,  179,  179,  179,  179,  179,  179,  179,  140,  179,
-      179,  179,  179,  152,  157,  179,  179,  179,  150,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,   59,  179,  179,  179,  179,  179,
-       73,   76,  179,   87,  179,  179,  179,  179,   90,   96,
-      179,  179,  109,  112,  113,  179,  179,  117,  118,  179,
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  143,  142,  179,  179,  179,  160,  179,  179,  179,
-      179,  179,  179,   33,  179,  179,  179,  179,   50,  179,
-      179,  179,  179,  179,  179,  179,   79,  179,  179,  179,
-
-       89,  179,  100,  179,  179,  179,  179,  179,  179,  179,
-      179,  130,  132,  179,  179,  179,  179,  155,  179,  179,
-      161,  179,  179,  179,  168,  179,  179,  179,   61,  179,
-       51,   58,  179,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  122,  179,  179,  128,  179,  179,  179,  137,
-      179,  179,   71,  179,  154,  179,  179,  179,  179,  179,
-       46,  179,   60,   49,  179,  179,   68,  179,  179,  179,
-      179,  179,  123,  179,  179,  129,  179,  179,  179,  156,
-      179,  179,  166,  179,  179,  179,  179,  179,  179,  179,
-      179,  179,  179,  179,  179,  179,  138,  179,  179,  179,
-
-      179,  179,  179,  179,  179,  179,  179,  179,  179,  110,
-      179,  179,  179,  179,  179,  167,  179,  179,   55,   63,
-       66,  179,  179,  179,  179,  179,  179,  131,  141,  164,
-      179,  179,  179,  179,  179,  179,  179,  126,  179,  179,
-       36,  179,  179,  179,  179,  179,  179,  172,  179,  179,
-      179,  179,  179,  127,  179,   91,   92,   93,  179,  179,
-      179,  179,  101,   64,    0
+        0,    0,  188,  186,    1,    1,  186,    5,  186,    6,
+      186,  186,  186,  186,  186,  181,   21,    2,  186,   16,
+      186,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  186,   28,   24,   19,   25,   17,
+       26,   18,    0,  183,    3,    4,   20,  182,  181,    0,
+       29,   27,   30,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+
+      185,  103,  102,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  124,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  167,  168,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,   23,   22,    0,
+      182,    0,    0,  184,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,   54,   65,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,   74,  185,
+      185,  185,  185,  185,  185,   90,  185,  185,  185,  185,
+
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  110,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      150,  185,  185,  185,  185,  185,  156,  185,  185,  185,
+      185,  175,  185,  185,  185,  185,  185,  185,  185,  185,
+        0,  183,    0,    0,  182,  185,   32,  185,  185,  185,
+      185,  185,   37,   39,  185,  185,  185,  185,   62,  185,
+       47,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+       53,  185,  185,  185,  185,  185,   72,  185,  185,  185,
+
+      185,  185,  185,   83,  185,   85,  185,  185,  185,   89,
+      185,  185,  185,  185,  185,   98,   99,  185,  185,  185,
+      185,  185,  185,  185,  185,  108,  109,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  141,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  164,  151,  185,
+      185,  185,  185,  149,  185,  185,  185,  185,  185,  185,
+      185,  170,  174,  185,  185,  185,  185,  185,  185,  185,
+       10,   15,    9,    8,  185,   12,   14,    0,  182,   31,
+      185,   35,  185,  185,  185,   41,  185,   43,  185,  185,
+
+      185,  185,  185,  185,  185,   57,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,   80,   82,
+      185,  185,  185,   86,  185,   88,  185,  185,  185,  185,
+      185,  185,  101,  185,  185,  106,  185,  185,  185,  111,
+      185,  185,  185,  185,  185,  119,  185,  121,  185,  185,
+      185,  125,  185,  126,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  139,  140,  185,  185,  185,  185,
+      185,  185,  154,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  176,  185,  185,  185,  179,  185,   11,
+      185,   13,  185,  185,   34,   38,   40,  185,   44,  185,
+
+      185,  185,   48,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,   69,   71,  185,  185,   79,  185,
+       84,  185,  185,  185,  185,  185,   92,  185,  185,  185,
+      185,  185,  112,  107,  185,  185,  185,  118,  185,  115,
+      185,  185,  185,  185,  130,  185,  129,  185,  185,  185,
+      185,  185,  144,  185,  138,  185,  185,  185,  185,  152,
+      153,  185,  158,  163,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  180,    7,  185,  185,
+       42,   45,  185,  185,  185,  185,  185,  185,   52,   56,
+      185,  185,  185,  185,  185,  185,  185,  185,   76,  185,
+
+      185,  185,   77,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  145,  185,
+      185,  185,  185,  157,  162,  185,  185,  185,  155,  185,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,   59,  185,  185,  185,  185,
+      185,  185,  185,   75,   78,  185,  185,   91,  185,  185,
+      185,  185,   94,  100,  185,  185,  113,  116,  117,  185,
+      185,  185,  122,  123,  185,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,  185,  185,  148,  147,  185,  185,
+
+      185,  165,  185,  185,  185,  185,  185,  185,  185,   33,
+      185,  185,  185,  185,   50,  185,  185,  185,  185,  185,
+      185,  185,  185,  185,   81,  185,  185,  185,  185,   93,
+      185,  104,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  135,  137,  185,  185,  185,  185,  160,  185,  185,
+      166,  185,  185,  185,  185,  173,  185,  185,  185,   61,
+      185,   51,   58,  185,  185,  185,  185,  185,  185,  185,
+       87,  185,  185,  185,  185,  185,  185,  127,  185,  185,
+      133,  185,  185,  185,  142,  185,  185,   73,  185,  159,
+      185,  185,  185,  185,  185,  185,   46,  185,   60,   49,
+
+      185,  185,  185,  185,   70,  185,  185,  185,  185,  185,
+      185,  128,  185,  185,  134,  185,  185,  185,  161,  185,
+      177,  185,  171,  185,  185,  185,  185,  185,   67,   68,
+      185,  185,  185,  185,  185,  120,  185,  185,  185,  143,
+      185,  185,  185,  185,  185,  185,  185,  185,  185,  185,
+      185,  185,  114,  185,  185,  185,  185,  185,  172,  185,
+      185,   55,   63,   66,  185,  185,  185,  185,  185,  185,
+      136,  146,  169,  185,  185,  185,  185,  185,  185,  185,
+      131,  185,  185,   36,  185,  185,  185,  185,  185,  185,
+      178,  185,  185,  185,  185,  185,  132,  185,   95,   96,
+
+       97,  185,  185,  185,  185,  105,   64,    0
     } ;
 
 static yyconst flex_int32_t yy_ec[256] =
@@ -532,205 +537,215 @@ static yyconst flex_int32_t yy_meta[74] =
         2,    2,    1
     } ;
 
-static yyconst flex_int16_t yy_base[867] =
+static yyconst flex_int16_t yy_base[910] =
     {   0,
-        0,    0,  998,  999,  999,  999,  976,  999,  990,  999,
-      974,   65,   66,   64,   76,   78,  999,  999,  973,  972,
-      971,   49,   49,   56,   67,   68,   81,   50,   80,   97,
-        0,  931,   97,  108,  923,  925,  107,  921,  118,  125,
-      158,   56,  926,  934,  912,  999,  999,  999,  999,  999,
-      999,  999,  973,  184,  999,  999,  999,  199,  214,  229,
-      999,  999,  999,    0,  922,  921,  933,  924,  929,  922,
-      929,  914,   37,  908,   86,  918,  925,  908,  194,  904,
-      918,  149,  911,  920,  909,  915,  901,  914,  116,  914,
-      910,  900,  899,  895,  898,  916,  890,  904,   24,  892,
-
-      911,    0,  886,  890,  879,   96,   62,  895,  917,  102,
-      896,  882,  894,  880,  879,  871,    0,   58,  137,  885,
-      892,  879,  182,  138,  880,  889,  870,  874,  874,  872,
-      199,  868,  867,  866,  149,    0,    0,  894,  868,  857,
-      875,  877,  873,  867,  864,  852,  999,  999,  255,  260,
-      269,  275,  280,  856,  854,  856,  869,  192,  856,  855,
-      856,  847,  856,  851,  852,  850,  850,  843,  856,   82,
-      844,  175,  840,  832,  847,    0,  853,  844,  847,  846,
-      849,  827,  839,  155,  833,  835,  826,    0,  827,  825,
-      831,  827,  836,    0,  836,  855,  272,  832,  831,  821,
-
-      820,  853,  827,  812,  825,  822,  823,  822,  807,  858,
-      824,  809,  814,  801,  818,  814,  817,  808,  798,  802,
-      807,  800,  811,  798,  806,  805,  200,  799,  793,  786,
-      800,  803,  790,  797,  790,  273,  778,  791,  784,  792,
-      787,  786,  775,  277,  787,  780,  788,  810,  781,  769,
-      786,  773,  780,  771,  763,  256,  312,  317,  326,  331,
-      336,  763,    0,  762,  762,  765,  769,  776,    0,  808,
-      766,  765,  768,  768,    0,  751,    0,  769,  758,  751,
-      755,  749,  756,  160,  760,  773,    0,  743,  748,  747,
-      740,  739,    0,  742,  742,  749,  737,  744,    0,  732,
-
-        0,  747,  733,    0,  730,  748,  734,  727,  744,    0,
-        0,  733,  724,  749,  724,  722,  722,  719,  726,    0,
-        0,  770,  240,  718,  758,  722,  714,  714,  718,  715,
-      719,  722,  717,  706,  707,  704,  181,    0,  710,  704,
-      707,  716,  701,  700,  697,  711,  710,  708,  704,  694,
-        0,    0,  691,  692,  241,  695,    0,  252,  698,  689,
-      700,  703,  698,  714,    0,    0,  725,  676,  681,  692,
-      690,  684,    0,    0,  684,    0,  689,  682,    0,  341,
-      346,    0,  704,  693,  672,  676,  675,    0,  674,    0,
-      669,  676,  673,  680,  677,  676,  666,  684,  665,  672,
-
-      656,  666,  659,  668,  667,  666,  665,  664,  238,  651,
-        0,    0,  663,  662,    0,    0,  656,  284,  643,  646,
-      651,  647,    0,  669,  641,    0,  640,  649,  638,    0,
-      654,  645,  629,  641,  637,    0,    0,  645,  645,  645,
-        0,  634,    0,  652,  639,  627,  641,  624,  636,  639,
-      626,  620,  632,    0,    0,  649,  634,  630,  625,  627,
-      626,    0,  611,  610,  613,  614,  621,  132,  622,  605,
-      609,  603,    0,  311,  612,    0,  615,    0,  612,    0,
-      613,  608,    0,    0,  648,  610,    0,  601,  602,  593,
-        0,  598,  599,  608,  603,  584,  593,  592,  585,  608,
-
-      624,  584,    0,    0,  206,  591,    0,  590,  593,  583,
-      342,  620,    0,  586,  574,  586,  602,  586,    0,    0,
-      585,  576,  563,    0,  580,    0,  567,  576,  583,    0,
-      568,    0,  573,  332,  572,  592,  560,    0,  573,    0,
-      576,  563,  570,  569,    0,    0,  567,    0,    0,  568,
-      565,  569,  558,  563,  550,  562,  546,  328,  563,  550,
-        0,    0,  544,  542,    0,    0,  553,  566,  553,  554,
-      542,  553,    0,    0,  550,  552,  543,  537,  536,  548,
-        0,  530,  544,  545,    0,  532,  559,  554,  547,  528,
-      535,  515,  551,  534,  517,  525,  529,  519,  515,  528,
-
-      519,  521,  345,  527,  514,  505,  520,  519,    0,  505,
-      515,  504,  503,    0,    0,  510,  499,  516,    0,  492,
-      510,  497,  493,  499,  492,  505,  501,  500,  530,  492,
-      488,  499,  496,  491,    0,  482,  486,  484,  485,  478,
-        0,    0,  483,    0,  505,  504,  515,  485,    0,    0,
-      515,  471,    0,    0,    0,  472,  479,    0,    0,  482,
-      482,  483,  470,  470,  463,  476,  475,  461,  490,  458,
-      471,    0,    0,  452,  465,  470,    0,  461,  462,  469,
-      460,  463,  489,    0,  476,  451,  452,  454,    0,  438,
-      456,  455,  446,  444,  439,  451,    0,  462,  461,  470,
-
-        0,   54,    0,   68,   97,   90,  125,  162,  334,  206,
-      256,    0,    0,  268,  285,  304,  321,    0,  306,  323,
-        0,  327,  326,  312,    0,  318,  318,  312,    0,  318,
-        0,    0,  320,  322,  331,  326,  344,  350,  351,  352,
-      369,  335,    0,  350,  359,    0,  352,  348,  343,    0,
-      343,  361,    0,  359,    0,  345,  371,  362,  355,  350,
-        0,  351,    0,    0,  357,  371,    0,  376,  377,  378,
-      386,  369,    0,  373,  357,    0,  380,  374,  359,    0,
-      365,  368,    0,  368,  378,  379,  382,  378,  412,  413,
-      414,  406,  384,  380,  401,  388,    0,  395,  396,  393,
-
-      384,  390,  402,  382,  388,  415,  416,  417,  411,    0,
-      393,  408,  396,  398,  398,    0,  416,  405,    0,  430,
-        0,  426,  427,  429,  430,  407,  409,    0,    0,    0,
-      414,  410,  415,  446,  447,  448,  455,    0,  415,  416,
-        0,  453,  447,  448,  449,  457,  423,    0,  428,  454,
-      455,  456,  466,    0,  436,    0,    0,    0,  460,  444,
-      470,  433,    0,    0,  999,  497
+        0,    0, 1041, 1042, 1042, 1042, 1019, 1042, 1033, 1042,
+     1017,   65,   66,   64,   76,   78, 1042, 1042, 1016, 1015,
+     1014,   49,   49,   56,   67,   68,   81,   50,   80,   97,
+        0,  974,   97,  108,  966,   61,  107,  965,  118,  125,
+      158,   62,  970,  978,  956, 1042, 1042, 1042, 1042, 1042,
+     1042, 1042, 1017,  184, 1042, 1042, 1042,  199,  214,  229,
+     1042, 1042, 1042,    0,  966,  965,  977,  968,  973,  966,
+      973,  958,   37,  952,   58,  962,  969,  952,  194,  948,
+      962,  149,  955,  964,  953,  959,  945,  958,  116,  958,
+      109,  945,  944,  940,  943,  961,  935,  949,   24,  937,
+
+      956,    0,  931,  935,  924,   84,  130,  940,  962,  158,
+      941,  927,  938,  938,  924,  923,  915,    0,  116,   98,
+      929,  936,  923,  182,  127,  924,  933,  914,  918,  918,
+      916,  199,  912,  911,  910,  145,    0,    0,  938,  912,
+      901,  158,  922,  918,  912,  909,  897, 1042, 1042,  255,
+      260,  269,  275,  280,  901,  899,  901,  914,  273,  901,
+      900,  901,  892,  901,  896,  897,  895,  895,  888,  901,
+       82,  889,  159,  885,  877,  892,    0,  898,  889,  892,
+      891,  894,  872,  884,  206,  878,  880,  195,    0,  873,
+      871,  877,  882,  872,  881,    0,  881,  900,  272,  877,
+
+      876,  866,  865,  898,  872,  857,  870,  867,  868,  867,
+      852,  903,  869,  854,  859,  846,  863,  853,  858,  861,
+      852,  842,  846,  851,  844,  855,  842,  850,  849,  239,
+      843,  837,  830,  844,  847,  834,  841,  834,  280,  822,
+      835,  828,  836,  831,  830,  819,  282,  831,  824,  832,
+      854,  825,  813,  830,  829,  816,  823,  814,  806,  268,
+      324,  329,  338,  343,  348,  806,    0,  805,  805,  808,
+      812,  819,    0,  851,  809,  808,  811,  811,    0,  794,
+        0,  812,  801,  794,  798,  792,  799,  243,  803,  816,
+        0,  786,  791,  790,  783,  782,    0,  785,  785,  792,
+
+      780,  787,  776,    0,  774,    0,  789,  812,  774,    0,
+      771,  789,  775,  768,  785,    0,    0,  774,  765,  790,
+      765,  763,  763,  760,  767,    0,    0,  811,  240,  759,
+      799,  763,  755,  771,  754,  758,  755,  759,  762,  757,
+      746,  747,  744,  261,    0,  750,  744,  747,  756,  741,
+      740,  737,  751,  750,  748,  744,  734,    0,    0,  731,
+      732,  242,  735,    0,  199,  738,  729,  740,  743,  738,
+      754,    0,    0,  765,  716,  728,  720,  731,  729,  723,
+        0,    0,  723,    0,  728,  721,    0,  353,  358,    0,
+      743,  732,  711,  715,  714,    0,  713,    0,  708,  715,
+
+      712,  719,  716,  715,  705,  723,  704,  711,  695,  705,
+      698,  707,  706,  705,  704,  703,  258,  690,    0,    0,
+      702,  687,  700,    0,  680,    0,  693,  290,  680,  683,
+      688,  684,    0,  706,  678,    0,  677,  686,  675,    0,
+      691,  682,  666,  678,  674,    0,  685,    0,  681,  681,
+      681,    0,  670,    0,  688,  675,  663,  677,  660,  672,
+      675,  662,  656,  668,    0,    0,  685,  670,  666,  661,
+      663,  662,    0,  647,  646,  649,  650,  657,  273,  658,
+      641,  645,  639,    0,  669,  209,  647,    0,  650,    0,
+      647,    0,  648,  643,    0,    0,  683,  645,    0,  636,
+
+      637,  628,    0,  633,  634,  643,  638,  619,  628,  627,
+      620,  643,  351,  620,    0,    0,  325,  627,    0,  626,
+        0,  629,  624,  618,  288,  655,    0,  621,  609,  621,
+      637,  621,    0,    0,  620,  611,  598,    0,  615,    0,
+      645,  601,  610,  617,    0,  602,    0,  607,  344,  606,
+      626,  594,    0,  607,    0,  610,  597,  604,  603,    0,
+        0,  601,    0,    0,  602,  599,  603,  592,  597,  584,
+      596,  580,  593,  340,  596,  583,    0,    0,  577,  575,
+        0,    0,  586,  599,  586,  587,  575,  586,    0,    0,
+      583,  585,  576,  570,  569,  562,  562,  579,    0,  561,
+
+      575,  576,    0,  558,  562,  589,  584,  577,  558,  565,
+      545,  581,  564,  547,  555,  559,  549,  559,  544,  557,
+      548,  550,  357,  556,  543,  534,  549,  548,    0,  534,
+      544,  533,  532,    0,    0,  539,  528,  545,    0,  521,
+      539,  526,  530,  521,  527,  520,  533,  529,  528,  558,
+      520,  516,  527,  524,  519,    0,  510,  514,  512,  513,
+      513,  507,  504,    0,    0,  509,  502,    0,  530,  529,
+      540,  510,    0,    0,  540,  496,    0,    0,    0,  497,
+      494,  503,    0,    0,  506,  506,  507,  494,  494,  487,
+      500,  499,  485,  514,  482,  495,    0,    0,  476,  489,
+
+      494,    0,  485,   40,   45,   99,  120,  134,  193,    0,
+      183,  172,  250,  273,    0,  263,  297,  298,  322,  323,
+      320,  337,  332,  337,    0,  325,  351,  354,  365,    0,
+      355,    0,  343,  345,  354,  342,  356,  351,  374,  357,
+      360,    0,    0,  358,  362,  381,  365,    0,  350,  367,
+        0,  371,  357,  372,  358,    0,  364,  364,  357,    0,
+      363,    0,    0,  364,  365,  373,  366,  381,  375,  385,
+        0,  390,  391,  392,  409,  375,  381,    0,  391,  400,
+        0,  393,  388,  383,    0,  383,  401,    0,  398,    0,
+      384,  381,  411,  402,  395,  390,    0,  391,    0,    0,
+
+      397,  411,  396,  407,    0,  418,  419,  420,  428,  411,
+      407,    0,  417,  401,    0,  423,  417,  402,    0,  408,
+        0,  411,    0,  411,  422,  423,  426,  421,    0,    0,
+      455,  456,  457,  449,  427,    0,  423,  444,  431,    0,
+      438,  439,  436,  427,  433,  445,  425,  431,  458,  459,
+      460,  454,    0,  436,  451,  439,  441,  441,    0,  459,
+      448,    0,  473,    0,  469,  470,  472,  473,  450,  452,
+        0,    0,    0,  457,  453,  458,  489,  490,  491,  498,
+        0,  458,  459,    0,  496,  490,  491,  492,  500,  466,
+        0,  471,  497,  498,  499,  509,    0,  479,    0,    0,
+
+        0,  503,  487,  513,  476,    0,    0, 1042,  540
     } ;
 
-static yyconst flex_int16_t yy_def[867] =
+static yyconst flex_int16_t yy_def[910] =
     {   0,
-      865,    1,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  865,  865,  865,  865,
-      865,  865,  865,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  865,  865,  865,  865,
-      865,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  865,
-      865,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,  866,  866,  866,  866,  866,  866,
-      866,  866,  866,  866,    0,  865
+      908,    1,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  908,  908,  908,
+      908,  908,  908,  908,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      908,  908,  908,  908,  908,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  908,  908,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+      909,  909,  909,  909,  909,  909,  909,  909,  909,  909,
+
+      909,  909,  909,  909,  909,  909,  909,    0,  908
     } ;
 
-static yyconst flex_int16_t yy_nxt[1073] =
+static yyconst flex_int16_t yy_nxt[1116] =
     {   0,
         4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
        14,   15,   16,   16,   16,   16,   16,   17,   18,   19,
@@ -740,119 +755,124 @@ static yyconst flex_int16_t yy_nxt[1073] =
        31,   31,   31,   31,   31,   31,   31,   31,   31,   44,
        31,   31,   31,   31,   31,   31,   31,   31,   31,   31,
        31,   31,   45,   49,   53,   51,   54,   54,   54,   54,
-       54,  199,  200,   55,   96,   50,   52,   56,   58,   72,
-       59,   59,   59,   59,   59,  741,   57,   65,   66,   67,
-
-       73,   97,  162,   75,   60,  220,   68,   76,  163,   74,
-       77,   78,   69,   70,   71,  143,   79,   80,   82,   81,
-      144,  208,   83,  742,  221,   85,  209,   86,   90,   60,
-       84,   87,  101,  280,   88,   98,   91,   89,   92,   93,
-       99,   94,  281,  165,  105,  109,  743,   95,  106,  102,
-      100,  166,  107,  744,  114,  206,  103,  108,  115,  110,
-      212,  116,  117,  207,  118,  122,  213,  119,  111,  123,
-      120,  187,  136,  137,  126,  745,  127,  188,  124,  128,
-      129,  189,  295,  130,  125,  296,  131,  132,  138,  552,
-      133,  134,  222,  553,  223,  135,   54,   54,   54,   54,
-
-       54,  178,  179,  232,  233,  139,  180,  246,  247,  140,
-      149,  150,  150,  150,  150,  150,  266,  400,  141,  746,
-      401,  142,  446,  283,   58,  151,   59,   59,   59,   59,
-       59,  227,  267,  268,  228,  149,  284,  152,  152,  229,
-       60,  153,  153,  153,  153,  153,  446,  230,  170,  231,
-      151,  171,  172,  240,  173,  174,  241,  581,  175,  748,
-      339,  582,  242,  257,  257,   60,  340,  258,  258,  258,
-      258,  258,  150,  150,  150,  150,  150,  260,  260,  431,
-      432,  261,  261,  261,  261,  261,  259,  153,  153,  153,
-      153,  153,  153,  153,  153,  153,  153,  349,  307,  464,
-
-      461,  358,  505,  506,  359,  373,  462,  749,  374,  350,
-      465,  259,  308,  375,  360,  309,  361,  376,  511,  377,
-      378,  512,  750,  379,  258,  258,  258,  258,  258,  258,
-      258,  258,  258,  258,  380,  380,  751,  752,  381,  381,
-      381,  381,  381,  261,  261,  261,  261,  261,  261,  261,
-      261,  261,  261,  381,  381,  381,  381,  381,  381,  381,
-      381,  381,  381,  558,  587,  604,  623,  661,  559,  747,
-      662,  753,  588,  754,  755,  756,  757,  758,  759,  760,
-      663,  761,  762,  624,  763,  664,  764,  605,  765,  604,
-      623,  766,  661,  747,  767,  662,  768,  769,  770,  771,
-
-      772,  773,  774,  775,  663,  776,  777,  778,  779,  664,
-      780,  781,  782,  783,  784,  785,  786,  787,  788,  789,
-      790,  791,  792,  793,  794,  795,  774,  796,  797,  798,
-      799,  800,  801,  802,  803,  804,  782,  805,  806,  807,
-      808,  809,  810,  811,  812,  813,  814,  815,  816,  817,
-      818,  819,  820,  821,  822,  823,  824,  825,  826,  827,
-      828,  829,  830,  831,  832,  833,  834,  835,  812,  836,
-      837,  838,  839,  840,  841,  842,  843,  844,  845,  846,
-      847,  848,  849,  850,  851,  852,  853,  854,  855,  856,
-      857,  858,  859,  860,  861,  862,  863,  864,   64,  740,
-
-      739,  738,  737,  736,  735,  734,  733,  732,  731,  730,
-      729,  728,  727,  726,  725,  724,  723,  722,  721,  720,
-      719,  718,  717,  716,  715,  714,  713,  712,  711,  710,
-      709,  708,  707,  706,  705,  704,  703,  702,  701,  700,
-      699,  698,  697,  696,  695,  694,  693,  692,  691,  690,
-      689,  688,  687,  686,  685,  684,  683,  682,  681,  680,
+       54,  201,  202,   55,   96,   50,   52,   56,   58,   72,
+       59,   59,   59,   59,   59,  752,   57,   65,   66,   67,
+
+       73,   97,  163,   75,   60,  753,   68,   76,  164,   74,
+       77,   78,   69,   70,   71,  166,   79,   80,   82,   81,
+      113,  144,   83,  167,  114,   85,  145,   86,   90,   60,
+       84,   87,  101,  284,   88,   98,   91,   89,   92,   93,
+       99,   94,  285,  208,  105,  109,  754,   95,  106,  102,
+      100,  209,  107,  225,  115,  226,  103,  108,  116,  110,
+      192,  117,  118,  223,  119,  123,  193,  120,  111,  124,
+      121,  188,  137,  138,  127,  755,  128,  189,  125,  129,
+      130,  190,  224,  131,  126,  756,  132,  133,  139,  210,
+      134,  135,  235,  236,  211,  136,   54,   54,   54,   54,
+
+       54,  179,  180,  249,  250,  140,  181,  287,  254,  141,
+      150,  151,  151,  151,  151,  151,  214,  757,  142,  758,
+      288,  143,  215,  255,   58,  152,   59,   59,   59,   59,
+       59,  230,  759,  299,  231,  150,  300,  153,  153,  232,
+       60,  154,  154,  154,  154,  154,  475,  233,  171,  234,
+      152,  172,  173,  243,  174,  175,  244,  476,  176,  303,
+      304,  574,  245,  261,  261,   60,  575,  262,  262,  262,
+      262,  262,  151,  151,  151,  151,  151,  264,  264,  441,
+      442,  265,  265,  265,  265,  265,  263,  154,  154,  154,
+      154,  154,  154,  154,  154,  154,  154,  270,  313,  346,
+
+      408,  472,  457,  409,  356,  347,  365,  473,  760,  366,
+      606,  263,  314,  271,  272,  315,  357,  381,  607,  367,
+      382,  368,  517,  518,  525,  383,  457,  526,  761,  384,
+      567,  385,  386,  762,  568,  387,  262,  262,  262,  262,
+      262,  262,  262,  262,  262,  262,  388,  388,  763,  764,
+      389,  389,  389,  389,  389,  265,  265,  265,  265,  265,
+      265,  265,  265,  265,  265,  389,  389,  389,  389,  389,
+      389,  389,  389,  389,  389,  595,  599,  624,  644,  686,
+      600,  765,  687,  766,  767,  768,  596,  769,  770,  771,
+      772,  597,  688,  773,  774,  645,  775,  689,  776,  625,
+
+      777,  624,  644,  778,  686,  779,  780,  687,  781,  782,
+      783,  784,  785,  786,  787,  788,  688,  789,  790,  791,
+      792,  689,  793,  794,  795,  796,  797,  798,  799,  800,
+      801,  802,  803,  782,  804,  805,  806,  807,  808,  809,
+      810,  811,  812,  813,  814,  815,  816,  817,  818,  819,
+      820,  821,  822,  823,  824,  825,  826,  827,  828,  829,
+      830,  831,  832,  833,  834,  835,  836,  813,  837,  838,
+      839,  840,  841,  842,  843,  844,  822,  845,  846,  847,
+      848,  849,  850,  851,  852,  853,  854,  855,  856,  857,
+      858,  859,  860,  861,  862,  863,  864,  865,  866,  867,
+
+      868,  869,  870,  871,  872,  873,  874,  875,  876,  877,
+      878,  855,  879,  880,  881,  882,  883,  884,  885,  886,
+      887,  888,  889,  890,  891,  892,  893,  894,  895,  896,
+      897,  898,  899,  900,  901,  902,  903,  904,  905,  906,
+      907,   64,  751,  750,  749,  748,  747,  746,  745,  744,
+      743,  742,  741,  740,  739,  738,  737,  736,  735,  734,
+      733,  732,  731,  730,  729,  728,  727,  726,  725,  724,
+      723,  722,  721,  720,  719,  718,  717,  716,  715,  714,
+      713,  712,  711,  710,  709,  708,  707,  706,  705,  704,
+      703,  702,  701,  700,  699,  698,  697,  696,  695,  694,
+
+      693,  692,  691,  690,  685,  684,  683,  682,  681,  680,
       679,  678,  677,  676,  675,  674,  673,  672,  671,  670,
-      669,  668,  667,  666,  665,  660,  659,  658,  657,  656,
-      655,  654,  653,  652,  651,  650,  649,  648,  647,  646,
-      645,  644,  643,  642,  641,  640,  639,  638,  637,  636,
-
-      635,  634,  633,  632,  631,  630,  629,  628,  627,  626,
-      625,  622,  621,  620,  619,  618,  617,  616,  615,  614,
-      613,  612,  611,  610,  609,  608,  607,  606,  603,  602,
-      601,  600,  599,  598,  597,  596,  595,  594,  593,  592,
-      591,  590,  589,  586,  585,  584,  583,  580,  579,  578,
-      577,  576,  575,  574,  573,  572,  571,  570,  569,  568,
-      567,  566,  565,  564,  563,  562,  561,  560,  557,  556,
-      555,  554,  551,  550,  549,  548,  547,  546,  545,  544,
-      543,  542,  541,  540,  539,  538,  537,  536,  535,  534,
-      533,  532,  531,  530,  529,  528,  527,  526,  525,  524,
-
-      523,  522,  521,  520,  519,  518,  517,  516,  515,  514,
-      513,  510,  509,  508,  507,  504,  503,  502,  501,  500,
-      499,  498,  497,  496,  495,  494,  493,  492,  491,  490,
-      489,  488,  487,  486,  485,  484,  483,  482,  481,  480,
-      479,  478,  477,  476,  475,  474,  473,  472,  471,  470,
-      469,  468,  467,  466,  463,  460,  459,  458,  457,  456,
-      455,  454,  453,  452,  451,  450,  449,  448,  447,  445,
-      444,  443,  442,  441,  440,  439,  438,  437,  436,  435,
-      434,  433,  430,  429,  428,  427,  426,  425,  424,  423,
-      422,  421,  420,  419,  418,  417,  416,  415,  414,  413,
-
-      412,  411,  410,  409,  408,  407,  406,  405,  404,  403,
-      402,  399,  398,  397,  396,  395,  394,  393,  392,  391,
-      390,  389,  388,  387,  386,  385,  384,  383,  382,  372,
-      371,  370,  369,  368,  367,  366,  365,  364,  363,  362,
-      357,  356,  355,  354,  353,  352,  351,  348,  347,  346,
-      345,  344,  343,  342,  341,  338,  337,  336,  335,  334,
-      333,  332,  331,  330,  329,  328,  327,  326,  325,  324,
-      323,  322,  321,  320,  319,  318,  317,  316,  315,  314,
-      313,  312,  311,  310,  306,  305,  304,  303,  302,  301,
-      300,  299,  298,  297,  294,  293,  292,  291,  290,  289,
-
-      288,  287,  286,  285,  282,  279,  278,  277,  276,  275,
-      274,  273,  272,  271,  270,  269,  265,  264,  263,  262,
-      256,  255,  254,  253,  252,  251,  250,  249,  248,  245,
-      244,  243,  239,  238,  237,  236,  235,  234,  226,  225,
-      224,  219,  218,  217,  216,  215,  214,  211,  210,  205,
-      204,  203,  202,  201,  198,  197,  196,  195,  194,  193,
-      192,  191,  190,  186,  185,  184,  183,  182,  181,  177,
-      176,  169,  168,  167,  164,  161,  160,  159,  158,  157,
-      156,  155,  154,  148,  147,  146,  145,  121,  113,  112,
-      104,   63,   62,   61,   48,   47,   46,  865,    3,  865,
-
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865
+      669,  668,  667,  666,  665,  664,  663,  662,  661,  660,
+      659,  658,  657,  656,  655,  654,  653,  652,  651,  650,
+      649,  648,  647,  646,  643,  642,  641,  640,  639,  638,
+      637,  636,  635,  634,  633,  632,  631,  630,  629,  628,
+      627,  626,  623,  622,  621,  620,  619,  618,  617,  616,
+      615,  614,  613,  612,  611,  610,  609,  608,  605,  604,
+      603,  602,  601,  598,  594,  593,  592,  591,  590,  589,
+      588,  587,  586,  585,  584,  583,  582,  581,  580,  579,
+
+      578,  577,  576,  573,  572,  571,  570,  569,  566,  565,
+      564,  563,  562,  561,  560,  559,  558,  557,  556,  555,
+      554,  553,  552,  551,  550,  549,  548,  547,  546,  545,
+      544,  543,  542,  541,  540,  539,  538,  537,  536,  535,
+      534,  533,  532,  531,  530,  529,  528,  527,  524,  523,
+      522,  521,  520,  519,  516,  515,  514,  513,  512,  511,
+      510,  509,  508,  507,  506,  505,  504,  503,  502,  501,
+      500,  499,  498,  497,  496,  495,  494,  493,  492,  491,
+      490,  489,  488,  487,  486,  485,  484,  483,  482,  481,
+      480,  479,  478,  477,  474,  471,  470,  469,  468,  467,
+
+      466,  465,  464,  463,  462,  461,  460,  459,  458,  456,
+      455,  454,  453,  452,  451,  450,  449,  448,  447,  446,
+      445,  444,  443,  440,  439,  438,  437,  436,  435,  434,
+      433,  432,  431,  430,  429,  428,  427,  426,  425,  424,
+      423,  422,  421,  420,  419,  418,  417,  416,  415,  414,
+      413,  412,  411,  410,  407,  406,  405,  404,  403,  402,
+      401,  400,  399,  398,  397,  396,  395,  394,  393,  392,
+      391,  390,  380,  379,  378,  377,  376,  375,  374,  373,
+      372,  371,  370,  369,  364,  363,  362,  361,  360,  359,
+      358,  355,  354,  353,  352,  351,  350,  349,  348,  345,
+
+      344,  343,  342,  341,  340,  339,  338,  337,  336,  335,
+      334,  333,  332,  331,  330,  329,  328,  327,  326,  325,
+      324,  323,  322,  321,  320,  319,  318,  317,  316,  312,
+      311,  310,  309,  308,  307,  306,  305,  302,  301,  298,
+      297,  296,  295,  294,  293,  292,  291,  290,  289,  286,
+      283,  282,  281,  280,  279,  278,  277,  276,  275,  274,
+      273,  269,  268,  267,  266,  260,  259,  258,  257,  256,
+      253,  252,  251,  248,  247,  246,  242,  241,  240,  239,
+      238,  237,  229,  228,  227,  222,  221,  220,  219,  218,
+      217,  216,  213,  212,  207,  206,  205,  204,  203,  200,
+
+      199,  198,  197,  196,  195,  194,  191,  187,  186,  185,
+      184,  183,  182,  178,  177,  170,  169,  168,  165,  162,
+      161,  160,  159,  158,  157,  156,  155,  149,  148,  147,
+      146,  122,  112,  104,   63,   62,   61,   48,   47,   46,
+      908,    3,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908
     } ;
 
-static yyconst flex_int16_t yy_chk[1073] =
+static yyconst flex_int16_t yy_chk[1116] =
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
@@ -863,115 +883,120 @@ static yyconst flex_int16_t yy_chk[1073] =
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    1,    1,   12,   14,   13,   14,   14,   14,   14,
        14,   99,   99,   15,   28,   12,   13,   15,   16,   23,
-       16,   16,   16,   16,   16,  702,   15,   22,   22,   22,
-
-       23,   28,   73,   24,   16,  118,   22,   24,   73,   23,
-       24,   24,   22,   22,   22,   42,   24,   24,   25,   24,
-       42,  107,   25,  704,  118,   26,  107,   26,   27,   16,
-       25,   26,   30,  170,   26,   29,   27,   26,   27,   27,
-       29,   27,  170,   75,   33,   34,  705,   27,   33,   30,
-       29,   75,   33,  706,   37,  106,   30,   33,   37,   34,
-      110,   37,   37,  106,   37,   39,  110,   37,   34,   39,
+       16,   16,   16,   16,   16,  704,   15,   22,   22,   22,
+
+       23,   28,   73,   24,   16,  705,   22,   24,   73,   23,
+       24,   24,   22,   22,   22,   75,   24,   24,   25,   24,
+       36,   42,   25,   75,   36,   26,   42,   26,   27,   16,
+       25,   26,   30,  171,   26,   29,   27,   26,   27,   27,
+       29,   27,  171,  106,   33,   34,  706,   27,   33,   30,
+       29,  106,   33,  120,   37,  120,   30,   33,   37,   34,
+       91,   37,   37,  119,   37,   39,   91,   37,   34,   39,
        37,   89,   41,   41,   40,  707,   40,   89,   39,   40,
-       40,   89,  184,   40,   39,  184,   40,   40,   41,  468,
-       40,   40,  119,  468,  119,   40,   54,   54,   54,   54,
-
-       54,   82,   82,  124,  124,   41,   82,  135,  135,   41,
-       54,   58,   58,   58,   58,   58,  158,  284,   41,  708,
-      284,   41,  337,  172,   59,   58,   59,   59,   59,   59,
-       59,  123,  158,  158,  123,   54,  172,   60,   60,  123,
-       59,   60,   60,   60,   60,   60,  337,  123,   79,  123,
-       58,   79,   79,  131,   79,   79,  131,  505,   79,  710,
-      227,  505,  131,  149,  149,   59,  227,  149,  149,  149,
-      149,  149,  150,  150,  150,  150,  150,  151,  151,  323,
-      323,  151,  151,  151,  151,  151,  150,  152,  152,  152,
-      152,  152,  153,  153,  153,  153,  153,  236,  197,  358,
-
-      355,  244,  409,  409,  244,  256,  355,  711,  256,  236,
-      358,  150,  197,  256,  244,  197,  244,  256,  418,  256,
-      256,  418,  714,  256,  257,  257,  257,  257,  257,  258,
-      258,  258,  258,  258,  259,  259,  715,  716,  259,  259,
-      259,  259,  259,  260,  260,  260,  260,  260,  261,  261,
-      261,  261,  261,  380,  380,  380,  380,  380,  381,  381,
-      381,  381,  381,  474,  511,  534,  558,  603,  474,  709,
-      603,  717,  511,  719,  720,  722,  723,  724,  726,  727,
-      603,  728,  730,  558,  733,  603,  734,  534,  735,  534,
-      558,  736,  603,  709,  737,  603,  738,  739,  740,  741,
-
-      742,  744,  745,  747,  603,  748,  749,  751,  752,  603,
-      754,  756,  757,  758,  759,  760,  762,  765,  766,  768,
-      769,  770,  771,  772,  774,  775,  745,  777,  778,  779,
-      781,  782,  784,  785,  786,  787,  757,  788,  789,  790,
-      791,  792,  793,  794,  795,  796,  798,  799,  800,  801,
-      802,  803,  804,  805,  806,  807,  808,  809,  811,  812,
-      813,  814,  815,  817,  818,  820,  822,  823,  795,  824,
-      825,  826,  827,  831,  832,  833,  834,  835,  836,  837,
-      839,  840,  842,  843,  844,  845,  846,  847,  849,  850,
-      851,  852,  853,  855,  859,  860,  861,  862,  866,  700,
-
-      699,  698,  696,  695,  694,  693,  692,  691,  690,  688,
-      687,  686,  685,  683,  682,  681,  680,  679,  678,  676,
-      675,  674,  671,  670,  669,  668,  667,  666,  665,  664,
-      663,  662,  661,  660,  657,  656,  652,  651,  648,  647,
-      646,  645,  643,  640,  639,  638,  637,  636,  634,  633,
-      632,  631,  630,  629,  628,  627,  626,  625,  624,  623,
-      622,  621,  620,  618,  617,  616,  613,  612,  611,  610,
-      608,  607,  606,  605,  604,  602,  601,  600,  599,  598,
-      597,  596,  595,  594,  593,  592,  591,  590,  589,  588,
-      587,  586,  584,  583,  582,  580,  579,  578,  577,  576,
-
-      575,  572,  571,  570,  569,  568,  567,  564,  563,  560,
-      559,  557,  556,  555,  554,  553,  552,  551,  550,  547,
-      544,  543,  542,  541,  539,  537,  536,  535,  533,  531,
-      529,  528,  527,  525,  523,  522,  521,  518,  517,  516,
-      515,  514,  512,  510,  509,  508,  506,  502,  501,  500,
-      499,  498,  497,  496,  495,  494,  493,  492,  490,  489,
-      488,  486,  485,  482,  481,  479,  477,  475,  472,  471,
-      470,  469,  467,  466,  465,  464,  463,  461,  460,  459,
-      458,  457,  456,  453,  452,  451,  450,  449,  448,  447,
-      446,  445,  444,  442,  440,  439,  438,  435,  434,  433,
-
-      432,  431,  429,  428,  427,  425,  424,  422,  421,  420,
-      419,  417,  414,  413,  410,  408,  407,  406,  405,  404,
-      403,  402,  401,  400,  399,  398,  397,  396,  395,  394,
-      393,  392,  391,  389,  387,  386,  385,  384,  383,  378,
-      377,  375,  372,  371,  370,  369,  368,  367,  364,  363,
-      362,  361,  360,  359,  356,  354,  353,  350,  349,  348,
-      347,  346,  345,  344,  343,  342,  341,  340,  339,  336,
-      335,  334,  333,  332,  331,  330,  329,  328,  327,  326,
-      325,  324,  322,  319,  318,  317,  316,  315,  314,  313,
-      312,  309,  308,  307,  306,  305,  303,  302,  300,  298,
-
-      297,  296,  295,  294,  292,  291,  290,  289,  288,  286,
-      285,  283,  282,  281,  280,  279,  278,  276,  274,  273,
-      272,  271,  270,  268,  267,  266,  265,  264,  262,  255,
-      254,  253,  252,  251,  250,  249,  248,  247,  246,  245,
-      243,  242,  241,  240,  239,  238,  237,  235,  234,  233,
-      232,  231,  230,  229,  228,  226,  225,  224,  223,  222,
-      221,  220,  219,  218,  217,  216,  215,  214,  213,  212,
-      211,  210,  209,  208,  207,  206,  205,  204,  203,  202,
-      201,  200,  199,  198,  196,  195,  193,  192,  191,  190,
-      189,  187,  186,  185,  183,  182,  181,  180,  179,  178,
-
-      177,  175,  174,  173,  171,  169,  168,  167,  166,  165,
-      164,  163,  162,  161,  160,  159,  157,  156,  155,  154,
-      146,  145,  144,  143,  142,  141,  140,  139,  138,  134,
-      133,  132,  130,  129,  128,  127,  126,  125,  122,  121,
-      120,  116,  115,  114,  113,  112,  111,  109,  108,  105,
-      104,  103,  101,  100,   98,   97,   96,   95,   94,   93,
-       92,   91,   90,   88,   87,   86,   85,   84,   83,   81,
-       80,   78,   77,   76,   74,   72,   71,   70,   69,   68,
-       67,   66,   65,   53,   45,   44,   43,   38,   36,   35,
-       32,   21,   20,   19,   11,    9,    7,    3,  865,  865,
-
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865,  865,  865,  865,  865,  865,  865,  865,  865,
-      865,  865
+       40,   89,  119,   40,   39,  708,   40,   40,   41,  107,
+       40,   40,  125,  125,  107,   40,   54,   54,   54,   54,
+
+       54,   82,   82,  136,  136,   41,   82,  173,  142,   41,
+       54,   58,   58,   58,   58,   58,  110,  709,   41,  711,
+      173,   41,  110,  142,   59,   58,   59,   59,   59,   59,
+       59,  124,  712,  185,  124,   54,  185,   60,   60,  124,
+       59,   60,   60,   60,   60,   60,  365,  124,   79,  124,
+       58,   79,   79,  132,   79,   79,  132,  365,   79,  188,
+      188,  486,  132,  150,  150,   59,  486,  150,  150,  150,
+      150,  150,  151,  151,  151,  151,  151,  152,  152,  329,
+      329,  152,  152,  152,  152,  152,  151,  153,  153,  153,
+      153,  153,  154,  154,  154,  154,  154,  159,  199,  230,
+
+      288,  362,  344,  288,  239,  230,  247,  362,  713,  247,
+      525,  151,  199,  159,  159,  199,  239,  260,  525,  247,
+      260,  247,  417,  417,  428,  260,  344,  428,  714,  260,
+      479,  260,  260,  716,  479,  260,  261,  261,  261,  261,
+      261,  262,  262,  262,  262,  262,  263,  263,  717,  718,
+      263,  263,  263,  263,  263,  264,  264,  264,  264,  264,
+      265,  265,  265,  265,  265,  388,  388,  388,  388,  388,
+      389,  389,  389,  389,  389,  513,  517,  549,  574,  623,
+      517,  719,  623,  720,  721,  722,  513,  723,  724,  726,
+      727,  513,  623,  728,  729,  574,  731,  623,  733,  549,
+
+      734,  549,  574,  735,  623,  736,  737,  623,  738,  739,
+      740,  741,  744,  745,  746,  747,  623,  749,  750,  752,
+      753,  623,  754,  755,  757,  758,  759,  761,  764,  765,
+      766,  767,  768,  739,  769,  770,  772,  773,  774,  775,
+      776,  777,  779,  780,  782,  783,  784,  786,  787,  789,
+      791,  792,  793,  794,  795,  796,  798,  801,  802,  803,
+      804,  806,  807,  808,  809,  810,  811,  780,  813,  814,
+      816,  817,  818,  820,  822,  824,  793,  825,  826,  827,
+      828,  831,  832,  833,  834,  835,  837,  838,  839,  841,
+      842,  843,  844,  845,  846,  847,  848,  849,  850,  851,
+
+      852,  854,  855,  856,  857,  858,  860,  861,  863,  865,
+      866,  838,  867,  868,  869,  870,  874,  875,  876,  877,
+      878,  879,  880,  882,  883,  885,  886,  887,  888,  889,
+      890,  892,  893,  894,  895,  896,  898,  902,  903,  904,
+      905,  909,  703,  701,  700,  699,  696,  695,  694,  693,
+      692,  691,  690,  689,  688,  687,  686,  685,  682,  681,
+      680,  676,  675,  672,  671,  670,  669,  667,  666,  663,
+      662,  661,  660,  659,  658,  657,  655,  654,  653,  652,
+      651,  650,  649,  648,  647,  646,  645,  644,  643,  642,
+      641,  640,  638,  637,  636,  633,  632,  631,  630,  628,
+
+      627,  626,  625,  624,  622,  621,  620,  619,  618,  617,
+      616,  615,  614,  613,  612,  611,  610,  609,  608,  607,
+      606,  605,  604,  602,  601,  600,  598,  597,  596,  595,
+      594,  593,  592,  591,  588,  587,  586,  585,  584,  583,
+      580,  579,  576,  575,  573,  572,  571,  570,  569,  568,
+      567,  566,  565,  562,  559,  558,  557,  556,  554,  552,
+      551,  550,  548,  546,  544,  543,  542,  541,  539,  537,
+      536,  535,  532,  531,  530,  529,  528,  526,  524,  523,
+      522,  520,  518,  514,  512,  511,  510,  509,  508,  507,
+      506,  505,  504,  502,  501,  500,  498,  497,  494,  493,
+
+      491,  489,  487,  485,  483,  482,  481,  480,  478,  477,
+      476,  475,  474,  472,  471,  470,  469,  468,  467,  464,
+      463,  462,  461,  460,  459,  458,  457,  456,  455,  453,
+      451,  450,  449,  447,  445,  444,  443,  442,  441,  439,
+      438,  437,  435,  434,  432,  431,  430,  429,  427,  425,
+      423,  422,  421,  418,  416,  415,  414,  413,  412,  411,
+      410,  409,  408,  407,  406,  405,  404,  403,  402,  401,
+      400,  399,  397,  395,  394,  393,  392,  391,  386,  385,
+      383,  380,  379,  378,  377,  376,  375,  374,  371,  370,
+      369,  368,  367,  366,  363,  361,  360,  357,  356,  355,
+
+      354,  353,  352,  351,  350,  349,  348,  347,  346,  343,
+      342,  341,  340,  339,  338,  337,  336,  335,  334,  333,
+      332,  331,  330,  328,  325,  324,  323,  322,  321,  320,
+      319,  318,  315,  314,  313,  312,  311,  309,  308,  307,
+      305,  303,  302,  301,  300,  299,  298,  296,  295,  294,
+      293,  292,  290,  289,  287,  286,  285,  284,  283,  282,
+      280,  278,  277,  276,  275,  274,  272,  271,  270,  269,
+      268,  266,  259,  258,  257,  256,  255,  254,  253,  252,
+      251,  250,  249,  248,  246,  245,  244,  243,  242,  241,
+      240,  238,  237,  236,  235,  234,  233,  232,  231,  229,
+
+      228,  227,  226,  225,  224,  223,  222,  221,  220,  219,
+      218,  217,  216,  215,  214,  213,  212,  211,  210,  209,
+      208,  207,  206,  205,  204,  203,  202,  201,  200,  198,
+      197,  195,  194,  193,  192,  191,  190,  187,  186,  184,
+      183,  182,  181,  180,  179,  178,  176,  175,  174,  172,
+      170,  169,  168,  167,  166,  165,  164,  163,  162,  161,
+      160,  158,  157,  156,  155,  147,  146,  145,  144,  143,
+      141,  140,  139,  135,  134,  133,  131,  130,  129,  128,
+      127,  126,  123,  122,  121,  117,  116,  115,  114,  113,
+      112,  111,  109,  108,  105,  104,  103,  101,  100,   98,
+
+       97,   96,   95,   94,   93,   92,   90,   88,   87,   86,
+       85,   84,   83,   81,   80,   78,   77,   76,   74,   72,
+       71,   70,   69,   68,   67,   66,   65,   53,   45,   44,
+       43,   38,   35,   32,   21,   20,   19,   11,    9,    7,
+        3,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+
+      908,  908,  908,  908,  908,  908,  908,  908,  908,  908,
+      908,  908,  908,  908,  908
     } ;
 
 static yy_state_type yy_last_accepting_state;
@@ -999,20 +1024,42 @@ char *gmsh_yytext;
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include "GmshConfig.h"
 #include "GmshMessage.h"
 #include "Geo.h"
 #include "Gmsh.tab.hpp"
+#include "GmshIO.h"
 
 void   parsestring(char endchar);
 char  *strsave(char *ptr);
 void   skipcomments(void);
 void   skipline(void);
 
+#if defined(HAVE_COMPRESSED_IO) && defined(HAVE_ZLIB)
+#define YY_INPUT(buf,result,max_size)                                   \
+     {                                                                  \
+       int c = '*', n;                                                  \
+       for ( n = 0; n < (int) max_size &&                               \
+               (c = gzgetc( gmsh_yyin )) != EOF && c != '\n'; ++n )          \
+         buf[n] = (char) c;                                             \
+       if ( c == '\n' ){                                                \
+         buf[n++] = (char) c;                                           \
+         gmsh_yylineno++;                                                    \
+       }                                                                \
+       if ( c == EOF )  {                                               \
+         int ernum;                                                     \
+         const char *msg=gzerror(gmsh_yyin,&ernum);                          \
+         if (ernum)                                                     \
+            Msg::Fatal("Input in flex scanner failed");                 \
+       }                                                                \
+       result = n;                                                      \
+     }
+#else
 #define YY_INPUT(buf,result,max_size)					\
      {									\
        int c = '*', n;							\
-       for ( n = 0; n < max_size &&					\
-	       (c = getc( gmsh_yyin )) != EOF && c != '\n'; ++n )		\
+       for ( n = 0; n < (int) max_size &&                               \
+	       (c = fgetc( gmsh_yyin )) != EOF && c != '\n'; ++n )		\
 	 buf[n] = (char) c;						\
        if ( c == '\n' ){						\
 	 buf[n++] = (char) c;						\
@@ -1021,14 +1068,15 @@ void   skipline(void);
        if ( c == EOF && ferror( gmsh_yyin ) )				\
 	 Msg::Fatal("Input in flex scanner failed");			\
        result = n;							\
-     }									\
+     }
+#endif
 
 #if defined(WIN32)
 #define isatty(arg) -1
 #define YY_NO_UNISTD_H
 #endif
 
-#line 1032 "Gmsh.yy.cpp"
+#line 1080 "Gmsh.yy.cpp"
 
 #define INITIAL 0
 
@@ -1210,10 +1258,10 @@ YY_DECL
 	register char *yy_cp, *yy_bp;
 	register int yy_act;
     
-#line 49 "Gmsh.l"
+#line 72 "Gmsh.l"
 
 
-#line 1217 "Gmsh.yy.cpp"
+#line 1265 "Gmsh.yy.cpp"
 
 	if ( !(yy_init) )
 		{
@@ -1266,13 +1314,13 @@ yy_match:
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 866 )
+				if ( yy_current_state >= 909 )
 					yy_c = yy_meta[(unsigned int) yy_c];
 				}
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 			++yy_cp;
 			}
-		while ( yy_base[yy_current_state] != 999 );
+		while ( yy_base[yy_current_state] != 1042 );
 
 yy_find_action:
 		yy_act = yy_accept[yy_current_state];
@@ -1299,901 +1347,931 @@ do_action:	/* This label is used only to access EOF actions. */
 case 1:
 /* rule 1 can match eol */
 YY_RULE_SETUP
-#line 51 "Gmsh.l"
+#line 74 "Gmsh.l"
 /* none */;
 	YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 52 "Gmsh.l"
+#line 75 "Gmsh.l"
 return tEND;
 	YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 53 "Gmsh.l"
+#line 76 "Gmsh.l"
 skipcomments();
 	YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 54 "Gmsh.l"
+#line 77 "Gmsh.l"
 skipline();
 	YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 55 "Gmsh.l"
+#line 78 "Gmsh.l"
 { parsestring('\"'); return tBIGSTR; }
 	YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 56 "Gmsh.l"
+#line 79 "Gmsh.l"
 { parsestring('\''); return tBIGSTR; }
 	YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 57 "Gmsh.l"
+#line 80 "Gmsh.l"
 { gmsh_yylval.d = NEWREG(); return tDOUBLE; }
 	YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 58 "Gmsh.l"
+#line 81 "Gmsh.l"
 { gmsh_yylval.d = NEWPOINT(); return tDOUBLE; }
 	YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 59 "Gmsh.l"
+#line 82 "Gmsh.l"
 { gmsh_yylval.d = NEWLINE(); return tDOUBLE; }
 	YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 60 "Gmsh.l"
+#line 83 "Gmsh.l"
 { gmsh_yylval.d = NEWLINE(); return tDOUBLE; }
 	YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 61 "Gmsh.l"
+#line 84 "Gmsh.l"
 { gmsh_yylval.d = NEWLINELOOP(); return tDOUBLE; }
 	YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 62 "Gmsh.l"
+#line 85 "Gmsh.l"
 { gmsh_yylval.d = NEWSURFACE(); return tDOUBLE; }
 	YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 63 "Gmsh.l"
+#line 86 "Gmsh.l"
 { gmsh_yylval.d = NEWSURFACELOOP(); return tDOUBLE; }
 	YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 64 "Gmsh.l"
+#line 87 "Gmsh.l"
 { gmsh_yylval.d = NEWVOLUME(); return tDOUBLE; }
 	YY_BREAK
 case 15:
 YY_RULE_SETUP
-#line 65 "Gmsh.l"
+#line 88 "Gmsh.l"
 { gmsh_yylval.d = NEWFIELD(); return tDOUBLE; }
 	YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 66 "Gmsh.l"
+#line 89 "Gmsh.l"
 return tAFFECT;
 	YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 67 "Gmsh.l"
+#line 90 "Gmsh.l"
 return tAFFECTPLUS;
 	YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 68 "Gmsh.l"
+#line 91 "Gmsh.l"
 return tAFFECTMINUS;
 	YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 69 "Gmsh.l"
+#line 92 "Gmsh.l"
 return tAFFECTTIMES;
 	YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 70 "Gmsh.l"
+#line 93 "Gmsh.l"
 return tAFFECTDIVIDE;
 	YY_BREAK
 case 21:
 YY_RULE_SETUP
-#line 71 "Gmsh.l"
+#line 94 "Gmsh.l"
 return tDOTS;
 	YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 72 "Gmsh.l"
+#line 95 "Gmsh.l"
 return tDOTS;
 	YY_BREAK
 case 23:
 YY_RULE_SETUP
-#line 73 "Gmsh.l"
+#line 96 "Gmsh.l"
 return tOR;
 	YY_BREAK
 case 24:
 YY_RULE_SETUP
-#line 74 "Gmsh.l"
+#line 97 "Gmsh.l"
 return tAND;
 	YY_BREAK
 case 25:
 YY_RULE_SETUP
-#line 75 "Gmsh.l"
+#line 98 "Gmsh.l"
 return tPLUSPLUS;
 	YY_BREAK
 case 26:
 YY_RULE_SETUP
-#line 76 "Gmsh.l"
+#line 99 "Gmsh.l"
 return tMINUSMINUS;
 	YY_BREAK
 case 27:
 YY_RULE_SETUP
-#line 77 "Gmsh.l"
+#line 100 "Gmsh.l"
 return tEQUAL;
 	YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 78 "Gmsh.l"
+#line 101 "Gmsh.l"
 return tNOTEQUAL;
 	YY_BREAK
 case 29:
 YY_RULE_SETUP
-#line 79 "Gmsh.l"
+#line 102 "Gmsh.l"
 return tLESSOREQUAL;
 	YY_BREAK
 case 30:
 YY_RULE_SETUP
-#line 80 "Gmsh.l"
+#line 103 "Gmsh.l"
 return tGREATEROREQUAL;
 	YY_BREAK
 case 31:
 YY_RULE_SETUP
-#line 82 "Gmsh.l"
+#line 105 "Gmsh.l"
 return tAbort;
 	YY_BREAK
 case 32:
 YY_RULE_SETUP
-#line 83 "Gmsh.l"
+#line 106 "Gmsh.l"
 return tAcos;
 	YY_BREAK
 case 33:
 YY_RULE_SETUP
-#line 84 "Gmsh.l"
+#line 107 "Gmsh.l"
 return tAdaptMesh;
 	YY_BREAK
 case 34:
 YY_RULE_SETUP
-#line 85 "Gmsh.l"
+#line 108 "Gmsh.l"
 return tAcos;
 	YY_BREAK
 case 35:
 YY_RULE_SETUP
-#line 86 "Gmsh.l"
+#line 109 "Gmsh.l"
 return tAlias;
 	YY_BREAK
 case 36:
 YY_RULE_SETUP
-#line 87 "Gmsh.l"
+#line 110 "Gmsh.l"
 return tAliasWithOptions;
 	YY_BREAK
 case 37:
 YY_RULE_SETUP
-#line 88 "Gmsh.l"
+#line 111 "Gmsh.l"
 return tAsin;
 	YY_BREAK
 case 38:
 YY_RULE_SETUP
-#line 89 "Gmsh.l"
+#line 112 "Gmsh.l"
 return tAsin;
 	YY_BREAK
 case 39:
 YY_RULE_SETUP
-#line 90 "Gmsh.l"
+#line 113 "Gmsh.l"
 return tAtan;
 	YY_BREAK
 case 40:
 YY_RULE_SETUP
-#line 91 "Gmsh.l"
+#line 114 "Gmsh.l"
 return tAtan;
 	YY_BREAK
 case 41:
 YY_RULE_SETUP
-#line 92 "Gmsh.l"
+#line 115 "Gmsh.l"
 return tAtan2;
 	YY_BREAK
 case 42:
 YY_RULE_SETUP
-#line 93 "Gmsh.l"
+#line 116 "Gmsh.l"
 return tAtan2;
 	YY_BREAK
 case 43:
 YY_RULE_SETUP
-#line 95 "Gmsh.l"
+#line 118 "Gmsh.l"
 return tBetti;
 	YY_BREAK
 case 44:
 YY_RULE_SETUP
-#line 96 "Gmsh.l"
+#line 119 "Gmsh.l"
 return tBezier;
 	YY_BREAK
 case 45:
 YY_RULE_SETUP
-#line 97 "Gmsh.l"
+#line 120 "Gmsh.l"
 return tBSpline;
 	YY_BREAK
 case 46:
 YY_RULE_SETUP
-#line 98 "Gmsh.l"
+#line 121 "Gmsh.l"
 return tBoundingBox;
 	YY_BREAK
 case 47:
 YY_RULE_SETUP
-#line 100 "Gmsh.l"
+#line 123 "Gmsh.l"
 return tCeil;
 	YY_BREAK
 case 48:
 YY_RULE_SETUP
-#line 101 "Gmsh.l"
+#line 124 "Gmsh.l"
 return tCircle;
 	YY_BREAK
 case 49:
 YY_RULE_SETUP
-#line 102 "Gmsh.l"
+#line 125 "Gmsh.l"
 return tCopyOptions;
 	YY_BREAK
 case 50:
 YY_RULE_SETUP
-#line 103 "Gmsh.l"
+#line 126 "Gmsh.l"
 return tCoherence;
 	YY_BREAK
 case 51:
 YY_RULE_SETUP
-#line 104 "Gmsh.l"
+#line 127 "Gmsh.l"
 return tCohomology;
 	YY_BREAK
 case 52:
 YY_RULE_SETUP
-#line 105 "Gmsh.l"
+#line 128 "Gmsh.l"
 return tCombine;
 	YY_BREAK
 case 53:
 YY_RULE_SETUP
-#line 106 "Gmsh.l"
+#line 129 "Gmsh.l"
 return tCosh;
 	YY_BREAK
 case 54:
 YY_RULE_SETUP
-#line 107 "Gmsh.l"
+#line 130 "Gmsh.l"
 return tCos;
 	YY_BREAK
 case 55:
 YY_RULE_SETUP
-#line 108 "Gmsh.l"
+#line 131 "Gmsh.l"
 return tCharacteristic;
 	YY_BREAK
 case 56:
 YY_RULE_SETUP
-#line 109 "Gmsh.l"
+#line 132 "Gmsh.l"
 return tComplex;
 	YY_BREAK
 case 57:
 YY_RULE_SETUP
-#line 110 "Gmsh.l"
+#line 133 "Gmsh.l"
 return tColor;
 	YY_BREAK
 case 58:
 YY_RULE_SETUP
-#line 111 "Gmsh.l"
+#line 134 "Gmsh.l"
 return tColorTable;
 	YY_BREAK
 case 59:
 YY_RULE_SETUP
-#line 112 "Gmsh.l"
+#line 135 "Gmsh.l"
 return tCompound;
 	YY_BREAK
 case 60:
 YY_RULE_SETUP
-#line 113 "Gmsh.l"
+#line 136 "Gmsh.l"
 return tCoordinates;
 	YY_BREAK
 case 61:
 YY_RULE_SETUP
-#line 114 "Gmsh.l"
+#line 137 "Gmsh.l"
 return tSpline;
 	YY_BREAK
 case 62:
 YY_RULE_SETUP
-#line 115 "Gmsh.l"
+#line 138 "Gmsh.l"
 return tCall;
 	YY_BREAK
 case 63:
 YY_RULE_SETUP
-#line 116 "Gmsh.l"
+#line 139 "Gmsh.l"
 return tCreateTopology;
 	YY_BREAK
 case 64:
 YY_RULE_SETUP
-#line 117 "Gmsh.l"
+#line 140 "Gmsh.l"
 return tCreateTopologyNoHoles;
 	YY_BREAK
 case 65:
 YY_RULE_SETUP
-#line 118 "Gmsh.l"
+#line 141 "Gmsh.l"
 return tCpu;
 	YY_BREAK
 case 66:
 YY_RULE_SETUP
-#line 120 "Gmsh.l"
+#line 143 "Gmsh.l"
 return tDefineConstant;
 	YY_BREAK
 case 67:
 YY_RULE_SETUP
-#line 121 "Gmsh.l"
-return tDelete;
+#line 144 "Gmsh.l"
+return tDefineNumber;
 	YY_BREAK
 case 68:
 YY_RULE_SETUP
-#line 122 "Gmsh.l"
-return tDegenerated;
+#line 145 "Gmsh.l"
+return tDefineString;
 	YY_BREAK
 case 69:
 YY_RULE_SETUP
-#line 123 "Gmsh.l"
-return tDilate;
+#line 146 "Gmsh.l"
+return tDelete;
 	YY_BREAK
 case 70:
 YY_RULE_SETUP
-#line 124 "Gmsh.l"
-return tDraw;
+#line 147 "Gmsh.l"
+return tDegenerated;
 	YY_BREAK
 case 71:
 YY_RULE_SETUP
-#line 125 "Gmsh.l"
-return tSetChanged;
+#line 148 "Gmsh.l"
+return tDilate;
 	YY_BREAK
 case 72:
 YY_RULE_SETUP
-#line 127 "Gmsh.l"
-return tExp;
+#line 149 "Gmsh.l"
+return tDraw;
 	YY_BREAK
 case 73:
 YY_RULE_SETUP
-#line 128 "Gmsh.l"
-return tEllipse;
+#line 150 "Gmsh.l"
+return tSetChanged;
 	YY_BREAK
 case 74:
 YY_RULE_SETUP
-#line 129 "Gmsh.l"
-return tEllipse;
+#line 152 "Gmsh.l"
+return tExp;
 	YY_BREAK
 case 75:
 YY_RULE_SETUP
-#line 130 "Gmsh.l"
-return tExtrude;
+#line 153 "Gmsh.l"
+return tEllipse;
 	YY_BREAK
 case 76:
 YY_RULE_SETUP
-#line 131 "Gmsh.l"
-return tElliptic;
+#line 154 "Gmsh.l"
+return tEllipse;
 	YY_BREAK
 case 77:
 YY_RULE_SETUP
-#line 132 "Gmsh.l"
-return tEndFor;
+#line 155 "Gmsh.l"
+return tExtrude;
 	YY_BREAK
 case 78:
 YY_RULE_SETUP
-#line 133 "Gmsh.l"
-return tEndIf;
+#line 156 "Gmsh.l"
+return tElliptic;
 	YY_BREAK
 case 79:
 YY_RULE_SETUP
-#line 134 "Gmsh.l"
-return tEuclidian;
+#line 157 "Gmsh.l"
+return tEndFor;
 	YY_BREAK
 case 80:
 YY_RULE_SETUP
-#line 135 "Gmsh.l"
-return tError;
+#line 158 "Gmsh.l"
+return tEndIf;
 	YY_BREAK
 case 81:
 YY_RULE_SETUP
-#line 136 "Gmsh.l"
-return tExit;
+#line 159 "Gmsh.l"
+return tEuclidian;
 	YY_BREAK
 case 82:
 YY_RULE_SETUP
-#line 138 "Gmsh.l"
-return tFabs;
+#line 160 "Gmsh.l"
+return tError;
 	YY_BREAK
 case 83:
 YY_RULE_SETUP
-#line 139 "Gmsh.l"
-return tField;
+#line 161 "Gmsh.l"
+return tExit;
 	YY_BREAK
 case 84:
 YY_RULE_SETUP
-#line 140 "Gmsh.l"
-return tFloor;
+#line 162 "Gmsh.l"
+return tExists;
 	YY_BREAK
 case 85:
 YY_RULE_SETUP
-#line 141 "Gmsh.l"
-return tFmod;
+#line 164 "Gmsh.l"
+return tFabs;
 	YY_BREAK
 case 86:
 YY_RULE_SETUP
-#line 142 "Gmsh.l"
-return tFor;
+#line 165 "Gmsh.l"
+return tField;
 	YY_BREAK
 case 87:
 YY_RULE_SETUP
-#line 143 "Gmsh.l"
-return tFunction;
+#line 166 "Gmsh.l"
+return tFileExists;
 	YY_BREAK
 case 88:
 YY_RULE_SETUP
-#line 145 "Gmsh.l"
-return tGetEnv;
+#line 167 "Gmsh.l"
+return tFloor;
 	YY_BREAK
 case 89:
 YY_RULE_SETUP
-#line 146 "Gmsh.l"
-return tGetString;
+#line 168 "Gmsh.l"
+return tFmod;
 	YY_BREAK
 case 90:
 YY_RULE_SETUP
-#line 147 "Gmsh.l"
-return tGetValue;
+#line 169 "Gmsh.l"
+return tFor;
 	YY_BREAK
 case 91:
 YY_RULE_SETUP
-#line 148 "Gmsh.l"
-return tGMSH_MAJOR_VERSION;
+#line 170 "Gmsh.l"
+return tFunction;
 	YY_BREAK
 case 92:
 YY_RULE_SETUP
-#line 149 "Gmsh.l"
-return tGMSH_MINOR_VERSION;
+#line 172 "Gmsh.l"
+return tGetEnv;
 	YY_BREAK
 case 93:
 YY_RULE_SETUP
-#line 150 "Gmsh.l"
-return tGMSH_PATCH_VERSION;
+#line 173 "Gmsh.l"
+return tGetString;
 	YY_BREAK
 case 94:
 YY_RULE_SETUP
-#line 152 "Gmsh.l"
-return tHide;
+#line 174 "Gmsh.l"
+return tGetValue;
 	YY_BREAK
 case 95:
 YY_RULE_SETUP
-#line 153 "Gmsh.l"
-return tHole;
+#line 175 "Gmsh.l"
+return tGMSH_MAJOR_VERSION;
 	YY_BREAK
 case 96:
 YY_RULE_SETUP
-#line 154 "Gmsh.l"
-return tHomology;
+#line 176 "Gmsh.l"
+return tGMSH_MINOR_VERSION;
 	YY_BREAK
 case 97:
 YY_RULE_SETUP
-#line 155 "Gmsh.l"
-return tHypot;
+#line 177 "Gmsh.l"
+return tGMSH_PATCH_VERSION;
 	YY_BREAK
 case 98:
 YY_RULE_SETUP
-#line 157 "Gmsh.l"
-return tIn;
+#line 179 "Gmsh.l"
+return tHide;
 	YY_BREAK
 case 99:
 YY_RULE_SETUP
-#line 158 "Gmsh.l"
-return tIf;
+#line 180 "Gmsh.l"
+return tHole;
 	YY_BREAK
 case 100:
 YY_RULE_SETUP
-#line 159 "Gmsh.l"
-return tIntersect;
+#line 181 "Gmsh.l"
+return tHomology;
 	YY_BREAK
 case 101:
 YY_RULE_SETUP
-#line 160 "Gmsh.l"
-return tInterpolationScheme;
+#line 182 "Gmsh.l"
+return tHypot;
 	YY_BREAK
 case 102:
 YY_RULE_SETUP
-#line 162 "Gmsh.l"
-return tNurbsKnots;
+#line 184 "Gmsh.l"
+return tIn;
 	YY_BREAK
 case 103:
 YY_RULE_SETUP
-#line 164 "Gmsh.l"
-return tLength;
+#line 185 "Gmsh.l"
+return tIf;
 	YY_BREAK
 case 104:
 YY_RULE_SETUP
-#line 165 "Gmsh.l"
-return tLine;
+#line 186 "Gmsh.l"
+return tIntersect;
 	YY_BREAK
 case 105:
 YY_RULE_SETUP
-#line 166 "Gmsh.l"
-return tList;
+#line 187 "Gmsh.l"
+return tInterpolationScheme;
 	YY_BREAK
 case 106:
 YY_RULE_SETUP
-#line 167 "Gmsh.l"
-return tLog;
+#line 189 "Gmsh.l"
+return tNurbsKnots;
 	YY_BREAK
 case 107:
 YY_RULE_SETUP
-#line 168 "Gmsh.l"
-return tLog10;
+#line 191 "Gmsh.l"
+return tLength;
 	YY_BREAK
 case 108:
 YY_RULE_SETUP
-#line 169 "Gmsh.l"
+#line 192 "Gmsh.l"
+return tLine;
+	YY_BREAK
+case 109:
+YY_RULE_SETUP
+#line 193 "Gmsh.l"
+return tList;
+	YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 194 "Gmsh.l"
+return tLog;
+	YY_BREAK
+case 111:
+YY_RULE_SETUP
+#line 195 "Gmsh.l"
+return tLog10;
+	YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 196 "Gmsh.l"
 return tLayers;
 	YY_BREAK
-case 109:
+case 113:
 YY_RULE_SETUP
-#line 170 "Gmsh.l"
+#line 197 "Gmsh.l"
 return tLevelset;
 	YY_BREAK
-case 110:
+case 114:
 YY_RULE_SETUP
-#line 172 "Gmsh.l"
+#line 199 "Gmsh.l"
 return tMeshAlgorithm;
 	YY_BREAK
-case 111:
+case 115:
 YY_RULE_SETUP
-#line 173 "Gmsh.l"
+#line 200 "Gmsh.l"
 return tModulo;
 	YY_BREAK
-case 112:
+case 116:
 YY_RULE_SETUP
-#line 174 "Gmsh.l"
+#line 201 "Gmsh.l"
 return tMPI_Rank;
 	YY_BREAK
-case 113:
+case 117:
 YY_RULE_SETUP
-#line 175 "Gmsh.l"
+#line 202 "Gmsh.l"
 return tMPI_Size;
 	YY_BREAK
-case 114:
+case 118:
 YY_RULE_SETUP
-#line 176 "Gmsh.l"
+#line 203 "Gmsh.l"
 return tMemory;
 	YY_BREAK
-case 115:
+case 119:
 YY_RULE_SETUP
-#line 178 "Gmsh.l"
+#line 205 "Gmsh.l"
 return tNurbs;
 	YY_BREAK
-case 116:
+case 120:
 YY_RULE_SETUP
-#line 180 "Gmsh.l"
+#line 207 "Gmsh.l"
+return tOnelabAction;
+	YY_BREAK
+case 121:
+YY_RULE_SETUP
+#line 208 "Gmsh.l"
 return tNurbsOrder;
 	YY_BREAK
-case 117:
+case 122:
 YY_RULE_SETUP
-#line 182 "Gmsh.l"
+#line 210 "Gmsh.l"
 return tPeriodic;
 	YY_BREAK
-case 118:
+case 123:
 YY_RULE_SETUP
-#line 183 "Gmsh.l"
+#line 211 "Gmsh.l"
 return tPhysical;
 	YY_BREAK
-case 119:
+case 124:
 YY_RULE_SETUP
-#line 184 "Gmsh.l"
+#line 212 "Gmsh.l"
 return tPi;
 	YY_BREAK
-case 120:
+case 125:
 YY_RULE_SETUP
-#line 185 "Gmsh.l"
+#line 213 "Gmsh.l"
 return tPlane;
 	YY_BREAK
-case 121:
+case 126:
 YY_RULE_SETUP
-#line 186 "Gmsh.l"
+#line 214 "Gmsh.l"
 return tPoint;
 	YY_BREAK
-case 122:
+case 127:
 YY_RULE_SETUP
-#line 187 "Gmsh.l"
+#line 215 "Gmsh.l"
 return tParametric;
 	YY_BREAK
-case 123:
+case 128:
 YY_RULE_SETUP
-#line 188 "Gmsh.l"
+#line 216 "Gmsh.l"
 return tPolarSphere;
 	YY_BREAK
-case 124:
+case 129:
 YY_RULE_SETUP
-#line 189 "Gmsh.l"
+#line 217 "Gmsh.l"
 return tPrintf;
 	YY_BREAK
-case 125:
+case 130:
 YY_RULE_SETUP
-#line 190 "Gmsh.l"
+#line 218 "Gmsh.l"
 return tPlugin;
 	YY_BREAK
-case 126:
+case 131:
 YY_RULE_SETUP
-#line 192 "Gmsh.l"
+#line 220 "Gmsh.l"
 return tQuadTriAddVerts;
 	YY_BREAK
-case 127:
+case 132:
 YY_RULE_SETUP
-#line 193 "Gmsh.l"
+#line 221 "Gmsh.l"
 return tQuadTriNoNewVerts;
 	YY_BREAK
-case 128:
+case 133:
 YY_RULE_SETUP
-#line 195 "Gmsh.l"
+#line 223 "Gmsh.l"
 return tQuadTriDbl;
 	YY_BREAK
-case 129:
+case 134:
 YY_RULE_SETUP
-#line 196 "Gmsh.l"
+#line 224 "Gmsh.l"
 return tQuadTriSngl;
 	YY_BREAK
-case 130:
+case 135:
 YY_RULE_SETUP
-#line 198 "Gmsh.l"
+#line 226 "Gmsh.l"
 return tRecombine;
 	YY_BREAK
-case 131:
+case 136:
 YY_RULE_SETUP
-#line 199 "Gmsh.l"
+#line 227 "Gmsh.l"
 return tRecombLaterals;
 	YY_BREAK
-case 132:
+case 137:
 YY_RULE_SETUP
-#line 200 "Gmsh.l"
+#line 228 "Gmsh.l"
 return tRecursive;
 	YY_BREAK
-case 133:
+case 138:
 YY_RULE_SETUP
-#line 201 "Gmsh.l"
+#line 229 "Gmsh.l"
 return tRotate;
 	YY_BREAK
-case 134:
+case 139:
 YY_RULE_SETUP
-#line 202 "Gmsh.l"
+#line 230 "Gmsh.l"
 return tRound;
 	YY_BREAK
-case 135:
+case 140:
 YY_RULE_SETUP
-#line 203 "Gmsh.l"
+#line 231 "Gmsh.l"
 return tRuled;
 	YY_BREAK
-case 136:
+case 141:
 YY_RULE_SETUP
-#line 204 "Gmsh.l"
+#line 232 "Gmsh.l"
 return tRand;
 	YY_BREAK
-case 137:
+case 142:
 YY_RULE_SETUP
-#line 205 "Gmsh.l"
+#line 233 "Gmsh.l"
 return tRefineMesh;
 	YY_BREAK
-case 138:
+case 143:
 YY_RULE_SETUP
-#line 206 "Gmsh.l"
+#line 234 "Gmsh.l"
 return tRelocateMesh;
 	YY_BREAK
-case 139:
+case 144:
 YY_RULE_SETUP
-#line 207 "Gmsh.l"
+#line 235 "Gmsh.l"
 return tReturn;
 	YY_BREAK
-case 140:
+case 145:
 YY_RULE_SETUP
-#line 208 "Gmsh.l"
+#line 236 "Gmsh.l"
 return tReverse;
 	YY_BREAK
-case 141:
+case 146:
 YY_RULE_SETUP
-#line 210 "Gmsh.l"
+#line 238 "Gmsh.l"
 return tScaleLast;
 	YY_BREAK
-case 142:
+case 147:
 YY_RULE_SETUP
-#line 211 "Gmsh.l"
+#line 239 "Gmsh.l"
 return tSmoother;
 	YY_BREAK
-case 143:
+case 148:
 YY_RULE_SETUP
-#line 212 "Gmsh.l"
+#line 240 "Gmsh.l"
 return tSetOrder;
 	YY_BREAK
-case 144:
+case 149:
 YY_RULE_SETUP
-#line 213 "Gmsh.l"
+#line 241 "Gmsh.l"
 return tSqrt;
 	YY_BREAK
-case 145:
+case 150:
 YY_RULE_SETUP
-#line 214 "Gmsh.l"
+#line 242 "Gmsh.l"
 return tSin;
 	YY_BREAK
-case 146:
+case 151:
 YY_RULE_SETUP
-#line 215 "Gmsh.l"
+#line 243 "Gmsh.l"
 return tSinh;
 	YY_BREAK
-case 147:
+case 152:
 YY_RULE_SETUP
-#line 216 "Gmsh.l"
+#line 244 "Gmsh.l"
 return tSphere;
 	YY_BREAK
-case 148:
+case 153:
 YY_RULE_SETUP
-#line 217 "Gmsh.l"
+#line 245 "Gmsh.l"
 return tSpline;
 	YY_BREAK
-case 149:
+case 154:
 YY_RULE_SETUP
-#line 218 "Gmsh.l"
+#line 246 "Gmsh.l"
 return tSplit;
 	YY_BREAK
-case 150:
+case 155:
 YY_RULE_SETUP
-#line 219 "Gmsh.l"
+#line 247 "Gmsh.l"
 return tSurface;
 	YY_BREAK
-case 151:
+case 156:
 YY_RULE_SETUP
-#line 220 "Gmsh.l"
+#line 248 "Gmsh.l"
 return tStr;
 	YY_BREAK
-case 152:
+case 157:
 YY_RULE_SETUP
-#line 221 "Gmsh.l"
+#line 249 "Gmsh.l"
 return tSprintf;
 	YY_BREAK
-case 153:
+case 158:
 YY_RULE_SETUP
-#line 222 "Gmsh.l"
+#line 250 "Gmsh.l"
 return tStrCat;
 	YY_BREAK
-case 154:
+case 159:
 YY_RULE_SETUP
-#line 223 "Gmsh.l"
+#line 251 "Gmsh.l"
 return tStrReplace;
 	YY_BREAK
-case 155:
+case 160:
 YY_RULE_SETUP
-#line 224 "Gmsh.l"
+#line 252 "Gmsh.l"
 return tStrPrefix;
 	YY_BREAK
-case 156:
+case 161:
 YY_RULE_SETUP
-#line 225 "Gmsh.l"
+#line 253 "Gmsh.l"
 return tStrRelative;
 	YY_BREAK
-case 157:
+case 162:
 YY_RULE_SETUP
-#line 226 "Gmsh.l"
+#line 254 "Gmsh.l"
 return tStrFind;
 	YY_BREAK
-case 158:
+case 163:
 YY_RULE_SETUP
-#line 227 "Gmsh.l"
+#line 255 "Gmsh.l"
 return tStrCmp;
 	YY_BREAK
-case 159:
+case 164:
 YY_RULE_SETUP
-#line 228 "Gmsh.l"
+#line 256 "Gmsh.l"
 return tShow;
 	YY_BREAK
-case 160:
+case 165:
 YY_RULE_SETUP
-#line 229 "Gmsh.l"
+#line 257 "Gmsh.l"
 return tSymmetry;
 	YY_BREAK
-case 161:
+case 166:
 YY_RULE_SETUP
-#line 230 "Gmsh.l"
+#line 258 "Gmsh.l"
 return tSyncModel;
 	YY_BREAK
-case 162:
+case 167:
 YY_RULE_SETUP
-#line 232 "Gmsh.l"
+#line 260 "Gmsh.l"
 return tText2D;
 	YY_BREAK
-case 163:
+case 168:
 YY_RULE_SETUP
-#line 233 "Gmsh.l"
+#line 261 "Gmsh.l"
 return tText3D;
 	YY_BREAK
-case 164:
+case 169:
 YY_RULE_SETUP
-#line 234 "Gmsh.l"
+#line 262 "Gmsh.l"
 return tTextAttributes;
 	YY_BREAK
-case 165:
+case 170:
 YY_RULE_SETUP
-#line 235 "Gmsh.l"
+#line 263 "Gmsh.l"
 return tTime;
 	YY_BREAK
-case 166:
+case 171:
 YY_RULE_SETUP
-#line 236 "Gmsh.l"
+#line 264 "Gmsh.l"
 return tTransfinite;
 	YY_BREAK
-case 167:
+case 172:
 YY_RULE_SETUP
-#line 237 "Gmsh.l"
+#line 265 "Gmsh.l"
 return tTransfQuadTri;
 	YY_BREAK
-case 168:
+case 173:
 YY_RULE_SETUP
-#line 238 "Gmsh.l"
+#line 266 "Gmsh.l"
 return tTranslate;
 	YY_BREAK
-case 169:
+case 174:
 YY_RULE_SETUP
-#line 239 "Gmsh.l"
+#line 267 "Gmsh.l"
 return tTanh;
 	YY_BREAK
-case 170:
+case 175:
 YY_RULE_SETUP
-#line 240 "Gmsh.l"
+#line 268 "Gmsh.l"
 return tTan;
 	YY_BREAK
-case 171:
+case 176:
 YY_RULE_SETUP
-#line 241 "Gmsh.l"
+#line 269 "Gmsh.l"
 return tToday;
 	YY_BREAK
-case 172:
+case 177:
 YY_RULE_SETUP
-#line 243 "Gmsh.l"
+#line 270 "Gmsh.l"
+return tTotalMemory;
+	YY_BREAK
+case 178:
+YY_RULE_SETUP
+#line 272 "Gmsh.l"
 return tUndefineConstant;
 	YY_BREAK
-case 173:
+case 179:
 YY_RULE_SETUP
-#line 244 "Gmsh.l"
+#line 273 "Gmsh.l"
 return tUsing;
 	YY_BREAK
-case 174:
+case 180:
 YY_RULE_SETUP
-#line 246 "Gmsh.l"
+#line 275 "Gmsh.l"
 return tVolume;
 	YY_BREAK
-case 175:
-#line 249 "Gmsh.l"
-case 176:
-#line 250 "Gmsh.l"
-case 177:
-#line 251 "Gmsh.l"
-case 178:
-YY_RULE_SETUP
-#line 251 "Gmsh.l"
+case 181:
+#line 278 "Gmsh.l"
+case 182:
+#line 279 "Gmsh.l"
+case 183:
+#line 280 "Gmsh.l"
+case 184:
+YY_RULE_SETUP
+#line 280 "Gmsh.l"
 { gmsh_yylval.d = atof((char *)gmsh_yytext); return tDOUBLE; }
 	YY_BREAK
-case 179:
+case 185:
 YY_RULE_SETUP
-#line 253 "Gmsh.l"
+#line 282 "Gmsh.l"
 { gmsh_yylval.c = strsave((char*)gmsh_yytext); return tSTRING; }
 	YY_BREAK
-case 180:
+case 186:
 YY_RULE_SETUP
-#line 255 "Gmsh.l"
+#line 284 "Gmsh.l"
 return gmsh_yytext[0];
 	YY_BREAK
-case 181:
+case 187:
 YY_RULE_SETUP
-#line 257 "Gmsh.l"
+#line 286 "Gmsh.l"
 ECHO;
 	YY_BREAK
-#line 2197 "Gmsh.yy.cpp"
+#line 2275 "Gmsh.yy.cpp"
 case YY_STATE_EOF(INITIAL):
 	yyterminate();
 
@@ -2485,7 +2563,7 @@ static int yy_get_next_buffer (void)
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 866 )
+			if ( yy_current_state >= 909 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -2513,11 +2591,11 @@ static int yy_get_next_buffer (void)
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 866 )
+		if ( yy_current_state >= 909 )
 			yy_c = yy_meta[(unsigned int) yy_c];
 		}
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 865);
+	yy_is_jam = (yy_current_state == 908);
 
 	return yy_is_jam ? 0 : yy_current_state;
 }
@@ -3190,7 +3268,7 @@ void gmsh_yyfree (void * ptr )
 
 #define YYTABLES_NAME "yytables"
 
-#line 257 "Gmsh.l"
+#line 286 "Gmsh.l"
 
 
 
@@ -3204,7 +3282,7 @@ void skipcomments(void)
 
   while (1) {
     while ((c = yyinput()) != '*'){
-      if(feof(gmsh_yyin)){
+      if(gmsheof(gmsh_yyin)){
 	Msg::Error("End of file in commented region");
         return;
       }
@@ -3224,7 +3302,7 @@ void parsestring(char endchar)
   // etc.) "as is" in the output string: see yyinput() above
   int i = 0;
   while ((c = yyinput()) != endchar) {
-    if(feof(gmsh_yyin)){
+    if(gmsheof(gmsh_yyin)){
       Msg::Error("End of file in string");
       break;
     }
@@ -3249,7 +3327,7 @@ void skipline()
 {
   int c;
   while ((c = yyinput()) != '\n'){
-    if(feof(gmsh_yyin)) return;
+    if(gmsheof(gmsh_yyin)) return;
   }
 }
 
@@ -3271,7 +3349,7 @@ void skip_until(const char *skip, const char *until)
   while(1){
     while (1){
       chars[0] = yyinput();
-      if(feof(gmsh_yyin)){
+      if(gmsheof(gmsh_yyin)){
 	Msg::Error("Unexpected end of file");
 	return;
       }
@@ -3286,7 +3364,7 @@ void skip_until(const char *skip, const char *until)
     }
     for(i=1; i<l; i++){
       chars[i] = yyinput();
-      if(feof(gmsh_yyin)){
+      if(gmsheof(gmsh_yyin)){
 	l = i;
 	break;
       }
diff --git a/Parser/Parser.h b/Parser/Parser.h
index eeff17c..8c30286 100644
--- a/Parser/Parser.h
+++ b/Parser/Parser.h
@@ -9,6 +9,7 @@
 #include <map>
 #include <string>
 #include <vector>
+#include "GmshIO.h"
 
 int gmsh_yyparse();
 int gmsh_yylex();
@@ -22,7 +23,7 @@ class gmsh_yysymbol{
 };
 
 // global parser variables that need to be exported
-extern FILE *gmsh_yyin;
+extern gmshFILE gmsh_yyin;
 extern int gmsh_yylineno;
 extern char *gmsh_yytext;
 extern int gmsh_yyviewindex;
@@ -31,4 +32,6 @@ extern int gmsh_yyerrorstate;
 extern std::map<std::string, gmsh_yysymbol> gmsh_yysymbols;
 extern std::map<std::string, std::string> gmsh_yystringsymbols;
 
+void PrintParserSymbols(bool help, std::vector<std::string> &vec);
+
 #endif
diff --git a/Plugin/AnalyseCurvedMesh.cpp b/Plugin/AnalyseCurvedMesh.cpp
index f99be26..657ccbc 100644
--- a/Plugin/AnalyseCurvedMesh.cpp
+++ b/Plugin/AnalyseCurvedMesh.cpp
@@ -3,18 +3,20 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
-#include "Gmsh.h"
-#include "GModel.h"
-#include "GmshMessage.h"
-
-#include "polynomialBasis.h"
 #include "AnalyseCurvedMesh.h"
+#include "GModel.h"
+#include "OS.h"
 #include "Context.h"
-#include <queue>
+
 #include <cmath>
-#include<fstream>
-#include "OS.h"
-#include "PView.h"
+#include <queue>
+#include <sstream>
+
+//#include "Gmsh.h"
+//#include "GmshMessage.h"
+//#include "polynomialBasis.h"
+//#include <fstream>
+//#include "PView.h"
 
 #if defined(HAVE_OPENGL)
 #include "drawContext.h"
@@ -24,29 +26,51 @@
 #endif
 
 namespace {
-  double sum(fullVector<double> &v)
-  {
-    double sum = .0;
-    for (int i = 0; i < v.size(); ++i) {
-      sum += v(i);
-    }
-    return sum;
+
+class BezierJacobian;
+struct lessMinVal {
+  bool operator()(BezierJacobian*, BezierJacobian*) const;
+};
+struct lessMax {
+  bool operator()(BezierJacobian*, BezierJacobian*) const;
+};
+
+class BezierJacobian
+{
+private:
+  fullVector<double> _jacBez;
+  double _minL, _maxL, _minB, _maxB; //Extremum of Jac at corners and of bezier values
+  int _depthSub;
+  const JacobianBasis *_jfs;
+
+public:
+  BezierJacobian(fullVector<double> &, const JacobianBasis *, int depth);
+  void subDivisions(fullVector<double> &vect) const
+    {_jfs->subdivideBezierCoeff(_jacBez, vect);}
+
+  bool boundsOk(double tol, double minL, double maxL) {
+    return (minL <= 0 || _minB > 0) &&
+           minL - _minB <= tol &&
+           _maxB - maxL <= tol;
   }
-}
 
-//#define UNDEF_JAC_TAG -999
-//#define _ANALYSECURVEDMESH_BLAS_
-
-StringXNumber JacobianOptions_Number[] = {
-  {GMSH_FULLRC, "Dim", NULL, -1},
-  {GMSH_FULLRC, "Analysis", NULL, 2},
-  {GMSH_FULLRC, "Effect (1)", NULL, 6},
-  {GMSH_FULLRC, "JacBreak (1)", NULL, .0},
-  {GMSH_FULLRC, "BezBreak (1)", NULL, .0},
-  {GMSH_FULLRC, "MaxDepth (1,2)", NULL, 20},
-  {GMSH_FULLRC, "Tolerance (2)", NULL, 1e-3}
+  inline int depth() const {return _depthSub;}
+  inline double minL() const {return _minL;}
+  inline double maxL() const {return _maxL;}
+  inline double minB() const {return _minB;}
+  inline double maxB() const {return _maxB;}
 };
 
+} // namespace
+
+StringXNumber CurvedMeshOptions_Number[] = {
+  {GMSH_FULLRC, "Show: (0) Jacobian, (1) Metric", NULL, 1},
+  {GMSH_FULLRC, "Number of PView", NULL, 2},
+  {GMSH_FULLRC, "Hidding threshold", NULL, .1},
+  {GMSH_FULLRC, "Dimension of elements", NULL, -1},
+  {GMSH_FULLRC, "Recompute bounds", NULL, 0},
+  {GMSH_FULLRC, "Tolerance", NULL, 1e-3}
+};
 extern "C"
 {
   GMSH_Plugin *GMSH_RegisterAnalyseCurvedMeshPlugin()
@@ -56,357 +80,183 @@ extern "C"
 }
 int GMSH_AnalyseCurvedMeshPlugin::getNbOptions() const
 {
-  return sizeof(JacobianOptions_Number) / sizeof(StringXNumber);
+  return sizeof(CurvedMeshOptions_Number) / sizeof(StringXNumber);
 }
-
 StringXNumber *GMSH_AnalyseCurvedMeshPlugin::getOption(int iopt)
 {
-  return &JacobianOptions_Number[iopt];
+  return &CurvedMeshOptions_Number[iopt];
 }
-
 std::string GMSH_AnalyseCurvedMeshPlugin::getHelp() const
 {
-  return "Plugin(AnalyseCurvedMesh) check the jacobian of all elements of dimension 'Dim' or "
-    "the greater model dimension if 'Dim' is either <0 or >3.\n\n "
-    "Analysis : 0 do nothing\n"
-    "          +1 find invalid elements (*)\n"
-    "          +2 compute J_min and J_max of all elements and print some statistics\n\n"
-    "Effect (for *) : 0 do nothing\n"
-    "                +1 print a list of invalid elements\n"
-    "                +2 print some statistics\n"
-    "                +4 hide valid elements (for GUI)\n\n"
-    "MaxDepth = 0,1,...\n"
-    "         0 : only sample the jacobian\n"
-    "         1 : compute Bezier coefficients\n"
-    "        2+ : execute a maximum of 1+ subdivision(s)\n\n"
-    "JacBreak = [0,1[ : if a value of the jacobian <= 'JacBreak' is found, "
-    "the element is said to be invalid\n\n"
-    "BezBreak = [0,JacBreak[ : if all Bezier coefficients are > 'BezBreak', "
-    "the element is said to be valid\n\n"
-    "Tolerance = R+ , << 1 : tolerance (relatively to J_min and J_max) used during the computation of J_min and J_max";
+  return "Plugin(AnalyseCurvedMesh) analyse all elements of a given dimension. "
+    "It computes, min(J) where J is the scaled Jacobian determinant. Eventually, "
+    "it computes min(R) where R is the ratio between the smaller and the greater "
+    "of the eigenvalues of the metric. It creates one or more PView and hides "
+    "elements for which min({J, R}) < 'Hidding threshold'.\n"
+    "\n"
+    "Parameters:\n"
+    "\n"
+    "- Show [...] = {0, 1}: If 0, computes Jacobian and shows min(J). If 1, computes "
+    "Jacobian and metric and shows min(R).\n"
+    "\n"
+    "- Number of PView = {0, 1, 2}: If 1, create one PView with all elements. If 2, create "
+    "two PView, one with straight-sided elements and one with curved elements.\n"
+    "\n"
+    "- Hidding threshold = [0,1]: Hides all element for which min(R) or min(J) "
+    "is strictly greater than the threshold. If = 1, no effect, if = 0 hide "
+    "all elements except invalid.\n"
+    "\n"
+    "- Dimension = {-1, 1, 2, 3}: If = -1, analyse element of the greater dimension.\n"
+    "\n"
+    "- Recompute = {0,1}: If the mesh has changed, set to 1 to recompute the bounds.\n"
+    "\n"
+    "- Tolerance = ]0, 1[: Tolerance on the computation of min(R) or min(J). "
+    "It should be at most 0.01 but it can be set to 1 to just check the validity of "
+    "the mesh.";
 }
 
 // Execution
 PView *GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
 {
   _m = GModel::current();
-  _dim = (int) JacobianOptions_Number[0].def;
-  if (_dim < 0 || _dim > 3)
-    _dim = _m->getDim();
-  int analysis = (int) JacobianOptions_Number[1].def % 4;
-  int toDo = (int) JacobianOptions_Number[2].def % 8;
-  _maxDepth = (int) JacobianOptions_Number[5].def;
-  _jacBreak = (double) JacobianOptions_Number[3].def;
-  _bezBreak = (double) JacobianOptions_Number[4].def;
-  _tol = (double) JacobianOptions_Number[6].def;
-
-  if (analysis % 2) {
-    double t = Cpu();
-    Msg::Info("Starting validity check...");
-    checkValidity(toDo);
-    Msg::Info("Done validity check (%fs)", Cpu()-t);
+  _computeMetric = static_cast<int>(CurvedMeshOptions_Number[0].def);
+  _numPView      = static_cast<int>(CurvedMeshOptions_Number[1].def);
+  _threshold     = static_cast<double>(CurvedMeshOptions_Number[2].def);
+  _dim           = static_cast<int>(CurvedMeshOptions_Number[3].def);
+  _recompute     = static_cast<bool>(CurvedMeshOptions_Number[4].def);
+  _tol           = static_cast<double>(CurvedMeshOptions_Number[5].def);
+
+  if (_dim < 0 || _dim > 3) _dim = _m->getDim();
+
+  if (_recompute) {
+    _data.clear();
+    _computedJ3D = false;
+    _computedJ2D = false;
+    _computedJ1D = false;
+    _computedR3D = false;
+    _computedR2D = false;
+    _msgHide = true;
+    _1PViewJ = false;
+    _2PViewJ = false;
+    _1PViewR = false;
+    _2PViewR = false;
   }
-  if (analysis / 2) {
-    double t = Cpu();
-    Msg::Info("Starting computation J_min, J_max...");
-    std::map<int, std::vector<double> > data;
-    computeMinMax(&data);
-    new PView("Jmin", "ElementData", _m, data);
-    Msg::Info("Done computation J_min, J_max (%fs)", Cpu()-t);
-  }
-  return 0;
-}
-
-void GMSH_AnalyseCurvedMeshPlugin::checkValidity(int toDo)
-{
-  std::vector<MElement*> invalids;
-  _numAnalysedEl = 0;
-  _numInvalid = 0;
-  _numValid = 0;
-  _numUncertain = 0;
-
-  switch (_dim) {
-    case 3 :
-      for(GModel::riter it = _m->firstRegion(); it != _m->lastRegion(); it++) {
-        GRegion *r = *it;
-        unsigned int numType[5] = {0, 0, 0, 0, 0};
-        r->getNumMeshElements(numType);
-
-        for(int type = 0; type < 5; type++) {
-          MElement *const *el = r->getStartElementType(type);
-          checkValidity(el, numType[type], invalids);
-          _numAnalysedEl += numType[type];
-        }
-      }
-      break;
-
-    case 2 :
-      Msg::Warning("2D elements must be in a z=cst plane ! If they aren't, results won't be correct.");
-
-      for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) {
-        GFace *f = *it;
-
-        unsigned int numType[3] = {0, 0, 0};
-        f->getNumMeshElements(numType);
-
-        for (int type = 0; type < 3; type++) {
-          MElement *const *el = f->getStartElementType(type);
-          for (unsigned int jo = 0; jo < numType[type]; jo++)
-            el[jo]->setVolumePositive();
-        }
-      }
-      for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) {
-        GFace *f = *it;
-        unsigned int numType[3] = {0, 0, 0};
-        f->getNumMeshElements(numType);
-
-        for (int type = 0; type < 3; type++) {
-          MElement *const *el = f->getStartElementType(type);
-          checkValidity(el, numType[type], invalids);
-          _numAnalysedEl += numType[type];
-        }
-      }
-      break;
-
-    case 1 :
-      Msg::Warning("1D elements must be on a y=cst & z=cst line ! If they aren't, results won't be correct.");
-      for (GModel::eiter it = _m->firstEdge(); it != _m->lastEdge(); it++) {
-        GEdge *e = *it;
-        unsigned int numElement = e->getNumMeshElements();
-        MElement *const *el = e->getStartElementType(0);
-        checkValidity(el, numElement, invalids);
-        _numAnalysedEl += numElement;
-      }
-      break;
 
-    default :
-      Msg::Error("I can't analyse any element.");
+  if ((_dim == 1 && !_computedJ1D) ||
+      (_dim == 2 && !_computedJ2D) ||
+      (_dim == 3 && !_computedJ3D)   ) {
+    double time = Cpu();
+    Msg::StatusBar(true, "Computing Jacobian for %dD elements...", _dim);
+    _computeMinMaxJandValidity();
+    Msg::StatusBar(true, "... Done computing Jacobian (%g seconds)", Cpu()-time);
+    _printStatJacobian();
   }
 
-  if (toDo % 2) {
-    Msg::Info("Invalids elements :");
-    Msg::Info("-------------------");
-    for (unsigned int i = 0; i < invalids.size(); ++i) {
-      Msg::Info(" %d", invalids[i]->getNum());
-    }
+  if (_computeMetric &&
+      ((_dim == 2 && !_computedR2D) ||
+       (_dim == 3 && !_computedR3D)   )) {
+    double time = Cpu();
+    Msg::StatusBar(true, "Computing metric for %dD elements...", _dim);
+    _computeMinR();
+    Msg::StatusBar(true, "... Done computing metric (%g seconds)", Cpu()-time);
+    _printStatMetric();
   }
-  if (toDo / 2 % 2) {
-    Msg::Info("Found %d invalid elements and %d valid", _numInvalid, _numValid);
-    if (_numUncertain) {
-      Msg::Info("%d uncertain elements.", _numUncertain);
-      if (_jacBreak < _bezBreak) {
-        Msg::Info("'JacBreak' is smaller than 'BezBreak'. Change values in order to decrease the number of uncertain elements.");
-      }
-      else {
-        Msg::Info("Increase MaxDepth in order to decrease the number of uncertain elements.");
-      }
-    }
-    Msg::Info("%d elements analysed", _numAnalysedEl);
-  }
-  if (toDo / 4 % 2) {
-    Msg::Info("Note: Valid elements are hidden. Change 'Effect' to disable this functionality.");
-    Msg::Info("(To revert visibility : Tools > Visibility > Interactive > Show All)");
-    hideValid_ShowInvalid(invalids);
-    CTX::instance()->mesh.changed = (ENT_ALL);
-#if defined(HAVE_FLTK)
-    FlGui::instance()->check();
-#endif
-#if defined(HAVE_OPENGL)
-    drawContext::global()->draw();
-#endif
-  }
-}
 
-void GMSH_AnalyseCurvedMeshPlugin::checkValidity(MElement *const*el,
-                                                 int numEl,
-                                                 std::vector<MElement*> &invalids)
-{
-  if (numEl < 1)
-    return;
-
-  const JacobianBasis *jfs = el[0]->getJacobianFuncSpace(-1);
-  const JacobianBasis *jfs1 = el[0]->getJacobianFuncSpace(1);
-  if (!jfs || !jfs1) {
-    Msg::Error("Jacobian function space not implemented for type of element %d", el[0]->getNum());
-    return;
+  if (_computeMetric &&
+      (_dim == 1 ||
+       (_dim == 2 && !_computedR2D) ||
+       (_dim == 3 && !_computedR3D))) {
+    return 0;
   }
-  const int numSamplingPt = jfs->getNumJacNodes(), numSamplingPt1 = jfs1->getNumJacNodes();
-  const int numMapNodes = jfs->getNumMapNodes(), numMapNodes1 = jfs1->getNumMapNodes();
-
-#ifdef _ANALYSECURVEDMESH_BLAS_
-  fullMatrix<double> jacobianB(numSamplingPt, numEl);
-  fullMatrix<double> jacBezB(numSamplingPt, numEl);
-  fullMatrix<double> jac1B(numSamplingPt1, numEl);
-  fullVector<double> jacBez, jacobian, jac1;
-
-  fullMatrix<double> nodesX(numMapNodes, numEl), nodesY(numMapNodes, numEl), nodesZ(numMapNodes, numEl);
-  fullMatrix<double> nodesX1(numMapNodes, numEl), nodesY1(numMapNodes, numEl), nodesZ1(numMapNodes, numEl);
-  for (int k = 0; k < numEl; ++k)
-    for (int i = 0; i < numMapNodes; ++i)
-    {
-      MVertex *v = (el[k])->getShapeFunctionNode(i);
-      nodesX(i,k) = v->x();
-      nodesY(i,k) = v->y();
-      nodesZ(i,k) = v->z();
-      if (i < numMapNodes1) {
-        nodesX1(i,k) = nodesX(i,k);
-        nodesY1(i,k) = nodesY(i,k);
-        nodesZ1(i,k) = nodesZ(i,k);
-      }
-    }
-
-  jfs->getSignedJacobian(nodesX, nodesY, nodesZ, jacobianB);
-  jfs1->getSignedJacobian(nodesX1, nodesY1, nodesZ1, jac1B);
-  jfs->lag2Bez(jacobianB, jacBezB);
-#else
-  fullVector<double> jacobian(numSamplingPt);
-  fullVector<double> jacBez(numSamplingPt);
-  fullVector<double> jac1(numSamplingPt1);
-#endif
-
-  for (int k = 0; k < numEl; ++k) {
-
-#ifdef _ANALYSECURVEDMESH_BLAS_
-    jacBez.setAsProxy(jacBezB, k);
-    jacobian.setAsProxy(jacobianB, k);
-    jac1.setAsProxy(jac1B, k);
-#else
-    fullMatrix<double> nodesXYZ(numMapNodes,3), nodesXYZ1(numMapNodes1,3);
-    el[k]->getNodesCoord(nodesXYZ);
-    nodesXYZ1.copy(nodesXYZ,0,numMapNodes1,0,3,0,0);
-    jfs->getSignedJacobian(nodesXYZ,jacobian);
-    jfs1->getSignedJacobian(nodesXYZ1,jac1);
-#endif
 
-    // AmJ : avgJ is not the average Jac for quad, prism or hex
-    double avgJ = sum(jac1) / jac1.size();
-    if (avgJ < 0) {
-      jacBez.scale(-1);
-      jacobian.scale(-1);
-      avgJ *= -1;
+  // Create PView
+
+  std::map<int, std::vector<double> > *dataPV1 = NULL;
+  std::map<int, std::vector<double> > *dataPV2 = NULL;
+  std::stringstream name1, name2;
+  if (_numPView == 1 &&
+      ((_computeMetric && !_1PViewR) || (!_computeMetric && !_1PViewJ))) {
+    dataPV1 = new std::map<int, std::vector<double> >();
+    if (_computeMetric) {
+      name1 << "min R";
+      _1PViewR = true;
     }
-
-    int i;
-    for (i = 0; i < numSamplingPt && jacobian(i) > _jacBreak * avgJ; ++i);
-    if (i < numSamplingPt) {
-      invalids.push_back(el[k]);
-      ++_numInvalid;
-      continue;
-    }
-
-    if (_maxDepth < 1) {
-      invalids.push_back(el[k]);
-      ++_numUncertain;
-      continue;
+    else {
+      name1 << "min J";
+      _1PViewJ = true;
     }
-
-#ifndef _ANALYSECURVEDMESH_BLAS_
-    jfs->lag2Bez(jacobian, jacBez);
-#endif
-
-    for (i = 0; i < jacBez.size() && jacBez(i) > _bezBreak * avgJ; ++i);
-    if (i >= jacBez.size()) {
-      ++_numValid;
-      continue;
+    for (unsigned int i = 0; i < _data.size(); ++i) {
+      MElement *const el = _data[i].element();
+      if (el->getDim() == _dim) {
+        double val = _computeMetric ? _data[i].minR() : _data[i].minJ();
+        (*dataPV1)[el->getNum()].push_back(val);
+      }
     }
-
-    if (_maxDepth < 2) {
-      invalids.push_back(el[k]);
-      ++_numUncertain;
-      continue;
+  }
+  else if (_numPView == 2 &&
+      ((_computeMetric && !_2PViewR) || (!_computeMetric && !_2PViewJ))) {
+    dataPV1 = new std::map<int, std::vector<double> >();
+    dataPV2 = new std::map<int, std::vector<double> >();
+    if (_computeMetric) {
+      name1 << "min R straight";
+      name2 << "min R curved";
+      _2PViewR = true;
     }
     else {
-      int result = subDivision(jfs, jacBez, _maxDepth-1);
-      if (result < 0) {
-        invalids.push_back(el[k]);
-        ++_numInvalid;
-        continue;
-      }
-      if (result > 0) {
-        ++_numValid;
-        continue;
+      name1 << "min J straight";
+      name2 << "min J curved";
+      _2PViewJ = true;
+    }
+    for (unsigned int i = 0; i < _data.size(); ++i) {
+      MElement *const el = _data[i].element();
+      if (el->getDim() == _dim) {
+        double val = _computeMetric ? _data[i].minR() : _data[i].minJ();
+        if (_data[i].maxJ() - _data[i].minJ() < _tol * 1e-2)
+          (*dataPV1)[el->getNum()].push_back(val);
+        else
+          (*dataPV2)[el->getNum()].push_back(val);
       }
-      invalids.push_back(el[k]);
-      ++_numUncertain;
-      continue;
     }
   }
-}
 
-int GMSH_AnalyseCurvedMeshPlugin::subDivision(const JacobianBasis *jb,
-                                              const fullVector<double> &jacobian,
-                                              int depth)
-{
-  fullVector<double> newJacobian(jb->getNumSubNodes());
-  jb->subdivideBezierCoeff(jacobian, newJacobian);
-
-  for (int i = 0; i < jb->getNumDivisions(); i++)
-  for (int j = 0; j < jb->getNumLagCoeff(); j++)
-  if (newJacobian(i * jb->getNumJacNodes() + j) <= _jacBreak)
-    return -1;
+  if (dataPV1) new PView(name1.str().c_str(), "ElementData", _m, *dataPV1);
+  if (dataPV2) new PView(name2.str().c_str(), "ElementData", _m, *dataPV2);
 
-  int i = 0;
-  while (i < newJacobian.size() && newJacobian(i) > _bezBreak)
-    ++i;
-  if (i >= newJacobian.size()) return 1;
+  //
 
-  if (depth <= 1) {
-    return 0;
+#if defined(HAVE_OPENGL)
+  if (_hideWithThreshold() && _msgHide) {
+    _msgHide = false;
+    Msg::Info("Note: Some elements have been hidden (param 'Hidding Threshold').");
+    Msg::Info("      (To revert visibility : Tools > Visibility > Interactive > Show All)");
   }
-  else{
-    fullVector<double> subJacobian;
-    std::vector<int> negTag, posTag;
-    bool zeroTag = false;
-
-    for (int i = 0; i < jb->getNumDivisions(); i++) {
-      subJacobian.setAsProxy(newJacobian, i * jacobian.size(), jacobian.size());
-      int tag = subDivision(jb, subJacobian, depth-1);
-
-      if (tag < 0)
-        negTag.push_back(tag);
-      else if (tag > 0)
-        posTag.push_back(tag);
-      else
-        zeroTag = true;
-    }
-
-    if (negTag.size() > 0)
-      return *std::min_element(negTag.begin(), negTag.end()) - 1;
-
-    if (zeroTag) return 0;
+  CTX::instance()->mesh.changed = (ENT_ALL);
+  drawContext::global()->draw();
+#endif
 
-    return *std::max_element(posTag.begin(), posTag.end()) + 1;
-  }
+  return 0;
 }
 
-
-void GMSH_AnalyseCurvedMeshPlugin::computeMinMax(std::map<int, std::vector<double> > *data)
+void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity()
 {
-  _numAnalysedEl = 0;
-  _numInvalid = 0;
-  _numValid = 0;
-  _numUncertain = 0;
-  _min_Javg = .0, _max_Javg = .0, _avg_Javg = .0;
-  _min_pJmin = .0, _avg_pJmin = .0;
-  _min_ratioJ = .0, _avg_ratioJ = .0;
-
   switch (_dim) {
     case 3 :
-      for(GModel::riter it = _m->firstRegion(); it != _m->lastRegion(); it++) {
+      if (_computedJ3D) break;
+      for (GModel::riter it = _m->firstRegion(); it != _m->lastRegion(); it++) {
         GRegion *r = *it;
         unsigned int numType[5] = {0, 0, 0, 0, 0};
         r->getNumMeshElements(numType);
 
         for(int type = 0; type < 5; type++) {
           MElement *const *el = r->getStartElementType(type);
-          computeMinMax(el, numType[type], data);
-          _numAnalysedEl += numType[type];
+          _computeMinMaxJandValidity(el, numType[type]);
         }
       }
+      _computedJ3D = true;
       break;
 
     case 2 :
-      Msg::Warning("2D elements must be in a z=cst plane ! If they aren't, results won't be correct.");
+      if (_computedJ2D) break;
       for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) {
         GFace *f = *it;
         unsigned int numType[3] = {0, 0, 0};
@@ -414,339 +264,285 @@ void GMSH_AnalyseCurvedMeshPlugin::computeMinMax(std::map<int, std::vector<doubl
 
         for (int type = 0; type < 3; type++) {
           MElement *const *el = f->getStartElementType(type);
-          computeMinMax(el, numType[type], data);
-          _numAnalysedEl += numType[type];
+          _computeMinMaxJandValidity(el, numType[type]);
         }
       }
+      _computedJ2D = true;
       break;
 
     case 1 :
-      Msg::Warning("1D elements must be on a y=cst & z=cst line ! If they aren't, results won't be correct.");
+      if (_computedJ1D) break;
       for (GModel::eiter it = _m->firstEdge(); it != _m->lastEdge(); it++) {
         GEdge *e = *it;
         unsigned int numElement = e->getNumMeshElements();
         MElement *const *el = e->getStartElementType(0);
-        computeMinMax(el, numElement, data);
-        _numAnalysedEl += numElement;
+        _computeMinMaxJandValidity(el, numElement);
       }
+      _computedJ1D = true;
       break;
 
     default :
-      Msg::Error("I can't analyse any element.");
+      Msg::Error("I can not analyse any element.");
       return;
   }
-  Msg::Info("Extrema of J_avg : %g, %g (avg: %g)", _min_Javg, _max_Javg, _avg_Javg/_numAnalysedEl);
-  Msg::Info("Minimum of min(~distortion) : %g", _min_pJmin);
-  Msg::Info("Average of min(~distortion) : %g", _avg_pJmin / _numAnalysedEl);
-  Msg::Info("Minimum of min(J) / max(J) : %g", _min_ratioJ);
-  Msg::Info("Average of min(J) / max(J) : %g", _avg_ratioJ / _numAnalysedEl);
 }
 
-void GMSH_AnalyseCurvedMeshPlugin::computeMinMax(MElement *const*el, int numEl, std::map<int, std::vector<double> > *data)
+void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(MElement *const*el, int numEl)
 {
   if (numEl < 1)
     return;
 
-  const JacobianBasis *jfs = el[0]->getJacobianFuncSpace(-1);
-  const JacobianBasis *jfs1 = el[0]->getJacobianFuncSpace(1);
-  if (!jfs || !jfs1) {
+  const JacobianBasis *jfs = el[0]->getJacobianFuncSpace();
+  if (!jfs) {
     Msg::Error("Jacobian function space not implemented for type of element %d", el[0]->getNum());
     return;
   }
 
-  const int numSamplingPt = jfs->getNumJacNodes(), numSamplingPt1 = jfs1->getNumJacNodes();
-  const int numMapNodes = jfs->getNumMapNodes(), numMapNodes1 = jfs1->getNumMapNodes();
-
-#ifdef _ANALYSECURVEDMESH_BLAS_
-  fullMatrix<double> jacobianB(numSamplingPt, numEl);
-  fullMatrix<double> jacBezB(numSamplingPt, numEl);
-  fullMatrix<double> jac1B(numSamplingPt1, numEl);
-  fullVector<double> jacBez, jacobian, jac1;
-
-  fullMatrix<double> nodesX(numMapNodes, numEl), nodesY(numMapNodes, numEl), nodesZ(numMapNodes, numEl);
-  fullMatrix<double> nodesX1(numMapNodes1, numEl), nodesY1(numMapNodes1, numEl), nodesZ1(numMapNodes1, numEl);
-  for (int k = 0; k < numEl; ++k)
-    for (int i = 0; i < numMapNodes; ++i)
-    {
-      MVertex *v = (el[k])->getShapeFunctionNode(i);
-      nodesX(i,k) = v->x();
-      nodesY(i,k) = v->y();
-      nodesZ(i,k) = v->z();
-      if (i < numMapNodes1) {
-        nodesX1(i,k) = nodesX(i,k);
-        nodesY1(i,k) = nodesY(i,k);
-        nodesZ1(i,k) = nodesZ(i,k);
-      }
-    }
-
-  jfs->getSignedJacobian(nodesX, nodesY, nodesZ, jacobianB);
-  jfs1->getSignedJacobian(nodesX, nodesY, nodesZ, jac1B);
-  jfs->lag2Bez(jacobianB, jacBezB);
-#else
+  const int numSamplingPt = jfs->getNumJacNodes();
+  const int numMapNodes = jfs->getNumMapNodes();
   fullVector<double> jacobian(numSamplingPt);
   fullVector<double> jacBez(numSamplingPt);
-  fullVector<double> jac1(numSamplingPt1);
-#endif
   fullVector<double> subJacBez(jfs->getNumSubNodes());
 
-  _min_Javg = 1.7e308;
-  _max_Javg = -1.7e308;
-  _min_pJmin = 1.7e308;
-  _min_ratioJ = 1.7e308;
-
-  std::ofstream fwrite("minDisto.txt");
-  fwrite << numEl << "\r";
-
   for (int k = 0; k < numEl; ++k) {
-
-#ifdef _ANALYSECURVEDMESH_BLAS_
-    jacBez.setAsProxy(jacBezB, k);
-    jacobian.setAsProxy(jacobianB, k);
-    jac1.setAsProxy(jac1B, k);
-#else
-    fullMatrix<double> nodesXYZ(numMapNodes,3), nodesXYZ1(numMapNodes1,3);
+    fullMatrix<double> nodesXYZ(numMapNodes,3);
     el[k]->getNodesCoord(nodesXYZ);
-    nodesXYZ1.copy(nodesXYZ,0,numMapNodes1,0,3,0,0);
-    jfs->getSignedJacobian(nodesXYZ,jacobian);
-    jfs1->getSignedJacobian(nodesXYZ1,jac1);
+    jfs->getScaledJacobian(nodesXYZ,jacobian);
     jfs->lag2Bez(jacobian, jacBez);
-#endif
 
-    // AmJ : avgJ is not the average Jac for quad, prism or hex
-    double avgJ = sum(jac1) / jac1.size();
-    if (avgJ < 0) {
-      jacBez.scale(-1);
-      jacobian.scale(-1);
-      avgJ *= -1;
-    }
+    BezierJacobian *bj = new BezierJacobian(jacBez, jfs, 0);
+    std::vector<BezierJacobian*> heap;
+    heap.push_back(bj);
 
-    double minJ, maxJ = minJ = jacobian(0);
+    double minL = bj->minL(), maxL = bj->maxL();
+    int currentDepth = 0;
 
-    for (int i = 1; i < numSamplingPt; ++i) {
-      if (jacobian(i) < minJ) minJ = jacobian(i);
-      if (jacobian(i) > maxJ) maxJ = jacobian(i);
-    }
+    while (!heap[0]->boundsOk(_tol, minL, maxL)) {
+      bj = heap[0];
+      pop_heap(heap.begin(), heap.end(), lessMinVal());
+      heap.pop_back();
 
-    double minB, maxB = minB = jacBez(0);//, avgJ = .0;
+      bj->subDivisions(subJacBez);
+      currentDepth = bj->depth() + 1;
+      if (currentDepth > 20) Msg::Error("depth is too damn high !");
 
-    for (int i = 1; i < numSamplingPt; ++i) {
-      if (jacBez(i) < minB) minB = jacBez(i);
-      if (jacBez(i) > maxB) maxB = jacBez(i);
-      //avgJ += jacBez(i);
-    }
-    //avgJ /= numSamplingPt;
-
-    _avg_Javg += avgJ;
-    _min_Javg = std::min(_min_Javg, avgJ);
-    _max_Javg = std::max(_max_Javg, avgJ);
-
-    if (_maxDepth > 1 &&
-        (minJ - minB > _tol * (std::abs(minJ) + std::abs(minB)) / 2 ||
-         maxB - maxJ > _tol * (std::abs(maxJ) + std::abs(maxB)) / 2   )) {
-
-      BezierJacobian *bj = new BezierJacobian(jacBez, jfs, 0);
-      std::set<BezierJacobian*> setBJ;
-      std::priority_queue<BezierJacobian*, std::vector<BezierJacobian*>, lessMinB> pqMin;
-      std::priority_queue<BezierJacobian*, std::vector<BezierJacobian*>, lessMaxB> pqMax;
-      setBJ.insert(bj);
-      pqMin.push(bj);
-
-      int currentDepth = 0;
-      while(minJ - minB > _tol * (std::abs(minJ) + std::abs(minB)) / 2 &&
-            pqMin.top()->depth() < _maxDepth-1) {
-        bj = pqMin.top();
-        bj->subDivisions(subJacBez);
-        currentDepth = bj->depth() + 1;
-        setBJ.erase(bj);
-        pqMin.pop();
-        delete bj;
-
-        for (int i = 0; i < jfs->getNumDivisions(); i++) {
-          jacBez.setAsProxy(subJacBez, i * numSamplingPt, numSamplingPt);
-          bj = new BezierJacobian(jacBez, jfs, currentDepth);
-          pqMin.push(bj);
-          setBJ.insert(bj);
-          minJ = std::min(minJ, bj->minJ());
-          maxJ = std::max(maxJ, bj->maxJ());
-        }
+      for (int i = 0; i < jfs->getNumDivisions(); i++) {
+        jacBez.setAsProxy(subJacBez, i * numSamplingPt, numSamplingPt);
+        bj = new BezierJacobian(jacBez, jfs, currentDepth);
+        minL = std::min(minL, bj->minL());
+        maxL = std::max(maxL, bj->maxL());
 
-        minB = minJ;
-        maxB = maxJ;
-        std::set<BezierJacobian*>::iterator it;
-        for (it = setBJ.begin(); it != setBJ.end(); ++it) {
-          minB = std::min(minB, (*it)->minB());
-          maxB = std::max(maxB, (*it)->maxB());
-        }
+        heap.push_back(bj);
+        push_heap(heap.begin(), heap.end(), lessMinVal());
       }
+    }
 
-      while (pqMin.size() > 0) {
-        bj = pqMin.top();
-        pqMin.pop();
-        pqMax.push(bj);
-      }
+    make_heap(heap.begin(), heap.end(), lessMax());
 
-      while(maxB - maxJ > _tol * (std::abs(maxJ) + std::abs(maxB)) / 2 &&
-            pqMax.top()->depth() < _maxDepth-1) {
-        bj = pqMax.top();
-        bj->subDivisions(subJacBez);
-        currentDepth = bj->depth() + 1;
-        setBJ.erase(bj);
-        pqMax.pop();
-        delete bj;
-
-        for (int i = 0; i < jfs->getNumDivisions(); i++) {
-          jacBez.setAsProxy(subJacBez, i * numSamplingPt, numSamplingPt);
-          bj = new BezierJacobian(jacBez, jfs, currentDepth);
-          pqMax.push(bj);
-          setBJ.insert(bj);
-          minJ = std::min(minJ, bj->minJ());
-          maxJ = std::max(maxJ, bj->maxJ());
-        }
+    while (!heap[0]->boundsOk(_tol, minL, maxL)) {
+      bj = heap[0];
+      pop_heap(heap.begin(), heap.end(), lessMax());
+      heap.pop_back();
 
-        minB = minJ;
-        maxB = maxJ;
-        std::set<BezierJacobian*>::iterator it;
-        for (it = setBJ.begin(); it != setBJ.end(); ++it) {
-          minB = std::min(minB, (*it)->minB());
-          maxB = std::max(maxB, (*it)->maxB());
-        }
-      }
+      bj->subDivisions(subJacBez);
+      currentDepth = bj->depth() + 1;
+      if (currentDepth > 20) Msg::Error("depth is too damn high !");
+
+      for (int i = 0; i < jfs->getNumDivisions(); i++) {
+        jacBez.setAsProxy(subJacBez, i * numSamplingPt, numSamplingPt);
+        bj = new BezierJacobian(jacBez, jfs, currentDepth);
+        minL = std::min(minL, bj->minL());
+        maxL = std::max(maxL, bj->maxL());
 
-      while (pqMax.size() > 0) {
-        bj = pqMax.top();
-        pqMax.pop();
-        delete bj;
+        heap.push_back(bj);
+        push_heap(heap.begin(), heap.end(), lessMax());
       }
     }
-    fwrite << minB/avgJ << " " << minB/maxB << "\r";
 
-    if (data){
-      if (1-minB <= _tol * minJ && maxB-1 <= _tol * maxB)
-        (*data)[el[k]->getNum()].push_back(1.);
-      else if (1-minB/avgJ <= 1e-8)
-        (*data)[el[k]->getNum()].push_back(1.);
-      else
-        (*data)[el[k]->getNum()].push_back(minB/avgJ);
+    double minB = minL;
+    double maxB = maxL;
+    for (unsigned int i = 0; i < heap.size(); ++i) {
+      minB = std::min(minB, heap[i]->minB());
+      maxB = std::max(maxB, heap[i]->maxB());
     }
-    _min_pJmin = std::min(_min_pJmin, minB/avgJ);
-    _avg_pJmin += minB/avgJ;
-    _min_ratioJ = std::min(_min_ratioJ, minB/maxB);
-    _avg_ratioJ += minB/maxB;
+
+    // TODO REMOVE #include "BasisFactory.h"
+
+    /*if (el[k]->getNum() == 26776) {
+      Msg::Info("%g %g %g %g", minB, minL, maxL, maxB);
+
+      / *const nodalBasis* nb = BasisFactory::getNodalBasis(el[k]->getTypeForMSH());
+      int tag1 = ElementType::getTag(el[k]->getType(), 1);
+      const nodalBasis* nb1 = BasisFactory::getNodalBasis(tag1);
+
+      //double *f;
+      //f = new double[nb1->points.size1()];
+      fullMatrix<double> f;
+      nb1->f(nb->points, f);
+      Msg::Info("SIZES [%d %d] (%d, %d)", f.size1(), f.size2(), nb->points.size1(), nb1->points.size1());
+
+      for (int i = 0; i < nb->points.size1(); ++i) {
+        double X[3] = {0, 0, 0};
+        for (int j = 0; j < f.size2(); ++j) {
+          X[0] += el[k]->getVertex(j)->x() * f(i, j);
+          X[1] += el[k]->getVertex(j)->y() * f(i, j);
+          X[2] += el[k]->getVertex(j)->z() * f(i, j);
+        }
+        if (std::abs(X[0] - el[k]->getVertex(i)->x()) < 1e-12 &&
+            std::abs(X[1] - el[k]->getVertex(i)->y()) < 1e-12 &&
+            std::abs(X[2] - el[k]->getVertex(i)->z()) < 1e-12);
+        else {
+          Msg::Info("aaarg %d/%d : [%g %g %g] ([%g %g %g])", i+1, nb->points.size1(),
+              el[k]->getVertex(i)->x(), el[k]->getVertex(i)->y(), el[k]->getVertex(i)->z(),
+              X[0], X[1], X[2]);
+        }
+      }* /
+    }*/
+
+    _data.push_back(CurvedMeshPluginData(el[k], minB, maxB));
   }
 }
 
-void GMSH_AnalyseCurvedMeshPlugin::hideValid_ShowInvalid(std::vector<MElement*> &invalids)
+void GMSH_AnalyseCurvedMeshPlugin::_computeMinR()
 {
-  unsigned int current = 0;
-  invalids.push_back(NULL);
+  if (_dim == 1 ||
+      (_dim == 2 && _computedR2D) ||
+      (_dim == 3 && _computedR3D)) {
+    return;
+  }
 
-  switch (_dim) {
-   case 3 :
-    for(GModel::riter it = _m->firstRegion(); it != _m->lastRegion(); it++) {
-      GRegion *r = *it;
-      unsigned int numType[5] = {0, 0, 0, 0, 0};
-      r->getNumMeshElements(numType);
-
-      for(int type = 0; type < 5; type++) {
-        MElement *const *el = r->getStartElementType(type);
-        for (unsigned int i = 0; i < numType[type]; ++i) {
-          if (el[i] == invalids[current]) {
-            ++current;
-            el[i]->setVisibility(1);
-          }
-          else
-            el[i]->setVisibility(0);
-        }
-      }
+  MetricBasis::setTol(_tol);
+
+  double initial, time = initial = Cpu();
+  unsigned int percentage = 0, nextCheck = 0;
+
+  for (unsigned int i = 0; i < _data.size(); ++i) {
+    MElement *const el = _data[i].element();
+    if (el->getDim() == _dim) {
+      if (_data[i].minJ() <= 0)
+        _data[i].setMinR(0);
+      else if (_data[i].maxJ() - _data[i].minJ() < _tol * 1e-2)
+        _data[i].setMinR(MetricBasis::sampleR(el, 0));
+      else
+        _data[i].setMinR(MetricBasis::boundMinR(el));
     }
-    break;
-
-   case 2 :
-    for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) {
-      GFace *f = *it;
-      unsigned int numType[3] = {0, 0, 0};
-      f->getNumMeshElements(numType);
-
-      for (int type = 0; type < 3; type++) {
-        MElement *const *el = f->getStartElementType(type);
-        for (unsigned int i = 0; i < numType[type]; ++i) {
-          if (el[i] == invalids[current]) {
-            ++current;
-            el[i]->setVisibility(1);
-          }
-          else
-            el[i]->setVisibility(0);
-        }
+    if (i >= nextCheck) {
+      nextCheck += _data.size() / 100;
+      if (Cpu() - time > 10. && i*100/_data.size() > percentage + 4) {
+        percentage = i*100/_data.size();
+        time = Cpu();
+        Msg::StatusBar(true, "%d%% (remaining time ~%g secondes)",
+            percentage, (Cpu()-initial) / (i+1) * (_data.size() - i-1));
       }
     }
-    break;
-
-   case 1 :
-    for (GModel::eiter it = _m->firstEdge(); it != _m->lastEdge(); it++) {
-      GEdge *e = *it;
-      unsigned int numElement = e->getNumMeshElements();
-      MElement *const *el = e->getStartElementType(0);
-      for (unsigned int i = 0; i < numElement; ++i) {
-        if (el[i] == invalids[current]) {
-          ++current;
-          el[i]->setVisibility(1);
-        }
-        else
-          el[i]->setVisibility(0);
+  }
+
+  if (_dim == 2) _computedR2D = true;
+  if (_dim == 3) _computedR3D = true;
+}
+
+bool GMSH_AnalyseCurvedMeshPlugin::_hideWithThreshold()
+{
+  if (_threshold >= 1.) return false;
+
+  bool ans = false;
+  for (unsigned int i = 0; i < _data.size(); ++i) {
+    MElement *const el = _data[i].element();
+    if (el->getDim() == _dim) {
+      if (( _computeMetric && _data[i].minR() > _threshold) ||
+          (!_computeMetric && _data[i].minJ() > _threshold)   ) {
+        el->setVisibility(0);
+        ans = true;
+      }
+      else {
+        el->setVisibility(1);
       }
     }
-    break;
-
-   default :
-    break;
   }
+  return ans;
+}
 
-  invalids.pop_back();
-
-  switch (_dim) {
-   case 3 :
-    for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++)
-      (*it)->setVisibility(0);
+void GMSH_AnalyseCurvedMeshPlugin::_printStatMetric()
+{
+  if (_data.empty()) {
+    Msg::Info("No stat to print...");
+    return;
+  }
+  double infminR, supminR, avgminR;
+  infminR = supminR = avgminR = _data[0].minR();
 
-   case 2 :
-    for (GModel::eiter it = _m->firstEdge(); it != _m->lastEdge(); it++)
-      (*it)->setVisibility(0);
+  for (unsigned int i = 1; i < _data.size(); ++i) {
+    infminR = std::min(infminR, _data[i].minR());
+    supminR = std::max(supminR, _data[i].minR());
+    avgminR += _data[i].minR();
+  }
+  avgminR /= _data.size();
 
-   case 1 :
-    for (GModel::viter it = _m->firstVertex(); it != _m->lastVertex(); it++)
-      (*it)->setVisibility(0);
+  Msg::Info("Minimum of R: in [%g, %g], avg=%g (R ~= measure of anisotropy)",
+      infminR, supminR, avgminR);
+}
 
-   default :
-    break;
+void GMSH_AnalyseCurvedMeshPlugin::_printStatJacobian()
+{
+  if (_data.empty()) {
+    Msg::Info("No stat to print...");
+    return;
   }
+  double infminJ, supminJ, avgminJ;
+  double infratJ, supratJ, avgratJ;
+  int count = 0;
+
+  infminJ = infratJ = 1e10;
+  supminJ = supratJ = -1e10;
+  avgminJ = avgratJ = 0;
+
+  for (unsigned int i = 0; i < _data.size(); ++i) {
+    if (_data[i].maxJ() - _data[i].minJ() > _tol * 1e-2) {
+      infminJ = std::min(infminJ, _data[i].minJ());
+      supminJ = std::max(supminJ, _data[i].minJ());
+      avgminJ += _data[i].minJ();
+      infratJ = std::min(infratJ, _data[i].minJ()/_data[i].maxJ());
+      supratJ = std::max(supratJ, _data[i].minJ()/_data[i].maxJ());
+      avgratJ += _data[i].minJ()/_data[i].maxJ();
+      ++count;
+    }
+  }
+  avgminJ /= count;
+  avgratJ /= count;
+
+  Msg::Info("Minimum of Jacobian: in [%g, %g], avg=%g (only the %d curved elem.)",
+      infminJ, supminJ, avgminJ, count);
+  Msg::Info("Ratio minJ/maxJ    : in [%g, %g], avg=%g (only the %d curved elem.)",
+      infratJ, supratJ, avgratJ, count);
 }
 
-BezierJacobian::BezierJacobian(fullVector<double> &v, const JacobianBasis *jfs, int depth)
+BezierJacobian::BezierJacobian(fullVector<double> &v,
+    const JacobianBasis *jfs, int depth)
 {
   _jacBez = v;
   _depthSub = depth;
   _jfs = jfs;
 
-  _minJ = _maxJ = v(0);
+  _minL = _maxL = v(0);
   int i = 1;
   for (; i < jfs->getNumLagCoeff(); i++) {
-    if (_minJ > v(i)) _minJ = v(i);
-    if (_maxJ < v(i)) _maxJ = v(i);
+    if (_minL > v(i)) _minL = v(i);
+    if (_maxL < v(i)) _maxL = v(i);
   }
-  _minB = _minJ;
-  _maxB = _maxJ;
+  _minB = _minL;
+  _maxB = _maxL;
   for (; i < v.size(); i++) {
     if (_minB > v(i)) _minB = v(i);
     if (_maxB < v(i)) _maxB = v(i);
   }
 }
 
-bool lessMinB::operator()(BezierJacobian *bj1, BezierJacobian *bj2) const
+bool lessMinVal::operator()(BezierJacobian *bj1, BezierJacobian *bj2) const
 {
   return bj1->minB() > bj2->minB();
 }
 
-bool lessMaxB::operator()(BezierJacobian *bj1, BezierJacobian *bj2) const
+bool lessMax::operator()(BezierJacobian *bj1, BezierJacobian *bj2) const
 {
   return bj1->maxB() < bj2->maxB();
 }
diff --git a/Plugin/AnalyseCurvedMesh.h b/Plugin/AnalyseCurvedMesh.h
index a16c68c..0fe626a 100644
--- a/Plugin/AnalyseCurvedMesh.h
+++ b/Plugin/AnalyseCurvedMesh.h
@@ -7,7 +7,10 @@
 #define _ANALYSECURVEDMESH_H_
 
 #include "Plugin.h"
+#include "JacobianBasis.h"
+#include "MetricBasis.h"
 #include "MElement.h"
+
 #include <vector>
 
 extern "C"
@@ -15,70 +18,71 @@ extern "C"
   GMSH_Plugin *GMSH_RegisterAnalyseCurvedMeshPlugin();
 }
 
-class GMSH_AnalyseCurvedMeshPlugin : public GMSH_PostPlugin
+class CurvedMeshPluginData
 {
-  private :
-    int _dim;
-    GModel *_m;
-    int _maxDepth;
-    double _jacBreak, _bezBreak, _tol;
-    
-    int _numAnalysedEl;
-    int _numInvalid, _numValid, _numUncertain;
-    double _min_Javg, _max_Javg, _avg_Javg;
-    double _min_pJmin, _avg_pJmin;
-    double _min_ratioJ, _avg_ratioJ;
-    
-  public :
-    GMSH_AnalyseCurvedMeshPlugin(){}
-    std::string getName() const { return "AnalyseCurvedMesh"; }
-    std::string getShortHelp() const {
-      return "Check validity of elements and/or compute min&max of the jacobian";
-    }
-    std::string getHelp() const;
-    std::string getAuthor() const { return "Amaury Johnen"; }
-    int getNbOptions() const;
-    StringXNumber *getOption(int);  
-    PView *execute(PView *);
-    void checkValidity(MElement *const *, int numEl, std::vector<MElement*> &invalids);
-    
-    //void storeJMin(MElement *const *, int numEl, std::map<int, std::vector<double> > &data);
-    
-    
-  private :
-    void checkValidity(int toDo);
-    void computeMinMax(std::map<int, std::vector<double> > *data = 0);
-    void computeMinMax(MElement *const *, int numEl, std::map<int, std::vector<double> > *data = 0);
-    int subDivision(const JacobianBasis *, const fullVector<double>&, int depth);
-    void hideValid_ShowInvalid(std::vector<MElement*> &invalids);
-};
+private:
+  MElement *_el;
+  double _minJ, _maxJ, _minR;
 
-class BezierJacobian;
-struct lessMinB {
-  bool operator()(BezierJacobian*, BezierJacobian*) const;
-};
-struct lessMaxB {
-  bool operator()(BezierJacobian*, BezierJacobian*) const;
+public:
+  CurvedMeshPluginData(MElement *e,
+                       double minJ = 2,
+                       double maxJ = 0,
+                       double minR = -1)
+    : _el(e), _minJ(minJ), _maxJ(maxJ), _minR(minR) {}
+
+  void setMinR(double r) {_minR = r;}
+  MElement* element() {return _el;}
+  double minJ() {return _minJ;}
+  double maxJ() {return _maxJ;}
+  double minR() {return _minR;}
 };
 
-class BezierJacobian
+class GMSH_AnalyseCurvedMeshPlugin : public GMSH_PostPlugin
 {
-private:
-  fullVector<double> _jacBez;
-  double _minJ, _maxJ, _minB, _maxB; //Extremum of Jac at corners and of bezier values
-  int _depthSub;
-  const JacobianBasis *_jfs;
-  
-public:
-  BezierJacobian(fullVector<double> &, const JacobianBasis *, int depth);
-  void subDivisions(fullVector<double> &vect) const
-    {_jfs->subdivideBezierCoeff(_jacBez, vect);}
-  
-  inline int depth() const {return _depthSub;}
-  inline double minJ() const {return _minJ;}
-  inline double maxJ() const {return _maxJ;}
-  inline double minB() const {return _minB;}
-  inline double maxB() const {return _maxB;}
+private :
+  int _dim;
+  GModel *_m;
+  double _threshold, _tol;
+  int _numPView, _computeMetric;
+  bool _recompute;
+  bool _computedR3D, _computedR2D;
+  bool _computedJ3D, _computedJ2D, _computedJ1D;
+  bool _1PViewJ, _2PViewJ, _1PViewR, _2PViewR;
+  bool _msgHide;
+
+  std::vector<CurvedMeshPluginData> _data;
+
+public :
+  GMSH_AnalyseCurvedMeshPlugin() {
+    _computedR3D = false;
+    _computedR2D = false;
+    _computedJ3D = false;
+    _computedJ2D = false;
+    _computedJ1D = false;
+    _msgHide = true;
+    _1PViewJ = false;
+    _2PViewJ = false;
+    _1PViewR = false;
+    _2PViewR = false;
+  }
+  std::string getName() const { return "AnalyseCurvedMesh"; }
+  std::string getShortHelp() const {
+    return "Compute bounds on Jacobian and metric quality.";
+  }
+  std::string getHelp() const;
+  std::string getAuthor() const { return "Amaury Johnen"; }
+  int getNbOptions() const;
+  StringXNumber *getOption(int);
+  PView *execute(PView *);
+
+private :
+  void _computeMinMaxJandValidity();
+  void _computeMinMaxJandValidity(MElement *const *, int numEl);
+  void _computeMinR();
+  bool _hideWithThreshold();
+  void _printStatMetric();
+  void _printStatJacobian();
 };
 
 #endif
diff --git a/Plugin/CMakeLists.txt b/Plugin/CMakeLists.txt
index 2545e44..48fc3a4 100644
--- a/Plugin/CMakeLists.txt
+++ b/Plugin/CMakeLists.txt
@@ -6,13 +6,13 @@
 set(SRC
   Plugin.cpp PluginManager.cpp
   Levelset.cpp
-    CutPlane.cpp CutSphere.cpp Isosurface.cpp
+  CutPlane.cpp CutSphere.cpp Isosurface.cpp
   Smooth.cpp CutParametric.cpp
   Lambda2.cpp
   Eigenvectors.cpp Eigenvalues.cpp
   StreamLines.cpp Particles.cpp CutGrid.cpp CutBox.cpp
   Transform.cpp
-    LongitudeLatitude.cpp
+  LongitudeLatitude.cpp
   Triangulate.cpp Tetrahedralize.cpp
   Warp.cpp SphericalRaise.cpp
   Skin.cpp
@@ -25,10 +25,11 @@ set(SRC
   HomologyComputation.cpp HomologyPostProcessing.cpp
   Distance.cpp ExtractEdges.cpp NearestNeighbor.cpp
   AnalyseCurvedMesh.cpp
+  CurvedBndDist.cpp
   FieldFromAmplitudePhase.cpp
   Bubbles.cpp NearToFarField.cpp
   DiscretizationError.cpp
-  Scal2Vec.cpp
+  Scal2Tens.cpp Scal2Vec.cpp
   CutMesh.cpp
   NewView.cpp
   SimplePartition.cpp Crack.cpp
diff --git a/Plugin/CurvedBndDist.cpp b/Plugin/CurvedBndDist.cpp
new file mode 100644
index 0000000..10d9c5d
--- /dev/null
+++ b/Plugin/CurvedBndDist.cpp
@@ -0,0 +1,166 @@
+// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
+#include "Gmsh.h"
+#include "GmshConfig.h"
+#include "GModel.h"
+#include "MElement.h"
+#include "PViewDataList.h"
+#include "BasisFactory.h"
+#include "CurvedBndDist.h"
+
+#if defined(HAVE_OPTHOM)
+#include "OptHomIntegralBoundaryDist.h"
+#endif
+
+extern "C"
+{
+  GMSH_Plugin *GMSH_RegisterCurvedBndDistPlugin()
+  {
+    return new GMSH_CurvedBndDistPlugin();
+  }
+}
+
+std::string GMSH_CurvedBndDistPlugin::getHelp() const
+{
+  return "Plugin(CurvedBndDist) ...";
+}
+
+static void addLine(PViewDataList *data, const SVector3 &p0, const SVector3 &p1, double v0, double v1)
+{
+  data->NbSL ++;
+  data->SL.push_back(p0.x()); data->SL.push_back(p1.x());
+  data->SL.push_back(p0.y()); data->SL.push_back(p1.y());
+  data->SL.push_back(p0.z()); data->SL.push_back(p1.z());
+  data->SL.push_back(v0); data->SL.push_back(v1);
+}
+
+/*
+static void addQua(PViewDataList *data, const SVector3 &p0, const SVector3 &p1,
+                   const SVector3 &p2, const SVector3 &p3, double v)
+{
+  data->NbSQ ++;
+  data->SQ.push_back(p0.x()); data->SQ.push_back(p1.x()); data->SQ.push_back(p2.x()); data->SQ.push_back(p3.x());
+  data->SQ.push_back(p0.y()); data->SQ.push_back(p1.y()); data->SQ.push_back(p2.y()); data->SQ.push_back(p3.y());
+  data->SQ.push_back(p0.z()); data->SQ.push_back(p1.z()); data->SQ.push_back(p2.z()); data->SQ.push_back(p3.z());
+  data->SQ.push_back(v); data->SQ.push_back(v); data->SQ.push_back(v); data->SQ.push_back(v);
+}
+
+static void addPoint(PViewDataList *data, const SVector3 &p0, double v0)
+{
+  data->NbSP ++;
+  data->SP.push_back(p0.x());
+  data->SP.push_back(p0.y());
+  data->SP.push_back(p0.z());
+  data->SP.push_back(v0);
+}
+
+static void addVP(PViewDataList *data, const SVector3 p0, SVector3 v)
+{
+  data->NbVP ++;
+  data->VP.push_back(p0.x());
+  data->VP.push_back(p0.y());
+  data->VP.push_back(p0.z());
+  data->VP.push_back(v.x());
+  data->VP.push_back(v.y());
+  data->VP.push_back(v.z());
+}
+*/
+
+#if defined(HAVE_OPTHOM)
+
+#include <limits>
+static void drawElementDist(PViewDataList *data, GEdge *edge,
+                            const std::vector<MVertex *>&vertices, const nodalBasis &basis)
+{
+  std::vector<double> gradient;
+  std::vector<double> param(vertices.size());
+  std::vector<bool> onEdge(vertices.size());
+  std::vector<SPoint3> xyz(vertices.size());
+  for (size_t i = 0; i < vertices.size(); ++i) {
+    MVertex *v = vertices[i];
+    reparamMeshVertexOnEdge(v, edge, param[i]);
+    onEdge[i] = v->onWhat() == edge;
+    xyz[i] = v->point();
+  }
+  parametricLineGEdge line0(edge, param[0], param[1]);
+  parametricLineNodalBasis line1(basis, xyz);
+  {
+    SPoint3 p,p1;
+    line0.hausdorffDistance(line1,p,p1);
+    addLine(data, p, p1, 0., 1);
+  }
+}
+
+/*
+static void drawElement(PViewDataList *data, GEdge *edge,
+                        const std::vector<MVertex *>&vertices, const nodalBasis &basis)
+{
+  std::vector<double> gradient;
+  std::vector<double> param(vertices.size());
+  std::vector<bool> onEdge(vertices.size());
+  std::vector<SPoint3> xyz(vertices.size());
+  for (size_t i = 0; i < vertices.size(); ++i) {
+    MVertex *v = vertices[i];
+    reparamMeshVertexOnEdge(v, edge, param[i]);
+    onEdge[i] = v->onWhat() == edge;
+    xyz[i] = v->point();
+  }
+  computeBndDistAndGradient(edge, param, vertices, basis, xyz, onEdge, gradient,1.e-6);
+  for (size_t i = 0; i < vertices.size(); ++i) {
+    double t0;
+    reparamMeshVertexOnEdge(vertices[i], edge, t0);
+    SPoint3 p = vertices[i]->point();
+    GPoint gpt =  edge->point(t0 + 1e-8);
+    SPoint3 pt(gpt.x(), gpt.y(), gpt.z());
+    SVector3 t = (pt - p);
+    t.normalize();
+    //addPoint(data, p, 0);
+    addVP(data, p, t * (-gradient[i]));
+  }
+}
+*/
+
+#endif
+
+PView *GMSH_CurvedBndDistPlugin::execute(PView *v)
+{
+#if defined(HAVE_OPTHOM)
+  PView *pv = new PView();
+  PViewDataList *data = getDataList(pv);
+  data->Time.push_back(0.);
+  GModel *m = GModel::current();
+  for (GModel::fiter iface = m->firstFace(); iface != m->lastFace(); ++iface) {
+    GFace *face = *iface;
+    for (size_t iElement = 0; iElement < face->getNumMeshElements(); ++iElement) {
+      MElement *element = face->getMeshElement(iElement);
+      const nodalBasis &elbasis = *element->getFunctionSpace();
+      for (int iEdge = 0; iEdge < element->getNumEdges(); ++iEdge) {
+	int clId = elbasis.getClosureId(iEdge, 1);
+        const std::vector<int> &closure = elbasis.closures[clId];
+        std::vector<MVertex *> vertices;
+        GEdge *edge = NULL;
+        for (size_t i = 0; i < closure.size(); ++i) {
+          MVertex *v = element->getVertex(closure[i]);
+          vertices.push_back(v);
+          if ((int)i >= 2 && v->onWhat() && v->onWhat()->dim() == 1) {
+            edge = v->onWhat()->cast2Edge();
+          }
+        }
+        if (edge){
+	  drawElementDist(data, edge, vertices,
+                          *BasisFactory::getNodalBasis(elbasis.getClosureType(clId)));
+	}
+      }
+    }
+  }
+  data->finalize();
+  return pv;
+#else
+  Msg::Error("Plugin requires OPTHOM module");
+  return v;
+#endif
+}
+
diff --git a/Plugin/CurvedBndDist.h b/Plugin/CurvedBndDist.h
new file mode 100644
index 0000000..904e5ba
--- /dev/null
+++ b/Plugin/CurvedBndDist.h
@@ -0,0 +1,29 @@
+// Gmsh - Copyright (C) 1997-2013 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
+#ifndef _CURVEDBNDDIST_H_
+#define _CURVEDBNDDIST_H_
+
+#include "Plugin.h"
+
+extern "C"
+{
+  GMSH_Plugin *GMSH_RegisterCurvedBndDistPlugin();
+}
+
+class GMSH_CurvedBndDistPlugin : public GMSH_PostPlugin
+{
+ public :
+  GMSH_CurvedBndDistPlugin(){}
+  std::string getName() const { return "CurvedBndDist"; }
+  std::string getShortHelp() const
+  {
+    return "Compute distance to curved boundary";
+  }
+  std::string getHelp() const;
+  std::string getAuthor() const { return "Jonathan Lambrechts"; }
+  PView *execute(PView *);
+};
+#endif
diff --git a/Plugin/Distance.cpp b/Plugin/Distance.cpp
index 930cfec..aa7b088 100644
--- a/Plugin/Distance.cpp
+++ b/Plugin/Distance.cpp
@@ -197,6 +197,14 @@ PView *GMSH_DistancePlugin::execute(PView *v)
 
   PView *view = new PView();
   _data = getDataList(view);
+
+  std::vector<GEntity*> _entities;
+  GModel::current()->getEntities(_entities);
+  if (!_entities.size() || !_entities[_entities.size()-1]->getMeshElement(0)) {
+    Msg::Error("This plugin needs a mesh !");
+    return view;
+  }
+
 #if defined(HAVE_SOLVER)
 #if defined(HAVE_TAUCS)
   linearSystemCSRTaucs<double> *lsys = new linearSystemCSRTaucs<double>;
@@ -209,13 +217,6 @@ PView *GMSH_DistancePlugin::execute(PView *v)
   dofManager<double> * dofView = new dofManager<double>(lsys);
 #endif
 
-  std::vector<GEntity*> _entities;
-  GModel::current()->getEntities(_entities);
-  if (!_entities.size() || !_entities[_entities.size()-1]->getMeshElement(0)) {
-    Msg::Error("This plugin needs a mesh !");
-    return view;
-  }
-
   GEntity* ge = _entities[_entities.size()-1];
   int integrationPointTetra[2] = {0,0};
 
@@ -326,10 +327,10 @@ PView *GMSH_DistancePlugin::execute(PView *v)
       if (id_pt != 0)   Msg::Error("The Physical Point does not exist !");
       if (id_line != 0) Msg::Error("The Physical Line does not exist !");
       if (id_face != 0) Msg::Error("The Physical Surface does not exist !");
-      return view;
     }
-
-    printView(_entities, _distance_map);
+    else{
+      printView(_entities, _distance_map);
+    }
 
     /* TO DO (by AM)
     printView(_entities, _closePts_map);
@@ -374,52 +375,45 @@ PView *GMSH_DistancePlugin::execute(PView *v)
       if (id_pt != 0)   Msg::Error("The Physical Point does not exist !");
       if (id_line != 0) Msg::Error("The Physical Line does not exist !");
       if (id_face != 0) Msg::Error("The Physical Surface does not exist !");
-      return view;
     }
-
-    std::vector<MElement *> allElems;
-    for(unsigned int ii = 0; ii < _entities.size(); ii++){
-      if(_entities[ii]->dim() == _maxDim) {
-        GEntity *ge = _entities[ii];
-        for(unsigned int i = 0; i < ge->getNumMeshElements(); ++i) {
-          MElement *t = ge->getMeshElement(i);
-          allElems.push_back(t);
-          for (int k = 0; k < t->getNumVertices(); k++)
-            dofView->numberVertex(t->getVertex(k), 0, 1);
+    else{
+      std::vector<MElement *> allElems;
+      for(unsigned int ii = 0; ii < _entities.size(); ii++){
+        if(_entities[ii]->dim() == _maxDim) {
+          GEntity *ge = _entities[ii];
+          for(unsigned int i = 0; i < ge->getNumMeshElements(); ++i) {
+            MElement *t = ge->getMeshElement(i);
+            allElems.push_back(t);
+            for (int k = 0; k < t->getNumVertices(); k++)
+              dofView->numberVertex(t->getVertex(k), 0, 1);
+          }
         }
       }
+      double L = norm(SVector3(bbox.max(), bbox.min()));
+      double mu = type*L;
+      simpleFunction<double> DIFF(mu*mu), ONE(1.0);
+      distanceTerm distance(GModel::current(), 1, &DIFF, &ONE);
+      for (std::vector<MElement* >::iterator it = allElems.begin();
+           it != allElems.end(); it++){
+        SElement se((*it));
+        distance.addToMatrix(*dofView, &se);
+      }
+      groupOfElements gr(allElems);
+      distance.addToRightHandSide(*dofView, gr);
+      Msg::Info("Distance Computation: Assembly done");
+      lsys->systemSolve();
+      Msg::Info("Distance Computation: System solved");
+      for (std::map<MVertex*,double >::iterator itv = _distance_map.begin();
+           itv != _distance_map.end() ; ++itv) {
+        MVertex *v = itv->first;
+        double value;
+        dofView->getDofValue(v, 0, 1, value);
+        value = std::min(0.9999, value);
+        double dist = -mu * log(1. - value);
+        itv->second = dist;
+      }
+      printView(_entities, _distance_map);
     }
-
-    double L = norm(SVector3(bbox.max(), bbox.min()));
-    double mu = type*L;
-
-    simpleFunction<double> DIFF(mu*mu), ONE(1.0);
-    distanceTerm distance(GModel::current(), 1, &DIFF, &ONE);
-
-    for (std::vector<MElement* >::iterator it = allElems.begin();
-         it != allElems.end(); it++){
-      SElement se((*it));
-      distance.addToMatrix(*dofView, &se);
-    }
-    groupOfElements gr(allElems);
-    distance.addToRightHandSide(*dofView, gr);
-
-    Msg::Info("Distance Computation: Assembly done");
-    lsys->systemSolve();
-    Msg::Info("Distance Computation: System solved");
-
-    for (std::map<MVertex*,double >::iterator itv = _distance_map.begin();
-         itv != _distance_map.end() ; ++itv) {
-      MVertex *v = itv->first;
-      double value;
-      dofView->getDofValue(v, 0, 1, value);
-      value = std::min(0.9999, value);
-      double dist = -mu * log(1. - value);
-      itv->second = dist;
-    }
-
-    printView(_entities, _distance_map);
-
 #endif
   }
 
@@ -577,5 +571,11 @@ PView *GMSH_DistancePlugin::execute(PView *v)
 #endif
   }
 
+
+#if defined(HAVE_SOLVER)
+  delete lsys;
+  delete dofView;
+#endif
+
   return view;
 }
diff --git a/Plugin/FieldFromAmplitudePhase.cpp b/Plugin/FieldFromAmplitudePhase.cpp
index 287bfe5..2cfc266 100644
--- a/Plugin/FieldFromAmplitudePhase.cpp
+++ b/Plugin/FieldFromAmplitudePhase.cpp
@@ -68,14 +68,14 @@ PView *GMSH_FieldFromAmplitudePhasePlugin::execute(PView *v)
   int phiView = (int)FieldFromAmplitudePhaseOptions_Number[2].def;
   std::string fileName = FieldFromAmplitudePhaseOptions_String[0].def;
 
-  std::string name_model("") ; 
+  std::string name_model("") ;
 
   if(fileName==""){
-    Msg::Info("Could not find mesh file for interpolating U=A*exp(j*k*phi)." 
+    Msg::Info("Could not find mesh file for interpolating U=A*exp(j*k*phi)."
                " Trying to use current model mesh, instead.") ;
-    name_model = GModel::current()->getName() ; 
+    name_model = GModel::current()->getName() ;
     fileName = name_model + ".msh" ;
-  } 
+  }
 
   PView *va = getView(aView, v);
   if(!va) return v;
@@ -91,52 +91,52 @@ PView *GMSH_FieldFromAmplitudePhasePlugin::execute(PView *v)
     return v;
   }
   PViewData *phiData = vphi->getData();
-  
+
   if(aData->hasMultipleMeshes() || phiData->hasMultipleMeshes()){
     Msg::Error("FieldFromAmplitudePhase plugin cannot be run on multi-mesh views");
     return v;
   }
 
   OctreePost *oA = 0, *oPhi = 0 ;
-  oA = new OctreePost(va); 
-  oPhi = new OctreePost(vphi); 
+  oA = new OctreePost(va);
+  oPhi = new OctreePost(vphi);
 
   GModel::current()->setVisibility(0);
-  GModel *umodel = new GModel ;  
-  umodel->readMSH(fileName) ; 
+  GModel *umodel = new GModel ;
+  umodel->readMSH(fileName) ;
   std::vector<GEntity*> _entities ;
-  umodel->getEntities(_entities) ;    
-     
+  umodel->getEntities(_entities) ;
+
   std::set<MVertex*> ve;
   std::map<int, std::vector<double> > dataR ;
   std::map<int, std::vector<double> > dataI ;
 
   for(unsigned int ent = 0; ent < _entities.size(); ent++)
-    for(unsigned int ele = 0; ele < _entities[ent]->getNumMeshElements(); ele++){ 
-      MElement *e = _entities[ent]->getMeshElement(ele);	
+    for(unsigned int ele = 0; ele < _entities[ent]->getNumMeshElements(); ele++){
+      MElement *e = _entities[ent]->getMeshElement(ele);
       for(int nod = 0; nod < e->getNumVertices() ; nod++)
         ve.insert(e->getVertex(nod));
     }
-  
+
   for (std::set<MVertex*>::iterator it = ve.begin(); it != ve.end(); ++it){
     double phi, ar, ai ;
     std::vector<double> uR(1) ;
     std::vector<double> uI(1) ;
-    oPhi->searchScalar((*it)->x(), (*it)->y(), (*it)->z(), &phi, 0);
-    oA->searchScalar((*it)->x(), (*it)->y(), (*it)->z(), &ar, 0);
-    oA->searchScalar((*it)->x(), (*it)->y(), (*it)->z(), &ai, 1);
-    
+    oPhi->searchScalarWithTol((*it)->x(), (*it)->y(), (*it)->z(), &phi, 0);
+    oA->searchScalarWithTol((*it)->x(), (*it)->y(), (*it)->z(), &ar, 0);
+    oA->searchScalarWithTol((*it)->x(), (*it)->y(), (*it)->z(), &ai, 1);
+
     uR[0] = ar * cos(k*phi) - ai * sin(k*phi) ;
     uI[0] = ar * sin(k*phi) + ai* cos(k*phi) ;
-    
-    dataR[(*it)->getNum()] = uR ;   
-    dataI[(*it)->getNum()] = uI ;   
+
+    dataR[(*it)->getNum()] = uR ;
+    dataI[(*it)->getNum()] = uI ;
   }
-  
+
   delete oA ;
   delete oPhi;
-    
-  PView *vu = new PView("FieldFromAPhi","NodeData", umodel, dataR, 0.0, 1) ;
+
+  PView *vu = new PView("FieldFromAPhi", "NodeData", umodel, dataR, 0.0, 1) ;
   vu->addStep(umodel, dataI, 1);
 
   if(name_model.empty())
diff --git a/Plugin/HomologyComputation.cpp b/Plugin/HomologyComputation.cpp
index 2caccf9..44eb97d 100644
--- a/Plugin/HomologyComputation.cpp
+++ b/Plugin/HomologyComputation.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #include <stdlib.h>
 #include <string>
diff --git a/Plugin/HomologyComputation.h b/Plugin/HomologyComputation.h
index 8b8425c..0d38d73 100644
--- a/Plugin/HomologyComputation.h
+++ b/Plugin/HomologyComputation.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #ifndef _HOMOLOGY_COMPUTATION_H_
 #define _HOMOLOGY_COMPUTATION_H_
diff --git a/Plugin/HomologyPostProcessing.cpp b/Plugin/HomologyPostProcessing.cpp
index ac72c87..656acc8 100644
--- a/Plugin/HomologyPostProcessing.cpp
+++ b/Plugin/HomologyPostProcessing.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #include <stdlib.h>
 #include <string>
diff --git a/Plugin/HomologyPostProcessing.h b/Plugin/HomologyPostProcessing.h
index a4a1183..6eb4ed1 100644
--- a/Plugin/HomologyPostProcessing.h
+++ b/Plugin/HomologyPostProcessing.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 //
-// Contributed by Matti Pellikka <matti.pellikka at tut.fi>.
+// Contributed by Matti Pellikka <matti.pellikka at microsoft.com>.
 
 #ifndef _HOMOLOGY_POST_PROCESSING_H_
 #define _HOMOLOGY_POST_PROCESSING_H_
diff --git a/Plugin/Integrate.cpp b/Plugin/Integrate.cpp
index 4d22d96..be2f253 100644
--- a/Plugin/Integrate.cpp
+++ b/Plugin/Integrate.cpp
@@ -79,7 +79,7 @@ PView *GMSH_IntegratePlugin::execute(PView * v)
 	  int numNodes = data1->getNumNodes(step, ent, ele);
 	  int dim = data1->getDimension(step, ent, ele);
           if((dimension>0) && (dim!=dimension)) continue;
-	  double x[8], y[8], z[8], val[8 * 3];
+	  double x[8], y[8], z[8], val[8 * 3] = {0.};
 	  for(int nod = 0; nod < numNodes; nod++){
 	    data1->getNode(step, ent, ele, nod, x[nod], y[nod], z[nod]);
 	    for(int comp = 0; comp < numComp; comp++)
diff --git a/Plugin/Lambda2.h b/Plugin/Lambda2.h
index 30dbc45..a910455 100644
--- a/Plugin/Lambda2.h
+++ b/Plugin/Lambda2.h
@@ -4,7 +4,7 @@
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
 #ifndef _LAMBDA2_H_
-#define _LAMBDA2_H
+#define _LAMBDA2_H_
 
 #include "Plugin.h"
 
@@ -25,7 +25,7 @@ class GMSH_Lambda2Plugin : public GMSH_PostPlugin
   std::string getHelp() const;
   std::string getAuthor() const { return "E. Marchandise"; }
   int getNbOptions() const;
-  StringXNumber* getOption(int iopt);  
+  StringXNumber* getOption(int iopt);
   PView *execute(PView *);
 };
 
diff --git a/Plugin/LongitudeLatitude.cpp b/Plugin/LongitudeLatitude.cpp
index 07af390..a4864c9 100644
--- a/Plugin/LongitudeLatitude.cpp
+++ b/Plugin/LongitudeLatitude.cpp
@@ -39,21 +39,23 @@ StringXNumber *GMSH_LongituteLatitudePlugin::getOption(int iopt)
 PView *GMSH_LongituteLatitudePlugin::execute(PView *v)
 {
   int iView = (int)LongituteLatitudeOptions_Number[0].def;
-  
+
   PView *v1 = getView(iView, v);
   if(!v1) return v;
   PViewData *data1 = v1->getData();
 
-  // tag all the nodes with "0" (the default tag)
-  for(int step = 0; step < data1->getNumTimeSteps(); step++){
-    for(int ent = 0; ent < data1->getNumEntities(step); ent++){
-      for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
-        if(data1->skipElement(step, ent, ele)) continue;
-        for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
-          data1->tagNode(step, ent, ele, nod, 0);
+  if(data1->isNodeData()){
+    // tag all the nodes with "0" (the default tag)
+    for(int step = 0; step < data1->getNumTimeSteps(); step++){
+      for(int ent = 0; ent < data1->getNumEntities(step); ent++){
+        for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
+          if(data1->skipElement(step, ent, ele)) continue;
+          for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
+            data1->tagNode(step, ent, ele, nod, 0);
+        }
       }
     }
-  } 
+  }
   double gxmin = 180, gxmax = -180, gymin = 90, gymax = -90;
   // transform all "0" nodes
   for(int step = 0; step < data1->getNumTimeSteps(); step++){
@@ -66,32 +68,31 @@ PView *GMSH_LongituteLatitudePlugin::execute(PView *v)
         for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++){
           double x, y, z;
           int tag = data1->getNode(step, ent, ele, nod, x, y, z);
-          if(!tag){
-            double x2, y2, z2;
-            z2 = sqrt(x * x + y * y + z * z);
-            y2 = asin(z / z2);
-            x2 = atan2(y, x);
-            xmin=std::min(x2, xmin);
-            xmax=std::max(x2, xmax);
-            gxmin = std::min(x2 * 180 / M_PI, gxmin);
-            gxmax = std::max(x2 * 180 / M_PI, gxmax);
-            gymin = std::min(y2 * 180 / M_PI, gymin);
-            gymax = std::max(y2 * 180 / M_PI, gymax);
-            data1->setNode(step, ent, ele, nod, x2 * 180 / M_PI, y2 * 180 / M_PI, 0);
-            data1->tagNode(step, ent, ele, nod, 1);
-            if(nbComp == 3){
-              for(int i = 0; i < 3; i++)
-                data1->getValue(step, ent, ele, nod, i, vin[i]);
-              vout[0] = -sin(x2) * vin[0] + cos(x2) * vin[1];
-              vout[1] =
-                -sin(y2) * (cos(x2) * vin[0] + sin(x2) * vin[1]) +
-                cos(y2) * vin[2];
-              vout[2] =
-                cos(y2) * (cos(x2) * vin[0] + sin(x2) * vin[1]) +
-                sin(y2) * vin[2];
-              for(int i = 0; i < 3; i++)
-                data1->setValue(step, ent, ele, nod, i, vout[i]);
-            }
+          if(data1->isNodeData() && tag) continue;
+          double x2, y2, z2;
+          z2 = sqrt(x * x + y * y + z * z);
+          y2 = asin(z / z2);
+          x2 = atan2(y, x);
+          xmin=std::min(x2, xmin);
+          xmax=std::max(x2, xmax);
+          gxmin = std::min(x2 * 180 / M_PI, gxmin);
+          gxmax = std::max(x2 * 180 / M_PI, gxmax);
+          gymin = std::min(y2 * 180 / M_PI, gymin);
+          gymax = std::max(y2 * 180 / M_PI, gymax);
+          data1->setNode(step, ent, ele, nod, x2 * 180 / M_PI, y2 * 180 / M_PI, 0);
+          if(data1->isNodeData()) data1->tagNode(step, ent, ele, nod, 1);
+          if(nbComp == 3){
+            for(int i = 0; i < 3; i++)
+              data1->getValue(step, ent, ele, nod, i, vin[i]);
+            vout[0] = -sin(x2) * vin[0] + cos(x2) * vin[1];
+            vout[1] =
+              -sin(y2) * (cos(x2) * vin[0] + sin(x2) * vin[1]) +
+              cos(y2) * vin[2];
+            vout[2] =
+              cos(y2) * (cos(x2) * vin[0] + sin(x2) * vin[1]) +
+              sin(y2) * vin[2];
+            for(int i = 0; i < 3; i++)
+              data1->setValue(step, ent, ele, nod, i, vout[i]);
           }
         }
         if(xmax - xmin > M_PI){ // periodicity check (broken for continuous views)
diff --git a/Plugin/MathEval.cpp b/Plugin/MathEval.cpp
index bdb926a..9c232aa 100644
--- a/Plugin/MathEval.cpp
+++ b/Plugin/MathEval.cpp
@@ -126,14 +126,6 @@ PView *GMSH_MathEvalPlugin::execute(PView *view)
     return view;
   }
 
-  OctreePost *octree = 0;
-  if(forceInterpolation ||
-     (data1->getNumEntities() != otherData->getNumEntities()) ||
-     (data1->getNumElements() != otherData->getNumElements())){
-    Msg::Info("Other view based on different grid: interpolating...");
-    octree = new OctreePost(otherView);
-  }
-
   if(otherTimeStep < 0 && otherData->getNumTimeSteps() != data1->getNumTimeSteps()){
     Msg::Error("Number of time steps don't match: using step 0");
     otherTimeStep = 0;
@@ -171,6 +163,14 @@ PView *GMSH_MathEvalPlugin::execute(PView *view)
   if(expr.empty()) return view;
   std::vector<double> values(numVariables), res(numComp2);
 
+  OctreePost *octree = 0;
+  if(forceInterpolation ||
+     (data1->getNumEntities() != otherData->getNumEntities()) ||
+     (data1->getNumElements() != otherData->getNumElements())){
+    Msg::Info("Other view based on different grid: interpolating...");
+    octree = new OctreePost(otherView);
+  }
+
   PView *v2 = new PView();
   PViewDataList *data2 = getDataList(v2);
 
@@ -236,14 +236,21 @@ PView *GMSH_MathEvalPlugin::execute(PView *view)
           values[0] = x[nod]; values[1] = y[nod]; values[2] = z[nod];
           for(int i = 0; i < 9; i++) values[3 + i] = v[i];
           for(int i = 0; i < 9; i++) values[12 + i] = w[i];
-          if(f.eval(values, res))
+          if(f.eval(values, res)){
             for(int i = 0; i < numComp2; i++)
               out->push_back(res[i]);
+          }
+          else{
+            goto end;
+          }
         }
       }
     }
   }
 
+ end:
+  if(octree) delete octree;
+
   if(timeStep < 0){
     for(int i = firstNonEmptyStep; i < data1->getNumTimeSteps(); i++) {
       if(!data1->hasTimeStep(i)) continue;
diff --git a/Plugin/MinMax.cpp b/Plugin/MinMax.cpp
index 13e812c..3b0c060 100644
--- a/Plugin/MinMax.cpp
+++ b/Plugin/MinMax.cpp
@@ -44,16 +44,16 @@ PView *GMSH_MinMaxPlugin::execute(PView * v)
   int iView = (int)MinMaxOptions_Number[0].def;
   int overTime = (int)MinMaxOptions_Number[1].def;
   int argument = (int)MinMaxOptions_Number[2].def;
-  
+
   PView *v1 = getView(iView, v);
   if(!v1) return v;
 
-  PViewData *data1 = v1->getData();
+  PViewData *data1 = v1->getData(true);
   PView *vMin = new PView();
   PView *vMax = new PView();
   PViewDataList *dataMin = getDataList(vMin);
   PViewDataList *dataMax = getDataList(vMax);
-  
+
   if(!argument){
     double x = data1->getBoundingBox().center().x();
     double y = data1->getBoundingBox().center().y();
@@ -64,86 +64,67 @@ PView *GMSH_MinMaxPlugin::execute(PView * v)
     dataMax->NbSP = 1;
   }
 
-  double minView=VAL_INF, maxView=-VAL_INF, min=VAL_INF, max=-VAL_INF, timeMin=0, timeMax=0;
-  double xmin, ymin, zmin, xmax, ymax, zmax;
+  double min=VAL_INF, max=-VAL_INF, timeMin=0, timeMax=0;
 
   for(int step = 0; step < data1->getNumTimeSteps(); step++){
     if(data1->hasTimeStep(step)){
 
-      //minView=data1->getMin(step); 
-      //maxView=data1->getMax(step);
- 
+      double minView = VAL_INF, maxView = -VAL_INF;
+      double xmin = 0., ymin = 0., zmin = 0., xmax = 0., ymax = 0., zmax = 0.;
       for(int ent = 0; ent < data1->getNumEntities(step); ent++){
 	for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
 	  for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++){
 	    double val;
 	    data1->getScalarValue(step, ent, ele, nod, val);
-	    if(val<minView){
+	    if(val < minView){
 	      data1->getNode(step, ent, ele, nod, xmin, ymin, zmin);
-	      minView=val;
+	      minView = val;
 	    }
-	    if(val>maxView){
+	    if(val > maxView){
 	      data1->getNode(step, ent, ele, nod, xmax, ymax, zmax);
-	      maxView=val;
+	      maxView = val;
 	    }
 	  }
 	}
       }
-      if(!overTime){ 
-	// one stores min/max and at each time step 
+
+      if(!overTime){
 	if(argument){
 	  dataMin->SP.push_back(xmin); dataMin->SP.push_back(ymin); dataMin->SP.push_back(zmin);
 	  dataMax->SP.push_back(xmax); dataMax->SP.push_back(ymax); dataMax->SP.push_back(zmax);
 	  (dataMin->NbSP)++;
 	  (dataMax->NbSP)++;
 	}
+        else{
+          double time = data1->getTime(step);
+          dataMin->Time.push_back(time);
+          dataMax->Time.push_back(time);
+        }
 	dataMin->SP.push_back(minView);
 	dataMax->SP.push_back(maxView);
-	double time = data1->getTime(step);
-	dataMin->Time.push_back(time);//?
-	dataMax->Time.push_back(time);//?
       }
       else{
-	if(minView<min){
-	  min=minView;
+	if(minView < min){
+	  min = minView;
 	  timeMin = data1->getTime(step);
 	}
-	if(maxView>max){ 
-	  max=maxView;
+	if(maxView > max){
+	  max = maxView;
 	  timeMax = data1->getTime(step);
-	} 
+	}
       }
     }
   }
 
-  if(overTime){ 
+  if(overTime){
     dataMin->SP.push_back(min);
     dataMax->SP.push_back(max);
-    dataMin->Time.push_back(timeMin);//?
-    dataMax->Time.push_back(timeMax);//?
+    dataMin->Time.push_back(timeMin);
+    dataMax->Time.push_back(timeMax);
   }
 
-  // dataMin->NbSP = 1;
-  // dataMax->NbSP = 1;
-
   vMin->getOptions()->intervalsType = PViewOptions::Numeric;
   vMax->getOptions()->intervalsType = PViewOptions::Numeric;
-  
-  /*
-  for(int step = 0; step < data1->getNumTimeSteps(); step++){
-    if(data1->hasTimeStep(step)){
-      if(overTime){
-	dataMin->Time.push_back(timeMin);
-	dataMax->Time.push_back(timeMax);
-      }
-      else{
-	double time = data1->getTime(step);
-	dataMin->Time.push_back(time);
-	dataMax->Time.push_back(time);
-      }
-    }
-  }
-  */
 
   dataMin->setName(data1->getName() + "_Min");
   dataMin->setFileName(data1->getName() + "_Min.pos");
@@ -151,6 +132,6 @@ PView *GMSH_MinMaxPlugin::execute(PView * v)
   dataMax->setName(data1->getName() + "_Max");
   dataMax->setFileName(data1->getName() + "_Max.pos");
   dataMax->finalize();
-  
+
   return 0;
 }
diff --git a/Plugin/ModifyComponent.cpp b/Plugin/ModifyComponent.cpp
index d38bb27..3802181 100644
--- a/Plugin/ModifyComponent.cpp
+++ b/Plugin/ModifyComponent.cpp
@@ -157,12 +157,14 @@ PView *GMSH_ModifyComponentPlugin::execute(PView *view)
     double time = data1->getTime(step);
     int step2 = (otherTimeStep < 0) ? step : otherTimeStep;
 
-    // tag all the nodes with "0" (the default tag)
-    for(int ent = 0; ent < data1->getNumEntities(step); ent++){
-      for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
-        if(data1->skipElement(step, ent, ele)) continue;
-        for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
-          data1->tagNode(step, ent, ele, nod, 0);
+    if(data1->isNodeData()){
+      // tag all the nodes with "0" (the default tag)
+      for(int ent = 0; ent < data1->getNumEntities(step); ent++){
+        for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
+          if(data1->skipElement(step, ent, ele)) continue;
+          for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
+            data1->tagNode(step, ent, ele, nod, 0);
+        }
       }
     }
 
@@ -172,12 +174,12 @@ PView *GMSH_ModifyComponentPlugin::execute(PView *view)
         int numComp = data1->getNumComponents(step, ent, ele);
         int numComp2 = octree ? 9 : data2->getNumComponents(step2, ent, ele);
         int numNodes = data1->getNumNodes(step, ent, ele);
-        std::vector<int> tag(numNodes);
         std::vector<double> x(numNodes), y(numNodes), z(numNodes);
+        std::vector<int> tag(numNodes);
         for(int nod = 0; nod < numNodes; nod++)
           tag[nod] = data1->getNode(step, ent, ele, nod, x[nod], y[nod], z[nod]);
         for(int nod = 0; nod < numNodes; nod++){
-          if(tag[nod]) continue; // node has already been modified
+          if(data1->isNodeData() && tag[nod]) continue; // node has already been modified
           std::vector<double> v(std::max(9, numComp), 0.);
           for(int comp = 0; comp < numComp; comp++)
             data1->getValue(step, ent, ele, nod, comp, v[comp]);
@@ -204,7 +206,7 @@ PView *GMSH_ModifyComponentPlugin::execute(PView *view)
             for(int i = 0; i < 9; i++) values[16 + i] = w[i];
             if(f.eval(values, res))
               data1->setValue(step, ent, ele, nod, comp, res[0]);
-            data1->tagNode(step, ent, ele, nod, 1);
+            if(data1->isNodeData()) data1->tagNode(step, ent, ele, nod, 1);
           }
         }
       }
diff --git a/Plugin/ModulusPhase.cpp b/Plugin/ModulusPhase.cpp
index 1664b6b..8921953 100644
--- a/Plugin/ModulusPhase.cpp
+++ b/Plugin/ModulusPhase.cpp
@@ -61,13 +61,15 @@ PView *GMSH_ModulusPhasePlugin::execute(PView *v)
     return v1;
   }
 
-  // tag all the nodes with "0" (the default tag)
-  for(int step = 0; step < data1->getNumTimeSteps(); step++){
-    for(int ent = 0; ent < data1->getNumEntities(step); ent++){
-      for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
-        if(data1->skipElement(step, ent, ele)) continue;
-        for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
-          data1->tagNode(step, ent, ele, nod, 0);
+  if(data1->isNodeData()){
+    // tag all the nodes with "0" (the default tag)
+    for(int step = 0; step < data1->getNumTimeSteps(); step++){
+      for(int ent = 0; ent < data1->getNumEntities(step); ent++){
+        for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
+          if(data1->skipElement(step, ent, ele)) continue;
+          for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
+            data1->tagNode(step, ent, ele, nod, 0);
+        }
       }
     }
   }
@@ -79,7 +81,7 @@ PView *GMSH_ModulusPhasePlugin::execute(PView *v)
       for(int nod = 0; nod < data1->getNumNodes(rIndex, ent, ele); nod++){
         double x, y, z;
         int tag = data1->getNode(rIndex, ent, ele, nod, x, y, z);
-        if(tag) continue;
+        if(data1->isNodeData() && tag) continue;
         for(int comp = 0; comp < data1->getNumComponents(rIndex, ent, ele); comp++){
           double vr, vi;
           data1->getValue(rIndex, ent, ele, nod, comp, vr);
@@ -88,8 +90,10 @@ PView *GMSH_ModulusPhasePlugin::execute(PView *v)
           double phase = atan2(vi, vr);
           data1->setValue(rIndex, ent, ele, nod, comp, modulus);
           data1->setValue(iIndex, ent, ele, nod, comp, phase);
-          data1->tagNode(rIndex, ent, ele, nod, 1);
-          data1->tagNode(iIndex, ent, ele, nod, 1);
+          if(data1->isNodeData()){
+            data1->tagNode(rIndex, ent, ele, nod, 1);
+            data1->tagNode(iIndex, ent, ele, nod, 1);
+          }
         }
       }
     }
diff --git a/Plugin/Particles.h b/Plugin/Particles.h
index 4f79d08..9b38532 100644
--- a/Plugin/Particles.h
+++ b/Plugin/Particles.h
@@ -4,7 +4,7 @@
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
 #ifndef _PARTICLES_H_
-#define _PARTICLES_H
+#define _PARTICLES_H_
 
 #include "Plugin.h"
 
@@ -26,7 +26,7 @@ class GMSH_ParticlesPlugin : public GMSH_PostPlugin
   }
   std::string getHelp() const;
   int getNbOptions() const;
-  StringXNumber *getOption(int iopt);  
+  StringXNumber *getOption(int iopt);
   PView *execute(PView *);
 
   static int getNbU();
diff --git a/Plugin/PluginManager.cpp b/Plugin/PluginManager.cpp
index a444dc6..bf4593b 100644
--- a/Plugin/PluginManager.cpp
+++ b/Plugin/PluginManager.cpp
@@ -20,6 +20,7 @@
 #include "CutBox.h"
 #include "Skin.h"
 #include "AnalyseCurvedMesh.h"
+#include "CurvedBndDist.h"
 #include "MathEval.h"
 #include "ExtractElements.h"
 #include "SimplePartition.h"
@@ -55,6 +56,7 @@
 #include "Bubbles.h"
 #include "NearToFarField.h"
 #include "DiscretizationError.h"
+#include "Scal2Tens.h"
 #include "Scal2Vec.h"
 #include "CutMesh.h"
 #include "NewView.h"
@@ -186,6 +188,8 @@ void PluginManager::registerDefaultPlugins()
                       ("AnalyseCurvedMesh", GMSH_RegisterAnalyseCurvedMeshPlugin()));
 #endif
     allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
+                      ("CurvedBndDist", GMSH_RegisterCurvedBndDistPlugin()));
+    allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
                       ("ModifyComponent", GMSH_RegisterModifyComponentPlugin()));
     allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
                       ("ExtractElements", GMSH_RegisterExtractElementsPlugin()));
@@ -242,6 +246,8 @@ void PluginManager::registerDefaultPlugins()
     allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
                       ("DiscretizationError", GMSH_RegisterDiscretizationErrorPlugin()));
     allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
+                      ("Scal2Tens", GMSH_RegisterScal2TensPlugin()));
+    allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
                       ("Scal2Vec", GMSH_RegisterScal2VecPlugin()));
     allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
                       ("NewView", GMSH_RegisterNewViewPlugin()));
diff --git a/Plugin/Scal2Tens.cpp b/Plugin/Scal2Tens.cpp
new file mode 100644
index 0000000..408559a
--- /dev/null
+++ b/Plugin/Scal2Tens.cpp
@@ -0,0 +1,142 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
+#include "Scal2Tens.h"
+#include "PViewOptions.h"
+#include "shapeFunctions.h"
+
+StringXNumber Scal2TensOptions_Number[] = {
+  {GMSH_FULLRC, "NumberOfComponents", NULL, 9},
+  {GMSH_FULLRC, "View0", NULL, -1},
+  {GMSH_FULLRC, "View1", NULL, -1},
+  {GMSH_FULLRC, "View2", NULL, -1},
+  {GMSH_FULLRC, "View3", NULL, -1},
+  {GMSH_FULLRC, "View4", NULL, -1},
+  {GMSH_FULLRC, "View5", NULL, -1},
+  {GMSH_FULLRC, "View6", NULL, -1},
+  {GMSH_FULLRC, "View7", NULL, -1},
+  {GMSH_FULLRC, "View8", NULL, -1}
+};
+
+StringXString Scal2TensOptions_String[] = {
+  {GMSH_FULLRC, "NameNewView", NULL, "NewView"}
+};
+
+extern "C"
+{
+  GMSH_Plugin *GMSH_RegisterScal2TensPlugin()
+  {
+    return new GMSH_Scal2TensPlugin();
+  }
+}
+
+std::string GMSH_Scal2TensPlugin::getHelp() const
+{
+  return "Plugin(Scal2Tens) converts some scalar fields into a tensor field. "
+         "The number of components must be given (max. 9). "
+         "The new view 'NameNewView' contains the new tensor field. If the number "
+         "of a view is -1, the value of the corresponding component is 0.";
+}
+
+int GMSH_Scal2TensPlugin::getNbOptions() const
+{
+  return sizeof(Scal2TensOptions_Number) / sizeof(StringXNumber);
+}
+
+StringXNumber *GMSH_Scal2TensPlugin::getOption(int iopt)
+{
+  return &Scal2TensOptions_Number[iopt];
+}
+
+int GMSH_Scal2TensPlugin::getNbOptionsStr() const
+{
+  return sizeof(Scal2TensOptions_String) / sizeof(StringXString);
+}
+
+StringXString *GMSH_Scal2TensPlugin::getOptionStr(int iopt)
+{
+  return &Scal2TensOptions_String[iopt];
+}
+
+
+PView *GMSH_Scal2TensPlugin::execute(PView *v)
+{
+  // Load options
+  int numComp = (int)Scal2TensOptions_Number[0].def;
+  if ((numComp<1) || (numComp>9)) {
+    Msg::Error("Scal2Tens plugin: NumberOfComponents must be between 1 and 9 (not '%i')", numComp);
+    return v;
+  }
+  int iView[9];
+  for (int comp=0; comp<numComp; comp++)
+    iView[comp] = (int)Scal2TensOptions_Number[comp+1].def;
+  
+  // Load data
+  PView *vRef=0, *vComp[9];
+  for (int comp=0; comp<numComp; comp++) {
+    if (iView[comp]<0) vComp[comp] = 0;
+    else {
+      vComp[comp] = getView(iView[comp], v);
+      if (!vComp[comp]) {
+        Msg::Error("Scal2Tens plugin could not find View '%i'", iView[comp]);
+        return v;
+      }
+      if (!vRef) vRef = vComp[comp];
+    }
+  }
+  if (!vRef) {
+    Msg::Error("Scal2Tens plugin could not find any view.");
+    return v;
+  }
+  PViewData *dataRef = vRef->getData();
+  
+  // Initialize the new view
+  PView *vNew = new PView();
+  PViewDataList *dataNew = getDataList(vNew);
+  
+  int step0 = dataRef->getFirstNonEmptyTimeStep();
+  for (int ent=0; ent < dataRef->getNumEntities(step0); ent++) {
+    for (int ele=0; ele < dataRef->getNumElements(step0, ent); ele++) {
+      if (dataRef->skipElement(step0, ent, ele)) continue;
+      int type = dataRef->getType(step0, ent, ele);
+      int numNodes = dataRef->getNumNodes(step0, ent, ele);
+      std::vector<double> *out = dataNew->incrementList(numComp, type, numNodes); // Pointer in data of the new view
+      if (!out) continue;
+      double x[8], y[8], z[8];
+      for (int nod=0; nod<numNodes; nod++)
+        dataRef->getNode(step0, ent, ele, nod, x[nod], y[nod], z[nod]);
+      int dim = dataRef->getDimension(step0, ent, ele);
+      elementFactory factory;
+      element *element = factory.create(numNodes, dim, x, y, z);
+      if (!element) continue;
+      for (int nod=0; nod<numNodes; nod++) out->push_back(x[nod]); // Save coordinates (x,y,z)
+      for (int nod=0; nod<numNodes; nod++) out->push_back(y[nod]);
+      for (int nod=0; nod<numNodes; nod++) out->push_back(z[nod]);
+      for (int step=step0; step < dataRef->getNumTimeSteps(); step++) {
+        if (!dataRef->hasTimeStep(step)) continue;
+        for (int nod=0; nod<numNodes; nod++) {
+          for (int comp=0; comp<numComp; comp++) {
+            double val=0.;
+            if(vComp[comp]) vComp[comp]->getData()->getValue(step, ent, ele, nod, 0, val);
+            out->push_back(val); // Save value
+          }
+        }
+      }
+      delete element;
+    }
+  }
+  
+  for (int step=step0; step < dataRef->getNumTimeSteps(); step++) {
+    if (!dataRef->hasTimeStep(step)) continue;
+    dataNew->Time.push_back(dataRef->getTime(step));
+  }
+  
+  std::string nameNewView = Scal2TensOptions_String[0].def;
+  dataNew->setName(nameNewView);
+  dataNew->setFileName(nameNewView + ".pos");
+  dataNew->finalize();
+  
+  return vNew;
+}
diff --git a/Plugin/Scal2Tens.h b/Plugin/Scal2Tens.h
new file mode 100644
index 0000000..41c9454
--- /dev/null
+++ b/Plugin/Scal2Tens.h
@@ -0,0 +1,33 @@
+// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to the public mailing list <gmsh at geuz.org>.
+
+#ifndef _SCAL2TENS_H_
+#define _SCAL2TENS_H_
+
+#include "Plugin.h"
+
+extern "C"
+{
+  GMSH_Plugin *GMSH_RegisterScal2TensPlugin();
+}
+
+class GMSH_Scal2TensPlugin : public GMSH_PostPlugin
+{
+ public:
+  GMSH_Scal2TensPlugin(){}
+  std::string getName() const { return "Scal2Tens"; }
+  std::string getShortHelp() const
+  {
+    return "Convert some scalar fields into a tensor field with several components";
+  }
+  std::string getHelp() const;
+  int getNbOptions() const;
+  StringXNumber *getOption(int iopt);
+  int getNbOptionsStr() const;
+  StringXString* getOptionStr(int iopt);
+  PView *execute(PView *);
+};
+
+#endif
diff --git a/Plugin/Scal2Vec.cpp b/Plugin/Scal2Vec.cpp
index 436ea1e..87a0bfd 100644
--- a/Plugin/Scal2Vec.cpp
+++ b/Plugin/Scal2Vec.cpp
@@ -8,9 +8,9 @@
 #include "shapeFunctions.h"
 
 StringXNumber Scal2VecOptions_Number[] = {
-  {GMSH_FULLRC, "ViewX", NULL, -1.},
-  {GMSH_FULLRC, "ViewY", NULL, -1.},
-  {GMSH_FULLRC, "ViewZ", NULL, -1.}
+  {GMSH_FULLRC, "ViewX", NULL, -1},
+  {GMSH_FULLRC, "ViewY", NULL, -1},
+  {GMSH_FULLRC, "ViewZ", NULL, -1}
 };
 
 StringXString Scal2VecOptions_String[] = {
@@ -27,11 +27,10 @@ extern "C"
 
 std::string GMSH_Scal2VecPlugin::getHelp() const
 {
-  return "Plugin(Scal2Vec) converts the scalar fields of 'ViewX', "
-         "'ViewY' and/or 'ViewZ' into a vectorial field. "
-         "The new view 'NameNewView' contains it.\n\n"
-         "If the value of 'ViewX', 'ViewY' or 'ViewZ' is -1, "
-         "the value of the vectorial field in the corresponding direction is 0.";
+  return "Plugin(Scal2Vec) converts the scalar fields into a vectorial field. "
+         "The new view 'NameNewView' contains it. "
+         "If the number of a view is -1, the value of the corresponding "
+         "component of the vector field is 0.";
 }
 
 int GMSH_Scal2VecPlugin::getNbOptions() const
@@ -57,99 +56,72 @@ StringXString *GMSH_Scal2VecPlugin::getOptionStr(int iopt)
 
 PView *GMSH_Scal2VecPlugin::execute(PView *v)
 {
-  int iViewX = (int)Scal2VecOptions_Number[0].def;
-  int iViewY = (int)Scal2VecOptions_Number[1].def;
-  int iViewZ = (int)Scal2VecOptions_Number[2].def;
-  std::string nameNewView = Scal2VecOptions_String[0].def;
-  
-  PView *vRef = 0, *vX = 0, *vY = 0, *vZ = 0;
-  PViewData *dataRef = 0, *dataX = 0, *dataY = 0, *dataZ = 0;
+  // Load options
+  int iView[3];
+  for (int comp=0; comp<3; comp++)
+    iView[comp] = (int)Scal2VecOptions_Number[comp].def;
   
   // Load data
-  if(iViewX >= 0){
-    vX = getView(iViewX, v);
-    if(!vX){
-      Msg::Error("Scal2Vec plugin could not find View X: %i", iViewX);
-      return v;
-    }
-    dataX = vX->getData();
-    if(!vRef){
-      vRef = vX;
-      dataRef = dataX;
-    }
-  }
-  if(iViewY >= 0){
-    vY = getView(iViewY, v);
-    if(!vY){
-      Msg::Error("Scal2Vec plugin could not find View Y: %i", iViewY);
-      return v;
-    }
-    dataY = vY->getData();
-    if(!vRef){
-      vRef = vY;
-      dataRef = dataY;
-    }
-  }
-  if(iViewZ >= 0){
-    vZ = getView(iViewZ, v);
-    if(!vZ){
-      Msg::Error("Scal2Vec plugin could not find View Z: %i", iViewZ);
-      return v;
-    }
-    dataZ = vZ->getData();
-    if(!vRef){
-      vRef = vZ;
-      dataRef = dataZ;
+  PView *vRef=0, *vComp[3];
+  for (int comp=0; comp<3; comp++) {
+    if (iView[comp]<0) vComp[comp] = 0;
+    else {
+      vComp[comp] = getView(iView[comp], v);
+      if (!vComp[comp]) {
+        Msg::Error("Scal2Vec plugin could not find View '%i'", iView[comp]);
+        return v;
+      }
+      if (!vRef) vRef = vComp[comp];
     }
   }
-  if(!vRef){
-    Msg::Error("Scal2Vec plugin could not find any view.", iViewZ);
+  if (!vRef) {
+    Msg::Error("Scal2Vec plugin could not find any view.");
     return v;
   }
+  PViewData *dataRef = vRef->getData();
   
   // Initialize the new view
   PView *vNew = new PView();
   PViewDataList *dataNew = getDataList(vNew);
   
-  for(int ent = 0; ent < dataRef->getNumEntities(0); ent++){
-    for(int ele = 0; ele < dataRef->getNumElements(0, ent); ele++){
-      if(dataRef->skipElement(0, ent, ele)) continue;
-      int numComp = 3; // The 3 components of the new view: x,y,z
-      int type = dataRef->getType(0, ent, ele);
-      int numNodes = dataRef->getNumNodes(0, ent, ele);
-      std::vector<double> *out = dataNew->incrementList(numComp, type, numNodes); // Pointer in data of the new view
-      if(!out) continue;
-      double x[8], y[8], z[8], valX, valY, valZ;
-      for(int nod = 0; nod < numNodes; nod++)
-        dataRef->getNode(0, ent, ele, nod, x[nod], y[nod], z[nod]);
-      int dim = dataRef->getDimension(0, ent, ele);
+  int step0 = dataRef->getFirstNonEmptyTimeStep();
+  for (int ent=0; ent < dataRef->getNumEntities(step0); ent++) {
+    for (int ele=0; ele < dataRef->getNumElements(step0, ent); ele++) {
+      if (dataRef->skipElement(step0, ent, ele)) continue;
+      int type = dataRef->getType(step0, ent, ele);
+      int numNodes = dataRef->getNumNodes(step0, ent, ele);
+      std::vector<double> *out = dataNew->incrementList(3, type, numNodes); // Pointer in data of the new view
+      if (!out) continue;
+      double x[8], y[8], z[8];
+      for (int nod=0; nod<numNodes; nod++)
+        dataRef->getNode(step0, ent, ele, nod, x[nod], y[nod], z[nod]);
+      int dim = dataRef->getDimension(step0, ent, ele);
       elementFactory factory;
       element *element = factory.create(numNodes, dim, x, y, z);
-      if(!element) continue;
-      for(int nod = 0; nod < numNodes; nod++) out->push_back(x[nod]); // Save coordinates (x,y,z)
-      for(int nod = 0; nod < numNodes; nod++) out->push_back(y[nod]);
-      for(int nod = 0; nod < numNodes; nod++) out->push_back(z[nod]);
-      for(int step = 0; step < dataRef->getNumTimeSteps(); step++){
-        for(int nod = 0; nod < numNodes; nod++){
-          if(vX) dataX->getValue(step, ent, ele, nod, 0, valX); else valX = 0;
-          if(vY) dataY->getValue(step, ent, ele, nod, 0, valY); else valY = 0;
-          if(vZ) dataZ->getValue(step, ent, ele, nod, 0, valZ); else valZ = 0;
-          out->push_back(valX); // Save values (fx,fy,fz)
-          out->push_back(valY);
-          out->push_back(valZ);
+      if (!element) continue;
+      for (int nod=0; nod<numNodes; nod++) out->push_back(x[nod]); // Save coordinates (x,y,z)
+      for (int nod=0; nod<numNodes; nod++) out->push_back(y[nod]);
+      for (int nod=0; nod<numNodes; nod++) out->push_back(z[nod]);
+      for (int step=step0; step < dataRef->getNumTimeSteps(); step++) {
+        if (!dataRef->hasTimeStep(step)) continue;
+        for (int nod=0; nod<numNodes; nod++) {
+          for (int comp=0; comp<3; comp++) {
+            double val=0.;
+            if(vComp[comp]) vComp[comp]->getData()->getValue(step, ent, ele, nod, 0, val);
+            out->push_back(val); // Save value
+          }
         }
       }
       delete element;
     }
   }
   
-  for(int step = 0; step < dataRef->getNumTimeSteps(); step++){
-    if(dataRef->hasTimeStep(step)){
-      double time = dataRef->getTime(step);
-      dataNew->Time.push_back(time);
-    }
+  for (int step=step0; step < dataRef->getNumTimeSteps(); step++) {
+    if (!dataRef->hasTimeStep(step)) continue;
+    dataNew->Time.push_back(dataRef->getTime(step));
   }
   
+  std::string nameNewView = Scal2VecOptions_String[0].def;
   dataNew->setName(nameNewView);
   dataNew->setFileName(nameNewView + ".pos");
   dataNew->finalize();
diff --git a/Plugin/SphericalRaise.cpp b/Plugin/SphericalRaise.cpp
index f631175..278a4c1 100644
--- a/Plugin/SphericalRaise.cpp
+++ b/Plugin/SphericalRaise.cpp
@@ -74,13 +74,15 @@ PView *GMSH_SphericalRaisePlugin::execute(PView *v)
     return v;
   }
 
-  // tag all the nodes with "0" (the default tag)
-  for(int step = 0; step < data1->getNumTimeSteps(); step++){
-    for(int ent = 0; ent < data1->getNumEntities(step); ent++){
-      for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
-        if(data1->skipElement(step, ent, ele)) continue;
-        for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
-          data1->tagNode(step, ent, ele, nod, 0);
+  if(data1->isNodeData()){
+    // tag all the nodes with "0" (the default tag)
+    for(int step = 0; step < data1->getNumTimeSteps(); step++){
+      for(int ent = 0; ent < data1->getNumEntities(step); ent++){
+        for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
+          if(data1->skipElement(step, ent, ele)) continue;
+          for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
+            data1->tagNode(step, ent, ele, nod, 0);
+        }
       }
     }
   }
@@ -93,20 +95,19 @@ PView *GMSH_SphericalRaisePlugin::execute(PView *v)
         for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++){
           double x, y, z;
           int tag = data1->getNode(step, ent, ele, nod, x, y, z);
-          if(!tag){
-            double r[3], val;
-            r[0] = x - center[0];
-            r[1] = y - center[1];
-            r[2] = z - center[2];
-            norme(r);
-            data1->getScalarValue(step, ent, ele, nod, val);
-            double coef = offset + raise * val;
-            x += coef * r[0];
-            y += coef * r[1];
-            z += coef * r[2];
-            data1->setNode(step, ent, ele, nod, x, y, z);
-            data1->tagNode(step, ent, ele, nod, 1);
-          }
+          if(data1->isNodeData() && tag) continue;
+          double r[3], val;
+          r[0] = x - center[0];
+          r[1] = y - center[1];
+          r[2] = z - center[2];
+          norme(r);
+          data1->getScalarValue(step, ent, ele, nod, val);
+          double coef = offset + raise * val;
+          x += coef * r[0];
+          y += coef * r[1];
+          z += coef * r[2];
+          data1->setNode(step, ent, ele, nod, x, y, z);
+          if(data1->isNodeData()) data1->tagNode(step, ent, ele, nod, 1);
         }
       }
     }
diff --git a/Plugin/StreamLines.h b/Plugin/StreamLines.h
index 078ae57..d0c0012 100644
--- a/Plugin/StreamLines.h
+++ b/Plugin/StreamLines.h
@@ -4,7 +4,7 @@
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
 #ifndef _STREAM_LINES_H_
-#define _STREAM_LINES_H
+#define _STREAM_LINES_H_
 
 #include "Plugin.h"
 
@@ -26,7 +26,7 @@ class GMSH_StreamLinesPlugin : public GMSH_PostPlugin
   }
   std::string getHelp() const;
   int getNbOptions() const;
-  StringXNumber *getOption(int iopt);  
+  StringXNumber *getOption(int iopt);
   PView *execute(PView *);
 
   static int getNbU();
diff --git a/Plugin/Tetrahedralize.cpp b/Plugin/Tetrahedralize.cpp
index 38bc261..f26f57b 100644
--- a/Plugin/Tetrahedralize.cpp
+++ b/Plugin/Tetrahedralize.cpp
@@ -9,8 +9,8 @@
 #include "GmshMessage.h"
 #include "Tetrahedralize.h"
 
-#if defined(HAVE_TETGEN)
-#include "tetgen.h"
+#if defined(HAVE_MESH)
+#include "meshGRegionDelaunayInsertion.h"
 #endif
 
 StringXNumber TetrahedralizeOptions_Number[] = {
@@ -43,15 +43,15 @@ StringXNumber *GMSH_TetrahedralizePlugin::getOption(int iopt)
   return &TetrahedralizeOptions_Number[iopt];
 }
 
-class PointData {
+#if defined(HAVE_MESH)
+
+class PointData : public MVertex {
  public:
-  std::vector<double> v;
+  std::vector<double> val;
   PointData(double x, double y, double z, int numVal)
+    : MVertex(x, y, z)
   {
-    v.resize(3 + numVal);
-    v[0] = x;
-    v[1] = y;
-    v[2] = z;
+    val.resize(numVal);
   }
 };
 
@@ -69,7 +69,7 @@ PView *GMSH_TetrahedralizePlugin::execute(PView *v)
   }
 
   // create list of points with associated data
-  std::vector<PointData> points;
+  std::vector<MVertex*> points;
   int numSteps = data1->getNumTimeSteps();
   for(int ent = 0; ent < data1->getNumEntities(0); ent++){
     for(int ele = 0; ele < data1->getNumElements(0, ent); ele++){
@@ -78,89 +78,82 @@ PView *GMSH_TetrahedralizePlugin::execute(PView *v)
       int numComp = data1->getNumComponents(0, ent, ele);
       double x, y, z;
       data1->getNode(0, ent, ele, 0, x, y, z);
-      PointData p(x, y, z, numComp * numSteps);
+      PointData *p = new PointData(x, y, z, numComp * numSteps);
       for(int step = 0; step < numSteps; step++)
         for(int comp = 0; comp < numComp; comp++)
-          data1->getValue(step, ent, ele, 0, comp, p.v[3 + numComp * step + comp]);
+          data1->getValue(step, ent, ele, 0, comp, p->val[numComp * step + comp]);
       points.push_back(p);
     }
   }
 
   if(points.size() < 4){
     Msg::Error("Need at least 4 points to tetrahedralize");
+    for(unsigned int i = 0; i < points.size(); i++) delete points[i];
     return v1;
   }
 
-#if !defined(HAVE_TETGEN)
-  Msg::Error("Gmsh has to be compiled with Tetgen support to run "
-             "Plugin(Tetrahedralize)");
-  return v1;
-#else
-  // fill tetgen structure
-  tetgenio in, out;
-  in.mesh_dim = 3;
-  in.numberofpoints = points.size();
-  in.pointlist = new REAL[in.numberofpoints * 3];
-  for(unsigned int i = 0; i < points.size(); i++){
-    in.pointlist[i * 3 + 0] = points[i].v[0];
-    in.pointlist[i * 3 + 1] = points[i].v[1];
-    in.pointlist[i * 3 + 2] = points[i].v[2];
-  }
-  try{
-    tetrahedralize((char*)"Q", &in, &out);
-  }
-  catch (int error){
-    Msg::Error("Could not tetrahedralize points");
-    return v1;
-  }
-
-  if(out.numberofpoints != (int)points.size()){
-    Msg::Error("Tetrahedralization added points (%d -> %d): aborting",
-               points.size(), out.numberofpoints);
-    return v1;
-  }
+  std::vector<MTetrahedron*> tets;
+  delaunayMeshIn3D(points, tets);
 
   // create output
   PView *v2 = new PView();
   PViewDataList *data2 = getDataList(v2);
-  for(int i = 0; i < out.numberoftetrahedra; i++){
+  for(unsigned int i = 0; i < tets.size(); i++){
     PointData *p[4];
-    p[0] = &points[out.tetrahedronlist[i * 4 + 0]];
-    p[1] = &points[out.tetrahedronlist[i * 4 + 1]];
-    p[2] = &points[out.tetrahedronlist[i * 4 + 2]];
-    p[3] = &points[out.tetrahedronlist[i * 4 + 3]];
+    p[0] = (PointData*)tets[i]->getVertex(0);
+    p[1] = (PointData*)tets[i]->getVertex(1);
+    p[2] = (PointData*)tets[i]->getVertex(2);
+    p[3] = (PointData*)tets[i]->getVertex(3);
     int numComp = 0;
     std::vector<double> *vec = 0;
-    if((int)p[0]->v.size() == 3 + 9 * numSteps &&
-       (int)p[1]->v.size() == 3 + 9 * numSteps &&
-       (int)p[2]->v.size() == 3 + 9 * numSteps &&
-       (int)p[3]->v.size() == 3 + 9 * numSteps){
+    if((int)p[0]->val.size() == 9 * numSteps &&
+       (int)p[1]->val.size() == 9 * numSteps &&
+       (int)p[2]->val.size() == 9 * numSteps &&
+       (int)p[3]->val.size() == 9 * numSteps){
       numComp = 9; data2->NbTS++; vec = &data2->TS;
     }
-    else if((int)p[0]->v.size() == 3 + 3 * numSteps &&
-            (int)p[1]->v.size() == 3 + 3 * numSteps &&
-            (int)p[2]->v.size() == 3 + 3 * numSteps &&
-            (int)p[2]->v.size() == 3 + 3 * numSteps){
+    else if((int)p[0]->val.size() == 3 * numSteps &&
+            (int)p[1]->val.size() == 3 * numSteps &&
+            (int)p[2]->val.size() == 3 * numSteps &&
+            (int)p[3]->val.size() == 3 * numSteps){
       numComp = 3; data2->NbVS++; vec = &data2->VS;
     }
-    else{
+    else if((int)p[0]->val.size() == numSteps &&
+            (int)p[1]->val.size() == numSteps &&
+            (int)p[2]->val.size() == numSteps &&
+            (int)p[3]->val.size() == numSteps){
       numComp = 1; data2->NbSS++; vec = &data2->SS;
     }
-    for(int nod = 0; nod < 4; nod++) vec->push_back(p[nod]->v[0]);
-    for(int nod = 0; nod < 4; nod++) vec->push_back(p[nod]->v[1]);
-    for(int nod = 0; nod < 4; nod++) vec->push_back(p[nod]->v[2]);
+    else{
+      Msg::Warning("Bad data in tetrahedralization");
+      continue;
+    }
+    for(int nod = 0; nod < 4; nod++) vec->push_back(p[nod]->x());
+    for(int nod = 0; nod < 4; nod++) vec->push_back(p[nod]->y());
+    for(int nod = 0; nod < 4; nod++) vec->push_back(p[nod]->z());
     for(int step = 0; step < numSteps; step++)
       for(int nod = 0; nod < 4; nod++)
         for(int comp = 0; comp < numComp; comp++)
-          vec->push_back(p[nod]->v[3 + numComp * step + comp]);
+          vec->push_back(p[nod]->val[numComp * step + comp]);
   }
 
+  for(unsigned int i = 0; i < tets.size(); i++) delete tets[i];
+  for(unsigned int i = 0; i < points.size(); i++) delete points[i];
+
   for(int i = 0; i < data1->getNumTimeSteps(); i++)
     data2->Time.push_back(data1->getTime(i));
   data2->setName(data1->getName() + "_Tetrahedralize");
   data2->setFileName(data1->getName() + "_Tetrahedralize.pos");
   data2->finalize();
-
   return v2;
-#endif
 }
+
+#else
+
+PView *GMSH_TetrahedralizePlugin::execute(PView *v)
+{
+  Msg::Error("Plugin(Tetrahedralize requires mesh module");
+  return v;
+}
+
+#endif
diff --git a/Plugin/Transform.cpp b/Plugin/Transform.cpp
index 3598232..9c04be6 100644
--- a/Plugin/Transform.cpp
+++ b/Plugin/Transform.cpp
@@ -80,14 +80,16 @@ PView *GMSH_TransformPlugin::execute(PView *v)
 
   PViewData *data1 = v1->getData();
 
-  // tag all the nodes with "0" (the default tag)
-  for(int step = 0; step < data1->getNumTimeSteps(); step++){
-    for(int ent = 0; ent < data1->getNumEntities(step); ent++){
-      for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
-        if(data1->skipElement(step, ent, ele)) continue;
-        if(swap) data1->reverseElement(step, ent, ele);
-        for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
-          data1->tagNode(step, ent, ele, nod, 0);
+  if(data1->isNodeData()){
+    // tag all the nodes with "0" (the default tag)
+    for(int step = 0; step < data1->getNumTimeSteps(); step++){
+      for(int ent = 0; ent < data1->getNumEntities(step); ent++){
+        for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
+          if(data1->skipElement(step, ent, ele)) continue;
+          if(swap) data1->reverseElement(step, ent, ele);
+          for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
+            data1->tagNode(step, ent, ele, nod, 0);
+        }
       }
     }
   }
@@ -100,14 +102,13 @@ PView *GMSH_TransformPlugin::execute(PView *v)
         for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++){
           double x, y, z;
           int tag = data1->getNode(step, ent, ele, nod, x, y, z);
-          if(!tag){
-            double x2, y2, z2;
-            x2 = mat[0][0] * x + mat[0][1] * y + mat[0][2] * z + mat[0][3];
-            y2 = mat[1][0] * x + mat[1][1] * y + mat[1][2] * z + mat[1][3];
-            z2 = mat[2][0] * x + mat[2][1] * y + mat[2][2] * z + mat[2][3];
-            data1->setNode(step, ent, ele, nod, x2, y2, z2);
-            data1->tagNode(step, ent, ele, nod, 1);
-          }
+          if(data1->isNodeData() && tag) continue;
+          double x2, y2, z2;
+          x2 = mat[0][0] * x + mat[0][1] * y + mat[0][2] * z + mat[0][3];
+          y2 = mat[1][0] * x + mat[1][1] * y + mat[1][2] * z + mat[1][3];
+          z2 = mat[2][0] * x + mat[2][1] * y + mat[2][2] * z + mat[2][3];
+          data1->setNode(step, ent, ele, nod, x2, y2, z2);
+          if(data1->isNodeData()) data1->tagNode(step, ent, ele, nod, 1);
         }
       }
     }
diff --git a/Plugin/Triangulate.cpp b/Plugin/Triangulate.cpp
index 1444214..be24d3f 100644
--- a/Plugin/Triangulate.cpp
+++ b/Plugin/Triangulate.cpp
@@ -15,6 +15,7 @@
 
 #if defined(HAVE_MESH)
 #include "DivideAndConquer.h"
+#include "meshGFaceDelaunayInsertion.h"
 #endif
 
 StringXNumber TriangulateOptions_Number[] = {
@@ -64,16 +65,6 @@ class PointData : public MVertex {
   }
 };
 
-static void project(MVertex *v, double mat[3][3])
-{
-  double X = v->x() * mat[0][0] + v->y() * mat[0][1] + v->z() * mat[0][2];
-  double Y = v->x() * mat[1][0] + v->y() * mat[1][1] + v->z() * mat[1][2];
-  double Z = v->x() * mat[2][0] + v->y() * mat[2][1] + v->z() * mat[2][2];
-  v->x() = X;
-  v->y() = Y;
-  v->z() = Z;
-}
-
 PView *GMSH_TriangulatePlugin::execute(PView *v)
 {
   int iView = (int)TriangulateOptions_Number[0].def;
@@ -107,24 +98,32 @@ PView *GMSH_TriangulatePlugin::execute(PView *v)
 
   if(points.size() < 3){
     Msg::Error("Need at least 3 points to triangulate");
-    for(unsigned int i = 0; i < points.size(); i++)
-      delete points[i];
+    for(unsigned int i = 0; i < points.size(); i++) delete points[i];
     return v1;
   }
 
+  // get bounding box
+  SBoundingBox3d bbox;
+  for(unsigned int i = 0; i < points.size(); i++) bbox += points[i]->point();
+  double lc = 10 * norm(SVector3(bbox.max(), bbox.min()));
+
   // project points onto plane
   discreteFace *s = new discreteFace
     (GModel::current(), GModel::current()->getNumFaces() + 1);
   s->computeMeanPlane(points);
-  double plan[3][3];
-  s->getMeanPlaneData(plan);
-  for(unsigned int i = 0; i < points.size(); i++) project(points[i], plan);
+  double x, y, z, VX[3], VY[3];
+  s->getMeanPlaneData(VX, VY, x, y, z);
+  for(unsigned int i = 0; i < points.size(); i++) {
+    double vec[3] = {points[i]->x() - x, points[i]->y() - y, points[i]->z() - z}, u, v;
+    prosca(vec, VX, &u);
+    prosca(vec, VY, &v);
+    points[i]->x() = u;
+    points[i]->y() = v;
+    points[i]->z() = 0.;
+  }
   delete s;
 
-  // get lc
-  SBoundingBox3d bbox;
-  for(unsigned int i = 0; i < points.size(); i++) bbox += points[i]->point();
-  double lc = 10 * norm(SVector3(bbox.max(), bbox.min()));
+#if 0 // old code
 
   // build a point record structure for the divide and conquer algorithm
   DocRecord doc(points.size());
@@ -138,7 +137,12 @@ PView *GMSH_TriangulatePlugin::execute(PView *v)
   }
 
   // triangulate
-  doc.MakeMeshWithPoints();
+  try{
+    doc.MakeMeshWithPoints();
+  }
+  catch(const char *err){
+    Msg::Error("%s", err);
+  }
 
   // create output (using unperturbed data)
   PView *v2 = new PView();
@@ -180,6 +184,50 @@ PView *GMSH_TriangulatePlugin::execute(PView *v)
           vec->push_back(p[nod]->v[3 + numComp * step + comp]);
   }
 
+#else // new code
+  Msg::Info("Using new triangulation code");
+  std::vector<MTriangle*> tris;
+  for(unsigned int i = 0; i < points.size(); i++) {
+    double XX = 1.e-12 * lc * (double)rand() / (double)RAND_MAX;
+    double YY = 1.e-12 * lc * (double)rand() / (double)RAND_MAX;
+    points[i]->x() += XX;
+    points[i]->y() += YY;
+  }
+  delaunayMeshIn2D(points, tris);
+
+  PView *v2 = new PView();
+  PViewDataList *data2 = getDataList(v2);
+  for(unsigned int i = 0; i < tris.size(); i++){
+    PointData *p[3];
+    p[0] = (PointData*)tris[i]->getVertex(0);
+    p[1] = (PointData*)tris[i]->getVertex(1);
+    p[2] = (PointData*)tris[i]->getVertex(2);
+    int numComp = 0;
+    std::vector<double> *vec = 0;
+    if((int)p[0]->v.size() == 3 + 9 * numSteps &&
+       (int)p[1]->v.size() == 3 + 9 * numSteps &&
+       (int)p[2]->v.size() == 3 + 9 * numSteps){
+      numComp = 9; data2->NbTT++; vec = &data2->TT;
+    }
+    else if((int)p[0]->v.size() == 3 + 3 * numSteps &&
+            (int)p[1]->v.size() == 3 + 3 * numSteps &&
+            (int)p[2]->v.size() == 3 + 3 * numSteps){
+      numComp = 3; data2->NbVT++; vec = &data2->VT;
+    }
+    else{
+      numComp = 1; data2->NbST++; vec = &data2->ST;
+    }
+    for(int nod = 0; nod < 3; nod++) vec->push_back(p[nod]->v[0]);
+    for(int nod = 0; nod < 3; nod++) vec->push_back(p[nod]->v[1]);
+    for(int nod = 0; nod < 3; nod++) vec->push_back(p[nod]->v[2]);
+    for(int step = 0; step < numSteps; step++)
+      for(int nod = 0; nod < 3; nod++)
+        for(int comp = 0; comp < numComp; comp++)
+          vec->push_back(p[nod]->v[3 + numComp * step + comp]);
+    delete tris[i];
+  }
+#endif
+
   for(unsigned int i = 0; i < points.size(); i++)
     delete points[i];
 
diff --git a/Plugin/Warp.cpp b/Plugin/Warp.cpp
index 4bec27f..d2c2d73 100644
--- a/Plugin/Warp.cpp
+++ b/Plugin/Warp.cpp
@@ -96,13 +96,15 @@ PView *GMSH_WarpPlugin::execute(PView *v)
     }
   }
 
-  // tag all the nodes with "0" (the default tag)
-  for(int step = 0; step < data1->getNumTimeSteps(); step++){
-    for(int ent = 0; ent < data1->getNumEntities(step); ent++){
-      for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
-        if(data1->skipElement(step, ent, ele)) continue;
-        for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
-          data1->tagNode(step, ent, ele, nod, 0);
+  if(data1->isNodeData()){
+    // tag all the nodes with "0" (the default tag)
+    for(int step = 0; step < data1->getNumTimeSteps(); step++){
+      for(int ent = 0; ent < data1->getNumEntities(step); ent++){
+        for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
+          if(data1->skipElement(step, ent, ele)) continue;
+          for(int nod = 0; nod < data1->getNumNodes(step, ent, ele); nod++)
+            data1->tagNode(step, ent, ele, nod, 0);
+        }
       }
     }
   }
@@ -113,6 +115,7 @@ PView *GMSH_WarpPlugin::execute(PView *v)
       for(int ele = 0; ele < data1->getNumElements(step, ent); ele++){
         if(data1->skipElement(step, ent, ele)) continue;
         int numNodes = data1->getNumNodes(step, ent, ele);
+        if(numNodes < 2) continue;
         double x[8], y[8], z[8], n[3] = {0., 0., 0.};
         int tag[8];
         for(int nod = 0; nod < numNodes; nod++)
@@ -121,7 +124,7 @@ PView *GMSH_WarpPlugin::execute(PView *v)
         if(normals && dim == 2)
           normal3points(x[0], y[0], z[0], x[1], y[1], z[1], x[2], y[2], z[2], n);
         for(int nod = 0; nod < numNodes; nod++){
-          if(tag[nod]) continue; // already transformed
+          if(data1->isNodeData() && tag[nod]) continue; // already transformed
           double mult = 1., val[3] = {n[0], n[1], n[2]};
           if(normals){
             if(dim == 2){
@@ -138,7 +141,7 @@ PView *GMSH_WarpPlugin::execute(PView *v)
           y[nod] += factor * mult * val[1];
           z[nod] += factor * mult * val[2];
           data1->setNode(step, ent, ele, nod, x[nod], y[nod], z[nod]);
-          data1->tagNode(step, ent, ele, nod, 1);
+          if(data1->isNodeData()) data1->tagNode(step, ent, ele, nod, 1);
         }
       }
     }
diff --git a/Post/PViewData.cpp b/Post/PViewData.cpp
index d4ed4fd..768d88f 100644
--- a/Post/PViewData.cpp
+++ b/Post/PViewData.cpp
@@ -188,43 +188,55 @@ bool PViewData::combineSpace(nameData &nd)
 }
 
 bool PViewData::searchScalar(double x, double y, double z, double *values,
-                             int step, double *size)
+                             int step, double *size, int qn,
+                             double *qx, double *qy, double *qz)
 {
   if(!_octree) _octree = new OctreePost(this);
-  return _octree->searchScalar(x, y, z, values, step, size);
+  return _octree->searchScalar(x, y, z, values, step, size,
+                               qn, qx, qy, qz);
 }
 
 bool PViewData::searchScalarWithTol(double x, double y, double z, double *values,
-                                    int step, double *size, double tol)
+                                    int step, double *size, double tol, int qn,
+                                    double *qx, double *qy, double *qz)
 {
   if(!_octree) _octree = new OctreePost(this);
-  return _octree->searchScalarWithTol(x, y, z, values, step, size, tol);
+  return _octree->searchScalarWithTol(x, y, z, values, step, size, tol,
+                                      qn, qx, qy, qz);
 }
 
 bool PViewData::searchVector(double x, double y, double z, double *values,
-                             int step, double *size)
+                             int step, double *size, int qn,
+                             double *qx, double *qy, double *qz)
 {
   if(!_octree) _octree = new OctreePost(this);
-  return _octree->searchVector(x, y, z, values, step, size);
+  return _octree->searchVector(x, y, z, values, step, size,
+                               qn, qx, qy, qz);
 }
 
 bool PViewData::searchVectorWithTol(double x, double y, double z, double *values,
-                                    int step, double *size, double tol)
+                                    int step, double *size, double tol, int qn,
+                                    double *qx, double *qy, double *qz)
 {
   if(!_octree) _octree = new OctreePost(this);
-  return _octree->searchVectorWithTol(x, y, z, values, step, size, tol);
+  return _octree->searchVectorWithTol(x, y, z, values, step, size, tol,
+                                      qn, qx, qy, qz);
 }
 
 bool PViewData::searchTensor(double x, double y, double z, double *values,
-                             int step, double *size)
+                             int step, double *size, int qn,
+                             double *qx, double *qy, double *qz)
 {
   if(!_octree) _octree = new OctreePost(this);
-  return _octree->searchTensor(x, y, z, values, step, size);
+  return _octree->searchTensor(x, y, z, values, step, size,
+                               qn, qx, qy, qz);
 }
 
 bool PViewData::searchTensorWithTol(double x, double y, double z, double *values,
-                                    int step, double *size, double tol)
+                                    int step, double *size, double tol, int qn,
+                                    double *qx, double *qy, double *qz)
 {
   if(!_octree) _octree = new OctreePost(this);
-  return _octree->searchTensorWithTol(x, y, z, values, step, size, tol);
+  return _octree->searchTensorWithTol(x, y, z, values, step, size, tol,
+                                      qn, qx, qy, qz);
 }
diff --git a/Post/PViewData.h b/Post/PViewData.h
index 5d82cd1..c4e8d1c 100644
--- a/Post/PViewData.h
+++ b/Post/PViewData.h
@@ -189,6 +189,7 @@ class PViewData {
   virtual bool hasPartition(int step, int part){ return false; }
   virtual bool hasMultipleMeshes(){ return false; }
   virtual bool hasModel(GModel *model, int step=-1){ return false; }
+  virtual bool isNodeData(){ return false; }
 
   // true if data is given at Gauss points (instead of vertices)
   virtual bool useGaussPoints(){ return false; }
@@ -252,17 +253,23 @@ class PViewData {
   // time steps are present, they are all interpolated unless time step is set
   // to a different value than -1.
   bool searchScalar(double x, double y, double z, double *values,
-                    int step=-1, double *size=0);
+                    int step=-1, double *size=0, int qn=0,
+                    double *qx=0, double *qy=0, double *qz=0);
   bool searchScalarWithTol(double x, double y, double z, double *values,
-                           int step=-1, double *size=0, double tol=1.e-2);
+                           int step=-1, double *size=0, double tol=1.e-2, int qn=0,
+                           double *qx=0, double *qy=0, double *qz=0);
   bool searchVector(double x, double y, double z, double *values,
-                    int step=-1, double *size=0);
+                    int step=-1, double *size=0, int qn=0,
+                    double *qx=0, double *qy=0, double *qz=0);
   bool searchVectorWithTol(double x, double y, double z, double *values,
-                           int step=-1, double *size=0, double tol=1.e-2);
+                           int step=-1, double *size=0, double tol=1.e-2, int qn=0,
+                           double *qx=0, double *qy=0, double *qz=0);
   bool searchTensor(double x, double y, double z, double *values,
-                    int step=-1, double *size=0);
+                    int step=-1, double *size=0, int qn=0,
+                    double *qx=0, double *qy=0, double *qz=0);
   bool searchTensorWithTol(double x, double y, double z, double *values,
-                           int step=-1, double *size=0, double tol=1.e-2);
+                           int step=-1, double *size=0, double tol=1.e-2, int qn=0,
+                           double *qx=0, double *qy=0, double *qz=0);
 
   // I/O routines
   virtual bool writeSTL(const std::string &fileName);
diff --git a/Post/PViewDataGModel.h b/Post/PViewDataGModel.h
index a2c0a47..226396b 100644
--- a/Post/PViewDataGModel.h
+++ b/Post/PViewDataGModel.h
@@ -227,6 +227,7 @@ class PViewDataGModel : public PViewData {
   bool hasPartition(int step, int part);
   bool hasMultipleMeshes();
   bool hasModel(GModel *model, int step=-1);
+  bool isNodeData(){ return _type == NodeData; }
   bool useGaussPoints(){ return _type == GaussPointData; }
   GModel* getModel(int step){ return _steps[step]->getModel(); }
   GEntity *getEntity(int step, int ent);
diff --git a/Post/PViewDataIO.cpp b/Post/PViewDataIO.cpp
index 1d0138b..5b11050 100644
--- a/Post/PViewDataIO.cpp
+++ b/Post/PViewDataIO.cpp
@@ -215,8 +215,13 @@ bool PViewData::toVector(std::vector<std::vector<double> > &vec)
 
 bool PViewData::fromVector(const std::vector<std::vector<double> > &vec)
 {
+  if(empty() || !getNumTimeSteps()){
+    Msg::Warning("Cannot import vector in an empty view; skipping");
+    return false;
+  }
+
   if((int)vec.size() != getNumTimeSteps()){
-    Msg::Error("Incompatible number of steps in vector (%d) and view (%d)",
+    Msg::Error("Incompatible number of steps in vector for view import (%d!=%d)",
                (int)vec.size(), getNumTimeSteps());
     return false;
   }
@@ -234,7 +239,8 @@ bool PViewData::fromVector(const std::vector<std::vector<double> > &vec)
               setValue(step, ent, ele, nod, comp, vec[step][i++]);
             }
             else{
-              Msg::Error("Bad index (%d) in vector (%d)", i, (int)vec[step].size());
+              Msg::Error("Bad index (%d) in vector (%d) for view import",
+                         i, (int)vec[step].size());
               return false;
             }
           }
diff --git a/Post/PViewDataList.cpp b/Post/PViewDataList.cpp
index 5b1a60a..1886fee 100644
--- a/Post/PViewDataList.cpp
+++ b/Post/PViewDataList.cpp
@@ -630,13 +630,17 @@ bool PViewDataList::combineSpace(nameData &nd)
       return false;
     }
 
-    // copy interpolation marices
+    // copy interpolation matrices
     for(std::map<int, std::vector<fullMatrix<double>*> >::iterator it =
           l->_interpolation.begin(); it != l->_interpolation.end(); it++)
       if(_interpolation[it->first].empty())
         for(unsigned int i = 0; i < it->second.size(); i++)
           _interpolation[it->first].push_back(new fullMatrix<double>(*it->second[i]));
 
+    // copy time values
+
+    if(!i) Time = l->Time;
+
     // merge elememts
     dVecMerge(l->SP, SP); NbSP += l->NbSP; dVecMerge(l->VP, VP); NbVP += l->NbVP;
     dVecMerge(l->TP, TP); NbTP += l->NbTP; dVecMerge(l->SL, SL); NbSL += l->NbSL;
@@ -696,9 +700,9 @@ bool PViewDataList::combineSpace(nameData &nd)
     tmp = nd.name;
   char name[256];
   sprintf(name, "%s_Combine", tmp.c_str());
-
   setName(name);
   setFileName(std::string(name) + ".pos");
+
   return finalize();
 }
 
diff --git a/Post/PViewDataListIO.cpp b/Post/PViewDataListIO.cpp
index 0ef1cd1..3228133 100644
--- a/Post/PViewDataListIO.cpp
+++ b/Post/PViewDataListIO.cpp
@@ -392,6 +392,7 @@ bool PViewDataList::writePOS(const std::string &fileName, bool binary, bool pars
       int one = 1;
       if(!fwrite(&one, sizeof(int), 1, fp)){
         Msg::Error("Write error");
+        fclose(fp);
         return false;
       }
     }
diff --git a/Post/PViewIO.cpp b/Post/PViewIO.cpp
index b838a72..9932ded 100644
--- a/Post/PViewIO.cpp
+++ b/Post/PViewIO.cpp
@@ -21,8 +21,8 @@ bool PView::readPOS(const std::string &fileName, int fileIndex)
   }
 
   char str[256] = "XXX";
-  double version;
-  int format, size, index = -1;
+  double version = -1.;
+  int format = -1, size = -1, index = -1;
 
   while(1) {
 
@@ -38,16 +38,19 @@ bool PView::readPOS(const std::string &fileName, int fileIndex)
 
       if(!fscanf(fp, "%lf %d %d\n", &version, &format, &size)){
         Msg::Error("Read error");
+        fclose(fp);
         return false;
       }
       if(version < 1.0) {
         Msg::Error("Post-processing file too old (ver. %g < 1.0)", version);
+        fclose(fp);
         return false;
       }
       if(size == sizeof(double))
         Msg::Debug("Data is in double precision format (size==%d)", size);
       else {
         Msg::Error("Unknown data size (%d) in post-processing file", size);
+        fclose(fp);
         return false;
       }
 
@@ -59,6 +62,7 @@ bool PView::readPOS(const std::string &fileName, int fileIndex)
         if(!d->readPOS(fp, version, format ? true : false)){
           Msg::Error("Could not read data in list format");
           delete d;
+          fclose(fp);
           return false;
         }
         else{
@@ -78,7 +82,6 @@ bool PView::readPOS(const std::string &fileName, int fileIndex)
   }
 
   fclose(fp);
-
   return true;
 }
 
diff --git a/Post/PViewVertexArrays.cpp b/Post/PViewVertexArrays.cpp
index cf25983..d26d909 100644
--- a/Post/PViewVertexArrays.cpp
+++ b/Post/PViewVertexArrays.cpp
@@ -677,7 +677,8 @@ static void addScalarPolygon(PView *p, double **xyz,
         ite != edges.end(); ite++){
       int i = (int) (*ite).second / 100;
       int j = (*ite).second % 100;
-      addScalarLine(p, xyz, val, pre, 3*i+il[j][0], 3*i+il[j][0], true);
+      if(j < 3)
+        addScalarLine(p, xyz, val, pre, 3*i+il[j][0], 3*i+il[j][0], true);
     }
     opt->boundary++;
 
@@ -772,8 +773,10 @@ static void addScalarHexahedron(PView *p, double **xyz,
 
   const int iq[6][4] = {{0, 3, 2, 1}, {0, 1, 5, 4}, {0, 4, 7, 3},
                         {1, 2, 6, 5}, {2, 3, 7, 6}, {4, 5, 6, 7}};
-  const int is[6][4] = {{0, 1, 3, 4}, {1, 3, 4, 5}, {3, 4, 5, 7},
-                        {1, 2, 3, 6}, {3, 1, 6, 5}, {6, 3, 5, 7}};
+  //const int is[6][4] = {{0, 1, 3, 4}, {1, 3, 4, 5}, {3, 4, 5, 7},
+  //                      {1, 2, 3, 6}, {3, 1, 6, 5}, {6, 3, 5, 7}};
+  const int is[6][4] = {{0,1,3,7}, {0,4,1,7}, {1,4,5,7},
+                        {1,2,3,7}, {1,6,2,7}, {1,5,6,7}};
 
   if(opt->boundary > 0){
     opt->boundary--;
@@ -804,7 +807,8 @@ static void addScalarPrism(PView *p, double **xyz, double **val, bool pre)
   PViewOptions *opt = p->getOptions();
   const int iq[3][4] = {{0, 1, 4, 3}, {0, 3, 5, 2}, {1, 2, 5, 4}};
   const int it[2][3] = {{0, 2, 1}, {3, 4, 5}};
-  const int is[3][4] = {{0, 1, 2, 3}, {3, 4, 5, 2}, {1, 2, 4, 3}};
+  // const int is[3][4] = {{0, 1, 2, 3}, {3, 4, 5, 2}, {1, 2, 4, 3}};
+  const int is[3][4] = {{0,1,2,4}, {0,2,4,5}, {0,3,4,5}};
 
   if(opt->boundary > 0){
     opt->boundary--;
@@ -836,7 +840,8 @@ static void addScalarPyramid(PView *p, double **xyz,
   PViewOptions *opt = p->getOptions();
 
   const int it[4][3] = {{0, 1, 4}, {3, 0, 4}, {1, 2, 4}, {2, 3, 4}};
-  const int is[2][4] = {{0, 1, 2, 4}, {2, 3, 0, 4}};
+  //const int is[2][4] = {{0, 1, 2, 4}, {2, 3, 0, 4}};
+  const int is[2][4] = {{0,1,3,4}, {1,2,3,4}};
 
   if(opt->boundary > 0){
     opt->boundary--;
@@ -854,6 +859,7 @@ static void addScalarPyramid(PView *p, double **xyz,
 static void addOutlinePolyhedron(PView *p, double **xyz,
                                  unsigned int color, bool pre, int numNodes)
 {
+  // FIXME: this code is horribly slow
   const int it[4][3] = {{0, 2, 1}, {0, 1, 3}, {0, 3, 2}, {3, 1, 2}};
   std::map<MFace, int, Less_Face> triFaces;
   std::vector<MVertex *> verts;
@@ -874,7 +880,8 @@ static void addOutlinePolyhedron(PView *p, double **xyz,
       ite != triFaces.end(); ite++){
     int i = (int) (*ite).second / 100;
     int j = (*ite).second % 100;
-    addOutlineTriangle(p, xyz, color, pre, 4*i+it[j][0], 4*i+it[j][1], 4*i+it[j][2]);
+    if(j < 4)
+      addOutlineTriangle(p, xyz, color, pre, 4*i+it[j][0], 4*i+it[j][1], 4*i+it[j][2]);
   }
   for(int i = 0; i < numNodes; i++)
     delete verts[i];
diff --git a/Post/adaptiveData.cpp b/Post/adaptiveData.cpp
index efdf29e..2d91ede 100644
--- a/Post/adaptiveData.cpp
+++ b/Post/adaptiveData.cpp
@@ -47,7 +47,7 @@ int adaptiveHexahedron::numEdges = 12;
 
 template <class T>
 static void cleanElement()
-{  
+{
   for(typename std::list<T*>::iterator it = T::all.begin(); it != T::all.end(); ++it)
     delete *it;
   T::all.clear();
@@ -123,7 +123,7 @@ void adaptiveLine::recurCreate(adaptiveLine *e, int maxlevel, int level)
   adaptiveVertex *p1 = e->p[0];
   adaptiveVertex *p2 = e->p[1];
   adaptiveVertex *p12 = adaptiveVertex::add
-    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5, 
+    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5,
      allVertices);
   adaptiveLine *e1 = new adaptiveLine(p1, p12);
   recurCreate(e1, maxlevel, level);
@@ -201,13 +201,13 @@ void adaptiveTriangle::recurCreate(adaptiveTriangle *t, int maxlevel, int level)
   adaptiveVertex *p2 = t->p[1];
   adaptiveVertex *p3 = t->p[2];
   adaptiveVertex *p12 = adaptiveVertex::add
-    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5, 
+    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5,
      allVertices);
   adaptiveVertex *p13 = adaptiveVertex::add
-    ((p1->x + p3->x) * 0.5, (p1->y + p3->y) * 0.5, (p1->z + p3->z) * 0.5, 
+    ((p1->x + p3->x) * 0.5, (p1->y + p3->y) * 0.5, (p1->z + p3->z) * 0.5,
      allVertices);
   adaptiveVertex *p23 = adaptiveVertex::add
-    ((p3->x + p2->x) * 0.5, (p3->y + p2->y) * 0.5, (p3->z + p2->z) * 0.5, 
+    ((p3->x + p2->x) * 0.5, (p3->y + p2->y) * 0.5, (p3->z + p2->z) * 0.5,
      allVertices);
   adaptiveTriangle *t1 = new adaptiveTriangle(p1, p12, p13);
   recurCreate(t1, maxlevel, level);
@@ -315,19 +315,19 @@ void adaptiveQuadrangle::recurCreate(adaptiveQuadrangle *q, int maxlevel, int le
   adaptiveVertex *p3 = q->p[2];
   adaptiveVertex *p4 = q->p[3];
   adaptiveVertex *p12 = adaptiveVertex::add
-    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5, 
+    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5,
      allVertices);
   adaptiveVertex *p23 = adaptiveVertex::add
-    ((p2->x + p3->x) * 0.5, (p2->y + p3->y) * 0.5, (p2->z + p3->z) * 0.5, 
+    ((p2->x + p3->x) * 0.5, (p2->y + p3->y) * 0.5, (p2->z + p3->z) * 0.5,
      allVertices);
   adaptiveVertex *p34 = adaptiveVertex::add
-    ((p3->x + p4->x) * 0.5, (p3->y + p4->y) * 0.5, (p3->z + p4->z) * 0.5, 
+    ((p3->x + p4->x) * 0.5, (p3->y + p4->y) * 0.5, (p3->z + p4->z) * 0.5,
      allVertices);
   adaptiveVertex *p14 = adaptiveVertex::add
-    ((p1->x + p4->x) * 0.5, (p1->y + p4->y) * 0.5, (p1->z + p4->z) * 0.5, 
+    ((p1->x + p4->x) * 0.5, (p1->y + p4->y) * 0.5, (p1->z + p4->z) * 0.5,
      allVertices);
   adaptiveVertex *pc = adaptiveVertex::add
-    ((p1->x + p2->x + p3->x + p4->x) * 0.25, (p1->y + p2->y + p3->y + p4->y) * 0.25, 
+    ((p1->x + p2->x + p3->x + p4->x) * 0.25, (p1->y + p2->y + p3->y + p4->y) * 0.25,
      (p1->z + p2->z + p3->z + p4->z) * 0.25, allVertices);
   adaptiveQuadrangle *q1 = new adaptiveQuadrangle(p1, p12, pc, p14);
   recurCreate(q1, maxlevel, level);
@@ -441,7 +441,7 @@ void adaptiveTetrahedron::recurCreate(adaptiveTetrahedron *t, int maxlevel, int
     ((p0->x + p3->x) * 0.5, (p0->y + p3->y) * 0.5, (p0->z + p3->z) * 0.5,
      allVertices);
   adaptiveVertex *pe3 = adaptiveVertex::add
-    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5, 
+    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5,
      allVertices);
   adaptiveVertex *pe4 = adaptiveVertex::add
     ((p1->x + p3->x) * 0.5, (p1->y + p3->y) * 0.5, (p1->z + p3->z) * 0.5,
@@ -578,7 +578,7 @@ void adaptiveHexahedron::recurCreate(adaptiveHexahedron *h, int maxlevel, int le
   adaptiveVertex *p6 = h->p[6];
   adaptiveVertex *p7 = h->p[7];
   adaptiveVertex *p01 = adaptiveVertex::add
-    ((p0->x + p1->x) * 0.5, (p0->y + p1->y) * 0.5, (p0->z + p1->z) * 0.5, 
+    ((p0->x + p1->x) * 0.5, (p0->y + p1->y) * 0.5, (p0->z + p1->z) * 0.5,
      allVertices);
   adaptiveVertex *p12 = adaptiveVertex::add
     ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5,
@@ -614,19 +614,19 @@ void adaptiveHexahedron::recurCreate(adaptiveHexahedron *h, int maxlevel, int le
     ((p7->x + p3->x) * 0.5, (p7->y + p3->y) * 0.5, (p7->z + p3->z) * 0.5,
      allVertices);
   adaptiveVertex *p0145 = adaptiveVertex::add
-    ((p45->x + p01->x) * 0.5, (p45->y + p01->y) * 0.5,(p45->z + p01->z) * 0.5, 
+    ((p45->x + p01->x) * 0.5, (p45->y + p01->y) * 0.5,(p45->z + p01->z) * 0.5,
      allVertices);
   adaptiveVertex *p1256 = adaptiveVertex::add
-    ((p12->x + p56->x) * 0.5, (p12->y + p56->y) * 0.5, (p12->z + p56->z) * 0.5, 
+    ((p12->x + p56->x) * 0.5, (p12->y + p56->y) * 0.5, (p12->z + p56->z) * 0.5,
      allVertices);
   adaptiveVertex *p2367 = adaptiveVertex::add
-    ((p23->x + p67->x) * 0.5, (p23->y + p67->y) * 0.5, (p23->z + p67->z) * 0.5, 
+    ((p23->x + p67->x) * 0.5, (p23->y + p67->y) * 0.5, (p23->z + p67->z) * 0.5,
      allVertices);
   adaptiveVertex *p0347 = adaptiveVertex::add
     ((p03->x + p47->x) * 0.5, (p03->y + p47->y) * 0.5, (p03->z + p47->z) * 0.5,
      allVertices);
   adaptiveVertex *p4756 = adaptiveVertex::add
-    ((p47->x + p56->x) * 0.5, (p47->y + p56->y) * 0.5, (p47->z + p56->z) * 0.5, 
+    ((p47->x + p56->x) * 0.5, (p47->y + p56->y) * 0.5, (p47->z + p56->z) * 0.5,
      allVertices);
   adaptiveVertex *p0312 = adaptiveVertex::add
     ((p03->x + p12->x) * 0.5, (p03->y + p12->y) * 0.5, (p03->z + p12->z) * 0.5,
@@ -773,40 +773,40 @@ void adaptivePrism::recurCreate(adaptivePrism *p, int maxlevel, int level)
   adaptiveVertex *p5 = p->p[4];
   adaptiveVertex *p6 = p->p[5];
   adaptiveVertex *p14 = adaptiveVertex::add
-    ((p1->x + p4->x) * 0.5, (p1->y + p4->y) * 0.5, (p1->z + p4->z) * 0.5, 
+    ((p1->x + p4->x) * 0.5, (p1->y + p4->y) * 0.5, (p1->z + p4->z) * 0.5,
      allVertices);
   adaptiveVertex *p25 = adaptiveVertex::add
-    ((p2->x + p5->x) * 0.5, (p2->y + p5->y) * 0.5, (p2->z + p5->z) * 0.5, 
+    ((p2->x + p5->x) * 0.5, (p2->y + p5->y) * 0.5, (p2->z + p5->z) * 0.5,
      allVertices);
   adaptiveVertex *p36 = adaptiveVertex::add
-    ((p3->x + p6->x) * 0.5, (p3->y + p6->y) * 0.5, (p3->z + p6->z) * 0.5, 
+    ((p3->x + p6->x) * 0.5, (p3->y + p6->y) * 0.5, (p3->z + p6->z) * 0.5,
      allVertices);
   adaptiveVertex *p12 = adaptiveVertex::add
-    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5, 
+    ((p1->x + p2->x) * 0.5, (p1->y + p2->y) * 0.5, (p1->z + p2->z) * 0.5,
      allVertices);
   adaptiveVertex *p23 = adaptiveVertex::add
-    ((p2->x + p3->x) * 0.5, (p2->y + p3->y) * 0.5, (p2->z + p3->z) * 0.5, 
+    ((p2->x + p3->x) * 0.5, (p2->y + p3->y) * 0.5, (p2->z + p3->z) * 0.5,
      allVertices);
   adaptiveVertex *p31 = adaptiveVertex::add
-    ((p3->x + p1->x) * 0.5, (p3->y + p1->y) * 0.5, (p3->z + p1->z) * 0.5, 
+    ((p3->x + p1->x) * 0.5, (p3->y + p1->y) * 0.5, (p3->z + p1->z) * 0.5,
      allVertices);
   adaptiveVertex *p1425 = adaptiveVertex::add
-    ((p14->x + p25->x) * 0.5, (p14->y + p25->y) * 0.5, (p14->z + p25->z) * 0.5, 
+    ((p14->x + p25->x) * 0.5, (p14->y + p25->y) * 0.5, (p14->z + p25->z) * 0.5,
      allVertices);
   adaptiveVertex *p2536 = adaptiveVertex::add
-    ((p25->x + p36->x) * 0.5, (p25->y + p36->y) * 0.5, (p25->z + p36->z) * 0.5, 
+    ((p25->x + p36->x) * 0.5, (p25->y + p36->y) * 0.5, (p25->z + p36->z) * 0.5,
      allVertices);
   adaptiveVertex *p3614 = adaptiveVertex::add
-    ((p36->x + p14->x) * 0.5, (p36->y + p14->y) * 0.5, (p36->z + p14->z) * 0.5, 
+    ((p36->x + p14->x) * 0.5, (p36->y + p14->y) * 0.5, (p36->z + p14->z) * 0.5,
      allVertices);
   adaptiveVertex *p45 = adaptiveVertex::add
-    ((p4->x + p5->x) * 0.5, (p4->y + p5->y) * 0.5, (p4->z + p5->z) * 0.5, 
+    ((p4->x + p5->x) * 0.5, (p4->y + p5->y) * 0.5, (p4->z + p5->z) * 0.5,
      allVertices);
   adaptiveVertex *p56 = adaptiveVertex::add
-    ((p5->x + p6->x) * 0.5, (p5->y + p6->y) * 0.5, (p5->z + p6->z) * 0.5, 
+    ((p5->x + p6->x) * 0.5, (p5->y + p6->y) * 0.5, (p5->z + p6->z) * 0.5,
      allVertices);
   adaptiveVertex *p64 = adaptiveVertex::add
-    ((p6->x + p4->x) * 0.5, (p6->y + p4->y) * 0.5, (p6->z + p4->z) * 0.5, 
+    ((p6->x + p4->x) * 0.5, (p6->y + p4->y) * 0.5, (p6->z + p4->z) * 0.5,
      allVertices);
   p->e[0] = new adaptivePrism(p1, p12, p31, p14, p1425, p3614);
   recurCreate(p->e[0], maxlevel, level);
@@ -916,24 +916,24 @@ void adaptiveElements<T>::init(int level)
   T::create(level);
   int numVals = _coeffsVal ? _coeffsVal->size1() : T::numNodes;
   int numNodes = _coeffsGeom ? _coeffsGeom->size1() : T::numNodes;
-  
+
   if(_interpolVal) delete _interpolVal;
   _interpolVal = new fullMatrix<double>(T::allVertices.size(), numVals);
-  
+
   if(_interpolGeom) delete _interpolGeom;
   _interpolGeom = new fullMatrix<double>(T::allVertices.size(), numNodes);
-  
+
   fullVector<double> sfv(numVals), *tmpv = 0;
   fullVector<double> sfg(numNodes), *tmpg = 0;
   if(_eexpsVal) tmpv = new fullVector<double>(_eexpsVal->size1());
   if(_eexpsGeom) tmpg = new fullVector<double>(_eexpsGeom->size1());
 
   int i = 0;
-  for(std::set<adaptiveVertex>::iterator it = T::allVertices.begin(); 
+  for(std::set<adaptiveVertex>::iterator it = T::allVertices.begin();
       it != T::allVertices.end(); ++it) {
 
     if(_coeffsVal && _eexpsVal)
-      computeShapeFunctions(_coeffsVal, _eexpsVal, 
+      computeShapeFunctions(_coeffsVal, _eexpsVal,
                             it->x, it->y, it->z, &sfv, tmpv);
     else
       T::GSF(it->x, it->y, it->z, sfv);
@@ -941,7 +941,7 @@ void adaptiveElements<T>::init(int level)
       (*_interpolVal)(i, j) = sfv(j);
 
     if(_coeffsGeom && _eexpsGeom)
-      computeShapeFunctions(_coeffsGeom, _eexpsGeom, 
+      computeShapeFunctions(_coeffsGeom, _eexpsGeom,
                             it->x, it->y, it->z, &sfg, tmpg);
     else
       T::GSF(it->x, it->y, it->z, sfg);
@@ -961,10 +961,10 @@ void adaptiveElements<T>::init(int level)
 }
 
 template <class T>
-void adaptiveElements<T>::adapt(double tol, int numComp, 
+void adaptiveElements<T>::adapt(double tol, int numComp,
                                 std::vector<PCoords> &coords,
-                                std::vector<PValues> &values, 
-                                double &minVal, double &maxVal, 
+                                std::vector<PValues> &values,
+                                double &minVal, double &maxVal,
                                 GMSH_PostPlugin *plug,
                                 bool onlyComputeMinMax)
 {
@@ -972,17 +972,17 @@ void adaptiveElements<T>::adapt(double tol, int numComp,
     Msg::Error("Can only adapt scalar or vector data");
     return;
   }
-  
+
   int numVertices = T::allVertices.size();
 
   if(!numVertices){
     Msg::Error("No adapted vertices to interpolate");
     return;
   }
-  
+
   int numVals = _coeffsVal ? _coeffsVal->size1() : T::numNodes;
   if(numVals != (int)values.size()){
-    Msg::Error("Wrong number of values in adaptation %d != %i", 
+    Msg::Error("Wrong number of values in adaptation %d != %i",
                numVals, values.size());
     return;
   }
@@ -990,7 +990,7 @@ void adaptiveElements<T>::adapt(double tol, int numComp,
 #ifdef TIMER
   double t1 = GetTimeInSeconds();
 #endif
-  
+
   fullVector<double> val(numVals), res(numVertices);
   if(numComp == 1){
     for(int i = 0; i < numVals; i++)
@@ -1003,14 +1003,14 @@ void adaptiveElements<T>::adapt(double tol, int numComp,
   }
   _interpolVal->mult(val, res);
 
-  //minVal = VAL_INF;  
-  //maxVal = -VAL_INF;  
+  //minVal = VAL_INF;
+  //maxVal = -VAL_INF;
   for(int i = 0; i < numVertices; i++){
     minVal = std::min(minVal, res(i));
     maxVal = std::max(maxVal, res(i));
   }
   if(onlyComputeMinMax) return;
-  
+
   fullMatrix<double> *resxyz = 0;
   if(numComp == 3){
     fullMatrix<double> valxyz(numVals, 3);
@@ -1022,14 +1022,15 @@ void adaptiveElements<T>::adapt(double tol, int numComp,
     }
     _interpolVal->mult(valxyz, *resxyz);
   }
-  
+
   int numNodes = _coeffsGeom ? _coeffsGeom->size1() : T::numNodes;
   if(numNodes != (int)coords.size()){
-    Msg::Error("Wrong number of nodes in adaptation %d != %i", 
+    Msg::Error("Wrong number of nodes in adaptation %d != %i",
                numNodes, coords.size());
+    if(resxyz) delete resxyz;
     return;
   }
-  
+
   fullMatrix<double> xyz(numNodes, 3), XYZ(numVertices, 3);
   for(int i = 0; i < numNodes; i++){
     xyz(i, 0) = coords[i].c[0];
@@ -1059,22 +1060,22 @@ void adaptiveElements<T>::adapt(double tol, int numComp,
     p->Z = XYZ(i, 2);
     i++;
   }
-  
+
   if(resxyz) delete resxyz;
-  
-  for(typename std::list<T*>::iterator it = T::all.begin(); 
+
+  for(typename std::list<T*>::iterator it = T::all.begin();
       it != T::all.end(); it++)
     (*it)->visible = false;
-  
+
   if(!plug || tol != 0.){
     double avg = fabs(maxVal - minVal);
     if(tol < 0) avg = 1.; // force visibility to the smallest subdivision
     T::error(avg, tol);
   }
-  
+
   if(plug)
     plug->assignSpecificVisibility();
-  
+
   coords.clear();
   values.clear();
   for(typename std::list<T*>::iterator it = T::all.begin();
@@ -1093,23 +1094,23 @@ void adaptiveElements<T>::adapt(double tol, int numComp,
 }
 
 template <class T>
-void adaptiveElements<T>::addInView(double tol, int step, 
-                                    PViewData *in, PViewDataList *out, 
+void adaptiveElements<T>::addInView(double tol, int step,
+                                    PViewData *in, PViewDataList *out,
                                     GMSH_PostPlugin *plug)
 {
   int numComp = in->getNumComponents(0, 0, 0);
   if(numComp != 1 && numComp != 3) return;
-  
+
   int numEle = 0, *outNb = 0;
   std::vector<double> *outList = 0;
   switch(T::numEdges){
-  case 0: 
-    numEle = in->getNumPoints(); 
+  case 0:
+    numEle = in->getNumPoints();
     outNb = (numComp == 1) ? &out->NbSP : &out->NbVP;
     outList = (numComp == 1) ? &out->SP : &out->VP;
     break;
-  case 1: 
-    numEle = in->getNumLines(); 
+  case 1:
+    numEle = in->getNumLines();
     outNb = (numComp == 1) ? &out->NbSL : &out->NbVL;
     outList = (numComp == 1) ? &out->SL : &out->VL;
     break;
@@ -1128,22 +1129,22 @@ void adaptiveElements<T>::addInView(double tol, int step,
     outNb = (numComp == 1) ? &out->NbSS : &out->NbVS;
     outList = (numComp == 1) ? &out->SS : &out->VS;
     break;
-  case 9: 
+  case 9:
     numEle = in->getNumPrisms();
     outNb = (numComp == 1) ? &out->NbSI : &out->NbVI;
     outList = (numComp == 1) ? &out->SI : &out->VI;
     break;
-  case 12: 
+  case 12:
     numEle = in->getNumHexahedra();
     outNb = (numComp == 1) ? &out->NbSH : &out->NbVH;
     outList = (numComp == 1) ? &out->SH : &out->VH;
     break;
   }
   if(!numEle) return;
-  
+
   outList->clear();
   *outNb = 0;
-  
+
   for(int ent = 0; ent < in->getNumEntities(step); ent++){
     for(int ele = 0; ele < in->getNumElements(step, ent); ele++){
       if(in->skipElement(step, ent, ele) ||
@@ -1167,20 +1168,20 @@ void adaptiveElements<T>::addInView(double tol, int step,
       else if(numComp == 3){
         for(int i = 0; i < numVal / 3; i++){
           double vx, vy, vz;
-          in->getValue(step, ent, ele, 3 * i, vx); 
-          in->getValue(step, ent, ele, 3 * i + 1, vy); 
-          in->getValue(step, ent, ele, 3 * i + 2, vz); 
+          in->getValue(step, ent, ele, 3 * i, vx);
+          in->getValue(step, ent, ele, 3 * i + 1, vy);
+          in->getValue(step, ent, ele, 3 * i + 2, vz);
           values.push_back(PValues(vx, vy, vz));
         }
       }
       adapt(tol, numComp, coords, values, out->Min, out->Max, plug);
       *outNb += coords.size() / T::numNodes;
       for(unsigned int i = 0; i < coords.size() / T::numNodes; i++){
-        for(int k = 0; k < T::numNodes; ++k) 
+        for(int k = 0; k < T::numNodes; ++k)
           outList->push_back(coords[T::numNodes * i + k].c[0]);
-        for(int k = 0; k < T::numNodes; ++k) 
+        for(int k = 0; k < T::numNodes; ++k)
           outList->push_back(coords[T::numNodes * i + k].c[1]);
-        for(int k = 0; k < T::numNodes; ++k) 
+        for(int k = 0; k < T::numNodes; ++k)
           outList->push_back(coords[T::numNodes * i + k].c[2]);
         for(int k = 0; k < T::numNodes; ++k)
           for(int l = 0; l < numComp; ++l)
@@ -1191,8 +1192,8 @@ void adaptiveElements<T>::addInView(double tol, int step,
 }
 
 adaptiveData::adaptiveData(PViewData *data)
-  : _step(-1), _level(-1), _tol(-1.), _inData(data), 
-    _points(0), _lines(0), _triangles(0), _quadrangles(0), 
+  : _step(-1), _level(-1), _tol(-1.), _inData(data),
+    _points(0), _lines(0), _triangles(0), _quadrangles(0),
     _tetrahedra(0), _hexahedra(0), _prisms(0)
 {
   _outData = new PViewDataList(true);
@@ -1243,7 +1244,7 @@ adaptiveData::~adaptiveData()
 double adaptiveData::timerInit = 0.;
 double adaptiveData::timerAdapt = 0.;
 
-void adaptiveData::changeResolution(int step, int level, double tol, 
+void adaptiveData::changeResolution(int step, int level, double tol,
                                     GMSH_PostPlugin *plug)
 {
   timerInit = timerAdapt = 0.;
@@ -1271,7 +1272,7 @@ void adaptiveData::changeResolution(int step, int level, double tol,
   _step = step;
   _level = level;
   _tol = tol;
-  
+
 #ifdef TIMER
   printf("init time = %g\n", timerInit);
   printf("adapt time = %g\n", timerAdapt);
diff --git a/Solver/dofManager.cpp b/Solver/dofManager.cpp
index 77222fc..a6fff9b 100644
--- a/Solver/dofManager.cpp
+++ b/Solver/dofManager.cpp
@@ -3,13 +3,14 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
-#include <dofManager.h>
 #include "GmshConfig.h"
 
 #ifdef HAVE_MPI
 #include "mpi.h"
 #endif
 
+#include <dofManager.h>
+
 template<>
 void dofManager<double>::scatterSolution()
 {
diff --git a/Solver/eigenSolver.cpp b/Solver/eigenSolver.cpp
index bc2bc3f..17ee431 100644
--- a/Solver/eigenSolver.cpp
+++ b/Solver/eigenSolver.cpp
@@ -18,40 +18,40 @@ void eigenSolver::_try(int ierr) const
   CHKERRABORT(PETSC_COMM_WORLD, ierr);
 }
 
-eigenSolver::eigenSolver(dofManager<double> *manager, std::string A,
-                         std::string B, bool hermitian)
+eigenSolver::eigenSolver(dofManager<double> *manager, std::string A, std::string B, bool hermitian)
   : _A(0), _B(0), _hermitian(hermitian)
 {
-  if(A.size()){
+  if (A.size()) {
     _A = dynamic_cast<linearSystemPETSc<double>*>(manager->getLinearSystem(A));
     if(!_A) Msg::Error("Could not find PETSc system '%s'", A.c_str());
   }
-  if(B.size()){
+  if (B.size()) {
     _B = dynamic_cast<linearSystemPETSc<double>*>(manager->getLinearSystem(B));
     if(!_B) Msg::Error("Could not find PETSc system '%s'", B.c_str());
   }
 }
 
-eigenSolver::eigenSolver(linearSystemPETSc<double> *A,linearSystemPETSc<double> *B, bool hermitian) : _A(A), _B(B), _hermitian(hermitian){}
+eigenSolver::eigenSolver(linearSystemPETSc<double> *A, linearSystemPETSc<double> *B,
+  bool hermitian) : _A(A), _B(B), _hermitian(hermitian) {}
 
-bool eigenSolver::solve(int numEigenValues, std::string which)
+bool eigenSolver::solve(int numEigenValues, std::string which, std::string method, double tolVal, int iterMax)
 {
   if(!_A) return false;
   Mat A = _A->getMatrix();
   Mat B = _B ? _B->getMatrix() : PETSC_NULL;
-
+  
   PetscInt N, M;
   _try(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
   _try(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
   _try(MatGetSize(A, &N, &M));
-
+  
   PetscInt N2, M2;
   if (_B) {
     _try(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
     _try(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
     _try(MatGetSize(B, &N2, &M2));
   }
-
+  
   // generalized eigenvalue problem A x - \lambda B x = 0
   EPS eps;
   _try(EPSCreate(PETSC_COMM_WORLD, &eps));
@@ -60,37 +60,43 @@ bool eigenSolver::solve(int numEigenValues, std::string which)
     _try(EPSSetProblemType(eps, _B ? EPS_GHEP : EPS_HEP));
   else
     _try(EPSSetProblemType(eps, _B ? EPS_GNHEP : EPS_NHEP));
-
+  
   // set some default options
   _try(EPSSetDimensions(eps, numEigenValues, PETSC_DECIDE, PETSC_DECIDE));
-  _try(EPSSetTolerances(eps, 1.e-7, 20));//1.e-7 20
-  _try(EPSSetType(eps, EPSKRYLOVSCHUR)); //default
-  //_try(EPSSetType(eps, EPSARNOLDI));
-  //_try(EPSSetType(eps, EPSARPACK));
-  //_try(EPSSetType(eps, EPSPOWER));
-
+  _try(EPSSetTolerances(eps, tolVal, iterMax));
+  if (method=="krylovschur")
+    _try(EPSSetType(eps, EPSKRYLOVSCHUR));
+  else if (method=="arnoldi")
+    _try(EPSSetType(eps, EPSARNOLDI));
+  else if (method=="arpack")
+    _try(EPSSetType(eps, EPSARPACK));
+  else if (method=="power")
+    _try(EPSSetType(eps, EPSPOWER));
+  else
+    Msg::Fatal("eigenSolver: method '%s' not available", method.c_str());
+  
   // override these options at runtime, petsc-style
   _try(EPSSetFromOptions(eps));
-
+  
   // force options specified directly as arguments
-  if(numEigenValues)
+  if (numEigenValues)
     _try(EPSSetDimensions(eps, numEigenValues, PETSC_DECIDE, PETSC_DECIDE));
-  if(which == "smallest")
+  if (which=="smallest")
     _try(EPSSetWhichEigenpairs(eps, EPS_SMALLEST_MAGNITUDE));
-  else if(which == "smallestReal")
+  else if (which=="smallestReal")
     _try(EPSSetWhichEigenpairs(eps, EPS_SMALLEST_REAL));
-  else if(which == "largest")
+  else if (which=="largest")
     _try(EPSSetWhichEigenpairs(eps, EPS_LARGEST_MAGNITUDE));
-
+  
   // print info
-  #if (SLEPC_VERSION_RELEASE == 0 || (SLEPC_VERSION_MAJOR > 3 || (SLEPC_VERSION_MAJOR == 3 && SLEPC_VERSION_MINOR >= 4)))
+#if (SLEPC_VERSION_RELEASE == 0 || (SLEPC_VERSION_MAJOR > 3 || (SLEPC_VERSION_MAJOR == 3 && SLEPC_VERSION_MINOR >= 4)))
   EPSType type;
-  #else
+#else
   const EPSType type;
-  #endif
+#endif
   _try(EPSGetType(eps, &type));
   Msg::Debug("SLEPc solution method: %s", type);
-
+  
   PetscInt nev;
   _try(EPSGetDimensions(eps, &nev, PETSC_NULL, PETSC_NULL));
   Msg::Debug("SLEPc number of requested eigenvalues: %d", nev);
@@ -98,45 +104,45 @@ bool eigenSolver::solve(int numEigenValues, std::string which)
   PetscInt maxit;
   _try(EPSGetTolerances(eps, &tol, &maxit));
   Msg::Debug("SLEPc stopping condition: tol=%g, maxit=%d", tol, maxit);
-
+  
   // solve
   Msg::Info("SLEPc solving...");
   double t1 = Cpu();
   _try(EPSSolve(eps));
-
+  
   // check convergence
   int its;
   _try(EPSGetIterationNumber(eps, &its));
   EPSConvergedReason reason;
   _try(EPSGetConvergedReason(eps, &reason));
-  if(reason == EPS_CONVERGED_TOL){
-    double t2 = Cpu();
+  if (reason==EPS_CONVERGED_TOL) {
+    double t2=Cpu();
     Msg::Debug("SLEPc converged in %d iterations (%g s)", its, t2-t1);
   }
-  else if(reason == EPS_DIVERGED_ITS)
+  else if (reason==EPS_DIVERGED_ITS)
     Msg::Error("SLEPc diverged after %d iterations", its);
-  else if(reason == EPS_DIVERGED_BREAKDOWN)
+  else if (reason==EPS_DIVERGED_BREAKDOWN)
     Msg::Error("SLEPc generic breakdown in method");
 #if (SLEPC_VERSION_MAJOR < 3 || (SLEPC_VERSION_MAJOR == 3 && SLEPC_VERSION_MINOR < 2))
-  else if(reason == EPS_DIVERGED_NONSYMMETRIC)
+  else if (reason==EPS_DIVERGED_NONSYMMETRIC)
     Msg::Error("The operator is nonsymmetric");
 #endif
-
+  
   // get number of converged approximate eigenpairs
   PetscInt nconv;
   _try(EPSGetConverged(eps, &nconv));
   Msg::Debug("SLEPc number of converged eigenpairs: %d", nconv);
-
+  
   // ignore additional eigenvalues if we get more than what we asked
-  if(nconv > nev) nconv = nev;
+  if (nconv>nev) nconv = nev;
 
-  if (nconv > 0) {
+  if (nconv>0) {
     Vec xr, xi;
     _try(MatGetVecs(A, PETSC_NULL, &xr));
     _try(MatGetVecs(A, PETSC_NULL, &xi));
     Msg::Debug("         Re[EigenValue]          Im[EigenValue]"
-	       "          Relative error");
-    for (int i = 0; i < nconv; i++){
+         "          Relative error");
+    for (int i=0; i<nconv; i++) {
       PetscScalar kr, ki;
       _try(EPSGetEigenpair(eps, i, &kr, &ki, xr, xi));
       PetscReal error;
@@ -149,7 +155,7 @@ bool eigenSolver::solve(int numEigenValues, std::string which)
       PetscReal im = ki;
 #endif
       Msg::Debug("EIG %03d %s%.16e %s%.16e  %3.6e",
-		 i, (re < 0) ? "" : " ", re, (im < 0) ? "" : " ", im, error);
+        i, (re<0) ? "" : " ", re, (im<0) ? "" : " ", im, error);
 
       // store eigenvalues and eigenvectors
       _eigenValues.push_back(std::complex<double>(re, im));
@@ -157,14 +163,14 @@ bool eigenSolver::solve(int numEigenValues, std::string which)
       _try(VecGetArray(xr, &tmpr));
       _try(VecGetArray(xi, &tmpi));
       std::vector<std::complex<double> > ev(N);
-      for(int i = 0; i < N; i++){
+      for (int i=0; i<N; i++) {
 #if defined(PETSC_USE_COMPLEX)
         ev[i] = tmpr[i];
 #else
         ev[i] = std::complex<double>(tmpr[i], tmpi[i]);
 #endif
       }
-       _eigenVectors.push_back(ev);
+      _eigenVectors.push_back(ev);
     }
     _try(VecDestroy(&xr));
     _try(VecDestroy(&xi));
@@ -172,15 +178,35 @@ bool eigenSolver::solve(int numEigenValues, std::string which)
 
   _try(EPSDestroy(&eps));
 
-  if(reason == EPS_CONVERGED_TOL){
+  if (reason==EPS_CONVERGED_TOL) {
     Msg::Debug("SLEPc done");
     return true;
   }
-  else{
+  else {
     Msg::Warning("SLEPc failed");
     return false;
   }
+  
+}
 
+void eigenSolver::normalize_mode(double scale) {
+  Msg::Info("Normalize all eigenvectors");
+  for (unsigned int i=0; i<_eigenVectors.size(); i++) {
+    double norm = 0.;
+    for (unsigned int j=0; j<_eigenVectors[i].size(); j++) {
+      std::complex<double> val = _eigenVectors[i][j];
+      double normval = std::abs(val);
+      if (normval>norm)
+        norm = normval;
+    }
+    if (norm==0) {
+      Msg::Error("zero eigenvector");
+      return;
+    }
+    for (unsigned int j=0; j<_eigenVectors[i].size(); j++) {
+      _eigenVectors[i][j] *= (scale/norm);
+    }
+  }
 }
 
 #endif
diff --git a/Solver/eigenSolver.h b/Solver/eigenSolver.h
index 62ad7be..0a7a94e 100644
--- a/Solver/eigenSolver.h
+++ b/Solver/eigenSolver.h
@@ -16,7 +16,7 @@
 
 #include "linearSystemPETSc.h"
 
-class eigenSolver{
+class eigenSolver {
  private:
   linearSystemPETSc<double> *_A, *_B;
   bool _hermitian;
@@ -28,43 +28,53 @@ class eigenSolver{
               std::string B="", bool hermitian=true);
   eigenSolver(linearSystemPETSc<double> *A, linearSystemPETSc<double>* B = NULL,
               bool hermitian=true);
-  bool solve(int numEigenValues=0, std::string which="");
-  int getNumEigenValues(){ return _eigenValues.size(); }
-  std::complex<double> getEigenValue(int num){ return _eigenValues[num]; }
-  std::vector<std::complex<double> > &getEigenVector(int num){ return _eigenVectors[num]; }
-  void clear()
-  {
+  bool solve(int numEigenValues=0, std::string which="", std::string method="krylovschur",
+             double tolVal=1.e-7, int iterMax=20);
+  
+  int getNumEigenValues() {return _eigenValues.size();}
+  int getNumberEigenvectors() {return _eigenVectors.size();}
+  
+  std::complex<double> getEigenValue(int num) {
+    return _eigenValues[num];
+  }
+  std::complex<double> getEigenVectorComp(int num, int com) {
+    return _eigenVectors[num][com];
+  };
+  std::vector<std::complex<double> > &getEigenVector(int num) {
+    return _eigenVectors[num];
+  }
+  
+  void normalize_mode(double scale=1.);
+  
+  void clear() {
     _eigenValues.clear();
     _eigenVectors.clear();
   };
-  std::complex<double> getEigenVectorComp(int num, int com)
-  {
-    return _eigenVectors[num][com];
-  };
 };
 
 #else
 
 #include "linearSystemPETSc.h"
 
-class eigenSolver{
+class eigenSolver {
  private:
   std::vector<std::complex<double> > _dummy;
  public:
   eigenSolver(dofManager<double> *manager, std::string A,
-              std::string B="", bool hermitian=false){}
-  eigenSolver(linearSystemPETSc<double> *A,linearSystemPETSc<double>* B = NULL,
-              bool hermitian=false){}
-  bool solve(int numEigenValues=0, std::string which="")
-  {
+              std::string B="", bool hermitian=false) {}
+  eigenSolver(linearSystemPETSc<double> *A, linearSystemPETSc<double>* B=NULL,
+              bool hermitian=false) {}
+  bool solve(int=0, std::string="", std::string="", double=0, int=0) {
     Msg::Error("Eigen solver requires SLEPc");
     return false;
   }
-  int getNumEigenValues(){ return 0; }
-  std::complex<double> getEigenValue(int num){ return 0.; }
-  std::vector<std::complex<double> > &getEigenVector(int num){ return _dummy; }
-  void clear(){}
-  std::complex<double> getEigenVectorComp(int num, int com) { return 0.; }
+  int getNumEigenValues() {return 0;}
+  int getNumberEigenvectors() {return 0;}
+  std::complex<double> getEigenValue(int num) {return 0.;}
+  std::complex<double> getEigenVectorComp(int num, int com) {return 0.;}
+  std::vector<std::complex<double> > &getEigenVector(int num) {return _dummy;}
+  void normalize_mode(double scale=1.) {}
+  void clear() {}
 };
 
 #endif
diff --git a/Solver/elasticitySolver.cpp b/Solver/elasticitySolver.cpp
index 4d32445..58d1aa0 100644
--- a/Solver/elasticitySolver.cpp
+++ b/Solver/elasticitySolver.cpp
@@ -62,13 +62,14 @@ void elasticitySolver::setMesh(const std::string &meshFileName)
 
   if (LagSpace) delete LagSpace;
   if (_dim==3) LagSpace=new VectorLagrangeFunctionSpace(_tag);
-  if (_dim==2) LagSpace=new VectorLagrangeFunctionSpace(_tag,VectorLagrangeFunctionSpace::VECTOR_X,VectorLagrangeFunctionSpace::VECTOR_Y);
+  if (_dim==2) LagSpace=new VectorLagrangeFunctionSpace
+                 (_tag,VectorLagrangeFunctionSpace::VECTOR_X,
+                  VectorLagrangeFunctionSpace::VECTOR_Y);
 
   if (LagrangeMultiplierSpace) delete LagrangeMultiplierSpace;
   LagrangeMultiplierSpace = new ScalarLagrangeFunctionSpace(_tag+1);
 }
 
-
 void elasticitySolver::exportKb()
 {
   FILE *f = Fopen ( "K.txt", "w" );
@@ -123,7 +124,8 @@ void elasticitySolver::solve()
     SolverField<SVector3> Field(pAssembler, LagSpace);
     IsotropicElasticTerm Eterm(Field,elasticFields[i]._E,elasticFields[i]._nu);
     BilinearTermToScalarTerm Elastic_Energy_Term(Eterm);
-    Assemble(Elastic_Energy_Term,elasticFields[i].g->begin(),elasticFields[i].g->end(),Integ_Bulk,energ);
+    Assemble(Elastic_Energy_Term,elasticFields[i].g->begin(),elasticFields[i].g->end(),
+             Integ_Bulk,energ);
   }
   printf("elastic energy=%f\n",energ);
 }
@@ -149,7 +151,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
   FILE *f = Fopen(fn.c_str(), "r");
   char what[256];
   while(!feof(f)){
-    if(fscanf(f, "%s", what) != 1) return;
+    if(fscanf(f, "%s", what) != 1){
+      fclose(f);
+      return;
+    }
     if(what[0]=='#'){
       /*
       char *line=NULL;
@@ -161,7 +166,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
     else if (!strcmp(what, "ElasticDomain")){
       elasticField field;
       int physical;
-      if(fscanf(f, "%d %lf %lf", &physical, &field._E, &field._nu) != 3) return;
+      if(fscanf(f, "%d %lf %lf", &physical, &field._E, &field._nu) != 3){
+        fclose(f);
+        return;
+      }
       field._tag = _tag;
       field.g = new groupOfElements (_dim, physical);
       elasticFields.push_back(field);
@@ -171,7 +179,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
       int physical;
       double d1, d2, d3, val;
       if(fscanf(f, "%d %lf %lf %lf %lf %lf %d", &physical, &field._tau,
-        &d1, &d2, &d3, &val, &field._tag) != 7) return;
+                &d1, &d2, &d3, &val, &field._tag) != 7){
+        fclose(f);
+        return;
+      }
       field._tag = _tag;
       field._d = SVector3(d1, d2, d3);
       field._f = simpleFunction<double>(val);
@@ -181,7 +192,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
     else if (!strcmp(what, "Void")){
       elasticField field;
       int physical;
-      if(fscanf(f, "%d", &physical) != 1) return;
+      if(fscanf(f, "%d", &physical) != 1){
+        fclose(f);
+        return;
+      }
       field._E = field._nu = 0;
       field.g = new groupOfElements (_dim, physical);
       field._tag = 0;
@@ -190,7 +204,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
     else if (!strcmp(what, "NodeDisplacement")){
       double val;
       int node, comp;
-      if(fscanf(f, "%d %d %lf", &node, &comp, &val) != 3) return;
+      if(fscanf(f, "%d %d %lf", &node, &comp, &val) != 3){
+        fclose(f);
+        return;
+      }
       dirichletBC diri;
       diri.g = new groupOfElements (0, node);
       diri._f= new simpleFunction<double>(val);
@@ -202,7 +219,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
     else if (!strcmp(what, "EdgeDisplacement")){
       double val;
       int edge, comp;
-      if(fscanf(f, "%d %d %lf", &edge, &comp, &val) != 3) return;
+      if(fscanf(f, "%d %d %lf", &edge, &comp, &val) != 3){
+        fclose(f);
+        return;
+      }
       dirichletBC diri;
       diri.g = new groupOfElements (1, edge);
       diri._f= new simpleFunction<double>(val);
@@ -214,7 +234,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
     else if (!strcmp(what, "FaceDisplacement")){
       double val;
       int face, comp;
-      if(fscanf(f, "%d %d %lf", &face, &comp, &val) != 3) return;
+      if(fscanf(f, "%d %d %lf", &face, &comp, &val) != 3){
+        fclose(f);
+        return;
+      }
       dirichletBC diri;
       diri.g = new groupOfElements (2, face);
       diri._f= new simpleFunction<double>(val);
@@ -226,7 +249,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
     else if (!strcmp(what, "NodeForce")){
       double val1, val2, val3;
       int node;
-      if(fscanf(f, "%d %lf %lf %lf", &node, &val1, &val2, &val3) != 4) return;
+      if(fscanf(f, "%d %lf %lf %lf", &node, &val1, &val2, &val3) != 4){
+        fclose(f);
+        return;
+      }
       neumannBC neu;
       neu.g = new groupOfElements (0, node);
       neu._f= new simpleFunction<SVector3>(SVector3(val1, val2, val3));
@@ -237,7 +263,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
     else if (!strcmp(what, "EdgeForce")){
       double val1, val2, val3;
       int edge;
-      if(fscanf(f, "%d %lf %lf %lf", &edge, &val1, &val2, &val3) != 4) return;
+      if(fscanf(f, "%d %lf %lf %lf", &edge, &val1, &val2, &val3) != 4){
+        fclose(f);
+        return;
+      }
       neumannBC neu;
       neu.g = new groupOfElements (1, edge);
       neu._f= new simpleFunction<SVector3>(SVector3(val1, val2, val3));
@@ -248,7 +277,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
     else if (!strcmp(what, "FaceForce")){
       double val1, val2, val3;
       int face;
-      if(fscanf(f, "%d %lf %lf %lf", &face, &val1, &val2, &val3) != 4) return;
+      if(fscanf(f, "%d %lf %lf %lf", &face, &val1, &val2, &val3) != 4){
+        fclose(f);
+        return;
+      }
       neumannBC neu;
       neu.g = new groupOfElements (2, face);
       neu._f= new simpleFunction<SVector3>(SVector3(val1, val2, val3));
@@ -259,7 +291,10 @@ void elasticitySolver::readInputFile(const std::string &fn)
     else if (!strcmp(what, "VolumeForce")){
       double val1, val2, val3;
       int volume;
-      if(fscanf(f, "%d %lf %lf %lf", &volume, &val1, &val2, &val3) != 4) return;
+      if(fscanf(f, "%d %lf %lf %lf", &volume, &val1, &val2, &val3) != 4){
+        fclose(f);
+        return;
+      }
       neumannBC neu;
       neu.g = new groupOfElements (3, volume);
       neu._f= new simpleFunction<SVector3>(SVector3(val1, val2, val3));
@@ -269,26 +304,34 @@ void elasticitySolver::readInputFile(const std::string &fn)
     }
     else if (!strcmp(what, "MeshFile")){
       char name[245];
-      if(fscanf(f, "%s", name) != 1) return;
+      if(fscanf(f, "%s", name) != 1){
+        fclose(f);
+        return;
+      }
       setMesh(name);
     }
     else if (!strcmp(what, "CutMeshPlane")){
       double a, b, c, d;
-      if(fscanf(f, "%lf %lf %lf %lf", &a, &b, &c, &d) != 4) return;
+      if(fscanf(f, "%lf %lf %lf %lf", &a, &b, &c, &d) != 4){
+        fclose(f);
+        return;
+      }
       int tag=1;
       gLevelsetPlane ls(a,b,c,d,tag);
       pModel = pModel->buildCutGModel(&ls);
     }
     else if (!strcmp(what, "CutMeshSphere")){
       double x, y, z, r;
-      if(fscanf(f, "%lf %lf %lf %lf", &x, &y, &z, &r) != 4) return;
+      if(fscanf(f, "%lf %lf %lf %lf", &x, &y, &z, &r) != 4){
+        fclose(f);
+        return;
+      }
       int tag=1;
       gLevelsetSphere ls(x,y,z,r,tag);
       pModel = pModel->buildCutGModel(&ls);
     }
     else {
       Msg::Error("Invalid input : '%s'", what);
-//      return;
     }
   }
   fclose(f);
@@ -361,24 +404,28 @@ void elasticitySolver::assemble(linearSystem<double> *lsys)
   for (unsigned int i = 0; i < allDirichlet.size(); i++)
   {
     FilterDofComponent filter(allDirichlet[i]._comp);
-    FixNodalDofs(*LagSpace,allDirichlet[i].g->begin(),allDirichlet[i].g->end(),*pAssembler,*allDirichlet[i]._f,filter);
+    FixNodalDofs(*LagSpace,allDirichlet[i].g->begin(),allDirichlet[i].g->end(),
+                 *pAssembler,*allDirichlet[i]._f,filter);
   }
   // LagrangeMultipliers
   for (unsigned int i = 0; i < LagrangeMultiplierFields.size(); ++i)
   {
-    NumberDofs(*LagrangeMultiplierSpace, LagrangeMultiplierFields[i].g->begin(), LagrangeMultiplierFields[i].g->end(), *pAssembler);
+    NumberDofs(*LagrangeMultiplierSpace, LagrangeMultiplierFields[i].g->begin(),
+               LagrangeMultiplierFields[i].g->end(), *pAssembler);
   }
   // Elastic Fields
   for (unsigned int i = 0; i < elasticFields.size(); ++i)
   {
     if(elasticFields[i]._E != 0.)
-      NumberDofs(*LagSpace, elasticFields[i].g->begin(), elasticFields[i].g->end(),*pAssembler);
+      NumberDofs(*LagSpace, elasticFields[i].g->begin(), elasticFields[i].g->end(),
+                 *pAssembler);
   }
   // Voids
   for (unsigned int i = 0; i < elasticFields.size(); ++i)
   {
     if(elasticFields[i]._E == 0.)
-      FixVoidNodalDofs(*LagSpace, elasticFields[i].g->begin(), elasticFields[i].g->end(), *pAssembler);
+      FixVoidNodalDofs(*LagSpace, elasticFields[i].g->begin(), elasticFields[i].g->end(),
+                       *pAssembler);
   }
   // Neumann conditions
   GaussQuadrature Integ_Boundary(GaussQuadrature::Val);
@@ -386,29 +433,36 @@ void elasticitySolver::assemble(linearSystem<double> *lsys)
   for (unsigned int i = 0; i < allNeumann.size(); i++)
   {
     LoadTerm<SVector3> Lterm(*LagSpace,*allNeumann[i]._f);
-    Assemble(Lterm,*LagSpace,allNeumann[i].g->begin(),allNeumann[i].g->end(),Integ_Boundary,*pAssembler);
+    Assemble(Lterm,*LagSpace,allNeumann[i].g->begin(),allNeumann[i].g->end(),
+             Integ_Boundary,*pAssembler);
   }
   // Assemble cross term, laplace term and rhs term for LM
   GaussQuadrature Integ_LagrangeMult(GaussQuadrature::ValVal);
   GaussQuadrature Integ_Laplace(GaussQuadrature::GradGrad);
   for (unsigned int i = 0; i < LagrangeMultiplierFields.size(); i++)
   {
-    LagrangeMultiplierTerm LagTerm(*LagSpace, *LagrangeMultiplierSpace, LagrangeMultiplierFields[i]._d);
+    LagrangeMultiplierTerm LagTerm(*LagSpace, *LagrangeMultiplierSpace,
+                                   LagrangeMultiplierFields[i]._d);
     Assemble(LagTerm, *LagSpace, *LagrangeMultiplierSpace,
-             LagrangeMultiplierFields[i].g->begin(), LagrangeMultiplierFields[i].g->end(), Integ_LagrangeMult, *pAssembler);
+             LagrangeMultiplierFields[i].g->begin(),
+             LagrangeMultiplierFields[i].g->end(), Integ_LagrangeMult, *pAssembler);
 
-    LaplaceTerm<double,double> LapTerm(*LagrangeMultiplierSpace, LagrangeMultiplierFields[i]._tau);
-    Assemble(LapTerm, *LagrangeMultiplierSpace, LagrangeMultiplierFields[i].g->begin(), LagrangeMultiplierFields[i].g->end(), Integ_Laplace, *pAssembler);
+    LaplaceTerm<double,double> LapTerm(*LagrangeMultiplierSpace,
+                                       LagrangeMultiplierFields[i]._tau);
+    Assemble(LapTerm, *LagrangeMultiplierSpace, LagrangeMultiplierFields[i].g->begin(),
+             LagrangeMultiplierFields[i].g->end(), Integ_Laplace, *pAssembler);
 
     LoadTerm<double> Lterm(*LagrangeMultiplierSpace, LagrangeMultiplierFields[i]._f);
-    Assemble(Lterm, *LagrangeMultiplierSpace, LagrangeMultiplierFields[i].g->begin(), LagrangeMultiplierFields[i].g->end(), Integ_Boundary, *pAssembler);
+    Assemble(Lterm, *LagrangeMultiplierSpace, LagrangeMultiplierFields[i].g->begin(),
+             LagrangeMultiplierFields[i].g->end(), Integ_Boundary, *pAssembler);
   }
   // Assemble elastic term for
   GaussQuadrature Integ_Bulk(GaussQuadrature::GradGrad);
   for (unsigned int i = 0; i < elasticFields.size(); i++)
   {
     IsotropicElasticTerm Eterm(*LagSpace,elasticFields[i]._E,elasticFields[i]._nu);
-    Assemble(Eterm,*LagSpace,elasticFields[i].g->begin(),elasticFields[i].g->end(),Integ_Bulk,*pAssembler);
+    Assemble(Eterm,*LagSpace,elasticFields[i].g->begin(),elasticFields[i].g->end(),
+             Integ_Bulk,*pAssembler);
   }
 
   /*for (int i=0;i<pAssembler->sizeOfR();i++){
@@ -503,7 +557,8 @@ PView* elasticitySolver::buildDisplacementView (const std::string postFileName)
   for (unsigned int i = 0; i < elasticFields.size(); ++i)
   {
     if(elasticFields[i]._E == 0.) continue;
-    for (groupOfElements::elementContainer::const_iterator it = elasticFields[i].g->begin(); it != elasticFields[i].g->end(); ++it){
+    for (groupOfElements::elementContainer::const_iterator it = elasticFields[i].g->begin();
+         it != elasticFields[i].g->end(); ++it){
       MElement *e=*it;
       if(e->getParent()) {
         for (int j = 0; j < e->getNumVertices(); ++j) {
@@ -551,7 +606,8 @@ PView* elasticitySolver::buildStressesView (const std::string postFileName)
     SolverField<SVector3> Field(pAssembler, LagSpace);
     IsotropicElasticTerm Eterm(Field,elasticFields[i]._E,elasticFields[i]._nu);
     BilinearTermToScalarTerm Elastic_Energy_Term(Eterm);
-    for (groupOfElements::elementContainer::const_iterator it = elasticFields[i].g->begin(); it != elasticFields[i].g->end(); ++it)
+    for (groupOfElements::elementContainer::const_iterator it = elasticFields[i].g->begin();
+         it != elasticFields[i].g->end(); ++it)
     {
       MElement *e=*it;
       int nbVertex = e->getNumVertices();
@@ -594,7 +650,8 @@ PView* elasticitySolver::buildStressesView (const std::string postFileName)
       double syz = A * eps[5];
 
       std::vector<double> vec(9);
-      vec[0]=sxx; vec[1]=sxy; vec[2]=sxz; vec[3]=sxy; vec[4]=syy; vec[5]=syz; vec[6]=sxz; vec[7]=syz; vec[8]=szz;
+      vec[0]=sxx; vec[1]=sxy; vec[2]=sxz; vec[3]=sxy; vec[4]=syy;
+      vec[5]=syz; vec[6]=sxz; vec[7]=syz; vec[8]=szz;
 
       data[e->getNum()]=vec;
     }
@@ -611,7 +668,9 @@ PView* elasticitySolver::buildLagrangeMultiplierView (const std::string postFile
   std::set<MVertex*> v;
   for (unsigned int i = 0; i < LagrangeMultiplierFields.size(); ++i)
   {
-    for(groupOfElements::elementContainer::const_iterator it = LagrangeMultiplierFields[i].g->begin(); it != LagrangeMultiplierFields[i].g->end(); ++it)
+    for(groupOfElements::elementContainer::const_iterator it =
+          LagrangeMultiplierFields[i].g->begin();
+        it != LagrangeMultiplierFields[i].g->end(); ++it)
     {
       MElement *e = *it;
       for (int j = 0; j < e->getNumVertices(); ++j) v.insert(e->getVertex(j));
@@ -645,7 +704,8 @@ PView *elasticitySolver::buildElasticEnergyView(const std::string postFileName)
     IsotropicElasticTerm Eterm(Field,elasticFields[i]._E,elasticFields[i]._nu);
     BilinearTermToScalarTerm Elastic_Energy_Term(Eterm);
     ScalarTermConstant<double> One(1.0);
-    for (groupOfElements::elementContainer::const_iterator it = elasticFields[i].g->begin(); it != elasticFields[i].g->end(); ++it)
+    for (groupOfElements::elementContainer::const_iterator it =
+           elasticFields[i].g->begin(); it != elasticFields[i].g->end(); ++it)
     {
       MElement *e = *it;
       double energ;
@@ -673,7 +733,8 @@ PView *elasticitySolver::buildVonMisesView(const std::string postFileName)
     SolverField<SVector3> Field(pAssembler, LagSpace);
     IsotropicElasticTerm Eterm(Field,elasticFields[i]._E,elasticFields[i]._nu);
     BilinearTermToScalarTerm Elastic_Energy_Term(Eterm);
-    for (groupOfElements::elementContainer::const_iterator it = elasticFields[i].g->begin(); it != elasticFields[i].g->end(); ++it)
+    for (groupOfElements::elementContainer::const_iterator it = elasticFields[i].g->begin();
+         it != elasticFields[i].g->end(); ++it)
     {
       MElement *e=*it;
       double energ;
@@ -691,6 +752,7 @@ PView *elasticitySolver::buildVonMisesView(const std::string postFileName)
 
 
 #else
+
 PView* elasticitySolver::buildDisplacementView(const std::string postFileName)
 {
   Msg::Error("Post-pro module not available");
@@ -714,9 +776,11 @@ PView* elasticitySolver::buildVonMisesView(const std::string postFileName)
   Msg::Error("Post-pro module not available");
   return 0;
 }
+
 PView* elasticitySolver::buildStressesView (const std::string postFileName)
 {
   Msg::Error("Post-pro module not available");
   return 0;
 }
+
 #endif
diff --git a/Solver/linearSystem.h b/Solver/linearSystem.h
index 5075170..fbce5c3 100644
--- a/Solver/linearSystem.h
+++ b/Solver/linearSystem.h
@@ -18,6 +18,7 @@ class linearSystemBase {
   virtual ~linearSystemBase(){}
   virtual bool isAllocated() const = 0;
   virtual void allocate(int nbRows) = 0;
+  virtual void preAllocateEntries(){};
   virtual void clear() = 0;
   virtual void zeroMatrix() = 0;
   virtual void zeroRightHandSide() = 0;
diff --git a/Solver/linearSystemPETSc.cpp b/Solver/linearSystemPETSc.cpp
index 1bf23e9..887b1ed 100644
--- a/Solver/linearSystemPETSc.cpp
+++ b/Solver/linearSystemPETSc.cpp
@@ -4,13 +4,14 @@
 // bugs and problems to the public mailing list <gmsh at geuz.org>.
 
 #include "GmshConfig.h"
+#include <string.h>
+
 #if defined(HAVE_PETSC)
 #include "petsc.h"
 #include "linearSystemPETSc.h"
 #include "fullMatrix.h"
 #include <stdlib.h>
 #include "GmshMessage.h"
-
 #include "linearSystemPETSc.hpp"
 
 template class linearSystemPETSc<double>;
@@ -34,35 +35,19 @@ void linearSystemPETSc<fullMatrix<double> >::addToMatrix(int row, int col,
 {
   if (!_entriesPreAllocated)
     preAllocateEntries();
+  PetscInt i = row, j = col;
   #ifdef PETSC_USE_COMPLEX
   fullMatrix<std::complex<double> > modval(val.size1(), val.size2());
   for (int ii = 0; ii < val.size1(); ii++) {
     for (int jj = 0; jj < val.size1(); jj++) {
-      modval(ii, jj) = val (jj, ii);
-      modval(jj, ii) = val (ii, jj);
+      modval(ii, jj) = val (ii, jj);
     }
   }
+  MatSetValuesBlocked(_a, 1, &i, 1, &j, modval.getDataPtr(), ADD_VALUES);
   #else
-  fullMatrix<double> &modval = *const_cast<fullMatrix<double> *>(&val);
-  for (int ii = 0; ii < val.size1(); ii++) {
-    for (int jj = 0; jj < ii; jj++) {
-      PetscScalar buff = modval(ii, jj);
-      modval(ii, jj) = modval (jj, ii);
-      modval(jj, ii) = buff;
-    }
-  }
-  #endif
-  PetscInt i = row, j = col;
-  MatSetValuesBlocked(_a, 1, &i, 1, &j, &modval(0,0), ADD_VALUES);
-  //transpose back so that the original matrix is not modified
-  #ifndef PETSC_USE_COMPLEX
-  for (int ii = 0; ii < val.size1(); ii++)
-    for (int jj = 0; jj < ii; jj++) {
-      PetscScalar buff = modval(ii,jj);
-      modval(ii, jj) = modval (jj,ii);
-      modval(jj, ii) = buff;
-    }
+  MatSetValuesBlocked(_a, 1, &i, 1, &j, val.getDataPtr(), ADD_VALUES);
   #endif
+
   _valuesNotAssembled = true;
 }
 
diff --git a/Solver/linearSystemPETSc.h b/Solver/linearSystemPETSc.h
index 246746d..ef62343 100644
--- a/Solver/linearSystemPETSc.h
+++ b/Solver/linearSystemPETSc.h
@@ -39,7 +39,9 @@
 #include "linearSystem.h"
 #include "sparsityPattern.h"
 #include "fullMatrix.h"
+#include <string.h>
 #include <vector>
+
 #if defined(HAVE_PETSC)
 
 #ifndef SWIG
@@ -84,13 +86,14 @@ class linearSystemPETSc : public linearSystem<scalar> {
   void insertInSparsityPattern (int i, int j);
   bool isAllocated() const { return _isAllocated; }
   void preAllocateEntries();
-  void allocate(int nbRows);
+  virtual void allocate(int nbRows);
   void print();
   void clear();
   void getFromMatrix(int row, int col, scalar &val) const;
   void addToRightHandSide(int row, const scalar &val);
   void getFromRightHandSide(int row, scalar &val) const;
   double normInfRightHandSide() const;
+  int getNumKspIteration() const;
   void addToMatrix(int row, int col, const scalar &val);
   void addToSolution(int row, const scalar &val);
   void getFromSolution(int row, scalar &val) const;
@@ -98,7 +101,7 @@ class linearSystemPETSc : public linearSystem<scalar> {
   void zeroRightHandSide();
   void zeroSolution();
   void printMatlab(const char *filename) const;
-  int systemSolve();
+  virtual int systemSolve();
   Mat &getMatrix(){ return _a; }
   //std::vector<scalar> getData();
   //std::vector<int> getRowPointers();
@@ -127,11 +130,12 @@ class linearSystemPETSc : public linearSystem<scalar> {
   void addToSolution(int row, const scalar &val) {}
   void getFromRightHandSide(int row, scalar &val) const {}
   void getFromSolution(int row, scalar &val) const {}
+  int getNumKspIteration() const {return 0;};
   void zeroMatrix() {}
   void zeroRightHandSide() {}
   void zeroSolution() {}
   void printMatlab(const char *filename) const{};
-  int systemSolve() { return 0; }
+  virtual int systemSolve() { return 0; }
   double normInfRightHandSide() const{return 0;}
 };
 #endif
diff --git a/Solver/linearSystemPETSc.hpp b/Solver/linearSystemPETSc.hpp
index f271188..136daf3 100644
--- a/Solver/linearSystemPETSc.hpp
+++ b/Solver/linearSystemPETSc.hpp
@@ -36,6 +36,14 @@ void linearSystemPETSc<scalar>::_kspCreate()
 }
 
 template <class scalar>
+int linearSystemPETSc<scalar>::getNumKspIteration() const
+{
+  int n;
+  _try(KSPGetIterationNumber(_ksp, &n));
+  return n;
+}
+
+template <class scalar>
 linearSystemPETSc<scalar>::linearSystemPETSc(MPI_Comm com)
 {
   _comm = com;
@@ -137,6 +145,8 @@ void linearSystemPETSc<scalar>::preAllocateEntries()
     else
       _try(MatMPIBAIJSetPreallocation(_a, blockSize, 0, &nByRowDiag[0], 0, &nByRowOffDiag[0]));
   }
+  if (blockSize > 1)
+    _try(MatSetOption(_a, MAT_ROW_ORIENTED, PETSC_FALSE));
   _entriesPreAllocated = true;
 }
 
@@ -151,10 +161,10 @@ void linearSystemPETSc<scalar>::allocate(int nbRows)
   _try(MatSetSizes(_a, blockSize * nbRows, blockSize * nbRows, PETSC_DETERMINE, PETSC_DETERMINE));
   if (blockSize > 1) {
     if (commSize > 1) {
-      MatSetType(_a, MATMPIBAIJ);
+      _try(MatSetType(_a, MATMPIBAIJ));
     }
     else {
-      MatSetType(_a, MATSEQBAIJ);
+      _try(MatSetType(_a, MATSEQBAIJ));
     }
   }
   // override the default options with the ones from the option
diff --git a/Solver/multiscaleLaplace.cpp b/Solver/multiscaleLaplace.cpp
index 366b6b3..59a3c64 100644
--- a/Solver/multiscaleLaplace.cpp
+++ b/Solver/multiscaleLaplace.cpp
@@ -762,6 +762,7 @@ multiscaleLaplace::multiscaleLaplace (std::vector<MElement *> &elements,
   ordering_dirichlet(elements,boundaryNodes);
 
   //Assign Dirichlet BCs
+  // FIXME: this is never deleted
   root = new multiscaleLaplaceLevel;
   root->elements = elements;
   for(unsigned int i = 0; i < boundaryNodes.size(); i++){
@@ -789,14 +790,14 @@ multiscaleLaplace::multiscaleLaplace (std::vector<MElement *> &elements,
 
   //Split the mesh in left and right
   //or Cut the mesh in left and right (of bamg)
-  if ( CTX::instance()->mesh.algo2d ==  ALGO_2D_BAMG){ 
+  if ( CTX::instance()->mesh.algo2d ==  ALGO_2D_BAMG){
     printf("-------------> EXACT CUTTING \n");
     cutElems(elements);
-  } 
+  }
   else {
     splitElems(elements);
   }
- 
+
 }
 
 void multiscaleLaplace::fillCoordinates (multiscaleLaplaceLevel & level,
@@ -949,6 +950,7 @@ void multiscaleLaplace::parametrize(multiscaleLaplaceLevel & level)
       }
     }
 
+    // FIXME: this is never deleted
     multiscaleLaplaceLevel *nextLevel = new multiscaleLaplaceLevel;
     nextLevel->elements = regions[i];
     nextLevel->recur = level.recur+1;
@@ -979,7 +981,7 @@ void multiscaleLaplace::parametrize(multiscaleLaplaceLevel & level)
       Msg::Info("Level (%d-%d) Multiscale Laplace (reg[%d] =  %d too small)",
                 level.recur,level.region, i, tooSmallv.size());
       level.children.push_back(nextLevel);
-      parametrize (*nextLevel);
+      parametrize(*nextLevel);
     }
   }
 }
@@ -1028,6 +1030,8 @@ void multiscaleLaplace::parametrize_method (multiscaleLaplaceLevel & level,
       mapping->addToMatrix(myAssembler, &se);
     }
 
+    delete mapping;
+
     // solve
     if (myAssembler.sizeOfR() != 0) _lsys->systemSolve();
 
diff --git a/contrib/HighOrderMeshOptimizer/CMakeLists.txt b/contrib/HighOrderMeshOptimizer/CMakeLists.txt
index 3147c72..f7311c8 100644
--- a/contrib/HighOrderMeshOptimizer/CMakeLists.txt
+++ b/contrib/HighOrderMeshOptimizer/CMakeLists.txt
@@ -7,6 +7,7 @@ set(SRC
   OptHomMesh.cpp 
   OptHOM.cpp 
   OptHomRun.cpp 
+  OptHomIntegralBoundaryDist.cpp
   ParamCoord.cpp 
   SuperEl.cpp 
   OptHomElastic.cpp
diff --git a/contrib/HighOrderMeshOptimizer/OptHOM.cpp b/contrib/HighOrderMeshOptimizer/OptHOM.cpp
index f6a39bf..fd0e6d1 100644
--- a/contrib/HighOrderMeshOptimizer/OptHOM.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHOM.cpp
@@ -106,6 +106,29 @@ bool OptHOM::addJacObjGrad(double &Obj, alglib::real_1d_array &gradObj)
   return true;
 }
 
+bool OptHOM::addBndObjGrad(double factor, double &Obj, alglib::real_1d_array &gradObj)
+{
+  maxDistCAD = 0.0;
+
+  std::vector<double> gradF;
+  double DISTANCE = 0.0;
+  for (int iEl = 0; iEl < mesh.nEl(); iEl++) {
+    double f;
+    if (mesh.bndDistAndGradients(iEl, f, gradF, geomTol)) {
+      maxDistCAD = std::max(maxDistCAD,f);
+      DISTANCE += f;
+      Obj += f * factor;
+      for (size_t i = 0; i < mesh.nPCEl(iEl); ++i){
+        gradObj[mesh.indPCEl(iEl, i)] += gradF[i] * factor;
+	//	printf("gradf[%d] = %12.5E\n",i,gradF[i]*factor);
+      }
+    }
+  }
+  //  printf("DIST = %12.5E\n",DISTANCE);
+  return true;
+
+}
+
 bool OptHOM::addMetricMinObjGrad(double &Obj, alglib::real_1d_array &gradObj)
 {
 
@@ -132,7 +155,7 @@ bool OptHOM::addMetricMinObjGrad(double &Obj, alglib::real_1d_array &gradObj)
 }
 
 // Contribution of the vertex distance to the objective function value and
-// gradients (2D version)
+// gradients
 bool OptHOM::addDistObjGrad(double Fact, double Fact2, double &Obj,
                             alglib::real_1d_array &gradObj)
 {
@@ -169,7 +192,10 @@ void OptHOM::evalObjGrad(const alglib::real_1d_array &x, double &Obj,
   addDistObjGrad(lambda, lambda2, Obj, gradObj);
   if(_optimizeMetricMin)
     addMetricMinObjGrad(Obj, gradObj);
-  if ((minJac > barrier_min) && (maxJac < barrier_max || !_optimizeBarrierMax)) {
+  if(_optimizeCAD)
+    addBndObjGrad(lambda3, Obj, gradObj);
+  //  printf("maxDistCAD = %12.5E distMax = %12.5E Obj %12.5E\n",maxDistCAD,distance_max,Obj);
+  if ((minJac > barrier_min) && (maxJac < barrier_max || !_optimizeBarrierMax) && (maxDistCAD < distance_max|| !_optimizeCAD) ) {
     Msg::Info("Reached %s (%g %g) requirements, setting null gradient",
               _optimizeMetricMin ? "svd" : "jacobian", minJac, maxJac);
     Obj = 0.;
@@ -243,16 +269,37 @@ void OptHOM::calcScale(alglib::real_1d_array &scale)
     for (int iPC = 0; iPC < mesh.nPCFV(iFV); iPC++)
       scale[mesh.indPCFV(iFV,iPC)] = scaleFV[iPC];
   }
+
+//  std::vector<double> inSize(mesh.nEl());
+//  mesh.elInSize(inSize);
+//  for (int iEl = 0; iEl < mesh.nEl(); iEl++) {
+////    std::cout << "DBGTT: inSize[" << iEl << "] = " << inSize[iEl] << std::endl;
+//    for (int iPCEl = 0; iPCEl < mesh.nPCEl(iEl); iPCEl++)
+//      scale[mesh.indPCEl(iEl,iPCEl)] *= inSize[iEl];
+//  }
+
+//  for (int iEl = 0; iEl < mesh.nEl(); iEl++) {
+//    std::vector<double> sJ(mesh.nBezEl(iEl)), gSJ(mesh.nBezEl(iEl)*mesh.nPCEl(iEl));
+//    mesh.scaledJacAndGradients(iEl,sJ,gSJ);
+//    for (int iPC = 0; iPC < mesh.nPCEl(iEl); iPC++) {
+//      double grad = 0.;
+//      for (int l = 0; l < mesh.nBezEl(iEl); l++) grad = std::max(grad,fabs(gSJ[mesh.indGSJ(iEl,l,iPC)]));
+//      scale[mesh.indPCEl(iEl,iPC)] *= mesh.nBezEl(iEl)/grad;
+////      std::cout << "DBGTT: scale[" << mesh.indPCEl(iEl,iPC) << "] = " << scale[mesh.indPCEl(iEl,iPC)] << std::endl;
+//    }
+//  }
+
 }
 
 void OptHOM::OptimPass(alglib::real_1d_array &x,
                        const alglib::real_1d_array &initGradObj, int itMax)
 {
+
   static const double EPSG = 0.;
   static const double EPSF = 0.;
   static const double EPSX = 0.;
   static int OPTMETHOD = 1;
-
+  
   Msg::Info("--- Optimization pass with initial jac. range (%g, %g), jacBar = %g",
             minJac, maxJac, jacBar);
 
@@ -312,20 +359,24 @@ void OptHOM::OptimPass(alglib::real_1d_array &x,
   }
 }
 
-int OptHOM::optimize(double weightFixed, double weightFree, double b_min,
+int OptHOM::optimize(double weightFixed, double weightFree, double weightCAD, double b_min,
                      double b_max, bool optimizeMetricMin, int pInt,
-                     int itMax, int optPassMax)
+                     int itMax, int optPassMax, int optCAD, double distanceMax, double tolerance)
 {
   barrier_min = b_min;
   barrier_max = b_max;
+  distance_max = distanceMax;
   progressInterv = pInt;
 //  powM = 4;
 //  powP = 3;
 
   _optimizeMetricMin = optimizeMetricMin;
+  _optimizeCAD = optCAD;
   // Set weights & length scale for non-dimensionalization
   lambda = weightFixed;
   lambda2 = weightFree;
+  lambda3 = weightCAD;
+  geomTol = tolerance;
   std::vector<double> dSq(mesh.nEl());
   mesh.distSqToStraight(dSq);
   const double maxDSq = *max_element(dSq.begin(),dSq.end());
@@ -364,13 +415,14 @@ int OptHOM::optimize(double weightFixed, double weightFree, double b_min,
 
   int ITER = 0;
   bool minJacOK = true;
-  while (minJac < barrier_min) {
+  while (minJac < barrier_min || (maxDistCAD > distance_max && _optimizeCAD)) {
     const double startMinJac = minJac;
     OptimPass(x, gradObj, itMax);
     recalcJacDist();
     jacBar = (minJac > 0.) ? 0.9*minJac : 1.1*minJac;
+    if (_optimizeCAD)   jacBar = std::min(jacBar,barrier_min); 
     if (ITER ++ > optPassMax) {
-      minJacOK = (minJac > barrier_min);
+      minJacOK = (minJac > barrier_min && (maxDistCAD < distance_max || !_optimizeCAD));
       break;
     }
     if (fabs((minJac-startMinJac)/startMinJac) < 0.01) {
diff --git a/contrib/HighOrderMeshOptimizer/OptHOM.h b/contrib/HighOrderMeshOptimizer/OptHOM.h
index 098d829..7ca9db1 100644
--- a/contrib/HighOrderMeshOptimizer/OptHOM.h
+++ b/contrib/HighOrderMeshOptimizer/OptHOM.h
@@ -50,8 +50,8 @@ public:
   // are in the range; returns 0 if the mesh is valid (all jacobians positive,
   // JMIN > 0) but JMIN < barrier_min || JMAX > barrier_max; returns -1 if the
   // mesh is invalid : some jacobians cannot be made positive
-  int optimize(double lambda, double lambda2, double barrier_min, double barrier_max,
-               bool optimizeMetricMin, int pInt, int itMax, int optPassMax);
+  int optimize(double lambda, double lambda2, double lambda3, double barrier_min, double barrier_max,
+               bool optimizeMetricMin, int pInt, int itMax, int optPassMax, int optimizeCAD, double optCADDistMax, double tolerance);
   void recalcJacDist();
   inline void getJacDist(double &minJ, double &maxJ, double &maxD, double &avgD);
   void updateMesh(const alglib::real_1d_array &x);
@@ -59,17 +59,20 @@ public:
                    alglib::real_1d_array &gradObj);
   void printProgress(const alglib::real_1d_array &x, double Obj);
 
-  double barrier_min, barrier_max;
+  double barrier_min, barrier_max, distance_max, geomTol;
 
  private:
-  double lambda, lambda2, jacBar, invLengthScaleSq;
+  double lambda, lambda2, lambda3, jacBar, invLengthScaleSq;
   int iter, progressInterv; // Current iteration, interval of iterations for reporting
   bool _optimizeMetricMin;
   double initObj, initMaxDist, initAvgDist; // Values for reporting
-  double minJac, maxJac, maxDist, avgDist; // Values for reporting
+  double minJac, maxJac, maxDist, maxDistCAD, avgDist; // Values for reporting
   bool _optimizeBarrierMax; // false : only moving barrier min;
                             // true : fixed barrier min + moving barrier max
+  bool _optimizeCAD; // false : do not minimize the distance between mesh and CAD
+                     // true : minimize the distance between mesh and CAD
   bool addJacObjGrad(double &Obj, alglib::real_1d_array &gradObj);
+  bool addBndObjGrad(double Fact, double &Obj, alglib::real_1d_array &gradObj);
   bool addMetricMinObjGrad(double &Obj, alglib::real_1d_array &gradObj);
   bool addDistObjGrad(double Fact, double Fact2, double &Obj,
                       alglib::real_1d_array &gradObj);
diff --git a/contrib/HighOrderMeshOptimizer/OptHomElastic.cpp b/contrib/HighOrderMeshOptimizer/OptHomElastic.cpp
index c32f3ea..5c48492 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomElastic.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomElastic.cpp
@@ -55,7 +55,7 @@
 
 #define SQU(a)      ((a)*(a))
 
-void ElasticAnalogy(GModel *m, double threshold, bool onlyVisible)
+void ElasticAnalogy(GModel *m, bool onlyVisible)
 {
   bool CAD, complete;
   int meshOrder;
diff --git a/contrib/HighOrderMeshOptimizer/OptHomElastic.h b/contrib/HighOrderMeshOptimizer/OptHomElastic.h
index f823c23..2295e4e 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomElastic.h
+++ b/contrib/HighOrderMeshOptimizer/OptHomElastic.h
@@ -34,7 +34,7 @@
 #include "GmshMessage.h"
 #include "GModel.h"
 
-void ElasticAnalogy(GModel *m, double threshold, bool onlyVisible);
+void ElasticAnalogy(GModel *m, bool onlyVisible);
 
 #if defined(HAVE_SOLVER)
 
diff --git a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp
index ea07f08..15474d5 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp
@@ -47,6 +47,7 @@
 #include "SuperEl.h"
 #include "SVector3.h"
 #include "BasisFactory.h"
+#include "Field.h"
 
 
 
@@ -54,69 +55,7 @@ namespace {
 
 
 
-void exportMeshToDassault(GModel *gm, const std::string &fn, int dim)
-{
-  FILE *f = fopen(fn.c_str(),"w");
-
-  int numVertices = gm->indexMeshVertices(true);
-  std::vector<GEntity*> entities;
-  gm->getEntities(entities);
-  fprintf(f,"%d %d\n", numVertices, dim);
-  for(unsigned int i = 0; i < entities.size(); i++)
-    for(unsigned int j = 0; j < entities[i]->mesh_vertices.size(); j++){
-      MVertex *v = entities[i]->mesh_vertices[j];
-      if (dim == 2)
-        fprintf(f,"%d %22.15E %22.15E\n", v->getIndex(), v->x(), v->y());
-      else if (dim == 3)
-        fprintf(f,"%d %22.15E %22.15E %22.5E\n", v->getIndex(), v->x(),
-                v->y(), v->z());
-    }
-
-  if (dim == 2){
-    int nt = 0;
-    int order  = 0;
-    for (GModel::fiter itf = gm->firstFace(); itf != gm->lastFace(); ++itf){
-      std::vector<MTriangle*> &tris = (*itf)->triangles;
-      nt += tris.size();
-      if (tris.size())order = tris[0]->getPolynomialOrder();
-    }
-    fprintf(f,"%d %d\n", nt,(order+1)*(order+2)/2);
-    int count = 1;
-    for (GModel::fiter itf = gm->firstFace(); itf != gm->lastFace(); ++itf){
-      std::vector<MTriangle*> &tris = (*itf)->triangles;
-      for (size_t i=0;i<tris.size();i++){
-  MTriangle *t = tris[i];
-  fprintf(f,"%d ", count++);
-  for (int j=0;j<t->getNumVertices();j++){
-    fprintf(f,"%d ", t->getVertex(j)->getIndex());
-  }
-  fprintf(f,"\n");
-      }
-    }
-    int ne = 0;
-    for (GModel::eiter ite = gm->firstEdge(); ite != gm->lastEdge(); ++ite){
-      std::vector<MLine*> &l = (*ite)->lines;
-      ne += l.size();
-    }
-    fprintf(f,"%d %d\n", ne,(order+1));
-    count = 1;
-    for (GModel::eiter ite = gm->firstEdge(); ite != gm->lastEdge(); ++ite){
-      std::vector<MLine*> &l = (*ite)->lines;
-      for (size_t i=0;i<l.size();i++){
-  MLine *t = l[i];
-  fprintf(f,"%d ", count++);
-  for (int j=0;j<t->getNumVertices();j++){
-    fprintf(f,"%d ", t->getVertex(j)->getIndex());
-  }
-  fprintf(f,"%d \n",(*ite)->tag());
-      }
-    }
-  }
-  fclose(f);
-}
-
-
-
+// Compute vertex -> element connectivity
 void calcVertex2Elements(int dim, GEntity *entity,
                                 std::map<MVertex*, std::vector<MElement *> > &vertex2elements)
 {
@@ -130,217 +69,452 @@ void calcVertex2Elements(int dim, GEntity *entity,
 
 
 
-// Among edges connected to a given vertex, return the direction of the one that is closest to the given normal
-// Return the given normal if no edge is sufficiently close
-SVector3 getNormalEdge(MVertex *vert, const SVector3 &n,
-                       const std::map<MVertex*, std::vector<MElement*> > &vertex2elements) {
-
-//  static const double spLimit = 0.70711;                          // Limit in dot product below which we return the normal
-  static const double spLimit = 0.5;                          // Limit in dot product below which we return the normal
-
-  const std::vector<MElement*> &elts = (*vertex2elements.find(vert)).second;     // All elements connected to vertex
+// Given a starting vertex and a direction, find the next vertex in a column
+MVertex *findVertFromDir(const std::map<MVertex*, std::vector<MElement*> > &vertex2elements,
+                         MVertex *v0, MVertex *vExclude, const SVector3 &dir, double spLimit)
+{
 
+  const std::vector<MElement*> &elts = (*vertex2elements.find(v0)).second;                      // All elements connected to vertex
+  MVertex *vFound = 0;
   double spMax = 0.;
-  SVector3 normalEdge;
-//  std::cout << "DBGTT: Looking for normal edge at vertex " << vert->getNum()
-//              << " with n = (" << n.x() << ", " << n.y() << ", " << n.z() << ")\n";
-
-  for (std::vector<MElement*>::const_iterator itEl = elts.begin(); itEl != elts.end(); ++itEl)
-    for (int i=0; i<(*itEl)->getNumEdges(); i++) {
-      std::vector<MVertex*> edgeVert;
-      (*itEl)->getEdgeVertices(i,edgeVert);
-      SVector3 edge;
-      if (edgeVert[0] == vert) edge = SVector3(vert->point(),edgeVert[1]->point());
-      else if (edgeVert[1] == vert) edge = SVector3(vert->point(),edgeVert[0]->point());
+  for (std::vector<MElement*>::const_iterator itEl = elts.begin(); itEl != elts.end(); ++itEl)  // Loop over all elements
+    for (int i=0; i<(*itEl)->getNumEdges(); i++) {                                              // Loop over all edges of each element
+      MEdge edge = (*itEl)->getEdge(i);
+      MVertex *vA = edge.getVertex(0), *vB = edge.getVertex(1), *vTmp;
+      if (v0 == vA)                                                                             // Skip if edge unconnected to vertex...
+        if (vB == vExclude) continue;                                                           // ... or if connecting to preceding vertex
+        else vTmp = vB;
+      else if (v0 == vB)
+        if (vA == vExclude) continue;
+        else vTmp = vA;
       else continue;
-      edge.normalize();
-      double sp = dot(edge,n);
-      if (sp > spMax) {                                           // Retain the edge giving max. dot product with normal
+      SVector3 tanVec = edge.tangent();
+      double sp = fabs(dot(tanVec, dir));
+      if ((sp > spMax) && (sp > spLimit)){                                                      // Retain the edge giving max. dot product with normal
         spMax = sp;
-        normalEdge = edge;
+        vFound = vTmp;
       }
-//      std::cout << "DBGTT:   -> checking edge " << edgeVert[0]->getNum() << " - " << edgeVert[1]->getNum()
-//                  << ", sp = " << sp << "\n";
     }
+  return vFound;
+}
 
-  if (spMax < spLimit) { std::cout << "DBGTT: no normal edge\n"; normalEdge = n; }                            // If max. dot product is below limit, just take normal
 
-  return normalEdge;
 
+// Find a column of vertices starting with a given vertex
+template<class bndType>
+bool findColumn(const std::map<MVertex*, std::vector<MElement*> > &vertex2elements,
+                MVertex *baseVert, const SVector3 &norm,
+                const bndType &baseEd, std::vector<MVertex*> &col, int maxNumLayers)
+{
+  static const double spMin = 0.866025404;                                                // Threshold in cosine between 1st edge and normal
+  static const double spTol = 0.999;                                                      // Threshold in cosine between an edge and 1st edge
+
+  MVertex *vert = findVertFromDir(vertex2elements, baseVert, 0, norm, spMin);
+  if (!vert) {                                                                            // If 1st normal edge not found...
+    vert = findVertFromDir(vertex2elements, baseVert, 0, baseEd.normal(), spMin);         // ... tries normal to base edge/face
+    if (!vert) {
+      Msg::Warning("Could not find normal edge for vertex %i ", baseVert->getNum());
+      return false;
+    }
+  }
+  SVector3 firstEdgeDir(baseVert->point(), vert->point());
+  firstEdgeDir.normalize();
+
+  SVector3 dir(baseVert->point(), vert->point());
+  col.push_back(vert);
+  MVertex *oldVert = baseVert, *newVert;
+  for (int iLayer = 0; iLayer < maxNumLayers; iLayer++) {
+    newVert = findVertFromDir(vertex2elements, vert, oldVert, firstEdgeDir, spTol);
+    col.push_back(newVert);                                                               // Will add null pointer at the end, which is OK
+    if (!newVert) break;
+    oldVert = vert;
+    vert = newVert;
+  }
+
+  return (col.size() > 1);
 }
 
 
 
-// Detect whether edge/face is curved, and give normal
-bool isCurvedAndNormal(int type, int order, const std::vector<MVertex*> &faceVert,
-                       SVector3 &normal, double &maxDist) {
+// Add normal to edge/face to data structure for vertices
+void addNormVertEl(MElement *el, const SVector3 &norm,
+                   std::map<MVertex*, SVector3> &normVert)
+{
+  for(unsigned int iV = 0; iV<el->getNumVertices(); iV++) {
+    MVertex *vert = el->getVertex(iV);
+    std::pair<std::map<MVertex*, SVector3>::iterator, bool> insNorm =           // If nothing for vert...
+      normVert.insert(std::pair<MVertex*, SVector3>(vert, SVector3(0.)));       // ... create zero normal
+    insNorm.first->second += norm;                                              // Cumulate normals
+  }
+}
 
-//  static const double eps = 1.e-10;
-  static const double eps = 1.e-6;
 
-  // Compute HO points in straight edge/face
-  const nodalBasis *lagrange = BasisFactory::getNodalBasis(ElementType::getTag(type,order,false));
-  const nodalBasis *lagrange1 = BasisFactory::getNodalBasis(ElementType::getTag(type,1,false));
-  int nV = lagrange->points.size1();
-  int nV1 = lagrange1->points.size1();
-  SPoint3 sxyz[256];
-  for (int i = 0; i < nV1; ++i) sxyz[i] = faceVert[i]->point();
-  for (int i = nV1; i < nV; ++i) {
-    double f[256];
-    lagrange1->f(lagrange->points(i, 0), lagrange->points(i, 1), lagrange->points(i, 2), f);
-    for (int j = 0; j < nV1; ++j)
-      sxyz[i] += sxyz[j] * f[j];
-  }
 
-  // Compute unit normal to straight edge/face and its scale [length]
-  double scale;
-  const SPoint3 &p0 = sxyz[0], &p1 = sxyz[1];
-  if (type == TYPE_LIN) {
-//    normal = SVector3(p0.y()-p1.y(),p1.x()-p0.x(),0.);
-    normal = SVector3(p1.y()-p0.y(),p0.x()-p1.x(),0.);
-    scale = normal.normalize();
-  }
-  else {
-    const SPoint3 &p2 = sxyz[2];
-    SVector3 p01(p0,p1), p02(p0,p2);
-//    normal = crossprod(p01,p02);
-    normal = crossprod(p02,p01);
-    scale = sqrt(normal.normalize());
+// Compute normals to boundary edges/faces and store them per vertex
+void buildNormals(const std::map<MVertex*, std::vector<MElement*> > &vertex2elements,
+                    const std::multimap<GEntity*,GEntity*> &entities, const FastCurvingParameters &p,
+                    std::map<GEntity*, std::map<MVertex*, SVector3> > &normVertEnt)
+{
+  normVertEnt.clear();
+  for (std::multimap<GEntity*,GEntity*>::const_iterator itBE = entities.begin();
+                                                   itBE != entities.end(); itBE++) {  // Loop over model entities
+    GEntity* const &bndEnt = itBE->second;
+    std::map<MVertex*, SVector3> &normVert = normVertEnt[bndEnt];
+    if (bndEnt->dim() == 1) {
+      GEdge *ge = bndEnt->cast2Edge();
+      for(unsigned int iEl = 0; iEl<ge->lines.size(); iEl++) {
+        MLine* const &line = ge->lines[iEl];
+        SVector3 norm = line->getEdge(0).normal();
+        addNormVertEl(line, norm, normVert);
+      }
+    }
+    else if (bndEnt->dim() == 2) {
+      GFace *gf = bndEnt->cast2Face();
+      for(unsigned int iEl = 0; iEl<gf->triangles.size(); iEl++) {
+        MTriangle* const &tri = gf->triangles[iEl];
+        SVector3 norm = tri->getFace(0).normal();
+        addNormVertEl(tri, norm, normVert);
+      }
+      for(unsigned int iEl = 0; iEl<gf->quadrangles.size(); iEl++) {
+        MQuadrangle* const &quad = gf->quadrangles[iEl];
+        SVector3 norm = quad->getFace(0).normal();
+        addNormVertEl(quad, norm, normVert);
+      }
+    }
+    for (std::map<MVertex*, SVector3> ::iterator itNV =                                 // Re-normalize for each geom. entity
+         normVert.begin(); itNV != normVert.end(); itNV++)
+      itNV->second.normalize();
   }
+}
+
 
-  // Calc max. normal dist. from straight to HO points
-  maxDist = 0.;
-  for (int iV = nV1; iV < nV; iV++) {
-    const double normalDisp = dot(SVector3(sxyz[iV],faceVert[iV]->point()),normal);
-    maxDist = std::max(maxDist,fabs(normalDisp));
+
+// Get first domain element for a given boundary edge
+MElement *getFirstEl(const std::map<MVertex*, std::vector<MElement*> > &vertex2elements,
+                     const MEdge &baseEd)
+{
+  MVertex *vb0 = baseEd.getVertex(0), *vb1 = baseEd.getVertex(1);
+
+  const std::vector<MElement*> &nb0 = vertex2elements.find(vb0)->second;
+  const std::vector<MElement*> &nb1 = vertex2elements.find(vb1)->second;
+  MElement *firstEl = 0;
+  for (int iEl=0; iEl<nb0.size(); iEl++) {
+    if (find(nb1.begin(), nb1.end(), nb0[iEl]) != nb1.end()) {
+      firstEl = nb0[iEl];
+      break;
+    }
   }
 
-//  std::cout << "DBGTT: v0 is " << faceVert[0]->getNum() << ", v1 is " << faceVert[1]->getNum()
-//            << ", v2 is " << faceVert[2]->getNum() << ", maxDist = " << maxDist
-//            << ", scale = " << scale << ", test = " << (maxDist > eps*scale) << "\n";
-  return (maxDist > eps*scale);
+  return firstEl;
+}
 
+
+
+// Get intersection of two vectors of MElement*
+void intersect(const std::vector<MElement*> &vi1, const std::vector<MElement*> &vi2,
+               std::vector<MElement*> &vo)
+{
+  vo.clear();
+  for (std::vector<MElement*>::const_iterator it = vi1.begin(); it != vi1.end(); it++)
+    if (std::find(vi2.begin(), vi2.end(), *it) != vi2.end())
+      vo.push_back(*it);
 }
 
 
 
-void makeStraight(MElement *el, const std::set<MVertex*> &movedVert) {
+// Get first domain element for a given boundary face
+MElement *getFirstEl(const std::map<MVertex*, std::vector<MElement*> > &vertex2elements,
+                     const MFace &baseFace)
+{
+  MVertex *vb0 = baseFace.getVertex(0), *vb1 = baseFace.getVertex(1);
+
+  // Get elements common to vertices 0 and 1
+  const std::vector<MElement*> &nb0 = vertex2elements.find(vb0)->second;
+  const std::vector<MElement*> &nb1 = vertex2elements.find(vb1)->second;
+  std::vector<MElement*> nb01;
+  intersect(nb0, nb1, nb01);
+  if (nb01.empty()) return 0;
+  if (nb01.size() == 1) return nb01.front();
+
+  // Get elements common to vertices 0, 1 and 2
+  MVertex *vb2 = baseFace.getVertex(2);
+  const std::vector<MElement*> &nb2 = vertex2elements.find(vb2)->second;
+  std::vector<MElement*> nb012;
+  intersect(nb01, nb2, nb012);
+  if (nb012.empty()) return 0;
+  if (nb012.size() == 1) return nb012.front();
+
+  // If quad, get elements common to all 4 vertices
+  if (baseFace.getNumVertices() == 4) {
+    MVertex *vb3 = baseFace.getVertex(3);
+    const std::vector<MElement*> &nb3 = vertex2elements.find(vb3)->second;
+    std::vector<MElement*> nb0123;
+    intersect(nb012, nb3, nb0123);
+    if (nb0123.empty()) return 0;
+    if (nb0123.size() == 1) return nb0123.front();
+  }
 
-  const nodalBasis *nb = el->getFunctionSpace();
-  const fullMatrix<double> &pts = nb->points;
+  // Too many elements, return error
+  return 0;
+}
 
-  SPoint3 p;
 
-  for(int iPt = el->getNumPrimaryVertices(); iPt < el->getNumVertices(); ++iPt) {
-    MVertex *vert = el->getVertex(iPt);
-    if (movedVert.find(vert) == movedVert.end()) {
-      el->primaryPnt(pts(iPt,0),pts(iPt,1),pts(iPt,2),p);
-      vert->setXYZ(p.x(),p.y(),p.z());
-    }
+
+// Get base vertices (in order of first element) for an edge
+bool getBaseVertices(const MEdge &baseEd, MElement *firstEl, std::vector<MVertex*> &baseVert)
+{
+  baseVert.clear();
+  for (int iEd = 0; iEd < firstEl->getNumEdges(); iEd++)
+    if (firstEl->getEdge(iEd) == baseEd)
+      firstEl->getEdgeVertices(iEd, baseVert);
+
+  if (baseVert.empty()) {
+    Msg::Error("Base edge vertices not found in getBaseVertices");
+    return false;
   }
+  else
+    return true;
+}
 
+
+
+// Get base vertices (in order of first element) for a face
+bool getBaseVertices(const MFace &baseFace, MElement *firstEl, std::vector<MVertex*> &baseVert)
+{
+  baseVert.clear();
+  for (int iFace = 0; iFace < firstEl->getNumFaces(); iFace++)
+    if (firstEl->getFace(iFace) == baseFace)
+      firstEl->getFaceVertices(iFace, baseVert);
+
+  if (baseVert.empty()) {
+    Msg::Error("Base face vertices not found in getBaseVertices");
+    return false;
+  }
+  else
+    return true;
 }
 
 
 
-std::set<MElement*> getSuperElBlob(MElement *el, const std::map<MVertex*,
-                                   std::vector<MElement*> > &vertex2elements,
-                                   const SuperEl *sEl)
+// Top primary vertices (in order corresponding to the primary base vertices)
+template<class bndType>
+bool getTopPrimVertices(std::map<MVertex*, std::vector<MElement *> > &vertex2elements,
+                        const std::map<MVertex*, SVector3> &normVert,
+                        const BoundaryLayerColumns *blc, const bndType &baseBnd,
+                        int maxNumLayers, const std::vector<MVertex*> &baseVert,
+                        std::vector<MVertex*> &topPrimVert)
 {
+  int nbVert = baseBnd.getNumVertices();
+  topPrimVert = std::vector<MVertex*>(nbVert);
+  for(int i = 0; i < nbVert; i++) {
+    if (blc && (blc->size() > 1)) {                                                             // Is there BL data?
+      const BoundaryLayerData &c = blc->getColumn(baseVert[i], baseBnd);
+      if (c._column.size() == 0) return false;                                                  // Give up element if column not found
+      topPrimVert[i] = *(c._column.end()-2);
+    }
+    else {                                                                                      // No BL data, look for columns of vertices
+      std::map<MVertex*, SVector3>::const_iterator itNorm = normVert.find(baseVert[i]);
+      if (itNorm == normVert.end()) {
+        Msg::Error("Normal to vertex not found in getTopPrimVertices");
+        itNorm = normVert.begin();
+      }
+      std::vector<MVertex*> col;
+      bool colFound = findColumn(vertex2elements, baseVert[i], itNorm->second,
+                                 baseBnd, col, maxNumLayers);
+      if (!colFound) return false;                                                              // Give up element if column not found
+      topPrimVert[i] = *(col.end()-2);
+    }
+  }
+
+  return true;
+}
 
-  static const int depth = 100;
 
-  std::set<MElement*> blob;
-  std::list<MElement*> currentLayer, lastLayer;
 
-  blob.insert(el);
-  lastLayer.push_back(el);
-  for (int d = 0; d < depth; ++d) {
+// Get blob of elements encompassed by a given meta-element
+// FIXME: Implement 3D
+void get2DBLBlob(const std::map<MVertex*, std::vector<MElement*> > &vertex2elements,
+                 MElement *firstEl, const SuperEl *supEl, std::set<MElement*> &blob)
+{
+  static const int maxDepth = 100;
+  typedef std::list<MElement*> elLType;
+  typedef std::vector<MElement*> elVType;
+
+  // Build blob by looping over layers of elements (assuming that if an el is too far, its neighbours are too far as well)
+  blob.clear();
+  elLType currentLayer, lastLayer;
+  blob.insert(firstEl);
+  lastLayer.push_back(firstEl);
+  for (int d = 0; d < maxDepth; ++d) {                                                              // Loop over layers
     currentLayer.clear();
-    for (std::list<MElement*>::iterator it = lastLayer.begin();
-         it != lastLayer.end(); ++it) {
+    for (elLType::iterator it = lastLayer.begin(); it != lastLayer.end(); ++it) {                   // Loop over elements of last layer
       for (int i = 0; i < (*it)->getNumPrimaryVertices(); ++i) {
-        const std::vector<MElement*> &neighbours = vertex2elements.find
-          ((*it)->getVertex(i))->second;
-        for (std::vector<MElement*>::const_iterator itN = neighbours.begin();
-             itN != neighbours.end(); ++itN){
-          if (sEl->isPointIn((*itN)->barycenter(true))) {
-            // Assume that if an el is too far, its neighbours are too far as well
-            if (blob.insert(*itN).second) currentLayer.push_back(*itN);
-          }
+        const elVType &neighbours = vertex2elements.find((*it)->getVertex(i))->second;
+        for (elVType::const_iterator itN = neighbours.begin(); itN != neighbours.end(); ++itN) {    // Loop over neighbours of last layer
+          SPoint3 p = (*itN)->barycenter(true);
+          if (supEl->isPointIn(p))                                                                  // Add neighbour to blob if inside test element
+            if (blob.insert(*itN).second) currentLayer.push_back(*itN);                             // Add to current layer if new in blob
         }
       }
     }
+    if (currentLayer.empty()) break;                                                                // Finished if no new element in blob
     lastLayer = currentLayer;
-    if (currentLayer.empty()) break;
   }
+}
+
+
 
-  return blob;
+void makeStraight(MElement *el, const std::set<MVertex*> &movedVert)
+{
+  const nodalBasis *nb = el->getFunctionSpace();
+  const fullMatrix<double> &pts = nb->points;
+
+  SPoint3 p;
+
+  for(int iPt = el->getNumPrimaryVertices(); iPt < el->getNumVertices(); ++iPt) {
+    MVertex *vert = el->getVertex(iPt);
+    if (movedVert.find(vert) == movedVert.end()) {
+      el->primaryPnt(pts(iPt,0),pts(iPt,1),pts(iPt,2),p);
+      vert->setXYZ(p.x(),p.y(),p.z());
+    }
+  }
 }
 
 
 
-void curveMeshFromFaces(std::map<MVertex*, std::vector<MElement *> > &vertex2elements,
-                        std::set<MElement*> &faceElements, FastCurvingParameters &p)
+inline void insertIfCurved(MElement *el, std::list<MElement*> &bndEl)
 {
+  static const double curvedTol = 1.e-3;                                              // Tolerance to consider element as curved
 
-  const int nbFaceElts = faceElements.size();
-  std::vector<MElement*> faceElts;
-  std::vector<SuperEl*> superElts;
-  faceElts.reserve(nbFaceElts);
-  superElts.reserve(nbFaceElts);
+  const double normalDispCurved = curvedTol*el->getInnerRadius();                     // Threshold in normal displacement to consider element as curved
+  const int dim = el->getDim();
 
-  std::ofstream of("dum.pos");
-  of << "View \" \"{\n";
+  // Compute unit normal to straight edge/face
+  SVector3 normal = (dim == 1) ? el->getEdge(0).normal() : el->getFace(0).normal();
+
+  // Get functional spaces
+  const nodalBasis *lagBasis = el->getFunctionSpace();
+  const fullMatrix<double> &uvw = lagBasis->points;
+  const int &nV = uvw.size1();
+  const nodalBasis *lagBasis1 = el->getFunctionSpace(1);
+  const int &nV1 = lagBasis1->points.size1();
 
-  for (std::set<MElement*>::const_iterator itFE = faceElements.begin(); itFE != faceElements.end(); ++itFE) {
-    const int dim = (*itFE)->getDim();
-    const int order = (*itFE)->getPolynomialOrder();
-    const int numPrimVert = (*itFE)->getNumPrimaryVertices();
-    const int type = (*itFE)->getType();
-    std::vector<MVertex*> faceVert;
-    (*itFE)->getVertices(faceVert);
-    double maxDist;
-    SVector3 faceNormal;
-    if (isCurvedAndNormal(type,order,faceVert,faceNormal,maxDist)) {
-      std::vector<SVector3> baseNormal;
-      for (int iV=0; iV<numPrimVert; iV++)                                // Compute normals to prim. vert. of edge/face
-        baseNormal.push_back(getNormalEdge(faceVert[iV],faceNormal,vertex2elements));
-      faceElts.push_back(*itFE);
-      superElts.push_back(new SuperEl(order,maxDist*p.distanceFactor,type,faceVert,baseNormal));
-      of << superElts.back()->printPOS();
+  // Get first-order vertices
+  std::vector<SPoint3> xyz1(nV1);
+  for (int iV = 0; iV < nV1; ++iV) xyz1[iV] = el->getVertex(iV)->point();
+
+  // Check normal displacement at each HO vertex
+  for (int iV = nV1; iV < nV; ++iV) {                                                 // Loop over HO nodes
+    double f[256];
+    lagBasis1->f(uvw(iV, 0), (dim > 1) ? uvw(iV, 1) : 0., 0., f);
+    SPoint3 xyzS(0.,0.,0.);
+    for (int iSF = 0; iSF < nV1; ++iSF) xyzS += xyz1[iSF]*f[iSF];                     // Compute location of node in straight element
+    const SVector3 vec(xyzS, el->getVertex(iV)->point());
+    const double normalDisp = dot(vec, normal);                                       // Normal component of displacement
+    if (normalDisp > normalDispCurved) {
+      bndEl.push_back(el);
+      break;
     }
   }
+}
+
 
-  of << "};\n";
-  of.close();
+
+// Curve elements adjacent to a boundary model entity
+void curveMeshFromBnd(std::map<MVertex*, std::vector<MElement *> > &vertex2elements,
+                      const std::map<MVertex*, SVector3> &normVert, BoundaryLayerColumns *blc,
+                      GEntity *bndEnt, FastCurvingParameters &p)
+{
+  // Build list of bnd. elements to consider
+  std::list<MElement*> bndEl;
+  if (bndEnt->dim() == 1) {
+    GEdge *gEd = bndEnt->cast2Edge();
+    for(unsigned int i = 0; i< gEd->lines.size(); i++)
+      insertIfCurved(gEd->lines[i], bndEl);
+  }
+  else if (bndEnt->dim() == 2) {
+    GFace *gFace = bndEnt->cast2Face();
+    for(unsigned int i = 0; i< gFace->triangles.size(); i++)
+      insertIfCurved(gFace->triangles[i], bndEl);
+    for(unsigned int i = 0; i< gFace->quadrangles.size(); i++)
+      insertIfCurved(gFace->quadrangles[i], bndEl);
+  }
+  else
+    Msg::Error("Cannot treat model entity %i of dim %i", bndEnt->tag(), bndEnt->dim());
+
+  std::ostringstream oss;
+  oss << "meta-elements_" << bndEnt->tag() << ".pos";
+  std::ofstream of(oss.str().c_str());
+  of << "View \" \"{\n";
 
   std::set<MVertex*> movedVert;
-  for (int iFE=0; iFE<faceElts.size(); ++iFE) {
-    std::set<MElement*> blob = getSuperElBlob(faceElts[iFE], vertex2elements, superElts[iFE]);
-//    std::cout << "DBGTT: Blob of bad el. " << faceElts[iBE]->getNum() << " contains elts.";
-//    for (std::set<MElement*>::iterator itE = blob.begin(); itE != blob.end(); ++itE) std::cout << " " << (*itE)->getNum();
-//    std::cout << "\n";
-//    makeStraight(faceElts[iFE],movedVert);                                             // Make bad. el. straight
+  for(std::list<MElement*>::iterator itBE = bndEl.begin();
+      itBE != bndEl.end(); itBE++) {   // Loop over bnd. elements
+    const int bndType = (*itBE)->getType();
+    int seType;
+    bool foundVert;
+    MElement *firstEl = 0;
+    std::vector<MVertex*> baseVert, topPrimVert;
+    if (bndType == TYPE_LIN) {                                                               // 1D boundary?
+      MVertex *vb0 = (*itBE)->getVertex(0);
+      MVertex *vb1 = (*itBE)->getVertex(1);
+      seType = TYPE_QUA;
+      MEdge baseEd(vb0, vb1);
+      firstEl = getFirstEl(vertex2elements, baseEd);
+      foundVert = getBaseVertices(baseEd, firstEl, baseVert);
+      if (!foundVert) continue;                                                             // Skip bnd. el. if base vertices not found
+      foundVert = getTopPrimVertices(vertex2elements, normVert, blc, baseEd,
+                                     p.maxNumLayers, baseVert, topPrimVert);
+    }
+    else {                                                                                  // 2D boundary
+      MVertex *vb0 = (*itBE)->getVertex(0);
+      MVertex *vb1 = (*itBE)->getVertex(1);
+      MVertex *vb2 = (*itBE)->getVertex(2);
+      MVertex *vb3;
+      if (bndType == TYPE_QUA) {
+        vb3 = (*itBE)->getVertex(3);
+        seType = TYPE_HEX;
+      }
+      else {
+        vb3 = 0;
+        seType = TYPE_PRI;
+      }
+      MFace baseFace(vb0, vb1, vb2, vb3);
+      firstEl = getFirstEl(vertex2elements, baseFace);
+      if (!firstEl) {
+        Msg::Error("Did not find first domain element for boundary element %i",
+                   (*itBE)->getNum());
+        continue;
+      }
+      foundVert = getBaseVertices(baseFace, firstEl, baseVert);
+      if (!foundVert) continue;                                                             // Skip bnd. el. if base vertices not found
+      foundVert = getTopPrimVertices(vertex2elements, normVert, blc,
+                                     baseFace, p.maxNumLayers,
+                                     baseVert, topPrimVert);
+    }
+    if (!foundVert) continue;                                                               // Skip bnd. el. if top vertices not found
+    int order = firstEl->getPolynomialOrder();
+    SuperEl se(seType, order, baseVert, topPrimVert);
+    of << se.printPOS();
+    std::set<MElement*> blob;
+    get2DBLBlob(vertex2elements, firstEl, &se, blob); // TODO: Implement for 3D
     for (std::set<MElement*>::iterator itE = blob.begin(); itE != blob.end(); ++itE) {
-      makeStraight(*itE,movedVert);
-      for (int i = 0; i < (*itE)->getNumVertices(); ++i) {                            // For each vert. of each el. in blob
-//      for (int i = (*itE)->getNumPrimaryVertices(); i < (*itE)->getNumVertices(); ++i) {                            // For each vert. of each el. in blob
+      makeStraight(*itE, movedVert);
+      for (int i = (*itE)->getNumPrimaryVertices(); i < (*itE)->getNumVertices(); ++i) {    // Loop over HO vert. of each el. in blob
         MVertex* vert = (*itE)->getVertex(i);
-        if (movedVert.find(vert) == movedVert.end()) {                                // If vert. not already moved
+        if (movedVert.find(vert) == movedVert.end()) {                                      // Try to move vert. not already moved
           double xyzS[3] = {vert->x(), vert->y(), vert->z()}, xyzC[3];
-          if (superElts[iFE]->straightToCurved(xyzS,xyzC)) {
-//            std::cout << "DBGTT: moving vertex " << vert->getNum() << " from (" << xyzS[0] << "," << xyzS[1] << "," << xyzS[2] << ") to (" << xyzC[0] << "," << xyzC[1] << "," << xyzC[2] << ")\n";
-            vert->setXYZ(xyzC[0],xyzC[1],xyzC[2]);
+          if (se.straightToCurved(xyzS,xyzC)) {
+            vert->setXYZ(xyzC[0], xyzC[1], xyzC[2]);
             movedVert.insert(vert);
           }
-//          else std::cout << "DBGTT: Failed to move vertex " << vert->getNum() << " with bad. el " << faceElts[iBE]->getNum() << "\n";
         }
-//        else std::cout << "DBGTT: Already moved vertex " << vert->getNum() << " with bad. el " << faceElts[iBE]->getNum() << "\n";
       }
     }
   }
 
+  of << "};\n";
+  of.close();
 }
 
 
@@ -349,35 +523,81 @@ void curveMeshFromFaces(std::map<MVertex*, std::vector<MElement *> > &vertex2ele
 
 
 
+// Main function for fast curving
 void HighOrderMeshFastCurving(GModel *gm, FastCurvingParameters &p)
 {
-
   double t1 = Cpu();
 
   Msg::StatusBar(true, "Optimizing high order mesh...");
-  std::vector<GEntity*> entities;
-  gm->getEntities(entities);
-  const int bndDim = p.dim-1;
+  std::vector<GEntity*> allEntities;
+  gm->getEntities(allEntities);
 
   // Compute vert. -> elt. connectivity
   Msg::Info("Computing connectivity...");
   std::map<MVertex*, std::vector<MElement *> > vertex2elements;
-  for (int iEnt = 0; iEnt < entities.size(); ++iEnt)
-    calcVertex2Elements(p.dim,entities[iEnt],vertex2elements);
+  for (int iEnt = 0; iEnt < allEntities.size(); ++iEnt)
+    calcVertex2Elements(p.dim, allEntities[iEnt], vertex2elements);
+
+  // Get BL field (if any)
+  BoundaryLayerField *blf = getBLField(gm);
+
+  // Build multimap of each geometric entity to its boundaries
+  std::multimap<GEntity*,GEntity*> entities;
+  if (blf) {                                                                                    // BF field?
+    for (int iEnt = 0; iEnt < allEntities.size(); ++iEnt) {
+      GEntity* &entity = allEntities[iEnt];
+      if (entity->dim() == p.dim && (!p.onlyVisible || entity->getVisibility()))                // Consider only "domain" entities
+        if (p.dim == 2) {                                                                       // "Domain" face?
+          std::list<GEdge*> edges = entity->edges();
+          for (std::list<GEdge*>::iterator itEd = edges.begin(); itEd != edges.end(); itEd++)   // Loop over model boundary edges
+            if (blf->isEdgeBL((*itEd)->tag()))                                                  // Already skip model edge if no BL there
+              entities.insert(std::pair<GEntity*,GEntity*>(entity, *itEd));
+        }
+        else if (p.dim == 3) {                                                                  // "Domain" region?
+          std::list<GFace*> faces = entity->faces();
+          for (std::list<GFace*>::iterator itF = faces.begin(); itF != faces.end(); itF++)      // Loop over model boundary faces
+            if (blf->isFaceBL((*itF)->tag()))                                                   // Already skip model face if no BL there
+              entities.insert(std::pair<GEntity*,GEntity*>(entity, *itF));
+        }
+    }
+  }
+  else {                                                                                        // No BL field
+    for (int iEnt = 0; iEnt < allEntities.size(); ++iEnt) {
+      GEntity* &entity = allEntities[iEnt];
+      if (entity->dim() == p.dim-1 && (!p.onlyVisible || entity->getVisibility()))              // Consider boundary entities
+        entities.insert(std::pair<GEntity*,GEntity*>(0, entity));
+    }
+  }
+
+  // Build normals if necessary
+  std::map<GEntity*, std::map<MVertex*, SVector3> > normVertEnt;                                // Normal to each vertex for each geom. entity
+  if (!blf) {
+    Msg::Warning("Boundary layer data not found, trying to detect columns");
+    buildNormals(vertex2elements, entities, p, normVertEnt);
+  }
 
   // Loop over geometric entities
-  for (int iEnt = 0; iEnt < entities.size(); ++iEnt) {
-    GEntity* &entity = entities[iEnt];
-    if (entity->dim() != bndDim || (p.onlyVisible && !entity->getVisibility())) continue;
-    Msg::Info("Curving elements for entity %d...",entity->tag());
-    std::set<MElement*> faceElements;
-    for (int iEl = 0; iEl < entity->getNumMeshElements();iEl++)
-      faceElements.insert(entity->getMeshElement(iEl));
-    curveMeshFromFaces(vertex2elements, faceElements, p);
+  for (std::multimap<GEntity*,GEntity*>::iterator itBE = entities.begin();
+       itBE != entities.end(); itBE++) {
+    GEntity *domEnt = itBE->first, *bndEnt = itBE->second;
+    BoundaryLayerColumns *blc = 0;
+    if (blf) {
+      Msg::Info("Curving elements for entity %d bounding entity %d...",
+                bndEnt->tag(), domEnt->tag());
+      if (p.dim == 2)
+        blc = domEnt->cast2Face()->getColumns();
+      else if (p.dim == 3)
+        blc = domEnt->cast2Region()->getColumns();
+      else
+        Msg::Error("Fast curving implemented only in dim. 2 and 3");
+    }
+    else
+      Msg::Info("Curving elements for boundary entity %d...", bndEnt->tag());
+    std::map<MVertex*, SVector3> &normVert = normVertEnt[bndEnt];
+    curveMeshFromBnd(vertex2elements, normVert, blc, bndEnt, p);
   }
 
   double t2 = Cpu();
 
   Msg::StatusBar(true, "Done curving high order mesh (%g s)", t2-t1);
-
 }
diff --git a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.h b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.h
index f9ae4a5..9b11491 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.h
+++ b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.h
@@ -33,17 +33,12 @@
 class GModel;
 
 struct FastCurvingParameters {
-  // INPUT ------>
-  double BARRIER_MIN ; // minimum scaled jcaobian
-  double BARRIER_MAX ; // maximum scaled jcaobian
-  int dim ; // which dimension to optimize
-  bool onlyVisible ; // apply optimization to visible entities ONLY
-  double distanceFactor; // filter elements such that no elements further away
-                         // than DistanceFactor times the max distance to
-                         // straight sided version of an element are optimized
+  int dim ;           // Which dimension to curve
+  bool onlyVisible ;  // Apply curving to visible entities ONLY
+  int maxNumLayers;   // Maximum number of element layers to consider when trying to detect BL
 
   FastCurvingParameters ()
-    : BARRIER_MIN(0.1), BARRIER_MAX(2.0), dim(3) , onlyVisible(true), distanceFactor(12)
+    : dim(3) , onlyVisible(true), maxNumLayers(6)
   {
   }
 };
diff --git a/contrib/HighOrderMeshOptimizer/OptHomIntegralBoundaryDist.cpp b/contrib/HighOrderMeshOptimizer/OptHomIntegralBoundaryDist.cpp
new file mode 100644
index 0000000..a19f492
--- /dev/null
+++ b/contrib/HighOrderMeshOptimizer/OptHomIntegralBoundaryDist.cpp
@@ -0,0 +1,521 @@
+#include "GEdge.h"
+#include "nodalBasis.h"
+#include "SVector3.h"
+#include <algorithm>
+#include <limits>
+#include "OptHomIntegralBoundaryDist.h"
+#include "discreteFrechetDistance.h"
+#include "MLine.h"
+
+parametricLineNodalBasis::parametricLineNodalBasis(const nodalBasis &basis,
+                                                   const std::vector<SPoint3> &xyz):
+  _basis(basis), _xyz(xyz) {};
+
+SPoint3 parametricLineNodalBasis::operator()(double xi) const
+{
+  std::vector<double> psi(_xyz.size());
+  SPoint3 p(0, 0, 0);
+  _basis.f(-1 + 2 * xi, 0, 0, &psi[0]);
+  for (size_t j = 0; j < psi.size(); ++j) {
+    p[0] += psi[j] * _xyz[j].x();
+    p[1] += psi[j] * _xyz[j].y();
+    p[2] += psi[j] * _xyz[j].z();
+  }
+  return p;
+}
+
+SVector3 parametricLineNodalBasis::derivative(double xi) const
+{
+  double dpsi[1256][3];
+  SVector3 p(0, 0, 0);
+  _basis.df(-1 + 2 * xi, 0, 0, dpsi);
+  for (size_t j = 0; j < _xyz.size(); ++j) {
+    p[0] += dpsi[j][0] * _xyz[j].x();
+    p[1] += dpsi[j][0] * _xyz[j].y();
+    p[2] += dpsi[j][0] * _xyz[j].z();
+  }
+  return p;
+}
+
+SVector3 parametricLineNodalBasis::secondDerivative(double xi) const
+{
+  double ddpsi[1256][3][3];
+  SVector3 p(0, 0, 0);
+  _basis.ddf(-1 + 2 * xi, 0, 0, ddpsi);
+  for (size_t j = 0; j < _xyz.size(); ++j) {
+    p[0] += ddpsi[j][0][0] * _xyz[j].x();
+    p[1] += ddpsi[j][0][0] * _xyz[j].y();
+    p[2] += ddpsi[j][0][0] * _xyz[j].z();
+  }
+  return p;
+}
+
+parametricLineGEdge::parametricLineGEdge(const GEdge *edge, double t0, double t1):
+  _edge(edge), _t0(t0), _t1(t1) {}
+
+SPoint3 parametricLineGEdge::operator()(double xi) const
+{
+  GPoint gp = _edge->point(_t0 + (_t1 - _t0) * xi);
+  return SPoint3 (gp.x(), gp.y(), gp.z());
+}
+
+SVector3 parametricLineGEdge::derivative(double xi) const
+{
+  return _edge->firstDer(_t0 + (_t1 - _t0) * xi);
+}
+
+SVector3 parametricLineGEdge::secondDerivative(double xi) const
+{
+  return _edge->secondDer(_t0 + (_t1 - _t0) * xi);
+}
+
+static void oversample (std::vector<SPoint3> &s, double tol)
+{
+  std::vector<SPoint3> t;
+  for (unsigned int i=1;i<s.size();i++){
+    SPoint3 p0 = s[i-1];
+    SPoint3 p1 = s[i];
+    double d = p0.distance(p1);
+    int N = (int) (d / tol);
+    //    printf("N = %d %g %g\n",N,d,tol);
+    t.push_back(p0);
+    for (int j=1;j<N;j++){
+      const double xi = (double) j/ N;
+      t.push_back(p0 + (p1-p0)*xi);
+    }
+  }
+  t.push_back(s[s.size()-1]);
+  s = t;
+}
+
+// FAST IMPLEMENTATION OF DISCRETE UNIDIRECTIONAL HAUSDORFF DISTANCE
+double computeBndDistH(GEdge *edge, std::vector<double> & params, // the model edge
+		       const std::vector<MVertex*> &vs,
+		       const nodalBasis &basis, const std::vector<SPoint3> &xyz,
+		       const double tolerance) // the mesh edge
+{
+  if (edge->geomType() == GEntity::Line)return 0.0;
+  std::vector<SPoint3> dpts;
+  std::vector<double> ts;
+  std::vector<MVertex*> hov;
+  for (unsigned int i=2;i<vs.size();i++)hov.push_back(vs[i]);
+  MLineN l (vs[0],vs[1],hov);
+  l.discretize (tolerance,dpts,ts);
+  oversample(dpts,tolerance);
+  double maxDist = 0.0;
+  for (unsigned int i = 0; i<dpts.size(); i++){
+    maxDist = std::max (maxDist,dpts[i].distance(edge->closestPoint(dpts[i],tolerance)));
+  }
+  return maxDist;
+}
+
+SVector3 parametricLine::curvature(double xi) const
+{
+  SVector3 xp  = derivative(xi);
+  SVector3 xpp = secondDerivative(xi);
+  const double nxp = xp.norm();
+  const double onxp = 1./nxp;
+  SVector3 c = (onxp*onxp*onxp)*(xpp*nxp-xp*dot(xp,xpp)*onxp);
+  return c;
+}
+
+double parametricLine::frechetDistance(const parametricLine &l,
+				       SPoint3 &p1, SPoint3 &p2,
+				       double tol) const
+{
+  std::vector<SPoint3> dpts1,dpts2;
+  std::vector<double> ts1,ts2;
+  discretize (dpts1,ts1,tol);
+  l.discretize (dpts2,ts2,tol);
+  //  printf("discretizing gives %d %d points\n",dpts1.size(),dpts2.size());
+  oversample(dpts1,tol);
+  oversample(dpts2,tol);
+  //  printf("after oversaplinf an discretizing gives %d %d points\n",dpts1.size(),dpts2.size());
+  return discreteFrechetDistance(dpts1,dpts2);
+}
+double parametricLine::hausdorffDistance(const parametricLine &l, SPoint3 &p1, SPoint3 &p2,
+					 double tolerance) const
+{
+  std::vector<SPoint3> dpts1,dpts2;
+  std::vector<double> ts1,ts2;
+  discretize (dpts1,ts1,tolerance);
+  l.discretize (dpts2,ts2,tolerance);
+
+  //  oversample(dpts1,tolerance);
+  //  oversample(dpts2,tolerance);
+  //  printf("coucou4 %d %d points\n",dpts1.size(),dpts2.size());
+  double h1 = 0.0;
+  int I1=0,J1=0;
+  int I2=0,J2=0;
+  for (unsigned int i = 0; i<dpts1.size();i++){
+    double hl = 1.e22;
+    int JLOC = 0;
+    for (unsigned int j = 0; j<dpts2.size();j++){
+      double H = dpts1[i].distance(dpts2[j]);
+      if (hl < H){
+	hl = H;
+	JLOC = j;
+      }
+    }
+    if (hl > h1){
+      h1 = hl;
+      J1 = JLOC;
+      I1 = i;
+    }
+  }
+  double h2 = 0.0;
+  for (unsigned int i = 0; i<dpts2.size();i++){
+    double hl = 1.e22;
+    int JLOC = 0;
+    for (unsigned int j = 0; j<dpts1.size();j++){
+      double H = dpts1[j].distance(dpts2[i]);
+      if (hl < H){
+	hl = H;
+	JLOC = j;
+      }
+    }
+    if (hl > h2){
+      h2 = hl;
+      J2 = JLOC;
+      I2 = i;
+    }
+  }
+  if (h1 > h2){
+    p1 = dpts1[I1];
+    p2 = dpts2[J1];
+    return h1;
+  }
+  else{
+    p1 = dpts2[I2];
+    p2 = dpts1[J2];
+    return h2;
+  }
+}
+
+// DISCRETE FRECHET DISTANCE
+double computeBndDistF(GEdge *edge,
+		       std::vector<double> & params, // the model edge
+		       const nodalBasis &basis,
+		       const std::vector<SPoint3> &xyz,
+		       const double tolerance) // the mesh edge
+{
+  if (edge->geomType() == GEntity::Line)return 0.0;
+  parametricLineGEdge l1 = parametricLineGEdge(edge, params[0],params[1]);
+  parametricLineNodalBasis l2 = parametricLineNodalBasis(basis, xyz);
+  SPoint3 p1,p2;
+  return l1.frechetDistance(l2,p1,p2,tolerance);
+}
+
+// GMSH's DISTANCE
+/*
+ */
+double computeBndDistGb(GEdge *edge, std::vector<double> & params, // the model edge
+		       const nodalBasis &basis, const std::vector<SPoint3> &xyz, double tolerance) // the mesh edge
+{
+  parametricLineGEdge l1 = parametricLineGEdge(edge, params[0], params[1]);
+  parametricLineNodalBasis l2 = parametricLineNodalBasis(basis, xyz);
+  const unsigned int N = 20;
+  SPoint3 P1[N];
+  SPoint3 P2[N];
+  double D = 0.0;
+  for (unsigned int i=0;i<N;i++){
+    const double _x2 = (double)i / (N-1);
+    P1[i] = l1(_x2);
+    P2[i] = l2(_x2);
+  }
+  double L = 0.0;
+  for (unsigned int i=0;i<N-1;i++){
+    SPoint3 p11 = P1[i];
+    SPoint3 p12 = P1[i+1];
+    SPoint3 p21 = P2[i];
+    SPoint3 p22 = P2[i+1];
+    SVector3 v1  (p21,p11);
+    SVector3 v2  (p12,p11);
+    SVector3 v12 (p22,p11);
+    SVector3 vl (p22,p21);
+    SVector3 x1 = crossprod(v12,v1);
+    SVector3 x2 = crossprod(v12,v2);
+    D += 0.5*(x1.norm()+x2.norm());
+    L += vl.norm();
+  }
+  return D;
+}
+
+double computeBndDistG_(GEdge *edge, std::vector<double> & p, // the model edge
+		       const nodalBasis &basis, const std::vector<SPoint3> &xyz,
+		       const unsigned int NN) // the mesh edge
+{
+  const unsigned int N = 256;
+  std::vector<int> o;
+  o.push_back(0);
+  for (unsigned int i=2; i < p.size();i++)o.push_back(i);
+  o.push_back(1);
+
+  //  printf("computing diustance with tolerance %g\n",tolerac);
+
+  double D = 0.0;
+  const double U0 = basis.points(0,0);
+  const double U1 = basis.points(1,0);
+  for (int i = 0 ; i < basis.order ; i++) {
+    const double u0 = basis.points(o[i],0);
+    const double u1 = basis.points(o[i+1],0);
+
+    // U0 ----u0-----u1-----U1
+
+    const double t0 = p[o[i]];
+    const double t1 = p[o[i+1]];
+    parametricLineGEdge l1 = parametricLineGEdge(edge, t0, t1);
+    parametricLineNodalBasis l2 = parametricLineNodalBasis(basis, xyz);
+    std::vector<SPoint3> P1(N), P2(N);
+    for (unsigned int i=0;i<N;i++){
+      const double _x2 = (double)i / (N-1);
+      const double u = u0 + _x2 * (u1-u0);
+      // U0 + uu * (U1 - U0) = u
+      const double uu = (u - U0) / (U1-U0);
+      P1[i] = l1(_x2);
+      P2[i] = l2(uu);
+    }
+    //    double L = 0.0;
+    for (unsigned int i=0;i<N-1;i++){
+      SPoint3 p11 = P1[i];
+      SPoint3 p12 = P1[i+1];
+      SPoint3 p21 = P2[i];
+      SPoint3 p22 = P2[i+1];
+      SVector3 v1  (p21,p11);
+      SVector3 v2  (p12,p11);
+      SVector3 v12 (p22,p11);
+      //      SVector3 vl (p22,p21);
+      SVector3 x1 = crossprod(v12,v1);
+      SVector3 x2 = crossprod(v12,v2);
+      D += 0.5*(x1.norm()+x2.norm());
+      //      L += vl.norm();
+    }
+  }
+  return D;
+}
+
+double computeBndDistG(GEdge *edge, std::vector<double> & p, // the model edge
+		       const nodalBasis &basis, const std::vector<SPoint3> &xyz,
+		       double tolerance) // the mesh edge
+{
+  int N = 4;
+  double d = computeBndDistG_(edge, p, basis, xyz, N);
+
+  //    printf("GO !!\n");
+  while (1){
+    N *= 2;
+    double dp = computeBndDistG_(edge, p, basis, xyz, N);
+    //        printf("%12.5E %12.5E %12.5E %12.5E\n",d,dp,fabs(d - dp),tolerance);
+    if (fabs(d - dp) < tolerance) // Richardson with assumed linear convergence ...
+      return dp;
+    d = dp;
+  }
+}
+
+void parametricLine::recur_discretize(const double &t1, const double &t2,
+				      const SPoint3 &p1, const SPoint3 &p2,
+				      std::vector<SPoint3> &dpts,
+				      std::vector<double> &ts,
+				      double Prec, int depth) const
+{
+  double t = 0.5 * (t2 + t1);
+  SPoint3 p = (*this)(t);
+  SVector3 dx (p,(p1+p2)*0.5);
+  //  printf("%g %g -- %g %g dist %12.5E %12.5E\n",p1.x(),p1.y(),p2.x(),p2.y(),dx.norm(),Prec);
+  if ((depth > 20 && dx.norm() < Prec) || depth > 45){
+    dpts.push_back(p);
+    ts.push_back(t);
+    dpts.push_back(p2);
+    ts.push_back(t2);
+  }
+  else {
+    recur_discretize (t1,t,p1,p,dpts,ts,Prec,depth+1);
+    recur_discretize (t,t2,p,p2,dpts,ts,Prec,depth+1);
+  }
+}
+
+void parametricLine::discretize(std::vector<SPoint3> &dpts,
+				std::vector<double> &ts,
+				double Prec, double t0, double t1) const
+{
+  dpts.push_back((*this)(t0));
+  ts.push_back(t0);
+  recur_discretize (t0,t1,dpts[0],(*this)(t1),dpts,ts,Prec,0);
+
+  //  printf("discretizing from %g to %g\n",t0,t1);
+  //  for (unsigned int i=0;i<ts.size();i++){
+  //    printf("%g ",ts[i]);
+  //  }
+  //  printf("\n");
+
+}
+
+double trapeze (SPoint3 &p1, SPoint3 &p2){
+  return (p2.x() - p1.x())*(p1.y()+p2.y())*0.5;
+}
+
+double computeDeviationOfTangents(GEdge *edge,
+				  std::vector<double> &p, // parameters of mesh vertices on the model edge
+				  const nodalBasis &basis,
+				  const std::vector<SPoint3> &xyz) // the mesh edge
+{
+  //  parametricLineGEdge l1 = parametricLineGEdge(edge,p[0],p[p.size()-1]);
+  parametricLineNodalBasis l2 = parametricLineNodalBasis(basis, xyz);
+  double  deviation = 0;
+  double ddeviation = 0;
+  std::vector<int> o;
+  o.push_back(0);
+  for (unsigned int i=2; i < p.size();i++)o.push_back(i);
+  o.push_back(1);
+
+  SVector3 dx (xyz[xyz.size() - 1], xyz[0]);
+
+  for (unsigned int i=0; i<p.size();i++){
+    const double u = basis.points(o[i],0);
+    SVector3 xp = edge->firstDer (p[o[i]]);
+    SVector3 xpp = edge->secondDer (p[o[i]]);
+    const double nxp = xp.norm();
+    const double onxp = 1./nxp;
+    SVector3 c = (onxp*onxp*onxp)*(xpp*nxp-xp*dot(xp,xpp)*onxp);
+
+    SVector3 t_mesh_edge  = l2.derivative(0.5*(1+u));
+    SVector3 c2  = l2.curvature(0.5*(1+u));
+    //    GPoint p0 = edge->point(p[o[i]]);
+    //    SPoint3 p1 = l2 (0.5*(1+u));
+    //    printf("%g = %g %g vs %g %g\n",u,p0.x(),p0.y(),p1.x(),p1.y());
+    xp.normalize();
+    t_mesh_edge.normalize();
+    SVector3 diff1 = (dot(xp, t_mesh_edge) > 0) ? xp -  t_mesh_edge : xp +  t_mesh_edge;
+    SVector3 diff2 = (dot(c, c2) > 0) ? c -  c2 : c +  c2;
+    //printf("%g %g %g vs %g %g %g diff %g %g %g\n",c.x(),c.y(),c.z(),c2.x(),c2.y(),c2.z(),diff2.x(),diff2.y(),diff2.z());
+    //    printf("%g %g %g vs %g %g %g val %g\n",t_model_edge.x(),t_model_edge.y(),t_model_edge.z(),
+    //	   t_mesh_edge.x(),t_mesh_edge.y(),t_mesh_edge.z(),c.norm());
+    //     deviation = std::max(diff1.norm(),deviation);
+    //    ddeviation = std::max(diff2.norm(),ddeviation);
+     deviation += diff1.norm();
+    ddeviation += diff2.norm();
+  }
+  const double h =  dx.norm();
+  //  printf ("%g %g\n",deviation * h,ddeviation * h * h * 0.5);
+  return deviation * h;// + ddeviation * h * h * 0.5;
+}
+
+double computeBndDistAccurateArea(GEdge *edge,
+				  std::vector<double> &p, // parameters of mesh vertices on the model edge
+				  const nodalBasis &basis,
+				  const std::vector<SPoint3> &xyz,
+				  double tolerance) // the mesh edge
+{
+  // assume mesh and CAD non intersecting except at mesh vertices
+  // compute distance for "order" sub-polygonal curves
+  double area = 0.0;
+  double length = 0.0;
+  std::vector<int> o;
+  o.push_back(0);
+  for (unsigned int i=2; i < p.size();i++)o.push_back(i);
+  o.push_back(1);
+
+  //  printf("computing diustance with tolerance %g\n",tolerac);
+
+  for (int i = 0 ; i < basis.order ; i++) {
+    const double u0 = basis.points(o[i],0);
+    const double u1 = basis.points(o[i+1],0);
+    const double t0 = p[o[i]];
+    const double t1 = p[o[i+1]];
+    parametricLineGEdge l1 = parametricLineGEdge(edge, t0, t1);
+    parametricLineNodalBasis l2 = parametricLineNodalBasis(basis, xyz);
+    std::vector<SPoint3> dpts1,dpts2;
+    std::vector<double> ts1,ts2;
+    l1.discretize (dpts1,ts1,tolerance);
+    l2.discretize (dpts2,ts2,tolerance,0.5*(1+u0),0.5*(1+u1));
+    //    printf("discretizing : %g %g and %g %g\n",u0,u1,t0,t1);
+    // simple 2D version
+    double arealocal = 0.0;
+    for (unsigned int j=1;j<dpts1.size(); j++) {
+      length += dpts1[j-1].distance (dpts1[j]);
+      arealocal += trapeze (dpts1[j-1],dpts1[j]);
+    }
+    for (unsigned int j=1;j<dpts2.size(); j++) {
+      arealocal -= trapeze (dpts2[j-1],dpts2[j]);
+    }
+    area += fabs(arealocal);
+  }
+  return area;
+}
+
+
+// INPUT FCT FOR OPTIMIZATION
+double computeBndDistAndGradient(GEdge *edge,
+				 std::vector<double> &param, // parameters of mesh vertices on the model edge
+				 const std::vector<MVertex*> &vs, // vertices
+				 const nodalBasis &basis,  // what is the FE basis of the edge
+				 std::vector<SPoint3> &xyz,  // real coordinates of mesh vertices on the model edge
+				 std::vector<bool> &onEdge, // tell if a given vertex sits on the model edge and therefore can be movd
+				 std::vector<double> &grad,
+				 double tolerance)// model tolerance
+{
+  grad.resize(xyz.size());
+  double ref;
+  if (tolerance  < 0 ) ref = computeDeviationOfTangents(edge, param,basis, xyz);
+  else ref = computeBndDistG(edge, param,basis, xyz, tolerance);
+    //double ref = computeBndDistAccurateArea(edge, param,basis, xyz, tolerance);
+  double delta = (edge->getUpperBound() - edge->getLowerBound()) * 1e-8;
+  for (size_t i = 0; i < xyz.size(); ++i) {
+    if (!onEdge[i]) {
+      grad[i] = 0;
+      continue;
+    }
+    double p = param[i];
+    double delta = 1e-6;
+    param[i] += delta;
+    xyz[i] = SPoint3(edge->position(param[i]));
+    if (tolerance > 0) grad[i] = (computeBndDistG(edge, param,basis, xyz,tolerance) - ref) / delta;
+    else grad[i] = (computeDeviationOfTangents(edge, param,basis, xyz) - ref) / delta;
+    param[i] = p;
+    xyz[i] = SPoint3(edge->position(param[i]));
+  }
+  return ref;
+}
+
+#include "MElement.h"
+#include "MVertex.h"
+#include "BasisFactory.h"
+double computeBndDist(MElement *element, int distanceDefinition, double tolerance)
+{
+  double dist = 0;
+  const nodalBasis &elbasis = *element->getFunctionSpace();
+  for (int iEdge = 0; iEdge < element->getNumEdges(); ++iEdge) {
+    int clId = elbasis.getClosureId(iEdge, 1);
+    const std::vector<int> &closure = elbasis.closures[clId];
+    std::vector<SPoint3> xyz;
+    GEdge *edge = NULL;
+    std::vector<MVertex *> vertices (closure.size());
+    for (size_t i = 0; i < closure.size(); ++i) {
+      MVertex *v = element->getVertex(closure[i]);
+      vertices[i] = v;
+      xyz.push_back(v->point());
+      if ((int)i >= 2  && v->onWhat() && v->onWhat()->dim() == 1) {
+        edge = v->onWhat()->cast2Edge();
+      }
+    }
+    if (edge){
+      std::vector<double> params(closure.size());
+      for (size_t i = 0; i < closure.size(); ++i) {
+	reparamMeshVertexOnEdge(element->getVertex(closure[i]), edge, params[i]);
+      }
+      if (distanceDefinition == 1)
+	dist = std::max(computeBndDistH(edge, params, vertices, *BasisFactory::getNodalBasis(elbasis.getClosureType(clId)), xyz,tolerance),dist);
+      else if (distanceDefinition == 2)
+	dist = std::max(computeBndDistG(edge, params, *BasisFactory::getNodalBasis(elbasis.getClosureType(clId)), xyz, tolerance),dist);
+      else if (distanceDefinition == 4)
+	dist = std::max(computeBndDistF(edge, params, *BasisFactory::getNodalBasis(elbasis.getClosureType(clId)), xyz, tolerance),dist);
+      else if (distanceDefinition == 5)
+	dist = std::max(computeBndDistAccurateArea(edge, params,*BasisFactory::getNodalBasis(elbasis.getClosureType(clId)), xyz, tolerance),dist);
+      else if (distanceDefinition == 6)
+	dist = std::max(computeDeviationOfTangents(edge, params,*BasisFactory::getNodalBasis(elbasis.getClosureType(clId)), xyz),dist);
+      else
+	Msg::Fatal("unknown distance definition %d. Choose 1 for Hausdorff and 2 for Area/Length 4 for Discrete Frechet",distanceDefinition);
+    }
+  }
+  return dist;
+}
diff --git a/contrib/HighOrderMeshOptimizer/OptHomIntegralBoundaryDist.h b/contrib/HighOrderMeshOptimizer/OptHomIntegralBoundaryDist.h
new file mode 100644
index 0000000..3a9e5db
--- /dev/null
+++ b/contrib/HighOrderMeshOptimizer/OptHomIntegralBoundaryDist.h
@@ -0,0 +1,55 @@
+#ifndef OPT_HOM_INTEGRAL_BOUNDARY_DIST_H
+#define OPT_HOM_INTEGRAL_BOUNDARY_DIST_H
+#include <vector>
+class GEdge;
+class nodalBasis;
+class SPoint3;
+class MElement;
+class MVertex;
+double computeBndDist(MElement *element, int distanceDefinition, double tolerance);
+double computeBndDistAndGradient(GEdge *edge,
+				 std::vector<double> &param,
+				 const std::vector<MVertex*> &vs,
+				 const nodalBasis &basis, std::vector<SPoint3> &xyz,
+				 std::vector<bool> &onEdge, std::vector<double> &grad, double tolerance);
+
+class parametricLine {
+ public :
+  virtual SPoint3 operator()(double xi) const = 0;
+  virtual SVector3 derivative(double xi) const = 0;
+  virtual SVector3 secondDerivative(double xi) const = 0;
+  SVector3 curvature(double xi) const;
+  void discretize(std::vector<SPoint3> &dpts,std::vector<double> &ts,double Prec,
+		  double t0 = 0.0, double t1 = 1.0) const;
+  void recur_discretize(const double &t1, const double &t2,
+			const SPoint3 &p1, const SPoint3 &p2,
+			std::vector<SPoint3> &dpts,
+			std::vector<double> &ts,
+			double Prec, int depth) const;
+  double frechetDistance(const parametricLine &l, SPoint3 &p1, SPoint3 &p2, double tol = 1.e-6) const;
+  double hausdorffDistance(const parametricLine &l, SPoint3 &p1, SPoint3 &p2, double tol = 1.e-6) const;
+};
+
+class parametricLineNodalBasis : public parametricLine
+{
+  const nodalBasis &_basis;
+  const std::vector<SPoint3> &_xyz;
+ public :
+  parametricLineNodalBasis(const nodalBasis &basis, const std::vector<SPoint3> &xyz);
+  virtual SPoint3 operator()(double xi) const;
+  virtual SVector3 derivative(double xi) const;
+  virtual SVector3 secondDerivative(double xi) const;
+};
+
+class parametricLineGEdge : public parametricLine
+{
+  const GEdge *_edge;
+  double _t0, _t1;
+  public :
+  parametricLineGEdge(const GEdge *edge, double t0, double t1);
+  virtual SPoint3 operator()(double xi) const;
+  virtual SVector3 derivative(double xi) const;
+  virtual SVector3 secondDerivative(double xi) const;
+};
+
+#endif
diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
index e8cdf9d..5c7614c 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.cpp
@@ -34,6 +34,8 @@
 #include "MTetrahedron.h"
 #include "ParamCoord.h"
 #include "OptHomMesh.h"
+#include "BasisFactory.h"
+#include "OptHomIntegralBoundaryDist.h"
 
 Mesh::Mesh(const std::map<MElement*,GEntity*> &element2entity,
            const std::set<MElement*> &els, std::set<MVertex*> &toFix,
@@ -108,7 +110,7 @@ Mesh::Mesh(const std::map<MElement*,GEntity*> &element2entity,
     _invStraightJac.resize(nEl(),1.);
     double dumJac[3][3];
     for (int iEl = 0; iEl < nEl(); iEl++)
-      _invStraightJac[iEl] = 1. / _el[iEl]->getPrimaryJacobian(0.,0.,0.,dumJac);
+      _invStraightJac[iEl] = 1. / fabs(_el[iEl]->getPrimaryJacobian(0.,0.,0.,dumJac));
   }
 
 }
@@ -222,6 +224,12 @@ void Mesh::elSizeSq(std::vector<double> &sSq)
   }
 }
 
+void Mesh::elInSize(std::vector<double> &s)
+{
+  for (int iEl = 0; iEl < nEl(); iEl++)
+    s[iEl] = fabs(_el[iEl]->getInnerRadius());
+}
+
 void Mesh::updateGEntityPositions()
 {
   for (int iV = 0; iV < nVert(); iV++)
@@ -286,6 +294,66 @@ void Mesh::metricMinAndGradients(int iEl, std::vector<double> &lambda,
   }
 }
 
+bool Mesh::bndDistAndGradients(int iEl, double &f , std::vector<double> &gradF, double eps)
+{
+  MElement *element = _el[iEl];
+  f = 0.;
+  // dommage ;-)
+  if (element->getDim() != 2)
+    return false;
+
+  int currentId = 0;
+  std::vector<int> vertex2param(element->getNumVertices());
+  for (size_t i = 0; i < element->getNumVertices(); ++i) {
+    if (_el2FV[iEl][i] >= 0) {
+      vertex2param[i] = currentId;
+      currentId += _nPCFV[_el2FV[iEl][i]];
+    }
+    else
+      vertex2param[i] = -1;
+  }
+  gradF.clear();
+  gradF.resize(currentId, 0.);
+
+  const nodalBasis &elbasis = *element->getFunctionSpace();
+  bool edgeFound = false;
+  for (int iEdge = 0; iEdge < element->getNumEdges(); ++iEdge) {
+    int clId = elbasis.getClosureId(iEdge, 1);
+    const std::vector<int> &closure = elbasis.closures[clId];
+    std::vector<MVertex *> vertices;
+    GEdge *edge = NULL;
+    for (size_t i = 0; i < closure.size(); ++i) {
+      MVertex *v = element->getVertex(closure[i]);
+      vertices.push_back(v);
+      // only valid in 2D
+      if ((int)i >= 2 && v->onWhat() && v->onWhat()->dim() == 1) {
+        edge = v->onWhat()->cast2Edge();
+      }
+    }
+    if (edge) {
+      edgeFound = true;
+      std::vector<double> localgrad;
+      std::vector<SPoint3> nodes(closure.size());
+      std::vector<double> params(closure.size());
+      std::vector<bool> onedge(closure.size());
+      for (size_t i = 0; i < closure.size(); ++i) {
+        nodes[i] = _xyz[_el2V[iEl][closure[i]]];
+        onedge[i] = element->getVertex(closure[i])->onWhat() == edge && _el2FV[iEl][closure[i]] >= 0;
+        if (onedge[i]) {
+          params[i] = _uvw[_el2FV[iEl][closure[i]]].x();
+        }else
+          reparamMeshVertexOnEdge(element->getVertex(closure[i]), edge, params[i]);
+      }
+      f += computeBndDistAndGradient(edge, params, vertices, *BasisFactory::getNodalBasis(elbasis.getClosureType(clId)), nodes, onedge, localgrad, eps);
+      for (size_t i = 0; i < closure.size(); ++i) {
+        if (onedge[i])
+	  gradF[vertex2param[closure[i]]] += localgrad[i];
+      }
+    }
+  }
+  return edgeFound;
+}
+
 void Mesh::scaledJacAndGradients(int iEl, std::vector<double> &sJ,
                                  std::vector<double> &gSJ)
 {
@@ -374,7 +442,7 @@ void Mesh::writeMSH(const char *filename)
   fprintf(f, "$Elements\n");
   fprintf(f, "%d\n", nEl());
   for (int iEl = 0; iEl < nEl(); iEl++) {
-    fprintf(f, "%d %d 2 0 0", iEl+1, _el[iEl]->getTypeForMSH());
+    fprintf(f, "%d %d 2 0 0", _el[iEl]->getNum(), _el[iEl]->getTypeForMSH());
     for (size_t iVEl = 0; iVEl < _el2V[iEl].size(); iVEl++)
       fprintf(f, " %d", _el2V[iEl][iVEl] + 1);
     fprintf(f, "\n");
diff --git a/contrib/HighOrderMeshOptimizer/OptHomMesh.h b/contrib/HighOrderMeshOptimizer/OptHomMesh.h
index ea54b5b..f1f48c9 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomMesh.h
+++ b/contrib/HighOrderMeshOptimizer/OptHomMesh.h
@@ -57,6 +57,7 @@ public:
 
   void metricMinAndGradients(int iEl, std::vector<double> &sJ, std::vector<double> &gSJ);
   void scaledJacAndGradients(int iEl, std::vector<double> &sJ, std::vector<double> &gSJ);
+  bool bndDistAndGradients(int iEl, double &f , std::vector<double> &gradF, double eps);
   inline int indGSJ(int iEl, int l, int iPC) { return iPC*_nBezEl[iEl]+l; }
 
   inline double distSq(int iFV);
@@ -69,6 +70,7 @@ public:
   void updateMesh(const double *it);
   void distSqToStraight(std::vector<double> &dSq);
   void elSizeSq(std::vector<double> &sSq);
+  void elInSize(std::vector<double> &s);
 
   void updateGEntityPositions();
   void writeMSH(const char *filename);
diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
index b5f5d61..f99522a 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomRun.cpp
@@ -47,6 +47,35 @@
 
 #if defined(HAVE_BFGS)
 
+double distMaxStraight(MElement *el)
+{
+  const polynomialBasis *lagrange = (polynomialBasis*)el->getFunctionSpace();
+  const polynomialBasis *lagrange1 = (polynomialBasis*)el->getFunctionSpace(1);
+  int nV = lagrange->points.size1();
+  int nV1 = lagrange1->points.size1();
+  int dim = lagrange1->dimension;
+  SPoint3 sxyz[256];
+  for (int i = 0; i < nV1; ++i) {
+    sxyz[i] = el->getVertex(i)->point();
+  }
+  for (int i = nV1; i < nV; ++i) {
+    double f[256];
+    lagrange1->f(lagrange->points(i, 0), lagrange->points(i, 1),
+                 dim < 3 ? 0 : lagrange->points(i, 2), f);
+    for (int j = 0; j < nV1; ++j)
+      sxyz[i] += sxyz[j] * f[j];
+  }
+
+  double maxdx = 0.0;
+  for (int iV = nV1; iV < nV; iV++) {
+    SVector3 d = el->getVertex(iV)->point()-sxyz[iV];
+    double dx = d.norm();
+    if (dx > maxdx) maxdx = dx;
+  }
+
+  return maxdx;
+}
+
 void exportMeshToDassault(GModel *gm, const std::string &fn, int dim)
 {
   FILE *f = fopen(fn.c_str(),"w");
@@ -129,13 +158,50 @@ static std::set<MVertex *> getAllBndVertices
   return bnd;
 }
 
+// Approximate test of intersection element with circle/sphere by sampling
+static bool testElInDist(const SPoint3 p, double limDist, MElement *el)
+{
+  const double sampleLen = 0.5*limDist;                                   // Distance between sample points
+
+  if (el->getDim() == 2) {                                                // 2D?
+    for (int iEd = 0; iEd < el->getNumEdges(); iEd++) {                   // Loop over edges of element
+      MEdge ed = el->getEdge(iEd);
+      const int nPts = int(ed.length()/sampleLen)+2;                      // Nb of sample points based on edge length
+      for (int iPt = 0; iPt < nPts; iPt++) {                              // Loop over sample points
+        const SPoint3 pt = ed.interpolate(iPt/float(nPts-1));
+        if (p.distance(pt) < limDist) return true;
+      }
+    }
+  }
+  else {                                                                  // 3D
+    for (int iFace = 0; iFace < el->getNumFaces(); iFace++) {             // Loop over faces of element
+      MFace face = el->getFace(iFace);
+      double lMax = 0.;                                                   // Max. edge length in face
+      const int nVert = face.getNumVertices();
+      for (int iEd = 0; iEd < nVert; iEd++)
+        lMax = std::max(lMax, face.getEdge(iEd).length());
+      const int nPts = int(lMax/sampleLen)+2;                             // Nb of sample points based on max. edge length in face
+      for (int iPt0 = 0; iPt0 < nPts; iPt0++) {
+        const double u = iPt0/float(nPts-1);
+        for (int iPt1 = 0; iPt1 < nPts; iPt1++) {                         // Loop over sample points
+          const double vMax = (nVert == 3) ? 1.-u : 1.;
+          const SPoint3 pt = face.interpolate(u, vMax*iPt1/float(nPts-1));
+          if (p.distance(pt) < limDist) return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
 static std::set<MElement*> getSurroundingBlob
    (MElement *el, int depth,
     const std::map<MVertex*, std::vector<MElement*> > &vertex2elements,
     const double distFactor, int forceDepth, bool optPrimSurfMesh)
 {
 
-  const SPoint3 p = el->barycenter();
+  const SPoint3 p = el->barycenter(true);
   const double dist = el->maxDistToStraight();
   const double limDist = ((optPrimSurfMesh && (dist < 1.e-10)) ?
                           el->getOuterRadius() : dist) * distFactor;
@@ -154,8 +220,8 @@ static std::set<MElement*> getSurroundingBlob
           ((*it)->getVertex(i))->second;
         for (std::vector<MElement*>::const_iterator itN = neighbours.begin();
              itN != neighbours.end(); ++itN){
-          if ((d < forceDepth) || (p.distance((*itN)->barycenter_infty()) < limDist)){
-            // Assume that if an el is too far, its neighbours are too far as wella
+          if ((d < forceDepth) || testElInDist(p, limDist, *itN)){
+            // Assume that if an el is too far, its neighbours are too far as well
             if (blob.insert(*itN).second) currentLayer.push_back(*itN);
           }
         }
@@ -212,7 +278,8 @@ static std::vector<std::pair<std::set<MElement*>, std::set<MVertex*> > > getConn
   std::vector<std::set<MElement*> > primBlobs;
   primBlobs.reserve(badElements.size());
   for (std::set<MElement*>::const_iterator it = badElements.begin(); it != badElements.end(); ++it) {
-    const int minLayers = ((*it)->getDim() == 3) ? 1 : 0;
+    //const int minLayers = ((*it)->getDim() == 3) ? 1 : 0;
+    const int minLayers = 3;
     primBlobs.push_back(getSurroundingBlob(*it, depth, vertex2elements,
                                 distFactor, minLayers, optPrimSurfMesh));
   }
@@ -287,23 +354,24 @@ static void optimizeConnectedBlobs
 
   //#pragma omp parallel for schedule(dynamic, 1)
   for (int i = 0; i < toOptimize.size(); ++i) {
+//    if (toOptimize[i].first.size() > 10000) continue;
     Msg::Info("Optimizing a blob %i/%i composed of %4d elements", i+1,
               toOptimize.size(), toOptimize[i].first.size());
     fflush(stdout);
     OptHOM temp(element2entity, toOptimize[i].first, toOptimize[i].second, p.fixBndNodes);
-    //std::ostringstream ossI1;
-    //ossI1 << "initial_ITER_" << i << ".msh";
-    //temp.mesh.writeMSH(ossI1.str().c_str());
+    std::ostringstream ossI1;
+    ossI1 << "initial_blob-" << i << ".msh";
+    temp.mesh.writeMSH(ossI1.str().c_str());
     int success = -1;
     if (temp.mesh.nPC() == 0)
       Msg::Info("Blob %i has no degree of freedom, skipping", i+1);
     else
-      success = temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN,
-                              p.BARRIER_MAX, false, samples, p.itMax, p.optPassMax);
+      success = temp.optimize(p.weightFixed, p.weightFree, p.optCADWeight, p.BARRIER_MIN,
+                              p.BARRIER_MAX, false, samples, p.itMax, p.optPassMax, p.optCAD, p.optCADDistMax, p.discrTolerance);
     if (success >= 0 && p.BARRIER_MIN_METRIC > 0) {
       Msg::Info("Jacobian optimization succeed, starting svd optimization");
-      success = temp.optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN_METRIC, p.BARRIER_MAX,
-                              true, samples, p.itMax, p.optPassMax);
+      success = temp.optimize(p.weightFixed, p.weightFree, p.optCADWeight, p.BARRIER_MIN_METRIC, p.BARRIER_MAX,
+                              true, samples, p.itMax, p.optPassMax, p.optCAD, p.optCADDistMax,p.discrTolerance);
     }
     double minJac, maxJac, distMaxBND, distAvgBND;
     temp.recalcJacDist();
@@ -311,11 +379,11 @@ static void optimizeConnectedBlobs
     p.minJac = std::min(p.minJac,minJac);
     p.maxJac = std::max(p.maxJac,maxJac);
     temp.mesh.updateGEntityPositions();
-    if (success <= 0) {
+    //if (success <= 0) {
       std::ostringstream ossI2;
       ossI2 << "final_ITER_" << i << ".msh";
       temp.mesh.writeMSH(ossI2.str().c_str());
-    }
+    //}
     //#pragma omp critical
     p.SUCCESS = std::min(p.SUCCESS, success);
   }
@@ -383,7 +451,7 @@ static std::set<MElement*> getSurroundingBlob3D
         for (std::vector<MElement*>::const_iterator itN = neighbours.begin();
              itN != neighbours.end(); ++itN) {
           // Check distance from all seed points
-          SPoint3 pt = (*itN)->barycenter_infty();
+          SPoint3 pt = (*itN)->barycenter();
           bool nearSeed = false;
           for (std::list<SPoint3>::const_iterator itS = seedPts.begin();
                itS != seedPts.end(); ++itS)
@@ -537,15 +605,15 @@ static void optimizeOneByOne
                 toOptimize.size());
       fflush(stdout);
       OptHOM *opt = new OptHOM(element2entity, toOptimize, toFix, p.fixBndNodes);
-      //std::ostringstream ossI1;
-      //ossI1 << "initial_corrective_" << iter << ".msh";
-      //opt->mesh.writeMSH(ossI1.str().c_str());
-      success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN,
-                              p.BARRIER_MAX, false, samples, p.itMax, p.optPassMax);
+      std::ostringstream ossI1;
+      ossI1 << "initial_blob-" << iBadEl << ".msh";
+      opt->mesh.writeMSH(ossI1.str().c_str());
+      success = opt->optimize(p.weightFixed, p.weightFree, p.optCADWeight, p.BARRIER_MIN,
+                              p.BARRIER_MAX, false, samples, p.itMax, p.optPassMax, p.optCAD, p.optCADDistMax,p.discrTolerance);
       if (success >= 0 && p.BARRIER_MIN_METRIC > 0) {
         Msg::Info("Jacobian optimization succeed, starting svd optimization");
-        success = opt->optimize(p.weightFixed, p.weightFree, p.BARRIER_MIN_METRIC,
-                                p.BARRIER_MAX, true, samples, p.itMax, p.optPassMax);
+        success = opt->optimize(p.weightFixed, p.weightFree, p.optCADWeight, p.BARRIER_MIN_METRIC,
+                                p.BARRIER_MAX, true, samples, p.itMax, p.optPassMax, p.optCAD, p.optCADDistMax,p.discrTolerance);
       }
 
       // Measure min and max Jac., update mesh
@@ -568,7 +636,7 @@ static void optimizeOneByOne
                   iBadEl, iterBlob);
 //        if (iterBlob == p.maxAdaptBlob-1) {
           std::ostringstream ossI2;
-          ossI2 << "final_" << iBadEl << ".msh";
+          ossI2 << "final_blob-" << iBadEl << ".msh";
           opt->mesh.writeMSH(ossI2.str().c_str());
 //        }
       }
@@ -584,6 +652,28 @@ static void optimizeOneByOne
 
 #endif
 
+#include "OptHomIntegralBoundaryDist.h"
+double ComputeDistanceToGeometry (GEntity *ge , int distanceDefinition, double tolerance)
+{
+  double maxd = 0.0;
+  double sum = 0.0;
+  int NUM = 0;
+  for (int iEl = 0; iEl < ge->getNumMeshElements();iEl++) {
+    MElement *el = ge->getMeshElement(iEl);
+    if (ge->dim() == el->getDim()){
+      const double DISTE =computeBndDist(el,distanceDefinition, tolerance);
+      if (DISTE != 0.0){
+	NUM++;
+	//	if(distanceDefinition == 1)printf("%d %12.5E\n",iEl,DISTE);
+	maxd = std::max(maxd,DISTE);
+	sum += DISTE;
+      }
+    }
+  }
+  if (distanceDefinition == 2 && NUM) return sum / (double)NUM;
+  return maxd;
+}
+
 void HighOrderMeshOptimizer(GModel *gm, OptHomParameters &p)
 {
 #if defined(HAVE_BFGS)
@@ -600,6 +690,7 @@ void HighOrderMeshOptimizer(GModel *gm, OptHomParameters &p)
   std::map<MVertex*, std::vector<MElement *> > vertex2elements;
   std::map<MElement*,GEntity*> element2entity;
   std::set<MElement*> badasses;
+  double maxdist = 0;
   for (int iEnt = 0; iEnt < entities.size(); ++iEnt) {
     GEntity* &entity = entities[iEnt];
     if (entity->dim() != p.dim || (p.onlyVisible && !entity->getVisibility())) continue;
@@ -610,13 +701,22 @@ void HighOrderMeshOptimizer(GModel *gm, OptHomParameters &p)
     for (int iEl = 0; iEl < entity->getNumMeshElements();iEl++) { // Detect bad elements
       double jmin, jmax;
       MElement *el = entity->getMeshElement(iEl);
+      const double DISTE =computeBndDist(el,2,fabs(p.discrTolerance));
+      //      printf("Element %d Distance %12.5E\n",iEl,DISTE);
+      maxdist = std::max(DISTE, maxdist);
       if (el->getDim() == p.dim) {
-        el->scaledJacRange(jmin, jmax, p.optPrimSurfMesh ? entity : 0);
-        if (p.BARRIER_MIN_METRIC > 0) jmax = jmin;
-        if (jmin < p.BARRIER_MIN || jmax > p.BARRIER_MAX) badasses.insert(el);
+	if (p.optCAD && DISTE > p.optCADDistMax)
+	  badasses.insert(el);
+
+	el->scaledJacRange(jmin, jmax, p.optPrimSurfMesh ? entity : 0);
+	if (p.BARRIER_MIN_METRIC > 0) jmax = jmin;
+	if (jmin < p.BARRIER_MIN || jmax > p.BARRIER_MAX){
+	  badasses.insert(el);
+        }
       }
     }
   }
+  printf("maxdist = %g badasses size = %lu\n", maxdist, badasses.size());
 
   if (p.strategy == 0)
     optimizeConnectedBlobs(vertex2elements, element2entity, badasses, p, samples, false);
diff --git a/contrib/HighOrderMeshOptimizer/OptHomRun.h b/contrib/HighOrderMeshOptimizer/OptHomRun.h
index e934f01..f1d172f 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomRun.h
+++ b/contrib/HighOrderMeshOptimizer/OptHomRun.h
@@ -54,6 +54,10 @@ struct OptHomParameters {
   int adaptBlobLayerFact; // Growth factor in number of layers for blob adaptation
   double adaptBlobDistFact; // Growth factor in distance factor for blob adaptation
   bool optPrimSurfMesh; // Enable optimisation of p1 surface meshes
+  bool optCAD;//Enable optimization of mesh vertices positions for geometrical fitting
+  double optCADWeight;//Weight
+  double optCADDistMax;//Maximum allowed distance from the CAD
+  double discrTolerance;
 
   // OUTPUT ------>
   int SUCCESS ; // 0 --> success , 1 --> Not converged
@@ -64,11 +68,14 @@ struct OptHomParameters {
     : BARRIER_MIN_METRIC(-1.), BARRIER_MIN(0.1), BARRIER_MAX(2.0), weightFixed(1000.),
       weightFree (1.), nbLayers (6) , dim(3) , itMax(300), onlyVisible(true),
       distanceFactor(12), fixBndNodes(false), strategy(0), maxAdaptBlob(3),
-      adaptBlobLayerFact(2.), adaptBlobDistFact(2.), optPrimSurfMesh(false)
+      adaptBlobLayerFact(2.), adaptBlobDistFact(2.), optPrimSurfMesh(false),optCAD(false),
+      optCADWeight(1000.),optCADDistMax(1.e22),discrTolerance(1.e-4)
   {
   }
 };
 
 void HighOrderMeshOptimizer(GModel *gm, OptHomParameters &p);
+// distanceDefinition 1) Hausdorff 2) Area/Length 3) Frechet (not done)
+double ComputeDistanceToGeometry (GEntity *ge , int distanceDefinition,double tolerance) ;
 
 #endif
diff --git a/contrib/HighOrderMeshOptimizer/ParamCoord.cpp b/contrib/HighOrderMeshOptimizer/ParamCoord.cpp
index 97ce05e..88125af 100644
--- a/contrib/HighOrderMeshOptimizer/ParamCoord.cpp
+++ b/contrib/HighOrderMeshOptimizer/ParamCoord.cpp
@@ -57,6 +57,7 @@ SPoint3 ParamCoordParent::getUvw(MVertex* vert)
     break;
   }
   }
+  return SPoint3(0.,0.,0.);
 }
 
 SPoint3 ParamCoordParent::uvw2Xyz(const SPoint3 &uvw)
diff --git a/contrib/HighOrderMeshOptimizer/SuperEl.cpp b/contrib/HighOrderMeshOptimizer/SuperEl.cpp
index d564553..d7ec149 100644
--- a/contrib/HighOrderMeshOptimizer/SuperEl.cpp
+++ b/contrib/HighOrderMeshOptimizer/SuperEl.cpp
@@ -29,233 +29,174 @@
 
 #include <iostream>
 #include <sstream>
+#include "GmshMessage.h"
 #include "GEdge.h"
 #include "MLine.h"
 #include "MQuadrangle.h"
 #include "MPrism.h"
 #include "MHexahedron.h"
+#include "BasisFactory.h"
 #include "SuperEl.h"
 
+std::map<int,SuperEl::superInfoType> SuperEl::_superInfo;
 
-
-SuperEl::SuperEl(int order, double dist, int type, const std::vector<MVertex*> &baseVert,
-                 const std::vector<SVector3> &normals) {
-
-//  std::cout << "DBGTT: badEl = " << badEl->getNum() << ", _superEl = " << _superEl << std::endl;
-
+SuperEl::superInfoType::superInfoType(int type, int order)
+{
+  int iBaseFace = 0, iTopFace = 0;
   switch (type) {
-    case TYPE_LIN:
-      createSuperElQuad(order, dist, baseVert, normals[0], normals[1]);
+    case TYPE_QUA:
+      iBaseFace = 0; iTopFace = 2;
       break;
-    case TYPE_TRI:
-      createSuperElPrism(order, dist, baseVert, normals[0], normals[1], normals[2]);
+    case TYPE_PRI:
+      iBaseFace = 0; iTopFace = 1;
       break;
-    case TYPE_QUA:
-      createSuperElHex(order, dist, baseVert, normals[0], normals[1], normals[2], normals[3]);
+    case TYPE_HEX:
+      iBaseFace = 0; iTopFace = 5;
       break;
     default:
-      std::cout << "ERROR: SuperEl not implemented for element of type " << type << std::endl;
-      _superEl = 0;
-      break;
+      Msg::Error("SuperEl not implemented for element of type %d", type);
+      nV = 0;
+      return;
   }
 
-  if (!_superEl) std::cout << "ERROR: SuperEl not created" << std::endl;
-
+  // Get HO nodal basis
+  const int tag = ElementType::getTag(type, order, true);                 // Get tag for incomplete element type
+//  const int tag = ElementType::getTag(type, order);                     // Get tag for complete element type
+  if(tag){
+    const nodalBasis *basis = BasisFactory::getNodalBasis(tag);
+
+    nV = basis->getNumShapeFunctions();
+    //  _superInfo[type].nV1 = basis->getNumShapeFunctions();
+    points = basis->points;
+
+    baseInd = basis->getClosure(basis->getClosureId(iBaseFace,1,0));
+    topInd = basis->getClosure(basis->getClosureId(iTopFace,0,0));
+    otherInd.reserve(nV-baseInd.size()-topInd.size());
+    for(int i=0; i<nV; ++i) {
+      const std::vector<int>::iterator inBaseFace = find(baseInd.begin(),baseInd.end(),i);
+      const std::vector<int>::iterator inTopFace = find(topInd.begin(),topInd.end(),i);
+      if (inBaseFace == baseInd.end() && inTopFace == topInd.end()) otherInd.push_back(i);
+    }
+  }
 }
 
 
 
-void SuperEl::createSuperElQuad(int order, double dist, const std::vector<MVertex*> &baseVert,
-                                  const SVector3 &n0, const SVector3 &n1) {
+SuperEl::SuperEl(int type, int order, const std::vector<MVertex*> &baseVert,
+                 const std::vector<MVertex*> &topPrimVert) : _superEl(0), _superEl0(0)
+{
 
+  // Get useful info on meta-element type if not already there
+  std::map<int,SuperEl::superInfoType>::iterator itSInfo = _superInfo.find(type);
+  if (itSInfo == _superInfo.end())
+    itSInfo = _superInfo.insert(std::pair<int,superInfoType>(type,superInfoType(type, order))).first;
+  SuperEl::superInfoType &sInfo = itSInfo->second;
 
-  if (baseVert.empty()) {
-    std::cout << "ERROR: Base edge not given for SuperEl\n";
-    _superEl = 0;
-    return;
-  }
+  // Exit if unknown type
+  if (sInfo.nV == 0) return;
 
-  // First-order vertices for super-element
-  MVertex *v0 = new MVertex(*baseVert[0]);
-  MVertex *v1 = new MVertex(*baseVert[1]);
-//  double dist = distFactor*distMaxStraight(badEl);
-  double v2x = v1->x()+n1.x()*dist, v2y = v1->y()+n1.y()*dist;
-  MVertex *v2 = new MVertex(v2x,v2y,0.);
-  double v3x = v0->x()+n0.x()*dist, v3y = v0->y()+n0.y()*dist;
-  MVertex *v3 = new MVertex(v3x,v3y,0.);
-//  std::cout << "DBGTT: createSuperElQuad: v0 = (" << v0->x() << "," << v0->y()
-//              << "), v1 = (" << v1->x() << "," << v1->y()
-//              << "), v2 = (" << v2->x() << "," << v2->y()
-//              << "), v3 = (" << v3->x() << "," << v3->y() << ")" << std::endl;
+  // References for easier writing
+  const int &nV = sInfo.nV;
+  const fullMatrix<double> &points = sInfo.points;
+  const std::vector<int> &baseInd = sInfo.baseInd;
+  const std::vector<int> &topInd = sInfo.topInd;
+  const std::vector<int> &otherInd = sInfo.otherInd;
 
-  // Get basis functions
-  MQuadrangle quad1(v0,v1,v2,v3);
-  const nodalBasis *quadBasis = quad1.getFunctionSpace(order);
-  const int Nv = quadBasis->getNumShapeFunctions();
+  // Add copies of vertices in base & top faces (only first-order vertices for top face)
+  _superVert.resize(nV);
+  for (int i=0; i<baseInd.size(); ++i) _superVert[baseInd[i]] = new MVertex(*baseVert[i]);
+  for (int i=0; i<topPrimVert.size(); ++i) _superVert[topInd[i]] = new MVertex(*topPrimVert[i]);
 
-  // Store/create all vertices for super-element
-  _superVert.resize(Nv);
-  _superVert[0] = v0;                                                     // First-order vertices
-  _superVert[1] = v1;
-  _superVert[2] = v2;
-  _superVert[3] = v3;
-  for (int i=2; i<order+1; ++i) _superVert[2+i] = new MVertex(*baseVert[i]);  // HO vertices on base edge
-  for (int i=3+order; i<Nv; ++i) {                                            // Additional HO vertices
-    SPoint3 p;
-    quad1.pnt(quadBasis->points(i,0),quadBasis->points(i,1),0.,p);
-    _superVert[i] = new MVertex(p.x(),p.y(),0.);
-//    std::cout << "DBGTT: createSuperElQuad: add vertex (" << _superVert[i]->x()
-//                << "," << _superVert[i]->y()<< "," << _superVert[i]->z() << ")" << std::endl;
+  // Create first-order meta-element
+  switch (type) {
+    case TYPE_QUA:
+      _superEl0 = new MQuadrangle(_superVert);
+      break;
+    case TYPE_PRI:
+      _superEl0 = new MPrism(_superVert);
+      break;
+    case TYPE_HEX:
+      _superEl0 = new MHexahedron(_superVert);
+      break;
+    default:
+      Msg::Error("SuperEl not implemented for element of type %d", type);
+      return;
   }
 
-  _superEl = new MQuadrangleN(_superVert,order);
-  _superEl0 = new MQuadrangle(_superVert[0],_superVert[1],_superVert[2],_superVert[3]);
-//  std::cout << "Created SuperEl at address " << _superEl << std::endl;
-
-}
-
-
-
-void SuperEl::createSuperElPrism(int order, double dist, const std::vector<MVertex*> &baseVert,
-                                 const SVector3 &n0, const SVector3 &n1, const SVector3 &n2) {
-
-
-  if (baseVert.empty()) {
-    std::cout << "ERROR: Base edge not given for SuperEl\n";
-    _superEl = 0;
-    return;
+  // Add HO vertices in top face
+  for (int i=topPrimVert.size(); i<topInd.size(); ++i) {
+    SPoint3 p;
+    const int ind = topInd[i];
+    _superEl0->pnt(points(ind,0),points(ind,1),points(ind,2),p);
+    _superVert[ind] = new MVertex(p.x(),p.y(),p.z());
   }
 
-  // First-order vertices for super-element
-  MVertex *v0 = new MVertex(*baseVert[0]);
-  MVertex *v1 = new MVertex(*baseVert[1]);
-  MVertex *v2 = new MVertex(*baseVert[2]);
-  double v3x = v0->x()+n0.x()*dist, v3y = v0->y()+n0.y()*dist,  v3z = v0->z()+n0.z()*dist;
-  MVertex *v3 = new MVertex(v3x,v3y,v3z);
-  double v4x = v1->x()+n1.x()*dist, v4y = v1->y()+n1.y()*dist,  v4z = v1->z()+n1.z()*dist;
-  MVertex *v4 = new MVertex(v4x,v4y,v4z);
-  double v5x = v2->x()+n2.x()*dist, v5y = v2->y()+n2.y()*dist,  v5z = v2->z()+n2.z()*dist;
-  MVertex *v5 = new MVertex(v5x,v5y,v5z);
-
-  // Get basis functions
-  MPrism prism1(v0,v1,v2,v3,v4,v5);
-  const nodalBasis *prismBasis = prism1.getFunctionSpace(order);
-  const int Nv = prismBasis->getNumShapeFunctions();                        // Number of vertices in HO prism
-
-  // Store/create all vertices for super-element
-  if (order == 2) {
-    _superVert.resize(18);
-    _superVert[0] = v0;                                                     // First-order vertices
-    _superVert[1] = v1;
-    _superVert[2] = v2;
-    _superVert[3] = v3;
-    _superVert[4] = v4;
-    _superVert[5] = v5;
-    _superVert[6] = new MVertex(*baseVert[3]);                              // HO vertices on base face
-    _superVert[9] = new MVertex(*baseVert[4]);
-    _superVert[7] = new MVertex(*baseVert[5]);
-    const int indAddVerts[9] = {8,10,11,12,13,14,15,16,17};                 // Additional HO vertices
+  // Add vertices not in base & top faces
+  for (int i=0; i<otherInd.size(); ++i) {
     SPoint3 p;
-    for (int i=0; i<9; ++i) {
-      const int &ind = indAddVerts[i];
-      prism1.pnt(prismBasis->points(ind,0),prismBasis->points(ind,1),prismBasis->points(ind,2),p);
-      _superVert[ind] = new MVertex(p.x(),p.y(),p.z());
-    }
-    _superEl = new MPrism18(_superVert);
-  }
-  else {
-    std::cout << "ERROR: Prismatic superEl. of order " << order << " not supported\n";
-    _superEl = 0;
-    _superEl0 = 0;
-    return;
+    const int ind = otherInd[i];
+    _superEl0->pnt(points(ind,0),points(ind,1),points(ind,2),p);
+    _superVert[ind] = new MVertex(p.x(),p.y(),p.z());
   }
 
-  _superEl0 = new MPrism(_superVert[0],_superVert[1],_superVert[2],
-                         _superVert[3],_superVert[4],_superVert[5]);
-
-}
-
-
-
-void SuperEl::createSuperElHex(int order, double dist, const std::vector<MVertex*> &baseVert,
-                               const SVector3 &n0, const SVector3 &n1, const SVector3 &n2, const SVector3 &n3) {
-
-
-  if (baseVert.empty()) {
-    std::cout << "ERROR: Base edge not given for SuperEl\n";
-    _superEl = 0;
-    return;
+  // Create high-order meta-element
+  switch (type) {
+    case TYPE_QUA:
+      _superEl = new MQuadrangleN(_superVert, order);
+      break;
+    case TYPE_PRI:
+      _superEl = new MPrismN(_superVert, order);
+      break;
+    case TYPE_HEX:
+      _superEl = new MHexahedronN(_superVert, order);
+      break;
   }
 
-  // First-order vertices for super-element
-  MVertex *v0 = new MVertex(*baseVert[0]);
-  MVertex *v1 = new MVertex(*baseVert[1]);
-  MVertex *v2 = new MVertex(*baseVert[2]);
-  MVertex *v3 = new MVertex(*baseVert[3]);
-  double v4x = v0->x()+n0.x()*dist, v4y = v0->y()+n0.y()*dist,  v4z = v0->z()+n0.z()*dist;
-  MVertex *v4 = new MVertex(v4x,v4y,v4z);
-  double v5x = v1->x()+n1.x()*dist, v5y = v1->y()+n1.y()*dist,  v5z = v1->z()+n1.z()*dist;
-  MVertex *v5 = new MVertex(v5x,v5y,v5z);
-  double v6x = v2->x()+n2.x()*dist, v6y = v2->y()+n2.y()*dist,  v6z = v2->z()+n2.z()*dist;
-  MVertex *v6 = new MVertex(v6x,v6y,v6z);
-  double v7x = v3->x()+n3.x()*dist, v7y = v3->y()+n3.y()*dist,  v7z = v3->z()+n3.z()*dist;
-  MVertex *v7 = new MVertex(v7x,v7y,v7z);
-
-  // Get basis functions
-  MHexahedron *hex1 = new MHexahedron(v0,v1,v2,v3,v4,v5,v6,v7);
-  const nodalBasis *prismBasis = hex1->getFunctionSpace(order);
-  const int Nv = prismBasis->getNumShapeFunctions();                         // Number of vertices in HO hex
-
-  // Store/create all vertices for super-element
-  if (order == 2) {
-    _superVert.resize(27);
-    _superVert[0] = v0;                                                      // First-order vertices
-    _superVert[1] = v1;
-    _superVert[2] = v2;
-    _superVert[3] = v3;
-    _superVert[4] = v4;
-    _superVert[5] = v5;
-    _superVert[6] = v6;
-    _superVert[7] = v7;
-    _superVert[8] = new MVertex(*baseVert[4]);                                // HO vertices on base face
-    _superVert[11] = new MVertex(*baseVert[5]);                               // HO vertices on base face
-    _superVert[13] = new MVertex(*baseVert[6]);                               // HO vertices on base face
-    _superVert[9] = new MVertex(*baseVert[7]);
-    _superVert[20] = new MVertex(*baseVert[8]);
-    const int indAddVerts[14] = {10,12,14,15,16,17,18,19,21,22,23,24,25,26};  // Additional HO vertices
-    SPoint3 p;
-    for (int i=0; i<14; ++i) {
-      const int &ind = indAddVerts[i];
-      hex1->pnt(prismBasis->points(ind,0),prismBasis->points(ind,1),prismBasis->points(ind,2),p);
-      _superVert[ind] = new MVertex(p.x(),p.y(),p.z());
+  // Scale meta-element if not valid
+  // TODO: Scale depending on target Jmin?
+  // TODO: Could be improved by using complete meta-element and use optimization
+  for (int iter = 0; iter < 10; iter++) {
+    if (_superEl->distoShapeMeasure() > 0) break;
+    if (iter == 0) Msg::Warning("A meta-element has a negative distortion, trying to scale");
+    for (int i=0; i<topPrimVert.size(); ++i) {                                                // Move top primary vert.
+      MVertex *&vb = _superVert[baseInd[i]], *&vt = _superVert[topInd[i]];
+      SPoint3 pb = vb->point(), pt = vt->point();
+      pt += SPoint3(0.25*(pt-pb));
+      vt->setXYZ(pt.x(), pt.y(), pt.z());
+    }
+    for (int i=topPrimVert.size(); i<topInd.size(); ++i) {                                    // Recompute HO vert. in top face
+      SPoint3 p;
+      const int ind = topInd[i];
+      _superEl0->pnt(points(ind,0),points(ind,1),points(ind,2),p);
+      _superVert[ind]->setXYZ(p.x(),p.y(),p.z());
+    }
+    for (int i=0; i<otherInd.size(); ++i) {                                                   // Recompute vert. not in base & top faces
+      SPoint3 p;
+      const int ind = otherInd[i];
+      _superEl0->pnt(points(ind,0),points(ind,1),points(ind,2),p);
+      _superVert[ind]->setXYZ(p.x(),p.y(),p.z());
     }
-    _superEl = new MHexahedron27(_superVert);
-  }
-  else {
-    std::cout << "ERROR: Hex. superEl. of order " << order << " not supported\n";
-    _superEl = 0;
-    _superEl0 = 0;
-    return;
   }
 
-  _superEl0 = hex1;
-
 }
 
+SuperEl::~SuperEl()
+{
+  for (int i = 0; i < _superVert.size(); i++) delete _superVert[i];
+  _superVert.clear();
+  delete _superEl;
+  if(_superEl0) delete _superEl0;
+}
 
-
-bool SuperEl::isPointIn(const SPoint3 p) const {
-
+bool SuperEl::isPointIn(const SPoint3 p) const
+{
   double xyz[3] = {p.x(), p.y(), p.z()}, uvw[3];
   _superEl0->xyz2uvw(xyz,uvw);
   return _superEl0->isInside(uvw[0],uvw[1],uvw[2]);
-
 }
 
-
-
-bool SuperEl::straightToCurved(double *xyzS, double *xyzC) const {
-
+bool SuperEl::straightToCurved(double *xyzS, double *xyzC) const
+{
   double uvw[3];
   _superEl0->xyz2uvw(xyzS,uvw);
   if (!_superEl0->isInside(uvw[0],uvw[1],uvw[2])) return false;
@@ -267,17 +208,15 @@ bool SuperEl::straightToCurved(double *xyzS, double *xyzC) const {
   xyzC[2] = pC[2];
 
   return true;
-
 }
 
-
-
-std::string SuperEl::printPOS() {
-
+std::string SuperEl::printPOS()
+{
   std::vector<MVertex*> verts;
-  _superEl0->getVertices(verts);
-  std::string posStr(_superEl0->getStringForPOS());
-  int n = _superEl0->getNumVertices();
+  _superEl->getVertices(verts);
+//  std::string posStr = _superEl->getStringForPOS();
+  std::string posStr = _superEl0->getStringForPOS();
+  int n = (posStr[posStr.size()-1]=='2' ? _superEl : _superEl0)->getNumVertices();
 
   std::ostringstream oss;
 
@@ -286,10 +225,9 @@ std::string SuperEl::printPOS() {
     if(i) oss << ",";
     oss << _superVert[i]->x() << "," <<  _superVert[i]->y() << "," <<  _superVert[i]->z();
   }
-  oss << "){0";
-  for(int i = 0; i < n; i++) oss << ",0.";
+  oss << "){0.";
+  for(int i = 1; i < n; i++) oss << ",0.";
   oss << "};\n";
 
   return oss.str();
-
 }
diff --git a/contrib/HighOrderMeshOptimizer/SuperEl.h b/contrib/HighOrderMeshOptimizer/SuperEl.h
index 6d129bd..b360495 100644
--- a/contrib/HighOrderMeshOptimizer/SuperEl.h
+++ b/contrib/HighOrderMeshOptimizer/SuperEl.h
@@ -33,45 +33,35 @@
 #include <string>
 #include "MElement.h"
 
-
-
 class SuperEl
 {
-public:
-
-  SuperEl(int order, double dist, int type, const std::vector<MVertex*> &baseVert,
-          const std::vector<SVector3> &normals);
-  ~SuperEl() { _superVert.clear(); delete _superEl, _superEl0; }
-
+ public:
+  SuperEl(int type, int order, const std::vector<MVertex*> &baseVert,
+          const std::vector<MVertex*> &topPrimVert);
+  ~SuperEl();
   bool isOK() const { return _superEl; }
   bool isPointIn(const SPoint3 p) const;
   bool straightToCurved(double *xyzS, double *xyzC) const;
-
   std::string printPOS();
-
-  void printCoord() {
+  void printCoord()
+  {
     std::cout << "DBGTT: superEl -> ";
     for(int i = 0; i < _superVert.size(); i++){
-      std::cout << "v" << i << " = (" << _superVert[i]->x() << "," <<  _superVert[i]->y() << "," <<  _superVert[i]->z() << ")";
+      std::cout << "v" << i << " = (" << _superVert[i]->x() << ","
+                <<  _superVert[i]->y() << "," <<  _superVert[i]->z() << ")";
       if (i == _superVert.size()-1) std::cout << "\n"; else std::cout << ", ";
     }
-
   }
-
-private:
-
+ private:
+  struct superInfoType {
+    int nV;
+    fullMatrix<double> points;
+    std::vector<int> baseInd, topInd, otherInd;
+    superInfoType(int type, int order);
+  };
+  static std::map<int,superInfoType> _superInfo;
   std::vector<MVertex*> _superVert;
   MElement *_superEl, *_superEl0;
-
-  void createSuperElQuad(int order, double dist, const std::vector<MVertex*> &baseVert,
-                         const SVector3 &n0, const SVector3 &n1);
-  void createSuperElPrism(int order, double dist, const std::vector<MVertex*> &baseVert,
-                          const SVector3 &n0, const SVector3 &n1, const SVector3 &n2);
-  void createSuperElHex(int order, double dist, const std::vector<MVertex*> &baseVert,
-                        const SVector3 &n0, const SVector3 &n1, const SVector3 &n2, const SVector3 &n3);
-
-
 };
 
-
 #endif
diff --git a/contrib/Metis/CMakeLists.txt b/contrib/Metis/CMakeLists.txt
deleted file mode 100644
index c5c5541..0000000
--- a/contrib/Metis/CMakeLists.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-# Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
-#
-# See the LICENSE.txt file for license information. Please report all
-# bugs and problems to the public mailing list <gmsh at geuz.org>.
-
-set(SRC
-  balance.c 
-  fm.c        
-  kwayfm.c    
-  mcoarsen.c  
-  minitpart2.c 
-  mpmetis.c   
-  pmetis.c     
-  subdomains.c
-  bucketsort.c  
-  fortran.c  
-  kwayrefine.c
-  memory.c  
-  minitpart.c  
-  mrefine2.c
-  pqueue.c
-  timing.c
-  ccgraph.c 
-  frename.c 
-  kwayvolfm.c
-  mesh.c
-  mkmetis.c
-  mrefine.c 
-  refine.c  
-  util.c
-  coarsen.c 
-  graph.c
-  kwayvolrefine.c  
-  meshpart.c  
-  mkwayfmh.c 
-  mutil.c 
-  separator.c
-  compress.c
-  initpart.c
-  match.c
-  mfm2.c 
-  mkwayrefine.c
-  myqsort.c
-  sfm.c
-  debug.c 
-  kmetis.c  
-  mbalance2.c
-  mfm.c  
-  mmatch.c 
-  ometis.c 
-  srefine.c
-  estmem.c 
-  kvmetis.c
-  mbalance.c 
-  mincover.c  
-  mmd.c  
-#  parmetis.c 
-  stat.c
-)
-
-file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h)
-append_gmsh_src(contrib/Metis "${SRC};${HDR}")
diff --git a/contrib/Tetgen1.4/CMakeLists.txt b/contrib/Tetgen1.4/CMakeLists.txt
deleted file mode 100644
index a39edfa..0000000
--- a/contrib/Tetgen1.4/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-# Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
-#
-# See the LICENSE.txt file for license information. Please report all
-# bugs and problems to the public mailing list <gmsh at geuz.org>.
-
-set(SRC
-  tetgen.cxx
-  predicates.cxx
-)
-
-file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h)
-append_gmsh_src(contrib/Tetgen1.4 "${SRC};${HDR}")
diff --git a/contrib/Tetgen1.5/CMakeLists.txt b/contrib/Tetgen1.5/CMakeLists.txt
deleted file mode 100644
index 8f438fe..0000000
--- a/contrib/Tetgen1.5/CMakeLists.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-# Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
-#
-# See the LICENSE.txt file for license information. Please report all
-# bugs and problems to the public mailing list <gmsh at geuz.org>.
-
-set(SRC
-  tetgen.cxx
-  predicates.cxx
-)
-
-file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h)
-append_gmsh_src(contrib/Tetgen1.5 "${SRC};${HDR}")
diff --git a/contrib/bamg/bamglib/Mesh2.h b/contrib/bamg/bamglib/Mesh2.h
index 3c4afa3..879843d 100644
--- a/contrib/bamg/bamglib/Mesh2.h
+++ b/contrib/bamg/bamglib/Mesh2.h
@@ -54,7 +54,7 @@ namespace bamg {
 
 
 const  double Pi =  3.14159265358979323846264338328;
-const  float fPi =  3.14159265358979323846264338328;
+const  float fPi =  (float)3.14159265358979323846264338328;
 
 
 class MeshIstream;
diff --git a/contrib/blossom/concorde97/INCLUDE/linkern.h b/contrib/blossom/concorde97/INCLUDE/linkern.h
index fc3b6c2..dc8b466 100644
--- a/contrib/blossom/concorde97/INCLUDE/linkern.h
+++ b/contrib/blossom/concorde97/INCLUDE/linkern.h
@@ -40,8 +40,8 @@ int
 /*                                                                         */
 /***************************************************************************/
 
-
-#define CC_TWO_LEVEL_FLIPPER
+#define CC_LINKED_LIST_FLIPPER
+//#define CC_TWO_LEVEL_FLIPPER
 /* #define BTREE_FLIPPER */
 
 #ifdef CC_LINKED_LIST_FLIPPER
diff --git a/contrib/gmm/gmm_inoutput.h b/contrib/gmm/gmm_inoutput.h
index bb4d47f..b6f907a 100644
--- a/contrib/gmm/gmm_inoutput.h
+++ b/contrib/gmm/gmm_inoutput.h
@@ -50,10 +50,10 @@ namespace gmm {
   /*************************************************************************/
 
   // Fri Aug 15 16:29:47 EDT 1997
-  // 
+  //
   //                      Harwell-Boeing File I/O in C
   //                               V. 1.0
-  // 
+  //
   //          National Institute of Standards and Technology, MD.
   //                            K.A. Remington
   // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -66,8 +66,8 @@ namespace gmm {
   // supporting documentation.
   //
   // Neither the Author nor the Institution (National Institute of Standards
-  // and Technology) make any representations about the suitability of this 
-  // software for any purpose. This software is provided "as is" without 
+  // and Technology) make any representations about the suitability of this
+  // software for any purpose. This software is provided "as is" without
   // expressed or implied warranty.
   // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
@@ -84,7 +84,7 @@ namespace gmm {
     }
     return *width;
   }
-  
+
   inline int ParseRfmt(const char *fmt, int* perline, int* width,
 		       int* prec, int* flag) {
     char p;
@@ -108,7 +108,7 @@ namespace gmm {
     *flag = p;
     return *width;
   }
-      
+
   /** matrix input/output for Harwell-Boeing format */
   struct HarwellBoeing_IO {
     int nrows() const { return Nrow; }
@@ -130,10 +130,10 @@ namespace gmm {
     template <typename T, int shift>
     static void write(const char *filename, const csc_matrix<T, shift>& A,
 		      const std::vector<T> &rhs);
-    template <typename T, typename INDI, typename INDJ, int shift> 
+    template <typename T, typename INDI, typename INDJ, int shift>
     static void write(const char *filename,
 		      const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A);
-    template <typename T, typename INDI, typename INDJ, int shift> 
+    template <typename T, typename INDI, typename INDJ, int shift>
     static void write(const char *filename,
 		      const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A,
 		      const std::vector<T> &rhs);
@@ -146,18 +146,18 @@ namespace gmm {
     char Title[73], Key[9], Rhstype[4], Type[4];
     int Nrow, Ncol, Nnzero, Nrhs;
     char Ptrfmt[17], Indfmt[17], Valfmt[21], Rhsfmt[21];
-    int Ptrcrd, Indcrd, Valcrd, Rhscrd; 
+    int Ptrcrd, Indcrd, Valcrd, Rhscrd;
     int lcount;
 
 
     void close() { if (f) fclose(f); clear(); }
-    void clear() { 
+    void clear() {
       Nrow = Ncol = Nnzero = Nrhs = 0; f = 0; lcount = 0;
-      memset(Type, 0, sizeof Type); 
-      memset(Key, 0, sizeof Key); 
-      memset(Title, 0, sizeof Title); 
+      memset(Type, 0, sizeof Type);
+      memset(Key, 0, sizeof Key);
+      memset(Title, 0, sizeof Title);
     }
-    char *getline(char *buf) { 
+    char *getline(char *buf) {
       if(fgets(buf, BUFSIZ, f) == NULL) return buf; ++lcount;
       int s = SECURE_NONCHAR_SSCANF(buf,"%*s");
       GMM_ASSERT1(s >= 0, "blank line in HB file at line " << lcount);
@@ -177,15 +177,15 @@ namespace gmm {
 	for (int j=last+1;j>=0;j--) {
 	  s[j] = s[j-1];
 	  if ( s[j] == '+' || s[j] == '-' ) {
-	    s[j-1] = Valflag;                    
+	    s[j-1] = Valflag;
 	    break;
 	  }
 	}
       }
       return atof(s);
     }
-    template <typename IND_TYPE>   
-    int readHB_data(IND_TYPE colptr[], IND_TYPE rowind[], 
+    template <typename IND_TYPE>
+    int readHB_data(IND_TYPE colptr[], IND_TYPE rowind[],
 		    double val[]) {
       /***********************************************************************/
       /*  This function opens and reads the specified file, interpreting its */
@@ -219,11 +219,11 @@ namespace gmm {
       }
 
       cout << "Valwidth = " << Valwidth << endl; getchar();
-    
+
       /*  Read column pointer array:   */
       offset = 0;         /* if base 0 storage is declared (via macro def),  */
       /* then storage entries are offset by 1            */
-    
+
       for (count = 0, i=0;i<Ptrcrd;i++) {
 	getline(line);
 	for (col = 0, ind = 0;ind<Ptrperline;ind++) {
@@ -232,8 +232,8 @@ namespace gmm {
 	  count++; col += Ptrwidth;
 	}
       }
-    
-      /*  Read row index array:  */    
+
+      /*  Read row index array:  */
       for (count = 0, i=0;i<Indcrd;i++) {
 	getline(line);
 	for (col = 0, ind = 0;ind<Indperline;ind++) {
@@ -242,12 +242,12 @@ namespace gmm {
 	  count++; col += Indwidth;
 	}
       }
-    
+
       /*  Read array of values:  */
       if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
 	if ( Type[0] == 'C' ) Nentries = 2*Nnzero;
 	else Nentries = Nnzero;
-      
+
 	count = 0;
 	for (i=0;i<Valcrd;i++) {
 	  getline(line);
@@ -266,7 +266,7 @@ namespace gmm {
       return 1;
     }
   };
-  
+
   inline void HarwellBoeing_IO::open(const char *filename) {
     int Totcrd,Neltvl,Nrhsix;
     char line[BUFSIZ];
@@ -284,7 +284,7 @@ namespace gmm {
     Totcrd = Ptrcrd = Indcrd = Valcrd = Rhscrd = 0;
     SECURE_NONCHAR_SSCANF(getline(line), "%d%d%d%d%d", &Totcrd, &Ptrcrd,
 			  &Indcrd, &Valcrd, &Rhscrd);
-    
+
     /* Third line: */
     Nrow = Ncol = Nnzero = Neltvl = 0;
 #ifdef GMM_SECURE_CRT
@@ -296,7 +296,7 @@ namespace gmm {
 #endif
       IOHBTerminate("Invalid Type info, line 3 of Harwell-Boeing file.\n");
     for (size_type i = 0; i < 3; ++i) Type[i] = toupper(Type[i]);
-    
+
       /*  Fourth line:  */
 #ifdef GMM_SECURE_CRT
     if ( sscanf_s(getline(line), "%c%c%c%c",Ptrfmt, 16,Indfmt, 16,Valfmt,
@@ -305,11 +305,11 @@ namespace gmm {
     if ( sscanf(getline(line), "%16c%16c%20c%20c",Ptrfmt,Indfmt,Valfmt,
 		Rhsfmt) < 3)
 #endif
-      IOHBTerminate("Invalid format info, line 4 of Harwell-Boeing file.\n"); 
+      IOHBTerminate("Invalid format info, line 4 of Harwell-Boeing file.\n");
     Ptrfmt[16] = Indfmt[16] = Valfmt[20] = Rhsfmt[20] = 0;
-    
+
     /*  (Optional) Fifth line: */
-    if (Rhscrd != 0 ) { 
+    if (Rhscrd != 0 ) {
       Nrhs = Nrhsix = 0;
 #ifdef GMM_SECURE_CRT
       if ( sscanf_s(getline(line), "%c%d%d", Rhstype, 3, &Nrhs, &Nrhsix) != 1)
@@ -345,22 +345,22 @@ namespace gmm {
     for (int i = 0; i < nnz(); ++i)    { A.ir[i] += shift; A.ir[i] -= 1; }
   }
 
-  template <typename MAT> void 
+  template <typename MAT> void
   HarwellBoeing_IO::read(MAT &M) {
     csc_matrix<typename gmm::linalg_traits<MAT>::value_type> csc;
-    read(csc); 
+    read(csc);
     resize(M, mat_nrows(csc), mat_ncols(csc));
     copy(csc, M);
   }
-  
-  template <typename IND_TYPE> 
+
+  template <typename IND_TYPE>
   inline int writeHB_mat_double(const char* filename, int M, int N, int nz,
 				const IND_TYPE colptr[],
-				const IND_TYPE rowind[], 
+				const IND_TYPE rowind[],
 				const double val[], int Nrhs,
 				const double rhs[], const double guess[],
 				const double exact[], const char* Title,
-				const char* Key, const char* Type, 
+				const char* Key, const char* Type,
 				const char* Ptrfmt, const char* Indfmt,
 				const char* Valfmt, const char* Rhsfmt,
 				const char* Rhstype, int shift) {
@@ -382,33 +382,34 @@ namespace gmm {
     int Valperline, Valwidth, Valprec;
     int Valflag;           /* Indicates 'E','D', or 'F' float format */
     char pformat[16],iformat[16],vformat[19],rformat[19];
-    
+
     if ( Type[0] == 'C' )
       { nvalentries = 2*nz; nrhsentries = 2*M; }
     else
       { nvalentries = nz; nrhsentries = M; }
-    
+
     if ( filename != NULL ) {
       SECURE_FOPEN(&out_file, filename, "w");
       GMM_ASSERT1(out_file != NULL, "Error: Cannot open file: " << filename);
     } else out_file = stdout;
-    
+
     if ( Ptrfmt == NULL ) Ptrfmt = "(8I10)";
     ParseIfmt(Ptrfmt, &Ptrperline, &Ptrwidth);
     SECURE_SPRINTF1(pformat,sizeof(pformat),"%%%dd",Ptrwidth);
     ptrcrd = (N+1)/Ptrperline;
     if ( (N+1)%Ptrperline != 0) ptrcrd++;
-    
+
     if ( Indfmt == NULL ) Indfmt =  Ptrfmt;
     ParseIfmt(Indfmt, &Indperline, &Indwidth);
     SECURE_SPRINTF1(iformat,sizeof(iformat), "%%%dd",Indwidth);
     indcrd = nz/Indperline;
     if ( nz%Indperline != 0) indcrd++;
-    
+
     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
       if ( Valfmt == NULL ) Valfmt = "(4E21.13)";
       ParseRfmt(Valfmt, &Valperline, &Valwidth, &Valprec, &Valflag);
-      if (Valflag == 'D') *strchr(Valfmt,'D') = 'E';
+      //Gmsh fix: this is invalid, as Valfmt is a const char*
+      //if (Valflag == 'D') *strchr(Valfmt,'D') = 'E';
       if (Valflag == 'F')
 	SECURE_SPRINTF2(vformat, sizeof(vformat), "%% %d.%df", Valwidth,
 			Valprec);
@@ -418,7 +419,7 @@ namespace gmm {
       valcrd = nvalentries/Valperline;
       if ( nvalentries%Valperline != 0) valcrd++;
     } else valcrd = 0;
-    
+
     if ( Nrhs > 0 ) {
       if ( Rhsfmt == NULL ) Rhsfmt = Valfmt;
       ParseRfmt(Rhsfmt,&Rhsperline,&Rhswidth,&Rhsprec, &Rhsflag);
@@ -426,19 +427,20 @@ namespace gmm {
 	SECURE_SPRINTF2(rformat,sizeof(rformat), "%% %d.%df",Rhswidth,Rhsprec);
       else
 	SECURE_SPRINTF2(rformat,sizeof(rformat), "%% %d.%dE",Rhswidth,Rhsprec);
-      if (Rhsflag == 'D') *strchr(Rhsfmt,'D') = 'E';
-      rhscrd = nrhsentries/Rhsperline; 
+      //Gmsh fix: this is invalid, as Rhsfmt is a const char*
+      //if (Rhsflag == 'D') *strchr(Rhsfmt,'D') = 'E';
+      rhscrd = nrhsentries/Rhsperline;
       if ( nrhsentries%Rhsperline != 0) rhscrd++;
       if ( Rhstype[1] == 'G' ) rhscrd+=rhscrd;
       if ( Rhstype[2] == 'X' ) rhscrd+=rhscrd;
       rhscrd*=Nrhs;
     } else rhscrd = 0;
-    
+
     totcrd = 4+ptrcrd+indcrd+valcrd+rhscrd;
-    
-    
+
+
     /*  Print header information:  */
-    
+
     fprintf(out_file,"%-72s%-8s\n%14d%14d%14d%14d%14d\n",Title, Key, totcrd,
 	    ptrcrd, indcrd, valcrd, rhscrd);
     fprintf(out_file,"%3s%11s%14d%14d%14d%14d\n",Type,"          ", M, N, nz, 0);
@@ -450,38 +452,38 @@ namespace gmm {
     }
     else
       fprintf(out_file,"\n");
-    
+
     offset = 1 - shift;  /* if base 0 storage is declared (via macro def), */
     /* then storage entries are offset by 1           */
-    
+
     /*  Print column pointers:   */
     for (i = 0; i < N+1; i++) {
       entry = colptr[i]+offset;
       fprintf(out_file,pformat,entry);
       if ( (i+1)%Ptrperline == 0 ) fprintf(out_file,"\n");
     }
-    
+
     if ( (N+1) % Ptrperline != 0 ) fprintf(out_file,"\n");
-    
+
     /*  Print row indices:       */
     for (i=0;i<nz;i++) {
       entry = rowind[i]+offset;
       fprintf(out_file,iformat,entry);
       if ( (i+1)%Indperline == 0 ) fprintf(out_file,"\n");
     }
-    
+
     if ( nz % Indperline != 0 ) fprintf(out_file,"\n");
-    
+
     /*  Print values:            */
-    
+
     if ( Type[0] != 'P' ) {          /* Skip if pattern only  */
       for (i=0;i<nvalentries;i++) {
 	fprintf(out_file,vformat,val[i]);
 	if ( (i+1)%Valperline == 0 ) fprintf(out_file,"\n");
       }
-      
+
       if ( nvalentries % Valperline != 0 ) fprintf(out_file,"\n");
-      
+
       /*  Print right hand sides:  */
       acount = 1;
       linemod=0;
@@ -522,7 +524,7 @@ namespace gmm {
     GMM_ASSERT1(s == 0, "Error closing file in writeHB_mat_double().");
     return 1;
   }
-  
+
   template <typename T, int shift> void
   HarwellBoeing_IO::write(const char *filename,
 			  const csc_matrix<T, shift>& A) {
@@ -541,7 +543,7 @@ namespace gmm {
   template <typename T, typename INDI, typename INDJ, int shift> void
   HarwellBoeing_IO::write(const char *filename,
 			  const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A) {
-    const char *t = 0;    
+    const char *t = 0;
     if (is_complex_double__(T()))
       if (mat_nrows(A) == mat_ncols(A)) t = "CUA"; else t = "CRA";
     else
@@ -571,12 +573,12 @@ namespace gmm {
 		       t, 0, 0, 0, 0, "F  ", shift);
   }
 
-  
+
   template <typename MAT> void
   HarwellBoeing_IO::write(const char *filename, const MAT& A) {
-    gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type> 
+    gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type>
       tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
-    gmm::copy(A,tmp); 
+    gmm::copy(A,tmp);
     HarwellBoeing_IO::write(filename, tmp);
   }
 
@@ -601,9 +603,9 @@ namespace gmm {
   */
   template <typename MAT> inline void
   Harwell_Boeing_save(const std::string &filename, const MAT& A) {
-    gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type> 
+    gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type>
       tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
-    gmm::copy(A, tmp); 
+    gmm::copy(A, tmp);
     HarwellBoeing_IO::write(filename.c_str(), tmp);
   }
 
@@ -643,7 +645,7 @@ namespace gmm {
   /*                                                                       */
   /*************************************************************************/
 
-  /* 
+  /*
    *   Matrix Market I/O library for ANSI C
    *
    *   See http://math.nist.gov/MatrixMarket for details.
@@ -660,22 +662,22 @@ namespace gmm {
   /******************* MM_typecode query functions *************************/
 
 #define mm_is_matrix(typecode)	        ((typecode)[0]=='M')
-  
+
 #define mm_is_sparse(typecode)	        ((typecode)[1]=='C')
 #define mm_is_coordinate(typecode)      ((typecode)[1]=='C')
 #define mm_is_dense(typecode)	        ((typecode)[1]=='A')
 #define mm_is_array(typecode)	        ((typecode)[1]=='A')
-  
+
 #define mm_is_complex(typecode)	        ((typecode)[2]=='C')
 #define mm_is_real(typecode)	        ((typecode)[2]=='R')
 #define mm_is_pattern(typecode)	        ((typecode)[2]=='P')
 #define mm_is_integer(typecode)         ((typecode)[2]=='I')
-  
+
 #define mm_is_symmetric(typecode)       ((typecode)[3]=='S')
 #define mm_is_general(typecode)	        ((typecode)[3]=='G')
 #define mm_is_skew(typecode)	        ((typecode)[3]=='K')
 #define mm_is_hermitian(typecode)       ((typecode)[3]=='H')
-  
+
   /******************* MM_typecode modify fucntions ************************/
 
 #define mm_set_matrix(typecode)	        ((*typecode)[0]='M')
@@ -717,7 +719,7 @@ namespace gmm {
 
    MM_matrix_typecode: 4-character sequence
 
-	                object 	    sparse/   	data        storage 
+	                object 	    sparse/   	data        storage
 	                            dense     	type        scheme
 
    string position:	 [0]        [1]		[2]         [3]
@@ -732,7 +734,7 @@ namespace gmm {
 #define MM_MTX_STR	   "matrix"
 #define MM_ARRAY_STR	   "array"
 #define MM_DENSE_STR	   "array"
-#define MM_COORDINATE_STR  "coordinate" 
+#define MM_COORDINATE_STR  "coordinate"
 #define MM_SPARSE_STR	   "coordinate"
 #define MM_COMPLEX_STR	   "complex"
 #define MM_REAL_STR	   "real"
@@ -748,9 +750,9 @@ namespace gmm {
     const char *types[4] = {0,0,0,0};
     /*    int error =0; */
     /*   int i; */
-    
+
     /* check for MTX type */
-    if (mm_is_matrix(matcode)) 
+    if (mm_is_matrix(matcode))
       types[0] = MM_MTX_STR;
     /*
       else
@@ -764,7 +766,7 @@ namespace gmm {
         types[1] = MM_DENSE_STR;
       else
         return NULL;
-    
+
     /* check for element data type */
     if (mm_is_real(matcode))
       types[2] = MM_REAL_STR;
@@ -779,8 +781,8 @@ namespace gmm {
 	    types[2] = MM_INT_STR;
 	  else
 	    return NULL;
-    
-    
+
+
     /* check for symmetry type */
     if (mm_is_general(matcode))
       types[3] = MM_GENERAL_STR;
@@ -792,26 +794,26 @@ namespace gmm {
       types[3] = MM_SKEW_STR;
     else
       return NULL;
-    
+
     SECURE_SPRINTF4(buffer, sizeof(buffer), "%s %s %s %s", types[0], types[1],
 		    types[2], types[3]);
     return SECURE_STRDUP(buffer);
-    
+
   }
-  
+
   inline int mm_read_banner(FILE *f, MM_typecode *matcode) {
     char line[MM_MAX_LINE_LENGTH];
     char banner[MM_MAX_TOKEN_LENGTH];
-    char mtx[MM_MAX_TOKEN_LENGTH]; 
+    char mtx[MM_MAX_TOKEN_LENGTH];
     char crd[MM_MAX_TOKEN_LENGTH];
     char data_type[MM_MAX_TOKEN_LENGTH];
     char storage_scheme[MM_MAX_TOKEN_LENGTH];
     char *p;
     /*    int ret_code; */
-    
-    mm_clear_typecode(matcode);  
-    
-    if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL) 
+
+    mm_clear_typecode(matcode);
+
+    if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
       return MM_PREMATURE_EOF;
 
 #ifdef GMM_SECURE_CRT
@@ -826,7 +828,7 @@ namespace gmm {
       return MM_PREMATURE_EOF;
 
     for (p=mtx; *p!='\0'; *p=tolower(*p),p++);  /* convert to lower case */
-    for (p=crd; *p!='\0'; *p=tolower(*p),p++);  
+    for (p=crd; *p!='\0'; *p=tolower(*p),p++);
     for (p=data_type; *p!='\0'; *p=tolower(*p),p++);
     for (p=storage_scheme; *p!='\0'; *p=tolower(*p),p++);
 
@@ -851,7 +853,7 @@ namespace gmm {
 	mm_set_dense(matcode);
       else
         return MM_UNSUPPORTED_TYPE;
-    
+
 
     /* third field */
 
@@ -868,7 +870,7 @@ namespace gmm {
 	    mm_set_integer(matcode);
 	  else
 	    return MM_UNSUPPORTED_TYPE;
-    
+
 
     /* fourth field */
 
@@ -885,7 +887,7 @@ namespace gmm {
 	    mm_set_skew(matcode);
 	  else
 	    return MM_UNSUPPORTED_TYPE;
-        
+
     return 0;
   }
 
@@ -893,25 +895,25 @@ namespace gmm {
     char line[MM_MAX_LINE_LENGTH];
     /* int ret_code;*/
     int num_items_read;
-    
+
     /* set return null parameter values, in case we exit with errors */
     *M = *N = *nz = 0;
-    
+
     /* now continue scanning until you reach the end-of-comments */
     do {
-      if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL) 
+      if (fgets(line,MM_MAX_LINE_LENGTH,f) == NULL)
 	return MM_PREMATURE_EOF;
     } while (line[0] == '%');
-    
+
     /* line[] is either blank or has M,N, nz */
     if (SECURE_NONCHAR_SSCANF(line, "%d %d %d", M, N, nz) == 3) return 0;
     else
-      do { 
-	num_items_read = SECURE_NONCHAR_FSCANF(f, "%d %d %d", M, N, nz); 
+      do {
+	num_items_read = SECURE_NONCHAR_FSCANF(f, "%d %d %d", M, N, nz);
 	if (num_items_read == EOF) return MM_PREMATURE_EOF;
       }
       while (num_items_read != 3);
-    
+
     return 0;
   }
 
@@ -929,7 +931,7 @@ namespace gmm {
       for (i=0; i<nz; i++) {
 	if (SECURE_NONCHAR_FSCANF(f, "%d %d %lg\n", &I[i], &J[i], &val[i])
 	    != 3) return MM_PREMATURE_EOF;
-	
+
       }
     }
     else if (mm_is_pattern(matcode)) {
@@ -947,24 +949,24 @@ namespace gmm {
 			      MM_typecode matcode) {
     FILE *f;
     int i;
-    
-    if (strcmp(fname, "stdout") == 0) 
+
+    if (strcmp(fname, "stdout") == 0)
       f = stdout;
     else {
       SECURE_FOPEN(&f, fname, "w");
       if (f == NULL)
         return MM_COULD_NOT_WRITE_FILE;
     }
-    
+
     /* print banner followed by typecode */
     fprintf(f, "%s ", MatrixMarketBanner);
     char *str = mm_typecode_to_str(matcode);
     fprintf(f, "%s\n", str);
     free(str);
-    
+
     /* print matrix sizes and nonzeros */
     fprintf(f, "%d %d %d\n", M, N, nz);
-    
+
     /* print values */
     if (mm_is_pattern(matcode))
       for (i=0; i<nz; i++)
@@ -976,17 +978,17 @@ namespace gmm {
       else
 	if (mm_is_complex(matcode))
 	  for (i=0; i<nz; i++)
-            fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i], 
+            fprintf(f, "%d %d %20.16g %20.16g\n", I[i], J[i], val[2*i],
 		    val[2*i+1]);
 	else {
 	  if (f != stdout) fclose(f);
 	  return MM_UNSUPPORTED_TYPE;
 	}
-    
-    if (f !=stdout) fclose(f); 
+
+    if (f !=stdout) fclose(f);
     return 0;
   }
-  
+
 
   /** matrix input/output for MatrixMarket storage */
   class MatrixMarket_IO {
@@ -1011,13 +1013,13 @@ namespace gmm {
     /* read opened file */
     template <typename Matrix> void read(Matrix &A);
     /* write a matrix */
-    template <typename T, int shift> static void 
-    write(const char *filename, const csc_matrix<T, shift>& A);  
-    template <typename T, typename INDI, typename INDJ, int shift> static void 
+    template <typename T, int shift> static void
+    write(const char *filename, const csc_matrix<T, shift>& A);
+    template <typename T, typename INDI, typename INDJ, int shift> static void
     write(const char *filename,
-	  const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A);  
-    template <typename MAT> static void 
-    write(const char *filename, const MAT& A);  
+	  const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A);
+    template <typename MAT> static void
+    write(const char *filename, const MAT& A);
   };
 
   /** load a matrix-market file */
@@ -1054,8 +1056,8 @@ namespace gmm {
 	       "the file does only contain the pattern of a sparse matrix");
     int s5 = mm_is_skew(matcode);
     GMM_ASSERT1(s5 == 0, "not currently supporting skew symmetric");
-    isSymmetric = mm_is_symmetric(matcode) || mm_is_hermitian(matcode); 
-    isHermitian = mm_is_hermitian(matcode); 
+    isSymmetric = mm_is_symmetric(matcode) || mm_is_hermitian(matcode);
+    isHermitian = mm_is_hermitian(matcode);
     isComplex =   mm_is_complex(matcode);
     mm_read_mtx_crd_size(f, &row, &col, &nz);
   }
@@ -1069,33 +1071,33 @@ namespace gmm {
 		"Bad MM matrix format (real matrix expected)");
     A = Matrix(row, col);
     gmm::clear(A);
-    
+
     std::vector<int> I(nz), J(nz);
     std::vector<typename Matrix::value_type> PR(nz);
     mm_read_mtx_crd_data(f, row, col, nz, &I[0], &J[0],
 			 (double*)&PR[0], matcode);
-    
+
     for (size_type i = 0; i < size_type(nz); ++i) A(I[i]-1, J[i]-1) = PR[i];
   }
 
-  template <typename T, int shift> void 
+  template <typename T, int shift> void
   MatrixMarket_IO::write(const char *filename, const csc_matrix<T, shift>& A) {
     write(filename, csc_matrix_ref<T*,unsigned*,unsigned*,shift>
 	  (A.pr, A.ir, A.jc, A.nr, A.nc));
   }
 
-  template <typename T, typename INDI, typename INDJ, int shift> void 
-  MatrixMarket_IO::write(const char *filename, 
+  template <typename T, typename INDI, typename INDJ, int shift> void
+  MatrixMarket_IO::write(const char *filename,
 			 const csc_matrix_ref<T*, INDI*, INDJ*, shift>& A) {
     static MM_typecode t1 = {'M', 'C', 'R', 'G'};
     static MM_typecode t2 = {'M', 'C', 'C', 'G'};
     MM_typecode t;
-    
+
     if (is_complex_double__(T())) std::copy(&(t2[0]), &(t2[0])+4, &(t[0]));
     else std::copy(&(t1[0]), &(t1[0])+4, &(t[0]));
     size_type nz = A.jc[mat_ncols(A)];
     std::vector<int> I(nz), J(nz);
-    for (size_type j=0; j < mat_ncols(A); ++j) {      
+    for (size_type j=0; j < mat_ncols(A); ++j) {
       for (size_type i = A.jc[j]; i < A.jc[j+1]; ++i) {
 	I[i] = A.ir[i] + 1 - shift;
 	J[i] = j + 1;
@@ -1108,22 +1110,22 @@ namespace gmm {
 
   template <typename MAT> void
   MatrixMarket_IO::write(const char *filename, const MAT& A) {
-    gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type> 
+    gmm::csc_matrix<typename gmm::linalg_traits<MAT>::value_type>
       tmp(gmm::mat_nrows(A), gmm::mat_ncols(A));
-    gmm::copy(A,tmp); 
+    gmm::copy(A,tmp);
     MatrixMarket_IO::write(filename, tmp);
   }
 
   template<typename VEC> static void vecsave(std::string fname, const VEC& V) {
     std::ofstream f(fname.c_str()); f.precision(16);
-    for (size_type i=0; i < gmm::vect_size(V); ++i) f << V[i] << "\n"; 
-  } 
+    for (size_type i=0; i < gmm::vect_size(V); ++i) f << V[i] << "\n";
+  }
 
   template<typename VEC> static void vecload(std::string fname,
 					     const VEC& V_) {
     VEC &V(const_cast<VEC&>(V_));
     std::ifstream f(fname.c_str());
-    for (size_type i=0; i < gmm::vect_size(V); ++i) f >> V[i]; 
+    for (size_type i=0; i < gmm::vect_size(V); ++i) f >> V[i];
   }
 }
 
diff --git a/contrib/gmm/gmm_precond_diagonal.h b/contrib/gmm/gmm_precond_diagonal.h
index e3f74c6..f6dee5a 100644
--- a/contrib/gmm/gmm_precond_diagonal.h
+++ b/contrib/gmm/gmm_precond_diagonal.h
@@ -91,9 +91,9 @@ namespace gmm {
   void transposed_mult(const diagonal_precond<Matrix>& P,const V1 &v1,V2 &v2) {
     mult(P, v1, v2);
   }
-  
+
   // # define DIAG_LEFT_MULT_SQRT
-  
+
   template <typename Matrix, typename V1, typename V2> inline
   void left_mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
     GMM_ASSERT2(P.diag.size() == vect_size(v2), "dimensions mismatch");
@@ -112,10 +112,10 @@ namespace gmm {
 
   template <typename Matrix, typename V1, typename V2> inline
   void right_mult(const diagonal_precond<Matrix>& P, const V1 &v1, V2 &v2) {
-    typedef typename linalg_traits<Matrix>::value_type T;
+    //typedef typename linalg_traits<Matrix>::value_type T;
     GMM_ASSERT2(P.diag.size() == vect_size(v2), "dimensions mismatch");
     copy(v1, v2);
-#   ifdef DIAG_LEFT_MULT_SQRT    
+#   ifdef DIAG_LEFT_MULT_SQRT
     for (size_type i= 0; i < P.diag.size(); ++i) v2[i] *= gmm::sqrt(P.diag[i]);
 #   endif
   }
@@ -127,5 +127,5 @@ namespace gmm {
 
 }
 
-#endif 
+#endif
 
diff --git a/contrib/mobile/Android/AndroidManifest.xml b/contrib/mobile/Android/AndroidManifest.xml
index 497f806..6d55282 100644
--- a/contrib/mobile/Android/AndroidManifest.xml
+++ b/contrib/mobile/Android/AndroidManifest.xml
@@ -1,54 +1,54 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="org.geuz.onelab"
-    android:versionCode="1"
-    android:versionName="1.0"
-    android:installLocation="auto"
-    >
-
-    <uses-sdk
-        android:targetSdkVersion="17"
-        android:minSdkVersion="14" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-    <uses-permission android:name="android.permission.VIBRATE"/>
-    <uses-feature android:glEsVersion="0x00010000" android:required="true" />
-
-    <application
-        android:icon="@drawable/ic_launcher"
-        android:label="@string/app_name"
-        android:theme="@style/AppTheme"
-        android:logo="@drawable/ic_launcher"
-        android:allowBackup="true">
-        <activity
-            android:name=".SplashScreen"
-            android:label="@string/title_activity_main">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity
-            android:name=".ModelList"
-            android:label="@string/title_activity_main" />
-        <activity
-            android:name=".MainActivity"
-            android:label="@string/title_activity_main"
-            >
-            <intent-filter>
-				<action android:name="android.intent.action.VIEW" />
-				<category android:name="android.intent.category.DEFAULT" />
-				<data android:scheme="file"  android:host="*" android:pathPattern=".*\\.msh" android:mimeType="*/*"  />
-				<data android:scheme="file"  android:host="*" android:pathPattern=".*\\.geo" android:mimeType="*/*"  />
-				<data android:scheme="file"  android:host="*" android:pathPattern=".*\\.pro" android:mimeType="*/*"  />
-			</intent-filter>
-        </activity>
-         <activity
-            android:name=".PostProcessingActivity"
-            android:label="@string/title_activity_main"
-             />
-        <activity 
-            android:name=".OptionsActivity"
-            android:label="@string/title_activity_options"
-             />
-    </application>
-
+          package="org.geuz.onelab"
+          android:versionCode="5"
+          android:versionName="1.0.6"
+          android:installLocation="auto" >
+  
+  <uses-sdk android:minSdkVersion="14"
+            android:targetSdkVersion="17" />
+  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+  <uses-permission android:name="android.permission.VIBRATE"/>
+  <uses-feature android:glEsVersion="0x00010000" android:required="true" />
+  
+  <application android:icon="@drawable/ic_launcher"
+               android:label="@string/app_name"
+               android:theme="@style/AppTheme"
+               android:logo="@drawable/ic_launcher"
+               android:allowBackup="true" >
+    <activity android:name=".SplashScreen"
+              android:label="@string/title_activity_main">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+    <activity android:name=".ModelList"
+              android:label="@string/title_activity_main" />
+    <activity android:name=".AboutActivity"
+              android:label="@string/title_activity_about" />
+    <activity android:name=".MainActivity"
+              android:label="@string/title_activity_main" >
+      <intent-filter>
+        <action android:name="android.intent.action.VIEW" />
+        <category android:name="android.intent.category.DEFAULT" />
+        <data android:scheme="file" 
+              android:host="*" 
+              android:pathPattern=".*\\.msh" 
+              android:mimeType="*/*"  />
+        <data android:scheme="file" 
+              android:host="*"
+              android:pathPattern=".*\\.geo"
+              android:mimeType="*/*"  />
+        <data android:scheme="file"
+              android:host="*"
+              android:pathPattern=".*\\.pro" 
+              android:mimeType="*/*"  />
+      </intent-filter>
+    </activity>
+    <activity android:name=".PostProcessingActivity"
+              android:label="@string/title_activity_main" />
+    <activity android:name=".OptionsActivity"
+              android:label="@string/title_activity_options" />
+  </application>
+  
 </manifest>
diff --git a/contrib/mobile/Android/res/drawable-hdpi/ic_launcher.png b/contrib/mobile/Android/res/drawable-hdpi/ic_launcher.png
index 13ba138..c8b7990 100644
Binary files a/contrib/mobile/Android/res/drawable-hdpi/ic_launcher.png and b/contrib/mobile/Android/res/drawable-hdpi/ic_launcher.png differ
diff --git a/contrib/mobile/Android/res/drawable-ldpi/ic_launcher.png b/contrib/mobile/Android/res/drawable-ldpi/ic_launcher.png
index 09e5479..19a3ab1 100644
Binary files a/contrib/mobile/Android/res/drawable-ldpi/ic_launcher.png and b/contrib/mobile/Android/res/drawable-ldpi/ic_launcher.png differ
diff --git a/contrib/mobile/Android/res/drawable-mdpi/ic_launcher.png b/contrib/mobile/Android/res/drawable-mdpi/ic_launcher.png
index 286d27e..262b7f5 100644
Binary files a/contrib/mobile/Android/res/drawable-mdpi/ic_launcher.png and b/contrib/mobile/Android/res/drawable-mdpi/ic_launcher.png differ
diff --git a/contrib/mobile/Android/res/drawable-mdpi/icon_rotate.png b/contrib/mobile/Android/res/drawable-mdpi/icon_rotate.png
new file mode 100644
index 0000000..28ae466
Binary files /dev/null and b/contrib/mobile/Android/res/drawable-mdpi/icon_rotate.png differ
diff --git a/contrib/mobile/Android/res/drawable-mdpi/icon_translate.png b/contrib/mobile/Android/res/drawable-mdpi/icon_translate.png
new file mode 100644
index 0000000..acde225
Binary files /dev/null and b/contrib/mobile/Android/res/drawable-mdpi/icon_translate.png differ
diff --git a/contrib/mobile/Android/res/layout/activity_fragment.xml b/contrib/mobile/Android/res/layout/activity_fragment.xml
index 4d2f16d..4fc7a01 100644
--- a/contrib/mobile/Android/res/layout/activity_fragment.xml
+++ b/contrib/mobile/Android/res/layout/activity_fragment.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/model_fragment"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginLeft="0dp"
-    android:layout_marginRight="0dp" />
\ No newline at end of file
+             android:id="@+id/model_fragment"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             android:layout_marginLeft="0dp"
+             android:layout_marginRight="0dp" />
diff --git a/contrib/mobile/Android/res/layout/activity_model.xml b/contrib/mobile/Android/res/layout/activity_model.xml
index 285d00e..f50072f 100644
--- a/contrib/mobile/Android/res/layout/activity_model.xml
+++ b/contrib/mobile/Android/res/layout/activity_model.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/model_fragment"
-    android:name="org.geuz.onelab.ModelFragment"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginLeft="0dp"
-    android:layout_marginRight="0dp"
-    tools:context=".MainActivity" />
\ No newline at end of file
+             xmlns:tools="http://schemas.android.com/tools"
+             android:id="@+id/model_fragment"
+             android:name="org.geuz.onelab.ModelFragment"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             android:layout_marginLeft="0dp"
+             android:layout_marginRight="0dp"
+             tools:context=".MainActivity" />
diff --git a/contrib/mobile/Android/res/layout/activity_twopane.xml b/contrib/mobile/Android/res/layout/activity_twopane.xml
index 2b02a4d..b9ea76e 100644
--- a/contrib/mobile/Android/res/layout/activity_twopane.xml
+++ b/contrib/mobile/Android/res/layout/activity_twopane.xml
@@ -1,27 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:baselineAligned="false"
-    android:divider="?android:attr/dividerHorizontal"
-    android:orientation="horizontal"
-    android:showDividers="middle"
-    tools:context=".MainActivity" >
-    
-	<FrameLayout android:id="@+id/parameter_fragment"
-	    android:name="org.geuz.onelab.OptionsDisplayFragment"
-	    android:layout_marginTop="48dp"
-	    android:layout_width="0dp"
-	    android:layout_height="match_parent"
-	    android:layout_weight="1" />
-
-	<FrameLayout android:id="@+id/model_fragment"
-		android:name="org.geuz.onelab.ModelFragment"
-		android:layout_width="0dp"
-		android:layout_height="match_parent"
-		android:layout_marginLeft="0dp"
-		android:layout_marginRight="0dp"
-		android:layout_weight="3" />
-
-</LinearLayout>
\ No newline at end of file
+              xmlns:tools="http://schemas.android.com/tools"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:baselineAligned="false"
+              android:divider="?android:attr/dividerHorizontal"
+              android:orientation="horizontal"
+              android:showDividers="middle"
+              tools:context=".MainActivity" >
+  <FrameLayout android:id="@+id/parameter_fragment"
+               android:name="org.geuz.onelab.OptionsDisplayFragment"
+               android:layout_marginTop="48dp"
+               android:layout_width="0dp"
+               android:layout_height="match_parent"
+               android:layout_weight="1" />
+  <FrameLayout android:id="@+id/model_fragment"
+               android:name="org.geuz.onelab.ModelFragment"
+               android:layout_width="0dp"
+               android:layout_height="match_parent"
+               android:layout_marginLeft="0dp"
+               android:layout_marginRight="0dp"
+               android:layout_weight="2" />
+</LinearLayout>
diff --git a/contrib/mobile/Android/res/layout/control_bar.xml b/contrib/mobile/Android/res/layout/control_bar.xml
index 22f76a0..a8a8e0e 100644
--- a/contrib/mobile/Android/res/layout/control_bar.xml
+++ b/contrib/mobile/Android/res/layout/control_bar.xml
@@ -1,43 +1,38 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:background="@android:color/black"
-    android:alpha=".50"
-    android:gravity="center" >
-    <SeekBar
-        android:id="@+id/controlStepper"
-        android:layout_width="match_parent"
-	    android:layout_height="wrap_content" />
-    <LinearLayout
-	    android:layout_width="match_parent"
-	    android:layout_height="match_parent"
-	    android:orientation="horizontal"
-	    android:background="@android:color/black"
-	    android:alpha=".50"
-	    android:gravity="center" >
-
-	    <ImageButton
-	        android:id="@+id/controlPrev"
-	        android:layout_width="wrap_content"
-	        android:layout_height="wrap_content"
-	        android:src="@android:drawable/ic_media_previous"
-	        android:contentDescription="previous" />
-	
-	    <ImageButton
-	        android:id="@+id/controlPlay"
-	        android:layout_width="wrap_content"
-	        android:layout_height="wrap_content"
-	        android:src="@android:drawable/ic_media_play"
-	        android:contentDescription="play" />
-	
-	    <ImageButton
-	        android:id="@+id/controlNext"
-	        android:layout_width="wrap_content"
-	        android:layout_height="wrap_content"
-	        android:src="@android:drawable/ic_media_next"
-	        android:contentDescription="next" />
-
-	</LinearLayout>
-</LinearLayout>
\ No newline at end of file
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical"
+              android:background="@android:color/black"
+              android:alpha=".50"
+              android:gravity="center" >
+  <SeekBar android:id="@+id/controlStepper"
+           android:layout_width="match_parent"
+           android:layout_height="wrap_content" />
+  <LinearLayout android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="horizontal"
+                android:background="@android:color/black"
+                android:alpha=".50"
+                android:gravity="center" >
+    
+    <ImageButton android:id="@+id/controlPrev"
+                 android:layout_width="wrap_content"
+                 android:layout_height="wrap_content"
+                 android:src="@android:drawable/ic_media_previous"
+                 android:contentDescription="previous" />
+    
+    <ImageButton android:id="@+id/controlPlay"
+                 android:layout_width="wrap_content"
+                 android:layout_height="wrap_content"
+                 android:src="@android:drawable/ic_media_play"
+                 android:contentDescription="play" />
+    
+    <ImageButton android:id="@+id/controlNext"
+                 android:layout_width="wrap_content"
+                 android:layout_height="wrap_content"
+                 android:src="@android:drawable/ic_media_next"
+                 android:contentDescription="next" />
+    
+  </LinearLayout>
+</LinearLayout>
diff --git a/contrib/mobile/Android/res/layout/fragment_options.xml b/contrib/mobile/Android/res/layout/fragment_options.xml
index d184171..01cbbb1 100644
--- a/contrib/mobile/Android/res/layout/fragment_options.xml
+++ b/contrib/mobile/Android/res/layout/fragment_options.xml
@@ -1,35 +1,35 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:padding="4dip"
-	android:gravity="center_horizontal"
-	android:layout_width="match_parent"
-	android:layout_height="match_parent">
-
-	<FrameLayout android:id="@+id/options_fragment"
-	    android:name="org.geuz.onelab.OptionsModelFragment"
-	    android:layout_width="match_parent"
-		android:layout_height="0px"
-		android:layout_weight="1" />
-
-	<View android:layout_width="fill_parent"
-	    android:layout_height="1dp"
-	    android:background="@android:color/darker_gray" />
-    <LinearLayout android:orientation="horizontal"
+              android:orientation="vertical"
+              android:padding="4dip"
+              android:gravity="center_horizontal"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+  
+  <FrameLayout android:id="@+id/options_fragment"
+               android:name="org.geuz.onelab.OptionsModelFragment"
+               android:layout_width="match_parent"
+               android:layout_height="0px"
+               android:layout_weight="1" />
+  
+  <View android:layout_width="fill_parent"
+        android:layout_height="1dp"
+        android:background="@android:color/darker_gray" />
+  <LinearLayout android:orientation="horizontal"
 		android:gravity="center" android:measureWithLargestChild="true"
 		android:layout_width="match_parent"
 		android:layout_height="wrap_content"
 		android:layout_weight="0">
-        <Button android:id="@+id/goto_options_model"
+    <Button android:id="@+id/goto_options_model"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="Model">
-        </Button>
-        <Button android:id="@+id/goto_options_display"
+    </Button>
+    <Button android:id="@+id/goto_options_display"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="Display">
-        </Button>
-    </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
+    </Button>
+  </LinearLayout>
+  
+</LinearLayout>
diff --git a/contrib/mobile/Android/res/layout/fragment_options_display.xml b/contrib/mobile/Android/res/layout/fragment_options_display.xml
index beba95b..480d0ae 100644
--- a/contrib/mobile/Android/res/layout/fragment_options_display.xml
+++ b/contrib/mobile/Android/res/layout/fragment_options_display.xml
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <org.geuz.onelab.SeparatedListView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:id="@+id/displayOptionsList">
-    
-
-</org.geuz.onelab.SeparatedListView>
\ No newline at end of file
+                                   android:layout_width="match_parent"
+                                   android:layout_height="match_parent"
+                                   android:id="@+id/displayOptionsList">
+</org.geuz.onelab.SeparatedListView>
diff --git a/contrib/mobile/Android/res/layout/list_header.xml b/contrib/mobile/Android/res/layout/list_header.xml
index bf26b6d..9244e49 100644
--- a/contrib/mobile/Android/res/layout/list_header.xml
+++ b/contrib/mobile/Android/res/layout/list_header.xml
@@ -1,13 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
-	android:id="@+id/list_header_title"
-	android:layout_width="fill_parent"
-	android:layout_height="wrap_content"
-	android:paddingTop="2dip"
-	android:paddingBottom="2dip"
-	android:paddingLeft="5dip"
-	style="?android:attr/listSeparatorTextViewStyle"
-	>
-    
-
+          android:id="@+id/list_header_title"
+          android:layout_width="fill_parent"
+          android:layout_height="wrap_content"
+          android:paddingTop="2dip"
+          android:paddingBottom="2dip"
+          android:paddingLeft="5dip"
+          style="?android:attr/listSeparatorTextViewStyle"
+          >
+  
 </TextView>
\ No newline at end of file
diff --git a/contrib/mobile/Android/res/layout/model.xml b/contrib/mobile/Android/res/layout/model.xml
index eed5d61..758dae0 100644
--- a/contrib/mobile/Android/res/layout/model.xml
+++ b/contrib/mobile/Android/res/layout/model.xml
@@ -6,22 +6,19 @@
 
     <ImageView
         android:id="@+id/icon"
-        android:layout_width="0dp"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:adjustViewBounds="true"
+        android:layout_height="100dp"
+        android:layout_width="100dp"
+	android:layout_gravity="center"
         android:contentDescription="preview"
-        android:layout_weight="25."
         android:src="@drawable/ic_launcher"
-        android:paddingRight="10dp"
+	android:paddingRight="10dp"
         android:paddingTop="5dp"
         android:paddingBottom="10dp" />
 
     <LinearLayout
-        android:layout_width="0dp"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:layout_weight="70." >
+        android:orientation="vertical">
 
         <TextView
             android:id="@+id/title"
@@ -41,4 +38,4 @@
 
     </LinearLayout>
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/contrib/mobile/Android/res/layout/splash.xml b/contrib/mobile/Android/res/layout/splash.xml
index 44c7278..4091ae1 100644
--- a/contrib/mobile/Android/res/layout/splash.xml
+++ b/contrib/mobile/Android/res/layout/splash.xml
@@ -1,23 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent" >
-
-	<ImageView android:id="@+id/splashImage"
-	    android:layout_centerInParent="true"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:contentDescription="@string/app_name"
-		android:src="@drawable/ic_launcher" />
-	<TextView android:id="@+id/splashTitle"
-	    android:layout_below="@id/splashImage"
-	    android:layout_width="fill_parent"
-	    android:gravity="center"
-		android:layout_height="wrap_content"
-	    android:text="ONELAB for Android"
-	    android:textSize="24dp"
-		android:textStyle="bold"/>
-
-    
-
-</RelativeLayout>
\ No newline at end of file
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" >
+  <ImageView android:id="@+id/splashImage"
+             android:layout_centerInParent="true"
+             android:layout_width="wrap_content"
+             android:layout_height="wrap_content"
+             android:contentDescription="@string/app_name"
+             android:src="@drawable/ic_launcher" />
+</RelativeLayout>
diff --git a/contrib/mobile/Android/res/raw/models.zip b/contrib/mobile/Android/res/raw/models.zip
deleted file mode 100644
index c0c8cc6..0000000
Binary files a/contrib/mobile/Android/res/raw/models.zip and /dev/null differ
diff --git a/contrib/mobile/Android/res/values/strings.xml b/contrib/mobile/Android/res/values/strings.xml
index 7667365..30b32ac 100644
--- a/contrib/mobile/Android/res/values/strings.xml
+++ b/contrib/mobile/Android/res/values/strings.xml
@@ -1,20 +1,20 @@
 <resources>
-
-    <string name="app_name">Onelab</string>
-    <string name="button_open_file">Open file</string>
-    <string name="button_ok">OK</string>
-    <string name="button_recalculate_param">Recalulate with new parameters</string>
-    <string name="dialog_title_choosefile">Choose a file</string>
-    <string name="error_nosdcard">No SDcard found on your device</string>
-    <string name="title_activity_main">Onelab</string>
-    <string name="title_activity_options">Parameters</string>
-    <string name="error_nomshfile">No compatible files or directories in this folder</string>
-    <string name="title_share">Share screenshot with …</string>
-    <string name="menu_share">Share screenshot</string>
-    <string name="menu_parameters">Parameters</string>
-    <string name="menu_run">Run</string>
-    <string name="menu_stop">Stop</string>
-    <string name="postpro_intervalstype">Intervals type</string>
-    <string name="postpro_intervals">Intervals</string>
-	<string name="postpro_raisez">Raise (Z)</string>
-</resources>
\ No newline at end of file
+  <string name="app_name">Onelab</string>
+  <string name="button_open_file">Open file</string>
+  <string name="button_ok">OK</string>
+  <string name="button_recalculate_param">Recompute with new parameters</string>
+  <string name="dialog_title_choosefile">Choose a file</string>
+  <string name="error_nosdcard">No SDcard found on your device</string>
+  <string name="title_activity_main">Onelab</string>
+  <string name="title_activity_about">About</string>
+  <string name="title_activity_options">Parameters</string>
+  <string name="error_nomshfile">No compatible files or directories in this folder</string>
+  <string name="title_share">Share screenshot with …</string>
+  <string name="menu_share">Share screenshot</string>
+  <string name="menu_parameters">Parameters</string>
+  <string name="menu_run">Run</string>
+  <string name="menu_stop">Stop</string>
+  <string name="postpro_intervalstype">Intervals type</string>
+  <string name="postpro_intervals">Intervals</string>
+  <string name="postpro_raisez">Raise (Z)</string>
+</resources>
diff --git a/contrib/mobile/Android/res/values/styles.xml b/contrib/mobile/Android/res/values/styles.xml
index 4dba0d0..a0978b3 100644
--- a/contrib/mobile/Android/res/values/styles.xml
+++ b/contrib/mobile/Android/res/values/styles.xml
@@ -1,5 +1,3 @@
 <resources>
-
-    <style name="AppTheme" parent="android:Theme.Light" />
-
-</resources>
\ No newline at end of file
+  <style name="AppTheme" parent="android:Theme.Light" />
+</resources>
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/AboutActivity.java b/contrib/mobile/Android/src/org/geuz/onelab/AboutActivity.java
new file mode 100644
index 0000000..708de71
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/AboutActivity.java
@@ -0,0 +1,40 @@
+package org.geuz.onelab;
+
+import java.lang.String;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.view.MenuItem;
+import android.webkit.WebView;
+
+public class AboutActivity extends Activity{
+
+    protected void onCreate(android.os.Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getActionBar().setDisplayHomeAsUpEnabled(true);
+        WebView webview = new WebView(this);
+        String aboutGmsh = Gmsh.getAboutGmsh();
+        String aboutGetDP = Gmsh.getAboutGetDP();
+        String aboutOnelab = "<p> </p><center><h3>Onelab/Mobile</h3>";
+        try {
+            aboutOnelab += "Version "+this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName;
+        }
+        catch (android.content.pm.PackageManager.NameNotFoundException e) {
+            aboutOnelab += "Version ?.?.?";
+        }
+        aboutOnelab += "<p>Copyright (C) 2014 Christophe Geuzaine and Maxime Graulich, University of Liège</p>";
+        aboutOnelab += "<p>Visit <a href=\"http://onelab.info/\">http://onelab.info/</a> for more information</p>";
+        aboutOnelab += "<p> </p><p>This version of Onelab/Mobile contains:</p>";
+        webview.loadDataWithBaseURL("", aboutOnelab + aboutGmsh + aboutGetDP, "text/html", "UTF-8", "");
+        setContentView(webview);
+    }
+    @Override
+	public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        if(item.getItemId() == android.R.id.home) {
+            Intent returnIntent = new Intent();
+            this.setResult(RESULT_CANCELED, returnIntent);
+            this.finish();
+        }
+        return super.onMenuItemSelected(featureId, item);
+    }
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java b/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java
index 9790ee8..7016016 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/GLESRender.java
@@ -10,66 +10,51 @@ import android.opengl.GLSurfaceView.Renderer;
 
 public class GLESRender implements Renderer{
 
-	private Gmsh mGModel;
-	private int _width, _height;
-	private Bitmap _screenshot;
-	private boolean _needScreenshot;
+    private Gmsh mGModel;
+    private int _width, _height;
+    private Bitmap _screenshot;
+    private boolean _needScreenshot;
 
-	public GLESRender(Gmsh model) {
-		this.mGModel = model;
-		_needScreenshot = false;
-	}
-	
-	public void load(String filename){
-		mGModel.load(filename);
-	}
-	
-	public void startInteraction(float x, float y) {
-		mGModel.startEvent(x, y);
-	}
-	public void endInteraction(float x, float y) {
-		mGModel.endEvent(x, y);
-	}
-	public void rotateModel(float x, float y) {
-		mGModel.rotate(x, y);
-	}
-	public void scaleModel(float s) {
-		mGModel.scale(s);
-	}
-	public void translateModel(float x, float y) {
-		mGModel.translate(x, y);
-	}
-	public void resetModelPosition() {
-		mGModel.resetPosition();
-	}
-	public void viewX() { mGModel.viewX();}
-	public void viewY() { mGModel.viewY();}
-	public void viewZ() { mGModel.viewZ();}
-	
-	// OpenGL ES methods
-	public void onDrawFrame(GL10 gl) {
-		mGModel.viewDraw();
-		if(_needScreenshot) this.screenshot(gl);
-	}
+    public GLESRender(Gmsh model)
+    {
+        this.mGModel = model;
+        _needScreenshot = false;
+    }
+    public void load(String filename){ mGModel.load(filename); }
+    public void startInteraction(float x, float y) { mGModel.startEvent(x, y); }
+    public void endInteraction(float x, float y) { mGModel.endEvent(x, y); }
+    public void rotateModel(float x, float y) { mGModel.rotate(x, y); }
+    public void scaleModel(float s) { mGModel.scale(s); }
+    public void translateModel(float x, float y) { mGModel.translate(x, y); }
+    public void resetModelPosition() { mGModel.resetPosition(); }
+    public void viewX() { mGModel.viewX();}
+    public void viewY() { mGModel.viewY();}
+    public void viewZ() { mGModel.viewZ();}
 
-	public void onSurfaceChanged(GL10 gl, int width, int height) {
-		mGModel.viewInit(width, height);
-		_width = width;
-		_height = height;
-	}
+    // OpenGL ES methods
+    public void onDrawFrame(GL10 gl)
+    {
+        mGModel.viewDraw();
+        if(_needScreenshot) this.screenshot(gl);
+    }
+    public void onSurfaceChanged(GL10 gl, int width, int height)
+    {
+        mGModel.viewInit(width, height);
+        _width = width;
+        _height = height;
+    }
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) { }
+    public void needScreenshot() {_screenshot = null; _needScreenshot = true;}
+    public Bitmap getScreenshot(){return _screenshot;}
+    private void screenshot(GL10 gl)
+    {
+        _needScreenshot = false;
+        int bitmapBuffer[] = new int[_width * _height];
+        int bitmapSource[] = new int[_width * _height];
+        IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
+        intBuffer.position(0);
 
-	public void onSurfaceCreated(GL10 gl, EGLConfig config) { }
-	public void needScreenshot() {_screenshot = null; _needScreenshot = true;}
-	public Bitmap getScreenshot(){return _screenshot;}
-	private void screenshot(GL10 gl)
-	{
-		_needScreenshot = false;
-		int bitmapBuffer[] = new int[_width * _height];
-	    int bitmapSource[] = new int[_width * _height];
-	    IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer);
-	    intBuffer.position(0);
-
-	    gl.glReadPixels(0, 0, _width, _height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer);
+        gl.glReadPixels(0, 0, _width, _height, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer);
         int offset1, offset2;
         for (int i = 0; i < _height; i++) {
             offset1 = i * _width;
@@ -80,5 +65,5 @@ public class GLESRender implements Renderer{
             }
         }
         _screenshot = Bitmap.createBitmap(bitmapSource, _width, _height, Bitmap.Config.ARGB_8888);
-	}
+    }
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java b/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java
index 9433fda..cf7dc24 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/Gmsh.java
@@ -5,118 +5,125 @@ import android.os.Parcel;
 import android.os.Parcelable;
 
 public class Gmsh implements Parcelable {
-	/** From C / C++ code **/
-	static {
-		System.loadLibrary("f2cblas");
-		System.loadLibrary("f2clapack");
-		System.loadLibrary("petsc");
-		System.loadLibrary("Gmsh");
-		System.loadLibrary("GetDP");
-		System.loadLibrary("Onelab");
-    }
-	private native long init(); // Init Gmsh
-	private native void loadFile(long ptr, String name); // load a file(OpenProjet)
-	private native void initView(long ptr, int w, int h); // Called each time the GLView change
-	private native void drawView(long ptr); // Called each time the GLView request a render
-	private native void eventHandler(long ptr, int event, float x, float y);
-	public native String[] getParams(); // return the parameters for onelab
-	public native int setParam(String type, String name, String value); // change a parameters
-	public native int setStringOption(String category, String name, String value);
-	public native int setDoubleOption(String category, String name, double value);
-	public native int setIntegerOption(String category, String name, int value);
-	public native String getStringOption(String category, String name);
-	public native double getDoubleOption(String category, String name);
-	public native int getIntegerOption(String category, String name);
-	public native String[] getPView(); // get a list of PViews
-	public native void setPView(int position, int intervalsType,int visible,int nbIso, float raisez); // Change options for a PView
-	public native int onelabCB(String action); // Call onelab
-
-	public boolean haveAnimation() {return numberOfAnimation() > 1;}
-	public native int numberOfAnimation();
-	public native int animationNext();
-	public native int animationPrev();
-	public native void setAnimation(int animation);
-
-	/** Java CLASS **/
-	private long ptr;
-	private Handler handler;
-
-	public Gmsh(Handler handler) {
-		ptr = this.init();
-		this.handler = handler;
-	}
-
-	public void viewInit(int w, int h) {
-		this.initView(ptr, w, h);
-	}
-
-	public void viewDraw() {
-		this.drawView(ptr);
-	}
-
-	public void load(String filename){
-		this.loadFile(ptr, filename);
-	}
+    /** From C / C++ code **/
+    static {
+        System.loadLibrary("f2cblas");
+        System.loadLibrary("f2clapack");
+        System.loadLibrary("petsc");
+        System.loadLibrary("Gmsh");
+        System.loadLibrary("GetDP");
+        System.loadLibrary("Onelab");
+    }
+    private native long init(float fontFactor); // Init Gmsh
+    private native void loadFile(long ptr, String name); // load a file(OpenProjet)
+    private native void initView(long ptr, int w, int h); // Called each time the GLView change
+    private native void drawView(long ptr); // Called each time the GLView request a render
+    private native void eventHandler(long ptr, int event, float x, float y);
+    public native String[] getParams(); // return the parameters for onelab
+    public native int setParam(String type, String name, String value); // change a parameters
+    public native int setStringOption(String category, String name, String value);
+    public native int setDoubleOption(String category, String name, double value);
+    public native int setIntegerOption(String category, String name, int value);
+    public native String getStringOption(String category, String name);
+    public native double getDoubleOption(String category, String name);
+    public native int getIntegerOption(String category, String name);
+    public native String[] getPView(); // get a list of PViews
+    public native void setPView(int position, int intervalsType,int visible,int nbIso, float raisez); // Change options for a PView
+    public native int onelabCB(String action); // Call onelab
 
-	public void startEvent(float x, float y)
-	{
-		this.eventHandler(ptr, 0, x, y);
-	}
-	public void translate(float x, float y)
-	{
-		this.eventHandler(ptr, 1, x, y);
-	}
-	public void scale(float s)
-	{
-		this.eventHandler(ptr, 2, s, 0);
-	}
-	public void rotate(float x, float y)
-	{
-		this.eventHandler(ptr, 3, x, y);
-	}
-	public void viewX() { this.eventHandler(ptr, 5, 0, 0);}
-	public void viewY() { this.eventHandler(ptr, 6, 0, 0);}
-	public void viewZ() { this.eventHandler(ptr, 7, 0, 0);}
-	public void endEvent(float x, float y)
-	{
-		this.eventHandler(ptr, 4, x, y);
-	}
-	public void resetPosition()
-	{
-		this.eventHandler(ptr, 10, 0, 0);
-	}
-	public void ShowPopup(String message) {
-		if(handler != null)
-			handler.obtainMessage(0, message).sendToTarget();
-	}
-	public void RequestRender() {
-		if(handler != null)
-			handler.obtainMessage(1).sendToTarget();
-	}
-	public void SetLoading(String message) {
-		if(handler != null)
-			handler.obtainMessage(2, message).sendToTarget();
-	}
-	public void SetLoading(int percent) {
-		if(handler != null)
-			handler.obtainMessage(3, percent, 100).sendToTarget();
-	}
-	// Parcelable methods/constructors
-	private Gmsh(Parcel in) {
-		this.ptr = in.readLong();
-	}
-	public int describeContents() {return 0;}
-	public void writeToParcel(Parcel out, int flags) {
-		out.writeLong(this.ptr);
-	}
-	public static Parcelable.Creator<Gmsh> CREATOR = new Parcelable.Creator<Gmsh>() {
+    public boolean haveAnimation() {return numberOfAnimation() > 1;}
+    public native int numberOfAnimation();
+    public native int animationNext();
+    public native int animationPrev();
+    public native void setAnimation(int animation);
 
-		public Gmsh createFromParcel(Parcel source) {
-			return new Gmsh(source);
-		}
+    public static native String getAboutGmsh();
+    public static native String getAboutGetDP();
 
-		public Gmsh[] newArray(int size) {
-			return new Gmsh[size];
-		}
-	};
+    /** Java CLASS **/
+    private long ptr;
+    private Handler handler;
+    public Gmsh(Handler handler, float fontFactor)
+    {
+        ptr = this.init(fontFactor);
+        this.handler = handler;
+    }
+    public void viewInit(int w, int h)
+    {
+        this.initView(ptr, w, h);
+    }
+    public void viewDraw()
+    {
+        this.drawView(ptr);
+    }
+    public void load(String filename)
+    {
+        this.loadFile(ptr, filename);
+    }
+    public void startEvent(float x, float y)
+    {
+        this.eventHandler(ptr, 0, x, y);
+    }
+    public void translate(float x, float y)
+    {
+        this.eventHandler(ptr, 1, x, y);
+    }
+    public void scale(float s)
+    {
+        this.eventHandler(ptr, 2, s, 0);
+    }
+    public void rotate(float x, float y)
+    {
+        this.eventHandler(ptr, 3, x, y);
+    }
+    public void viewX() { this.eventHandler(ptr, 5, 0, 0);}
+    public void viewY() { this.eventHandler(ptr, 6, 0, 0);}
+    public void viewZ() { this.eventHandler(ptr, 7, 0, 0);}
+    public void endEvent(float x, float y)
+    {
+        this.eventHandler(ptr, 4, x, y);
+    }
+    public void resetPosition()
+    {
+        this.eventHandler(ptr, 10, 0, 0);
+    }
+    public void ShowPopup(String message) {
+        if(handler != null)
+            handler.obtainMessage(0, message).sendToTarget();
+    }
+    public void RequestRender() {
+        if(handler != null)
+            handler.obtainMessage(1).sendToTarget();
+    }
+    public void SetLoading(String message)
+    {
+        if(handler != null)
+            handler.obtainMessage(2, message).sendToTarget();
+    }
+    public void SetLoading(int percent)
+    {
+        if(handler != null)
+            handler.obtainMessage(3, percent, 100).sendToTarget();
+    }
+    // Parcelable methods/constructors
+    private Gmsh(Parcel in)
+    {
+        this.ptr = in.readLong();
+    }
+    public int describeContents() {return 0;}
+    public void writeToParcel(Parcel out, int flags)
+    {
+        out.writeLong(this.ptr);
+    }
+    public static Parcelable.Creator<Gmsh> CREATOR = new Parcelable.Creator<Gmsh>()
+    {
+        public Gmsh createFromParcel(Parcel source)
+        {
+            return new Gmsh(source);
+        }
+        public Gmsh[] newArray(int size)
+        {
+            return new Gmsh[size];
+        }
+    };
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java b/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java
index 0234b37..7648795 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/MainActivity.java
@@ -33,70 +33,69 @@ import android.widget.Toast;
 
 public class MainActivity extends Activity{
 
-	private Gmsh _gmsh;
-	private boolean _compute, _twoPane, _notify;
-	private MenuItem _runStopMenuItem, _switchFragmentMenuItem;
-	private ModelFragment _modelFragment;
-	private OptionsFragment _optionsFragment;
-	private ArrayList<String> _errors = new ArrayList<String>();
-	private Dialog _errorDialog;
+    private Gmsh _gmsh;
+    private boolean _compute, _twoPane, _notify;
+    private MenuItem _runStopMenuItem, _switchFragmentMenuItem;
+    private ModelFragment _modelFragment;
+    private OptionsFragment _optionsFragment;
+    private ArrayList<String> _errors = new ArrayList<String>();
+    private Dialog _errorDialog;
 
-	public MainActivity() {
-	}
-	
-	@Override
+    public MainActivity() { }
+
+    @Override
 	protected void onCreate(Bundle savedInstanceState) {
-		super.onCreate(savedInstanceState);
-		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
-		getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
-		setContentView(R.layout.main_activity_layout);
-		_gmsh = new Gmsh(mainHandler);
-		_notify = false;
-		ActionBar actionBar = getActionBar();
-		actionBar.setDisplayHomeAsUpEnabled(true);
-		actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#64000000")));
-		Intent intent = getIntent();
+        super.onCreate(savedInstanceState);
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
+        getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+        setContentView(R.layout.main_activity_layout);
+        _gmsh = new Gmsh(mainHandler, getResources().getDisplayMetrics().density);
+        _notify = false;
+        ActionBar actionBar = getActionBar();
+        actionBar.setDisplayHomeAsUpEnabled(true);
+        actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#64000000")));
+        Intent intent = getIntent();
     	Bundle extras = intent.getExtras();
     	if(savedInstanceState != null);
     	else if(intent.getAction() != null && intent.getAction().equals(Intent.ACTION_VIEW)) {
-    		String tmp = intent.getData().getPath();
-    		_gmsh.load(tmp);
-    	}  		
+            String tmp = intent.getData().getPath();
+            _gmsh.load(tmp);
+    	}
     	else if(extras != null) {
-    		String name = extras.getString("name");
-    		this.getActionBar().setTitle(name);
-    		String tmp = extras.getString("file");
-    		_gmsh.load(tmp);
+            String name = extras.getString("name");
+            this.getActionBar().setTitle(name);
+            String tmp = extras.getString("file");
+            _gmsh.load(tmp);
     	}
     	else
-    		this.finish();
+            this.finish();
     	_twoPane = (findViewById(R.id.parameter_fragment) != null);
     	_modelFragment = ModelFragment.newInstance(_gmsh);
-		getFragmentManager().beginTransaction().replace(R.id.model_fragment, _modelFragment).commit();
+        getFragmentManager().beginTransaction().replace(R.id.model_fragment, _modelFragment).commit();
     	if(_twoPane) {
-    		_optionsFragment = OptionsFragment.newInstance(_gmsh);
-    		getFragmentManager().beginTransaction().replace(R.id.parameter_fragment, _optionsFragment).commit();
-    		_optionsFragment.setOnOptionsChangedListener(new OptionsFragment.OnOptionsChangedListener() {
-    			
-    			public void OnOptionsChanged() {
-    				_modelFragment.requestRender();
-    			}
+            _optionsFragment = OptionsFragment.newInstance(_gmsh);
+            getFragmentManager().beginTransaction().replace(R.id.parameter_fragment, _optionsFragment).commit();
+            _optionsFragment.setOnOptionsChangedListener(new OptionsFragment.OnOptionsChangedListener() {
+
+                    public void OnOptionsChanged() {
+                        _modelFragment.requestRender();
+                    }
     		});
     	}
-	}
-	
-	@Override
+    }
+
+    @Override
 	protected void onSaveInstanceState(Bundle outState) {
-		outState.putBoolean("Compute", _compute);
-		super.onSaveInstanceState(outState);
-	}
-	
-	@Override
-    public boolean onCreateOptionsMenu(Menu menu) {
+        outState.putBoolean("Compute", _compute);
+        super.onSaveInstanceState(outState);
+    }
+
+    @Override
+        public boolean onCreateOptionsMenu(Menu menu) {
     	super.onCreateOptionsMenu(menu);
     	if(!_twoPane) {
-    		_switchFragmentMenuItem = menu.add(R.string.menu_parameters);
-    		_switchFragmentMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            _switchFragmentMenuItem = menu.add(R.string.menu_parameters);
+            _switchFragmentMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
     	}
     	_runStopMenuItem = menu.add((_compute)?R.string.menu_stop:R.string.menu_run);
     	_runStopMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
@@ -104,247 +103,247 @@ public class MainActivity extends Activity{
     	shareMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         return true;
     }
-	@Override
+    @Override
 	public boolean onMenuOpened(int featureId, Menu menu) {
-		_modelFragment.postDelay();
-		return super.onMenuOpened(featureId, menu);
-	}
-	@Override
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        _modelFragment.postDelay();
+        return super.onMenuOpened(featureId, menu);
+    }
+    @Override
+        public boolean onMenuItemSelected(int featureId, MenuItem item) {
     	if (item.getTitle().equals(getString(R.string.menu_parameters))) {
-    		Intent intent = new Intent(this, OptionsActivity.class);
-		    intent.putExtra("Gmsh", (Parcelable)_gmsh);
-		    intent.putExtra("Compute", _compute);
-			startActivityForResult(intent, 1);
-			_modelFragment.requestRender();
+            Intent intent = new Intent(this, OptionsActivity.class);
+            intent.putExtra("Gmsh", (Parcelable)_gmsh);
+            intent.putExtra("Compute", _compute);
+            startActivityForResult(intent, 1);
+            _modelFragment.requestRender();
     	}
     	else if(item.getTitle().equals(getString(R.string.menu_run))){
-    		if(_modelFragment != null) _modelFragment.hideControlBar();
-    		new Run().execute();
+            if(_modelFragment != null) _modelFragment.hideControlBar();
+            new Run().execute();
     	}
     	else if(item.getTitle().equals(getString(R.string.menu_stop))){
-    		_runStopMenuItem.setEnabled(false);
-    		_gmsh.onelabCB("stop");
+            _runStopMenuItem.setEnabled(false);
+            _gmsh.onelabCB("stop");
     	}
     	else if(item.getTitle().equals(getString(R.string.menu_share))) {
-    		if(this._compute) {
-				AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
-    			_errorDialog = dialogBuilder.setTitle("Can't show the models list")
-    			.setMessage("The computing have to be finished before you can take a screenshot.")
-    			.setPositiveButton("OK", new DialogInterface.OnClickListener() {
-					
-					public void onClick(DialogInterface dialog, int which) {
-						dialog.dismiss();
-					}
-				})
-    			.show();
-    		}
-    		else {
-    			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss");
-    			File file = new File(this.getExternalFilesDir(null), "onelab-screenshot-"+dateFormat.format(new Date())+".png");
-    			file.setReadable(true, false);
-    			_modelFragment.takeScreenshot(file);
-    			Intent shareIntent = new Intent();
-    			shareIntent.setAction(Intent.ACTION_SEND);
-    			shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
-    			shareIntent.setType("image/jpeg");
-    			startActivity(Intent.createChooser(shareIntent, getString(R.string.title_share)));
-    		}
+            if(this._compute) {
+                AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
+                _errorDialog = dialogBuilder.setTitle("Can't show the model list")
+                    .setMessage("The computation has to complete before you can take a screenshot")
+                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+
+                            public void onClick(DialogInterface dialog, int which) {
+                                dialog.dismiss();
+                            }
+                        })
+                    .show();
+            }
+            else {
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd-HH_mm_ss");
+                File file = new File(this.getExternalFilesDir(null), "onelab-screenshot-"+dateFormat.format(new Date())+".png");
+                file.setReadable(true, false);
+                _modelFragment.takeScreenshot(file);
+                Intent shareIntent = new Intent();
+                shareIntent.setAction(Intent.ACTION_SEND);
+                shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
+                shareIntent.setType("image/jpeg");
+                startActivity(Intent.createChooser(shareIntent, getString(R.string.title_share)));
+            }
     	}
-		else if(item.getItemId() == android.R.id.home) {
-			if(this._compute) {
-				AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
-    			_errorDialog = dialogBuilder.setTitle("Can't show the models list")
-    			.setMessage("The computing have to be finished before you can select an other model.")
-    			.setPositiveButton("OK", new DialogInterface.OnClickListener() {
-					
-					public void onClick(DialogInterface dialog, int which) {
-						dialog.dismiss();
-					}
-				})
-    			.show();
-    		}
-    		else
-    			this.finish();
-		}
+        else if(item.getItemId() == android.R.id.home) {
+            if(this._compute) {
+                AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
+                _errorDialog = dialogBuilder.setTitle("Can't show the model list")
+                    .setMessage("The computation has to complete before you can select another model")
+                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+
+                            public void onClick(DialogInterface dialog, int which) {
+                                dialog.dismiss();
+                            }
+                        })
+                    .show();
+            }
+            else
+                this.finish();
+        }
     	return super.onMenuItemSelected(featureId, item);
     }
-	
-	@Override
+
+    @Override
 	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-		super.onActivityResult(requestCode, resultCode, data);
-		switch (requestCode) {
-		case 1:
-			if(resultCode == RESULT_OK)
-				if(!_compute && data.getBooleanExtra("Compute", false)) new Run().execute();
-			break;
-		}
-	}
-	
-	public String getRealPathFromURI(Uri contentUri) {
+        super.onActivityResult(requestCode, resultCode, data);
+        switch (requestCode) {
+        case 1:
+            if(resultCode == RESULT_OK)
+                if(!_compute && data.getBooleanExtra("Compute", false)) new Run().execute();
+            break;
+        }
+    }
+
+    public String getRealPathFromURI(Uri contentUri) {
         String[] proj = { MediaStore.Images.Media.DATA };
         Cursor cursor = managedQuery(contentUri, proj, null, null, null);
         int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
         cursor.moveToFirst();
         return cursor.getString(column_index);
     }
-	
-	private class Run extends AsyncTask<Void, Void, Integer[]> {
+
+    private class Run extends AsyncTask<Void, Void, Integer[]> {
 
     	@Override
-    	protected void onPreExecute() {
-    		_compute = true;
-    		_runStopMenuItem.setTitle(R.string.menu_stop);
-    		super.onPreExecute();
+            protected void onPreExecute() {
+            _compute = true;
+            _runStopMenuItem.setTitle(R.string.menu_stop);
+            super.onPreExecute();
     	}
-    	
-		@Override
-		protected Integer[] doInBackground(Void... params) {
-			_gmsh.onelabCB("compute");
-			return new Integer[] {1};
-		}
 
-		@Override
-		protected void onPostExecute(Integer[] result) {
-			//(Vibrator) getSystemService(Context.VIBRATOR_SERVICE).vibrate(350);
-			_runStopMenuItem.setTitle(R.string.menu_run);
-			_runStopMenuItem.setEnabled(true);
-			if(_modelFragment != null) _modelFragment.hideProgress();
-			_compute = false;
-			if(_notify) notifyEndComputing();
-			super.onPostExecute(result);
-		}
-    	
+        @Override
+            protected Integer[] doInBackground(Void... params) {
+            _gmsh.onelabCB("compute");
+            return new Integer[] {1};
+        }
+
+        @Override
+            protected void onPostExecute(Integer[] result) {
+            //(Vibrator) getSystemService(Context.VIBRATOR_SERVICE).vibrate(350);
+            _runStopMenuItem.setTitle(R.string.menu_run);
+            _runStopMenuItem.setEnabled(true);
+            if(_modelFragment != null) _modelFragment.hideProgress();
+            _compute = false;
+            if(_notify) notifyEndComputing();
+            super.onPostExecute(result);
+        }
+
     }
-	private void showError(){
+    private void showError(){
     	if(_errors.size()>0){
-    		if(_errorDialog != null && _errorDialog.isShowing()) _errorDialog.dismiss();
-    		AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
-    		dialogBuilder.setTitle("Gmsh/GetDP Error(s)")
-		    .setMessage(_errors.get(_errors.size()-1))
-		    .setNegativeButton("Hide", new DialogInterface.OnClickListener() {
-		        public void onClick(DialogInterface dialog, int which) {
-		        	_errors.clear();
-		        	_errorDialog.dismiss();
-		        }
-		     });
-    		if(_errors.size()>1)dialogBuilder.setPositiveButton("Show more", new DialogInterface.OnClickListener() {
+            if(_errorDialog != null && _errorDialog.isShowing()) _errorDialog.dismiss();
+            AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
+            dialogBuilder.setTitle("Gmsh/GetDP Error(s)")
+                .setMessage(_errors.get(_errors.size()-1))
+                .setNegativeButton("Hide", new DialogInterface.OnClickListener() {
 		        public void onClick(DialogInterface dialog, int which) {
-		        	_errors.remove(_errors.size()-1);
-		        	_errorDialog.dismiss();
-		            showError();
+                            _errors.clear();
+                            _errorDialog.dismiss();
 		        }
-		     });
-		     _errorDialog = dialogBuilder.show();
+                    });
+            if(_errors.size()>1)dialogBuilder.setPositiveButton("Show more", new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        _errors.remove(_errors.size()-1);
+                        _errorDialog.dismiss();
+                        showError();
+                    }
+                });
+            _errorDialog = dialogBuilder.show();
     	}
     }
-	@Override
+    @Override
 	protected void onPause() {
-		if(_compute) notifyComputing();
-		super.onPause();
-		_notify = true;
-	}
-	
-	@Override
+        if(_compute) notifyComputing();
+        super.onPause();
+        _notify = true;
+    }
+
+    @Override
 	protected void onResume() {
-		super.onResume();
-		NotificationManager mNotificationManager =
-			    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-		mNotificationManager.cancel(1337);
-		_notify = false;
-	}
-	
-	@Override
+        super.onResume();
+        NotificationManager mNotificationManager =
+            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+        mNotificationManager.cancel(1337);
+        _notify = false;
+    }
+
+    @Override
 	protected void onStop() {
-		super.onStop();
-		if(_compute) notifyComputing();
-		_notify = true;
-	}
-	
-	@Override
+        super.onStop();
+        if(_compute) notifyComputing();
+        _notify = true;
+    }
+
+    @Override
 	public void onLowMemory() {
-		if(!_compute) return;
-		_gmsh.onelabCB("stop");
-		Toast.makeText(this, "Low memory !!! computing is going to stop", Toast.LENGTH_LONG).show();
-		super.onLowMemory();
-	}
-	
-	@Override
+        if(!_compute) return;
+        _gmsh.onelabCB("stop");
+        Toast.makeText(this, "Low memory! Computation is going to stop", Toast.LENGTH_LONG).show();
+        super.onLowMemory();
+    }
+
+    @Override
 	public void onTrimMemory(int level) {
-		if(!_compute) return;
-		if(level == Activity.TRIM_MEMORY_COMPLETE){
-			_gmsh.onelabCB("stop");
-			notifyEndComputing("The computing had to stop because your device ran out of memory");
-			_notify = false;
-		}
-		else if(level == Activity.TRIM_MEMORY_MODERATE) {
-			notifyComputing("Computing in progress - low memory", true);
-		}
-		super.onTrimMemory(level);
-	}
-	
-	private void notifyComputing(String msg, boolean alert) {
-		Intent intent = new Intent(this, MainActivity.class);
-	    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
-	    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-	    Notification.Builder notifyBuilder = new Notification.Builder(this);
-		notifyBuilder.setContentTitle("ONELAB")
-			.setContentIntent(pendingIntent)
-		    .setContentText(msg)
-		    .setSmallIcon(R.drawable.ic_launcher)
-		    .setProgress(0, 0, true);
-		if(alert) notifyBuilder.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
-		NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-		mNotificationManager.notify(1337, notifyBuilder.getNotification());
-	}
-	
-	private void notifyComputing() {
-		notifyComputing("Computing in progress", false);
-	}
-	
-	private void notifyEndComputing() {
-		notifyEndComputing("The computing is finished");
-	}
-	
-	private void notifyEndComputing(String msg) {
-		Intent intent = new Intent(this, MainActivity.class);
-	    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
-	    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-		Notification.Builder notifyBuilder = new Notification.Builder(this)
-		        .setSmallIcon(R.drawable.ic_launcher)
-		        .setContentIntent(pendingIntent)
-		        .setContentTitle("ONELAB")
-		        .setDefaults(Notification.DEFAULT_ALL)
-		        .setAutoCancel(true)
-		        .setProgress(0, 0, false)
-		        .setContentText(msg);
-		NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-		mNotificationManager.notify(1337, notifyBuilder.getNotification());
-	}
+        if(!_compute) return;
+        if(level == Activity.TRIM_MEMORY_COMPLETE){
+            _gmsh.onelabCB("stop");
+            notifyEndComputing("The computation had to stop because your device ran out of memory");
+            _notify = false;
+        }
+        else if(level == Activity.TRIM_MEMORY_MODERATE) {
+            notifyComputing("Computation in progress - low memory", true);
+        }
+        super.onTrimMemory(level);
+    }
 
-	private final Handler mainHandler = new Handler(){
-    	public void handleMessage(android.os.Message msg) {
+    private void notifyComputing(String msg, boolean alert) {
+        Intent intent = new Intent(this, MainActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+        Notification.Builder notifyBuilder = new Notification.Builder(this);
+        notifyBuilder.setContentTitle("ONELAB")
+            .setContentIntent(pendingIntent)
+            .setContentText(msg)
+            .setSmallIcon(R.drawable.ic_launcher)
+            .setProgress(0, 0, true);
+        if(alert) notifyBuilder.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE);
+        NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+        mNotificationManager.notify(1337, notifyBuilder.getNotification());
+    }
+
+    private void notifyComputing() {
+        notifyComputing("Computation in progress", false);
+    }
+
+    private void notifyEndComputing() {
+        notifyEndComputing("Computation done!");
+    }
+
+    private void notifyEndComputing(String msg) {
+        Intent intent = new Intent(this, MainActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+        Notification.Builder notifyBuilder = new Notification.Builder(this)
+            .setSmallIcon(R.drawable.ic_launcher)
+            .setContentIntent(pendingIntent)
+            .setContentTitle("ONELAB")
+            .setDefaults(Notification.DEFAULT_ALL)
+            .setAutoCancel(true)
+            .setProgress(0, 0, false)
+            .setContentText(msg);
+        NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+        mNotificationManager.notify(1337, notifyBuilder.getNotification());
+    }
+
+    private final Handler mainHandler = new Handler(){
+            public void handleMessage(android.os.Message msg) {
     		switch (msg.what) {
-			case 0: // we get a message from gmsh library
-				String message =(String) msg.obj;
-				_errors.add(message);
-				showError();
-				break;
-			case 1: // request render from gmsh library
-				if(_modelFragment != null) _modelFragment.requestRender();
-				if(_optionsFragment != null) _optionsFragment.refresh();
-				break;
-			case 2: // we get a message for loading
-				if(_modelFragment != null) _modelFragment.showProgress((String) msg.obj);
-				break;
-			case 3: // we get a progress for loading
-				//loading.setProgress(msg.arg1);
-				break;
-			default:
-				break;
-			}
-    	};
-    };
-    
+                case 0: // we get a message from gmsh library
+                    String message =(String) msg.obj;
+                    _errors.add(message);
+                    showError();
+                    break;
+                case 1: // request render from gmsh library
+                    if(_modelFragment != null) _modelFragment.requestRender();
+                    if(_optionsFragment != null) _optionsFragment.refresh();
+                    break;
+                case 2: // we get a message for loading
+                    if(_modelFragment != null) _modelFragment.showProgress((String) msg.obj);
+                    break;
+                case 3: // we get a progress for loading
+                    //loading.setProgress(msg.arg1);
+                    break;
+                default:
+                    break;
+                }
+            };
+        };
+
     public boolean isComputing() {return _compute;}
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/Model.java b/contrib/mobile/Android/src/org/geuz/onelab/Model.java
index 8b1b1bc..42419e3 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/Model.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/Model.java
@@ -6,37 +6,41 @@ import android.net.Uri;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 
-
 class Model {
-	private String _name, _summary;
-	private File _file;
-	private Bitmap _bitmap;
-	private Uri _url;
-	
-	public Model(String name, String summary, File file){
-		_name = name;
-		_summary = summary;
-		_file = file;
-	}
-	public String getName() {
-		return _name;
-	}
-	public String getSummary() {
-		return _summary;
-	}
-	public File getFile() {
-		return _file;
-	}
-	public Bitmap getBitmap() {
-		return _bitmap;
-	}
-	public Uri getUrl() {
-		return _url;
-	}
-	public void setBitmap(File f) {
-		_bitmap = BitmapFactory.decodeFile(f.toString());
-	}
-	public void setUrl(Uri url) {
-		_url = url;
-	}
+    private String _name, _summary;
+    private File _file;
+    private Bitmap _bitmap;
+    private Uri _url;
+
+    public Model(String name, String summary, File file){
+        _name = name;
+        _summary = summary;
+        _file = file;
+    }
+    public String getName() {
+        return _name;
+    }
+    public String getSummary() {
+        return _summary;
+    }
+    public File getFile() {
+        return _file;
+    }
+    public Bitmap getBitmap() {
+        return _bitmap;
+    }
+    public Uri getUrl() {
+        return _url;
+    }
+    public void setBitmap(File f) {
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inSampleSize = 8;
+        options.inJustDecodeBounds = false;
+        options.inPreferredConfig = Bitmap.Config.RGB_565;
+        options.inDither = true;
+        _bitmap = BitmapFactory.decodeFile(f.toString(), options);
+    }
+    public void setUrl(Uri url) {
+        _url = url;
+    }
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/ModelArrayAdapter.java b/contrib/mobile/Android/src/org/geuz/onelab/ModelArrayAdapter.java
index 1245b92..b6adf77 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/ModelArrayAdapter.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/ModelArrayAdapter.java
@@ -12,36 +12,36 @@ import android.widget.ImageView;
 import android.widget.TextView;
 
 public class ModelArrayAdapter extends ArrayAdapter<Model> {
-	private List<Model> _models;
-
-	public ModelArrayAdapter(Context c) {
-		super(c, R.layout.model);
-		_models = new ArrayList<Model>();
-	}
-	
-	@Override
+    private List<Model> _models;
+
+    public ModelArrayAdapter(Context c) {
+        super(c, R.layout.model);
+        _models = new ArrayList<Model>();
+    }
+
+    @Override
 	public void add(Model model) {
-		super.add(model);
-		_models.add(model);
-	}
-	
-	public Model getModel(int pos) {
-		return _models.get(pos);
-	}
-
-	@Override
+        super.add(model);
+        _models.add(model);
+    }
+
+    public Model getModel(int pos) {
+        return _models.get(pos);
+    }
+
+    @Override
 	public View getView(int position, View convertView, final ViewGroup parent) {
-		LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-		final Model m = _models.get(position);
-		View rowView = inflater.inflate(R.layout.model, parent, false);
-		TextView title = (TextView) rowView.findViewById(R.id.title);
-		TextView description = (TextView) rowView.findViewById(R.id.description);
-		ImageView icon = (ImageView) rowView.findViewById(R.id.icon);
-		if(m.getName() != null) title.setText(m.getName());
-		if(m.getSummary() != null) description.setText(m.getSummary());
-		if(m.getBitmap() != null) icon.setImageBitmap(m.getBitmap());
-		else icon.setImageResource(R.drawable.ic_launcher);
-		
-		return rowView;
-	}
+        LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        final Model m = _models.get(position);
+        View rowView = inflater.inflate(R.layout.model, parent, false);
+        TextView title = (TextView) rowView.findViewById(R.id.title);
+        TextView description = (TextView) rowView.findViewById(R.id.description);
+        ImageView icon = (ImageView) rowView.findViewById(R.id.icon);
+        if(m.getName() != null) title.setText(m.getName());
+        if(m.getSummary() != null) description.setText(m.getSummary());
+        if(m.getBitmap() != null) icon.setImageBitmap(m.getBitmap());
+        else icon.setImageResource(R.drawable.ic_launcher);
+
+        return rowView;
+    }
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/ModelFragment.java b/contrib/mobile/Android/src/org/geuz/onelab/ModelFragment.java
index 5545d77..caf7144 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/ModelFragment.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/ModelFragment.java
@@ -26,203 +26,232 @@ import android.widget.ProgressBar;
 import android.widget.RelativeLayout;
 import android.widget.SeekBar;
 import android.widget.TextView;
+import android.util.TypedValue;
 
 public class ModelFragment extends Fragment{
 
-	private Gmsh _gmsh;
-	private mGLSurfaceView _glView;
-	private TextView _progress;
-	private LinearLayout _progressLayout;
-	private LinearLayout _controlBarLayout;
-	private GestureDetector _gestureDetector;
-	private Timer _animation;
-	private Handler _hideDelay;
-	private SeekBar _animationStepper;
+    private Gmsh _gmsh;
+    private mGLSurfaceView _glView;
+    private TextView _progress;
+    private LinearLayout _progressLayout;
+    private LinearLayout _controlBarLayout;
+    private GestureDetector _gestureDetector;
+    private Timer _animation;
+    private Handler _hideDelay;
+    private SeekBar _animationStepper;
 
-	final Runnable hideControlsRunnable = new Runnable() {public void run() {hideControlBar();}};
+    final Runnable hideControlsRunnable = new Runnable() {
+            public void run() {hideControlBar();}
+        };
 
-	public static ModelFragment newInstance(Gmsh g) {
-		ModelFragment fragment = new ModelFragment();
-		Bundle bundle = new Bundle();
-		bundle.putParcelable("Gmsh", g);
-		fragment.setArguments(bundle);
+    public static ModelFragment newInstance(Gmsh g) {
+        ModelFragment fragment = new ModelFragment();
+        Bundle bundle = new Bundle();
+        bundle.putParcelable("Gmsh", g);
+        fragment.setArguments(bundle);
         return fragment;
     }
-	
-	public ModelFragment() {
-	}
 
-	@Override
+    public ModelFragment() {
+    }
+
+    @Override
 	public void onCreate(Bundle savedInstanceState) {
-		super.onCreate(savedInstanceState);
-		_gmsh = getArguments().getParcelable("Gmsh");
-	}
+        super.onCreate(savedInstanceState);
+        _gmsh = getArguments().getParcelable("Gmsh");
+    }
 
-	@Override
+    @Override
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
-			Bundle savedInstanceState) {
-		View rootView = inflater.inflate(R.layout.fragment_model, container, false);
-		RelativeLayout glViewLayout = (RelativeLayout)rootView.findViewById(R.id.glViewLayout);
-		GLESRender renderer = new GLESRender(_gmsh);
-		_glView = new mGLSurfaceView(glViewLayout.getContext(), renderer);
-		_glView.setEGLContextClientVersion(1);
-		_glView.setRenderer(renderer);
-		_glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
-		_glView.requestRender();
-		_hideDelay = new Handler();
-		_gestureDetector = new GestureDetector(getActivity(), new OnGestureListener() {
-			public boolean onSingleTapUp(MotionEvent e) { return false; } // UNUSED Auto-generated method stub
-			public void onShowPress(MotionEvent e) {} // UNUSED Auto-generated method stub
-			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } // UNUSED Auto-generated method stub
-			public void onLongPress(MotionEvent e) {} // UNUSED Auto-generated method stub
-			public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } // UNUSED Auto-generated method stub
-			public boolean onDown(MotionEvent e) { return false; } // UNUSED Auto-generated method stub
-		});
-		_gestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
-			public boolean onSingleTapConfirmed(MotionEvent e) {
-				if(View.VISIBLE == _controlBarLayout.getVisibility())
-					hideControlBar();
-				else
-					showControlBar();
-				return true;
-			}
-			public boolean onDoubleTapEvent(MotionEvent e) { return false; } // UNUSED Auto-generated method stub
-			public boolean onDoubleTap(MotionEvent e) { return false; } // UNUSED Auto-generated method stub
-		});
-		_glView.setOnTouchListener(new View.OnTouchListener() {
-			
-			public boolean onTouch(View v, MotionEvent event) {
-				return _gestureDetector.onTouchEvent(event);
-			}
-		});
-		glViewLayout.addView(_glView);
-		_progressLayout = new LinearLayout(container.getContext());
-		ProgressBar bar = new ProgressBar(container.getContext());
-		bar.setOnClickListener(new View.OnClickListener() {
-			public void onClick(View v) {
-				_progress.setAlpha((_progress.getAlpha() > 0)? 0 : 1);
-			}
-		});
-		_progressLayout.addView(bar);
-		_progress = new TextView(container.getContext());
-		_progressLayout.setAlpha(0);
-		_progressLayout.setGravity(Gravity.CENTER);
-		_progressLayout.addView(_progress);
-		RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
-			    RelativeLayout.LayoutParams.WRAP_CONTENT, 
-			    RelativeLayout.LayoutParams.WRAP_CONTENT);
-		layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
-		glViewLayout.addView(_progressLayout, layoutParams);
-		_controlBarLayout = (LinearLayout) getActivity().getLayoutInflater().inflate(R.layout.control_bar, null);
-		final ImageButton prevButton = (ImageButton)_controlBarLayout.findViewById(R.id.controlPrev);
-		final ImageButton playPauseButton = (ImageButton)_controlBarLayout.findViewById(R.id.controlPlay);
-		final ImageButton nextButton = (ImageButton)_controlBarLayout.findViewById(R.id.controlNext);
-		_animationStepper = (SeekBar)_controlBarLayout.findViewById(R.id.controlStepper);
-		_animationStepper.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-			
-			public void onStopTrackingTouch(SeekBar seekBar) {} // UNUSED Auto-generated method stub
-			public void onStartTrackingTouch(SeekBar seekBar) {} // UNUSED Auto-generated method stub
-			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-				if(fromUser) {
-					postDelay();
-					_gmsh.setAnimation(progress);
-					requestRender();
-				}
-			}
-		});
-		_controlBarLayout.setEnabled(false);
-		playPauseButton.setOnClickListener(new View.OnClickListener() {
-			public void onClick(View v) {
-				postDelay();
-				if(((ImageButton)v).getContentDescription().equals("play")) {
-					((ImageButton)v).setContentDescription("pause");
-					((ImageButton)v).setImageResource(android.R.drawable.ic_media_pause);
-					_animationStepper.setMax(_gmsh.numberOfAnimation()-1);
-		    		_animation = new Timer();
-		    		_animation.schedule(new TimerTask() {
-		    			public void run()  {
-		    				_animationStepper.setProgress(_gmsh.animationNext());
-		    				requestRender();
-		    			} }, 0, 500);
-		    		prevButton.setEnabled(false);
-		    		nextButton.setEnabled(false);
-				}
-				else {
-					((ImageButton)v).setContentDescription("play");
-					((ImageButton)v).setImageResource(android.R.drawable.ic_media_play);
-					_animation.cancel();
-					prevButton.setEnabled(true);
-					nextButton.setEnabled(true);
-				}
-			}
-		});
-		nextButton.setOnClickListener(new View.OnClickListener() {
-			public void onClick(View v) {
-				postDelay();
-				_animationStepper.setProgress(_gmsh.animationNext());
-		    	requestRender();
-			}
-		});
-		prevButton.setOnClickListener(new View.OnClickListener() {
-			public void onClick(View v) {
-				postDelay();
-				_animationStepper.setProgress(_gmsh.animationPrev());
-		    	requestRender();
-			}
-		});
-		layoutParams = new RelativeLayout.LayoutParams(
-			    RelativeLayout.LayoutParams.MATCH_PARENT, 
-			    RelativeLayout.LayoutParams.WRAP_CONTENT);
-		layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
-		glViewLayout.addView(_controlBarLayout, layoutParams);
-		this._controlBarLayout.setVisibility(View.INVISIBLE);
-		return rootView;
-	}
-	public void postDelay(int delay) {
-		_hideDelay.removeCallbacks(hideControlsRunnable);
-		_hideDelay.postDelayed(hideControlsRunnable, delay);
-	}
-	public void postDelay() {
-		this.postDelay(6000);
-	}
-	public void showControlBar() {
-		if(getActivity() == null || ((MainActivity)getActivity()).isComputing() || !_gmsh.haveAnimation()) return;
-		_controlBarLayout.setEnabled(true);
-		_animationStepper.setMax(_gmsh.numberOfAnimation()-1);
-		this.postDelay();
-		Animation bottomUp = AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in);
-		_controlBarLayout.setVisibility(View.VISIBLE);
-		_controlBarLayout.startAnimation(bottomUp);
-	}
-	public void hideControlBar() {
-		if(getActivity() == null || View.INVISIBLE == _controlBarLayout.getVisibility()) return;
-		_hideDelay.removeCallbacks(hideControlsRunnable);
-		Animation bottomDown = AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out);
-		_controlBarLayout.startAnimation(bottomDown);
-		_controlBarLayout.setVisibility(View.INVISIBLE);
-		
-	}
-	public void showProgress(String progress) {
-		_progressLayout.setAlpha(1);
-		_progress.setText(progress);
-	}
-	public void hideProgress() {
-		_progressLayout.setAlpha(0);
-		_progress.setText("");
-	}
-	public void requestRender() {
-		_glView.requestRender();
-	}
-	public void takeScreenshot(File out) {
-		Bitmap screenshot = _glView.getScreenshot();
-		try {
-			FileOutputStream f = new FileOutputStream(out);
-			screenshot.compress(Bitmap.CompressFormat.PNG, 85, f);
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		}
-		finally {
-			_glView.setDrawingCacheEnabled(false);
-		}
-	}
+                                 Bundle savedInstanceState) {
+        View rootView = inflater.inflate(R.layout.fragment_model, container, false);
+        RelativeLayout glViewLayout = (RelativeLayout)rootView.findViewById(R.id.glViewLayout);
+        GLESRender renderer = new GLESRender(_gmsh);
+        _glView = new mGLSurfaceView(glViewLayout.getContext(), renderer);
+        _glView.setEGLContextClientVersion(1);
+        _glView.setRenderer(renderer);
+        _glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+        _glView.requestRender();
+        _hideDelay = new Handler();
+        _gestureDetector = new GestureDetector(getActivity(), new OnGestureListener() {
+                public boolean onSingleTapUp(MotionEvent e) { return false; } // UNUSED Auto-generated method stub
+                public void onShowPress(MotionEvent e) {} // UNUSED Auto-generated method stub
+                public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } // UNUSED Auto-generated method stub
+                public void onLongPress(MotionEvent e) {} // UNUSED Auto-generated method stub
+                public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } // UNUSED Auto-generated method stub
+                public boolean onDown(MotionEvent e) { return false; } // UNUSED Auto-generated method stub
+            });
+        _gestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
+                public boolean onSingleTapConfirmed(MotionEvent e) {
+                    if(View.VISIBLE == _controlBarLayout.getVisibility())
+                        hideControlBar();
+                    else
+                        showControlBar();
+                    return true;
+                }
+                public boolean onDoubleTapEvent(MotionEvent e) { return false; } // UNUSED Auto-generated method stub
+                public boolean onDoubleTap(MotionEvent e) { return false; } // UNUSED Auto-generated method stub
+            });
+        _glView.setOnTouchListener(new View.OnTouchListener() {
+
+                public boolean onTouch(View v, MotionEvent event) {
+                    return _gestureDetector.onTouchEvent(event);
+                }
+            });
+        glViewLayout.addView(_glView);
+        RelativeLayout topRightLayout = new RelativeLayout(container.getContext());
+        ImageButton rotationButton = new ImageButton(container.getContext());
+        rotationButton.setBackgroundResource(R.drawable.icon_rotate);
+        rotationButton.setLayoutParams(new LinearLayout.LayoutParams(60, 60));
+        rotationButton.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) {
+                    boolean rotate = !_glView.getRotate();
+                    ((ImageButton)v).setBackgroundResource((rotate)?R.drawable.icon_translate:R.drawable.icon_rotate);
+                    _glView.setRotate(rotate);
+                }
+            });
+        topRightLayout.addView(rotationButton);
+        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams
+            (RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
+
+        TypedValue tv = new TypedValue();
+        int actionBarHeight = 80;
+        if(container.getContext().getTheme().resolveAttribute
+           (android.R.attr.actionBarSize, tv, true)){
+            actionBarHeight = TypedValue.complexToDimensionPixelSize
+                (tv.data, getResources().getDisplayMetrics());
+        }
+        layoutParams.setMargins(0, actionBarHeight + 20, 20, 0);
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+        glViewLayout.addView(topRightLayout, layoutParams);
+        _progressLayout = new LinearLayout(container.getContext());
+        ProgressBar bar = new ProgressBar(container.getContext());
+        bar.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) {
+                    _progress.setAlpha((_progress.getAlpha() > 0) ? 0 : 1);
+                }
+            });
+        _progressLayout.addView(bar);
+        _progress = new TextView(container.getContext());
+        _progressLayout.setAlpha(0);
+        _progressLayout.setGravity(Gravity.CENTER);
+        _progressLayout.addView(_progress);
+        layoutParams = new RelativeLayout.LayoutParams
+            (RelativeLayout.LayoutParams.WRAP_CONTENT,
+             RelativeLayout.LayoutParams.WRAP_CONTENT);
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+        glViewLayout.addView(_progressLayout, layoutParams);
+        _controlBarLayout = (LinearLayout) getActivity().getLayoutInflater().inflate(R.layout.control_bar, null);
+        final ImageButton prevButton = (ImageButton)_controlBarLayout.findViewById(R.id.controlPrev);
+        final ImageButton playPauseButton = (ImageButton)_controlBarLayout.findViewById(R.id.controlPlay);
+        final ImageButton nextButton = (ImageButton)_controlBarLayout.findViewById(R.id.controlNext);
+        _animationStepper = (SeekBar)_controlBarLayout.findViewById(R.id.controlStepper);
+        _animationStepper.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+
+                public void onStopTrackingTouch(SeekBar seekBar) {} // UNUSED Auto-generated method stub
+                public void onStartTrackingTouch(SeekBar seekBar) {} // UNUSED Auto-generated method stub
+                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                    if(fromUser) {
+                        postDelay();
+                        _gmsh.setAnimation(progress);
+                        requestRender();
+                    }
+                }
+            });
+        _controlBarLayout.setEnabled(false);
+        playPauseButton.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) {
+                    postDelay();
+                    if(((ImageButton)v).getContentDescription().equals("play")) {
+                        ((ImageButton)v).setContentDescription("pause");
+                        ((ImageButton)v).setImageResource(android.R.drawable.ic_media_pause);
+                        _animationStepper.setMax(_gmsh.numberOfAnimation()-1);
+                        _animation = new Timer();
+                        _animation.schedule(new TimerTask() {
+                                public void run()  {
+                                    _animationStepper.setProgress(_gmsh.animationNext());
+                                    requestRender();
+                                } }, 0, 500);
+                        prevButton.setEnabled(false);
+                        nextButton.setEnabled(false);
+                    }
+                    else {
+                        ((ImageButton)v).setContentDescription("play");
+                        ((ImageButton)v).setImageResource(android.R.drawable.ic_media_play);
+                        _animation.cancel();
+                        prevButton.setEnabled(true);
+                        nextButton.setEnabled(true);
+                    }
+                }
+            });
+        nextButton.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) {
+                    postDelay();
+                    _animationStepper.setProgress(_gmsh.animationNext());
+                    requestRender();
+                }
+            });
+        prevButton.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) {
+                    postDelay();
+                    _animationStepper.setProgress(_gmsh.animationPrev());
+                    requestRender();
+                }
+            });
+        layoutParams = new RelativeLayout.LayoutParams(
+                                                       RelativeLayout.LayoutParams.MATCH_PARENT,
+                                                       RelativeLayout.LayoutParams.WRAP_CONTENT);
+        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+        glViewLayout.addView(_controlBarLayout, layoutParams);
+        this._controlBarLayout.setVisibility(View.INVISIBLE);
+        return rootView;
+    }
+    public void postDelay(int delay) {
+        _hideDelay.removeCallbacks(hideControlsRunnable);
+        _hideDelay.postDelayed(hideControlsRunnable, delay);
+    }
+    public void postDelay() {
+        this.postDelay(6000);
+    }
+    public void showControlBar() {
+        if(getActivity() == null || ((MainActivity)getActivity()).isComputing() || !_gmsh.haveAnimation()) return;
+        _controlBarLayout.setEnabled(true);
+        _animationStepper.setMax(_gmsh.numberOfAnimation()-1);
+        this.postDelay();
+        Animation bottomUp = AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_in);
+        _controlBarLayout.setVisibility(View.VISIBLE);
+        _controlBarLayout.startAnimation(bottomUp);
+    }
+    public void hideControlBar() {
+        if(getActivity() == null || View.INVISIBLE == _controlBarLayout.getVisibility()) return;
+        _hideDelay.removeCallbacks(hideControlsRunnable);
+        Animation bottomDown = AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out);
+        _controlBarLayout.startAnimation(bottomDown);
+        _controlBarLayout.setVisibility(View.INVISIBLE);
+
+    }
+    public void showProgress(String progress) {
+        _progressLayout.setAlpha(1);
+        _progress.setText(progress);
+    }
+    public void hideProgress() {
+        _progressLayout.setAlpha(0);
+        _progress.setText("");
+    }
+    public void requestRender() {
+        _glView.requestRender();
+    }
+    public void takeScreenshot(File out) {
+        Bitmap screenshot = _glView.getScreenshot();
+        try {
+            FileOutputStream f = new FileOutputStream(out);
+            screenshot.compress(Bitmap.CompressFormat.PNG, 85, f);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+        finally {
+            _glView.setDrawingCacheEnabled(false);
+        }
+    }
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/ModelList.java b/contrib/mobile/Android/src/org/geuz/onelab/ModelList.java
index e5b10f5..f770d54 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/ModelList.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/ModelList.java
@@ -28,217 +28,223 @@ import android.widget.ListView;
 import android.widget.Toast;
 
 public class ModelList extends Activity {
-	
-	private ModelArrayAdapter _modelArrayAdapter;
-	
-	@Override
+
+    private ModelArrayAdapter _modelArrayAdapter;
+
+    @Override
 	protected void onCreate(Bundle savedInstanceState) {
-		super.onCreate(savedInstanceState);
-		_modelArrayAdapter = new ModelArrayAdapter(this);
-		try {
-			this.getModels();
-		} catch (XmlPullParserException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
+        super.onCreate(savedInstanceState);
+        _modelArrayAdapter = new ModelArrayAdapter(this);
+        try {
+            this.getModels();
+        } catch (XmlPullParserException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
 
-		LinearLayout layout = new LinearLayout(this);
+        LinearLayout layout = new LinearLayout(this);
     	layout.setOrientation(LinearLayout.VERTICAL);
     	ListView list = new ListView(this);
     	list.setAdapter(_modelArrayAdapter);
     	list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
 
-			public void onItemClick(AdapterView<?> parent, View view, int position,
+                public void onItemClick(AdapterView<?> parent, View view, int position,
 					long id) {
-				Model m = _modelArrayAdapter.getModel(position);
-				Intent intent = new Intent(ModelList.this, MainActivity.class);
-				intent.putExtra("file", m.getFile().toString());
-				intent.putExtra("name", m.getName());
-				startActivity(intent);
-			}
-		});
+                    Model m = _modelArrayAdapter.getModel(position);
+                    Intent intent = new Intent(ModelList.this, MainActivity.class);
+                    intent.putExtra("file", m.getFile().toString());
+                    intent.putExtra("name", m.getName());
+                    startActivity(intent);
+                }
+            });
     	list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
 
-			public boolean onItemLongClick(AdapterView<?> parent, View view,
-					int position, long id) {
-				final Model m = _modelArrayAdapter.getModel(position);
-				CharSequence[] actions;
-				if(m.getUrl() != null) {
-					actions = new CharSequence[2];
-					actions[0] = "Open this model";
-					actions[1] = "More information";
-				}
-				else {
-					actions = new CharSequence[1];
-					actions[0] = "Open this model";
-				}
-				AlertDialog.Builder builder = new AlertDialog.Builder(parent.getContext());
-				builder.setTitle(m.getName());
-				builder.setItems(actions, new DialogInterface.OnClickListener() {
-				    public void onClick(DialogInterface dialog, int position) {
-				    	switch (position) {
-						case 1:
-							Intent browserIntent = new Intent(Intent.ACTION_VIEW, m.getUrl());
-							startActivity(browserIntent);
-							break;
-						default:
-							Intent intent = new Intent(ModelList.this, MainActivity.class);
-							intent.putExtra("file", m.getFile().toString());
-							intent.putExtra("name", m.getName());
-							startActivity(intent);
-							break;
-						}
-				    }
-				});
-				AlertDialog alert = builder.create();
-				alert.show();
-				return true;
-			}
-		});
+                public boolean onItemLongClick(AdapterView<?> parent, View view,
+                                               int position, long id) {
+                    final Model m = _modelArrayAdapter.getModel(position);
+                    CharSequence[] actions;
+                    if(m.getUrl() != null) {
+                        actions = new CharSequence[2];
+                        actions[0] = "Open this model";
+                        actions[1] = "More information";
+                    }
+                    else {
+                        actions = new CharSequence[1];
+                        actions[0] = "Open this model";
+                    }
+                    AlertDialog.Builder builder = new AlertDialog.Builder(parent.getContext());
+                    builder.setTitle(m.getName());
+                    builder.setItems(actions, new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int position) {
+                                switch (position) {
+                                case 1:
+                                    Intent browserIntent = new Intent(Intent.ACTION_VIEW, m.getUrl());
+                                    startActivity(browserIntent);
+                                    break;
+                                default:
+                                    Intent intent = new Intent(ModelList.this, MainActivity.class);
+                                    intent.putExtra("file", m.getFile().toString());
+                                    intent.putExtra("name", m.getName());
+                                    startActivity(intent);
+                                    break;
+                                }
+                            }
+                        });
+                    AlertDialog alert = builder.create();
+                    alert.show();
+                    return true;
+                }
+            });
     	layout.addView(list);
-		this.setContentView(layout);
-		layout.setPadding(15, 10, 10, 5);
-		layout.setBackgroundColor(Color.argb(255, 67, 67, 67));
-	}
-	
-	@Override
+        this.setContentView(layout);
+        layout.setPadding(15, 10, 10, 5);
+        layout.setBackgroundColor(Color.argb(255, 67, 67, 67));
+    }
+
+    @Override
 	public boolean onCreateOptionsMenu(Menu menu) {
-		MenuItem loadFile = menu.add(R.string.button_open_file);
-		loadFile.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-		return super.onCreateOptionsMenu(menu);
-	}
-	
-	@Override
+        MenuItem about = menu.add("About");
+        about.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+        MenuItem loadFile = menu.add(R.string.button_open_file);
+        loadFile.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
 	public boolean onMenuItemSelected(int featureId, MenuItem item) {
-		if(item.getTitle().equals(getString(R.string.button_open_file))) {
-			Intent fileBrowserIntent = new Intent();
-			fileBrowserIntent.setAction(Intent.ACTION_GET_CONTENT);
-			fileBrowserIntent.setType("file/*");
-			try {
-				startActivityForResult(fileBrowserIntent, 1);
-			}
-			catch(ActivityNotFoundException e) {
-				Toast.makeText(this, "No application found on your device to open the files.", Toast.LENGTH_LONG).show();
-			}
-		}
-		return super.onMenuItemSelected(featureId, item);
-	}
-	
-	@Override
+        if(item.getTitle().equals(getString(R.string.button_open_file))) {
+            Intent fileBrowserIntent = new Intent();
+            fileBrowserIntent.setAction(Intent.ACTION_GET_CONTENT);
+            fileBrowserIntent.setType("file/*");
+            try {
+                startActivityForResult(fileBrowserIntent, 1);
+            }
+            catch(ActivityNotFoundException e) {
+                Toast.makeText(this, "No application found on your device to open the files.", Toast.LENGTH_LONG).show();
+            }
+        }
+        else if(item.getTitle().equals("About")) {
+            Intent intent = new Intent(ModelList.this, AboutActivity.class);
+            startActivity(intent);
+        }
+        return super.onMenuItemSelected(featureId, item);
+    }
+
+    @Override
 	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-		super.onActivityResult(requestCode, resultCode, data);
-		if(resultCode == RESULT_CANCELED) return;
-		switch (requestCode) {
-		case 1:
-			Uri uri = data.getData();
-			String[] projection = { MediaStore.Images.Media.DATA };
-	        Cursor cursor = managedQuery(uri, projection, null, null, null);
-	        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
-	        cursor.moveToFirst();
-			Intent intent = new Intent(ModelList.this, MainActivity.class);
-			intent.putExtra("file", cursor.getString(column_index));
-			intent.putExtra("name", "None");
-			startActivity(intent);
-			break;
-		}
-	}
-	
-	private void getModels() throws XmlPullParserException, IOException
+        super.onActivityResult(requestCode, resultCode, data);
+        if(resultCode == RESULT_CANCELED) return;
+        switch (requestCode) {
+        case 1:
+            Uri uri = data.getData();
+            String[] projection = { MediaStore.Images.Media.DATA };
+            Cursor cursor = managedQuery(uri, projection, null, null, null);
+            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
+            cursor.moveToFirst();
+            Intent intent = new Intent(ModelList.this, MainActivity.class);
+            intent.putExtra("file", cursor.getString(column_index));
+            intent.putExtra("name", "None");
+            startActivity(intent);
+            break;
+        }
+    }
+
+    private void getModels() throws XmlPullParserException, IOException
     {
-		File document = this.getFilesDir();
-		File files[] = document.listFiles();
-		for(int i=0; i<files.length; i++) {
-			if(files[i].isDirectory()) { // models are in directory
-				File xmlInfos = new File(files[i], "infos.xml");
-				if(!xmlInfos.isFile()) continue;
-				InputStream in = new FileInputStream(xmlInfos);
-				try {
-					XmlPullParser parser = Xml.newPullParser();
-					parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
-					parser.setInput(in, null);
-					parser.nextTag();
-					parser.require(XmlPullParser.START_TAG, null, "models");
-					while (parser.next() != XmlPullParser.END_TAG) {
-						if (parser.getEventType() != XmlPullParser.START_TAG) continue;
-						String tagName = parser.getName();
-						if(tagName.equals("model"))
-							readModel(parser, files[i].toString());
-						else
-							skipTag(parser);
-					}
-				}
-				finally {
-					in.close();
-				}
-			}
-		}
+        File document = this.getFilesDir();
+        File files[] = document.listFiles();
+        for(int i=0; i<files.length; i++) {
+            if(files[i].isDirectory()) { // models are in directory
+                File xmlInfos = new File(files[i], "infos.xml");
+                if(!xmlInfos.isFile()) continue;
+                InputStream in = new FileInputStream(xmlInfos);
+                try {
+                    XmlPullParser parser = Xml.newPullParser();
+                    parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+                    parser.setInput(in, null);
+                    parser.nextTag();
+                    parser.require(XmlPullParser.START_TAG, null, "models");
+                    while (parser.next() != XmlPullParser.END_TAG) {
+                        if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+                        String tagName = parser.getName();
+                        if(tagName.equals("model"))
+                            readModel(parser, files[i].toString());
+                        else
+                            skipTag(parser);
+                    }
+                }
+                finally {
+                    in.close();
+                }
+            }
+        }
+    }
+    private void readModel(XmlPullParser parser, String dir) throws XmlPullParserException, IOException{
+        parser.require(XmlPullParser.START_TAG, null, "model");
+        String title = null;
+        String summary = null;
+        String file = null;
+        String bitmap = null;
+        String url = null;
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) continue;
+            String name = parser.getName();
+            if(name.equals("title")) {
+                if (parser.next() == XmlPullParser.TEXT) {
+                    title = parser.getText();
+                    parser.nextTag();
+                }
+            }
+            else if(name.equals("summary")) {
+                if (parser.next() == XmlPullParser.TEXT) {
+                    summary = parser.getText();
+                    parser.nextTag();
+                }
+            }
+            else if(name.equals("file")) {
+                //String relType = parser.getAttributeValue(null, "type");
+                if (parser.next() == XmlPullParser.TEXT) {
+                    file = parser.getText();
+                    parser.nextTag();
+                }
+            }
+            else if(name.equals("preview")) {
+                if (parser.next() == XmlPullParser.TEXT) {
+                    bitmap = parser.getText();
+                    parser.nextTag();
+                }
+            }
+            else if(name.equals("url")) {
+                if (parser.next() == XmlPullParser.TEXT) {
+                    url = parser.getText();
+                    parser.nextTag();
+                }
+            }
+            else {
+                skipTag(parser);
+            }
+        }
+        if(title == null || file == null) return;
+        Model newModel = new Model(title, summary, new File(dir+"/"+file));
+        if(bitmap != null) newModel.setBitmap(new File(dir+"/"+bitmap));
+        if(url != null) newModel.setUrl(Uri.parse(url));
+        _modelArrayAdapter.add(newModel);
+    }
+    private void skipTag(XmlPullParser parser) throws XmlPullParserException, IOException {
+        if (parser.getEventType() != XmlPullParser.START_TAG) {
+            throw new IllegalStateException();
+        }
+        int depth = 1;
+        while (depth != 0) {
+            switch (parser.next()) {
+            case XmlPullParser.END_TAG:
+                depth--;
+                break;
+            case XmlPullParser.START_TAG:
+                depth++;
+                break;
+            }
+        }
     }
-	private void readModel(XmlPullParser parser, String dir) throws XmlPullParserException, IOException{
-		parser.require(XmlPullParser.START_TAG, null, "model");
-		String title = null;
-	    String summary = null;
-	    String file = null;
-	    String bitmap = null;
-	    String url = null;
-	    while (parser.next() != XmlPullParser.END_TAG) {
-	    	if (parser.getEventType() != XmlPullParser.START_TAG) continue;
-	    	String name = parser.getName();
-	    	if(name.equals("title")) {
-	    		if (parser.next() == XmlPullParser.TEXT) {
-	    			title = parser.getText();
-	    			parser.nextTag();
-	    		}
-	    	}
-	    	else if(name.equals("summary")) {
-	    		if (parser.next() == XmlPullParser.TEXT) {
-	    			summary = parser.getText();
-	    			parser.nextTag();
-	    		}
-	    	}
-	    	else if(name.equals("file")) {
-	    		//String relType = parser.getAttributeValue(null, "type"); 
-	    		if (parser.next() == XmlPullParser.TEXT) {
-	    			file = parser.getText();
-	    			parser.nextTag();
-	    		}
-	    	}
-	    	else if(name.equals("preview")) {
-	    		if (parser.next() == XmlPullParser.TEXT) {
-	    			bitmap = parser.getText();
-	    			parser.nextTag();
-	    		}
-	    	}
-	    	else if(name.equals("url")) {
-	    		if (parser.next() == XmlPullParser.TEXT) {
-	    			url = parser.getText();
-	    			parser.nextTag();
-	    		}
-	    	}
-	    	else {
-	    		skipTag(parser);
-	    	}
-	    }
-	    if(title == null || file == null) return;
-	    Model newModel = new Model(title, summary, new File(dir+"/"+file));
-	    if(bitmap != null) newModel.setBitmap(new File(dir+"/"+bitmap));
-	    if(url != null) newModel.setUrl(Uri.parse(url));
-	    _modelArrayAdapter.add(newModel);
-	}
-	private void skipTag(XmlPullParser parser) throws XmlPullParserException, IOException {
-	    if (parser.getEventType() != XmlPullParser.START_TAG) {
-	        throw new IllegalStateException();
-	    }
-	    int depth = 1;
-	    while (depth != 0) {
-	        switch (parser.next()) {
-	        case XmlPullParser.END_TAG:
-	            depth--;
-	            break;
-	        case XmlPullParser.START_TAG:
-	            depth++;
-	            break;
-	        }
-	    }
-	 }
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/OptionsActivity.java b/contrib/mobile/Android/src/org/geuz/onelab/OptionsActivity.java
index 73e3f34..ecac782 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/OptionsActivity.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/OptionsActivity.java
@@ -9,7 +9,7 @@ import android.view.WindowManager;
 
 public class OptionsActivity extends Activity {
 
-	boolean _compute;
+    boolean _compute;
 
 	@Override
 	protected void onCreate(Bundle savedInstanceState) {
@@ -24,28 +24,28 @@ public class OptionsActivity extends Activity {
 		OptionsFragment optionsFragment = OptionsFragment.newInstance(gmsh);
 		getFragmentManager().beginTransaction().replace(R.id.model_fragment, optionsFragment).commit();
 	}
-	
+
 	@Override
 	public boolean onCreateOptionsMenu(Menu menu) {
 		if(_compute) return super.onCreateOptionsMenu(menu);
 		MenuItem runStopMenuItem = menu.add(R.string.menu_run);
-    	runStopMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+                runStopMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
 		return super.onCreateOptionsMenu(menu);
 	}
 
 	@Override
 	public boolean onMenuItemSelected(int featureId, MenuItem item) {
-		if(item.getTitle().equals(getString(R.string.menu_run))) {
-			Intent returnIntent = new Intent();
-			returnIntent.putExtra("Compute", true);
-			this.setResult(RESULT_OK, returnIntent);     
-			this.finish();
-		}
-		else if(item.getItemId() == android.R.id.home) {
-			Intent returnIntent = new Intent();
-			this.setResult(RESULT_CANCELED, returnIntent);
-			this.finish();
-		}
-		return super.onMenuItemSelected(featureId, item);
+            if(item.getTitle().equals(getString(R.string.menu_run))) {
+                Intent returnIntent = new Intent();
+                returnIntent.putExtra("Compute", true);
+                this.setResult(RESULT_OK, returnIntent);
+                this.finish();
+            }
+            else if(item.getItemId() == android.R.id.home) {
+                Intent returnIntent = new Intent();
+                this.setResult(RESULT_CANCELED, returnIntent);
+                this.finish();
+            }
+            return super.onMenuItemSelected(featureId, item);
 	}
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/OptionsPostProcessingFragment.java b/contrib/mobile/Android/src/org/geuz/onelab/OptionsPostProcessingFragment.java
index 68e83f9..cc44519 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/OptionsPostProcessingFragment.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/OptionsPostProcessingFragment.java
@@ -7,7 +7,6 @@ import android.content.Context;
 import android.os.Bundle;
 import android.text.Editable;
 import android.text.TextWatcher;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -49,7 +48,6 @@ public class OptionsPostProcessingFragment extends Fragment{
 			Bundle savedInstanceState) {
 		String[] PViews = _gmsh.getPView();
 		String[] infos = PViews[_pview].split("\n");
-		if(infos.length != 5){ Log.e("Gmsh", "Pview length is incorect"); return null;}
 		getActivity().getActionBar().setTitle(infos[0]);
 		LinearLayout layout =  (LinearLayout)inflater.inflate(R.layout.fragment_postprocessing, container, false);
 		final Spinner intervalsType = (Spinner)layout.findViewById(R.id.intervals_type);
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/Parameter.java b/contrib/mobile/Android/src/org/geuz/onelab/Parameter.java
index 98c614c..dae90a4 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/Parameter.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/Parameter.java
@@ -7,82 +7,81 @@ import android.widget.TextView;
 
 
 public class Parameter {
-	protected Context _context;
-	protected Gmsh _gmsh;
-	protected String _name;
-	protected String _label;
-	protected boolean _readOnly;
-	protected boolean _changed;
-	protected TextView _title;
+    protected Context _context;
+    protected Gmsh _gmsh;
+    protected String _name;
+    protected String _label;
+    protected boolean _readOnly;
+    protected boolean _changed;
+    protected TextView _title;
 
-	public Parameter(Context context, Gmsh gmsh, String name){
-		_context = context;
-		_gmsh = gmsh;
-		_readOnly = false;
-		_name = name;
-		_title = new TextView(context);
-		_title.setText(name);
-		_title.setTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Medium);
-		_title.setTextColor(Color.DKGRAY);
-	}
-	public Parameter(Context context, Gmsh gmsh, String name, boolean readOnly){
-		this(context, gmsh, name);
-		_readOnly = readOnly;
-		_changed = false;
-	}
-	
-	protected void update(){
-		if(_label != null && !_label.equals(""))
-			_title.setText(_label);
-		else
-			_title.setText(getShortName());
-		if(isReadOnly()) _title.setAlpha(0.423f);
-	}
-	
-	public void setName(String name) {_name = name;this.update();}
-	public void setReadOnly(boolean readOnly) {_readOnly = readOnly;this.update();}
-	public void setLabel(String label) {
-		_label = label;
-		this.update();
-	}
-	public String getName() { return _name;}
-	public String getShortName() {
-		if(_label != null && _label.length() > 0) return _label;
-		String[] splited = _name.split("/");
-		String name = splited[splited.length-1];
-		while(name.length() > 0 && name.charAt(0) >= '0' && name.charAt(0) <= '9')
-			name = name.substring(1);
-		return name;
-	}
-	public boolean isReadOnly() {return _readOnly;}
-	public String getLabel() {return _label;}
-	public int fromString(String s){
-		String[] infos = s.split(Character.toString((char)0x03));
-		int pos=0;
-		pos++;// version
-		pos++;// type
-		setName(infos[pos++]);// name
-		setLabel(infos[pos++]);// label
-		pos++;// help
-		pos++;// never change
-		pos++;// changed
-		if(Integer.parseInt(infos[pos++]) != 1)return -1;// visible
-		this.setReadOnly((infos[pos++].equals("1")));// read only
-		int nAttributes = Integer.parseInt(infos[pos++]);// number of attributes
-		pos+=(nAttributes*2);// key+value
-		int nClients = Integer.parseInt(infos[pos++]);// number of client
-		pos+=nClients;// clients
-		this.update();
-		return pos;
-	}
-	public boolean changed() { if(_changed){_changed=false; return true;}return _changed;}
-	public String getType(){return "Parameter";}
-	
-	public LinearLayout getView() {
-		LinearLayout paramLayout = new LinearLayout(_context);
-		paramLayout.setOrientation(LinearLayout.VERTICAL);
-		paramLayout.addView(_title);
-		return paramLayout;
-	}
+    public Parameter(Context context, Gmsh gmsh, String name){
+        _context = context;
+        _gmsh = gmsh;
+        _readOnly = false;
+        _name = name;
+        _title = new TextView(context);
+        _title.setText(name);
+        _title.setTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Medium);
+        _title.setTextColor(Color.DKGRAY);
+    }
+    public Parameter(Context context, Gmsh gmsh, String name, boolean readOnly){
+        this(context, gmsh, name);
+        _readOnly = readOnly;
+        _changed = false;
+    }
+
+    protected void update(){
+        if(_label != null && !_label.equals(""))
+            _title.setText(_label);
+        else
+            _title.setText(getShortName());
+        if(isReadOnly()) _title.setAlpha(0.423f);
+    }
+
+    public void setName(String name) {_name = name;this.update();}
+    public void setReadOnly(boolean readOnly) {_readOnly = readOnly;this.update();}
+    public void setLabel(String label) {
+        _label = label;
+        this.update();
+    }
+    public String getName() { return _name;}
+    public String getShortName() {
+        if(_label != null && _label.length() > 0) return _label;
+        String[] splited = _name.split("/");
+        String name = splited[splited.length-1];
+        while(name.length() > 0 && name.charAt(0) >= '0' && name.charAt(0) <= '9')
+            name = name.substring(1);
+        return name;
+    }
+    public boolean isReadOnly() {return _readOnly;}
+    public String getLabel() {return _label;}
+    public int fromString(String s){
+        String[] infos = s.split(Character.toString((char)0x03));
+        int pos=0;
+        pos++;// version
+        pos++;// type
+        setName(infos[pos++]);// name
+        setLabel(infos[pos++]);// label
+        pos++;// help
+        pos++;// never change
+        if(Integer.parseInt(infos[pos++]) != 1)return -1;// visible
+        this.setReadOnly((infos[pos++].equals("1")));// read only
+        int nAttributes = Integer.parseInt(infos[pos++]);// number of attributes
+        pos+=(nAttributes*2);// key+value
+        int nClients = Integer.parseInt(infos[pos++]);// number of client
+        pos+=(nClients*2);// client+changed
+        this.update();
+        return pos;
+    }
+    public boolean changed() { if(_changed){_changed=false; return true;}return _changed;}
+    public String getType(){return "Parameter";}
+
+    public LinearLayout getView() {
+        LinearLayout paramLayout = new LinearLayout(_context);
+        paramLayout.setOrientation(LinearLayout.VERTICAL);
+        paramLayout.addView(_title);
+        return paramLayout;
+    }
 }
 
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/ParameterNumber.java b/contrib/mobile/Android/src/org/geuz/onelab/ParameterNumber.java
index 6b75613..4ec9e82 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/ParameterNumber.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/ParameterNumber.java
@@ -1,12 +1,11 @@
 package org.geuz.onelab;
 
-import java.text.DecimalFormat;
 import java.util.ArrayList;
 
+import android.app.Activity;
 import android.content.Context;
 import android.text.Editable;
 import android.text.TextWatcher;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
@@ -18,230 +17,295 @@ import android.widget.EditText;
 import android.widget.LinearLayout;
 import android.widget.SeekBar;
 import android.widget.Spinner;
+import android.app.Dialog;
+import android.app.AlertDialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
-public class ParameterNumber extends Parameter{
-	private double _value, _min, _max, _step;
-	private SeekBar _bar;
-	private ArrayList<Double> _values;
-	private ArrayList<String> _choices;
-	private ArrayAdapter<String> _adapter;
-	private Spinner _spinner;
-	private CheckBox _checkbox;
-	private EditText _edittext;
-	
-	public ParameterNumber(Context context, Gmsh gmsh, String name){
-		super(context, gmsh, name);
-	}
-	public ParameterNumber(Context context, Gmsh gmsh, String name,  double value, double min, double max, double step)
-	{
-		this(context, gmsh, name);
-		_value = value;
-		_min = min;
-		_max = max;
-		_step = step;
-	}
-	public ParameterNumber(Context context, Gmsh gmsh, String name, boolean readOnly, double value, double min, double max, double step)
-	{
-		this(context, gmsh, name, value, min, max, step);
-		_readOnly = readOnly;
-	}
-	
-	protected void update(){
-		super.update();
-		int nDecimal = String.valueOf(_min).length() - String.valueOf(_min).lastIndexOf('.') - 1; // hack for double round
-		if(_bar != null) {
-			DecimalFormat df = new DecimalFormat ( ) ;
-			df.setMaximumFractionDigits(nDecimal) ;
-			_title.setText(getShortName() + " (" + df.format(_value)+ ")");
-			_bar.setMax(100);
-			_bar.setProgress((int)(100*(_value-_min)/(_max-_min)));
-			_bar.setEnabled(!this.isReadOnly());
-		}
-		else if(_spinner != null)
-		{
-			for(int i=0;i<_choices.size();i++)
-				if(_values.get(i) == _value)
-					_spinner.setSelection(i, true);
-		}
-		else if(_checkbox != null)
-		{
-			_checkbox.setText(getShortName());
-			_checkbox.setChecked((_value == 0)? false : true);
-		}
-		else if(_edittext != null)
-		{
-			_edittext.setText(""+Math.round(_value*Math.pow(10, nDecimal))/Math.pow(10, nDecimal));
-		}
-	}
-	
-	public void setValue(double value) {
-		if(value < _min || value > _max) {
-			Log.w("ParameterNumber", "Incorect value "+value+" (max="+_max+" min="+_min+")");
-			return;
-		}
-		if(value == _value) return;
-		_value = value;
-		_changed = true;
-		_gmsh.setParam(getType(), getName(), String.valueOf(value));
-		if(mListener != null) mListener.OnParameterChanged();
-	}
-	public void setMin(double min) {_min = min;this.update();}
-	public void setMax(double max) {_max = max;this.update();}
-	public void setStep(double step) {_step = step;this.update();}
-	public void addChoice(double choice, String value) {
-		if(_values == null) {
-			_values = new ArrayList<Double>();
-			_choices = new ArrayList<String>();
-			_values.add(choice);
-			_choices.add(value);
-			if(_spinner == null) {
-				_spinner = new Spinner(_context);
-				_adapter = new ArrayAdapter<String>(_context, android.R.layout.simple_spinner_dropdown_item, _choices);
-				_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-				_spinner.setAdapter(_adapter);
-			}
-		}
-		else
-		{
-			for(int i=0;i<_values.size();i++) {
-				if(_values.get(i).equals(choice) && _choices.size() > i) {
-					_choices.set(i, value);
-					return;
-				}
-				else if(_values.get(i).equals(choice))
-				{
-					_choices.add(value);
-					return;
-				}
-			}
-			_values.add(choice);
-			_choices.add(value);
-		}
-	}
-	public double getValue() {return _value;}
-	public double getMax() {return _max;}
-	public double getMin() {return _min;}
-	public double getStep() {return _step;}
-	public int fromString(String s){
-		int pos = super.fromString(s);
-		if(pos <= 0) return -1; // error
-		String[] infos = s.split(Character.toString((char)0x03));
-		String tmpVal = infos[pos++];
-		if(tmpVal.equals("Inf")) // TODO set value to max ???
-			_value = 1;
-		else
-			_value = Double.parseDouble(tmpVal);
-		this.setMin(Double.parseDouble(infos[pos++]));
-		this.setMax(Double.parseDouble(infos[pos++]));
-		this.setStep(Double.parseDouble(infos[pos++]));
-		pos++;// index
-		int nChoix = Integer.parseInt(infos[pos++]); // choices' size
-		double choices[] = new double[nChoix];
-		for(int i=0; i<nChoix; i++)
-				choices[i] = Double.parseDouble(infos[pos++]); // choice
-		int nLabels = Integer.parseInt(infos[pos++]); // labels' size
-		if(nChoix == 2 && choices[0] == 0 && choices[1] == 1 && nLabels == 0) {
-			_checkbox = new CheckBox(_context);
-			this.update();
-			return pos;
-		}
-		if(_choices != null)_choices.clear();
-		if(_values != null) _values.clear();
-		for(int i=0; i<nLabels && nChoix == nLabels; i++)
-		{
-			double val = Double.parseDouble(infos[pos++]); // choice
-			this.addChoice(val, infos[pos++]); // label
-		}
-		// ...
-		if(nLabels < 1 && _step == 0)
-			_edittext = new EditText(_context);
-		else if(nLabels < 1)
-			_bar = new SeekBar(_context);
-		this.update();
-		return pos;
-	}
-	public String getType(){return "ParameterNumber";}
-	public LinearLayout getView(){
-		LinearLayout paramLayout = new LinearLayout(_context);
-		paramLayout.setOrientation(LinearLayout.VERTICAL);
-		paramLayout.addView(_title);
-		if(_spinner != null) {
-			paramLayout.addView(_spinner);
-			_spinner.setEnabled(!_readOnly);
-			_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
-				public void onNothingSelected(AdapterView<?> arg0) {}
-				public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-					setValue(_values.get(pos));
-				}
-			});
-		}
-		else if(_bar != null) {
-			paramLayout.addView(_bar);
-			_bar.setEnabled(!_readOnly);
-			_bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
-				public void onStopTrackingTouch(SeekBar seekBar) {
-					setValue(getMin() + (getMax() - getMin())*seekBar.getProgress()/100);
-				}
-				
-				public void onStartTrackingTouch(SeekBar seekBar) {}
-				
-				public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
-			});
-		}
-		else if(_checkbox != null) {
-			paramLayout.removeView(_title);
-			paramLayout.addView(_checkbox);
-			_checkbox.setEnabled(!_readOnly);
-			_checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
-				
-				public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
-					setValue((isChecked)? 1 : 0);
-				}
-			});
-		}
-		else if(_edittext != null){
-			paramLayout.addView(_edittext);
-			_edittext.setEnabled(!_readOnly);
-			
-			_edittext.setOnKeyListener(new View.OnKeyListener() {
-				public boolean onKey(View v, int keyCode, KeyEvent event) {
-					if(keyCode == KeyEvent.KEYCODE_ENTER){ // hide the keyboard
-						InputMethodManager imm = (InputMethodManager)_context.getSystemService(
-							      Context.INPUT_METHOD_SERVICE);
-						imm.hideSoftInputFromWindow(_edittext.getWindowToken(), 0);
-						setValue(_value);
-						_edittext.clearFocus();
-						return true;
-					}
-					if(keyCode > KeyEvent.KEYCODE_9 && keyCode != KeyEvent.KEYCODE_NUMPAD_DOT && (keyCode <KeyEvent.KEYCODE_NUMPAD_0 || keyCode >KeyEvent.KEYCODE_NUMPAD_9) && keyCode != KeyEvent.KEYCODE_DEL)
-							return true;
-					return false;
-				}
-			});
-			_edittext.addTextChangedListener(new TextWatcher() {
-				
+public class ParameterNumber extends Parameter {
+    private double _value, _tmpValue, _min, _max, _step;
+    private SeekBar _bar;
+    private ArrayList<Double> _values;
+    private ArrayList<String> _choices;
+    private ArrayAdapter<String> _adapter;
+    private Spinner _spinner;
+    private CheckBox _checkbox;
+    private EditText _edittext;
+    private Stepper _stepper;
+
+    public ParameterNumber(Context context, Gmsh gmsh, String name){
+        super(context, gmsh, name);
+    }
+    public ParameterNumber(Context context, Gmsh gmsh, String name,  double value, double min, double max, double step)
+    {
+        this(context, gmsh, name);
+        _value = value;
+        _min = min;
+        _max = max;
+        _step = step;
+    }
+    public ParameterNumber(Context context, Gmsh gmsh, String name, boolean readOnly, double value, double min, double max, double step)
+    {
+        this(context, gmsh, name, value, min, max, step);
+        _readOnly = readOnly;
+    }
+
+    public static String formatDouble(double x)
+    {
+        return String.format("%.6g", x).replaceFirst("\\.?0+(e|$)", "$1");
+    }
+
+    protected void update()
+    {
+        super.update();
+        if(_bar != null) {
+            _title.setText(getShortName() + " (" + formatDouble(_value)+ ")");
+            _bar.setMax(100);
+            _bar.setProgress((int)(100*(_value-_min)/(_max-_min)));
+            _bar.setEnabled(!this.isReadOnly());
+        }
+        else if(_spinner != null) {
+            for(int i=0;i<_choices.size();i++)
+                if(_values.get(i) == _value)
+                    _spinner.setSelection(i, true);
+        }
+        else if(_checkbox != null) {
+            _checkbox.setText(getShortName());
+            _checkbox.setChecked((_value == 0)? false : true);
+        }
+        else if(_edittext != null) {
+            _edittext.setText(""+formatDouble(_value));
+        }
+        else if(_stepper != null) {
+            _stepper.setMaximum((int)Math.round(_max));
+            _stepper.setMinimum((int)Math.round(_min));
+            _stepper.setValue((int)Math.round(_value));
+        }
+    }
+    public void setValue(double value)
+    {
+        if(value < _min || value > _max) {
+            //Log.w("ParameterNumber", "Incorect value "+value+" (max="+_max+" min="+_min+")");
+            return;
+        }
+        if(value == _value) return;
+        _value = value;
+        _changed = true;
+        _gmsh.setParam(getType(), getName(), String.valueOf(value));
+        if(mListener != null) mListener.OnParameterChanged();
+    }
+    public void setMin(double min) {_min = min;this.update();}
+    public void setMax(double max) {_max = max;this.update();}
+    public void setStep(double step) {_step = step;this.update();}
+    public void addChoice(double choice, String value)
+    {
+        if(_values == null) {
+            _values = new ArrayList<Double>();
+            _choices = new ArrayList<String>();
+            _values.add(choice);
+            _choices.add(value);
+            if(_spinner == null) {
+                _spinner = new Spinner(_context);
+                _adapter = new ArrayAdapter<String>(_context, android.R.layout.simple_spinner_dropdown_item, _choices);
+                _adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+                _spinner.setAdapter(_adapter);
+            }
+        }
+        else{
+            for(int i=0;i<_values.size();i++) {
+                if(_values.get(i).equals(choice) && _choices.size() > i) {
+                    _choices.set(i, value);
+                    return;
+                }
+                else if(_values.get(i).equals(choice))
+                    {
+                        _choices.add(value);
+                        return;
+                    }
+            }
+            _values.add(choice);
+            _choices.add(value);
+        }
+    }
+    public double getValue() {return _value;}
+    public double getMax() {return _max;}
+    public double getMin() {return _min;}
+    public double getStep() {return _step;}
+    public int fromString(String s)
+    {
+        int pos = super.fromString(s);
+        if(pos <= 0) return -1; // error
+        String[] infos = s.split(Character.toString((char)0x03));
+        String tmpVal = infos[pos++];
+        if(tmpVal.equals("Inf")) // TODO set value to max ???
+            _value = 1;
+        else
+            _value = Double.parseDouble(tmpVal);
+        this.setMin(Double.parseDouble(infos[pos++]));
+        this.setMax(Double.parseDouble(infos[pos++]));
+        this.setStep(Double.parseDouble(infos[pos++]));
+        pos++;// index
+        int nChoix = Integer.parseInt(infos[pos++]); // choices' size
+        double choices[] = new double[nChoix];
+        for(int i=0; i<nChoix; i++)
+            choices[i] = Double.parseDouble(infos[pos++]); // choice
+        int nLabels = Integer.parseInt(infos[pos++]); // labels' size
+        if(nChoix == 2 && choices[0] == 0 && choices[1] == 1 && nLabels == 0) {
+            _checkbox = new CheckBox(_context);
+            this.update();
+            return pos;
+        }
+        if(_choices != null)_choices.clear();
+        if(_values != null) _values.clear();
+        for(int i=0; i<nLabels && nChoix == nLabels; i++){
+            double val = Double.parseDouble(infos[pos++]); // choice
+            this.addChoice(val, infos[pos++]); // label
+        }
+        // ...
+        if(nLabels < 1 && _step == 0)
+            _edittext = new EditText(_context);
+        else if(_step == 1)
+            _stepper = new Stepper(_context);
+        else if(nLabels < 1)
+            _bar = new SeekBar(_context);
+        this.update();
+        return pos;
+    }
+    public String getType(){return "ParameterNumber";}
+    public LinearLayout getView()
+    {
+        LinearLayout paramLayout = new LinearLayout(_context);
+        paramLayout.setOrientation(LinearLayout.VERTICAL);
+        paramLayout.addView(_title);
+        if(!_readOnly) paramLayout.setOnLongClickListener(new View.OnLongClickListener(){
+                @Override
+                public boolean onLongClick(View v){
+			AlertDialog.Builder builder = new AlertDialog.Builder(_context);
+			LinearLayout layout = new LinearLayout(_context);
+			layout.setOrientation(LinearLayout.VERTICAL);
+			TextView label = new TextView(_context);
+			label.setText("Edit value of \n" + _name);
+			EditText edit = new EditText(_context);
+			edit.setText(String.valueOf(_value));
+			edit.addTextChangedListener(new TextWatcher() {
 				public void onTextChanged(CharSequence s, int start, int before, int count) {
 					try {
-						if(s.length() < 1) _value = 1;
-						else _value = Double.parseDouble(s.toString());
-					}
-					catch(NumberFormatException e)
-					{
-						_value = 1;
-						//_edittext.setText("");
+						if(s.length() < 1)  _tmpValue = 1;
+						_tmpValue = Double.parseDouble(s.toString());
+					} catch(NumberFormatException e) {
+	                                	_tmpValue = 1;
 					}
 				}
-				
-				public void beforeTextChanged(CharSequence s, int start, int count, int after) {} // UNUSED Auto-generated method stub
-				public void afterTextChanged(Editable s) {} // UNUSED Auto-generated method stub
+		                    public void beforeTextChanged(CharSequence s, int start, int count, int after) {} // UNUSED Auto-generated method stub
+		                    public void afterTextChanged(Editable s) {} // UNUSED Auto-generated method stub
+		        	});
+			edit.requestFocus();
+			//_context.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+			layout.addView(label);
+			layout.addView(edit);
+			builder.setView(layout)
+				.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+					public void onClick(DialogInterface dialog, int id) {
+						setValue(_tmpValue);
+					}
+				})
+				.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+					public void onClick(DialogInterface dialog, int id) {
+						// User cancelled the dialog
+					}
+				});
+			builder.create().show();
+                	return true;
+                }
+            });
+        if(_spinner != null) {
+            paramLayout.addView(_spinner);
+            _spinner.setEnabled(!_readOnly);
+            _spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+                    public void onNothingSelected(AdapterView<?> arg0) {}
+                    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+                        setValue(_values.get(pos));
+                    }
+                });
+        }
+        else if(_bar != null) {
+            paramLayout.addView(_bar);
+            _bar.setEnabled(!_readOnly);
+            _bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+                    public void onStopTrackingTouch(SeekBar seekBar) {
+                        setValue(getMin() + (getMax() - getMin())*seekBar.getProgress()/100);
+                    }
+
+                    public void onStartTrackingTouch(SeekBar seekBar) {}
+
+                    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}
+                });
+        }
+        else if(_checkbox != null) {
+            paramLayout.removeView(_title);
+            paramLayout.addView(_checkbox);
+            _checkbox.setEnabled(!_readOnly);
+            _checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+
+                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                        setValue((isChecked)? 1 : 0);
+                    }
+                });
+        }
+        else if(_edittext != null){
+            paramLayout.addView(_edittext);
+            _edittext.setEnabled(!_readOnly);
+
+            _edittext.setOnKeyListener(new View.OnKeyListener() {
+                    public boolean onKey(View v, int keyCode, KeyEvent event) {
+                        if(keyCode == KeyEvent.KEYCODE_ENTER){ // hide the keyboard
+                            InputMethodManager imm = (InputMethodManager)_context.getSystemService(
+                                                                                                   Context.INPUT_METHOD_SERVICE);
+                            imm.hideSoftInputFromWindow(_edittext.getWindowToken(), 0);
+                            setValue(_value);
+                            _edittext.clearFocus();
+                            return true;
+                        }
+                        if(keyCode > KeyEvent.KEYCODE_9 && keyCode != KeyEvent.KEYCODE_NUMPAD_DOT && (keyCode <KeyEvent.KEYCODE_NUMPAD_0 || keyCode >KeyEvent.KEYCODE_NUMPAD_9) && keyCode != KeyEvent.KEYCODE_DEL)
+                            return true;
+                        return false;
+                    }
+                });
+            _edittext.addTextChangedListener(new TextWatcher() {
+
+                    public void onTextChanged(CharSequence s, int start, int before, int count) {
+                        try {
+                            if(s.length() < 1) _value = 1;
+                            else _value = Double.parseDouble(s.toString());
+                        }
+                        catch(NumberFormatException e)
+                            {
+                                _value = 1;
+                                //_edittext.setText("");
+                            }
+                    }
+
+                    public void beforeTextChanged(CharSequence s, int start, int count, int after) {} // UNUSED Auto-generated method stub
+                    public void afterTextChanged(Editable s) {} // UNUSED Auto-generated method stub
 
-			});
-		}
-		return paramLayout;
-	}
-	private OnParameterChangedListener mListener;
-	public void setOnParameterChangedListener(OnParameterChangedListener listener) { mListener = listener;}
-	public interface OnParameterChangedListener {
-		void OnParameterChanged();
-	}
+                });
+        }
+        else if(_stepper != null) {
+            paramLayout.addView(_stepper);
+            _stepper.setOnValueChangedListener(new Stepper.OnValueChangedListener() {
+                    public void onValueChanged() {
+                        setValue(_stepper.getValue());
+                    }
+                });
+        }
+        return paramLayout;
+    }
+    private OnParameterChangedListener mListener;
+    public void setOnParameterChangedListener(OnParameterChangedListener listener) { mListener = listener;}
+    public interface OnParameterChangedListener
+    {
+        void OnParameterChanged();
+    }
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java b/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java
index 491b89a..0847f0c 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/ParameterString.java
@@ -15,141 +15,141 @@ import android.widget.LinearLayout;
 import android.widget.Spinner;
 
 public class ParameterString extends Parameter{
-	
-	private  String _kind;
-	private int _index;
-	private ArrayList<String> _choices;
-	private ArrayAdapter<String> _adapter;
-	private Spinner _spinner;
-	private EditText _edittext;
-	
-	public ParameterString(Context context, Gmsh gmsh, String name) {
-		super(context, gmsh, name);
-		_choices = new ArrayList<String>();
-		_choices.add("-"); // Default choice
-	}
-
-	private void createSpinner()
-	{
-		if(_spinner != null) return;
-		_spinner = new Spinner(_context);
-		_adapter = new ArrayAdapter<String>(_context, android.R.layout.simple_spinner_dropdown_item, _choices);
-		_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-		_spinner.setAdapter(_adapter);
-	}
-	
-	protected void update(){
-		super.update();
-		if(_spinner != null)
-			_spinner.setSelection(_index);
-		else if(_edittext != null && _choices.size() > 0)
-			_edittext.setText(_choices.get(0));
-	}
-	
-	public void setValue(int index) {
-		if(index == _index) return;
-		_changed = true;
-		_index = index;
-		_gmsh.setParam(getType(), getName(), _choices.get(_index));
-		if(mListener != null) mListener.OnParameterChanged();
-	}
-	public void setValue(String value) {
-		int index = _choices.indexOf(value);
-		if(index < 0) { // the value is not in the list, add it
-			this.addChoices(value);
-			index = _choices.indexOf(value);
-		}
-		if(index == _index) return;
-		_changed = true;
-		_index = index;
-		_gmsh.setParam(getType(), getName(), value);
-		if(mListener != null) mListener.OnParameterChanged();
-	}
-	public void setKind(String kind) {_kind = kind;}
-	public void addChoices(String choice) {
-		if(_edittext == null && _spinner == null) createSpinner();
-		for(String c : _choices) // do not add a duplicate value
-			if(c.equals(choice))return;
-		if(_choices.get(0).equals("-")) // remove the default choice with the first added choice
-			_choices.remove(0);
-		_choices.add(choice);
-		this.update();
-	}
-	public String getValue() {if( _index < 0) return "";return _choices.get(_index);}
-	public String getKind() {return _kind;}
-	public int getIndex() {return _index;}
-	public ArrayList<String> getChoices() {return _choices;}
-	public int fromString(String s){
-		int pos = super.fromString(s);
-		if(pos <= 0) return -1; // error
-		String[] infos = s.split(Character.toString((char)0x03));
-		String value = infos[pos++];
-		setKind(infos[pos++]); // generic file 
-		if(_kind.equals("file"))
-			return -1;
-		int nChoices = Integer.parseInt(infos[pos++]);
-		if(nChoices < 1 && _kind.equals("generic"))
-			_edittext = new EditText(_context);
-		if(_choices != null)_choices.clear();
-		for(int i=0;i<nChoices;i++) this.addChoices(infos[pos++]);
-		// ...
-		setValue(value);
-		this.update();
-		return pos;
-	}
-	public String getType(){return "ParameterString";}
-	public LinearLayout getView() {
-		LinearLayout paramLayout = new LinearLayout(_context);
-		paramLayout.setOrientation(LinearLayout.VERTICAL);
-		paramLayout.addView(_title);
-		if(_spinner != null){
-			paramLayout.addView(_spinner);
-			_spinner.setEnabled(!_readOnly);
-			_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
-
-				public void onNothingSelected(AdapterView<?> arg0) {}
-
-				public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
-					setValue(pos);
-				}
-
-			});
-		}
-		else if(_edittext != null){
-			paramLayout.addView(_edittext);
-			_edittext.setEnabled(!_readOnly);
-			_edittext.setOnKeyListener(new View.OnKeyListener() {
-				
-				public boolean onKey(View v, int keyCode, KeyEvent event) {
-					if(keyCode == KeyEvent.KEYCODE_ENTER){ // hide the keyboard
-						InputMethodManager imm = (InputMethodManager)_context.getSystemService(
-							      Context.INPUT_METHOD_SERVICE);
-							imm.hideSoftInputFromWindow(_edittext.getWindowToken(), 0);
-							_edittext.clearFocus();
-						return true;
-					}
-					return false;
-				}
-			});
-			_edittext.addTextChangedListener(new TextWatcher() {
-				
-				public void onTextChanged(CharSequence s, int start, int before, int count) {
-					_choices.clear(); _choices.add(s.toString());
-				}
-				
-				public void beforeTextChanged(CharSequence s, int start, int count, int after) {} // UNUSED Auto-generated method stub
-				
-				public void afterTextChanged(Editable s) {
-					_gmsh.setParam(getType(), getName(), _choices.get(0));
-				}
-			});
-		}
-		return paramLayout;
-	}
-	private OnParameterChangedListener mListener;
-	public void setOnParameterChangedListener(OnParameterChangedListener listener) { mListener = listener;}
-	public interface OnParameterChangedListener {
-		void OnParameterChanged();
-	}
-	
+
+    private  String _kind;
+    private int _index;
+    private ArrayList<String> _choices;
+    private ArrayAdapter<String> _adapter;
+    private Spinner _spinner;
+    private EditText _edittext;
+
+    public ParameterString(Context context, Gmsh gmsh, String name) {
+        super(context, gmsh, name);
+        _choices = new ArrayList<String>();
+        _choices.add("-"); // Default choice
+    }
+
+    private void createSpinner()
+    {
+        if(_spinner != null) return;
+        _spinner = new Spinner(_context);
+        _adapter = new ArrayAdapter<String>(_context, android.R.layout.simple_spinner_dropdown_item, _choices);
+        _adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        _spinner.setAdapter(_adapter);
+    }
+
+    protected void update(){
+        super.update();
+        if(_spinner != null)
+            _spinner.setSelection(_index);
+        else if(_edittext != null && _choices.size() > 0)
+            _edittext.setText(_choices.get(0));
+    }
+
+    public void setValue(int index) {
+        if(index == _index) return;
+        _changed = true;
+        _index = index;
+        _gmsh.setParam(getType(), getName(), _choices.get(_index));
+        if(mListener != null) mListener.OnParameterChanged();
+    }
+    public void setValue(String value) {
+        int index = _choices.indexOf(value);
+        if(index < 0) { // the value is not in the list, add it
+            this.addChoices(value);
+            index = _choices.indexOf(value);
+        }
+        if(index == _index) return;
+        _changed = true;
+        _index = index;
+        _gmsh.setParam(getType(), getName(), value);
+        if(mListener != null) mListener.OnParameterChanged();
+    }
+    public void setKind(String kind) {_kind = kind;}
+    public void addChoices(String choice) {
+        if(_edittext == null && _spinner == null) createSpinner();
+        for(String c : _choices) // do not add a duplicate value
+            if(c.equals(choice))return;
+        if(_choices.get(0).equals("-")) // remove the default choice with the first added choice
+            _choices.remove(0);
+        _choices.add(choice);
+        this.update();
+    }
+    public String getValue() {if( _index < 0) return "";return _choices.get(_index);}
+    public String getKind() {return _kind;}
+    public int getIndex() {return _index;}
+    public ArrayList<String> getChoices() {return _choices;}
+    public int fromString(String s){
+        int pos = super.fromString(s);
+        if(pos <= 0) return -1; // error
+        String[] infos = s.split(Character.toString((char)0x03));
+        String value = infos[pos++];
+        setKind(infos[pos++]); // generic file
+        if(_kind.equals("file"))
+            return -1;
+        int nChoices = Integer.parseInt(infos[pos++]);
+        if(nChoices < 1 && _kind.equals("generic"))
+            _edittext = new EditText(_context);
+        if(_choices != null)_choices.clear();
+        for(int i=0;i<nChoices;i++) this.addChoices(infos[pos++]);
+        // ...
+        setValue(value);
+        this.update();
+        return pos;
+    }
+    public String getType(){return "ParameterString";}
+    public LinearLayout getView() {
+        LinearLayout paramLayout = new LinearLayout(_context);
+        paramLayout.setOrientation(LinearLayout.VERTICAL);
+        paramLayout.addView(_title);
+        if(_spinner != null){
+            paramLayout.addView(_spinner);
+            _spinner.setEnabled(!_readOnly);
+            _spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+
+                    public void onNothingSelected(AdapterView<?> arg0) {}
+
+                    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+                        setValue(pos);
+                    }
+
+                });
+        }
+        else if(_edittext != null){
+            paramLayout.addView(_edittext);
+            _edittext.setEnabled(!_readOnly);
+            _edittext.setOnKeyListener(new View.OnKeyListener() {
+
+                    public boolean onKey(View v, int keyCode, KeyEvent event) {
+                        if(keyCode == KeyEvent.KEYCODE_ENTER){ // hide the keyboard
+                            InputMethodManager imm = (InputMethodManager)_context.getSystemService(
+                                                                                                   Context.INPUT_METHOD_SERVICE);
+                            imm.hideSoftInputFromWindow(_edittext.getWindowToken(), 0);
+                            _edittext.clearFocus();
+                            return true;
+                        }
+                        return false;
+                    }
+                });
+            _edittext.addTextChangedListener(new TextWatcher() {
+
+                    public void onTextChanged(CharSequence s, int start, int before, int count) {
+                        _choices.clear(); _choices.add(s.toString());
+                    }
+
+                    public void beforeTextChanged(CharSequence s, int start, int count, int after) {} // UNUSED Auto-generated method stub
+
+                    public void afterTextChanged(Editable s) {
+                        _gmsh.setParam(getType(), getName(), _choices.get(0));
+                    }
+                });
+        }
+        return paramLayout;
+    }
+    private OnParameterChangedListener mListener;
+    public void setOnParameterChangedListener(OnParameterChangedListener listener) { mListener = listener;}
+    public interface OnParameterChangedListener {
+        void OnParameterChanged();
+    }
+
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/SeparatedListView.java b/contrib/mobile/Android/src/org/geuz/onelab/SeparatedListView.java
index e9a1755..4a20677 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/SeparatedListView.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/SeparatedListView.java
@@ -15,153 +15,153 @@ import android.widget.TextView;
 
 public class SeparatedListView extends ListView{
 
-	private SeparatedListAdaptater adapter;
-	private Context _context;
-	
-	public SeparatedListView(Context context) {
-		super(context);
-		_context = context;
-		adapter = new SeparatedListAdaptater();
-		this.setAdapter(adapter);
-	}
-	public SeparatedListView(Context context, AttributeSet attrs) {
-		this(context);
-	}
-	public SeparatedListView(Context context, View[] footer) {
-		super(context);
-		_context = context;
-		for(View v : footer)
-			this.addFooterView(v);
-		adapter = new SeparatedListAdaptater();
-		this.setAdapter(adapter);
-	}
-	
-	public void addItem(String header, View item) {
-		TextView title = (TextView)((LayoutInflater) _context.getSystemService( Context.LAYOUT_INFLATER_SERVICE )).inflate(R.layout.list_header, null);
-		title.setText(header);
-		adapter.addItem(header, title, item);
-		adapter.notifyDataSetChanged();
-		this.invalidateViews();
-	}
-	public int itemsCountInSection(String header) {
-		return adapter.getCountForSection(header);
-	}
-	public void refresh()
-	{
-		adapter.notifyDataSetChanged();
-		this.invalidateViews();
-	}
-	
-	public void clear()
-	{
-		adapter.clear();
-		adapter.notifyDataSetChanged();
-	}
-	
-	private class Section{
-		private String _name;
-		private List<View> _items;
-		public Section(String name){
-			_name = name;
-			_items = new ArrayList<View>();
-		}
-		public void addItem(View v){
-			_items.add(v);
-		}
-		public String getName(){
-			return _name;
-		}
-		public int getItemsCount(){
-			return _items.size();
-		}
-		public View getItem(int pos){
-			return _items.get(pos);
-		}
-	}
-	
-	private class SeparatedListAdaptater extends BaseAdapter{
-
-		List<Section> sections;
-		List<View> titles;
-		
-		public SeparatedListAdaptater() {
-			sections = new ArrayList<SeparatedListView.Section>();
-			titles = new ArrayList<View>();
-		}
-		
-		public void addItem(String header, View title, View item) {
-			for(Section s : sections){
-				if(s.getName().equals(header)){
-					s.addItem(item);
-					return;
-				}
-			}
-			Section s = new Section(header);
-			s.addItem(item);
-			sections.add(s);
-			titles.add(title);
-		}
-		
-		//@Override
-		public int getCount() {
-			int count = 0;
-			for(Section s : sections) count += s.getItemsCount() + 1;
-			return count;
-		}
-		public int getCountForSection(String header) {
-			for(Section s : sections)
-				if(s.getName().equals(header))
-					return s.getItemsCount();
-			return 0;
-		}
-		//@Override
-		public Object getItem(int position) {
-			int section = -1,
-					lastPosition = -1;
-			while(lastPosition<position){
-				int itemsCount = sections.get(section+1).getItemsCount();
-				if(lastPosition+1 == position)// this is a section
-					return titles.get(section+1);
-				else if(lastPosition+1+itemsCount >= position){ // the view is in this section
-					if(section<0) return sections.get(section+1).getItem(position-1);
-					return sections.get(section+1).getItem(position-lastPosition-2);
-				}
-				lastPosition+= 1 + itemsCount;
-				section++;
-			}
-			return null;
-		}
-
-		//@Override
-		public long getItemId(int position) {
-			// UNUSED Auto-generated method stub
-			return 0;
-		}
-
-		//@Override
-		public View getView(int position, View convertView, ViewGroup parent) {
-			int section = -1,
-					lastPosition = -1;
-			while(lastPosition<position){
-				int itemsCount = sections.get(section+1).getItemsCount();
-				if(lastPosition+1 == position)// this is a section
-					return titles.get(section+1);
-				else if(lastPosition+1+itemsCount >= position){ // the view is in this section
-					if(section<0) return sections.get(section+1).getItem(position-1);
-					return sections.get(section+1).getItem(position-lastPosition-2);
-				}
-				lastPosition+= 1 + itemsCount;
-				section++;
-			}
-			return null;
-		}
-		public void clear()
-		{
-			sections.clear();
-			titles.clear();
-		}
-		
-	}
+    private SeparatedListAdaptater adapter;
+    private Context _context;
+
+    public SeparatedListView(Context context) {
+        super(context);
+        _context = context;
+        adapter = new SeparatedListAdaptater();
+        this.setAdapter(adapter);
+    }
+    public SeparatedListView(Context context, AttributeSet attrs) {
+        this(context);
+    }
+    public SeparatedListView(Context context, View[] footer) {
+        super(context);
+        _context = context;
+        for(View v : footer)
+            this.addFooterView(v);
+        adapter = new SeparatedListAdaptater();
+        this.setAdapter(adapter);
+    }
+
+    public void addItem(String header, View item) {
+        TextView title = (TextView)((LayoutInflater) _context.getSystemService( Context.LAYOUT_INFLATER_SERVICE )).inflate(R.layout.list_header, null);
+        title.setText(header);
+        adapter.addItem(header, title, item);
+        adapter.notifyDataSetChanged();
+        this.invalidateViews();
+    }
+    public int itemsCountInSection(String header) {
+        return adapter.getCountForSection(header);
+    }
+    public void refresh()
+    {
+        adapter.notifyDataSetChanged();
+        this.invalidateViews();
+    }
+
+    public void clear()
+    {
+        adapter.clear();
+        adapter.notifyDataSetChanged();
+    }
+
+    private class Section{
+        private String _name;
+        private List<View> _items;
+        public Section(String name){
+            _name = name;
+            _items = new ArrayList<View>();
+        }
+        public void addItem(View v){
+            _items.add(v);
+        }
+        public String getName(){
+            return _name;
+        }
+        public int getItemsCount(){
+            return _items.size();
+        }
+        public View getItem(int pos){
+            return _items.get(pos);
+        }
+    }
+
+    private class SeparatedListAdaptater extends BaseAdapter{
+
+        List<Section> sections;
+        List<View> titles;
+
+        public SeparatedListAdaptater() {
+            sections = new ArrayList<SeparatedListView.Section>();
+            titles = new ArrayList<View>();
+        }
+
+        public void addItem(String header, View title, View item) {
+            for(Section s : sections){
+                if(s.getName().equals(header)){
+                    s.addItem(item);
+                    return;
+                }
+            }
+            Section s = new Section(header);
+            s.addItem(item);
+            sections.add(s);
+            titles.add(title);
+        }
+
+        //@Override
+        public int getCount() {
+            int count = 0;
+            for(Section s : sections) count += s.getItemsCount() + 1;
+            return count;
+        }
+        public int getCountForSection(String header) {
+            for(Section s : sections)
+                if(s.getName().equals(header))
+                    return s.getItemsCount();
+            return 0;
+        }
+        //@Override
+        public Object getItem(int position) {
+            int section = -1,
+                lastPosition = -1;
+            while(lastPosition<position){
+                int itemsCount = sections.get(section+1).getItemsCount();
+                if(lastPosition+1 == position)// this is a section
+                    return titles.get(section+1);
+                else if(lastPosition+1+itemsCount >= position){ // the view is in this section
+                    if(section<0) return sections.get(section+1).getItem(position-1);
+                    return sections.get(section+1).getItem(position-lastPosition-2);
+                }
+                lastPosition+= 1 + itemsCount;
+                section++;
+            }
+            return null;
+        }
+
+        //@Override
+        public long getItemId(int position) {
+            // UNUSED Auto-generated method stub
+            return 0;
+        }
+
+        //@Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            int section = -1,
+                lastPosition = -1;
+            while(lastPosition<position){
+                int itemsCount = sections.get(section+1).getItemsCount();
+                if(lastPosition+1 == position)// this is a section
+                    return titles.get(section+1);
+                else if(lastPosition+1+itemsCount >= position){ // the view is in this section
+                    if(section<0) return sections.get(section+1).getItem(position-1);
+                    return sections.get(section+1).getItem(position-lastPosition-2);
+                }
+                lastPosition+= 1 + itemsCount;
+                section++;
+            }
+            return null;
+        }
+        public void clear()
+        {
+            sections.clear();
+            titles.clear();
+        }
+
+    }
 
 }
 
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/SplashScreen.java b/contrib/mobile/Android/src/org/geuz/onelab/SplashScreen.java
index 3320d54..48bd02e 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/SplashScreen.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/SplashScreen.java
@@ -10,84 +10,97 @@ import java.util.zip.ZipInputStream;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
 
 public class SplashScreen extends Activity{
-	private static final int SPLASHTIME = 1000; // duration for the splash screen in milliseconds
-	
-	private static final int STOPSPLASH = 0;
-	private static final int EXITAPP = 1;
-	
-	private Intent newIntent;
-	
-	private final Handler handler = new Handler()
+    private static final int SPLASHTIME = 1000; // duration for the splash screen in milliseconds
+
+    private static final int STOPSPLASH = 0;
+    private static final int EXITAPP = 1;
+
+    private Intent newIntent;
+
+    private final Handler handler = new Handler()
 	{
-		public void handleMessage(Message msg) {
-			switch (msg.what) {
-			case STOPSPLASH:
-				startActivity(newIntent);
-				finish();
-				break;
-			case EXITAPP:
-				finish();
-				break;
-			default:
-				break;
-			}
-		};
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                case STOPSPLASH:
+                    startActivity(newIntent);
+                    finish();
+                    break;
+                case EXITAPP:
+                    finish();
+                    break;
+                default:
+                    break;
+                }
+            };
 	};
-	
-	protected void onCreate(android.os.Bundle savedInstanceState) {
-		super.onCreate(savedInstanceState);
-		setContentView(R.layout.splash);
-		Intent oldIntent = this.getIntent();
-		if(oldIntent != null && oldIntent.getAction() != null && oldIntent.getAction().equals(Intent.ACTION_VIEW)){
-			newIntent = new Intent(SplashScreen.this, MainActivity.class);
-			newIntent.setAction(oldIntent.getAction());
-			newIntent.setData(oldIntent.getData());
-		}
-		else
-			newIntent = new Intent(SplashScreen.this, ModelList.class);
+
+    protected void onCreate(android.os.Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.splash);
+        Intent oldIntent = this.getIntent();
+        if(oldIntent != null && oldIntent.getAction() != null && oldIntent.getAction().equals(Intent.ACTION_VIEW)){
+            newIntent = new Intent(SplashScreen.this, MainActivity.class);
+            newIntent.setAction(oldIntent.getAction());
+            newIntent.setData(oldIntent.getData());
+        }
+        else
+            newIntent = new Intent(SplashScreen.this, ModelList.class);
+	SharedPreferences sharedPref = getSharedPreferences(getPackageName(), Context.MODE_PRIVATE);
+	int codev = 0;
+	try {
+		codev = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
+	} catch (android.content.pm.PackageManager.NameNotFoundException e) {}
+	int modelsv = sharedPref.getInt("OnelabModelsVersion", 0);
+	if(modelsv == 0 || modelsv != codev) {
+		Log.d("Models", "Updating models to version "+codev);
+		SharedPreferences.Editor editor = sharedPref.edit();
+		editor.putInt("OnelabModelsVersion", codev);
+		editor.commit();
 		loadNative();
-		final Message msg = new Message();
+	}
+	else Log.d("Models", "Leaving models as-is (version "+modelsv+")");
+        final Message msg = new Message();
         msg.what = STOPSPLASH;
         handler.sendMessageDelayed(msg, SPLASHTIME);
-	}
+    }
 
-	/**
+    /**
      * Load file from res/raw/ directory to the files directory of the application.
      */
     private void loadNative()
     {
     	try {
-    		ZipInputStream zipStream = new ZipInputStream(new BufferedInputStream(getResources().openRawResource(R.raw.models)));
-			ZipEntry entry;
-		     while ((entry = zipStream.getNextEntry()) != null) {
-		    	 String name = entry.getName();
-		    	 FileOutputStream outputStream;
-		    	 if(name.charAt(name.length()-1) == '/') {
-		    		 continue;
-		    	 }
-		    	 else if(name.lastIndexOf("/") > 0) {
-		    		 File document = this.getFilesDir();
-		    		 File currentDirectory = new File(document,name.substring(0, name.lastIndexOf("/")));
-		    		 currentDirectory.mkdir();
-		    		 File currentFile = new File(currentDirectory, name.substring(name.lastIndexOf("/")+1));
-		    		 outputStream = new FileOutputStream(currentFile);
-		    	 }
-		    	 else {
-		    		outputStream = openFileOutput(name, Context.MODE_PRIVATE);
-		    	 }
-				byte[] buffer = new byte[2048];
-				for (int i = zipStream.read(buffer, 0, buffer.length); i > 0;i = zipStream.read(buffer, 0, buffer.length)) 
-					outputStream.write(buffer,0,i);
-				Log.d("Load files", "Add " + entry.getName() + " from the zip file");
-		     }
-		     zipStream.close();
-		} catch (IOException e1) {
-			e1.printStackTrace();
-		}
+            ZipInputStream zipStream = new ZipInputStream(new BufferedInputStream(getResources().openRawResource(R.raw.models)));
+            ZipEntry entry;
+            while ((entry = zipStream.getNextEntry()) != null) {
+                String name = entry.getName();
+                FileOutputStream outputStream;
+                if(name.charAt(name.length()-1) == '/') {
+                    continue;
+                }
+                else if(name.lastIndexOf("/") > 0) {
+                    File document = this.getFilesDir();
+                    File currentDirectory = new File(document,name.substring(0, name.lastIndexOf("/")));
+                    currentDirectory.mkdir();
+                    File currentFile = new File(currentDirectory, name.substring(name.lastIndexOf("/")+1));
+                    outputStream = new FileOutputStream(currentFile);
+                }
+                else {
+                    outputStream = openFileOutput(name, Context.MODE_PRIVATE);
+                }
+                byte[] buffer = new byte[2048];
+                for (int i = zipStream.read(buffer, 0, buffer.length); i > 0;i = zipStream.read(buffer, 0, buffer.length))
+                    outputStream.write(buffer,0,i);
+            }
+            zipStream.close();
+        } catch (IOException e1) {
+            e1.printStackTrace();
+        }
     }
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/Stepper.java b/contrib/mobile/Android/src/org/geuz/onelab/Stepper.java
new file mode 100644
index 0000000..5392218
--- /dev/null
+++ b/contrib/mobile/Android/src/org/geuz/onelab/Stepper.java
@@ -0,0 +1,80 @@
+package org.geuz.onelab;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.widget.EditText;
+import android.text.TextWatcher;
+import android.text.Editable;
+
+
+class Stepper extends LinearLayout{
+
+    private int _min, _max, _val;
+    private Button _incBtn, _decBtn;
+    private EditText _valTxt;
+    private OnValueChangedListener _listener;
+
+    public Stepper(Context context){
+        super(context);
+        _max = _min = _val = 0;
+        _incBtn = new Button(context);
+        _decBtn = new Button(context);
+        _valTxt = new EditText(context);
+        _incBtn.setText("+");
+        _decBtn.setText("-");
+        _valTxt.setText(Integer.toString(_val));
+        this.addView(_decBtn);
+        this.addView(_valTxt);
+        this.addView(_incBtn);
+        _incBtn.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    inc();
+                }
+            });
+        _decBtn.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    dec();
+                }
+            });
+        _valTxt.addTextChangedListener(new TextWatcher() {
+                public void afterTextChanged(Editable s){}
+                public void beforeTextChanged(CharSequence s, int start, int count, int after){}
+                public void onTextChanged(CharSequence s, int start, int before, int count) {
+                    try {
+                        setValueButText(Integer.parseInt(s.toString()));
+                    }
+                    catch (NumberFormatException e) {}
+                }
+            });
+    }
+
+    public interface OnValueChangedListener {
+        public void onValueChanged();
+    }
+
+
+    public void inc(){setValue(_val+1);}
+    public void dec(){setValue(_val-1);}
+
+    public void setOnValueChangedListener(OnValueChangedListener listener) {_listener = listener;}
+    public void setMaximum(int max){_max = max;}
+    public void setMinimum(int min){_min = min;}
+    public void setValue(int val){
+        setValueButText(val);
+        _valTxt.setText(Integer.toString(_val));
+    }
+    public void setValueButText(int val){
+        if(_max > _min) {
+            if(val == _max) _incBtn.setEnabled(false);
+            else if(val == _min) _decBtn.setEnabled(false);
+            else {_incBtn.setEnabled(true); _decBtn.setEnabled(true);}
+        }
+        _val = val;
+        if(_listener != null) _listener.onValueChanged();
+    }
+    public int getMaximum(){return _max;}
+    public int getMinimum(){return _min;}
+    public int getValue(){return _val;}
+}
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/StringTexture.java b/contrib/mobile/Android/src/org/geuz/onelab/StringTexture.java
index 3faa40d..c53de72 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/StringTexture.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/StringTexture.java
@@ -17,156 +17,156 @@ import android.opengl.GLUtils;
 import android.os.Environment;
 
 public class StringTexture {
-	private String _text;
-	private Bitmap _bitmap;
-	private int[] _textures = new int[1]; // Texture pointer
-	
-	public StringTexture(String s) {
-		_text = s;
-		getBitmapFromText(12.0f, Color.BLACK);
-	}
-	
-	private void getBitmapFromText(float textSize, int textColor) {
-	    Paint paint = new Paint();
-	    paint.setTextSize(textSize);
-	    paint.setColor(textColor);
-	    paint.setTextAlign(Paint.Align.LEFT);
-	    int width = (int) (paint.measureText(_text) + 2.5f); // round
-	    int baseline = (int) (textSize + 2.5f);
-	    int height = (int) (baseline + paint.descent() + 2.5f);
-	    _bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-	    _bitmap.eraseColor(Color.TRANSPARENT);
-	    Canvas canvas = new Canvas(_bitmap);
-	    canvas.setBitmap(_bitmap);
-	    canvas.drawText(_text, 0, baseline, paint);
-	}
-	
-	private void loadGLTexture(GL10 gl) {
-		if(_bitmap == null) return;
-		gl.glGenTextures(1, _textures, 0);
-
-		gl.glBindTexture(GL10.GL_TEXTURE_2D, _textures[0]);
-		
-		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
-		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
- 
-		GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, _bitmap, 0);
-		
-		_bitmap.recycle();
-	}
-	
-	public void draw(GL10 gl, int x, int y) {
-		gl.glEnable(GL10.GL_TEXTURE_2D);
-		// VERTEX
-		float vertex[] = {
-				-1.0f, -1.0f,  0.0f,		// bottom left
-				-1.0f,  1.0f,  0.0f,		// top left
-				 1.0f, -1.0f,  0.0f,		// bottom right
-				 1.0f,  1.0f,  0.0f			// top right
-		};
-		FloatBuffer vertexBuffer;
-		ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(vertex.length * 4);
-		vertexByteBuffer.order(ByteOrder.nativeOrder());
-		vertexBuffer = vertexByteBuffer.asFloatBuffer();
-		vertexBuffer.put(vertex);
-		vertexBuffer.position(0);
-		
-		// TEXTURE
-		FloatBuffer textureBuffer;	// buffer holding the texture coordinates
-		float texture[] = {
-				0.0f, 1.0f,		// top left
-				0.0f, 0.0f,		// bottom left
-				1.0f, 1.0f,		// top right
-				1.0f, 0.0f		// bottom right
-		};
-		ByteBuffer textureByteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
-		textureByteBuffer.order(ByteOrder.nativeOrder());
-		textureBuffer = textureByteBuffer.asFloatBuffer();
-		textureBuffer.put(texture);
-		textureBuffer.position(0);
-		loadGLTexture(gl);
-		gl.glBindTexture(GL10.GL_TEXTURE_2D, _textures[0]);
-		
-		
-		// DRAW
-		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
-		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
-		gl.glColor4f(1,1,1,1);
-		gl.glEnable(GL10.GL_BLEND);
-		gl.glBlendFunc(GL10.GL_SRC_COLOR, GL10.GL_ONE_MINUS_SRC_ALPHA);
-		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
-		gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
-		gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertex.length / 3);
-		gl.glDisable(GL10.GL_BLEND);
-		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
-		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
-		gl.glDisable(GL10.GL_TEXTURE_2D);
-	}
-	
-	public static byte[] getBytesFromString(String s, int textSize)
-	{
-		// Generate the bitmap
-		int textColor = Color.BLACK;
-		Paint paint = new Paint();
-	    paint.setTextSize(textSize);
-	    paint.setColor(textColor);
-	    paint.setTextAlign(Paint.Align.LEFT);
-	    int width = (int) (paint.measureText(s) + 0.5f); // round
-	    int i;
-	    for(i=2;i<=width;i*=2); width = i;
-	    int baseline = (int) (textSize + 0.5f);
-	    int height = (int) (baseline + paint.descent() + 0.5f);
-	    for(i=2;i<=height;i*=2); height = i;
-	    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
-	    bitmap.eraseColor(Color.WHITE);
-	    Canvas canvas = new Canvas(bitmap);
-	    canvas.setBitmap(bitmap);
-	    canvas.drawText(s, 0, baseline, paint);
-	    // TMP
-		try {
-			FileOutputStream stream = new FileOutputStream(Environment.getExternalStorageDirectory()+"/test.jpg");
-			bitmap.compress(CompressFormat.JPEG, 80, stream);
-		} catch (FileNotFoundException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-	    // Get the pixel in a map
-	    ByteBuffer buffer = ByteBuffer.allocateDirect(width*height);
-	    buffer.order(ByteOrder.nativeOrder());
-	    buffer.position(0);
-	    for(int y = 0; y<height;y++)
-			for(int x = 0; x<width;x++)
-				buffer.put((byte) ((bitmap.getPixel(x, y) == Color.BLACK)? 0xFF : 0x00));
-	    buffer.position(0);
-	    byte[] b = new byte[buffer.capacity()];
-	    buffer.get(b);
-	    return b;
-	}
-	public static int getWidthFromString(String s, int textSize)
-	{
-		Paint paint = new Paint();
-	    paint.setTextSize(textSize);
-	    paint.setTextAlign(Paint.Align.LEFT);
-	    int ret = (int) (paint.measureText(s) + 0.5f);
-	    int i;
-	    for(i=2;i<=ret;i*=2); ret = i;
-	    return ret;
-	}
-	public static int getRealWidthFromString(String s, int textSize)
-	{
-		Paint paint = new Paint();
-	    paint.setTextSize(textSize);
-	    paint.setTextAlign(Paint.Align.LEFT);
-	    return (int) (paint.measureText(s) + 0.5f);
-	}
-	public static int getHeightFromString(String s, int textSize)
-	{
-		Paint paint = new Paint();
-	    paint.setTextSize(textSize);
-	    paint.setTextAlign(Paint.Align.LEFT);
-	    int ret = (int) (textSize + 0.5f + paint.descent() + 0.5f);
-	    int i;
-	    for(i=2;i<=ret;i*=2); ret = i;
-	    return ret;
-	}
+    private String _text;
+    private Bitmap _bitmap;
+    private int[] _textures = new int[1]; // Texture pointer
+
+    public StringTexture(String s) {
+        _text = s;
+        getBitmapFromText(12.0f, Color.BLACK);
+    }
+
+    private void getBitmapFromText(float textSize, int textColor) {
+        Paint paint = new Paint();
+        paint.setTextSize(textSize);
+        paint.setColor(textColor);
+        paint.setTextAlign(Paint.Align.LEFT);
+        int width = (int) (paint.measureText(_text) + 2.5f); // round
+        int baseline = (int) (textSize + 2.5f);
+        int height = (int) (baseline + paint.descent() + 2.5f);
+        _bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        _bitmap.eraseColor(Color.TRANSPARENT);
+        Canvas canvas = new Canvas(_bitmap);
+        canvas.setBitmap(_bitmap);
+        canvas.drawText(_text, 0, baseline, paint);
+    }
+
+    private void loadGLTexture(GL10 gl) {
+        if(_bitmap == null) return;
+        gl.glGenTextures(1, _textures, 0);
+
+        gl.glBindTexture(GL10.GL_TEXTURE_2D, _textures[0]);
+
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
+        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
+
+        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, _bitmap, 0);
+
+        _bitmap.recycle();
+    }
+
+    public void draw(GL10 gl, int x, int y) {
+        gl.glEnable(GL10.GL_TEXTURE_2D);
+        // VERTEX
+        float vertex[] = {
+            -1.0f, -1.0f,  0.0f,		// bottom left
+            -1.0f,  1.0f,  0.0f,		// top left
+            1.0f, -1.0f,  0.0f,		// bottom right
+            1.0f,  1.0f,  0.0f			// top right
+        };
+        FloatBuffer vertexBuffer;
+        ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(vertex.length * 4);
+        vertexByteBuffer.order(ByteOrder.nativeOrder());
+        vertexBuffer = vertexByteBuffer.asFloatBuffer();
+        vertexBuffer.put(vertex);
+        vertexBuffer.position(0);
+
+        // TEXTURE
+        FloatBuffer textureBuffer;	// buffer holding the texture coordinates
+        float texture[] = {
+            0.0f, 1.0f,		// top left
+            0.0f, 0.0f,		// bottom left
+            1.0f, 1.0f,		// top right
+            1.0f, 0.0f		// bottom right
+        };
+        ByteBuffer textureByteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
+        textureByteBuffer.order(ByteOrder.nativeOrder());
+        textureBuffer = textureByteBuffer.asFloatBuffer();
+        textureBuffer.put(texture);
+        textureBuffer.position(0);
+        loadGLTexture(gl);
+        gl.glBindTexture(GL10.GL_TEXTURE_2D, _textures[0]);
+
+
+        // DRAW
+        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
+        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
+        gl.glColor4f(1,1,1,1);
+        gl.glEnable(GL10.GL_BLEND);
+        gl.glBlendFunc(GL10.GL_SRC_COLOR, GL10.GL_ONE_MINUS_SRC_ALPHA);
+        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
+        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
+        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertex.length / 3);
+        gl.glDisable(GL10.GL_BLEND);
+        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
+        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
+        gl.glDisable(GL10.GL_TEXTURE_2D);
+    }
+
+    public static byte[] getBytesFromString(String s, int textSize)
+    {
+        // Generate the bitmap
+        int textColor = Color.BLACK;
+        Paint paint = new Paint();
+        paint.setTextSize(textSize);
+        paint.setColor(textColor);
+        paint.setTextAlign(Paint.Align.LEFT);
+        int width = (int) (paint.measureText(s) + 0.5f); // round
+        int i;
+        for(i=2;i<=width;i*=2); width = i;
+        int baseline = (int) (textSize + 0.5f);
+        int height = (int) (baseline + paint.descent() + 0.5f);
+        for(i=2;i<=height;i*=2); height = i;
+        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bitmap.eraseColor(Color.WHITE);
+        Canvas canvas = new Canvas(bitmap);
+        canvas.setBitmap(bitmap);
+        canvas.drawText(s, 0, baseline, paint);
+        // TMP
+        try {
+            FileOutputStream stream = new FileOutputStream(Environment.getExternalStorageDirectory()+"/test.jpg");
+            bitmap.compress(CompressFormat.JPEG, 80, stream);
+        } catch (FileNotFoundException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        // Get the pixel in a map
+        ByteBuffer buffer = ByteBuffer.allocateDirect(width*height);
+        buffer.order(ByteOrder.nativeOrder());
+        buffer.position(0);
+        for(int y = 0; y<height;y++)
+            for(int x = 0; x<width;x++)
+                buffer.put((byte) ((bitmap.getPixel(x, y) == Color.BLACK)? 0xFF : 0x00));
+        buffer.position(0);
+        byte[] b = new byte[buffer.capacity()];
+        buffer.get(b);
+        return b;
+    }
+    public static int getWidthFromString(String s, int textSize)
+    {
+        Paint paint = new Paint();
+        paint.setTextSize(textSize);
+        paint.setTextAlign(Paint.Align.LEFT);
+        int ret = (int) (paint.measureText(s) + 0.5f);
+        int i;
+        for(i=2;i<=ret;i*=2); ret = i;
+        return ret;
+    }
+    public static int getRealWidthFromString(String s, int textSize)
+    {
+        Paint paint = new Paint();
+        paint.setTextSize(textSize);
+        paint.setTextAlign(Paint.Align.LEFT);
+        return (int) (paint.measureText(s) + 0.5f);
+    }
+    public static int getHeightFromString(String s, int textSize)
+    {
+        Paint paint = new Paint();
+        paint.setTextSize(textSize);
+        paint.setTextAlign(Paint.Align.LEFT);
+        int ret = (int) (textSize + 0.5f + paint.descent() + 0.5f);
+        int i;
+        for(i=2;i<=ret;i*=2); ret = i;
+        return ret;
+    }
 }
diff --git a/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java b/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java
index 5f8d0cd..c69bbbc 100644
--- a/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java
+++ b/contrib/mobile/Android/src/org/geuz/onelab/mGLSurfaceView.java
@@ -11,124 +11,107 @@ import android.view.GestureDetector.OnGestureListener;
 import android.view.ScaleGestureDetector.OnScaleGestureListener;
 
 class mGLSurfaceView extends GLSurfaceView {
-	private float scaleFactor = 1f;
-	private GestureDetector gesture;
-	private ScaleGestureDetector scaleGesture;
-	private GLESRender _renderer;
-	public mGLSurfaceView(Context context, GLESRender renderer) {
-		super(context);
-		_renderer = renderer;
-		gesture = new GestureDetector(context, new GestureListener());
-		scaleGesture = new ScaleGestureDetector(context, new OnScaleGestureListener() {
-			
-			public void onScaleEnd(ScaleGestureDetector detector) {
-				_renderer.endInteraction(detector.getFocusX(), detector.getFocusY());
-			}
-			
-			public boolean onScaleBegin(ScaleGestureDetector detector) {
-				_renderer.startInteraction(detector.getFocusX(), detector.getFocusY());
-				return true;
-			}
-			
-			public boolean onScale(ScaleGestureDetector detector) {
-				scaleFactor *= detector.getScaleFactor();
-				scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 50.0f)); // limit the scale factor
-				_renderer.scaleModel(scaleFactor);
-				requestRender();
-				return true;
-				
-			}
-		});
-	}
-		
-	@Override
+    private float scaleFactor = 1f;
+    private GestureDetector gesture;
+    private ScaleGestureDetector scaleGesture;
+    private GLESRender _renderer;
+    private boolean _rotate;
+
+    public mGLSurfaceView(Context context, GLESRender renderer) {
+        super(context);
+        _renderer = renderer;
+        gesture = new GestureDetector(context, new GestureListener());
+        scaleGesture = new ScaleGestureDetector(context, new OnScaleGestureListener() {
+
+                public void onScaleEnd(ScaleGestureDetector detector) {
+                    _renderer.endInteraction(detector.getFocusX(), detector.getFocusY());
+                }
+
+                public boolean onScaleBegin(ScaleGestureDetector detector) {
+                    _renderer.startInteraction(detector.getFocusX(), detector.getFocusY());
+                    return true;
+                }
+
+                public boolean onScale(ScaleGestureDetector detector) {
+                    scaleFactor *= detector.getScaleFactor();
+                    scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 50.0f)); // limit the scale factor
+                    _renderer.scaleModel(scaleFactor);
+                    requestRender();
+                    return true;
+
+                }
+            });
+    }
+
+    @Override
 	public boolean onTouchEvent(MotionEvent event) {
-		if(event.getPointerCount() >= 3){
-			scaleGesture.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0,0, 0));
-			
-			final float x = event.getX(1);
-	        final float y = event.getY(1);
-	        
-	        int action = event.getActionMasked();
-	        
-	        if(action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_1_DOWN){
-	        	_renderer.startInteraction(x,y);
-	        }
-	        else if(action == MotionEvent.ACTION_MOVE){
-	        	_renderer.rotateModel(x, y);
-	        	requestRender();
-	        }
-	        else if(action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_1_UP){
-	        	_renderer.endInteraction(x, y);
-	        }
-
-			return true;
-		}
-		else {
-			scaleGesture.onTouchEvent(event);
-			return gesture.onTouchEvent(event);
-		}
-		
-	}
-	
-	private class GestureListener implements OnGestureListener, OnDoubleTapListener{
-		public boolean onDown(MotionEvent e) {
-			_renderer.startInteraction(e.getX(),e.getY());
-			return true;
-		}
-
-		public boolean onFling(MotionEvent e1, MotionEvent e2,
-				float velocityX, float velocityY) {
-			// UNUSED Auto-generated method stub
-			return false;
-		}
-
-		public void onLongPress(MotionEvent e) {
-			// UNUSED Auto-generated method stub
-			
-		}
-
-		public boolean onScroll(MotionEvent e1, MotionEvent e2,
+        scaleGesture.onTouchEvent(event);
+        return gesture.onTouchEvent(event);
+    }
+
+    private class GestureListener implements OnGestureListener, OnDoubleTapListener{
+        public boolean onDown(MotionEvent e) {
+            _renderer.startInteraction(e.getX(),e.getY());
+            return true;
+        }
+
+        public boolean onFling(MotionEvent e1, MotionEvent e2,
+                               float velocityX, float velocityY) {
+            // UNUSED Auto-generated method stub
+            return false;
+        }
+
+        public void onLongPress(MotionEvent e) {
+            // UNUSED Auto-generated method stub
+
+        }
+
+        public boolean onScroll(MotionEvent e1, MotionEvent e2,
 				float distanceX, float distanceY) {
-			if(e1.getPointerCount() > 1 || e2.getPointerCount() > 1) return false;
-			_renderer.translateModel(e2.getX(), e2.getY());
-			requestRender();
-			return true;
-		}
-
-		public void onShowPress(MotionEvent e) {
-			// UNUSED Auto-generated method stub
-			
-		}
-
-		public boolean onSingleTapUp(MotionEvent e) {
-			// UNUSED Auto-generated method stub
-			return false;
-		}
-		public boolean onDoubleTap(MotionEvent e) {
-			// UNUSED Auto-generated method stub
-			return false;
-		}
-		public boolean onDoubleTapEvent(MotionEvent e) {
-			scaleFactor = 1f;
-			_renderer.resetModelPosition();
-			requestRender();
-			return true;
-		}
-		public boolean onSingleTapConfirmed(MotionEvent e) {
-			// UNUSED Auto-generated method stub
-			return false;
-		}
-		
-	}
-	public void resetScale(){
-		scaleFactor = 1f;
-		_renderer.scaleModel(scaleFactor);
-	}
-	public Bitmap getScreenshot() {
-		_renderer.needScreenshot();
-		this.requestRender();
-		while(_renderer.getScreenshot() == null);
-		return _renderer.getScreenshot();
-	}
+            if(e1.getPointerCount() > 1 || e2.getPointerCount() > 1) return false;
+            if(_rotate)
+                _renderer.rotateModel(e2.getX(), e2.getY());
+            else
+                _renderer.translateModel(e2.getX(), e2.getY());
+            requestRender();
+            return true;
+        }
+
+        public void onShowPress(MotionEvent e) {
+            // UNUSED Auto-generated method stub
+
+        }
+
+        public boolean onSingleTapUp(MotionEvent e) {
+            // UNUSED Auto-generated method stub
+            return false;
+        }
+        public boolean onDoubleTap(MotionEvent e) {
+            // UNUSED Auto-generated method stub
+            return false;
+        }
+        public boolean onDoubleTapEvent(MotionEvent e) {
+            scaleFactor = 1f;
+            _renderer.resetModelPosition();
+            requestRender();
+            return true;
+        }
+        public boolean onSingleTapConfirmed(MotionEvent e) {
+            // UNUSED Auto-generated method stub
+            return false;
+        }
+
+    }
+    public boolean getRotate() {return _rotate;}
+    public void setRotate(boolean r) {_rotate = r;}
+    public void resetScale(){
+        scaleFactor = 1f;
+        _renderer.scaleModel(scaleFactor);
+    }
+    public Bitmap getScreenshot() {
+        _renderer.needScreenshot();
+        this.requestRender();
+        while(_renderer.getScreenshot() == null);
+        return _renderer.getScreenshot();
+    }
 }
diff --git a/contrib/mobile/CMakeLists.txt b/contrib/mobile/CMakeLists.txt
index e56cf87..d85a1ab 100644
--- a/contrib/mobile/CMakeLists.txt
+++ b/contrib/mobile/CMakeLists.txt
@@ -10,6 +10,19 @@ else(APPLE)
   option(ENABLE_BUILD_ANDROID "Build library for Android NDK (ARMv7)" ON)
 endif(APPLE)
 
+# find all benchmarks who provide infos.xml
+find_path(BENCHMARKSDIR benchmarks/)
+file(GLOB BENCHMARKSDIR ${BENCHMARKSDIR}/benchmarks/*)
+foreach(SUBDIR ${BENCHMARKSDIR})
+  if(IS_DIRECTORY ${SUBDIR})
+    file(GLOB INFOSFILE ${SUBDIR}/infos.xml)
+    if(INFOSFILE)
+      message(STATUS "Found benchmark ${SUBDIR}")
+      list(APPEND BENCHMARKS ${SUBDIR})
+    endif()
+  endif()
+endforeach()
+
 macro(set_config_option VARNAME STRING)
   set(${VARNAME} TRUE)
   list(APPEND CONFIG_OPTIONS ${STRING})
@@ -23,19 +36,12 @@ macro(append_src FILES)
   set(ONELAB_SRC ${ONELAB_SRC};${LIST})
 endmacro(append_src)
 
-macro(copy_headers SOURCE DEST)
-  file(GLOB hfiles "${SOURCE}/*.h")
-  foreach(file ${hfiles})
-    add_custom_command(TARGET xcodeProject POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${file} ${DEST})
-  endforeach(file ${hfiles})
-endmacro(copy_headers)
-
 if(ENABLE_BUILD_IOS_EMULATOR OR ENABLE_BUILD_IOS)
   # we need getdp framework
   find_path(GETDP_FRAMEWORK GetDP.framework)
   if(GETDP_FRAMEWORK)
     set(GETDP_FRAMEWORK ${GETDP_FRAMEWORK}/GetDP.framework)
-    message(STATUS "Found " ${GETDP_FRAMEWORK})
+    message(STATUS "Found framework " ${GETDP_FRAMEWORK})
   else(GETDP_FRAMEWORK)
     message(SEND_ERROR "Could not find GetDP.framework")
   endif(GETDP_FRAMEWORK)
@@ -43,7 +49,7 @@ if(ENABLE_BUILD_IOS_EMULATOR OR ENABLE_BUILD_IOS)
   find_path(GMSH_FRAMEWORK Gmsh.framework)
   if(GMSH_FRAMEWORK)
     set(GMSH_FRAMEWORK ${GMSH_FRAMEWORK}/Gmsh.framework)
-    message(STATUS "Found " ${GMSH_FRAMEWORK})
+    message(STATUS "Found framework " ${GMSH_FRAMEWORK})
   else(GMSH_FRAMEWORK)
     message(SEND_ERROR "Could not find Gmsh.framework")
   endif(GMSH_FRAMEWORK)
@@ -51,17 +57,26 @@ if(ENABLE_BUILD_IOS_EMULATOR OR ENABLE_BUILD_IOS)
   find_path(PETSC_FRAMEWORK petsc.framework)
   if(PETSC_FRAMEWORK)
     set(PETSC_FRAMEWORK ${PETSC_FRAMEWORK}/petsc.framework)
-    message(STATUS "Found " ${PETSC_FRAMEWORK})
+    message(STATUS "Found framework " ${PETSC_FRAMEWORK})
   else(PETSC_FRAMEWORK)
     message(SEND_ERROR "Could not find petsc.framework")
   endif(PETSC_FRAMEWORK)
+  # and we also need SLEPc
+  find_path(SLEPC_FRAMEWORK slepc.framework)
+  if(SLEPC_FRAMEWORK)
+    set(SLEPC_FRAMEWORK ${SLEPC_FRAMEWORK}/slepc.framework)
+    message(STATUS "Found framework " ${SLEPC_FRAMEWORK})
+  else(SLEPC_FRAMEWORK)
+    message(SEND_ERROR "Could not find slepc.framework")
+  endif(SLEPC_FRAMEWORK)
   # add target
   add_custom_target(xcodeProject
-    cd ${CMAKE_CURRENT_SOURCE_DIR}/utils/ && ${CMAKE_CURRENT_SOURCE_DIR}/utils/make_icon_ios.sh
+    COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/models/
     COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/Onelab/
-    COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/utils/ios.iconset/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/
-    COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/iOS/Onelab/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/
-    COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/iOS/Onelab.xcodeproj/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab.xcodeproj/
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/iOS/Onelab/ 
+                                               ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/iOS/Onelab.xcodeproj/
+                                               ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab.xcodeproj/
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/drawContext.cpp ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/drawContext.h ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/drawGeom.cpp ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/
@@ -73,16 +88,20 @@ if(ENABLE_BUILD_IOS_EMULATOR OR ENABLE_BUILD_IOS)
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/movePosition.h ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/iosGModel.h ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/
     COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/iosGModel.cpp ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/
-    COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/GetDP.framework/Headers/
-    COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/Gmsh.framework/Headers/
-    COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/petsc.framework/Headers/
-    COMMAND ${CMAKE_COMMAND} -E copy ${GETDP_FRAMEWORK}/GetDP ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/GetDP.framework/
-    COMMAND ${CMAKE_COMMAND} -E copy ${GMSH_FRAMEWORK}/Gmsh ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/Gmsh.framework/
-    COMMAND ${CMAKE_COMMAND} -E copy ${PETSC_FRAMEWORK}/petsc ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/petsc.framework/
+    COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${GETDP_FRAMEWORK}/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/GetDP.framework/
+    COMMAND ${CMAKE_COMMAND} -E remove ${GMSH_FRAMEWORK}/Headers/gmsh
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${GMSH_FRAMEWORK}/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/Gmsh.framework/
+    COMMAND ${CMAKE_COMMAND} -E create_symlink . ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/Gmsh.framework/Headers/gmsh
+    COMMAND ${CMAKE_COMMAND} -E create_symlink . ${GMSH_FRAMEWORK}/Headers/gmsh
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${PETSC_FRAMEWORK}/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/petsc.framework/
+    COMMAND ${CMAKE_COMMAND} -E copy_directory ${SLEPC_FRAMEWORK}/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/slepc.framework/
   )
-  copy_headers(${GETDP_FRAMEWORK}/Headers/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/GetDP.framework/Headers/)
-  copy_headers(${GMSH_FRAMEWORK}/Headers/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/Gmsh.framework/Headers/)
-  copy_headers(${PETSC_FRAMEWORK}/Headers/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/frameworks/petsc.framework/Headers/)
+  foreach(DIR ${BENCHMARKS})
+    get_filename_component(DIRNAME ${DIR} NAME)
+    add_custom_command(TARGET xcodeProject POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory
+                    ${DIR} ${CMAKE_CURRENT_BINARY_DIR}/Onelab/Onelab/files/${DIRNAME})
+  endforeach(DIR)
 
   message(STATUS "")
   message(STATUS "ONELAB for iOS successfully configured:")
@@ -142,6 +161,7 @@ if(ENABLE_BUILD_ANDROID)
   if(PETSC_LIB AND BLAS_LIB AND LAPACK_LIB AND ONELAB_LIB)
     add_custom_target(androidProject
       COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/Onelab/
+      COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/models/
       COMMAND ${CMAKE_COMMAND} -E copy_directory  ${CMAKE_CURRENT_SOURCE_DIR}/Android/ ${CMAKE_CURRENT_BINARY_DIR}/Onelab/
       COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/Onelab/libs/armeabi-v7a/
       COMMAND ${CMAKE_COMMAND} -E copy ${GMSH_LIB} ${CMAKE_CURRENT_BINARY_DIR}/Onelab/libs/armeabi-v7a/
@@ -150,7 +170,23 @@ if(ENABLE_BUILD_ANDROID)
       COMMAND ${CMAKE_COMMAND} -E copy ${PETSC_LIB} ${CMAKE_CURRENT_BINARY_DIR}/Onelab/libs/armeabi-v7a/
       COMMAND ${CMAKE_COMMAND} -E copy ${LAPACK_LIB} ${CMAKE_CURRENT_BINARY_DIR}/Onelab/libs/armeabi-v7a/
       COMMAND ${CMAKE_COMMAND} -E copy ${BLAS_LIB} ${CMAKE_CURRENT_BINARY_DIR}/Onelab/libs/armeabi-v7a/
-  )
+    )
+    foreach(DIR ${BENCHMARKS})
+      get_filename_component(DIRNAME ${DIR} NAME)
+      add_custom_command(TARGET androidProject POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory
+                      ${DIR} ${CMAKE_CURRENT_BINARY_DIR}/models/${DIRNAME})
+    endforeach(DIR)
+    find_program(ZIP_COMMAND zip)
+    add_custom_command(TARGET androidProject POST_BUILD COMMAND cd ${CMAKE_CURRENT_BINARY_DIR}/models/ && zip -r
+                     ${CMAKE_CURRENT_BINARY_DIR}/Onelab/res/raw/models.zip * --exclude=*.svn*)
+
+  message(STATUS "")
+  message(STATUS "ONELAB for Android successfully configured:")
+  message(STATUS " * Run `make androidProject' to create the project")
+  message(STATUS " * Then update android project with 'android update project --name Onelab --path Onelab --target [id] --subprojects'")
+  message(STATUS " * Finally you can build the app with ant 'ant debug'")
+  message(STATUS "")
+ 
   else(PETSC_LIB AND BLAS_LIB AND LAPACK_LIB AND ONELAB_LIB)
     message(STATUS "Cannot make Android project without PETSc or without BLAS or without LAPACK or without \"Onelab library\"")
   endif(PETSC_LIB AND BLAS_LIB AND LAPACK_LIB AND ONELAB_LIB)
diff --git a/contrib/mobile/README.txt b/contrib/mobile/README.txt
new file mode 100644
index 0000000..d451b4e
--- /dev/null
+++ b/contrib/mobile/README.txt
@@ -0,0 +1,30 @@
+This directory contains the source code for Onelab/Mobile, the mobile version of
+Onelab for iOS and Android devices.
+
+Copyright (C) 2014 Christophe Geuzaine and Maxime Graulich, University of Liege
+
+On iTunes:
+
+Onelab (http://onelab.info) is a finite element package based on the open source
+mesh generator Gmsh (http://gmsh.info) and the solver GetDP
+(http://getdp.info). It can be used to simulate a wide variety of multi-physic
+problems: electromagnetics, thermics, mechanics...
+
+Onelab comes packaged with a selection of ready-to-use examples. New models can
+be added through iTunes file sharing: see http://onelab.info/wiki/Mobile for
+more information.
+
+https://itunes.apple.com/us/app/onelab/id845930897
+
+On Google Play:
+
+Onelab (http://onelab.info) is a finite element package based on the open source
+mesh generator Gmsh (http://gmsh.info) and the solver GetDP
+(http://getdp.info). It can be used to simulate a wide variety of multi-physic
+problems: electromagnetics, thermics, mechanics... 
+
+Onelab comes packaged with a selection of ready-to-use examples. New models can
+be opened directly on your device: see http://onelab.info/wiki/Mobile for more
+information.
+
+https://play.google.com/store/apps/details?id=org.geuz.onelab
diff --git a/contrib/mobile/Trackball.cpp b/contrib/mobile/Trackball.cpp
index ad4d56e..25a5714 100644
--- a/contrib/mobile/Trackball.cpp
+++ b/contrib/mobile/Trackball.cpp
@@ -99,7 +99,7 @@ vsub(const double *src1, const double *src2, double *dst)
 void
 vcopy(const double *v1, double *v2)
 {
-    register int i;
+    /* register */ int i;
     for (i = 0 ; i < 3 ; i++)
         v2[i] = v1[i];
 }
@@ -186,13 +186,13 @@ trackball(double q[4], double p1x, double p1y, double p2x, double p2y)
    *  Now, we want the cross product of P1 and P2
    */
   vcross(p2,p1,a);
-   
+
   /*
    *  Figure out how much to rotate around that axis.
    */
   vsub(p1,p2,d);
   t = vlength(d);
-    
+
   /*
    * Avoid problems with out-of-control values...
    */
@@ -225,9 +225,9 @@ tb_project_to_sphere(double r, double x, double y)
 
   d = sqrt(x*x + y*y);
 
-  if (d < r ) {    
+  if (d < r ) {
     z = sqrt(r*r - d*d);
-  } else {           
+  } else {
     z = 0.;
   }
 
diff --git a/contrib/mobile/androidGModel.cpp b/contrib/mobile/androidGModel.cpp
index bf336d0..c8de0cc 100644
--- a/contrib/mobile/androidGModel.cpp
+++ b/contrib/mobile/androidGModel.cpp
@@ -1,11 +1,15 @@
+#ifndef NDEBUG
 #include <android/log.h>
-#include <dlfcn.h>
-
 #define  LOG_TAG    "Gmsh"
 #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
 #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
+#endif
+
+#include <dlfcn.h>
 
 #include <gmsh/Gmsh.h>
+#include <gmsh/GmshConfig.h>
+#include <gmsh/GmshVersion.h>
 #include <gmsh/GModel.h>
 #include <gmsh/onelab.h>
 #include <gmsh/onelabUtils.h>
@@ -14,6 +18,9 @@
 #include <gmsh/PViewData.h>
 #include <gmsh/PViewOptions.h>
 
+#include <getdp/GetDPConfig.h>
+#include <getdp/GetDPVersion.h>
+
 #include "androidGModel.h"
 #include "drawContext.h"
 
@@ -25,302 +32,337 @@ static jobject gCallbackObject = NULL;
 
 class MobileMessage : public GmshMessage
 {
-	private:
-	public:
-	MobileMessage(){}
-	~MobileMessage(){}
-	void operator()(std::string level, std::string message)
-	{
-		if(level == "Error")
-		{
-	 		LOGE("Error:\t%s", message.c_str());
-			JNIEnv *env;
-			if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK || !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
-			jstring jstr = env->NewStringUTF(message.c_str());
-			jclass jClass = env->FindClass("org/geuz/onelab/Gmsh"); 
-			if(jClass == 0)
-				return;
-			jmethodID mid = env->GetMethodID(jClass, "ShowPopup", "(Ljava/lang/String;)V");
-			if (mid == 0)
-				return;
-			env->CallVoidMethod(gCallbackObject, mid, jstr);
-			env->DeleteLocalRef(jstr);
-			env->DeleteLocalRef(jClass);
-			return;
-		}
-		else if(level == "Progress")
-		{
-			JNIEnv *env;
-			if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK || !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
-			jstring jstr = env->NewStringUTF(message.c_str());
-			jclass jClass = env->FindClass("org/geuz/onelab/Gmsh"); 
-			if(jClass == 0)
-				return;
-			jmethodID mid = env->GetMethodID(jClass, "SetLoading", "(Ljava/lang/String;)V");
-			if (mid == 0)
-				return;
-			env->CallVoidMethod(gCallbackObject, mid, jstr);
-			env->DeleteLocalRef(jstr);
-			env->DeleteLocalRef(jClass);
-			return;
-		}
-		else if(level == "RequestRender")
-		{
-			requestRender();
-			return;
-		}
-	 	LOGI("%s:\t%s", level.c_str(), message.c_str());
-	}
+public:
+  MobileMessage(){}
+  ~MobileMessage(){}
+  void operator()(std::string level, std::string message)
+  {
+    if(level == "Error"){
+#ifndef NDEBUG
+      LOGE("Error:\t%s", message.c_str());
+#endif
+      JNIEnv *env;
+      if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK ||
+         !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
+      jstring jstr = env->NewStringUTF(message.c_str());
+      jclass jClass = env->FindClass("org/geuz/onelab/Gmsh");
+      if(jClass == 0)
+        return;
+      jmethodID mid = env->GetMethodID(jClass, "ShowPopup", "(Ljava/lang/String;)V");
+      if (mid == 0)
+        return;
+      env->CallVoidMethod(gCallbackObject, mid, jstr);
+      env->DeleteLocalRef(jstr);
+      env->DeleteLocalRef(jClass);
+      return;
+    }
+    else if(level == "Progress"){
+      JNIEnv *env;
+      if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK ||
+         !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
+      jstring jstr = env->NewStringUTF(message.c_str());
+      jclass jClass = env->FindClass("org/geuz/onelab/Gmsh");
+      if(jClass == 0)
+        return;
+      jmethodID mid = env->GetMethodID(jClass, "SetLoading", "(Ljava/lang/String;)V");
+      if (mid == 0)
+        return;
+      env->CallVoidMethod(gCallbackObject, mid, jstr);
+      env->DeleteLocalRef(jstr);
+      env->DeleteLocalRef(jClass);
+      return;
+    }
+    else if(level == "RequestRender"){
+      requestRender();
+      return;
+    }
+#ifndef NDEBUG
+    LOGI("%s:\t%s", level.c_str(), message.c_str());
+#endif
+  }
 };
 
 void requestRender()
 {
-	JNIEnv *env;
-	if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK || !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
-	jclass jClass = env->FindClass("org/geuz/onelab/Gmsh"); 
-	if(jClass == 0)
-		return;
-	jmethodID mid = env->GetMethodID(jClass, "RequestRender", "()V");
-	if (mid == 0)
-		return;
-	env->CallVoidMethod(gCallbackObject, mid);
-	env->DeleteLocalRef(jClass);
+  JNIEnv *env;
+  if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK ||
+     !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
+  jclass jClass = env->FindClass("org/geuz/onelab/Gmsh");
+  if(jClass == 0)
+    return;
+  jmethodID mid = env->GetMethodID(jClass, "RequestRender", "()V");
+  if (mid == 0)
+    return;
+  env->CallVoidMethod(gCallbackObject, mid);
+  env->DeleteLocalRef(jClass);
 }
 
-void getBitmapFromString(const char *text, int textsize, unsigned char **map, int *height, int *width, int *realWidth)
+void getBitmapFromString(const char *text, int textsize, unsigned char **map,
+                         int *height, int *width, int *realWidth)
 {
-	JNIEnv *env;
-	if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK || !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
-	jclass jClass = env->FindClass("org/geuz/onelab/StringTexture"); 
-	if(jClass == 0)
-		return;
-	jstring jtext = env->NewStringUTF(text);
-	jmethodID mid = env->GetStaticMethodID(jClass, "getHeightFromString", "(Ljava/lang/String;I)I");
-	*height = env->CallIntMethod(gCallbackObject, mid, jtext, textsize);
-	mid = env->GetStaticMethodID(jClass, "getWidthFromString", "(Ljava/lang/String;I)I");
-	*width =env->CallIntMethod(gCallbackObject, mid, jtext, textsize);
-	if(realWidth != NULL){
-		mid = env->GetStaticMethodID(jClass, "getRealWidthFromString", "(Ljava/lang/String;I)I");
-		*realWidth = env->CallIntMethod(gCallbackObject, mid, jtext, textsize);
-	}
-	mid = env->GetStaticMethodID(jClass, "getBytesFromString", "(Ljava/lang/String;I)[B");
-	jobject jbuffer = env->CallObjectMethod(gCallbackObject, mid, jtext, textsize);
-	jbyteArray *jarray = reinterpret_cast<jbyteArray*>(&jbuffer);
-	*map = (unsigned char *) malloc((*height)*(*width));
-	env->GetByteArrayRegion(*jarray, 0, (*height)*(*width), (jbyte*)*map);
-	env->DeleteLocalRef(jClass);
-	env->DeleteLocalRef(jtext);
+  JNIEnv *env;
+  if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK ||
+     !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
+  jclass jClass = env->FindClass("org/geuz/onelab/StringTexture");
+  if(jClass == 0)
+    return;
+  jstring jtext = env->NewStringUTF(text);
+  jmethodID mid = env->GetStaticMethodID(jClass, "getHeightFromString",
+                                         "(Ljava/lang/String;I)I");
+  *height = env->CallIntMethod(gCallbackObject, mid, jtext, textsize);
+  mid = env->GetStaticMethodID(jClass, "getWidthFromString", "(Ljava/lang/String;I)I");
+  *width =env->CallIntMethod(gCallbackObject, mid, jtext, textsize);
+  if(realWidth != NULL){
+    mid = env->GetStaticMethodID(jClass, "getRealWidthFromString", "(Ljava/lang/String;I)I");
+    *realWidth = env->CallIntMethod(gCallbackObject, mid, jtext, textsize);
+  }
+  mid = env->GetStaticMethodID(jClass, "getBytesFromString", "(Ljava/lang/String;I)[B");
+  jobject jbuffer = env->CallObjectMethod(gCallbackObject, mid, jtext, textsize);
+  jbyteArray *jarray = reinterpret_cast<jbyteArray*>(&jbuffer);
+  *map = (unsigned char *) malloc((*height)*(*width));
+  env->GetByteArrayRegion(*jarray, 0, (*height)*(*width), (jbyte*)*map);
+  env->DeleteLocalRef(jClass);
+  env->DeleteLocalRef(jtext);
 }
 
 extern "C" {
-JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
-	gJavaVM = vm;
-	return JNI_VERSION_1_6;
-}
-JNIEXPORT jlong JNICALL Java_org_geuz_onelab_Gmsh_init
-  (JNIEnv *env, jobject obj)
-{
-	if(gCallbackObject != NULL) env->DeleteGlobalRef(gCallbackObject);
-	gCallbackObject = env->NewGlobalRef(obj);
-	gJavaVM->GetEnv((void**)&env, JNI_VERSION_1_6);
-	Msg::SetCallback(new MobileMessage());
-	return reinterpret_cast<jlong>(new drawContext());
-}
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_loadFile
+  JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
+  {
+    gJavaVM = vm;
+    return JNI_VERSION_1_6;
+  }
+  JNIEXPORT jlong JNICALL Java_org_geuz_onelab_Gmsh_init
+  (JNIEnv *env, jobject obj, jfloat fontFactor)
+  {
+    if(gCallbackObject != NULL) env->DeleteGlobalRef(gCallbackObject);
+    gCallbackObject = env->NewGlobalRef(obj);
+    gJavaVM->GetEnv((void**)&env, JNI_VERSION_1_6);
+    Msg::SetCallback(new MobileMessage());
+    return reinterpret_cast<jlong>(new drawContext(fontFactor));
+  }
+  JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_loadFile
   (JNIEnv *env, jobject obj, jlong jptr, jstring jname)
-{
-	const char*  filename = env->GetStringUTFChars(jname, NULL);
-	((drawContext *)jptr)->load(filename);
-}
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_initView
+  {
+    const char*  filename = env->GetStringUTFChars(jname, NULL);
+    ((drawContext *)jptr)->load(filename);
+  }
+  JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_initView
   (JNIEnv *env, jobject obj, jlong jptr, jint w, jint h)
-{
-	((drawContext *)jptr)->initView(w,h);
-}
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_drawView
+  {
+    ((drawContext *)jptr)->initView(w,h);
+  }
+  JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_drawView
   (JNIEnv *env, jobject obj, jlong jptr)
-{
-	((drawContext *)jptr)->drawView();
-}
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_eventHandler
+  {
+    ((drawContext *)jptr)->drawView();
+  }
+  JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_eventHandler
   (JNIEnv *env, jobject obj, jlong jptr, jint jevent, jfloat jx, jfloat jy)
-{
-	((drawContext *)jptr)->eventHandler(jevent, jx, jy);
-}
-JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_setStringOption
+  {
+    ((drawContext *)jptr)->eventHandler(jevent, jx, jy);
+  }
+  JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_setStringOption
   (JNIEnv *env, jobject obj, jstring c, jstring n, jstring v)
-{
-	const char* tmp;
-	tmp = env->GetStringUTFChars(v, NULL);
-	const std::string value(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(v, tmp);
-	tmp = env->GetStringUTFChars(n, NULL);
-	const std::string name(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(n, tmp);
-	tmp = env->GetStringUTFChars(c, NULL);
-	std::string category(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(c, tmp);
-	GmshSetOption(category, name, value, 0);
-}
-JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_setDoubleOption
+  {
+    const char* tmp;
+    tmp = env->GetStringUTFChars(v, NULL);
+    const std::string value(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(v, tmp);
+    tmp = env->GetStringUTFChars(n, NULL);
+    const std::string name(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(n, tmp);
+    tmp = env->GetStringUTFChars(c, NULL);
+    std::string category(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(c, tmp);
+    GmshSetOption(category, name, value, 0);
+  }
+  JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_setDoubleOption
   (JNIEnv *env, jobject obj, jstring c, jstring n, jdouble v)
-{
-	const char* tmp;
-	tmp = env->GetStringUTFChars(n, NULL);
-	const std::string name(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(n, tmp);
-	tmp = env->GetStringUTFChars(c, NULL);
-	const std::string category(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(c, tmp);
-	GmshSetOption(category, name, (double)v);
-}
-JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_setIntegerOption
+  {
+    const char* tmp;
+    tmp = env->GetStringUTFChars(n, NULL);
+    const std::string name(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(n, tmp);
+    tmp = env->GetStringUTFChars(c, NULL);
+    const std::string category(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(c, tmp);
+    GmshSetOption(category, name, (double)v);
+  }
+  JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_setIntegerOption
   (JNIEnv *env, jobject obj, jstring c, jstring n, jint v)
-{
-	const char* tmp;
-	tmp = env->GetStringUTFChars(n, NULL);
-	const std::string name(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(n, tmp);
-	tmp = env->GetStringUTFChars(c, NULL);
-	const std::string category(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(c, tmp);
-	GmshSetOption(category, name, (unsigned int)v);
-}
-JNIEXPORT jstring JNICALL Java_org_geuz_onelab_Gmsh_getStringOption
+  {
+    const char* tmp;
+    tmp = env->GetStringUTFChars(n, NULL);
+    const std::string name(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(n, tmp);
+    tmp = env->GetStringUTFChars(c, NULL);
+    const std::string category(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(c, tmp);
+    GmshSetOption(category, name, (unsigned int)v);
+  }
+  JNIEXPORT jstring JNICALL Java_org_geuz_onelab_Gmsh_getStringOption
   (JNIEnv *env, jobject obj, jstring c, jstring n)
-{
-	const char* tmp;
-	tmp = env->GetStringUTFChars(n, NULL);
-	const std::string name(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(n, tmp);
-	tmp = env->GetStringUTFChars(c, NULL);
-	const std::string category(tmp, strlen(tmp));
-	std::string value;
-	GmshGetOption(category, name, value);
-	return env->NewStringUTF(value.c_str());
-	
-}
-JNIEXPORT jdouble JNICALL Java_org_geuz_onelab_Gmsh_getDoubleOption
+  {
+    const char* tmp;
+    tmp = env->GetStringUTFChars(n, NULL);
+    const std::string name(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(n, tmp);
+    tmp = env->GetStringUTFChars(c, NULL);
+    const std::string category(tmp, strlen(tmp));
+    std::string value;
+    GmshGetOption(category, name, value);
+    return env->NewStringUTF(value.c_str());
+
+  }
+  JNIEXPORT jdouble JNICALL Java_org_geuz_onelab_Gmsh_getDoubleOption
   (JNIEnv *env, jobject obj, jstring c, jstring n)
-{
-	const char* tmp;
-	tmp = env->GetStringUTFChars(n, NULL);
-	const std::string name(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(n, tmp);
-	tmp = env->GetStringUTFChars(c, NULL);
-	const std::string category(tmp, strlen(tmp));
-	double value;
-	GmshGetOption(category, name, value);
-	return value;
-}
-JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_getIntegerOption
+  {
+    const char* tmp;
+    tmp = env->GetStringUTFChars(n, NULL);
+    const std::string name(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(n, tmp);
+    tmp = env->GetStringUTFChars(c, NULL);
+    const std::string category(tmp, strlen(tmp));
+    double value;
+    GmshGetOption(category, name, value);
+    return value;
+  }
+  JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_getIntegerOption
   (JNIEnv *env, jobject obj, jstring c, jstring n)
-{
-	const char* tmp;
-	tmp = env->GetStringUTFChars(n, NULL);
-	const std::string name(tmp, strlen(tmp));
-	env->ReleaseStringUTFChars(n, tmp);
-	tmp = env->GetStringUTFChars(c, NULL);
-	const std::string category(tmp, strlen(tmp));
-	unsigned int value;
-	GmshGetOption(category, name, value, 0);
-	return value;
-}
+  {
+    const char* tmp;
+    tmp = env->GetStringUTFChars(n, NULL);
+    const std::string name(tmp, strlen(tmp));
+    env->ReleaseStringUTFChars(n, tmp);
+    tmp = env->GetStringUTFChars(c, NULL);
+    const std::string category(tmp, strlen(tmp));
+    unsigned int value;
+    GmshGetOption(category, name, value, 0);
+    return value;
+  }
 
-JNIEXPORT jobjectArray JNICALL Java_org_geuz_onelab_Gmsh_getParams
+  JNIEXPORT jobjectArray JNICALL Java_org_geuz_onelab_Gmsh_getParams
   (JNIEnv *env, jobject obj)
-{
-	jclass stringClass = env->FindClass( "java/lang/String" );
-	std::vector<std::string> tmp =  onelab::server::instance()->toChar();
-	for(unsigned int i=0;i<tmp.size();i++)
-		for(unsigned int j=0; j<tmp[i].size();j++)
-			if(tmp[i][j] == '\0') tmp[i][j] = 0x03;
-	jobjectArray params = env->NewObjectArray(tmp.size(), stringClass, 0);
-	for(int i=0; i<tmp.size();i++){
-		jstring s = env->NewStringUTF(tmp[i].c_str());
-		env->SetObjectArrayElement(params, i, s);
-		env->DeleteLocalRef(s);
-	}
-	return params;
-}
+  {
+    jclass stringClass = env->FindClass( "java/lang/String" );
+    std::vector<std::string> tmp =  onelab::server::instance()->toChar();
+    for(unsigned int i=0;i<tmp.size();i++)
+      for(unsigned int j=0; j<tmp[i].size();j++)
+        if(tmp[i][j] == '\0') tmp[i][j] = 0x03;
+    jobjectArray params = env->NewObjectArray(tmp.size(), stringClass, 0);
+    for(int i=0; i<tmp.size();i++){
+      jstring s = env->NewStringUTF(tmp[i].c_str());
+      env->SetObjectArrayElement(params, i, s);
+      env->DeleteLocalRef(s);
+    }
+    return params;
+  }
 
-JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_setParam
+  JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_setParam
   (JNIEnv *env, jobject obj, jstring jtype, jstring jname, jstring jvalue)
-{
-	const char *type = env->GetStringUTFChars(jtype, NULL);
-	const char *name = env->GetStringUTFChars(jname, NULL);
-	const char *value = env->GetStringUTFChars(jvalue, NULL);
-	// Get the original param and then change the value
-	if(strcmp(type,"ParameterNumber") == 0){
-		std::vector<onelab::number> s;
-		if(onelab::server::instance()->get(s,  name)){
-			s[0].setValue(atof(value));
-			onelab::server::instance()->set(s[0]);
-		}
-	}
-	else if(strcmp(type,"ParameterString") == 0){
-		std::vector<onelab::string> s;
-		if(onelab::server::instance()->get(s,  name)){
-			s[0].setValue(value);
-			onelab::server::instance()->set(s[0]);
-		}
-	}
-}
+  {
+    const char *type = env->GetStringUTFChars(jtype, NULL);
+    const char *name = env->GetStringUTFChars(jname, NULL);
+    const char *value = env->GetStringUTFChars(jvalue, NULL);
+    // Get the original param and then change the value
+    if(strcmp(type,"ParameterNumber") == 0){
+      std::vector<onelab::number> s;
+      if(onelab::server::instance()->get(s,  name)){
+        s[0].setValue(atof(value));
+        onelab::server::instance()->set(s[0]);
+      }
+    }
+    else if(strcmp(type,"ParameterString") == 0){
+      std::vector<onelab::string> s;
+      if(onelab::server::instance()->get(s,  name)){
+        s[0].setValue(value);
+        onelab::server::instance()->set(s[0]);
+      }
+    }
+  }
 
-JNIEXPORT jobjectArray JNICALL Java_org_geuz_onelab_Gmsh_getPView
+  JNIEXPORT jobjectArray JNICALL Java_org_geuz_onelab_Gmsh_getPView
   (JNIEnv *env, jobject obj)
-{
-	jclass stringClass = env->FindClass( "java/lang/String" );
-	jobjectArray jPView = env->NewObjectArray(PView::list.size(), stringClass, 0);
-	for(unsigned int i = 0; i < PView::list.size(); i++){
-		std::ostringstream sstream;
-		sstream	<< PView::list[i]->getData()->getName().c_str()
-			<< "\n" <<  PView::list[i]->getOptions()->intervalsType
-			<< "\n" << ((PView::list[i]->getOptions()->visible) ? 1 : 0)
-			<< "\n" << PView::list[i]->getOptions()->nbIso
-			<< "\n" << PView::list[i]->getOptions()->raise[2];
-		jstring s = env->NewStringUTF(sstream.str().c_str());
-		env->SetObjectArrayElement(jPView, i, s);
-		env->DeleteLocalRef(s);
-	}
-	return jPView;
-}
+  {
+    jclass stringClass = env->FindClass( "java/lang/String" );
+    jobjectArray jPView = env->NewObjectArray(PView::list.size(), stringClass, 0);
+    for(unsigned int i = 0; i < PView::list.size(); i++){
+      std::ostringstream sstream;
+      sstream	<< PView::list[i]->getData()->getName().c_str()
+                << "\n" <<  PView::list[i]->getOptions()->intervalsType
+                << "\n" << ((PView::list[i]->getOptions()->visible) ? 1 : 0)
+                << "\n" << PView::list[i]->getOptions()->nbIso
+                << "\n" << PView::list[i]->getOptions()->raise[2];
+      jstring s = env->NewStringUTF(sstream.str().c_str());
+      env->SetObjectArrayElement(jPView, i, s);
+      env->DeleteLocalRef(s);
+    }
+    return jPView;
+  }
 
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setPView
+  JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setPView
   (JNIEnv *env, jobject, jint pos, jint intervalsType, jint visible, jint nIntervals, jfloat raisez)
-{
-	if(intervalsType > 0 && intervalsType < 4) PView::list[pos]->getOptions()->intervalsType = intervalsType;
-	if(visible >= 0) PView::list[pos]->getOptions()->visible = visible;
-	if(nIntervals > 0) PView::list[pos]->getOptions()->nbIso = nIntervals;
-	if(raisez>=0) PView::list[pos]->getOptions()->raise[2] = raisez;
-	PView::list[pos]->setChanged(true);
-}
+  {
+    if(intervalsType > 0 && intervalsType < 4) PView::list[pos]->getOptions()->intervalsType = intervalsType;
+    if(visible >= 0) PView::list[pos]->getOptions()->visible = visible;
+    if(nIntervals > 0) PView::list[pos]->getOptions()->nbIso = nIntervals;
+    if(raisez>=0) PView::list[pos]->getOptions()->raise[2] = raisez;
+    PView::list[pos]->setChanged(true);
+  }
 
-JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_onelabCB
+  JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_onelabCB
   (JNIEnv *env, jobject obj, jstring jaction)
-{
-	const char*  action = env->GetStringUTFChars(jaction, NULL);
-	return onelab_cb(action);
-}
+  {
+    const char*  action = env->GetStringUTFChars(jaction, NULL);
+    return onelab_cb(action);
+  }
 
-JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_numberOfAnimation
+  JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_numberOfAnimation
   (JNIEnv *, jobject)
-{
-	return number_of_animation();
-}
-JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_animationNext
+  {
+    return number_of_animation();
+  }
+  JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_animationNext
   (JNIEnv *, jobject)
-{
-	return animation_next();
-}
-JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_animationPrev
+  {
+    return animation_next();
+  }
+  JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_animationPrev
   (JNIEnv *, jobject)
-{
-	return animation_prev();
-}
-JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setAnimation
+  {
+    return animation_prev();
+  }
+  JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setAnimation
   (JNIEnv *, jobject, jint animation)
-{
-	set_animation(animation);
-}
+  {
+    set_animation(animation);
+  }
+  JNIEXPORT jstring JNICALL Java_org_geuz_onelab_Gmsh_getAboutGmsh
+  (JNIEnv *env, jclass c)
+  {
+    std::ostringstream sstream;
+    sstream << "<center><h3>Gmsh</h3>"
+            << "Version " << GMSH_VERSION << " "
+            << "(<i>Build date:</i> " << GMSH_DATE << ")"
+            << "<p>Copyright (C) 1997-2014 Christophe Geuzaine and Jean-François Remacle</p>"
+            << "<p><a href=\"http://geuz.org/gmsh/doc/CREDITS.txt\">Credits</a> "
+            << "and <a href=\"http://geuz.org/gmsh/doc/LICENSE.txt\">licensing information</a></p>"
+            << "<p><i>Build options:</i> " << GMSH_CONFIG_OPTIONS << "</p>"
+            << "<p>Visit <a href=\"http://gmsh.info\">http://gmsh.info</a> for more information</p></center>";
+    return env->NewStringUTF(sstream.str().c_str());
+  }
+  JNIEXPORT jstring JNICALL Java_org_geuz_onelab_Gmsh_getAboutGetDP
+  (JNIEnv *env, jclass c)
+  {
+    std::ostringstream sstream;
+    sstream << "<center><h3>GetDP</h3>"
+            << "Version " << GETDP_VERSION << " "
+            << "(<i>Build date:</i> " << GETDP_DATE << ")"
+            << "<p>Copyright (C) 1997-2014 Patrick Dular and Christophe Geuzaine, University of Liège</p>"
+            << "<p><a href=\"http://geuz.org/getdp/doc/CREDITS.txt\">Credits</a> "
+            << "and <a href=\"http://geuz.org/getdp/doc/LICENSE.txt\">licensing information</a></p>"
+            << "<p><i>Build options:</i> " << GETDP_CONFIG_OPTIONS << "</p>"
+            << "<p>Visit <a href=\"http://getdp.info\">http://getdp.info</a> for more information</p></center>";
+    return env->NewStringUTF(sstream.str().c_str());
+  }
 }
diff --git a/contrib/mobile/androidGModel.h b/contrib/mobile/androidGModel.h
index 013cd64..fca4dfd 100644
--- a/contrib/mobile/androidGModel.h
+++ b/contrib/mobile/androidGModel.h
@@ -12,10 +12,10 @@ extern "C" {
 /*
  * Class:     org_geuz_onelab_Gmsh
  * Method:    init
- * Signature: (Ljava/lang/String;)J
+ * Signature: (F)J
  */
 JNIEXPORT jlong JNICALL Java_org_geuz_onelab_Gmsh_init
-  (JNIEnv *, jobject);
+  (JNIEnv *, jobject, jfloat);
 
 /*
  * Class:     org_geuz_onelab_Gmsh
@@ -169,6 +169,22 @@ JNIEXPORT jint JNICALL Java_org_geuz_onelab_Gmsh_animationPrev
 JNIEXPORT void JNICALL Java_org_geuz_onelab_Gmsh_setAnimation
   (JNIEnv *, jobject, jint);
 
+/*
+ * Class:     org_geuz_onelab_Gmsh
+ * Method:    getAboutGmsh
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jstring JNICALL Java_org_geuz_onelab_Gmsh_getAboutGmsh
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     org_geuz_onelab_Gmsh
+ * Method:    getAboutGetDP
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jstring JNICALL Java_org_geuz_onelab_Gmsh_getAboutGetDP
+  (JNIEnv *, jclass);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/contrib/mobile/drawContext.cpp b/contrib/mobile/drawContext.cpp
index 1432160..f8c45f6 100644
--- a/contrib/mobile/drawContext.cpp
+++ b/contrib/mobile/drawContext.cpp
@@ -1,33 +1,7 @@
-#if !defined(BUILD_ANDROID)
-#define BUILD_IOS 1
-#endif
-
 #include <map>
 
-#if defined(BUILD_IOS)
-#include <OpenGLES/ES1/gl.h>
-#include <OpenGLES/ES1/glext.h>
-
-#include <Gmsh/Gmsh.h>
-#include <Gmsh/GModel.h>
-#include <Gmsh/MElement.h>
-#include <Gmsh/VertexArray.h>
-#include <Gmsh/onelab.h>
-#include <Gmsh/onelabUtils.h>
-#include <Gmsh/PView.h>
-#include <Gmsh/PViewOptions.h>
-#include <Gmsh/PViewData.h>
-#include <Gmsh/Context.h>
-#include <Gmsh/StringUtils.h>
-
-#include <GetDP/GetDP.h>
-#endif
-
-#if defined(BUILD_ANDROID)
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
 #include <gmsh/Gmsh.h>
+#include <gmsh/OpenFile.h>
 #include <gmsh/GModel.h>
 #include <gmsh/MElement.h>
 #include <gmsh/VertexArray.h>
@@ -38,10 +12,15 @@
 #include <gmsh/PViewData.h>
 #include <gmsh/Context.h>
 #include <gmsh/StringUtils.h>
-
 #include <getdp/GetDP.h>
 
+#if defined(BUILD_ANDROID)
+#include <GLES/gl.h>
+#include <GLES/glext.h>
 #include "androidGModel.h"
+#else // iOS
+#include <OpenGLES/ES1/gl.h>
+#include <OpenGLES/ES1/glext.h>
 #endif
 
 #include "drawContext.h"
@@ -51,690 +30,767 @@
 static bool locked = false;
 static bool onelabStop = false;
 
-drawContext::drawContext()
+drawContext::drawContext(float fontFactor, bool retina)
 {
-	GmshInitialize();
-	GmshSetOption("General", "Terminal", 1.0);
-	onelabUtils::setFirstComputationFlag(false);
-	for(int i = 0; i < 3; i++){
-		_translate[i] = 0.;
-		_scale[i] = 1.;
-	}
-	setQuaternion(0., 0., 0., 1.);
-    
-	_fillMesh = false;
-	_gradiant = true;
+  GmshInitialize();
+  GmshSetOption("General", "Terminal", 1.0);
+  onelabUtils::setFirstComputationFlag(false);
+  for(int i = 0; i < 3; i++){
+    _translate[i] = 0.;
+    _scale[i] = 1.;
+  }
+  setQuaternion(0., 0., 0., 1.);
+  _fontFactor = fontFactor;
+  _retina = retina;
 }
 
-static void checkGlError(const char* op) {
-	for (GLint error = glGetError(); error; error = glGetError())
-		Msg::Error("%s: glError (0x%x)",op,error);
+static void checkGlError(const char* op)
+{
+  for (GLint error = glGetError(); error; error = glGetError())
+    Msg::Error("%s: glError (0x%x)",op,error);
 }
 
 void drawContext::load(std::string filename)
 {
-	if(locked) return;
-	// clear previous GModel, onelab datas and PView
-	GModel::list.clear();
-	PView::list.clear();
-	onelab::server::instance()->clear();
-	
-	// open the file with Gmsh
-	GmshOpenProject(filename);
-    
-	// run getdp witout parameter
-	onelab_cb("check");
-    
-	// to allow the first run
-	onelab::server::instance()->setChanged(true, "Gmsh");
-	onelab::server::instance()->setChanged(true, "GetDP");
+  if(locked) return;
+
+  // delete all models and post-processing views
+  GmshClearProject();
+
+  // reset onelab database
+  onelab::server::instance()->clear();
+
+  // restore default options
+  GmshRestoreDefaultOptions();
+
+  // output messages on console
+  GmshSetOption("General", "Terminal", 1.0);
+
+  // open the file with Gmsh
+  GmshOpenProject(filename);
+
+  // reset openGL view
+  eventHandler(10);
+
+  // run onelab clients to populate the database
+  onelab_cb("check");
+
+  // mark all parameters as changed to force complete first run
+  onelab::server::instance()->setChanged(true);
 }
 
 void drawContext::eventHandler(int event, float x, float y)
 {
-	this->_current.set(this->_scale, this->_translate, this->_right, this->_left, this->_bottom, this->_top, this->_width, this->_height, x, y);
-    double xx[3] = {1.,0.,0.};
-    double yy[3] = {0.,1.,0.};
-    double q[4];
-	switch(event)
-	{
-		case 0: // finger(s) press the screen
-			// in this case x and y represent the start point
-			this->_start.set(this->_scale, this->_translate, this->_right, this->_left, this->_bottom, this->_top, this->_width, this->_height, x, y);
-			this->_previous.set(this->_scale, this->_translate, this->_right, this->_left, this->_bottom, this->_top, this->_width, this->_height, x, y);
-			break;
-		case 1: // finger move (translate)
-			// in this case x and y represent the current point
-			_translate[0] += (this->_current.wnr[0] - this->_previous.wnr[0]);
-			_translate[1] += (this->_current.wnr[1] - this->_previous.wnr[1]);
-			_translate[2] = 0.;
-			break;
-		case 2: // fingers move (scale)
-			// in this case we don't care about previous and current position, x represent the scale
-			this->_scale[0] = this->_scale[1] = this->_scale[2] = x;
-			this->_start.recenter(this->_scale, this->_translate);
-			break;
-		case 3: // fingers move (rotate)
-			this->addQuaternion((2. * this->_previous.win[0] - this->_width) / this->_width,
-                                (this->_height - 2. * this->_previous.win[1]) / this->_height,
-                                (2. * this->_current.win[0] - this->_width) / this->_width,
-                                (this->_height - 2. * this->_current.win[1]) / this->_height);
-			break;
-		case 4: // release the finger(s)
-			// Do nothink ?
-			break;
-		case 5: // X view
-			axis_to_quat(xx, M_PI/2, q);
-			setQuaternion(q[0], q[1], q[2], q[3]);
-			break;
-		case 6: // Y view
-			axis_to_quat(yy, M_PI/2, q);
-			setQuaternion(q[0], q[1], q[2], q[3]);
-			break;
-		case 7: // Z view
-			setQuaternion(0., 0., 0., 1.);
-			break;
-		default: // all other reset the position
-			setQuaternion(0., 0., 0., 1.);
-			for(int i = 0; i < 3; i++){
-				_translate[i] = 0.;
-				_scale[i] = 1.;
-			}
-			break;
-	}
-	this->_previous.set(this->_scale, this->_translate, this->_right, this->_left, this->_bottom, this->_top, this->_width, this->_height, x, y);
+  int width = _width, height = _height;
+  if(_retina){ // x,y for retina are still the same as for non-retina
+    width /= 2;
+    height /= 2;
+  }
+
+  _current.set(_scale, _translate, _right, _left,
+               _bottom, _top, width, height, x, y);
+  double xx[3] = {1.,0.,0.};
+  double yy[3] = {0.,1.,0.};
+  double q[4];
+  switch(event){
+  case 0: // finger(s) press the screen
+    // in this case x and y represent the start point
+    _start.set(_scale, _translate, _right, _left,
+               _bottom, _top, width, height, x, y);
+    _previous.set(_scale, _translate, _right, _left,
+                  _bottom, _top, width, height, x, y);
+    break;
+  case 1: // finger move (translate)
+    // in this case x and y represent the current point
+    _translate[0] += (_current.wnr[0] - _previous.wnr[0]);
+    _translate[1] += (_current.wnr[1] - _previous.wnr[1]);
+    _translate[2] = 0.;
+    break;
+  case 2: // fingers move (scale)
+    // in this case we don't care about previous and current position, x
+    // represent the scale
+    _scale[0] = _scale[1] = _scale[2] = x;
+    _start.recenter(_scale, _translate);
+    break;
+  case 3: // fingers move (rotate)
+    addQuaternion((2. * _previous.win[0] - width) / width,
+                  (height - 2. * _previous.win[1]) / height,
+                  (2. * _current.win[0] - width) / width,
+                  (height - 2. * _current.win[1]) / height);
+    break;
+  case 4: // release the finger(s)
+    // Do nothing ?
+    break;
+  case 5: // X view
+    axis_to_quat(xx, M_PI/2, q);
+    setQuaternion(q[0], q[1], q[2], q[3]);
+    break;
+  case 6: // Y view
+    axis_to_quat(yy, M_PI/2, q);
+    setQuaternion(q[0], q[1], q[2], q[3]);
+    break;
+  case 7: // Z view
+    setQuaternion(0., 0., 0., 1.);
+    break;
+  default: // all other reset the position
+    setQuaternion(0., 0., 0., 1.);
+    for(int i = 0; i < 3; i++){
+      _translate[i] = 0.;
+      _scale[i] = 1.;
+    }
+    break;
+  }
+  _previous.set(_scale, _translate, _right, _left,
+                _bottom, _top, width, height, x, y);
 }
 
 void drawContext::setQuaternion(double q0, double q1, double q2, double q3)
 {
-	this->_quaternion[0] = q0;
-	this->_quaternion[1] = q1;
-	this->_quaternion[2] = q2;
-	this->_quaternion[3] = q3;
+  _quaternion[0] = q0;
+  _quaternion[1] = q1;
+  _quaternion[2] = q2;
+  _quaternion[3] = q3;
 }
 
 void drawContext::addQuaternion(double p1x, double p1y, double p2x, double p2y)
 {
   double quat[4];
   trackball(quat, p1x, p1y, p2x, p2y);
-  add_quats(quat, this->_quaternion, this->_quaternion);
+  add_quats(quat, _quaternion, _quaternion);
 }
 
 void drawContext::buildRotationMatrix()
 {
-	build_rotmatrix(_rotate, _quaternion);
-	for(int i=0; i<16;i++)
-		_rotatef[i] = (float)_rotate[i];
+  build_rotmatrix(_rotate, _quaternion);
+  for(int i = 0; i < 16; i++)
+    _rotatef[i] = (float)_rotate[i];
 }
 
 void drawContext::OrthofFromGModel()
 {
-	SBoundingBox3d bb = GModel::current()->bounds();
-	double ratio = (double)(this->_width ? this->_width : 1.) / (double)(this->_height ? this->_height : 1.);
-	double bbRation = (bb.max().x() - bb.min().x()) / (bb.max().y() - bb.min().y());
-	double xmin = -ratio, xmax = ratio, ymin = -1., ymax = 1.;
-	if(bbRation < 1) {
-		xmin = bb.min().y() * ratio + bb.max().x() + bb.min().x();
-		xmax = bb.max().y() * ratio + bb.max().x() + bb.min().x();
-		ymin = bb.min().y() + bb.max().y() + bb.min().y();
-		ymax = bb.max().y() + bb.max().y() + bb.min().y();
-	}
-	else {
-		xmin = bb.min().x() + bb.max().x() + bb.min().x();
-		xmax = bb.max().x() + bb.max().x() + bb.min().x();
-		ymin = bb.min().x() / ratio + bb.max().y() + bb.min().y();
-		ymax = bb.max().x() / ratio + bb.max().y() + bb.min().y();
-	}
-	xmax += (xmax - xmin) / 5.;
-	xmin -= (xmax - xmin) / 5.;
-	ymax += (ymax - ymin) / 5.;
-	ymin -= (ymax - ymin) / 5.;
-	
-	// clipping
-	double zmax = std::max(fabs(bb.min().z()), fabs(bb.max().z()));
-	double clip = zmax  * 5.;
-	clip = 1.;
-
-	GLint matrixMode;
-	glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
-	glMatrixMode(GL_PROJECTION);
-	glLoadIdentity();
-	this->_left = (xmin != 0 || xmax != 0)? xmin : -ratio;
-	this->_right = (xmin != 0 || xmax != 0)? xmax : ratio;
-	this->_top = (xmin != 0 || xmax != 0)? ymax : 1.0;
-	this->_bottom = (xmin != 0 || xmax != 0)? ymin : -1.0;
-	glOrthof(this->_left, this->_right, this->_bottom, this->_top, -clip, clip);
-    
-	glMatrixMode(matrixMode);
+  double Va = (double)_height / (double)_width;
+  double Wa = (CTX::instance()->max[1] - CTX::instance()->min[1]) /
+    (CTX::instance()->max[0] - CTX::instance()->min[0]);
+  double vxmin, vxmax, vymin, vymax;
+  if(Va > Wa) {
+    vxmin = CTX::instance()->min[0];
+    vxmax = CTX::instance()->max[0];
+    vymin = 0.5 * (CTX::instance()->min[1] + CTX::instance()->max[1] -
+                   Va * (CTX::instance()->max[0] - CTX::instance()->min[0]));
+    vymax = 0.5 * (CTX::instance()->min[1] + CTX::instance()->max[1] +
+                   Va * (CTX::instance()->max[0] - CTX::instance()->min[0]));
+  }
+  else {
+    vxmin = 0.5 * (CTX::instance()->min[0] + CTX::instance()->max[0] -
+                   (CTX::instance()->max[1] - CTX::instance()->min[1]) / Va);
+    vxmax = 0.5 * (CTX::instance()->min[0] + CTX::instance()->max[0] +
+                   (CTX::instance()->max[1] - CTX::instance()->min[1]) / Va);
+    vymin = CTX::instance()->min[1];
+    vymax = CTX::instance()->max[1];
+  }
+  double fact = CTX::instance()->displayBorderFactor;
+  double xborder = fact * (vxmax - vxmin), yborder = fact * (vymax - vymin);
+  vxmin -= xborder;
+  vxmax += xborder;
+  vymin -= yborder;
+  vymax += yborder;
+
+  // set up the near and far clipping planes so that the box is large enough to
+  // manipulate the model and zoom, but not too big (otherwise the z-buffer
+  // resolution e.g. with Mesa can become insufficient)
+  double zmax = std::max(fabs(CTX::instance()->min[2]),
+                         fabs(CTX::instance()->max[2]));
+  if(zmax < CTX::instance()->lc) zmax = CTX::instance()->lc;
+  double clip_near = -zmax * _scale[2] * CTX::instance()->clipFactor;
+  double clip_far = -clip_near;
+
+  GLint matrixMode;
+  glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  glOrthof(vxmin, vxmax, vymin, vymax, clip_near, clip_far);
+  glMatrixMode(matrixMode);
+
+  _left = vxmin;
+  _right = vxmax;
+  _top = vymax;
+  _bottom = vymin;
+  _far = clip_far;
 }
 
 void drawContext::initView(int w, int h)
 {
-	this->_height = h;
-	this->_width = w;
-	glViewport(0, 0, w, h);
+  _height = h;
+  _width = w;
+  glViewport(0, 0, w, h);
+
+  OrthofFromGModel();
 
-	this->OrthofFromGModel();
-    
-	glClearColor(.83,.85,.98,1.);
-	glDepthMask(GL_TRUE);
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  glClearColor(.83, .85, .98, 1.);
+  glDepthMask(GL_TRUE);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-	glDepthFunc(GL_LESS);
+  glDepthFunc(GL_LESS);
 }
 
 void drawArray(VertexArray *va, GLint type, bool useColorArray, bool useNormalArray)
 {
-	if(!va) return;
-	glEnable(GL_BLEND);
-	glEnable(GL_RESCALE_NORMAL);
-	glShadeModel(GL_SMOOTH);
-	glVertexPointer(3, GL_FLOAT, 0, va->getVertexArray());
-	glEnableClientState(GL_VERTEX_ARRAY);
-	if(useNormalArray){
-		glNormalPointer(GL_BYTE, 0, va->getNormalArray());
-		glEnableClientState(GL_NORMAL_ARRAY);
-	}
-	if(useColorArray){
-		glColorPointer(4, GL_UNSIGNED_BYTE, 0, va->getColorArray());
-		glEnableClientState(GL_COLOR_ARRAY);
-	}
-	glDrawArrays(type, 0, va->getNumVertices());
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_NORMAL_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-	glDisable(GL_RESCALE_NORMAL);
-	glDisable(GL_BLEND);
+  if(!va) return;
+  glEnable(GL_BLEND);
+  glEnable(GL_RESCALE_NORMAL);
+  glShadeModel(GL_SMOOTH);
+  glVertexPointer(3, GL_FLOAT, 0, va->getVertexArray());
+  glEnableClientState(GL_VERTEX_ARRAY);
+  if(useNormalArray){
+    glNormalPointer(GL_BYTE, 0, va->getNormalArray());
+    glEnableClientState(GL_NORMAL_ARRAY);
+  }
+  if(useColorArray){
+    glColorPointer(4, GL_UNSIGNED_BYTE, 0, va->getColorArray());
+    glEnableClientState(GL_COLOR_ARRAY);
+  }
+  glDrawArrays(type, 0, va->getNumVertices());
+  glDisableClientState(GL_VERTEX_ARRAY);
+  glDisableClientState(GL_NORMAL_ARRAY);
+  glDisableClientState(GL_COLOR_ARRAY);
+  glDisable(GL_RESCALE_NORMAL);
+  glDisable(GL_BLEND);
 }
 
 void drawVector(double x, double y, double z, double dx, double dy, double dz)
 {
-	double l = sqrt(dx * dx + dy * dy + dz * dz), lt;
-	double n[3], t[3], u[3];
-    
-	if(l == 0.0) return;
-    
-	GLfloat line[] = {
-		(GLfloat)x, (GLfloat)y, (GLfloat)z,
-		(GLfloat)(x+dx), (GLfloat)(y+dy), (GLfloat)(z+dz),
-	};
-	glVertexPointer(3, GL_FLOAT, 0, line);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glDrawArrays(GL_LINES, 0, 2);
-	glDisableClientState(GL_VERTEX_ARRAY);
-    
-	n[0] = dx / l;
-	n[1] = dy / l;
-	n[2] = dz / l;
-    
-	if((fabs(n[0]) >= fabs(n[1]) && fabs(n[0]) >= fabs(n[2])) ||
-       (fabs(n[1]) >= fabs(n[0]) && fabs(n[1]) >= fabs(n[2]))) {
-		t[0] = n[1];
-		t[1] = -n[0];
-		t[2] = 0.;
-	}
-	else {
-		t[0] = 0.;
-		t[1] = n[2];
-		t[2] = -n[1];
-	}
-    
-	lt = sqrt(t[0] * t[0] + t[1] * t[1] + t[2] * t[2]);
-	t[0] /= lt;
-	t[1] /= lt;
-	t[2] /= lt;
-    
-	u[0] = n[1] * t[2] - n[2] * t[1];
-	u[1] = n[2] * t[0] - n[0] * t[2];
-	u[2] = n[0] * t[1] - n[1] * t[0];
-    
-	lt = sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
-	u[0] /= lt;
-	u[1] /= lt;
-	u[2] /= lt;
-    
-	double f1 = 0.75; // Stem lenght
-	double b = 0.1 * l;
-	
-	GLfloat arrow[] = {
-		(GLfloat)(x + dx), (GLfloat)(y + dy), (GLfloat)(z + dz),
-		(GLfloat)(x + f1 * dx + b * (t[0])), (GLfloat)(y + f1 * dy + b * (t[1])), (GLfloat)(z + f1 * dz + b * (t[2])),
-		(GLfloat)(x + f1 * dx + b * (-t[0])), (GLfloat)(y + f1 * dy + b * (-t[1])), (GLfloat)(z + f1 * dz + b * (-t[2])),
-        
-		(GLfloat)(x + dx), (GLfloat)(y + dy), (GLfloat)(z + dz),
-		(GLfloat)(x + f1 * dx + b * (-u[0])), (GLfloat)(y + f1 * dy + b * (-u[1])), (GLfloat)(z + f1 * dz + b * (-u[2])),
-		(GLfloat)(x + f1 * dx + b * (u[0])), (GLfloat)(y + f1 * dy + b * (u[1])), (GLfloat)(z + f1 * dz + b * (u[2])),
-	};
-	glVertexPointer(3, GL_FLOAT, 0, arrow);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnable(GL_LINE_SMOOTH);
-	glDrawArrays(GL_TRIANGLES, 0, 6);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisable(GL_LINE_SMOOTH);
-    
+  double l = sqrt(dx * dx + dy * dy + dz * dz), lt;
+  double n[3], t[3], u[3];
+
+  if(l == 0.0) return;
+
+  GLfloat line[] = {
+    (GLfloat)x, (GLfloat)y, (GLfloat)z,
+    (GLfloat)(x+dx), (GLfloat)(y+dy), (GLfloat)(z+dz),
+  };
+  glVertexPointer(3, GL_FLOAT, 0, line);
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glDrawArrays(GL_LINES, 0, 2);
+  glDisableClientState(GL_VERTEX_ARRAY);
+
+  n[0] = dx / l;
+  n[1] = dy / l;
+  n[2] = dz / l;
+
+  if((fabs(n[0]) >= fabs(n[1]) && fabs(n[0]) >= fabs(n[2])) ||
+     (fabs(n[1]) >= fabs(n[0]) && fabs(n[1]) >= fabs(n[2]))) {
+    t[0] = n[1];
+    t[1] = -n[0];
+    t[2] = 0.;
+  }
+  else {
+    t[0] = 0.;
+    t[1] = n[2];
+    t[2] = -n[1];
+  }
+
+  lt = sqrt(t[0] * t[0] + t[1] * t[1] + t[2] * t[2]);
+  t[0] /= lt;
+  t[1] /= lt;
+  t[2] /= lt;
+
+  u[0] = n[1] * t[2] - n[2] * t[1];
+  u[1] = n[2] * t[0] - n[0] * t[2];
+  u[2] = n[0] * t[1] - n[1] * t[0];
+
+  lt = sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
+  u[0] /= lt;
+  u[1] /= lt;
+  u[2] /= lt;
+
+  double f1 = 0.75; // Stem lenght
+  double b = 0.1 * l;
+
+  GLfloat arrow[] = {
+    (GLfloat)(x + dx), (GLfloat)(y + dy), (GLfloat)(z + dz),
+    (GLfloat)(x + f1 * dx + b * (t[0])), (GLfloat)(y + f1 * dy + b * (t[1])),
+    (GLfloat)(z + f1 * dz + b * (t[2])),
+    (GLfloat)(x + f1 * dx + b * (-t[0])), (GLfloat)(y + f1 * dy + b * (-t[1])),
+    (GLfloat)(z + f1 * dz + b * (-t[2])),
+
+    (GLfloat)(x + dx), (GLfloat)(y + dy), (GLfloat)(z + dz),
+    (GLfloat)(x + f1 * dx + b * (-u[0])), (GLfloat)(y + f1 * dy + b * (-u[1])),
+    (GLfloat)(z + f1 * dz + b * (-u[2])),
+    (GLfloat)(x + f1 * dx + b * (u[0])), (GLfloat)(y + f1 * dy + b * (u[1])),
+    (GLfloat)(z + f1 * dz + b * (u[2])),
+  };
+  glVertexPointer(3, GL_FLOAT, 0, arrow);
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glEnable(GL_LINE_SMOOTH);
+  glDrawArrays(GL_TRIANGLES, 0, 6);
+  glDisableClientState(GL_VERTEX_ARRAY);
+  glDisable(GL_LINE_SMOOTH);
 }
 
 void drawContext::drawVectorArray(PViewOptions *opt, VertexArray *va)
 {
-	if(!va || va->getNumVerticesPerElement() != 2) return;
-    
-	for(int i = 0; i < va->getNumVertices(); i += 2){
-		float *s = va->getVertexArray(3 * i);
-		float *v = va->getVertexArray(3 * (i + 1));
-		double l = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
-		double lmax = opt->tmpMax;
-		if((l && opt->vectorType) && lmax)
-		{
-			double scale = (opt->arrowSizeMax - opt->arrowSizeMin) / lmax;
-			if(opt->arrowSizeMin && l) scale += opt->arrowSizeMin / l;
-			double dx = scale * v[0];
-			double dy = scale * v[1];
-			double dz = scale * v[2];
-			GLubyte *color = (GLubyte *)va->getColorArray(4 * i);
-			glColor4ub(*(color), *(color+1), *(color+2), *(color+3));
-			if(fabs(dx) > 1. || fabs(dy) > 1. || fabs(dz) > 1.)
-			{
-				double d = (this->_right - this->_left) / this->_width / _scale[0];
-				dx *= d; dy *= d; dz *= d;
-				double x = s[0], y = s[1], z = s[2];
-				drawVector(x,y,z,dx,dy,dz);
-			}
-		}
-	}
+  if(!va || va->getNumVerticesPerElement() != 2) return;
+
+  for(int i = 0; i < va->getNumVertices(); i += 2){
+    float *s = va->getVertexArray(3 * i);
+    float *v = va->getVertexArray(3 * (i + 1));
+    double l = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+    double lmax = opt->tmpMax;
+    if((l && opt->vectorType) && lmax){
+      double scale = (opt->arrowSizeMax - opt->arrowSizeMin) / lmax;
+      if(opt->arrowSizeMin && l) scale += opt->arrowSizeMin / l;
+      double dx = scale * v[0];
+      double dy = scale * v[1];
+      double dz = scale * v[2];
+      GLubyte *color = (GLubyte *)va->getColorArray(4 * i);
+      glColor4ub(*(color), *(color+1), *(color+2), *(color+3));
+      if(fabs(dx) > 1. || fabs(dy) > 1. || fabs(dz) > 1.){
+        double d = (_right - _left) / _width / _scale[0];
+        dx *= d; dy *= d; dz *= d;
+        double x = s[0], y = s[1], z = s[2];
+        drawVector(x,y,z,dx,dy,dz);
+      }
+    }
+  }
 }
 
 void drawContext::drawPView(PView *p)
 {
-	PViewOptions *opt = p->getOptions();
-	if(!opt->visible) return;
-    
-	glPointSize((GLfloat)opt->pointSize);
-	glLineWidth((GLfloat)opt->lineWidth);
-    
-	drawArray(p->va_points, GL_POINTS, true);
-	drawArray(p->va_lines, GL_LINES, true);
-	drawArray(p->va_triangles, GL_TRIANGLES, true, true);
-
-	glLineWidth(1);
-	glPointSize(1);
-    
-	drawVectorArray(p->getOptions(), p->va_vectors);
+  PViewOptions *opt = p->getOptions();
+  if(!opt->visible) return;
+
+  glPointSize((GLfloat)opt->pointSize);
+  glLineWidth((GLfloat)opt->lineWidth);
+
+  drawArray(p->va_points, GL_POINTS, true);
+  drawArray(p->va_lines, GL_LINES, true);
+  drawArray(p->va_triangles, GL_TRIANGLES, true, true);
+
+  glLineWidth(1);
+  glPointSize(1);
+
+  drawVectorArray(p->getOptions(), p->va_vectors);
 }
 
 void drawContext::drawScale()
 {
-	glPushMatrix();
-	glLoadIdentity();
+  glPushMatrix();
+  glLoadIdentity();
+
+  double size = std::max(_right -_left, _top - _bottom);
+  double width = size / 3.5;
+  double height = size / 10.;
+  double dh = height / 5;
+
 	// Draw the scale bar
-	int nPview = 0;
-	for(int i=0; i<PView::list.size();i++){
-		PView *p = PView::list[i];
-		PViewOptions *opt = p->getOptions();
-		if(!opt->visible) continue;
-
-		double width = 6*(this->_right -this->_left) / 10.;
-		double height = (this->_top - this->_bottom) / 20.;
-		double box = width / (opt->nbIso ? opt->nbIso : 1);
-		double xmin = this->_left + (this->_right - this->_left -width)/2.;
-		double ymin = this->_bottom + height + 2*height*nPview;
-    
-		std::vector<GLfloat> vertex(opt->nbIso*3*4);
-		std::vector<GLubyte> color(opt->nbIso*4*4);
-		for(int i = 0; i < opt->nbIso; i++){
-			if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric)
-			{
-				unsigned int col = opt->getColor(i, opt->nbIso);
-				color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
-				color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
-				color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
-				color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
-				vertex[i*3*4+0] = xmin + i * box;
-				vertex[i*3*4+1] = ymin;
-				vertex[i*3*4+2] = 0.;
-				vertex[i*3*4+3] = xmin + i * box;
-				vertex[i*3*4+4] = ymin + height;
-				vertex[i*3*4+5] = 0.;
-				vertex[i*3*4+6] = xmin + (i + 1) * box;
-				vertex[i*3*4+7] = ymin;
-				vertex[i*3*4+8] = 0.;
-				vertex[i*3*4+9] = xmin + (i + 1) * box;
-				vertex[i*3*4+10] = ymin + height;
-				vertex[i*3*4+11] = 0.;
-			}
-			else if(opt->intervalsType == PViewOptions::Continuous)
-			{
-				double dv = (opt->tmpMax - opt->tmpMin) / (opt->nbIso ? opt->nbIso : 1);
-				double v1 = opt->tmpMin + i * dv;
-				unsigned int col1 = opt->getColor(v1, opt->tmpMin, opt->tmpMax, true);
-				color[i*4*4+0] = color[i*4*4+4] = (GLubyte)CTX::instance()->unpackRed(col1);
-				color[i*4*4+1] = color[i*4*4+5] = (GLubyte)CTX::instance()->unpackGreen(col1);
-				color[i*4*4+2] = color[i*4*4+6] = (GLubyte)CTX::instance()->unpackBlue(col1);
-				color[i*4*4+3] = color[i*4*4+7] = (GLubyte)CTX::instance()->unpackAlpha(col1);
-				vertex[i*3*4+0] = xmin + i * box;
-				vertex[i*3*4+1] = ymin;
-				vertex[i*3*4+2] = 0.;
-				vertex[i*3*4+3] = xmin + i * box;
-				vertex[i*3*4+4] = ymin + height;
-				vertex[i*3*4+5] = 0.;
-				double v2 = opt->tmpMin + (i + 1) * dv;
-				unsigned int col2 = opt->getColor(v2, opt->tmpMin, opt->tmpMax, true);
-				color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col2);
-				color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col2);
-				color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col2);
-				color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col2);
-				vertex[i*3*4+6] = xmin + (i + 1) * box;
-				vertex[i*3*4+7] = ymin;
-				vertex[i*3*4+8] = 0.;
-				vertex[i*3*4+9] = xmin + (i + 1) * box;
-				vertex[i*3*4+10] = ymin + height;
-				vertex[i*3*4+11] = 0.;
-			}
-			else
-			{
-				unsigned int col = opt->getColor(i, opt->nbIso);
-				color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col);
-				color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col);
-				color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col);
-				color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col);
-				vertex[i*3*4+0] = xmin + i * box;
-				vertex[i*3*4+1] = ymin;
-				vertex[i*3*4+2] = 0.;
-				vertex[i*3*4+3] = xmin + i * box;
-				vertex[i*3*4+4] = ymin + height;
-				vertex[i*3*4+5] = 0.;
-				vertex[i*3*4+6] = xmin + (i + 1) * box;
-				vertex[i*3*4+7] = ymin;
-				vertex[i*3*4+8] = 0.;
-				vertex[i*3*4+9] = xmin + (i + 1) * box;
-				vertex[i*3*4+10] = ymin + height;
-				vertex[i*3*4+11] = 0.;
-			}
-		}
-	
-		glVertexPointer(3, GL_FLOAT, 0, &vertex[0]);
-		glEnableClientState(GL_VERTEX_ARRAY);
-		glColorPointer(4, GL_UNSIGNED_BYTE, 0, &color[0]);
-		glEnableClientState(GL_COLOR_ARRAY);
-		if(opt->intervalsType == PViewOptions::Discrete || opt->intervalsType == PViewOptions::Numeric || opt->intervalsType == PViewOptions::Continuous)
-			glDrawArrays(GL_TRIANGLE_STRIP, 0, opt->nbIso*4);
-		else
-			glDrawArrays(GL_LINES, 0, opt->nbIso*4);
-		glDisableClientState(GL_COLOR_ARRAY);
-		glDisableClientState(GL_VERTEX_ARRAY);
-
-		char label[1024];
-		drawString lbl(p->getData()->getName().c_str(), 20);
-		lbl.draw(xmin+width/2, ymin-height/2, 0., _width/(_right-_left), _height/(_top-_bottom));
-		drawString val(p->getData()->getName().c_str(), 14);
-		for(int i = 0; i < 3; i++) {
-			double v = opt->getScaleValue(i, 3, opt->tmpMin, opt->tmpMax);
-			sprintf(label, opt->format.c_str(), v);
-			val.setText(label);
-			val.draw(xmin+i*width/2, ymin+height/2, 0., _width/(_right-_left), _height/(_top-_bottom));
-		}
-		nPview++;
-	}
-	glPopMatrix();
+  int nPview = 0;
+  for(int i=0; i<PView::list.size();i++){
+    PView *p = PView::list[i];
+    PViewOptions *opt = p->getOptions();
+    if(!opt->visible) continue;
+    PViewData *data = p->getData();
+
+    double box = width / (opt->nbIso ? opt->nbIso : 1);
+    double xmin = _left + (_right - _left - width)/2.;
+    double ymin = _bottom + 0.7 * height + height * nPview;
+
+    std::vector<GLfloat> vertex(opt->nbIso*3*4);
+    std::vector<GLubyte> color(opt->nbIso*4*4);
+    for(int i = 0; i < opt->nbIso; i++){
+      if(opt->intervalsType == PViewOptions::Discrete ||
+         opt->intervalsType == PViewOptions::Numeric){
+        unsigned int col = opt->getColor(i, opt->nbIso);
+        color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] =
+          (GLubyte)CTX::instance()->unpackRed(col);
+        color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] =
+          (GLubyte)CTX::instance()->unpackGreen(col);
+        color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] =
+          (GLubyte)CTX::instance()->unpackBlue(col);
+        color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] =
+          (GLubyte)CTX::instance()->unpackAlpha(col);
+        vertex[i*3*4+0] = xmin + i * box;
+        vertex[i*3*4+1] = ymin;
+        vertex[i*3*4+2] = 0.;
+        vertex[i*3*4+3] = xmin + i * box;
+        vertex[i*3*4+4] = ymin + dh;
+        vertex[i*3*4+5] = 0.;
+        vertex[i*3*4+6] = xmin + (i + 1) * box;
+        vertex[i*3*4+7] = ymin;
+        vertex[i*3*4+8] = 0.;
+        vertex[i*3*4+9] = xmin + (i + 1) * box;
+        vertex[i*3*4+10] = ymin + dh;
+        vertex[i*3*4+11] = 0.;
+      }
+      else if(opt->intervalsType == PViewOptions::Continuous){
+        double dv = (opt->tmpMax - opt->tmpMin) / (opt->nbIso ? opt->nbIso : 1);
+        double v1 = opt->tmpMin + i * dv;
+        unsigned int col1 = opt->getColor(v1, opt->tmpMin, opt->tmpMax, true);
+        color[i*4*4+0] = color[i*4*4+4] = (GLubyte)CTX::instance()->unpackRed(col1);
+        color[i*4*4+1] = color[i*4*4+5] = (GLubyte)CTX::instance()->unpackGreen(col1);
+        color[i*4*4+2] = color[i*4*4+6] = (GLubyte)CTX::instance()->unpackBlue(col1);
+        color[i*4*4+3] = color[i*4*4+7] = (GLubyte)CTX::instance()->unpackAlpha(col1);
+        vertex[i*3*4+0] = xmin + i * box;
+        vertex[i*3*4+1] = ymin;
+        vertex[i*3*4+2] = 0.;
+        vertex[i*3*4+3] = xmin + i * box;
+        vertex[i*3*4+4] = ymin + dh;
+        vertex[i*3*4+5] = 0.;
+        double v2 = opt->tmpMin + (i + 1) * dv;
+        unsigned int col2 = opt->getColor(v2, opt->tmpMin, opt->tmpMax, true);
+        color[i*4*4+8] = color[i*4*4+12] = (GLubyte)CTX::instance()->unpackRed(col2);
+        color[i*4*4+9] = color[i*4*4+13] = (GLubyte)CTX::instance()->unpackGreen(col2);
+        color[i*4*4+10] = color[i*4*4+14] = (GLubyte)CTX::instance()->unpackBlue(col2);
+        color[i*4*4+11] = color[i*4*4+15] = (GLubyte)CTX::instance()->unpackAlpha(col2);
+        vertex[i*3*4+6] = xmin + (i + 1) * box;
+        vertex[i*3*4+7] = ymin;
+        vertex[i*3*4+8] = 0.;
+        vertex[i*3*4+9] = xmin + (i + 1) * box;
+        vertex[i*3*4+10] = ymin + dh;
+        vertex[i*3*4+11] = 0.;
+      }
+      else{
+        unsigned int col = opt->getColor(i, opt->nbIso);
+        color[i*4*4+0] = color[i*4*4+4] = color[i*4*4+8] = color[i*4*4+12] =
+          (GLubyte)CTX::instance()->unpackRed(col);
+        color[i*4*4+1] = color[i*4*4+5] = color[i*4*4+9] = color[i*4*4+13] =
+          (GLubyte)CTX::instance()->unpackGreen(col);
+        color[i*4*4+2] = color[i*4*4+6] = color[i*4*4+10] = color[i*4*4+14] =
+          (GLubyte)CTX::instance()->unpackBlue(col);
+        color[i*4*4+3] = color[i*4*4+7] = color[i*4*4+11] = color[i*4*4+15] =
+          (GLubyte)CTX::instance()->unpackAlpha(col);
+        vertex[i*3*4+0] = xmin + i * box;
+        vertex[i*3*4+1] = ymin;
+        vertex[i*3*4+2] = 0.;
+        vertex[i*3*4+3] = xmin + i * box;
+        vertex[i*3*4+4] = ymin + dh;
+        vertex[i*3*4+5] = 0.;
+        vertex[i*3*4+6] = xmin + (i + 1) * box;
+        vertex[i*3*4+7] = ymin;
+        vertex[i*3*4+8] = 0.;
+        vertex[i*3*4+9] = xmin + (i + 1) * box;
+        vertex[i*3*4+10] = ymin + dh;
+        vertex[i*3*4+11] = 0.;
+      }
+    }
+
+    glVertexPointer(3, GL_FLOAT, 0, &vertex[0]);
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glColorPointer(4, GL_UNSIGNED_BYTE, 0, &color[0]);
+    glEnableClientState(GL_COLOR_ARRAY);
+    if(opt->intervalsType == PViewOptions::Discrete ||
+       opt->intervalsType == PViewOptions::Numeric ||
+       opt->intervalsType == PViewOptions::Continuous)
+      glDrawArrays(GL_TRIANGLE_STRIP, 0, opt->nbIso*4);
+    else
+      glDrawArrays(GL_LINES, 0, opt->nbIso*4);
+    glDisableClientState(GL_COLOR_ARRAY);
+    glDisableClientState(GL_VERTEX_ARRAY);
+
+    char label[1024];
+    int nt = data->getNumTimeSteps();
+    if((opt->showTime == 1 && nt > 1) || opt->showTime == 2){
+      char tmp[256];
+      sprintf(tmp, opt->format.c_str(), data->getTime(opt->timeStep));
+      sprintf(label, "%s (%s)", data->getName().c_str(), tmp);
+    }
+    else if((opt->showTime == 3 && nt > 1) || opt->showTime == 4){
+      sprintf(label, "%s (%d/%d)", data->getName().c_str(), opt->timeStep,
+              data->getNumTimeSteps() - 1);
+    }
+    else{
+      sprintf(label, "%s", data->getName().c_str());
+    }
+    drawString lbl(label, 20 * _fontFactor);
+    lbl.draw(xmin + width / 2, ymin + 2.8 * dh, 0.,
+             _width/(_right-_left), _height/(_top-_bottom));
+
+    drawString val(data->getName().c_str(), 15 * _fontFactor);
+    for(int i = 0; i < 3; i++) {
+      double v = opt->getScaleValue(i, 3, opt->tmpMin, opt->tmpMax);
+      sprintf(label, opt->format.c_str(), v);
+      val.setText(label);
+      val.draw(xmin + i * width/ 2, ymin + 1.5 * dh, 0.,
+               _width/(_right-_left), _height/(_top-_bottom));
+    }
+    nPview++;
+  }
+  glPopMatrix();
 }
 
 void drawContext::drawPost()
 {
-	if(PView::list.empty()) return ;
-    
-	for(unsigned int i = 0; i < PView::list.size(); i++){
-		PView::list[i]->fillVertexArrays();
-		drawPView(PView::list[i]);
-	}
+  if(PView::list.empty()) return ;
+
+  for(unsigned int i = 0; i < PView::list.size(); i++){
+    PView::list[i]->fillVertexArrays();
+    drawPView(PView::list[i]);
+  }
 }
 
-void drawContext::drawAxes(float x0, float y0, float z0, float h)
+void drawContext::drawAxes()
 {
-	glLineWidth(1.);
-	glPushMatrix();
-	glLoadIdentity();
-	glTranslatef(x0, y0, z0);
-	glMultMatrixf(_rotatef);
-	glTranslatef(-x0, -y0, -z0);
-    
+  glLineWidth(1.);
+  glPushMatrix();
+  glLoadIdentity();
+
+  GLfloat h = std::max(_top - _bottom, _right - _left) / 25. ;
+  GLfloat x0 = _right - 1.8 * h;
+  GLfloat y0 = _bottom + 1.5 * h;
+
+  GLfloat xx = h * _rotatef[0];
+  GLfloat xy = h * _rotatef[1];
+  GLfloat yx = h * _rotatef[4];
+  GLfloat yy = h * _rotatef[5];
+  GLfloat zx = h * _rotatef[8];
+  GLfloat zy = h * _rotatef[9];
+  GLfloat o = h / 10;
+
   const GLfloat axes[] = {
-		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
-		(GLfloat)(x0+h), (GLfloat)y0, (GLfloat)z0,
-		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
-		(GLfloat)x0, (GLfloat)(y0+h), (GLfloat)z0,
-		(GLfloat)x0, (GLfloat)y0, (GLfloat)z0,
-		(GLfloat)x0, (GLfloat)y0, (GLfloat)(z0+h),
-	};
+    x0, y0,
+    x0 + xx, y0 + xy,
+    x0, y0,
+    x0 + yx, y0 + yy,
+    x0, y0,
+    x0 + zx, y0 + zy
+  };
   GLfloat colors[] = {
-		1., 0, 0, 1.,
-		1., 0, 0, 1.,
-		0, 0, 1., 1.,
-		0, 0, 1., 1.,
-		0, 1., 0, 1.,
-		0, 1., 0, 1.,
-	};
-	glVertexPointer(3, GL_FLOAT, 0, axes);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glColorPointer(4, GL_FLOAT, 0, colors);
-	glEnableClientState(GL_COLOR_ARRAY);
-	glDrawArrays(GL_LINES, 0, 6);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_COLOR_ARRAY);
-	drawString x ("X", 16,colors);
-	x.draw(x0+h, y0, z0, _width/(_right-_left), _height/(_top-_bottom));
-	drawString y("Y", 16,colors+8);
-	y.draw(x0, y0+h, z0, _width/(_right-_left), _height/(_top-_bottom));
-	drawString z("Z", 16,colors+16);
-	z.draw(x0, y0, z0+h, _width/(_right-_left), _height/(_top-_bottom));
-	glPopMatrix();
-	glLineWidth(1);
+    0., 0, 0, 1.,
+    0., 0, 0, 1.,
+    0, 0, 0., 1.,
+    0, 0, 0., 1.,
+    0, 0., 0, 1.,
+    0, 0., 0, 1.,
+  };
+  glVertexPointer(2, GL_FLOAT, 0, axes);
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glColorPointer(4, GL_FLOAT, 0, colors);
+  glEnableClientState(GL_COLOR_ARRAY);
+  glDrawArrays(GL_LINES, 0, 6);
+  glDisableClientState(GL_VERTEX_ARRAY);
+  glDisableClientState(GL_COLOR_ARRAY);
+
+  drawString x("X", 15 * _fontFactor, colors);
+  x.draw(x0 + xx + o, y0 + xy + o, 0, _width/(_right-_left), _height/(_top-_bottom), false);
+  drawString y("Y", 15 * _fontFactor, colors+8);
+  y.draw(x0 + yx + o, y0 + yy + o, 0, _width/(_right-_left), _height/(_top-_bottom), false);
+  drawString z("Z", 15 * _fontFactor, colors+16);
+  z.draw(x0 + zx + o, y0 + zy + o, 0, _width/(_right-_left), _height/(_top-_bottom), false);
+  glPopMatrix();
 }
 
 void drawContext::drawView()
 {
-	this->OrthofFromGModel();
-    
-	glMatrixMode(GL_MODELVIEW);
-	// fill the background
-	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-	if(_gradiant)
-	{
-		glPushMatrix();
-		glLoadIdentity();
-		const GLfloat squareVertices[] = {
-			(GLfloat)this->_top,	(GLfloat)this->_left, -5.,
-			(GLfloat)this->_top,	(GLfloat)this->_right, -5.,
-			(GLfloat)this->_bottom,	(GLfloat)this->_left, -5.,
-			(GLfloat)this->_bottom,	(GLfloat)this->_right, -5.,
-		};
-		const GLubyte squareColors[] = {
-			255, 255, 255, 255,
-			255, 255, 255, 255,
-			190, 200, 255, 255,
-			190, 200, 255, 255,
-		};
-		glVertexPointer(3, GL_FLOAT, 0, squareVertices);
-		glEnableClientState(GL_VERTEX_ARRAY);
-		glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
-		glEnableClientState(GL_COLOR_ARRAY);
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-		glDisableClientState(GL_COLOR_ARRAY);
-		glDisableClientState(GL_VERTEX_ARRAY);
-		glPopMatrix();
-	}
-	checkGlError("Draw background");
-	//
-	glLoadIdentity();
-	glScalef(_scale[0], _scale[1], _scale[2]);
-	glTranslatef(_translate[0], _translate[1], _translate[2]);
-	this->buildRotationMatrix();
-	glMultMatrixf(_rotatef);
-	checkGlError("Initialize position");
-
-	//
+  OrthofFromGModel();
+
+  glMatrixMode(GL_MODELVIEW);
+  // fill the background
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  if(CTX::instance()->bgGradient){
+    glPushMatrix();
+    glLoadIdentity();
+    const GLfloat squareVertices[] = {
+      (GLfloat)_top,	(GLfloat)_left, 2*_far,
+      (GLfloat)_top,	(GLfloat)_right, 2*_far,
+      (GLfloat)_bottom,	(GLfloat)_left, 2*_far,
+      (GLfloat)_bottom,	(GLfloat)_right, 2*_far,
+    };
+    const GLubyte squareColors[] = {
+      255, 255, 255, 255,
+      255, 255, 255, 255,
+      190, 200, 255, 255,
+      190, 200, 255, 255,
+    };
+    glVertexPointer(3, GL_FLOAT, 0, squareVertices);
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
+    glEnableClientState(GL_COLOR_ARRAY);
+    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    glDisableClientState(GL_COLOR_ARRAY);
+    glDisableClientState(GL_VERTEX_ARRAY);
+    glPopMatrix();
+  }
+  checkGlError("Draw background");
+
+  glLoadIdentity();
+  glScalef(_scale[0], _scale[1], _scale[2]);
+  glTranslatef(_translate[0], _translate[1], _translate[2]);
+
+  if(CTX::instance()->rotationCenterCg)
+    glTranslatef(CTX::instance()->cg[0],
+                 CTX::instance()->cg[1],
+                 CTX::instance()->cg[2]);
+  else
+    glTranslatef(CTX::instance()->rotationCenter[0],
+                 CTX::instance()->rotationCenter[1],
+                 CTX::instance()->rotationCenter[2]);
+
+  buildRotationMatrix();
+  glMultMatrixf(_rotatef);
+
+  if(CTX::instance()->rotationCenterCg)
+    glTranslatef(-CTX::instance()->cg[0],
+                 -CTX::instance()->cg[1],
+                 -CTX::instance()->cg[2]);
+  else
+    glTranslatef(-CTX::instance()->rotationCenter[0],
+                 -CTX::instance()->rotationCenter[1],
+                 -CTX::instance()->rotationCenter[2]);
+
+  checkGlError("Initialize position");
+
   glEnable(GL_DEPTH_TEST);
-	this->drawMesh();
-	checkGlError("Draw mesh");
-	this->drawGeom();
-	checkGlError("Draw geometry");
-	this->drawPost();
-	checkGlError("Draw post-pro");
+
+  drawMesh();
+  checkGlError("Draw mesh");
+  drawGeom();
+  checkGlError("Draw geometry");
+  drawPost();
+  checkGlError("Draw post-pro");
   glDisable(GL_DEPTH_TEST);
-	this->drawScale();
-	checkGlError("Draw scales");
-	this->drawAxes(this->_right - (this->_top - this->_bottom)/15.0,
-                   this->_bottom + (this->_top - this->_bottom)/15.0,
-                    0, (this->_top - this->_bottom)/20.);
-	checkGlError("Draw axes");
+  drawScale();
+  checkGlError("Draw scales");
+  drawAxes();
+  checkGlError("Draw axes");
 }
 
 std::vector<std::string> commandToVector(const std::string cmd)
 {
-	std::vector<std::string> ret;
-	int pos=0, last=0;
-	while((pos = cmd.find("-", last+1)) != std::string::npos)
-	{
-		ret.push_back(cmd.substr(last,pos-1-last));
-		last = pos;
-	}
-	ret.push_back(cmd.substr(last,cmd.size()-1));
-	return ret;
+  std::vector<std::string> ret;
+  int pos = 0, last = 0;
+  while((pos = cmd.find("-", last+1)) != std::string::npos){
+    ret.push_back(cmd.substr(last,pos-1-last));
+    last = pos;
+  }
+  ret.push_back(cmd.substr(last));
+  return ret;
 }
 
 int onelab_cb(std::string action)
 {
-	Msg::Debug("Ask onlab to %s", action.c_str());
-	if(action == "stop"){
-		onelab::string o("GetDP/Action", "stop");
-		o.setVisible(false);
-		o.setNeverChanged(true);
-		onelab::server::instance()->set(o);
-		onelabStop = true;
-		return 0;
-	}
-	if(locked) return -1;
-	locked = true;
-	int redraw = 0;
-	if(action == "reset"){
-        onelab::server::instance()->clear();
-        onelabUtils::runGmshClient(action, true);
-		action = "check";
-	}
-    
-	Msg::ResetErrorCounter();
-    
-	if(action == "compute"){
-		onelabUtils::initializeLoop("1");
-		onelabUtils::initializeLoop("2");
-		onelabUtils::initializeLoop("3");
-	}
-    
-	do{
-		if(onelabUtils::runGmshClient(action, true))
-			redraw = 1;
-        
-		if(redraw == 0 && !onelab::server::instance()->getChanged("GetDP"))continue;
-        
-		std::vector<onelab::string> ps;
-		onelab::server::instance()->get(ps, "GetDP/1ModelName");
-		if(ps.empty()){
-			std::vector<std::string> split = SplitFileName(GModel::current()->getFileName());
-			std::string name(split[0] + split[1]);
-			onelab::string o("GetDP/1ModelName", name, "Model name");
-			o.setKind("file");
-			onelab::server::instance()->set(o);
-		}
-		onelab::string o("GetDP/Action", action);
-		o.setVisible(false);
-		o.setNeverChanged(true);
-		onelab::server::instance()->set(o);
-        
-		if(action == "compute" && (onelab::server::instance()->getChanged("Gmsh") || onelab::server::instance()->getChanged("GetDP"))){
-			std::string filename = GModel::current()->getFileName();
-			std::vector<std::string> args;
-			args.push_back("getdp");
-			std::vector<onelab::string> onelabArgs;
-			onelab::server::instance()->get(onelabArgs, "GetDP/1ModelName");
-			args.push_back((onelabArgs.empty())? SplitFileName(filename)[0] + SplitFileName(filename)[1] : onelabArgs[0].getValue());
-			onelab::server::instance()->get(onelabArgs, "GetDP/9ComputeCommand");
-			std::vector<std::string> compute = commandToVector((onelabArgs.empty())? "" : onelabArgs[0].getValue().c_str());
-			args.insert( args.end(), compute.begin(), compute.end() );
-			args.push_back("-onelab");
-			args.push_back("GetDP");
-			GetDP(args, onelab::server::instance());
-		}
-		if(action == "check" && (onelab::server::instance()->getChanged("Gmsh") || onelab::server::instance()->getChanged("GetDP"))){
-			std::string filename = GModel::current()->getFileName();
-			std::vector<std::string> args;
-			args.push_back("getdp");
-			std::vector<onelab::string> onelabArgs;
-			args.push_back(SplitFileName(filename)[0] + SplitFileName(filename)[1]);
-			onelab::server::instance()->get(onelabArgs, "GetDP/9CheckCommand");
-			args.push_back((onelabArgs.empty())? "" : onelabArgs[0].getValue());
-			args.push_back("-onelab");
-			args.push_back("GetDP");
-			GetDP(args, onelab::server::instance());
-		}
-	} while(action == "compute" && !onelabStop && (onelabUtils::incrementLoop("3") || onelabUtils::incrementLoop("2") || onelabUtils::incrementLoop("1")));
-    
-	locked = false;
-
-	return redraw;
+  if(action == "stop"){
+    onelab::string o("GetDP/Action", "stop");
+    o.setVisible(false);
+    o.setNeverChanged(true);
+    onelab::server::instance()->set(o);
+    onelabStop = true;
+    return 0;
+  }
+
+  if(locked) return -1;
+  locked = true;
+
+  if(action == "reset"){
+    onelab::server::instance()->clear();
+    onelabUtils::runGmshClient(action, true);
+    action = "check";
+  }
+
+  Msg::ResetErrorCounter();
+
+  if(action == "compute"){
+    onelabUtils::initializeLoop("1");
+    onelabUtils::initializeLoop("2");
+    onelabUtils::initializeLoop("3");
+  }
+
+  do{
+    // run Gmsh (only if necessary)
+    onelabUtils::runGmshClient(action, true);
+
+    // run GetDP (always -- to not confuse the user)
+    onelab::string o("GetDP/Action", action);
+    o.setVisible(false);
+    o.setNeverChanged(true);
+    onelab::server::instance()->set(o);
+
+    std::vector<std::string> args;
+    args.push_back("getdp");
+    std::vector<onelab::string> ps;
+    onelab::server::instance()->get(ps, "GetDP/1ModelName");
+    if(ps.empty()){
+      std::vector<std::string> split = SplitFileName(GModel::current()->getFileName());
+      std::string name(split[0] + split[1]);
+      onelab::string o("GetDP/1ModelName", name, "Model name");
+      o.setKind("file");
+      onelab::server::instance()->set(o);
+      ps.push_back(o);
+    }
+    args.push_back(ps[0].getValue());
+    if(action == "check")
+      onelab::server::instance()->get(ps, "GetDP/9CheckCommand");
+    else if(action == "compute")
+      onelab::server::instance()->get(ps, "GetDP/9ComputeCommand");
+    else
+      ps.clear();
+    std::vector<std::string> c = commandToVector(ps.empty() ? "" : ps[0].getValue().c_str());
+    args.insert(args.end(), c.begin(), c.end());
+    args.push_back("-onelab");
+    args.push_back("GetDP");
+    GetDP(args, onelab::server::instance());
+  } while(action == "compute" && !onelabStop && (onelabUtils::incrementLoop("3") ||
+                                                 onelabUtils::incrementLoop("2") ||
+                                                 onelabUtils::incrementLoop("1")));
+  locked = false;
+  return onelab::server::instance()->getChanged();
 }
 
-int number_of_animation() {
-	int ret = 0;
-	for(unsigned int i = 0; i < PView::list.size(); i++){
-		PView * p = PView::list[i];
-		if(p->getOptions()->visible){
-			int numSteps = (int)p->getData()->getNumTimeSteps();
-			if(numSteps > ret) ret = numSteps;
-		}
-	}
-	return ret;
+int number_of_animation()
+{
+  int ret = 0;
+  for(unsigned int i = 0; i < PView::list.size(); i++){
+    PView * p = PView::list[i];
+    if(p->getOptions()->visible){
+      int numSteps = (int)p->getData()->getNumTimeSteps();
+      if(numSteps > ret) ret = numSteps;
+    }
+  }
+  return ret;
 }
 
-void set_animation(int step) {
-	for(unsigned int i = 0; i < PView::list.size(); i++){
-		PView * p = PView::list[i];
-		if(p->getOptions()->visible){
-			p->getOptions()->timeStep = step;
-			p->setChanged(true);
-		}
-	}	
+void set_animation(int step)
+{
+  for(unsigned int i = 0; i < PView::list.size(); i++){
+    PView * p = PView::list[i];
+    if(p->getOptions()->visible){
+      p->getOptions()->timeStep = step;
+      p->setChanged(true);
+    }
+  }
 }
 
-int animation_next() {
-	int ret = 0;
-	for(unsigned int i = 0; i < PView::list.size(); i++){
-		PView * p = PView::list[i];
-		if(p->getOptions()->visible){
-			int step = (int)p->getOptions()->timeStep + 1;
-			int numSteps = (int)p->getData()->getNumTimeSteps();
-			if(step < 0) step = numSteps - 1;
-			if(step > numSteps - 1) step = 0;
-			p->getOptions()->timeStep = step;
-			p->setChanged(true);
-			ret = step;
-		}
-	}
-	return ret;
-}
-int animation_prev() {
-	int ret = 0;
-	for(unsigned int i = 0; i < PView::list.size(); i++){
-		PView * p = PView::list[i];
-		if(p->getOptions()->visible){
-			// skip empty steps
-			int step = (int)p->getOptions()->timeStep - 1;
-			int numSteps = (int)p->getData()->getNumTimeSteps();
-			if(step < 0) step = numSteps - 1;
-			if(step > numSteps - 1) step = 0;
-			p->getOptions()->timeStep = step;
-			p->setChanged(true);
-			ret = step;
-		}
-	}
-	return ret;
+int animation_next()
+{
+  int ret = 0;
+  for(unsigned int i = 0; i < PView::list.size(); i++){
+    PView * p = PView::list[i];
+    if(p->getOptions()->visible){
+      int step = (int)p->getOptions()->timeStep + 1;
+      int numSteps = (int)p->getData()->getNumTimeSteps();
+      if(step < 0) step = numSteps - 1;
+      if(step > numSteps - 1) step = 0;
+      p->getOptions()->timeStep = step;
+      p->setChanged(true);
+      ret = step;
+    }
+  }
+  return ret;
 }
 
-// vim:set ts=2:
+int animation_prev()
+{
+  int ret = 0;
+  for(unsigned int i = 0; i < PView::list.size(); i++){
+    PView * p = PView::list[i];
+    if(p->getOptions()->visible){
+      // skip empty steps
+      int step = (int)p->getOptions()->timeStep - 1;
+      int numSteps = (int)p->getData()->getNumTimeSteps();
+      if(step < 0) step = numSteps - 1;
+      if(step > numSteps - 1) step = 0;
+      p->getOptions()->timeStep = step;
+      p->setChanged(true);
+      ret = step;
+    }
+  }
+  return ret;
+}
diff --git a/contrib/mobile/drawContext.h b/contrib/mobile/drawContext.h
index e800ae3..ac7076d 100644
--- a/contrib/mobile/drawContext.h
+++ b/contrib/mobile/drawContext.h
@@ -1,67 +1,55 @@
 #ifndef _DRAW_GMODEL_H_
 #define _DRAW_GMODEL_H_
 
-#ifndef __cplusplus
-#error You need a Cpp compiler!
-#endif
-
-#if !defined(BUILD_ANDROID)
-#define BUILD_IOS 1
-#endif
-
 #include <string>
 
-#if defined(BUILD_IOS)
-#include <Gmsh/PView.h>
-#include <Gmsh/PViewOptions.h>
-#include <Gmsh/Context.h>
-#endif
+#include <gmsh/PView.h>
+#include <gmsh/PViewOptions.h>
 
 #include "movePosition.h"
 
-void drawArray(VertexArray *va, int type, bool useColorArray=false, bool useNormalArray=false);
+class drawContext{
+private:
+  float _translate[3], _scale[3]; // current translation and scale
+  double _rotate[16]; // current rotation matrix (double for Trackball)
+  float _rotatef[16]; // current rotation matrix (float for OpenGL ES)
+  double _quaternion[4]; // current quaternion used for rotation
+  movePosition _start, _previous, _current; // store informations about user interactions
+  int _width, _height; // size of OpenGL context in pixel
+  float _left, _right, _top, _bottom, _far; // value of "border"
+  float _fontFactor;
+  bool _retina; // retina display
+
+  void OrthofFromGModel(void);
+  void drawPView(PView *p);
+  void drawVectorArray(PViewOptions *opt, VertexArray *va);
+public:
+  drawContext(float fontFactor=1., bool retina=false);
+  ~drawContext(){}
+  void load(std::string filename);
+  void eventHandler(int event, float x=0, float y=0);
+  void setQuaternion(double q0, double q1, double q2, double q3);
+  void addQuaternion(double p1x, double p1y, double p2x, double p2y);
+  void buildRotationMatrix();
+  void setTranslate(int i, float t) {if(i>=0 && i<3) _translate[i] = t;}
+  float getTranslate(int i) {if(i>=0 && i<3) return _translate[i]; return 0;}
+  void setScale(int i, float s) {if(i>=0 && i<3) _scale[i] = s;}
+  float getScale(int i) {if(i>=0 && i<3) return _scale[i]; return 0;}
+  void initView(int w, int h);
+  void drawView();
+  void drawAxes();
+  void drawGeom();
+  void drawMesh();
+  void drawPost();
+  void drawScale();
+};
+
+void drawArray(VertexArray *va, int type, bool useColorArray=false,
+               bool useNormalArray=false);
 int onelab_cb(std::string);
 int animation_next();
 int animation_prev();
 int number_of_animation();
 void set_animation(int step);
 
-class drawContext{
-private:
-	float _translate[3], _scale[3]; // current translation and scale
-	double _rotate[16]; // current rotation matrix (double for Trackball)
-	float _rotatef[16]; // current rotation matrix (float for OpenGL ES)
-	double _quaternion[4]; // current quaternion used for rotation
-	movePosition _start, _previous, _current; // store informations about user interactions
-	int _width, _height; // size of OpenGL context in pixel
-	float _left, _right, _top, _bottom; // value of "border"
-	bool _gradiant, // show the background gradiant
-	_fillMesh; // fill the Mesh
-    
-	void OrthofFromGModel(void);
-	void drawPView(PView *p);
-	void drawVectorArray(PViewOptions *opt, VertexArray *va);
-    
-public:
-	drawContext();
-	~drawContext(){}
-	void load(std::string filename);
-	void eventHandler(int event, float x=0, float y=0);
-	void setQuaternion(double q0, double q1, double q2, double q3);
-	void addQuaternion(double p1x, double p1y, double p2x, double p2y);
-	void buildRotationMatrix();
-	void setTranslate(int i, float t) {if(i>=0 && i<3) this->_translate[i] = t;}
-	float getTranslate(int i) {if(i>=0 && i<3) return this->_translate[i]; return 0;}
-	void setScale(int i, float s) {if(i>=0 && i<3) this->_scale[i] = s;}
-	float getScale(int i) {if(i>=0 && i<3) return this->_scale[i]; return 0;}
-	void initView(int w, int h);
-	void drawView();
-	void drawAxes(float x0=0., float y0=0., float z0=0., float h=0.5);
-	void drawGeom();
-	void drawMesh();
-	void drawPost();
-	void drawScale();
-	void useGradiant(bool gradiant=true) {_gradiant = gradiant;}
-};
-
 #endif
diff --git a/contrib/mobile/drawGeom.cpp b/contrib/mobile/drawGeom.cpp
index fda9d77..71e377f 100644
--- a/contrib/mobile/drawGeom.cpp
+++ b/contrib/mobile/drawGeom.cpp
@@ -1,96 +1,89 @@
 #include <stdlib.h>
-#if !defined(BUILD_ANDROID)
-#define BUILD_IOS 1
-#endif
-
-#if defined(BUILD_IOS)
-#include <OpenGLES/ES1/gl.h>
-#include <OpenGLES/ES1/glext.h>
-
-#include <Gmsh/Gmsh.h>
-#include <Gmsh/GModel.h>
-#endif
 
 #if defined(BUILD_ANDROID)
 #include <GLES/gl.h>
 #include <GLES/glext.h>
+#else
+#include <OpenGLES/ES1/gl.h>
+#include <OpenGLES/ES1/glext.h>
+#endif
 
 #include <gmsh/Gmsh.h>
 #include <gmsh/GModel.h>
-#include <gmsh/PView.h>
 #include <gmsh/Context.h>
-#endif
 
 #include "drawContext.h"
 
 void drawGeomVertex(GVertex *v)
 {
-	if(!v->getVisibility()) return;
-	if(v->geomType() == GEntity::BoundaryLayerPoint) return;
+  if(!v->getVisibility()) return;
+  if(v->geomType() == GEntity::BoundaryLayerPoint) return;
 
-	unsigned int col = CTX::instance()->color.geom.point;
-	glColor4ub((GLubyte)CTX::instance()->unpackRed(col),
-               (GLubyte)CTX::instance()->unpackGreen(col),
-               (GLubyte)CTX::instance()->unpackBlue(col),
-               (GLubyte)CTX::instance()->unpackAlpha(col));
-	const GLfloat p[] = {(GLfloat)v->x(), (GLfloat)v->y(), (GLfloat)v->z()};
-	glPointSize((GLfloat)CTX::instance()->geom.pointSize);
-	glVertexPointer(3, GL_FLOAT, 0, p);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glDrawArrays(GL_POINTS, 0, 1);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glPointSize(1);
+  unsigned int col = CTX::instance()->color.geom.point;
+  glColor4ub((GLubyte)CTX::instance()->unpackRed(col),
+             (GLubyte)CTX::instance()->unpackGreen(col),
+             (GLubyte)CTX::instance()->unpackBlue(col),
+             (GLubyte)CTX::instance()->unpackAlpha(col));
+  const GLfloat p[] = {(GLfloat)v->x(), (GLfloat)v->y(), (GLfloat)v->z()};
+  glPointSize((GLfloat)CTX::instance()->geom.pointSize);
+  glVertexPointer(3, GL_FLOAT, 0, p);
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glDrawArrays(GL_POINTS, 0, 1);
+  glDisableClientState(GL_VERTEX_ARRAY);
+  glPointSize(1);
 }
+
 void drawGeomEdge(GEdge *e)
 {
-	if(!e->getVisibility()) return;
-	if(e->geomType() == GEntity::DiscreteCurve) return;
-	if(e->geomType() == GEntity::PartitionCurve) return;
-	if(e->geomType() == GEntity::BoundaryLayerCurve) return;
+  if(!e->getVisibility()) return;
+  if(e->geomType() == GEntity::DiscreteCurve) return;
+  if(e->geomType() == GEntity::PartitionCurve) return;
+  if(e->geomType() == GEntity::BoundaryLayerCurve) return;
 
-	unsigned int col = CTX::instance()->color.geom.line;
-	glColor4ub((GLubyte)CTX::instance()->unpackRed(col),
-               (GLubyte)CTX::instance()->unpackGreen(col),
-               (GLubyte)CTX::instance()->unpackBlue(col),
-               (GLubyte)CTX::instance()->unpackAlpha(col));
-	int N = e->minimumDrawSegments() + 1;
-	Range<double> t_bounds = e->parBounds(0);
-	double t_min = t_bounds.low();
-	double t_max = t_bounds.high();
+  unsigned int col = CTX::instance()->color.geom.line;
+  glColor4ub((GLubyte)CTX::instance()->unpackRed(col),
+             (GLubyte)CTX::instance()->unpackGreen(col),
+             (GLubyte)CTX::instance()->unpackBlue(col),
+             (GLubyte)CTX::instance()->unpackAlpha(col));
+  int N = e->minimumDrawSegments() + 1;
+  Range<double> t_bounds = e->parBounds(0);
+  double t_min = t_bounds.low();
+  double t_max = t_bounds.high();
 
-	// Create a VA for this edge
-        std::vector<GLfloat> edge(N*3);
-	for(unsigned int i=0; i < N; i++) {
-		double t = t_min + (double)i / (double)(N-1) * (t_max - t_min);
-		GPoint p = e->point(t);
-		edge[i*3] = p.x(); edge[i*3+1] = p.y(); edge[i*3+2] = p.z();
-	}
-	// Then print the VA
-	glLineWidth((GLfloat)CTX::instance()->geom.lineWidth);
-	glVertexPointer(3, GL_FLOAT, 0, &edge[0]);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glEnable(GL_LINE_SMOOTH);
-	glDrawArrays(GL_LINE_STRIP, 0, N);
-	glDisable(GL_LINE_SMOOTH);
-	glDisableClientState(GL_VERTEX_ARRAY);
+  // Create a VA for this edge
+  std::vector<GLfloat> edge(N*3);
+  for(unsigned int i=0; i < N; i++) {
+    double t = t_min + (double)i / (double)(N-1) * (t_max - t_min);
+    GPoint p = e->point(t);
+    edge[i*3] = p.x(); edge[i*3+1] = p.y(); edge[i*3+2] = p.z();
+  }
+  // Then print the VA
+  glLineWidth((GLfloat)CTX::instance()->geom.lineWidth);
+  glVertexPointer(3, GL_FLOAT, 0, &edge[0]);
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glEnable(GL_LINE_SMOOTH);
+  glDrawArrays(GL_LINE_STRIP, 0, N);
+  glDisable(GL_LINE_SMOOTH);
+  glDisableClientState(GL_VERTEX_ARRAY);
 }
+
 void drawGeomFace(GFace *f)
 {
 	// TODO
 }
+
 void drawContext::drawGeom()
 {
-	for(unsigned int i=0; i<GModel::list.size(); i++) {
-		GModel *m = GModel::list[i];
-		if(!m->getVisibility()) continue;
-		if(CTX::instance()->geom.points || CTX::instance()->geom.pointsNum)
-			std::for_each(m->firstVertex(), m->lastVertex(), drawGeomVertex);
-		if(CTX::instance()->geom.lines || CTX::instance()->geom.linesNum || CTX::instance()->geom.tangents)
-			std::for_each(m->firstEdge(), m->lastEdge(), drawGeomEdge);
-		if(CTX::instance()->geom.surfaces || CTX::instance()->geom.surfacesNum || CTX::instance()->geom.normals)
-			std::for_each(m->firstFace(), m->lastFace(), drawGeomFace);
-
-	}
+  for(unsigned int i=0; i<GModel::list.size(); i++) {
+    GModel *m = GModel::list[i];
+    if(!m->getVisibility()) continue;
+    if(CTX::instance()->geom.points || CTX::instance()->geom.pointsNum)
+      std::for_each(m->firstVertex(), m->lastVertex(), drawGeomVertex);
+    if(CTX::instance()->geom.lines || CTX::instance()->geom.linesNum ||
+       CTX::instance()->geom.tangents)
+      std::for_each(m->firstEdge(), m->lastEdge(), drawGeomEdge);
+    if(CTX::instance()->geom.surfaces || CTX::instance()->geom.surfacesNum ||
+       CTX::instance()->geom.normals)
+      std::for_each(m->firstFace(), m->lastFace(), drawGeomFace);
+  }
 }
-
-
diff --git a/contrib/mobile/drawMesh.cpp b/contrib/mobile/drawMesh.cpp
index 4ca5e26..7d4be6a 100644
--- a/contrib/mobile/drawMesh.cpp
+++ b/contrib/mobile/drawMesh.cpp
@@ -1,22 +1,10 @@
-#if !defined(BUILD_ANDROID)
-#define BUILD_IOS 1
-#endif
-
-#if defined(BUILD_IOS)
-#include <OpenGLES/ES1/gl.h>
-#include <OpenGLES/ES1/glext.h>
-
-#include <Gmsh/Gmsh.h>
-#include <Gmsh/GModel.h>
-#include <Gmsh/GEdgeCompound.h>
-#include <Gmsh/GFaceCompound.h>
-#include <Gmsh/PView.h>
-#include <Gmsh/PViewData.h>
-#endif
-
 #if defined(BUILD_ANDROID)
 #include <GLES/gl.h>
 #include <GLES/glext.h>
+#else
+#include <OpenGLES/ES1/gl.h>
+#include <OpenGLES/ES1/glext.h>
+#endif
 
 #include <gmsh/Gmsh.h>
 #include <gmsh/GModel.h>
@@ -25,7 +13,6 @@
 #include <gmsh/PView.h>
 #include <gmsh/PViewData.h>
 #include <gmsh/Context.h>
-#endif
 
 #include "drawContext.h"
 
@@ -34,90 +21,100 @@ extern unsigned int getColorByEntity(GEntity *e);
 
 void drawMeshVertex(GVertex *e)
 {
-    if(!CTX::instance()->mesh.points && !CTX::instance()->mesh.pointsNum) return;
-    if(!CTX::instance()->mesh.points) return;
-	std::vector<GLfloat> vertex;
-	std::vector<GLubyte> color;
-	for(unsigned int i = 0; i < e->mesh_vertices.size(); i++){
-		MVertex *v = e->mesh_vertices[i];
-		if(!v->getVisibility()) continue;
-        unsigned int col;
-		if(CTX::instance()->mesh.colorCarousel == 0 || CTX::instance()->mesh.volumesFaces || CTX::instance()->mesh.surfacesFaces) {
-			if(v->getPolynomialOrder() > 1)
-				col = CTX::instance()->color.mesh.vertexSup;
-			else
-				col = CTX::instance()->color.mesh.vertex;
-		}
-        else
-        col = getColorByEntity(e);
-        color.push_back((GLubyte)CTX::instance()->unpackRed(col));
-        color.push_back((GLubyte)CTX::instance()->unpackGreen(col));
-        color.push_back((GLubyte)CTX::instance()->unpackBlue(col));
-        color.push_back((GLubyte)CTX::instance()->unpackAlpha(col));
-		vertex.push_back(v->x());
-		vertex.push_back(v->y());
-		vertex.push_back(v->z());
-	}
-	glVertexPointer(3, GL_FLOAT, 0, &vertex.front());
-	glEnableClientState(GL_VERTEX_ARRAY);
-    glColorPointer(4, GL_UNSIGNED_BYTE, color.size()/4, &color.front());
-    glEnableClientState(GL_COLOR_ARRAY);
-	glDrawArrays(GL_POINTS, 0, vertex.size()/3);
-	glDisableClientState(GL_VERTEX_ARRAY);
-    glDisableClientState(GL_COLOR_ARRAY);
+  if(!CTX::instance()->mesh.points && !CTX::instance()->mesh.pointsNum) return;
+  if(!CTX::instance()->mesh.points) return;
+  std::vector<GLfloat> vertex;
+  std::vector<GLubyte> color;
+  for(unsigned int i = 0; i < e->mesh_vertices.size(); i++){
+    MVertex *v = e->mesh_vertices[i];
+    if(!v->getVisibility()) continue;
+    unsigned int col;
+    if(CTX::instance()->mesh.colorCarousel == 0 ||
+       CTX::instance()->mesh.volumesFaces || CTX::instance()->mesh.surfacesFaces) {
+      if(v->getPolynomialOrder() > 1)
+        col = CTX::instance()->color.mesh.vertexSup;
+      else
+        col = CTX::instance()->color.mesh.vertex;
+    }
+    else
+      col = getColorByEntity(e);
+    color.push_back((GLubyte)CTX::instance()->unpackRed(col));
+    color.push_back((GLubyte)CTX::instance()->unpackGreen(col));
+    color.push_back((GLubyte)CTX::instance()->unpackBlue(col));
+    color.push_back((GLubyte)CTX::instance()->unpackAlpha(col));
+    vertex.push_back(v->x());
+    vertex.push_back(v->y());
+    vertex.push_back(v->z());
+  }
+  glVertexPointer(3, GL_FLOAT, 0, &vertex.front());
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glColorPointer(4, GL_UNSIGNED_BYTE, color.size()/4, &color.front());
+  glEnableClientState(GL_COLOR_ARRAY);
+  glDrawArrays(GL_POINTS, 0, vertex.size()/3);
+  glDisableClientState(GL_VERTEX_ARRAY);
+  glDisableClientState(GL_COLOR_ARRAY);
 }
+
 void drawMeshEdge(GEdge *e)
 {
-    if(!e->getVisibility()) {
-        if(e->getCompound()) {
-            if(!e->getCompound()->getVisibility()) return;
-        }
-        else
-            return;
+  if(!e->getVisibility()) {
+    if(e->getCompound()) {
+      if(!e->getCompound()->getVisibility()) return;
     }
-    glLineWidth(CTX::instance()->mesh.lineWidth);
-	drawArray(e->va_lines, GL_LINES, true);
+    else
+      return;
+  }
+  glLineWidth(CTX::instance()->mesh.lineWidth);
+  drawArray(e->va_lines, GL_LINES, true);
 }
+
 void drawMeshFace(GFace *f)
 {
-    if(!f->getVisibility()) {
-        if(f->getCompound()) {
-            if(!f->getCompound()->getVisibility()) return;
-        }
-        else
-            return;
+  if(!f->getVisibility()) {
+    if(f->getCompound()) {
+      if(!f->getCompound()->getVisibility()) return;
     }
-	drawArray(f->va_lines, GL_LINES, true);
+    else
+      return;
+  }
+  drawArray(f->va_lines, GL_LINES, true);
 }
 
-void drawContext::drawMesh()
+void drawMeshRegion(GRegion *r)
 {
-	if(!CTX::instance()->mesh.draw) return;
+  if(!r->getVisibility()) return;
 
-	if(CTX::instance()->mesh.changed)
-		for(unsigned int i = 0; i < GModel::list.size(); i++)
-			for(unsigned int j = 0; j < PView::list.size(); j++)
-				if(PView::list[j]->getData()->hasModel(GModel::list[i]))
-					PView::list[j]->setChanged(true);
-
-    unsigned int col = CTX::instance()->color.mesh.line;
-	glColor4ub((GLubyte)CTX::instance()->unpackRed(col),
-               (GLubyte)CTX::instance()->unpackGreen(col),
-               (GLubyte)CTX::instance()->unpackBlue(col),
-               (GLubyte)CTX::instance()->unpackAlpha(col));
-	for(unsigned int i = 0; i < GModel::list.size(); i++){
-		GModel *m = GModel::list[i];
-		m->fillVertexArrays();
-		if(!m->getVisibility()) continue;
-		int status = m->getMeshStatus();
-		if(status >= 0)
-            std::for_each(m->firstVertex(), m->lastVertex(), drawMeshVertex);
-		if(status >= 1)
-			std::for_each(m->firstEdge(), m->lastEdge(), drawMeshEdge);
-		if(status >= 2)
-            std::for_each(m->firstFace(), m->lastFace(), drawMeshFace);
-	}
-	CTX::instance()->mesh.changed = 0;
+  drawArray(r->va_lines, GL_LINES, true);
 }
 
+void drawContext::drawMesh()
+{
+  if(!CTX::instance()->mesh.draw) return;
 
+  if(CTX::instance()->mesh.changed)
+    for(unsigned int i = 0; i < GModel::list.size(); i++)
+      for(unsigned int j = 0; j < PView::list.size(); j++)
+        if(PView::list[j]->getData()->hasModel(GModel::list[i]))
+          PView::list[j]->setChanged(true);
+
+  unsigned int col = CTX::instance()->color.mesh.line;
+  glColor4ub((GLubyte)CTX::instance()->unpackRed(col),
+             (GLubyte)CTX::instance()->unpackGreen(col),
+             (GLubyte)CTX::instance()->unpackBlue(col),
+             (GLubyte)CTX::instance()->unpackAlpha(col));
+  for(unsigned int i = 0; i < GModel::list.size(); i++){
+    GModel *m = GModel::list[i];
+    m->fillVertexArrays();
+    if(!m->getVisibility()) continue;
+    int status = m->getMeshStatus();
+    if(status >= 0)
+      std::for_each(m->firstVertex(), m->lastVertex(), drawMeshVertex);
+    if(status >= 1)
+      std::for_each(m->firstEdge(), m->lastEdge(), drawMeshEdge);
+    if(status >= 2)
+      std::for_each(m->firstFace(), m->lastFace(), drawMeshFace);
+    if(status >= 3)
+      std::for_each(m->firstRegion(), m->lastRegion(), drawMeshRegion);
+  }
+  CTX::instance()->mesh.changed = 0;
+}
diff --git a/contrib/mobile/drawString.cpp b/contrib/mobile/drawString.cpp
index 8d2b19e..8216971 100644
--- a/contrib/mobile/drawString.cpp
+++ b/contrib/mobile/drawString.cpp
@@ -1,83 +1,81 @@
-#if !defined(BUILD_ANDROID)
-#define BUILD_IOS 1
-#endif
-
-#if defined(BUILD_IOS)
-#include <OpenGLES/ES1/gl.h>
-#include <OpenGLES/ES1/glext.h>
-#endif
-
 #if defined(BUILD_ANDROID)
 #include <GLES/gl.h>
 #include <GLES/glext.h>
+#else
+#include <OpenGLES/ES1/gl.h>
+#include <OpenGLES/ES1/glext.h>
 #endif
 
 #include "drawString.h"
 
 drawString::drawString(std::string text, int size, float color[4])
 {
-	_size = size;
-	if(color == NULL)
-		this->setColor(0.0f, 0.0f, 0.0f, 1.0f);
-	else
-		this->setColor(color);
-	this->setText(text);
+  _map = 0;
+  _size = size;
+  if(color == NULL)
+    setColor(0.0f, 0.0f, 0.0f, 1.0f);
+  else
+    setColor(color);
+  setText(text);
 }
 
 void drawString::setText(std::string text)
 {
-	this->_text = text;
-	getBitmapFromString(this->_text.c_str(), _size, &this->_map, &this->_height, &this->_width, &this->_realWidth);
+  _text = text;
+  getBitmapFromString(_text.c_str(), _size, &_map,
+                      &_height, &_width, &_realWidth);
 }
 
 void drawString::setColor(float color[4])
 {
-	_color[0] = color[0];
-	_color[1] = color[1];
-	_color[2] = color[2];
-	_color[3] = color[3];
+  _color[0] = color[0];
+  _color[1] = color[1];
+  _color[2] = color[2];
+  _color[3] = color[3];
 }
 
 void drawString::setColor(float r, float g, float b, float a)
 {
-	_color[0] = r;
-	_color[1] = g;
-	_color[2] = b;
-	_color[3] = a;
+  _color[0] = r;
+  _color[1] = g;
+  _color[2] = b;
+  _color[3] = a;
 }
+
 void drawString::draw(float x, float y, float z, float w, float h, bool center)
 {
-	GLuint textureId;
-	glGenTextures(1, &textureId);
-	glBindTexture(GL_TEXTURE_2D, textureId);
-	glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, _width, _height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, _map);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glColor4f(_color[0], _color[1], _color[2], _color[3]);
-	if(center)
-		x-=(float)_realWidth/w/2;
-	GLfloat vertex[] = {
-		 x, y, z, // bottom left
-		 x, y+(float)_height/h, z, // top left
-		 x+(float)_width/w, y, z, // bottom right
-		 x+(float)_width/w, y+(float)_height/h, z, // top right
-	};
-	GLfloat texture[] = {
-		0.0f, 1.0f, // top left
-		0.0f, 0.0f, // bottom left
-		1.0f, 1.0f, // top right
-		1.0f, 0.0f, // bottom right
-	};
-	glEnable(GL_TEXTURE_2D);
-	glEnable(GL_BLEND);
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-	glTexCoordPointer(2, GL_FLOAT, 0, texture);
-	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glVertexPointer(3, GL_FLOAT, 0, vertex);
-	glEnableClientState(GL_VERTEX_ARRAY);
-	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-	glDisableClientState(GL_VERTEX_ARRAY);
-	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-	glDisable(GL_BLEND);
-	glDisable(GL_TEXTURE_2D);
-	glDeleteTextures(1, &textureId);
+  GLuint textureId;
+  glGenTextures(1, &textureId);
+  glBindTexture(GL_TEXTURE_2D, textureId);
+  glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, _width, _height, 0,
+               GL_ALPHA, GL_UNSIGNED_BYTE, _map);
+  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  glColor4f(_color[0], _color[1], _color[2], _color[3]);
+  if(center)
+    x-=(float)_realWidth/w/2;
+  GLfloat vertex[] = {
+    x, y-_height/h+_size/h, z, // bottom left
+    x, y+(float)_height/h-_height/h+_size/h, z, // top left
+    x+(float)_width/w, y-_height/h+_size/h, z, // bottom right
+    x+(float)_width/w, y+(float)_height/h-_height/h+_size/h, z, // top right
+  };
+  GLfloat texture[] = {
+    0.0f, 1.0f, // top left
+    0.0f, 0.0f, // bottom left
+    1.0f, 1.0f, // top right
+    1.0f, 0.0f, // bottom right
+  };
+  glEnable(GL_TEXTURE_2D);
+  glEnable(GL_BLEND);
+  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  glTexCoordPointer(2, GL_FLOAT, 0, texture);
+  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+  glVertexPointer(3, GL_FLOAT, 0, vertex);
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+  glDisableClientState(GL_VERTEX_ARRAY);
+  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+  glDisable(GL_BLEND);
+  glDisable(GL_TEXTURE_2D);
+  glDeleteTextures(1, &textureId);
 }
diff --git a/contrib/mobile/drawString.h b/contrib/mobile/drawString.h
index 7e14444..4a6184b 100644
--- a/contrib/mobile/drawString.h
+++ b/contrib/mobile/drawString.h
@@ -1,32 +1,26 @@
 #include <string>
 
-#if !defined(BUILD_ANDROID)
-#define BUILD_IOS 1
-#endif
-
-#if defined(BUILD_IOS)
-#include "iosGModel.h"
-#endif
-
 #if defined(BUILD_ANDROID)
 #include "androidGModel.h"
+#else
+#include "iosGModel.h"
 #endif
 
 class drawString
 {
 private:
-	std::string _text; // Text to draw
-	float _color[4]; // Text color
-	int _size; // Text size in px
-	int _height, _width, _realWidth; // Size of the texture in px
-	unsigned char *_map;
+  std::string _text; // Text to draw
+  float _color[4]; // Text color
+  int _size; // Text size in px
+  int _height, _width, _realWidth; // Size of the texture in px
+  unsigned char *_map;
 
 public:
-	drawString(std::string text, int size=12, float *color=NULL);
-	~drawString(){if(_map)free(_map);}
+  drawString(std::string text, int size=12, float *color=NULL);
+  ~drawString(){if(_map)free(_map);}
 
-	void setText(std::string text);
-	void setColor(float *color);
-	void setColor(float r, float g, float b, float a);
-	void draw(float x, float y, float z, float w, float h, bool center=true);
+  void setText(std::string text);
+  void setColor(float *color);
+  void setColor(float r, float g, float b, float a);
+  void draw(float x, float y, float z, float w, float h, bool center=true);
 };
diff --git a/contrib/mobile/iOS/Onelab.xcodeproj/project.pbxproj b/contrib/mobile/iOS/Onelab.xcodeproj/project.pbxproj
index 5927b95..3eb4164 100644
--- a/contrib/mobile/iOS/Onelab.xcodeproj/project.pbxproj
+++ b/contrib/mobile/iOS/Onelab.xcodeproj/project.pbxproj
@@ -7,17 +7,15 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		2907CCEC193DE6560011341A /* icon_onelab.png in Resources */ = {isa = PBXBuildFile; fileRef = 2907CCEB193DE6560011341A /* icon_onelab.png */; };
+		2988FF1E18E59558001435B6 /* libf2cblas.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2988FF1C18E59558001435B6 /* libf2cblas.a */; };
+		2988FF1F18E59558001435B6 /* libf2clapack.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2988FF1D18E59558001435B6 /* libf2clapack.a */; };
+		29A4AC80193CE6DA0007B5A5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 29A4AC7F193CE6DA0007B5A5 /* Images.xcassets */; };
+		9C1B9912194F4E0400507EFD /* slepc.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C1B9911194F4E0400507EFD /* slepc.framework */; };
 		9C1C10FA17BA5E7D00BFD483 /* OptionsViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C1C10F917BA5E7D00BFD483 /* OptionsViewController.mm */; };
 		9C2C3A1E187FDF9200E87F78 /* libc++.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C2C3A1D187FDF9200E87F78 /* libc++.dylib */; };
 		9C2C3A20187FDF9900E87F78 /* libstdc++.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C2C3A1F187FDF9900E87F78 /* libstdc++.dylib */; };
 		9C6A645817A7C3DB00DEDAFC /* drawString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9C6A645617A7C3DB00DEDAFC /* drawString.cpp */; };
-		9C928629180D217B00AAABD4 /* icon_app_ipad_61.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C928622180D217A00AAABD4 /* icon_app_ipad_61.png */; };
-		9C92862A180D217B00AAABD4 /* icon_app_ipad_retina_61.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C928623180D217A00AAABD4 /* icon_app_ipad_retina_61.png */; };
-		9C92862B180D217B00AAABD4 /* icon_app_ipad_retina.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C928624180D217A00AAABD4 /* icon_app_ipad_retina.png */; };
-		9C92862C180D217B00AAABD4 /* icon_app_ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C928625180D217A00AAABD4 /* icon_app_ipad.png */; };
-		9C92862D180D217B00AAABD4 /* icon_app_iphone_61.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C928626180D217A00AAABD4 /* icon_app_iphone_61.png */; };
-		9C92862E180D217B00AAABD4 /* icon_app_iphone_retina_61.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C928627180D217A00AAABD4 /* icon_app_iphone_retina_61.png */; };
-		9C92862F180D217B00AAABD4 /* icon_app_iphone_retina.png in Resources */ = {isa = PBXBuildFile; fileRef = 9C928628180D217B00AAABD4 /* icon_app_iphone_retina.png */; };
 		9C95B7F61726C88E00C0CCE2 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C95B7F51726C88E00C0CCE2 /* main.mm */; };
 		9C96083B1712C16300E1D4A0 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C96083A1712C16300E1D4A0 /* UIKit.framework */; };
 		9C96083D1712C16300E1D4A0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C96083C1712C16300E1D4A0 /* Foundation.framework */; };
@@ -26,11 +24,13 @@
 		9C9608511712C16400E1D4A0 /* ParametersViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C9608501712C16400E1D4A0 /* ParametersViewController.mm */; };
 		9C9608541712C16400E1D4A0 /* ModelViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C9608531712C16400E1D4A0 /* ModelViewController.mm */; };
 		9C9608741712C47200E1D4A0 /* EAGLView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9C9608731712C47200E1D4A0 /* EAGLView.mm */; };
-		9C9608991712C7B600E1D4A0 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C9608981712C7B600E1D4A0 /* Accelerate.framework */; };
 		9C96089B1712C7BE00E1D4A0 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C96089A1712C7BE00E1D4A0 /* OpenGLES.framework */; };
 		9C96089D1712C7F600E1D4A0 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C96089C1712C7F600E1D4A0 /* QuartzCore.framework */; };
 		9C96089F1712C8EB00E1D4A0 /* emulatorFix.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C96089E1712C8EB00E1D4A0 /* emulatorFix.c */; };
 		9C9608AC1712EF0900E1D4A0 /* iPadStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9C9608AA1712EF0900E1D4A0 /* iPadStoryboard.storyboard */; };
+		9CB1CD9818DB2D8700110882 /* icon_rotate.png in Resources */ = {isa = PBXBuildFile; fileRef = 9CB1CD9618DB2D8700110882 /* icon_rotate.png */; };
+		9CB1CD9B18DC36AC00110882 /* AboutViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9CB1CD9A18DC36AC00110882 /* AboutViewController.mm */; };
+		9CB1CD9D18DC57DE00110882 /* icon_translate.png in Resources */ = {isa = PBXBuildFile; fileRef = 9CB1CD9C18DC57DE00110882 /* icon_translate.png */; };
 		9CC6EBB717BA0A38001CA21A /* drawGeom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9CC6EBB617BA0A38001CA21A /* drawGeom.cpp */; };
 		9CC6EBB917BA1CC7001CA21A /* drawMesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9CC6EBB817BA1CC7001CA21A /* drawMesh.cpp */; };
 		9CC85C021790286C00F241C4 /* files in Resources */ = {isa = PBXBuildFile; fileRef = 9CC85C011790286C00F241C4 /* files */; };
@@ -51,20 +51,17 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
+		2907CCEB193DE6560011341A /* icon_onelab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_onelab.png; sourceTree = "<group>"; };
+		2988FF1C18E59558001435B6 /* libf2cblas.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libf2cblas.a; path = ../../frameworks_ios/libf2cblas.a; sourceTree = "<group>"; };
+		2988FF1D18E59558001435B6 /* libf2clapack.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libf2clapack.a; path = ../../frameworks_ios/libf2clapack.a; sourceTree = "<group>"; };
+		29A4AC7F193CE6DA0007B5A5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
+		9C1B9911194F4E0400507EFD /* slepc.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = slepc.framework; path = Onelab/frameworks/slepc.framework; sourceTree = "<group>"; };
 		9C1C10F817BA5E7D00BFD483 /* OptionsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OptionsViewController.h; sourceTree = "<group>"; };
 		9C1C10F917BA5E7D00BFD483 /* OptionsViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OptionsViewController.mm; sourceTree = "<group>"; };
 		9C2C3A1D187FDF9200E87F78 /* libc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libc++.dylib"; path = "usr/lib/libc++.dylib"; sourceTree = SDKROOT; };
 		9C2C3A1F187FDF9900E87F78 /* libstdc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libstdc++.dylib"; path = "usr/lib/libstdc++.dylib"; sourceTree = SDKROOT; };
 		9C6A645617A7C3DB00DEDAFC /* drawString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = drawString.cpp; sourceTree = "<group>"; usesTabs = 1; };
 		9C6A645717A7C3DB00DEDAFC /* drawString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = drawString.h; sourceTree = "<group>"; usesTabs = 1; };
-		9C928622180D217A00AAABD4 /* icon_app_ipad_61.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_app_ipad_61.png; sourceTree = "<group>"; };
-		9C928623180D217A00AAABD4 /* icon_app_ipad_retina_61.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_app_ipad_retina_61.png; sourceTree = "<group>"; };
-		9C928624180D217A00AAABD4 /* icon_app_ipad_retina.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_app_ipad_retina.png; sourceTree = "<group>"; };
-		9C928625180D217A00AAABD4 /* icon_app_ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_app_ipad.png; sourceTree = "<group>"; };
-		9C928626180D217A00AAABD4 /* icon_app_iphone_61.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_app_iphone_61.png; sourceTree = "<group>"; };
-		9C928627180D217A00AAABD4 /* icon_app_iphone_retina_61.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_app_iphone_retina_61.png; sourceTree = "<group>"; };
-		9C928628180D217B00AAABD4 /* icon_app_iphone_retina.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_app_iphone_retina.png; sourceTree = "<group>"; };
-		9C928632180D297C00AAABD4 /* Default-568h at 2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h at 2x.png"; sourceTree = "<group>"; };
 		9C95B7F51726C88E00C0CCE2 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
 		9C9608361712C16300E1D4A0 /* Onelab.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Onelab.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		9C96083A1712C16300E1D4A0 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
@@ -79,12 +76,15 @@
 		9C96085B1712C16400E1D4A0 /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
 		9C9608721712C47200E1D4A0 /* EAGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EAGLView.h; sourceTree = "<group>"; usesTabs = 1; };
 		9C9608731712C47200E1D4A0 /* EAGLView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EAGLView.mm; sourceTree = "<group>"; usesTabs = 1; };
-		9C9608981712C7B600E1D4A0 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
 		9C96089A1712C7BE00E1D4A0 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
 		9C96089C1712C7F600E1D4A0 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
 		9C96089E1712C8EB00E1D4A0 /* emulatorFix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = emulatorFix.c; sourceTree = "<group>"; usesTabs = 1; };
 		9C9608AB1712EF0900E1D4A0 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/iPadStoryboard.storyboard; sourceTree = "<group>"; };
 		9C99754C17390DEE0036EC24 /* iosGModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iosGModel.h; sourceTree = "<group>"; usesTabs = 1; };
+		9CB1CD9618DB2D8700110882 /* icon_rotate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_rotate.png; sourceTree = "<group>"; };
+		9CB1CD9918DC36AC00110882 /* AboutViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AboutViewController.h; sourceTree = "<group>"; };
+		9CB1CD9A18DC36AC00110882 /* AboutViewController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AboutViewController.mm; sourceTree = "<group>"; };
+		9CB1CD9C18DC57DE00110882 /* icon_translate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_translate.png; sourceTree = "<group>"; };
 		9CC6EBB617BA0A38001CA21A /* drawGeom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = drawGeom.cpp; sourceTree = "<group>"; usesTabs = 1; };
 		9CC6EBB817BA1CC7001CA21A /* drawMesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = drawMesh.cpp; sourceTree = "<group>"; };
 		9CC85C011790286C00F241C4 /* files */ = {isa = PBXFileReference; lastKnownFileType = folder; path = files; sourceTree = "<group>"; };
@@ -120,11 +120,12 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				2988FF1E18E59558001435B6 /* libf2cblas.a in Frameworks */,
+				2988FF1F18E59558001435B6 /* libf2clapack.a in Frameworks */,
 				9C2C3A20187FDF9900E87F78 /* libstdc++.dylib in Frameworks */,
 				9C2C3A1E187FDF9200E87F78 /* libc++.dylib in Frameworks */,
 				9C96089D1712C7F600E1D4A0 /* QuartzCore.framework in Frameworks */,
 				9C96089B1712C7BE00E1D4A0 /* OpenGLES.framework in Frameworks */,
-				9C9608991712C7B600E1D4A0 /* Accelerate.framework in Frameworks */,
 				9C96083B1712C16300E1D4A0 /* UIKit.framework in Frameworks */,
 				9C96083D1712C16300E1D4A0 /* Foundation.framework in Frameworks */,
 				9C96083F1712C16300E1D4A0 /* CoreGraphics.framework in Frameworks */,
@@ -132,6 +133,7 @@
 				9CE08E10178AEB1600A83B4B /* GetDP.framework in Frameworks */,
 				9CE08E11178AEB1600A83B4B /* Gmsh.framework in Frameworks */,
 				9CE08E12178AEB1600A83B4B /* petsc.framework in Frameworks */,
+				9C1B9912194F4E0400507EFD /* slepc.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -141,13 +143,9 @@
 		9C928621180D216500AAABD4 /* icons */ = {
 			isa = PBXGroup;
 			children = (
-				9C928622180D217A00AAABD4 /* icon_app_ipad_61.png */,
-				9C928623180D217A00AAABD4 /* icon_app_ipad_retina_61.png */,
-				9C928624180D217A00AAABD4 /* icon_app_ipad_retina.png */,
-				9C928625180D217A00AAABD4 /* icon_app_ipad.png */,
-				9C928626180D217A00AAABD4 /* icon_app_iphone_61.png */,
-				9C928627180D217A00AAABD4 /* icon_app_iphone_retina_61.png */,
-				9C928628180D217B00AAABD4 /* icon_app_iphone_retina.png */,
+				2907CCEB193DE6560011341A /* icon_onelab.png */,
+				9CB1CD9C18DC57DE00110882 /* icon_translate.png */,
+				9CB1CD9618DB2D8700110882 /* icon_rotate.png */,
 			);
 			name = icons;
 			sourceTree = "<group>";
@@ -155,7 +153,6 @@
 		9C96082B1712C16300E1D4A0 = {
 			isa = PBXGroup;
 			children = (
-				9C928632180D297C00AAABD4 /* Default-568h at 2x.png */,
 				9C9608401712C16300E1D4A0 /* Onelab */,
 				9C9608391712C16300E1D4A0 /* Frameworks */,
 				9C9608371712C16300E1D4A0 /* Products */,
@@ -173,6 +170,9 @@
 		9C9608391712C16300E1D4A0 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				9C1B9911194F4E0400507EFD /* slepc.framework */,
+				2988FF1C18E59558001435B6 /* libf2cblas.a */,
+				2988FF1D18E59558001435B6 /* libf2clapack.a */,
 				9C2C3A1F187FDF9900E87F78 /* libstdc++.dylib */,
 				9C2C3A1D187FDF9200E87F78 /* libc++.dylib */,
 				9CE2773917E197DA0076E728 /* Social.framework */,
@@ -181,7 +181,6 @@
 				9CE08E0F178AEB1600A83B4B /* petsc.framework */,
 				9C96089C1712C7F600E1D4A0 /* QuartzCore.framework */,
 				9C96089A1712C7BE00E1D4A0 /* OpenGLES.framework */,
-				9C9608981712C7B600E1D4A0 /* Accelerate.framework */,
 				9C96083A1712C16300E1D4A0 /* UIKit.framework */,
 				9C96083C1712C16300E1D4A0 /* Foundation.framework */,
 				9C96083E1712C16300E1D4A0 /* CoreGraphics.framework */,
@@ -218,6 +217,8 @@
 				9CE18C1F17B27EDB009BA06E /* Parameter.mm */,
 				9CEAECC517A91CD20014D229 /* ModelListController.h */,
 				9CEAECC617A91CD20014D229 /* ModelListController.mm */,
+				9CB1CD9918DC36AC00110882 /* AboutViewController.h */,
+				9CB1CD9A18DC36AC00110882 /* AboutViewController.mm */,
 				9CEAE87B17AFD5BB00813524 /* SplitViewController.h */,
 				9CEAE87C17AFD5BB00813524 /* SplitViewController.mm */,
 				9C96084F1712C16400E1D4A0 /* ParametersViewController.h */,
@@ -231,6 +232,7 @@
 				9C9608721712C47200E1D4A0 /* EAGLView.h */,
 				9C9608731712C47200E1D4A0 /* EAGLView.mm */,
 				9C96089E1712C8EB00E1D4A0 /* emulatorFix.c */,
+				29A4AC7F193CE6DA0007B5A5 /* Images.xcassets */,
 				9CF1C1F017AA8A46002CD2E3 /* Supporting Files */,
 			);
 			path = Onelab;
@@ -303,15 +305,12 @@
 			buildActionMask = 2147483647;
 			files = (
 				9C9608AC1712EF0900E1D4A0 /* iPadStoryboard.storyboard in Resources */,
+				9CB1CD9818DB2D8700110882 /* icon_rotate.png in Resources */,
 				9CC85C021790286C00F241C4 /* files in Resources */,
-				9C92862D180D217B00AAABD4 /* icon_app_iphone_61.png in Resources */,
-				9C92862A180D217B00AAABD4 /* icon_app_ipad_retina_61.png in Resources */,
-				9C92862F180D217B00AAABD4 /* icon_app_iphone_retina.png in Resources */,
-				9C92862C180D217B00AAABD4 /* icon_app_ipad.png in Resources */,
+				29A4AC80193CE6DA0007B5A5 /* Images.xcassets in Resources */,
+				2907CCEC193DE6560011341A /* icon_onelab.png in Resources */,
+				9CB1CD9D18DC57DE00110882 /* icon_translate.png in Resources */,
 				9CE1A65A17B0FB9700E5152F /* iPhoneiPodStoryboard.storyboard in Resources */,
-				9C928629180D217B00AAABD4 /* icon_app_ipad_61.png in Resources */,
-				9C92862B180D217B00AAABD4 /* icon_app_ipad_retina.png in Resources */,
-				9C92862E180D217B00AAABD4 /* icon_app_iphone_retina_61.png in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -328,6 +327,7 @@
 				9C9608511712C16400E1D4A0 /* ParametersViewController.mm in Sources */,
 				9C9608541712C16400E1D4A0 /* ModelViewController.mm in Sources */,
 				9C9608741712C47200E1D4A0 /* EAGLView.mm in Sources */,
+				9CB1CD9B18DC36AC00110882 /* AboutViewController.mm in Sources */,
 				9C96089F1712C8EB00E1D4A0 /* emulatorFix.c in Sources */,
 				9C95B7F61726C88E00C0CCE2 /* main.mm in Sources */,
 				9C6A645817A7C3DB00DEDAFC /* drawString.cpp in Sources */,
@@ -445,18 +445,23 @@
 		9C96086D1712C16400E1D4A0 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
-					"\"$(SRCROOT)/Onelab/frameworks\"",
+					"$(PROJECT_DIR)/Onelab/frameworks",
 				);
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PREFIX_HEADER = "Onelab/Onelab-Prefix.pch";
 				INFOPLIST_FILE = "Onelab/Onelab-Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
-				LIBRARY_SEARCH_PATHS = "$(inherited)";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Onelab/frameworks/petsc.framework",
+				);
 				OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE = "";
@@ -469,21 +474,23 @@
 		9C96086E1712C16400E1D4A0 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
-					"\"$(SRCROOT)/../../getdp-iOS\"",
-					"\"$(SRCROOT)/../../gmsh-iOS\"",
-					"\"$(SRCROOT)/../..\"",
-					"\"$(SRCROOT)/Onelab/frameworks\"",
+					"$(PROJECT_DIR)/Onelab/frameworks",
 				);
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PREFIX_HEADER = "Onelab/Onelab-Prefix.pch";
 				INFOPLIST_FILE = "Onelab/Onelab-Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
-				LIBRARY_SEARCH_PATHS = "$(inherited)";
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					"$(PROJECT_DIR)/Onelab/frameworks/petsc.framework",
+				);
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PROVISIONING_PROFILE = "";
 				TARGETED_DEVICE_FAMILY = "1,2";
diff --git a/contrib/mobile/iOS/Onelab/AboutViewController.h b/contrib/mobile/iOS/Onelab/AboutViewController.h
new file mode 100644
index 0000000..8df8225
--- /dev/null
+++ b/contrib/mobile/iOS/Onelab/AboutViewController.h
@@ -0,0 +1,7 @@
+#import <UIKit/UIKit.h>
+
+ at interface AboutViewController : UIViewController <UIWebViewDelegate>
+
+ at property (weak, nonatomic) IBOutlet UIWebView *aboutView;
+
+ at end
diff --git a/contrib/mobile/iOS/Onelab/AboutViewController.mm b/contrib/mobile/iOS/Onelab/AboutViewController.mm
new file mode 100644
index 0000000..b7d2423
--- /dev/null
+++ b/contrib/mobile/iOS/Onelab/AboutViewController.mm
@@ -0,0 +1,67 @@
+#import "AboutViewController.h"
+#import "Gmsh/GmshVersion.h"
+#import "Gmsh/GmshConfig.h"
+#import "GetDP/GetDPVersion.h"
+#import "GetDP/GetDPConfig.h"
+
+ at interface AboutViewController ()
+
+ at end
+
+ at implementation AboutViewController
+
+- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
+{
+  self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+  if (self) {
+    // Custom initialization
+  }
+  return self;
+}
+
+// this allows to open links in Safari, instead of opening them in the AboutViewController
+-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
+  if ( inType == UIWebViewNavigationTypeLinkClicked ) {
+    [[UIApplication sharedApplication] openURL:[inRequest URL]];
+    return NO;
+  }
+
+  return YES;
+}
+
+- (void)viewDidLoad
+{
+  [super viewDidLoad];
+  // Do any additional setup after loading the view.
+  self.aboutView.delegate = self;
+  self.aboutView.dataDetectorTypes = UIDataDetectorTypeNone;
+  [self.aboutView loadHTMLString:[NSString stringWithFormat:@"<html><head><style type=\"text/css\"><!--body { background-color: #FFFFFF; color: #252525; margin: 35px 10px 35px 10px; padding: 0; font-family: helvetica-neue,sans-serif; font-size: 1em; }--></style></head><body><center><p><!--img width=32 src=\"icon_onelab.png\"--></p><h3>Onelab/Mobile</h3>Version %@<p>Copyright (C) 2014 Christophe Geuzaine and Maxime Graulich, University of Liège</p><p>Visit <a href=\"http://onelab.i [...]
+                                           [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"],
+                                           GMSH_VERSION,
+                                           GMSH_DATE,
+                                           GMSH_CONFIG_OPTIONS,
+                                           GETDP_VERSION,
+                                           GETDP_DATE,
+                                           GETDP_CONFIG_OPTIONS]
+                         baseURL:[[NSBundle mainBundle] bundleURL]];
+
+}
+
+- (void)didReceiveMemoryWarning
+{
+  [super didReceiveMemoryWarning];
+  // Dispose of any resources that can be recreated.
+}
+
+/*
+  #pragma mark - Navigation
+
+// In a storyboard-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
+{
+    // Get the new view controller using [segue destinationViewController].
+    // Pass the selected object to the new view controller.
+}
+*/
+
+ at end
diff --git a/contrib/mobile/iOS/Onelab/AppDelegate.h b/contrib/mobile/iOS/Onelab/AppDelegate.h
index 2fd35b8..5704554 100644
--- a/contrib/mobile/iOS/Onelab/AppDelegate.h
+++ b/contrib/mobile/iOS/Onelab/AppDelegate.h
@@ -1,11 +1,3 @@
-//
-//  AppDelegate.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 08/04/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <UIKit/UIKit.h>
 
 #include "SplitViewController.h"
diff --git a/contrib/mobile/iOS/Onelab/AppDelegate.mm b/contrib/mobile/iOS/Onelab/AppDelegate.mm
index 863f1df..64579b9 100644
--- a/contrib/mobile/iOS/Onelab/AppDelegate.mm
+++ b/contrib/mobile/iOS/Onelab/AppDelegate.mm
@@ -1,59 +1,79 @@
-//
-//  AppDelegate.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 08/04/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import "AppDelegate.h"
 #import "ModelListController.h"
+#import "Utils.h"
 
 @implementation AppDelegate
 
 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
-    // Override point for customization after application launch.
-    self.modelListController = (ModelListController *)self.window.rootViewController;
-    if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]) {
-        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"iPadStoryboard" bundle:nil];
-        self.splitViewController = [storyboard instantiateViewControllerWithIdentifier:@"SplitViewController"];
-    }
-    compute = false;
-    return YES;
+  // Override point for customization after application launch.
+  self.modelListController = (ModelListController *)self.window.rootViewController;
+  if([[UIDevice currentDevice].model isEqualToString:@"iPad"] ||
+     [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]) {
+    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"iPadStoryboard" bundle:nil];
+    self.splitViewController = [storyboard instantiateViewControllerWithIdentifier:@"SplitViewController"];
+  }
+  compute = false;
+
+  // Copy resource files if the version of the app has changed
+  NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
+  NSString *prefsv = [prefs stringForKey:@"OnelabModelsVersion"];
+  NSString *bundlev = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
+  if (!prefsv || ![prefsv isEqualToString:bundlev]) {
+    NSLog(@"Updating models to version %@", bundlev);
+    [prefs setObject:bundlev forKey:@"OnelabModelsVersion"];
+    [prefs synchronize];
+    [Utils copyRes];
+  }
+  else{
+    NSLog(@"Leaving models as-is (version %@)", prefsv);
+  }
+  return YES;
 }
-							
+
 - (void)applicationWillResignActive:(UIApplication *)application
 {
-    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
-    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
+  // Sent when the application is about to move from active to inactive
+  // state. This can occur for certain types of temporary interruptions (such as
+  // an incoming phone call or SMS message) or when the user quits the
+  // application and it begins the transition to the background state.  Use this
+  // method to pause ongoing tasks, disable timers, and throttle down OpenGL ES
+  // frame rates. Games should use this method to pause the game.
 }
 
 - (void)applicationDidEnterBackground:(UIApplication *)application
 {
-    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
-    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+  // Use this method to release shared resources, save user data, invalidate
+  // timers, and store enough application state information to restore your
+  // application to its current state in case it is terminated later.  If your
+  // application supports background execution, this method is called instead
+  // of applicationWillTerminate: when the user quits.
 }
 
 - (void)applicationWillEnterForeground:(UIApplication *)application
 {
-    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+  // Called as part of the transition from the background to the inactive state;
+  // here you can undo many of the changes made on entering the background.
 }
 
 - (void)applicationDidBecomeActive:(UIApplication *)application
 {
-    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+  // Restart any tasks that were paused (or not yet started) while the
+  // application was inactive. If the application was previously in the
+  // background, optionally refresh the user interface.
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
 
 - (void)applicationWillTerminate:(UIApplication *)application
 {
-    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+  // Called when the application is about to terminate. Save data if
+  // appropriate. See also applicationDidEnterBackground:.
 }
 
 -(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
 {
-	application.applicationIconBadgeNumber = -1;
-	[UIApplication sharedApplication].applicationIconBadgeNumber = -1;
+  application.applicationIconBadgeNumber = -1;
+  [UIApplication sharedApplication].applicationIconBadgeNumber = -1;
 }
 
 @end
diff --git a/contrib/mobile/iOS/Onelab/EAGLView.h b/contrib/mobile/iOS/Onelab/EAGLView.h
index caa7c1e..5405143 100644
--- a/contrib/mobile/iOS/Onelab/EAGLView.h
+++ b/contrib/mobile/iOS/Onelab/EAGLView.h
@@ -29,6 +29,7 @@
 @public
 	/* our GModel drawing class */
     drawContext *mContext;
+	BOOL rotate;
 }
 
 - (void)drawView;
diff --git a/contrib/mobile/iOS/Onelab/EAGLView.mm b/contrib/mobile/iOS/Onelab/EAGLView.mm
index 8e80868..ac831bf 100644
--- a/contrib/mobile/iOS/Onelab/EAGLView.mm
+++ b/contrib/mobile/iOS/Onelab/EAGLView.mm
@@ -22,164 +22,171 @@
 // You must implement this
 + (Class)layerClass
 {
-    return [CAEAGLLayer class];
+  return [CAEAGLLayer class];
 }
 
 //The GL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:
 - (id)initWithCoder:(NSCoder*)coder
 {
-    if ((self = [super initWithCoder:coder])) {
-        // Get the layer
-        CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
-        eaglLayer.opaque = YES;
-        eaglLayer.drawableProperties =
-			[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],
-			 kEAGLDrawablePropertyRetainedBacking,
-			 kEAGLColorFormatRGBA8,
-			 kEAGLDrawablePropertyColorFormat, nil];
-        context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
-        if (!context || ![EAGLContext setCurrentContext:context]) {
-            //[self release];
-            return nil;
-        }
-        mContext = new drawContext();
+  if ((self = [super initWithCoder:coder])) {
+    // Get the layer
+    CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
+    int w = 320;
+    int h = 480;
+    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2f) {
+      // There is no retina display above 3.2
+      UIScreen* mainscr = [UIScreen mainScreen];
+      w = mainscr.currentMode.size.width;
+      h = mainscr.currentMode.size.height;
     }
-    rendering = NO;
-    return self;
+    if ((w == 640 && h == 960) ||
+        (h == 1136 && w == 640) ||
+        (h == 1536 && w == 2048)) {
+      // Retina display (iPhone or iPhone 4-inch or iPad/iPad mini)
+      self.contentScaleFactor = 2.0;
+      eaglLayer.contentsScale=2;
+    }
+    eaglLayer.opaque = YES;
+    eaglLayer.drawableProperties =
+      [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],
+                    kEAGLDrawablePropertyRetainedBacking,
+                    kEAGLColorFormatRGBA8,
+                    kEAGLDrawablePropertyColorFormat, nil];
+    context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
+    if (!context || ![EAGLContext setCurrentContext:context]) {
+      //[self release];
+      return nil;
+    }
+    mContext = new drawContext((eaglLayer.contentsScale==2) ? 1.5 : 1,
+                               eaglLayer.contentsScale==2);
+  }
+  rendering = NO;
+  return self;
 }
 
 - (void)drawView
 {
-    if(rendering) return;
-    rendering = YES;
-    [EAGLContext setCurrentContext:context];
-    
-    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
-    mContext->initView(backingWidth, backingHeight);
-    mContext->drawView();
-    
-    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
-    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
-    rendering = NO;
+  if(rendering) return;
+  rendering = YES;
+  [EAGLContext setCurrentContext:context];
+
+  glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
+  mContext->initView(backingWidth, backingHeight);
+  mContext->drawView();
+
+  glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
+  [context presentRenderbuffer:GL_RENDERBUFFER_OES];
+  rendering = NO;
 }
+
 - (void)load:(NSString*) file
 {
-    mContext->load(*new std::string([file fileSystemRepresentation]));
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"resetParameters" object:nil];
-    [self drawView];
+  mContext->load(*new std::string([file fileSystemRepresentation]));
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"resetParameters" object:nil];
+  [self drawView];
 }
+
 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
 {
-    NSUInteger ntouch = [[event allTouches] count];
-    UITouch* touch = [touches anyObject];
-    CGPoint position = [touch locationInView:self];
-    switch(ntouch)
-    {
-        case 1:
-        {
-            mContext->eventHandler(1,position.x,position.y);
-        }
-            break;
-        case 3:
-        {
-            mContext->eventHandler(3,position.x,position.y);
-        }
-            break;
-        default:
-            return ;
-    }
-    
-    [self drawView];
+  NSUInteger ntouch = [[event allTouches] count];
+  UITouch* touch = [touches anyObject];
+  CGPoint position = [touch locationInView:self];
+  if(ntouch != 1) return;
+  if(rotate)
+    mContext->eventHandler(3,position.x,position.y);
+  else
+    mContext->eventHandler(1,position.x,position.y);
+
+  [self drawView];
 }
 
 - (void)layoutSubviews
 {
-	[super layoutSubviews];
-    [EAGLContext setCurrentContext:context];
-    [self destroyFramebuffer];
-    [self createFramebuffer];
-    [self drawView];
+  [super layoutSubviews];
+  [EAGLContext setCurrentContext:context];
+  [self destroyFramebuffer];
+  [self createFramebuffer];
+  [self drawView];
 }
 
 - (BOOL)createFramebuffer
 {
-    glGenFramebuffersOES(1, &viewFramebuffer);
-    glGenRenderbuffersOES(1, &viewRenderbuffer);
-	
-    glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
-    glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
-    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
-    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
-    
-    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
-    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
-    
-    if (USE_DEPTH_BUFFER) {
-        glGenRenderbuffersOES(1, &depthRenderbuffer);
-        glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
-        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
-        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
-    }
-    
-    if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
-        NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
-        return NO;
-    }
-    
-    return YES;
+  glGenFramebuffersOES(1, &viewFramebuffer);
+  glGenRenderbuffersOES(1, &viewRenderbuffer);
+
+  glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
+  glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
+  [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
+  glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
+
+  glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
+  glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
+
+  if (USE_DEPTH_BUFFER) {
+    glGenRenderbuffersOES(1, &depthRenderbuffer);
+    glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
+    glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
+    glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
+  }
+
+  if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
+    NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
+    return NO;
+  }
+
+  return YES;
 }
 
 - (void)destroyFramebuffer
 {
-    glDeleteFramebuffersOES(1, &viewFramebuffer);
-    viewFramebuffer = 0;
-    glDeleteRenderbuffersOES(1, &viewRenderbuffer);
-    viewRenderbuffer = 0;
-    if(depthRenderbuffer) {
-        glDeleteRenderbuffersOES(1, &depthRenderbuffer);
-        depthRenderbuffer = 0;
-    }
+  glDeleteFramebuffersOES(1, &viewFramebuffer);
+  viewFramebuffer = 0;
+  glDeleteRenderbuffersOES(1, &viewRenderbuffer);
+  viewRenderbuffer = 0;
+  if(depthRenderbuffer) {
+    glDeleteRenderbuffersOES(1, &depthRenderbuffer);
+    depthRenderbuffer = 0;
+  }
 }
 
 - (void)dealloc
 {
-    if ([EAGLContext currentContext] == context) {
-        [EAGLContext setCurrentContext:nil];
-    }
+  if ([EAGLContext currentContext] == context) {
+    [EAGLContext setCurrentContext:nil];
+  }
 }
 
 - (UIImage*) getGLScreenshot
 {
-    NSInteger myDataLength = backingWidth * backingHeight * 4;
-
-    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
-    glReadPixels(0, 0, backingWidth, backingHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
-
-    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
-    for(int y = 0; y <backingHeight; y++)
-    {
-        for(int x = 0; x <backingWidth * 4; x++)
-        {
-            buffer2[(backingHeight - 1 - y) * backingWidth * 4 + x] = buffer[y * 4 * backingWidth + x];
-        }
-    }
+  NSInteger myDataLength = backingWidth * backingHeight * 4;
+
+  GLubyte *buffer = (GLubyte *) malloc(myDataLength);
+  glReadPixels(0, 0, backingWidth, backingHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
 
-    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
+  GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
+  for(int y = 0; y <backingHeight; y++){
+    for(int x = 0; x <backingWidth * 4; x++){
+      buffer2[(backingHeight - 1 - y) * backingWidth * 4 + x] = buffer[y * 4 * backingWidth + x];
+    }
+  }
 
-    int bitsPerComponent = 8;
-    int bitsPerPixel = 32;
-    int bytesPerRow = 4 * backingWidth;
-    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
-    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
-    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
+  CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
 
-    CGImageRef imageRef = CGImageCreate(backingWidth, backingHeight, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
+  int bitsPerComponent = 8;
+  int bitsPerPixel = 32;
+  int bytesPerRow = 4 * backingWidth;
+  CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
+  CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
+  CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
 
-    return [UIImage imageWithCGImage:imageRef];
+  CGImageRef imageRef = CGImageCreate(backingWidth, backingHeight, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
+  free(buffer);
+  free(buffer2);
+  return [UIImage imageWithCGImage:imageRef];
 }
 
 - (void)saveGLScreenshotToPhotosAlbum {
-    UIImageWriteToSavedPhotosAlbum([self getGLScreenshot], nil, nil, nil);
+  UIImageWriteToSavedPhotosAlbum([self getGLScreenshot], nil, nil, nil);
 }
 
 @end
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/Contents.json b/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..07ee4c7
--- /dev/null
+++ b/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,56 @@
+{
+  "images" : [
+    {
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "40x40"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "icon_app_iphone_retina.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "icon_app_ipad.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "icon_app_ipad_retina.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "1x",
+      "size" : "40x40"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "2x",
+      "size" : "40x40"
+    },
+    {
+      "idiom" : "iphone",
+      "scale" : "2x",
+      "size" : "29x29"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "1x",
+      "size" : "29x29"
+    },
+    {
+      "idiom" : "ipad",
+      "scale" : "2x",
+      "size" : "29x29"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/icon_app_ipad.png b/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/icon_app_ipad.png
new file mode 100644
index 0000000..001965f
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/icon_app_ipad.png differ
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/icon_app_ipad_retina.png b/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/icon_app_ipad_retina.png
new file mode 100644
index 0000000..be1e688
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/icon_app_ipad_retina.png differ
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/icon_app_iphone_retina.png b/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/icon_app_iphone_retina.png
new file mode 100644
index 0000000..fcaa30c
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/Images.xcassets/AppIcon.appiconset/icon_app_iphone_retina.png differ
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/Contents.json b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 0000000..ee3a5d7
--- /dev/null
+++ b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,57 @@
+{
+  "images" : [
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "filename" : "splash640x960.png",
+      "scale" : "2x"
+    },
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "retina4",
+      "filename" : "splash640x1136.png",
+      "minimum-system-version" : "7.0",
+      "orientation" : "portrait",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "filename" : "splash768x1024.png",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "filename" : "splash1024x768.png",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "filename" : "splash1536x2048.png",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "filename" : "splash2048x1536.png",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash1024x768.png b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash1024x768.png
new file mode 100644
index 0000000..db10645
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash1024x768.png differ
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash1536x2048.png b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash1536x2048.png
new file mode 100644
index 0000000..dd8883d
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash1536x2048.png differ
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash2048x1536.png b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash2048x1536.png
new file mode 100644
index 0000000..5399755
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash2048x1536.png differ
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash640x1136.png b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash640x1136.png
new file mode 100644
index 0000000..95693f0
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash640x1136.png differ
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash640x960.png b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash640x960.png
new file mode 100644
index 0000000..30e417d
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash640x960.png differ
diff --git a/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash768x1024.png b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash768x1024.png
new file mode 100644
index 0000000..48150da
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/Images.xcassets/LaunchImage.launchimage/splash768x1024.png differ
diff --git a/contrib/mobile/iOS/Onelab/Model.h b/contrib/mobile/iOS/Onelab/Model.h
index 6737052..101e430 100644
--- a/contrib/mobile/iOS/Onelab/Model.h
+++ b/contrib/mobile/iOS/Onelab/Model.h
@@ -1,11 +1,3 @@
-//
-//  Model.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 03/09/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <Foundation/Foundation.h>
 
 @interface Model : NSObject
diff --git a/contrib/mobile/iOS/Onelab/Model.mm b/contrib/mobile/iOS/Onelab/Model.mm
index 74f1c85..c34b3a8 100644
--- a/contrib/mobile/iOS/Onelab/Model.mm
+++ b/contrib/mobile/iOS/Onelab/Model.mm
@@ -1,66 +1,76 @@
-//
-//  Model.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 03/09/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import "Model.h"
 
 @implementation Model
 
--(id) initWithName:(NSString *)name {
-    self = [super init];
-    if(self) {
-        _name = name;
-        _summary = nil;
-        _file = nil;
-        _url = nil;
-        _preview = nil;
-    }
-    return self;
+-(id) initWithName:(NSString *)name
+{
+  self = [super init];
+  if(self) {
+    _name = name;
+    _summary = nil;
+    _file = nil;
+    _url = nil;
+    _preview = nil;
+  }
+  return self;
 }
 
--(id) initWithName:(NSString *)name withSummary:(NSString *)summary withFile:(NSString *)file {
-    self = [super init];
-    if(self) {
-        _name = name;
-        _summary = summary;
-        _file = file;
-        _url = nil;
-        _preview = nil;
-    }
-    return self;
+-(id) initWithName:(NSString *)name withSummary:(NSString *)summary withFile:(NSString *)file
+{
+  self = [super init];
+  if(self) {
+    _name = name;
+    _summary = summary;
+    _file = file;
+    _url = nil;
+    _preview = nil;
+  }
+  return self;
 }
 
--(NSString *) getName {
-    return _name;
-}
--(NSString *) getSummary {
-    return _summary;
+-(NSString *) getName
+{
+  return _name;
 }
--(NSString *) getFile {
-    return _file;
+
+-(NSString *) getSummary
+{
+  return _summary;
 }
--(NSURL *) getUrl {
-    return _url;
+
+-(NSString *) getFile
+{
+  return _file;
 }
--(UIImage *) getPreview {
-    return _preview;
+
+-(NSURL *) getUrl
+{
+  return _url;
 }
--(void) setSummary:(NSString *)summary {
-    _summary = summary;
+
+-(UIImage *) getPreview
+{
+  return _preview;
 }
--(void) setFile:(NSString *)file {
-    _file = file;
+
+-(void) setSummary:(NSString *)summary
+{
+  _summary = summary;
 }
--(void) setPreview:(NSString *)path {
-    _preview = [UIImage imageWithContentsOfFile:path];
+
+-(void) setFile:(NSString *)file
+{
+  _file = file;
 }
--(void) setUrl:(NSString *)url {
-    _url = [NSURL URLWithString:url];
+
+-(void) setPreview:(NSString *)path
+{
+  _preview = [UIImage imageWithContentsOfFile:path];
 }
 
+-(void) setUrl:(NSString *)url
+{
+  _url = [NSURL URLWithString:url];
+}
 
 @end
diff --git a/contrib/mobile/iOS/Onelab/ModelListController.h b/contrib/mobile/iOS/Onelab/ModelListController.h
index 003dd59..fea68ab 100644
--- a/contrib/mobile/iOS/Onelab/ModelListController.h
+++ b/contrib/mobile/iOS/Onelab/ModelListController.h
@@ -1,11 +1,3 @@
-//
-//  ModelListController.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 31/07/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <UIKit/UIKit.h>
 
 #import "EAGLView.h"
diff --git a/contrib/mobile/iOS/Onelab/ModelListController.mm b/contrib/mobile/iOS/Onelab/ModelListController.mm
index a96ccc8..186217b 100644
--- a/contrib/mobile/iOS/Onelab/ModelListController.mm
+++ b/contrib/mobile/iOS/Onelab/ModelListController.mm
@@ -1,11 +1,3 @@
-//
-//  ModelListController.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 31/07/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import "AppDelegate.h"
 #import "ModelListController.h"
 
@@ -15,193 +7,213 @@
 @implementation ModelListController
 -(void)viewDidLoad
 {
-	UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
-	[refreshControl addTarget:self action:@selector(refreshList) forControlEvents:UIControlEventValueChanged];
-	self.refreshControl = refreshControl;
-	
-	UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
-	lpgr.minimumPressDuration = 1.0;
-	[self.tableView addGestureRecognizer:lpgr];
-	
-    models = [[NSMutableArray alloc] init];
-    NSString *docsPath = [Utils getApplicationDocumentsDirectory];
-    [Utils copyRes];
-    NSArray *docs = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsPath error:NULL];
-    for(NSString* doc in docs) {
-        NSString *docPath = [NSString stringWithFormat:@"%@/%@/", docsPath, doc];
-        BOOL isDir = NO; [[NSFileManager defaultManager] fileExistsAtPath:docPath isDirectory:&isDir];
-        if(isDir){
-            NSString *infos = [NSString stringWithFormat:@"%@%@", docPath, @"infos.xml"];
-            if([[NSFileManager defaultManager] fileExistsAtPath:infos]) {
-				currentDir = docPath;
-                [self parseInfosFile:infos];
-            }
-        }
+  UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
+  [refreshControl addTarget:self action:@selector(refreshList) forControlEvents:UIControlEventValueChanged];
+  self.refreshControl = refreshControl;
+
+  UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
+  lpgr.minimumPressDuration = 1.0;
+  [self.tableView addGestureRecognizer:lpgr];
+
+  models = [[NSMutableArray alloc] init];
+  NSString *docsPath = [Utils getApplicationDocumentsDirectory];
+  NSArray *docs = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsPath error:NULL];
+  for(NSString* doc in docs) {
+    NSString *docPath = [NSString stringWithFormat:@"%@/%@/", docsPath, doc];
+    BOOL isDir = NO; [[NSFileManager defaultManager] fileExistsAtPath:docPath isDirectory:&isDir];
+    if(isDir){
+      NSString *infos = [NSString stringWithFormat:@"%@%@", docPath, @"infos.xml"];
+      if([[NSFileManager defaultManager] fileExistsAtPath:infos]) {
+        currentDir = docPath;
+        [self parseInfosFile:infos];
+      }
     }
+  }
+
+  UIBarButtonItem *about = [[UIBarButtonItem alloc] initWithTitle:@"About" style:UIBarButtonItemStyleBordered target:self action:@selector(showAbout)];
+  [self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects: about, nil]];
+}
+
+-(void)showAbout
+{
+  [self performSegueWithIdentifier:@"showAboutSegue" sender:self];
 }
 
 -(void)refreshList
 {
-	NSString *docsPath = [Utils getApplicationDocumentsDirectory];
-	NSArray *docs = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsPath error:NULL];
-    for(NSString* doc in docs) {
-		NSString *docPath = [NSString stringWithFormat:@"%@/%@/", docsPath, doc];
-        BOOL isDir = NO; [[NSFileManager defaultManager] fileExistsAtPath:docPath isDirectory:&isDir];
-        if(isDir){
-			NSString *infos = [NSString stringWithFormat:@"%@%@", docPath, @"infos.xml"];
-            if([[NSFileManager defaultManager] fileExistsAtPath:infos]) {
-				currentDir = docPath;
-                [self parseInfosFile:infos];
-            }
-		}
-	}
-	[self.tableView reloadData];
-	[self.refreshControl endRefreshing];
+  NSString *docsPath = [Utils getApplicationDocumentsDirectory];
+  NSArray *docs = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:docsPath error:NULL];
+  for(NSString* doc in docs) {
+    NSString *docPath = [NSString stringWithFormat:@"%@/%@/", docsPath, doc];
+    BOOL isDir = NO; [[NSFileManager defaultManager] fileExistsAtPath:docPath isDirectory:&isDir];
+    if(isDir){
+      NSString *infos = [NSString stringWithFormat:@"%@%@", docPath, @"infos.xml"];
+      if([[NSFileManager defaultManager] fileExistsAtPath:infos]) {
+        currentDir = docPath;
+        [self parseInfosFile:infos];
+      }
+    }
+  }
+  for (int i=0;i<[models count]; i++) {
+    if(![[NSFileManager defaultManager] fileExistsAtPath:[models[i] getFile]]) {
+      [models removeObject:models[i]];
+      i--;
+    }
+  }
+  [self.tableView reloadData];
+  [self.refreshControl endRefreshing];
 }
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 {
-    return 1;
+  return 1;
 }
 
 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
-    return [models count];
+  return [models count];
 }
 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    UITableViewCell *cell;
-    if(indexPath.row >= [models count])
-        return cell;
-    Model *m = [models objectAtIndex:indexPath.row];
-    cell = [tableView dequeueReusableCellWithIdentifier:[m getName]];
-    if(cell != nil) return cell;
-    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:[m getName]];
-    [cell.textLabel setText:[m getName]];
-    if([m getSummary] != nil) [cell.detailTextLabel setText:[m getSummary]];
-	if([m getPreview] != nil) cell.imageView.image = [m getPreview];
-	if([m getFile] == nil) {
-		cell.selectionStyle = UITableViewCellSelectionStyleNone;
-		cell.userInteractionEnabled = NO;
-		cell.textLabel.alpha = 0.75;
-	}
-    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+  UITableViewCell *cell;
+  if(indexPath.row >= [models count])
     return cell;
+  Model *m = [models objectAtIndex:indexPath.row];
+  cell = [tableView dequeueReusableCellWithIdentifier:[m getName]];
+  if(cell != nil) return cell;
+  cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:[m getName]];
+  [cell.textLabel setText:[m getName]];
+  if([m getSummary] != nil) [cell.detailTextLabel setText:[m getSummary]];
+  if([m getPreview] != nil) cell.imageView.image = [m getPreview];
+  if([m getFile] == nil) {
+    cell.selectionStyle = UITableViewCellSelectionStyleNone;
+    cell.userInteractionEnabled = NO;
+    cell.textLabel.alpha = 0.75;
+  }
+  cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+  return cell;
 }
+
 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
 {
-    return @"Select a model";
+  return @"Select a model";
 }
+
 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-    selectedModel = [[models objectAtIndex:indexPath.row] getFile];
-    if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]){
-        appDelegate.splitViewController.initialModel = selectedModel;
-        [UIView transitionWithView:appDelegate.window
-                          duration:0.5
-                           options:UIViewAnimationOptionTransitionFlipFromLeft
-                        animations:^{ appDelegate.window.rootViewController = appDelegate.splitViewController; }
-                        completion:nil];
-    }
-    else
+  AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
+  selectedModel = [[models objectAtIndex:indexPath.row] getFile];
+  if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]){
+    appDelegate.splitViewController.initialModel = selectedModel;
+    [UIView transitionWithView:appDelegate.window
+                      duration:0.5
+                       options:UIViewAnimationOptionTransitionFlipFromLeft
+                    animations:^{ appDelegate.window.rootViewController = appDelegate.splitViewController; }
+    completion:nil];
+  }
+  else
     {
-        [self performSegueWithIdentifier:@"showModelSegue" sender:self];
+      [self performSegueWithIdentifier:@"showModelSegue" sender:self];
     }
 }
+
 -(void)handleLongPress:(UILongPressGestureRecognizer *)sender
 {
-	CGPoint p = [sender locationInView:self.tableView];
-	if(sender.state == UIGestureRecognizerStateCancelled) return;
-    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
-	if(indexPath == nil) return;
-	UIActionSheet *actionSheet;
-	if([[models objectAtIndex:indexPath.row] getUrl])
-	actionSheet = [[UIActionSheet alloc] initWithTitle:[[models objectAtIndex:indexPath.row] getName] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles: @"Open this models", @"More information", nil];
-	else
-		actionSheet = [[UIActionSheet alloc] initWithTitle:[[models objectAtIndex:indexPath.row] getName] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles: @"Open this models", nil];
-	actionSheet.tag = indexPath.row;
-    [actionSheet showInView:self.view];
+  CGPoint p = [sender locationInView:self.tableView];
+  if(sender.state == UIGestureRecognizerStateCancelled) return;
+  NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
+  if(indexPath == nil) return;
+  UIActionSheet *actionSheet;
+  if([[models objectAtIndex:indexPath.row] getUrl])
+    actionSheet = [[UIActionSheet alloc] initWithTitle:[[models objectAtIndex:indexPath.row] getName] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles: @"Open this model", @"More information", nil];
+  else
+    actionSheet = [[UIActionSheet alloc] initWithTitle:[[models objectAtIndex:indexPath.row] getName] delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles: @"Open this model", nil];
+  actionSheet.tag = indexPath.row;
+  [actionSheet showInView:self.view];
 }
--(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
-	switch (buttonIndex) {
-		case 1:
-			[[UIApplication sharedApplication] openURL:[[models objectAtIndex:actionSheet.tag] getUrl]];
-			break;
-		case 0:
-			[self tableView:self.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:actionSheet.tag inSection:0]];
-			break;
-	}
+
+-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
+{
+  switch (buttonIndex) {
+  case 1:
+    [[UIApplication sharedApplication] openURL:[[models objectAtIndex:actionSheet.tag] getUrl]];
+    break;
+  case 0:
+    [self tableView:self.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:actionSheet.tag inSection:0]];
+    break;
+  }
 }
 
 - (BOOL) parseInfosFile:(NSString *)file
 {
-    NSData *xmlFile = [[NSFileManager defaultManager] contentsAtPath:file];
-    NSXMLParser *parser;
-    parser = [[NSXMLParser alloc] initWithData:xmlFile];
-    [parser setDelegate:self];
-
-    [parser setShouldProcessNamespaces:NO];
-    [parser setShouldReportNamespacePrefixes:NO];
-    [parser setShouldResolveExternalEntities:NO];
-    
-    return [parser parse];
+  NSData *xmlFile = [[NSFileManager defaultManager] contentsAtPath:file];
+  NSXMLParser *parser;
+  parser = [[NSXMLParser alloc] initWithData:xmlFile];
+  [parser setDelegate:self];
+
+  [parser setShouldProcessNamespaces:NO];
+  [parser setShouldReportNamespacePrefixes:NO];
+  [parser setShouldResolveExternalEntities:NO];
+
+  return [parser parse];
 }
+
 -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
 {
-    currentElement = elementName;
-	//[currentElementValue release];
-    currentElementValue = nil;
+  currentElement = elementName;
+  //[currentElementValue release];
+  currentElementValue = nil;
 }
+
 -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
 {
-    if (!currentElementValue)
-        currentElementValue = [[NSMutableString alloc] initWithString:string];
-    else
-        [currentElementValue appendString:string];
+  if (!currentElementValue)
+    currentElementValue = [[NSMutableString alloc] initWithString:string];
+  else
+    [currentElementValue appendString:string];
 }
+
 -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
 {
-    if([elementName isEqual:@"title"]) {
-		for(Model *mp in models) {
-			if([[mp getName] isEqual:currentElementValue]){
-				[parser abortParsing];
-				return;
-			}
-		}
-		Model *m = [[Model alloc] initWithName:currentElementValue];
-		[models addObject:m];
-	}
-	else {
-		if(models.count < 1) return;
-		if([elementName isEqual:@"summary"]) {
-			Model *m = [models lastObject];
-			[m setSummary:currentElementValue];
-		}
-		else if([elementName isEqual:@"file"]) {
-			Model *m = [models lastObject];
-			[m setFile:[NSString stringWithFormat:@"%@%@", currentDir, currentElementValue]];
-		}
-		else if([elementName isEqual:@"url"]) {
-			Model *m = [models lastObject];
-			[m setUrl:currentElementValue];
-		}
-		else if([elementName isEqual:@"preview"]) {
-			Model *m = [models lastObject];
-			[m setPreview:[NSString stringWithFormat:@"%@%@", currentDir, currentElementValue]];
-		}
-
-	}
-    //[currentElementValue release];
-    currentElementValue = nil;
+  if([elementName isEqual:@"title"]) {
+    for(Model *mp in models) {
+      if([[mp getName] isEqual:currentElementValue]){
+        [parser abortParsing];
+        return;
+      }
+    }
+    Model *m = [[Model alloc] initWithName:currentElementValue];
+    [models addObject:m];
+  }
+  else {
+    if(models.count < 1) return;
+    if([elementName isEqual:@"summary"]) {
+      Model *m = [models lastObject];
+      [m setSummary:currentElementValue];
+    }
+    else if([elementName isEqual:@"file"]) {
+      Model *m = [models lastObject];
+      [m setFile:[NSString stringWithFormat:@"%@%@", currentDir, currentElementValue]];
+    }
+    else if([elementName isEqual:@"url"]) {
+      Model *m = [models lastObject];
+      [m setUrl:currentElementValue];
+    }
+    else if([elementName isEqual:@"preview"]) {
+      Model *m = [models lastObject];
+      [m setPreview:[NSString stringWithFormat:@"%@%@", currentDir, currentElementValue]];
+    }
+
+  }
+  //[currentElementValue release];
+  currentElementValue = nil;
 }
 
 -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
 {
-    if ([[segue identifier] isEqualToString:@"showModelSegue"])
-    {
-        ModelViewController *modelViewController = [segue destinationViewController];
-        modelViewController.initialModel = selectedModel;
-    }
+  if ([[segue identifier] isEqualToString:@"showModelSegue"]) {
+    ModelViewController *modelViewController = [segue destinationViewController];
+    modelViewController.initialModel = selectedModel;
+  }
 }
 @end
diff --git a/contrib/mobile/iOS/Onelab/ModelViewController.h b/contrib/mobile/iOS/Onelab/ModelViewController.h
index 9c5d307..9605d32 100644
--- a/contrib/mobile/iOS/Onelab/ModelViewController.h
+++ b/contrib/mobile/iOS/Onelab/ModelViewController.h
@@ -1,15 +1,6 @@
-//
-//  DetailViewController.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 08/04/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <UIKit/UIKit.h>
 #import "EAGLView.h"
 
-
 @interface UIErrorAlertView : UIAlertView
 
 @end
@@ -41,4 +32,6 @@
 
 @property (nonatomic, retain) NSString *initialModel;
 
+- (IBAction)startRotation:(UIButton *)sender;
+
 @end
diff --git a/contrib/mobile/iOS/Onelab/ModelViewController.mm b/contrib/mobile/iOS/Onelab/ModelViewController.mm
index bcd1471..7afc0bb 100644
--- a/contrib/mobile/iOS/Onelab/ModelViewController.mm
+++ b/contrib/mobile/iOS/Onelab/ModelViewController.mm
@@ -1,10 +1,3 @@
-//
-//  DetailViewController.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 08/04/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
 #import <QuartzCore/QuartzCore.h>
 #import <Social/Social.h>
 
@@ -20,7 +13,7 @@
 
 -(void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
 {
-	if(buttonIndex == 0) [super dismissWithClickedButtonIndex:buttonIndex animated:animated];
+  if(buttonIndex == 0) [super dismissWithClickedButtonIndex:buttonIndex animated:animated];
 }
 @end
 
@@ -36,367 +29,401 @@
 
 - (void)setDetailItem:(id)newDetailItem
 {
-    if (_detailItem != newDetailItem) {
-        _detailItem = newDetailItem;
-        // Update the view.
-        [self configureView];
-    }
+  if (_detailItem != newDetailItem) {
+    _detailItem = newDetailItem;
+    // Update the view.
+    [self configureView];
+  }
 
-    if (self.masterPopoverController != nil) {
-        [self.masterPopoverController dismissPopoverAnimated:YES];
-    }        
+  if (self.masterPopoverController != nil) {
+    [self.masterPopoverController dismissPopoverAnimated:YES];
+  }
 }
 
 - (void)configureView
 {
-    // Update the user interface for the detail item.
-    if (self.detailItem) {
-        self.detailDescriptionLabel.text = [self.detailItem description];
-    }
+  // Update the user interface for the detail item.
+  if (self.detailItem) {
+    self.detailDescriptionLabel.text = [self.detailItem description];
+  }
 }
 
 -(void)viewWillAppear:(BOOL)animated
 {
-	if(self.initialModel != nil) {
-		_loadingAlert = [[UIAlertView alloc] initWithTitle:@"Please wait..." message: @"The model is loading" delegate: self cancelButtonTitle: nil otherButtonTitles: nil];
-		[_loadingAlert show];
-	}
+  //if(self.initialModel != nil) {
+  if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]) {
+    _loadingAlert = [[UIAlertView alloc] initWithTitle:@"Please wait..." message: @"The model is loading" delegate: self cancelButtonTitle: nil otherButtonTitles: nil];
+    [_loadingAlert show];
+  }
 }
 
 -(void)viewDidAppear:(BOOL)animated
 {
-	if(!_loadingAlert && self.initialModel != nil) {
-		_loadingAlert = [[UIAlertView alloc] initWithTitle:@"Please wait..." message: @"The model is loading" delegate: self cancelButtonTitle: nil otherButtonTitles: nil];
-		[_loadingAlert show];
-	}
-	_progressLabel.frame = CGRectMake(50, self.view.frame.size.height - 25, _progressLabel.frame.size.width, _progressLabel.frame.size.height);
-	_progressIndicator.frame = CGRectMake(20, self.view.frame.size.height - 25, _progressIndicator.frame.size.width, _progressIndicator.frame.size.height);
-	[_progressIndicator addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleProgressIndicatorTap:)]];
-	[_progressLabel setHidden:YES];
-	[_progressIndicator setHidden:YES];
-	[self.navigationController setToolbarHidden:YES animated:NO];
-	if(self.initialModel != nil){
-		[self.glView load:self.initialModel];
-		[[NSNotificationCenter defaultCenter] postNotificationName:@"refreshParameters" object:nil];
-		//[self.initialModel release];
-		self.initialModel = nil;
-		[_loadingAlert dismissWithClickedButtonIndex:-1 animated:YES];
-		//[_loadingAlert release];
-		_loadingAlert = nil;
-	}
+  if(!_loadingAlert && self.initialModel != nil) {
+    _loadingAlert = [[UIAlertView alloc] initWithTitle:@"Please wait..." message: @"The model is loading" delegate: self cancelButtonTitle: nil otherButtonTitles: nil];
+    [_loadingAlert show];
+  }
+  _progressLabel.frame = CGRectMake(50, self.view.frame.size.height - 25, _progressLabel.frame.size.width, _progressLabel.frame.size.height);
+  _progressIndicator.frame = CGRectMake(20, self.view.frame.size.height - 25, _progressIndicator.frame.size.width, _progressIndicator.frame.size.height);
+  [_progressIndicator addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleProgressIndicatorTap:)]];
+  [_progressLabel setHidden:YES];
+  [_progressIndicator setHidden:YES];
+  [self.navigationController setToolbarHidden:YES animated:NO];
+  if(self.initialModel != nil){
+    [self.glView load:self.initialModel];
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshParameters" object:nil];
+    //[self.initialModel release];
+    self.initialModel = nil;
+    [_loadingAlert dismissWithClickedButtonIndex:-1 animated:YES];
+    //[_loadingAlert release];
+    _loadingAlert = nil;
+  }
 }
 
 - (void)viewDidLoad
 {
-    [super viewDidLoad];
-	// Do any additional setup after loading the view, typically from a nib.
-    [self configureView];
-	[_singleTap requireGestureRecognizerToFail:_doubleTap];
-    scaleFactor = 1.;
-	_errors = [[NSMutableArray alloc] init];
-    setObjCBridge((__bridge void*) self);
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(requestRender) name:@"requestRender" object:nil];
-
-	_runStopButton = [[UIBarButtonItem alloc] initWithTitle:@"Run" style:UIBarButtonItemStyleBordered target:self action:@selector(compute)];
-	UIBarButtonItem *share = [[UIBarButtonItem alloc] initWithTitle:@"Share" style:UIBarButtonItemStyleBordered target:self action:@selector(share)];
-    if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]){
-		UIBarButtonItem *model = [[UIBarButtonItem alloc] initWithTitle:@"Model list" style:UIBarButtonItemStyleBordered target:self action:@selector(showModelsList)];
-		[self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects:_runStopButton, model, share, nil]];
-	}
-	else
-	{
-        UIBarButtonItem *settings = [[UIBarButtonItem alloc] initWithTitle:@"Parameters" style:UIBarButtonItemStyleBordered target:self action:@selector(showSettings)];
-        [self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects:_runStopButton, settings, share, nil]];
-    }
-
-	UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
-	UIBarButtonItem *prevButton = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem: UIBarButtonSystemItemRewind target:self action:@selector(prevAnimation)];
-	_stopButton = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem: UIBarButtonSystemItemPause target:self action:@selector(stopAnimation:)];
-	[_stopButton setEnabled:NO];
-	_playButton = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem: UIBarButtonSystemItemPlay target:self action:@selector(playAnimation:)];
-	UIBarButtonItem *nextButton = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem: UIBarButtonSystemItemFastForward target:self action:@selector(nextAnimation)];
-	self.toolbarItems = [[NSArray alloc] initWithObjects:flexibleSpace, prevButton, _stopButton, _playButton, nextButton, flexibleSpace, nil];
+  [super viewDidLoad];
+  // Do any additional setup after loading the view, typically from a nib.
+  [self configureView];
+  [_singleTap requireGestureRecognizerToFail:_doubleTap];
+  scaleFactor = 1.;
+  _errors = [[NSMutableArray alloc] init];
+  setObjCBridge((__bridge void*) self);
+  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(requestRender) name:@"requestRender" object:nil];
+
+  _runStopButton = [[UIBarButtonItem alloc] initWithTitle:@"Run" style:UIBarButtonItemStyleBordered target:self action:@selector(compute)];
+  //UIBarButtonItem *share = [[UIBarButtonItem alloc] initWithTitle:@"Share" style:UIBarButtonItemStyleBordered target:self action:@selector(share)];
+  if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]){
+    UIBarButtonItem *model = [[UIBarButtonItem alloc] initWithTitle:@"Model list" style:UIBarButtonItemStyleBordered target:self action:@selector(showModelsList)];
+    [self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects:_runStopButton, model, /*share,*/ nil]];
+  }
+  else {
+    UIBarButtonItem *settings = [[UIBarButtonItem alloc] initWithTitle:@"Parameters" style:UIBarButtonItemStyleBordered target:self action:@selector(showSettings)];
+    [self.navigationItem setRightBarButtonItems:[NSArray arrayWithObjects:_runStopButton, settings, /*share,*/ nil]];
+  }
+
+  UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
+  UIBarButtonItem *prevButton = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem: UIBarButtonSystemItemRewind target:self action:@selector(prevAnimation)];
+  _stopButton = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem: UIBarButtonSystemItemPause target:self action:@selector(stopAnimation:)];
+  [_stopButton setEnabled:NO];
+  _playButton = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem: UIBarButtonSystemItemPlay target:self action:@selector(playAnimation:)];
+  UIBarButtonItem *nextButton = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem: UIBarButtonSystemItemFastForward target:self action:@selector(nextAnimation)];
+  self.toolbarItems = [[NSArray alloc] initWithObjects:flexibleSpace, prevButton, _stopButton, _playButton, nextButton, flexibleSpace, nil];
 }
 
 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
 {
-	_progressLabel.frame = CGRectMake(50, self.view.frame.size.height - 25, _progressLabel.frame.size.width, _progressLabel.frame.size.height);
-	_progressIndicator.frame = CGRectMake(20, self.view.frame.size.height - 25, _progressIndicator.frame.size.width, _progressIndicator.frame.size.height);
+  _progressLabel.frame = CGRectMake(50, self.view.frame.size.height - 25, _progressLabel.frame.size.width, _progressLabel.frame.size.height);
+  _progressIndicator.frame = CGRectMake(20, self.view.frame.size.height - 25, _progressIndicator.frame.size.width, _progressIndicator.frame.size.height);
 }
 
 -(void)didReceiveMemoryWarning
 {
-	onelab_cb("stop");
-	UILocalNotification *localNotif = [[UILocalNotification alloc] init];
-	if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground && localNotif) {
-		localNotif.alertBody = @"The computing had to stop because your device ran out of memory";
-		localNotif.alertAction = @"View";
-		localNotif.hasAction = true;
-		localNotif.soundName = UILocalNotificationDefaultSoundName;
-		localNotif.applicationIconBadgeNumber = 1;
-		[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
-	}
-	[[UIApplication sharedApplication] endBackgroundTask: _computeBackgroundTaskIdentifier];
+  onelab_cb("stop");
+  UILocalNotification *localNotif = [[UILocalNotification alloc] init];
+  if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground && localNotif) {
+    localNotif.alertBody = @"The computation had to stop because your device ran out of memory";
+    localNotif.alertAction = @"View";
+    localNotif.hasAction = true;
+    localNotif.soundName = UILocalNotificationDefaultSoundName;
+    localNotif.applicationIconBadgeNumber = 1;
+    [[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
+  }
+  [[UIApplication sharedApplication] endBackgroundTask: _computeBackgroundTaskIdentifier];
 }
 
 -(void)share
 {
-	NSArray *dataToShare = @[[self.glView getGLScreenshot]];
-	UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
-	[self presentViewController:activityVC animated:YES completion:nil];
+  NSArray *dataToShare = @[[self.glView getGLScreenshot]];
+  UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
+  [self presentViewController:activityVC animated:YES completion:nil];
 }
 
 - (void)compute
 {
-	[_runStopButton setAction:@selector(stop)];
-	[_runStopButton setTitle:@"Stop"];
-	[_progressLabel setText:@""];
-	[_progressLabel setHidden:NO];
-	[_progressIndicator setHidden:NO];
-	[_progressIndicator startAnimating];
-	[[UIApplication sharedApplication] cancelAllLocalNotifications];
-	dispatch_group_t group = dispatch_group_create();
-	dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-		_computeBackgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
-			[[UIApplication sharedApplication] endBackgroundTask: _computeBackgroundTaskIdentifier];
-			_computeBackgroundTaskIdentifier = UIBackgroundTaskInvalid;
-		}];
-        AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-        appDelegate->compute = YES;
-        onelab_cb("compute");
-        appDelegate->compute = NO;
-		UILocalNotification *localNotif = [[UILocalNotification alloc] init];
-		if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground && localNotif) {
-			localNotif.alertBody = @"Computation finished";
-			localNotif.alertAction = @"View";
-			localNotif.hasAction = true;
-			localNotif.soundName = UILocalNotificationDefaultSoundName;
-			localNotif.applicationIconBadgeNumber = 1;
-			[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
-		}
-		[[UIApplication sharedApplication] endBackgroundTask: _computeBackgroundTaskIdentifier];
-		_computeBackgroundTaskIdentifier = UIBackgroundTaskInvalid;
+  [_errors removeAllObjects];
+  [_runStopButton setAction:@selector(stop)];
+  [_runStopButton setTitle:@"Stop"];
+  [_progressLabel setText:@""];
+  [_progressLabel setHidden:NO];
+  [_progressIndicator setHidden:NO];
+  [_progressIndicator startAnimating];
+  [[UIApplication sharedApplication] cancelAllLocalNotifications];
+  dispatch_group_t group = dispatch_group_create();
+  dispatch_queue_t queue = dispatch_queue_create("org.geuz.onelab", NULL);
+  dispatch_group_async(group, queue, ^{
+      _computeBackgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
+          [[UIApplication sharedApplication] endBackgroundTask: _computeBackgroundTaskIdentifier];
+          _computeBackgroundTaskIdentifier = UIBackgroundTaskInvalid;
+        }];
+      AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
+      appDelegate->compute = YES;
+      onelab_cb("compute");
+      appDelegate->compute = NO;
+      UILocalNotification *localNotif = [[UILocalNotification alloc] init];
+      if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground && localNotif) {
+        localNotif.alertBody = @"Computation done!";
+        localNotif.alertAction = @"View";
+        localNotif.hasAction = true;
+        localNotif.soundName = UILocalNotificationDefaultSoundName;
+        localNotif.applicationIconBadgeNumber = 1;
+        [[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
+      }
+      [[UIApplication sharedApplication] endBackgroundTask: _computeBackgroundTaskIdentifier];
+      _computeBackgroundTaskIdentifier = UIBackgroundTaskInvalid;
+    });
+
+  dispatch_group_notify(group, queue, ^{
+      [UIApplication sharedApplication].applicationIconBadgeNumber = -1;
+      [self performSelectorOnMainThread:@selector(stopGUI) withObject:nil waitUntilDone:YES];
     });
-	
-	dispatch_group_notify(group, dispatch_get_main_queue(), ^{
-		[UIApplication sharedApplication].applicationIconBadgeNumber = -1;
-		[_runStopButton setAction:@selector(compute)];
-		[_runStopButton setTitle:@"Run"];
-		[_progressLabel setHidden:YES];
-		[_progressIndicator stopAnimating];
-		[_progressIndicator setHidden:YES];
-		if(_errors.count > 0) {
-			_errorAlert = [[UIErrorAlertView alloc] initWithTitle:@"Gmsh/GetDP error" message:[_errors lastObject] delegate:self cancelButtonTitle:@"Hide" otherButtonTitles:@"Show more", nil];
-			[_errorAlert show];
-		}
-	});
 }
+
+-(void)stopGUI
+{
+  [_runStopButton setAction:@selector(compute)];
+  [_runStopButton setTitle:@"Run"];
+  [_progressLabel setHidden:YES];
+  [_progressIndicator stopAnimating];
+  [_progressIndicator setHidden:YES];
+  if(_errors.count > 0) {
+    _errorAlert = [[UIErrorAlertView alloc] initWithTitle:@"Gmsh/GetDP error" message:[_errors lastObject] delegate:self cancelButtonTitle:@"Hide" otherButtonTitles:@"Show more", nil];
+    [_errorAlert show];
+  }
+}
+
 - (void)stop
 {
-	onelab_cb("stop");
+  onelab_cb("stop");
 }
+
 -(void)playAnimation:(UIBarButtonItem *)sender
 {
-	[_playButton setEnabled:NO];
-	[_stopButton setEnabled:YES];
-	_animation = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(nextAnimation) userInfo:nil repeats:YES];
+  [_playButton setEnabled:NO];
+  [_stopButton setEnabled:YES];
+  _animation = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(nextAnimation) userInfo:nil repeats:YES];
 }
+
 -(void)stopAnimation:(UIBarButtonItem *)sender
 {
-	[_animation invalidate];
-	_animation = nil;
-	[_playButton setEnabled:YES];
-	[_stopButton setEnabled:NO];
+  [_animation invalidate];
+  _animation = nil;
+  [_playButton setEnabled:YES];
+  [_stopButton setEnabled:NO];
 }
+
 -(void)nextAnimation { animation_next(); [self requestRender]; }
+
 -(void)prevAnimation { animation_prev(); [self requestRender]; }
+
 -(IBAction)pinch:(UIPinchGestureRecognizer *)sender
 {
-    if([sender numberOfTouches] > 2) return;
+  if([sender numberOfTouches] <= 2) {
     float mScale = scaleFactor;
     if (sender.state == UIGestureRecognizerStateBegan)
-        mScale = scaleFactor;
+      mScale = scaleFactor;
     else if(sender.state == UIGestureRecognizerStateChanged)
-        mScale = scaleFactor * [sender scale];
-    else if(sender.state == UIGestureRecognizerStateEnded || sender.state == UIGestureRecognizerStateCancelled){
-        scaleFactor *= [sender scale];
-        mScale = scaleFactor;
+      mScale = scaleFactor * [sender scale];
+    else if(sender.state == UIGestureRecognizerStateEnded){
+      scaleFactor *= [sender scale];
+      mScale = scaleFactor;
+    }
+    else if(sender.state == UIGestureRecognizerStateCancelled){
+      mScale = scaleFactor;
     }
     mScale = MAX(0.1, mScale);
     glView->mContext->eventHandler(2,mScale);
-    [glView drawView];
+  }
+  [glView drawView];
 }
 
 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 {
-    UITouch *touch = [[event allTouches] anyObject];
-    CGPoint touchPoint = [touch locationInView:self.view];
-    glView->mContext->eventHandler(0, touchPoint.x, touchPoint.y);
+  UITouch *touch = [[event allTouches] anyObject];
+  CGPoint touchPoint = [touch locationInView:self.view];
+  glView->mContext->eventHandler(0, touchPoint.x, touchPoint.y);
 }
 
 -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
 {
-    [self touchesEnded:touches withEvent:event];
+  [self touchesEnded:touches withEvent:event];
 }
 
 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
 {
-    UITouch *touch = [[event allTouches] anyObject];
-    CGPoint touchPoint = [touch locationInView:self.view];
-    glView->mContext->eventHandler(4, touchPoint.x, touchPoint.y);
+  UITouch *touch = [[event allTouches] anyObject];
+  CGPoint touchPoint = [touch locationInView:self.view];
+  glView->mContext->eventHandler(4, touchPoint.x, touchPoint.y);
 }
 
 - (IBAction)singleTap:(UITapGestureRecognizer *)sender {
-	[self.navigationController setToolbarHidden:(!(self.navigationController.toolbarHidden && !((AppDelegate *)[UIApplication sharedApplication].delegate)->compute && number_of_animation() > 0)) animated:YES];
+  [self.navigationController setToolbarHidden:(!(self.navigationController.toolbarHidden && !((AppDelegate *)[UIApplication sharedApplication].delegate)->compute && number_of_animation() > 0)) animated:YES];
 }
 
 - (IBAction)doubleTap:(UITapGestureRecognizer *)sender {
-	scaleFactor = 1;
-	glView->mContext->eventHandler(10);
-	[glView drawView];
+  scaleFactor = 1;
+  glView->mContext->eventHandler(10);
+  [glView drawView];
 }
 
 - (void) showModelsList
 {
-    if(((AppDelegate *)[UIApplication sharedApplication].delegate)->compute) {
-        UIAlertView *alert;
-        alert = [[UIAlertView alloc] initWithTitle:@"Can't show the models list" message:@"The compute have to be finished before you can select an other model." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
-        [alert show];
-        return;
-    }
-    if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]){
-        AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
-        [UIView transitionWithView:appDelegate.window
-                          duration:0.5
-                           options:UIViewAnimationOptionTransitionFlipFromRight
-                        animations:^{ appDelegate.window.rootViewController = appDelegate.modelListController; }
-                        completion:nil];
-    }
-    [self.navigationController popToRootViewControllerAnimated:YES];
+  if(((AppDelegate *)[UIApplication sharedApplication].delegate)->compute) {
+    UIAlertView *alert;
+    alert = [[UIAlertView alloc] initWithTitle:@"Can't show the model list" message:@"The computation has to complete before you can select another model." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
+    [alert show];
+    return;
+  }
+  if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]){
+    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
+    [UIView transitionWithView:appDelegate.window
+                      duration:0.5
+                       options:UIViewAnimationOptionTransitionFlipFromRight
+                    animations:^{ appDelegate.window.rootViewController = appDelegate.modelListController; }
+    completion:nil];
+  }
+  [self.navigationController popToRootViewControllerAnimated:YES];
 }
-    
+
 - (void) showSettings
 {
-    [self performSegueWithIdentifier:@"showSettingsSegue" sender:self];
+  [self performSegueWithIdentifier:@"showSettingsSegue" sender:self];
 }
 
 - (void)viewDidUnload
 {
-    [self setGlView:nil];
-    [self setProgressLabel:nil];
-	[self setProgressIndicator:nil];
-	[self setSingleTap:nil];
-	[self setDoubleTap:nil];
-    [super viewDidUnload];
-    // Release any retained subviews of the main view.
+  [self setGlView:nil];
+  [self setProgressLabel:nil];
+  [self setProgressIndicator:nil];
+  [self setSingleTap:nil];
+  [self setDoubleTap:nil];
+  [super viewDidUnload];
+  // Release any retained subviews of the main view.
 }
 
 - (void)requestRender
 {
+  if([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
     [glView drawView];
 }
 
 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
 {
-    return YES;
+  return YES;
 }
 
 #pragma mark - Alert view
 
 -(void)addError:(std::string)msg
 {
-	[_errors addObject:[NSString stringWithCString:msg.c_str() encoding:[NSString defaultCStringEncoding]]];
+  [_errors addObject:[NSString stringWithCString:msg.c_str() encoding:[NSString defaultCStringEncoding]]];
 }
 
 -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
 {
-	if(buttonIndex == 0) [_errors removeAllObjects];
-	else [_errors removeLastObject];
-	if(_errors.count > 0) {
-		[_errorAlert setMessage:[_errors lastObject]];
-		[_errorAlert show];
-	}
-	else {
-		[_errorAlert dismissWithClickedButtonIndex:0 animated:YES];
-		//[_errorAlert release];
-		_errorAlert = nil;
-	}
+  if(buttonIndex == 0) {
+    [_errors removeAllObjects];
+    return;
+  }
+  else [_errors removeLastObject];
+  if(_errors.count > 1)
+    _errorAlert = [[UIErrorAlertView alloc] initWithTitle:@"Gmsh/GetDP error" message:[_errors lastObject] delegate:self cancelButtonTitle:@"Hide" otherButtonTitles:@"Show more", nil];
+  else
+    _errorAlert = [[UIErrorAlertView alloc] initWithTitle:@"Gmsh/GetDP error" message:[_errors lastObject] delegate:self cancelButtonTitle:@"Hide" otherButtonTitles: nil];
+  [_errorAlert show];
 }
 
 #pragma mark - Split view
 
 - (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
 {
-    barButtonItem.title = NSLocalizedString(@"Parameters", @"Parameters");
-	[self.navigationItem setLeftBarButtonItem:barButtonItem];
-    self.masterPopoverController = popoverController;
+  barButtonItem.title = NSLocalizedString(@"Parameters", @"Parameters");
+  [self.navigationItem setLeftBarButtonItem:barButtonItem];
+  self.masterPopoverController = popoverController;
 }
 
 - (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
 {
-    // Called when the view is shown again in the split view, invalidating the button and popover controller.
-    [self.navigationItem setLeftBarButtonItem:nil animated:YES];
-    self.masterPopoverController = nil;
+  // Called when the view is shown again in the split view, invalidating the button and popover controller.
+  [self.navigationItem setLeftBarButtonItem:nil animated:YES];
+  self.masterPopoverController = nil;
 }
 
 void messageFromCpp (void *self, std::string level, std::string msg)
 {
-    if(level == "RequestRender"){
-        [(__bridge id)self requestRender];
-        [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshParameters" object:nil];
-    }
-	else if(level == "Progress"){
-		[(__bridge id)self performSelectorOnMainThread:@selector(setProgress:) withObject:[NSString stringWithCString:msg.c_str() encoding:[NSString defaultCStringEncoding]] waitUntilDone:YES];
-	}
-    else if(level == "Error")
-        [(__bridge id)self addError:msg];
+  if(level == "RequestRender"){
+    [(__bridge id)self performSelectorOnMainThread:@selector(requestRender) withObject:nil waitUntilDone:YES];
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshParameters" object:nil];
+  }
+  else if(level == "Progress"){
+    [(__bridge id)self performSelectorOnMainThread:@selector(setProgress:) withObject:[NSString stringWithCString:msg.c_str() encoding:[NSString defaultCStringEncoding]] waitUntilDone:YES];
+  }
+  else if(level == "Error")
+    [(__bridge id)self addError:msg];
 }
+
 -(void)setProgress:(NSString *)progress
 {
-	[_progressLabel setText:progress];
+  [_progressLabel setText:progress];
 }
+
 -(void)handleProgressIndicatorTap:(id)sender
 {
-	[_progressLabel setHidden:!_progressLabel.hidden];
+  [_progressLabel setHidden:!_progressLabel.hidden];
 }
+
 void getBitmap(void *self, const char *text, int textsize, unsigned char **map, int *height, int *width, int *realWidth)
 {
-    [(__bridge id)self getBitmapFromStringObjC:text withTextSize:textsize inMap:map inHeight:height inWidth:width inRealWidth:realWidth];
+  [(__bridge id)self getBitmapFromStringObjC:text withTextSize:textsize inMap:map inHeight:height inWidth:width inRealWidth:realWidth];
 }
+
 -(void) getBitmapFromStringObjC:(const char *)text withTextSize:(int)textsize inMap:(unsigned char **)map inHeight:(int *)height inWidth:(int *)width inRealWidth:(int *) realWidth
 {
-    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 1024, textsize)];
-    lbl.font = [UIFont systemFontOfSize:textsize];
-    [lbl setText:[NSString stringWithCString:text  encoding:[NSString defaultCStringEncoding]]];
-    [lbl setBackgroundColor:[UIColor clearColor]];
-    CGSize lblSize = [[lbl text] sizeWithAttributes:@{NSFontAttributeName:[lbl font]}];
-    *realWidth = lblSize.width;
-    int i;
-    for(i=2;i<*realWidth;i*=2); *width = i;
-    *height = lblSize.height;
-    for(i=2;i<*height;i*=2); *height = i;
-    UIGraphicsBeginImageContextWithOptions(CGSizeMake(*width, *height), NO, 0.0);
-    [lbl.layer renderInContext:UIGraphicsGetCurrentContext()];
-    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
-
-    CGImageRef bitmap = [img CGImage];
-    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
-    unsigned char *rawData = (unsigned char*) calloc(*height * *width * 4, sizeof(unsigned char));
-    *map = (unsigned char*) calloc(*height * *width, sizeof(unsigned char));
-    NSUInteger bytesPerPixel = 4;
-    NSUInteger bytesPerRow = bytesPerPixel * *width;
-    NSUInteger bitsPerComponent = 8;
-    CGContextRef context = CGBitmapContextCreate(rawData, *width, *height,
-                                                 bitsPerComponent, bytesPerRow, colorSpace,
-                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
-    CGColorSpaceRelease(colorSpace);
-    
-    CGContextDrawImage(context, CGRectMake(0, 0, *width, *height), bitmap);
-    CGContextRelease(context);
-
-    // rawData contains the image data in the RGBA8888 pixel format.
-    for (int byteIndex = 0 ; byteIndex < *width * *height * 4 ; byteIndex+=4)
-        *(*map+byteIndex/4) = rawData[byteIndex + 3];
-    free(rawData);
+  UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 1024, textsize)];
+  lbl.font = [UIFont systemFontOfSize:textsize];
+  [lbl setText:[NSString stringWithCString:text  encoding:[NSString defaultCStringEncoding]]];
+  [lbl setBackgroundColor:[UIColor clearColor]];
+  CGSize lblSize = [[lbl text] sizeWithAttributes:@{NSFontAttributeName:[lbl font]}];
+  *realWidth = lblSize.width;
+  int i=2;
+  while(i<*realWidth) i*=2;
+  *width = i;
+  *height = lblSize.height;
+  i=2;
+  while(i<*height) i*=2;
+  *height = i;
+
+  UIGraphicsBeginImageContextWithOptions(CGSizeMake(*width, *height), NO, 0.0);
+  [lbl.layer renderInContext:UIGraphicsGetCurrentContext()];
+  UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
+  UIGraphicsEndImageContext();
+  CGImageRef bitmap = [img CGImage];
+  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+  unsigned char *rawData = (unsigned char*) calloc(*height * *width * 4, sizeof(unsigned char));
+  *map = (unsigned char*) calloc(*height * *width, sizeof(unsigned char));
+  NSUInteger bytesPerPixel = 4;
+  NSUInteger bytesPerRow = bytesPerPixel * *width;
+  NSUInteger bitsPerComponent = 8;
+  CGContextRef context = CGBitmapContextCreate(rawData, *width, *height,
+                                               bitsPerComponent, bytesPerRow, colorSpace,
+                                               kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
+  CGColorSpaceRelease(colorSpace);
+
+  CGContextDrawImage(context, CGRectMake(0, 0, *width, *height), bitmap);
+  CGContextRelease(context);
+
+  // rawData contains the image data in the RGBA8888 pixel format.
+  for (int byteIndex = 0 ; byteIndex < *width * *height * 4 ; byteIndex+=4)
+    *(*map+byteIndex/4) = rawData[byteIndex + 3];
+  free(rawData);
+}
+
+- (IBAction)startRotation:(UIButton *)sender {
+  glView->rotate = !glView->rotate;
+  if(glView->rotate)
+    [sender setImage:[UIImage imageNamed:@"icon_translate.png"] forState:UIControlStateNormal];
+  else
+    [sender setImage:[UIImage imageNamed:@"icon_rotate.png"] forState:UIControlStateNormal];
 }
+
 @end
diff --git a/contrib/mobile/iOS/Onelab/Onelab-Info.plist b/contrib/mobile/iOS/Onelab/Onelab-Info.plist
index 4a16e04..64118d5 100644
--- a/contrib/mobile/iOS/Onelab/Onelab-Info.plist
+++ b/contrib/mobile/iOS/Onelab/Onelab-Info.plist
@@ -1,98 +1,70 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleDisplayName</key>
-	<string>${PRODUCT_NAME}</string>
-	<key>CFBundleDocumentTypes</key>
-	<array>
-		<dict>
-			<key>CFBundleTypeExtensions</key>
-			<array>
-				<string>onelab</string>
-			</array>
-			<key>CFBundleTypeName</key>
-			<string>Onelab package</string>
-			<key>LSTypeIsPackage</key>
-			<true/>
-		</dict>
-	</array>
-	<key>CFBundleExecutable</key>
-	<string>${EXECUTABLE_NAME}</string>
-	<key>CFBundleIcons</key>
-	<dict>
-		<key>CFBundlePrimaryIcon</key>
-		<dict>
-			<key>CFBundleIconFiles</key>
-			<array>
-				<string>icon_app_iphone_retina</string>
-				<string>icon_app_ipad_61</string>
-				<string>ic_launcher.png</string>
-				<string>ic_launcher_retina.png</string>
-			</array>
-		</dict>
-	</dict>
-	<key>CFBundleIcons~ipad</key>
-	<dict>
-		<key>CFBundlePrimaryIcon</key>
-		<dict>
-			<key>CFBundleIconFiles</key>
-			<array>
-				<string>icon_app_ipad</string>
-				<string>icon_app_iphone_61</string>
-				<string>icon_app_ipad_retina</string>
-				<string>icon_app_iphone_retina</string>
-				<string>icon_app_ipad_61</string>
-				<string>ic_launcher.png</string>
-				<string>ic_launcher_retina.png</string>
-			</array>
-		</dict>
-	</dict>
-	<key>CFBundleIdentifier</key>
-	<string>org.geuz.${PRODUCT_NAME:rfc1034identifier}</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>${PRODUCT_NAME}</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1.0</string>
-	<key>LSRequiresIPhoneOS</key>
-	<true/>
-	<key>UIBackgroundModes</key>
-	<array>
-		<string></string>
-	</array>
-	<key>UIFileSharingEnabled</key>
-	<true/>
-	<key>UIMainStoryboardFile</key>
-	<string>iPhoneiPodStoryboard</string>
-	<key>UIMainStoryboardFile~ipad</key>
-	<string>iPadStoryboard</string>
-	<key>UIRequiredDeviceCapabilities</key>
-	<array>
-		<string>armv7</string>
-	</array>
-	<key>UISupportedInterfaceOrientations</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-		<string>UIInterfaceOrientationPortraitUpsideDown</string>
-	</array>
-	<key>UISupportedInterfaceOrientations~ipad</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationPortraitUpsideDown</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-	</array>
-</dict>
+  <dict>
+    <key>CFBundleExecutable</key>
+    <string>${EXECUTABLE_NAME}</string>
+    <key>CFBundleIcons</key>
+    <dict>
+      <key>CFBundlePrimaryIcon</key>
+      <dict>
+        <key>CFBundleIconFiles</key>
+        <array>
+          <string>icon_app_iphone_retina</string>
+        </array>
+      </dict>
+    </dict>
+    <key>CFBundleIcons~ipad</key>
+    <dict>
+      <key>CFBundlePrimaryIcon</key>
+      <dict>
+        <key>CFBundleIconFiles</key>
+        <array>
+          <string>icon_app_ipad</string>
+          <string>icon_app_ipad_retina</string>
+          <string>icon_app_iphone_retina</string>
+        </array>
+      </dict>
+    </dict>
+    <key>CFBundleIdentifier</key>
+    <string>org.geuz.${PRODUCT_NAME:rfc1034identifier}</string>
+    <key>CFBundleInfoDictionaryVersion</key>
+    <string>6.0</string>
+    <key>CFBundleName</key>
+    <string>${PRODUCT_NAME}</string>
+    <key>CFBundlePackageType</key>
+    <string>APPL</string>
+    <key>CFBundleShortVersionString</key>
+    <string>1.0.6</string>
+    <key>CFBundleSignature</key>
+    <string>????</string>
+    <key>CFBundleVersion</key>
+    <string>1.0.6</string>
+    <key>LSRequiresIPhoneOS</key>
+    <true/>
+    <key>UIFileSharingEnabled</key>
+    <true/>
+    <key>UIMainStoryboardFile</key>
+    <string>iPhoneiPodStoryboard</string>
+    <key>UIMainStoryboardFile~ipad</key>
+    <string>iPadStoryboard</string>
+    <key>UIRequiredDeviceCapabilities</key>
+    <array>
+      <string>opengles-1</string>
+    </array>
+    <key>UISupportedInterfaceOrientations</key>
+    <array>
+      <string>UIInterfaceOrientationPortrait</string>
+      <string>UIInterfaceOrientationLandscapeLeft</string>
+      <string>UIInterfaceOrientationLandscapeRight</string>
+      <string>UIInterfaceOrientationPortraitUpsideDown</string>
+    </array>
+    <key>UISupportedInterfaceOrientations~ipad</key>
+    <array>
+      <string>UIInterfaceOrientationPortrait</string>
+      <string>UIInterfaceOrientationPortraitUpsideDown</string>
+      <string>UIInterfaceOrientationLandscapeLeft</string>
+      <string>UIInterfaceOrientationLandscapeRight</string>
+    </array>
+  </dict>
 </plist>
diff --git a/contrib/mobile/iOS/Onelab/OptionsViewController.h b/contrib/mobile/iOS/Onelab/OptionsViewController.h
index b62a02a..9f0efc9 100644
--- a/contrib/mobile/iOS/Onelab/OptionsViewController.h
+++ b/contrib/mobile/iOS/Onelab/OptionsViewController.h
@@ -1,11 +1,3 @@
-//
-//  PostProViewController.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 13/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <UIKit/UIKit.h>
 
 @interface OptionsViewController : UITableViewController <UITextFieldDelegate>
diff --git a/contrib/mobile/iOS/Onelab/OptionsViewController.mm b/contrib/mobile/iOS/Onelab/OptionsViewController.mm
index e0e3217..99a4ae4 100644
--- a/contrib/mobile/iOS/Onelab/OptionsViewController.mm
+++ b/contrib/mobile/iOS/Onelab/OptionsViewController.mm
@@ -1,11 +1,3 @@
-//
-//  PostProViewController.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 13/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import "OptionsViewController.h"
 #import "ParametersViewController.h"
 #import "PostProcessingViewController.h"
@@ -25,88 +17,86 @@
 
 - (id)initWithStyle:(UITableViewStyle)style
 {
-    self = [super initWithStyle:style];
-    if (self) {
-        // Custom initialization
-    }
-    return self;
+  self = [super initWithStyle:style];
+  if (self) {
+    // Custom initialization
+  }
+  return self;
 }
 
 - (void)viewDidLoad
 {
-    [super viewDidLoad];
+  [super viewDidLoad];
 
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshOptions:) name:@"refreshParameters" object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshOptions:) name:@"resetParameters" object:nil];
+  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshOptions:) name:@"refreshParameters" object:nil];
+  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshOptions:) name:@"resetParameters" object:nil];
 
-    self.navigationItem.title = @"Display";
+  self.navigationItem.title = @"Display";
 
-    [self.navigationController setToolbarHidden:NO];
-	control = [[UISegmentedControl alloc] initWithItems:[[NSArray alloc] initWithObjects:@"Model", @"Display", nil]];
-	UIBarButtonItem *controlBtn = [[UIBarButtonItem alloc] initWithCustomView:control];
-	UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
-	self.toolbarItems = [[NSArray alloc] initWithObjects:flexibleSpace, controlBtn, flexibleSpace, nil];
-	[control addTarget:self action:@selector(indexDidChangeForSegmentedControl:) forControlEvents:UIControlEventValueChanged];
-    if(![[UIDevice currentDevice].model isEqualToString:@"iPad"] && ![[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"])
-        self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self action:@selector(backButtonPressed:)];
-    else
-        self.navigationItem.hidesBackButton = true;
+  [self.navigationController setToolbarHidden:NO];
+  control = [[UISegmentedControl alloc] initWithItems:[[NSArray alloc] initWithObjects:@"Model", @"Display", nil]];
+  UIBarButtonItem *controlBtn = [[UIBarButtonItem alloc] initWithCustomView:control];
+  UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
+  self.toolbarItems = [[NSArray alloc] initWithObjects:flexibleSpace, controlBtn, flexibleSpace, nil];
+  [control addTarget:self action:@selector(indexDidChangeForSegmentedControl:) forControlEvents:UIControlEventValueChanged];
+  if(![[UIDevice currentDevice].model isEqualToString:@"iPad"] && ![[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"])
+    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self action:@selector(backButtonPressed:)];
+  else
+    self.navigationItem.hidesBackButton = true;
 }
 - (void)viewWillAppear:(BOOL)animated
 {
-    control.selectedSegmentIndex = 1;
-    [super viewWillAppear:animated];
+  control.selectedSegmentIndex = 1;
+  [super viewWillAppear:animated];
 }
 
 -(void)backButtonPressed:(id)sender
 {
-    for(UIViewController *v in [self.navigationController viewControllers])
-        if([v isKindOfClass:[ModelViewController class]]) [self.navigationController popToViewController:v animated:YES];
+  for(UIViewController *v in [self.navigationController viewControllers])
+    if([v isKindOfClass:[ModelViewController class]]) [self.navigationController popToViewController:v animated:YES];
 }
 
 - (void)indexDidChangeForSegmentedControl:(id)sender
 {
-    [self.navigationController popViewControllerAnimated:YES];
+  [self.navigationController popViewControllerAnimated:YES];
 }
 
 - (void)didReceiveMemoryWarning
 {
-    [super didReceiveMemoryWarning];
-    // Dispose of any resources that can be recreated.
+  [super didReceiveMemoryWarning];
+  // Dispose of any resources that can be recreated.
 }
 
 - (void)refreshOptions:(id)sender
 {
-    [self performSelectorOnMainThread:@selector(refreshOptions) withObject:nil waitUntilDone:NO];
+  [self performSelectorOnMainThread:@selector(refreshOptions) withObject:nil waitUntilDone:NO];
 }
 - (void)refreshOptions
 {
-    NSInteger nrow = [self.tableView numberOfRowsInSection:1];
-    if(PView::list.size() == 0)
-    {
-        NSMutableArray *array = [[NSMutableArray alloc] init];
-        for(NSInteger i = 0; i<nrow; i++)
-            [array addObject:[NSIndexPath indexPathForRow:i inSection:1]];
-        [self.tableView beginUpdates];
-        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithArray:array] withRowAnimation:UITableViewRowAnimationAutomatic];
-        [self.tableView endUpdates];
-    }
-    else if(nrow < PView::list.size())
-    {
-        NSMutableArray *array = [[NSMutableArray alloc] init];
-        for(NSInteger i = nrow; i<PView::list.size(); i++)
-            [array addObject:[NSIndexPath indexPathForRow:i-nrow inSection:1]];
-        [self.tableView beginUpdates];
-        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithArray:array] withRowAnimation:UITableViewRowAnimationAutomatic];
-        [self.tableView endUpdates];
-    }
+  NSInteger nrow = [self.tableView numberOfRowsInSection:1];
+  if(PView::list.size() == 0) {
+    NSMutableArray *array = [[NSMutableArray alloc] init];
+    for(NSInteger i = 0; i<nrow; i++)
+      [array addObject:[NSIndexPath indexPathForRow:i inSection:1]];
+    [self.tableView beginUpdates];
+    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithArray:array] withRowAnimation:UITableViewRowAnimationAutomatic];
+    [self.tableView endUpdates];
+  }
+  else if(nrow < PView::list.size()) {
+    NSMutableArray *array = [[NSMutableArray alloc] init];
+    for(NSInteger i = nrow; i<PView::list.size(); i++)
+      [array addObject:[NSIndexPath indexPathForRow:i-nrow inSection:1]];
+    [self.tableView beginUpdates];
+    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithArray:array] withRowAnimation:UITableViewRowAnimationAutomatic];
+    [self.tableView endUpdates];
+  }
 }
 
 #pragma mark - Table view data source
 
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 {
-    return 2;
+  return 2;
     /**
      Section    Name
         0       Options (Show mesh, Show geometry)
@@ -116,146 +106,155 @@
 
 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
 {
-    switch (section) {
-        case 0:
-            return @"Display options";
-        case 1:
-            return @"Result options";
-        default:
-            return @"Other options";
-    }
+  switch (section) {
+  case 0:
+    return @"Display options";
+  case 1:
+    return @"Result options";
+  default:
+    return @"Other options";
+  }
 }
 
 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
-    switch (section) {
-        case 0:
-            return 4;
-        case 1:
-            return PView::list.size();
-        default:
-            return 0;
-    }
+  switch (section) {
+  case 0:
+    return 4;
+  case 1:
+    return PView::list.size();
+  default:
+    return 0;
+  }
 }
 
 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
-    if(cell == nil)
-        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"postproCell"];
-    else {
-        cell = nil;
-        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"postproCell"];
+  UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+  if(cell == nil)
+    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"postproCell"];
+  else {
+    cell = nil;
+    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"postproCell"];
+  }
+  [cell setFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.x, tableView.frame.size.width, cell.frame.size.height)];
+  switch (indexPath.section) {
+  case 0:
+    {
+      [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+      UISwitch *showHideOptions = [[UISwitch alloc] initWithFrame: CGRectMake(10, 10, 100, 30)];
+      UILabel *lblOptions = [[UILabel alloc] initWithFrame:CGRectMake(10 + (showHideOptions.frame.size.width)+25 , 10, (cell.bounds.size.width - (showHideOptions.frame.size.width) - 25), 30)];
+      if(indexPath.row == 0) {
+        [lblOptions setText:@"Show geometry points"];
+        [showHideOptions setOn:(CTX::instance()->geom.points)];
+        [showHideOptions addTarget:self action:@selector(setShowGeomPoints:) forControlEvents:UIControlEventValueChanged];
+      }
+      else if(indexPath.row == 1) {
+        [lblOptions setText:@"Show geometry lines"];
+        [showHideOptions setOn:(CTX::instance()->geom.lines)];
+        [showHideOptions addTarget:self action:@selector(setShowGeomLines:) forControlEvents:UIControlEventValueChanged];
+      }
+      else if(indexPath.row == 2) {
+        [lblOptions setText:@"Show mesh surface edges"];
+        [showHideOptions setOn:(CTX::instance()->mesh.surfacesEdges)];
+        [showHideOptions addTarget:self action:@selector(setShowMeshSurfacesEdges:) forControlEvents:UIControlEventValueChanged];
+      }
+      else if(indexPath.row == 3) {
+        [lblOptions setText:@"Show mesh volumes edges"];
+        [showHideOptions setOn:CTX::instance()->mesh.volumesEdges];
+        [showHideOptions addTarget:self action:@selector(setShowMeshVolumesEdges:) forControlEvents:UIControlEventValueChanged];
+      }
+      [cell addSubview:showHideOptions];
+      [cell addSubview:lblOptions];
     }
-    [cell setFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.x, tableView.frame.size.width, cell.frame.size.height)];
-    switch (indexPath.section) {
-        case 0:
-        {
-            [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
-            UISwitch *showHideOptions = [[UISwitch alloc] initWithFrame: CGRectMake(10, 10, 100, 30)];
-            UILabel *lblOptions = [[UILabel alloc] initWithFrame:CGRectMake(10 + (showHideOptions.frame.size.width)+25 , 10, (cell.bounds.size.width - (showHideOptions.frame.size.width) - 25), 30)];
-            if(indexPath.row == 0) {
-                [lblOptions setText:@"Show geometry points"];
-                [showHideOptions setOn:(CTX::instance()->geom.points)];
-                [showHideOptions addTarget:self action:@selector(setShowGeomPoints:) forControlEvents:UIControlEventValueChanged];
-            }
-            else if(indexPath.row == 1) {
-                [lblOptions setText:@"Show geometry lines"];
-                [showHideOptions setOn:(CTX::instance()->geom.lines)];
-                [showHideOptions addTarget:self action:@selector(setShowGeomLines:) forControlEvents:UIControlEventValueChanged];
-            }
-            else if(indexPath.row == 2) {
-                [lblOptions setText:@"Show mesh surface edges"];
-                [showHideOptions setOn:(CTX::instance()->mesh.surfacesEdges)];
-                [showHideOptions addTarget:self action:@selector(setShowMeshSurfacesEdges:) forControlEvents:UIControlEventValueChanged];
-            }
-            else if(indexPath.row == 3) {
-                [lblOptions setText:@"Show mesh volumes edges"];
-                [showHideOptions setOn:CTX::instance()->mesh.volumesEdges];
-                [showHideOptions addTarget:self action:@selector(setShowMeshVolumesEdges:) forControlEvents:UIControlEventValueChanged];
-            }
-            [cell addSubview:showHideOptions];
-            [cell addSubview:lblOptions];
-        }
-            break;
-        case 1:
-        {
-            [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
-            int i = PView::list.size() - 1 - indexPath.row;
-            cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
-            UISwitch *showHide = [[UISwitch alloc] initWithFrame: CGRectMake(10, 10, 100, 30)];
-            UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(25 + (showHide.frame.size.width), 10, (cell.bounds.size.width - showHide.frame.size.width - 50), 30)];
-            [showHide setOn:(PView::list[i]->getOptions()->visible == 1)];
-            [showHide setTag:i];
-            [showHide addTarget:self action:@selector(PViewVisible:) forControlEvents:UIControlEventValueChanged];
-            [lbl setBackgroundColor: [UIColor clearColor]];
-            [lbl setText:[NSString stringWithCString:PView::list[i]->getData()->getName().c_str() encoding:[NSString defaultCStringEncoding]]];
-            [cell addSubview:showHide];
-            [cell addSubview:lbl];
+    break;
+  case 1:
+    {
+      NSArray *rows = [tableView indexPathsForVisibleRows];
+      for(NSIndexPath *mIndexpath in rows)
+        if(![mIndexpath isEqual:indexPath]){
+          UITableViewCell *tmp = [tableView cellForRowAtIndexPath:indexPath];
+          for(UIView *tmpv in tmp.subviews)for(UIView *v in tmpv.subviews)
+                                             if([v isKindOfClass:[UISwitch class]])
+                                               [(UISwitch *)v setOn:PView::list[v.tag]->getOptions()->visible];
         }
-            break;
+
+      [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
+      int i = PView::list.size() - 1 - indexPath.row;
+      cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+      UISwitch *showHide = [[UISwitch alloc] initWithFrame: CGRectMake(10, 10, 100, 30)];
+      UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(25 + (showHide.frame.size.width), 10, (cell.bounds.size.width - showHide.frame.size.width - 50), 30)];
+      [showHide setOn:(PView::list[i]->getOptions()->visible == 1)];
+      [showHide setTag:i];
+      [showHide addTarget:self action:@selector(PViewVisible:) forControlEvents:UIControlEventValueChanged];
+      [lbl setBackgroundColor: [UIColor clearColor]];
+      [lbl setText:[NSString stringWithCString:PView::list[i]->getData()->getName().c_str() encoding:[NSString defaultCStringEncoding]]];
+      [cell addSubview:showHide];
+      [cell addSubview:lbl];
     }
-    return cell;
+    break;
+  }
+  return cell;
 }
 
 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    if(indexPath.section != 1) return;
-    UIStoryboard *storyboard;
-    if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"])
-        storyboard = [UIStoryboard storyboardWithName:@"iPadStoryboard" bundle:nil];
-    else
-        storyboard = [UIStoryboard storyboardWithName:@"iPhoneiPodStoryboard" bundle:nil];
-    PostProcessingViewController *postPro = [storyboard instantiateViewControllerWithIdentifier:@"PostProcessingViewController"];
-    [postPro setPView:PView::list[[tableView numberOfRowsInSection:1]-1- indexPath.row]];
-    [self.navigationController pushViewController:postPro animated:YES];
+  if(indexPath.section != 1) return;
+  UIStoryboard *storyboard;
+  if([[UIDevice currentDevice].model isEqualToString:@"iPad"] || [[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"])
+    storyboard = [UIStoryboard storyboardWithName:@"iPadStoryboard" bundle:nil];
+  else
+    storyboard = [UIStoryboard storyboardWithName:@"iPhoneiPodStoryboard" bundle:nil];
+  PostProcessingViewController *postPro = [storyboard instantiateViewControllerWithIdentifier:@"PostProcessingViewController"];
+  [postPro setPView:PView::list[[tableView numberOfRowsInSection:1]-1- indexPath.row]];
+  [self.navigationController pushViewController:postPro animated:YES];
 }
 
 - (void)setShowGeomPoints:(UISwitch*)sender
 {
-    CTX::instance()->geom.points = sender.on;
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  CTX::instance()->geom.points = sender.on;
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
 - (void)setShowGeomLines:(UISwitch*)sender
 {
-    CTX::instance()->geom.lines = sender.on;
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  CTX::instance()->geom.lines = sender.on;
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
 - (void)setShowMeshVolumesEdges:(UISwitch*)sender
 {
-    CTX::instance()->mesh.volumesEdges = sender.on;
-    CTX::instance()->mesh.changed = ENT_VOLUME;
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  CTX::instance()->mesh.volumesEdges = sender.on;
+  CTX::instance()->mesh.changed = ENT_VOLUME;
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
 - (void)setShowMeshSurfacesEdges:(UISwitch*)sender
 {
-    CTX::instance()->mesh.surfacesEdges = sender.on;
-    CTX::instance()->mesh.changed = ENT_SURFACE;
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  CTX::instance()->mesh.surfacesEdges = sender.on;
+  CTX::instance()->mesh.changed = ENT_SURFACE;
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
 -(IBAction)PViewVisible:(id)sender
 {
-    PView::list[((UISwitch*)sender).tag]->getOptions()->visible = (((UISwitch*)sender).on)? 1 : 0;
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  PView::list[((UISwitch*)sender).tag]->getOptions()->visible = (((UISwitch*)sender).on)? 1 : 0;
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
 
 #pragma mark - textfield
 
 -(BOOL)textFieldShouldEndEditing:(UITextField *)textField
 {
-    NSInteger val = [textField.text integerValue];
-    val = (val > 0)? val : 1;
-    val = (val < 1000)? val : 1000;
-    [textField setText:[NSString stringWithFormat:@"%d",val]];
-    PView::list[textField.tag]->getOptions()->nbIso = val;
-    PView::list[textField.tag]->setChanged(true);
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
-    return YES;
+  NSInteger val = [textField.text integerValue];
+  val = (val > 0)? val : 1;
+  val = (val < 1000)? val : 1000;
+  [textField setText:[NSString stringWithFormat:@"%d",val]];
+  PView::list[textField.tag]->getOptions()->nbIso = val;
+  PView::list[textField.tag]->setChanged(true);
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  return YES;
 }
 -(BOOL)textFieldShouldReturn:(UITextField *)textField
 {
-    [textField endEditing:YES];
-    return YES;
+  [textField endEditing:YES];
+  return YES;
 }
 
 @end
diff --git a/contrib/mobile/iOS/Onelab/Parameter.h b/contrib/mobile/iOS/Onelab/Parameter.h
index d226ef2..6fd94df 100644
--- a/contrib/mobile/iOS/Onelab/Parameter.h
+++ b/contrib/mobile/iOS/Onelab/Parameter.h
@@ -1,11 +1,3 @@
-//
-//  parameter.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 07/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <Foundation/Foundation.h>
 #import <Gmsh/onelab.h>
 
@@ -13,9 +5,9 @@
 
 @interface Parameter : NSObject
 {
-    @protected
-    NSString *name;
-    UILabel *label;
+ at protected
+  NSString *name;
+  UILabel *label;
 }
 -(id)init;
 -(void)setFrame:(CGRect)frame;
@@ -29,18 +21,17 @@
 
 @interface ParameterStringList : Parameter <UIActionSheetDelegate>
 {
-    @protected
-    UIButton *button;
+ at protected
+  UIButton *button;
 }
 -(id)initWithString:(onelab::string)string;
 -(UIPickerView *)getUIView;
 @end
 
-
 @interface ParameterNumberList : Parameter <UIActionSheetDelegate>
 {
-    @protected
-	UIButton *button;
+ at protected
+  UIButton *button;
 }
 -(id)initWithNumber:(onelab::number)number;
 -(UITextField *)getUIView;
@@ -48,17 +39,26 @@
 
 @interface ParameterNumberCheckbox : Parameter
 {
-    @protected
-    UISwitch *checkbox;
+ at protected
+  UISwitch *checkbox;
 }
 -(id)initWithNumber:(onelab::number)number;
 -(UISwitch *)getCheckbox;
 @end
 
+ at interface ParameterNumberStepper : Parameter
+{
+ at protected
+  UIStepper *stepper;
+}
+-(id)initWithNumber:(onelab::number)number;
+-(UIStepper *)getStepper;
+ at end
+
 @interface ParameterNumberRange : Parameter
 {
-    @protected
-    UISlider *slider;
+ at protected
+  UISlider *slider;
 }
 -(id)initWithNumber:(onelab::number)number;
 -(UISlider *)getSlider;
@@ -67,7 +67,7 @@
 @interface ParameterNumberTextbox : Parameter <UITextFieldDelegate>
 {
 @protected
-    UITextField *textbox;
+  UITextField *textbox;
 }
 -(id)initWithNumber:(onelab::number)number;
 -(UITextField *)getTextbox;
diff --git a/contrib/mobile/iOS/Onelab/Parameter.mm b/contrib/mobile/iOS/Onelab/Parameter.mm
index be8d85c..b487416 100644
--- a/contrib/mobile/iOS/Onelab/Parameter.mm
+++ b/contrib/mobile/iOS/Onelab/Parameter.mm
@@ -1,363 +1,451 @@
-//
-//  parameter.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 07/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import "parameter.h"
 
 @implementation Parameter
 -(id)init
 {
-    self = [super init];
-    if(self)
-    {
-        label = [[UILabel alloc] init];
-        [label setBackgroundColor:[UIColor clearColor]];
-    }
-    return self;
+  self = [super init];
+  if(self) {
+    label = [[UILabel alloc] init];
+    [label setBackgroundColor:[UIColor clearColor]];
+  }
+  return self;
 }
+
 -(void)refresh
 {
-	return;
+  return;
 }
+
 -(NSString *)getName
 {
-    return name;
+  return name;
 }
+
 -(UILabel *)getLabel
 {
-    return label;
+  return label;
 }
+
 -(void)setFrame:(CGRect)frame
 {
-    return;
+  return;
 }
+
 -(void)setLabelFrame:(CGRect)frame
 {
-    [label setFrame:frame];
+  [label setFrame:frame];
 }
--(bool)isReadOnly
+
+-(void)editValue
 {
-    return NO;
+  if(onelab_cb("check") == 1){
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+    [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshParameters" object:nil];
+  }
 }
+
+-(bool) isReadOnly {return NO;}
+
 +(double)getHeight
 {
-    return 60.0f;
+  return 60.0f;
 }
 @end
 
 @implementation ParameterStringList
 -(id) initWithString:(onelab::string)string
 {
-    self = [super init];
-    if(self)
-    {
-        label.alpha = (string.getReadOnly())? 0.439216f : 1.0f;
-        [label setText:[NSString stringWithCString:string.getShortName().c_str() encoding:[NSString defaultCStringEncoding]]];
-        name = [NSString stringWithCString:string.getName().c_str() encoding:[NSString defaultCStringEncoding]];
-        button = [UIButton buttonWithType:UIButtonTypeSystem];
-		[button addTarget:self action:@selector(selectValue) forControlEvents:UIControlEventTouchDown];
-        [button setTitle:[NSString stringWithFormat:@"%s", string.getValue().c_str()] forState:UIControlStateNormal];
-    }
-    return self;
+  self = [super init];
+  if(self){
+    label.alpha = (string.getReadOnly())? 0.439216f : 1.0f;
+    [label setText:[NSString stringWithCString:string.getShortName().c_str() encoding:[NSString defaultCStringEncoding]]];
+    name = [NSString stringWithCString:string.getName().c_str() encoding:[NSString defaultCStringEncoding]];
+    button = [UIButton buttonWithType:UIButtonTypeSystem];
+    [button addTarget:self action:@selector(selectValue) forControlEvents:UIControlEventTouchDown];
+    [button setTitle:[NSString stringWithFormat:@"%s", string.getValue().c_str()] forState:UIControlStateNormal];
+  }
+  return self;
 }
+
 -(void)selectValue
 {
-	std::vector<onelab::string> string;
-    onelab::server::instance()->get(string,[name UTF8String]);
-    if(string.size() < 1) return;
-	UIActionSheet *popupSelectValue = [[UIActionSheet alloc] initWithTitle:[NSString stringWithFormat:@"%s", string[0].getLabel().c_str()] delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
-	std::vector<std::string> choices = string[0].getChoices();
-	for(int i=0;i<choices.size();i++)
-		[popupSelectValue addButtonWithTitle:[NSString stringWithFormat:@"%s", choices[i].c_str()]];
-	[popupSelectValue showInView:button];
+  std::vector<onelab::string> string;
+  onelab::server::instance()->get(string,[name UTF8String]);
+  if(string.size() < 1) return;
+  UIActionSheet *popupSelectValue = [[UIActionSheet alloc] initWithTitle:[NSString stringWithFormat:@"%s", string[0].getLabel().c_str()] delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
+  std::vector<std::string> choices = string[0].getChoices();
+  for(int i=0;i<choices.size();i++)
+    [popupSelectValue addButtonWithTitle:[NSString stringWithFormat:@"%s", choices[i].c_str()]];
+  [popupSelectValue addButtonWithTitle:@"Cancel"];
+  [popupSelectValue setCancelButtonIndex:popupSelectValue.numberOfButtons - 1];
+  [popupSelectValue showInView:button];
 }
+
 -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
 {
-	std::vector<onelab::string> string;
-    onelab::server::instance()->get(string,[name UTF8String]);
-    if(string.size() < 1) return;
-    std::string selected = string[0].getChoices()[buttonIndex];
-    string[0].setValue(selected);
-    onelab::server::instance()->set(string[0]);
-    if(onelab_cb("check") == 1)
-        [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  std::vector<onelab::string> string;
+  onelab::server::instance()->get(string,[name UTF8String]);
+  if(string.size() < 1) return;
+  if(buttonIndex > string[0].getChoices().size() - 1) return; // cancel
+  std::string selected = string[0].getChoices()[buttonIndex];
+  string[0].setValue(selected);
+  onelab::server::instance()->set(string[0]);
+  [super editValue];
 }
+
 -(void)refresh
 {
-	std::vector<onelab::string> string;
-    onelab::server::instance()->get(string,[name UTF8String]);
-	[button setTitle:[NSString stringWithFormat:@"%s", string[0].getValue().c_str()] forState:UIControlStateNormal];
+  std::vector<onelab::string> string;
+  onelab::server::instance()->get(string,[name UTF8String]);
+  [button setTitle:[NSString stringWithFormat:@"%s", string[0].getValue().c_str()] forState:UIControlStateNormal];
 }
+
 -(void)setFrame:(CGRect)frame
 {
-    [button setFrame:frame];
+  [button setFrame:frame];
 }
+
 -(UIButton *)getUIView
 {
-    return button;
+  return button;
 }
+
 -(bool)isReadOnly
 {
-    std::vector<onelab::string> string;
-    onelab::server::instance()->get(string,[name UTF8String]);
-    if(string.size() < 1) return YES;
-    return string[0].getReadOnly();
+  std::vector<onelab::string> string;
+  onelab::server::instance()->get(string,[name UTF8String]);
+  if(string.size() < 1) return YES;
+  return string[0].getReadOnly();
 }
+
 +(double)getHeight
 {
-    return 60.f;
+  return 60.f;
 }
 @end
 
 @implementation ParameterNumberList
 -(id) initWithNumber:(onelab::number) number
 {
-    self = [super init];
-    if(self)
-    {
-        label.alpha = (number.getReadOnly())? 0.439216f : 1.0f;
-        [label setText:[NSString stringWithCString:number.getShortName().c_str() encoding:[NSString defaultCStringEncoding]]];
-        name = [NSString stringWithCString:number.getName().c_str() encoding:[NSString defaultCStringEncoding]];
-		button = [UIButton buttonWithType:UIButtonTypeSystem];
-		[button addTarget:self action:@selector(selectValue) forControlEvents:UIControlEventTouchDown];
-        [button setTitle:[NSString stringWithFormat:@"%s", number.getValueLabel(number.getValue()).c_str()] forState:UIControlStateNormal];
-    }
-    return self;
+  self = [super init];
+  if(self) {
+    label.alpha = (number.getReadOnly())? 0.439216f : 1.0f;
+    [label setText:[NSString stringWithCString:number.getShortName().c_str() encoding:[NSString defaultCStringEncoding]]];
+    name = [NSString stringWithCString:number.getName().c_str() encoding:[NSString defaultCStringEncoding]];
+    button = [UIButton buttonWithType:UIButtonTypeSystem];
+    [button addTarget:self action:@selector(selectValue) forControlEvents:UIControlEventTouchDown];
+    [button setTitle:[NSString stringWithFormat:@"%s", number.getValueLabel(number.getValue()).c_str()] forState:UIControlStateNormal];
+  }
+  return self;
 }
+
 -(void)selectValue
 {
-	std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return;
-	UIActionSheet *popupSelectValue = [[UIActionSheet alloc] initWithTitle:[NSString stringWithFormat:@"%s", number[0].getLabel().c_str()] delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
-	std::vector<double> choices = number[0].getChoices();
-	for(int i=0;i<choices.size();i++)
-		[popupSelectValue addButtonWithTitle:[NSString stringWithFormat:@"%s", number[0].getValueLabel(choices[i]).c_str()]];
-	[popupSelectValue showInView:button];
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return;
+  UIActionSheet *popupSelectValue = [[UIActionSheet alloc] initWithTitle:[NSString stringWithFormat:@"%s", number[0].getLabel().c_str()] delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
+  std::vector<double> choices = number[0].getChoices();
+  for(int i=0;i<choices.size();i++)
+    [popupSelectValue addButtonWithTitle:[NSString stringWithFormat:@"%s", number[0].getValueLabel(choices[i]).c_str()]];
+  [popupSelectValue addButtonWithTitle:@"Cancel"];
+  [popupSelectValue setCancelButtonIndex:popupSelectValue.numberOfButtons - 1];
+  [popupSelectValue showInView:button];
 }
+
 -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
 {
-	std::vector<onelab::number> number;
-	onelab::server::instance()->get(number,[name UTF8String]);
-	if(number.size() < 1) return;
-	double selected = number[0].getChoices()[buttonIndex];
-	number[0].setValue(selected);
-	onelab::server::instance()->set(number[0]);
-	[button setTitle:[NSString stringWithFormat:@"%s", number[0].getValueLabel(number[0].getValue()).c_str()] forState:UIControlStateNormal];
-	if(onelab_cb("check") == 1)
-		[[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return;
+  if(buttonIndex > number[0].getChoices().size() - 1) return; // cancel
+  double selected = number[0].getChoices()[buttonIndex];
+  number[0].setValue(selected);
+  onelab::server::instance()->set(number[0]);
+  [button setTitle:[NSString stringWithFormat:@"%s", number[0].getValueLabel(number[0].getValue()).c_str()] forState:UIControlStateNormal];
+  [super editValue];
 }
+
 -(void)refresh
 {
-	std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-	[button setTitle:[NSString stringWithFormat:@"%s", number[0].getValueLabel(number[0].getValue()).c_str()] forState:UIControlStateNormal];
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  [button setTitle:[NSString stringWithFormat:@"%s", number[0].getValueLabel(number[0].getValue()).c_str()] forState:UIControlStateNormal];
 }
+
 -(void)setFrame:(CGRect)frame
 {
-    [button setFrame:frame];
+  [button setFrame:frame];
 }
+
 -(UIButton *)getUIView
 {
-	return button;
+  return button;
 }
+
 -(bool)isReadOnly
 {
-    std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return YES;
-    return number[0].getReadOnly();
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return YES;
+  return number[0].getReadOnly();
 }
+
 +(double)getHeight
 {
-    return 60.f;
+  return 60.f;
 }
 @end
 
 @implementation ParameterNumberCheckbox
 -(id) initWithNumber:(onelab::number) number
 {
-    self = [super init];
-    if(self)
-    {
-        label.alpha = (number.getReadOnly())? 0.439216f : 1.0f;
-        [label setText:[NSString stringWithCString:number.getShortName().c_str() encoding:[NSString defaultCStringEncoding]]];
-        name = [NSString stringWithCString:number.getName().c_str() encoding:[NSString defaultCStringEncoding]];
-        checkbox = [[UISwitch alloc] init];
-        [checkbox setOn:(number.getValue() == 1)];
-        [checkbox addTarget:self action:@selector(valueChange:) forControlEvents:UIControlEventValueChanged];
-    }
-    return self;
+  self = [super init];
+  if(self) {
+    label.alpha = (number.getReadOnly())? 0.439216f : 1.0f;
+    [label setText:[NSString stringWithCString:number.getShortName().c_str() encoding:[NSString defaultCStringEncoding]]];
+    name = [NSString stringWithCString:number.getName().c_str() encoding:[NSString defaultCStringEncoding]];
+    checkbox = [[UISwitch alloc] init];
+    [checkbox setOn:(number.getValue() == 1)];
+    [checkbox addTarget:self action:@selector(valueChange:) forControlEvents:UIControlEventValueChanged];
+  }
+  return self;
 }
+
 -(void)refresh
 {
-	std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    [checkbox setSelected:(number[0].getValue() == 1)];
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  [checkbox setSelected:(number[0].getValue() == 1)];
 }
+
 -(void) valueChange:(UISwitch *)sender
 {
-    std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return;
-    number[0].setValue(([sender isOn])? 1 : 0);
-    onelab::server::instance()->set(number[0]);
-    if(onelab_cb("check") == 1)
-        [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return;
+  number[0].setValue(([sender isOn])? 1 : 0);
+  onelab::server::instance()->set(number[0]);
+  [super editValue];
 }
+
 -(void)setFrame:(CGRect)frame
 {
-    [checkbox setFrame:frame];
+  [checkbox setFrame:frame];
 }
+
 -(UISwitch *)getCheckbox
 {
-    return checkbox;
+  return checkbox;
 }
+
 -(bool)isReadOnly
 {
-    std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return YES;
-    return number[0].getReadOnly();
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return YES;
+  return number[0].getReadOnly();
 }
+
 +(double)getHeight
 {
-    return 40.0f;
+  return 40.0f;
+}
+ at end
+
+ at implementation ParameterNumberStepper
+-(id) initWithNumber:(onelab::number) number
+{
+  self = [super init];
+  if(self) {
+    name = [NSString stringWithCString:number.getName().c_str() encoding:[NSString defaultCStringEncoding]];
+    label.alpha = (number.getReadOnly())? 0.439216f : 1.0f;
+    stepper = [[UIStepper alloc] init];
+    [stepper setValue:number.getValue()];
+    [stepper setStepValue:1];
+    [stepper setMaximumValue:number.getMax()];
+    [stepper setMinimumValue:number.getMin()];
+    [stepper addTarget:self action:@selector(stepperValueChanged:) forControlEvents:UIControlEventValueChanged];
+    [label setText:[NSString stringWithFormat:@"%s %d" ,number.getShortName().c_str(), (int)number.getValue()]];
+  }
+  return self;
+}
+
+-(void)stepperValueChanged:(UIStepper *)sender
+{
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return;
+  number[0].setValue(sender.value);
+  onelab::server::instance()->set(number[0]);
+  [label setText:[NSString stringWithFormat:@"%s %d" ,number[0].getShortName().c_str(), (int)number[0].getValue()]];
+  [super editValue];
+}
+
+-(void)refresh
+{
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return;
+  [stepper setValue:number[0].getValue()];
+  [label setText:[NSString stringWithFormat:@"%s %d" ,number[0].getShortName().c_str(), (int)number[0].getValue()]];
+}
+
+-(void)setFrame:(CGRect)frame
+{
+  [stepper setFrame:frame];
+}
+
+-(UIStepper *)getStepper
+{
+  return stepper;
+}
+
++(double)getHeight
+{
+  return 60.0f;
 }
 @end
 
 @implementation ParameterNumberRange
 -(id) initWithNumber:(onelab::number) number
 {
-    self = [super init];
-    if(self)
-    {
-        label.alpha = (number.getReadOnly())? 0.439216f : 1.0f;
-        name = [NSString stringWithCString:number.getName().c_str() encoding:[NSString defaultCStringEncoding]];
-        slider = [[UISlider alloc] init];
-        [slider setMaximumValue:number.getMax()];
-        [slider setMinimumValue:number.getMin()];
-        [slider setValue:number.getValue()];
-        //TODO add step ?
-        [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventTouchUpOutside];
-        [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventTouchUpInside];
-        [label setText:[NSString stringWithFormat:@"%@ %f" ,[NSString stringWithCString:number.getShortName().c_str() encoding:[NSString defaultCStringEncoding]], number.getValue()]];
-    }
-    return self;
+  self = [super init];
+  if(self) {
+    label.alpha = (number.getReadOnly())? 0.439216f : 1.0f;
+    name = [NSString stringWithCString:number.getName().c_str() encoding:[NSString defaultCStringEncoding]];
+    slider = [[UISlider alloc] init];
+    [slider setMaximumValue:number.getMax()];
+    [slider setMinimumValue:number.getMin()];
+    [slider setValue:number.getValue()];
+    //TODO add step ?
+    [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventTouchUpOutside];
+    [slider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventTouchUpInside];
+    [label setText:[NSString stringWithFormat:@"%@ %g", [NSString stringWithCString:number.getShortName().c_str() encoding:[NSString defaultCStringEncoding]], number.getValue()]];
+  }
+  return self;
 }
+
 -(void)refresh
 {
-	std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return;
-	[slider setMaximumValue:number[0].getMax()];
-	[slider setMinimumValue:number[0].getMin()];
-	[slider setValue:number[0].getValue()];
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return;
+  [slider setMaximumValue:number[0].getMax()];
+  [slider setMinimumValue:number[0].getMin()];
+  [slider setValue:number[0].getValue()];
+  [label setText:[NSString stringWithFormat:@"%@ %g", [NSString stringWithCString:number[0].getShortName().c_str() encoding:[NSString defaultCStringEncoding]], number[0].getValue()]];
 }
+
 -(void)sliderValueChanged:(UISlider *)sender
 {
-    std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return;
-    number[0].setValue(sender.value);
-    onelab::server::instance()->set(number[0]);
-    [label setText:[NSString stringWithFormat:@"%s %f" ,number[0].getShortName().c_str(), number[0].getValue()]];
-    if(onelab_cb("check") == 1)
-        [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return;
+  number[0].setValue(sender.value);
+  onelab::server::instance()->set(number[0]);
+  [label setText:[NSString stringWithFormat:@"%s %g" ,number[0].getShortName().c_str(), number[0].getValue()]];
+  [super editValue];
 }
+
 -(void)setFrame:(CGRect)frame
 {
-    [slider setFrame:frame];
+  [slider setFrame:frame];
 }
+
 -(UISlider *)getSlider
 {
-    return slider;
+  return slider;
 }
+
 -(bool)isReadOnly
 {
-    std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return YES;
-    return number[0].getReadOnly();
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return YES;
+  return number[0].getReadOnly();
 }
+
 +(double)getHeight
 {
-    return 60.0f;
+  return 60.0f;
 }
 @end
 
 @implementation ParameterNumberTextbox
 -(id)initWithNumber:(onelab::number)number
 {
-    self = [super init];
-    if(self)
-    {
-        label.alpha = (number.getReadOnly())? 0.439216f : 1.0f;
-        [label setText:[NSString stringWithCString:number.getShortName().c_str() encoding:[NSString defaultCStringEncoding]]];
-        name = [NSString stringWithCString:number.getName().c_str() encoding:[NSString defaultCStringEncoding]];
-        textbox = [[UITextField alloc] init];
-        [textbox setBorderStyle:UITextBorderStyleRoundedRect];
-        [textbox setKeyboardType:UIKeyboardTypeNumberPad];
-        [textbox setText:[NSString stringWithFormat:@"%f", number.getValue()]];
-        [textbox setDelegate:self];
-        UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
-        numberToolbar.barStyle = UIBarStyleBlackTranslucent;
-        numberToolbar.items = [NSArray arrayWithObjects:
-                               [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
-                               [[UIBarButtonItem alloc]initWithTitle:@"Apply" style:UIBarButtonItemStyleDone target:self action:@selector(doneWithNumberPad)],
-                               nil];
-        [numberToolbar sizeToFit];
-        textbox.inputAccessoryView = numberToolbar;
-    }
-    return self;
+  self = [super init];
+  if(self) {
+    label.alpha = (number.getReadOnly())? 0.439216f : 1.0f;
+    [label setText:[NSString stringWithCString:number.getShortName().c_str() encoding:[NSString defaultCStringEncoding]]];
+    name = [NSString stringWithCString:number.getName().c_str() encoding:[NSString defaultCStringEncoding]];
+    textbox = [[UITextField alloc] init];
+    [textbox setBorderStyle:UITextBorderStyleRoundedRect];
+    [textbox setText:[NSString stringWithFormat:@"%g", number.getValue()]];
+    [textbox setDelegate:self];
+    UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
+    numberToolbar.items = [NSArray arrayWithObjects:
+                                     [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
+                                   [[UIBarButtonItem alloc]initWithTitle:@"Apply" style:UIBarButtonItemStyleDone target:self action:@selector(doneWithNumberPad)],
+                                   nil];
+    [numberToolbar sizeToFit];
+    textbox.inputAccessoryView = numberToolbar;
+  }
+  return self;
 }
+
 -(void)refresh
 {
-	std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return;
-	[textbox setText:[NSString stringWithFormat:@"%f", number[0].getValue()]];
-	[textbox reloadInputViews];
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return;
+  [textbox setText:[NSString stringWithFormat:@"%g", number[0].getValue()]];
+  [textbox reloadInputViews];
 }
+
 -(BOOL)textFieldShouldEndEditing:(UITextField *)textField
 {
-    std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return YES;
-    number[0].setValue([textField.text doubleValue]);
-    onelab::server::instance()->set(number[0]);
-	[textField setText:[NSString stringWithFormat:@"%f", number[0].getValue()]];
-    return YES;
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return YES;
+  number[0].setValue([textField.text doubleValue]);
+  onelab::server::instance()->set(number[0]);
+  [textField setText:[NSString stringWithFormat:@"%g", number[0].getValue()]];
+  [super editValue];
+  return YES;
 }
+
 -(BOOL)textFieldShouldReturn:(UITextField *)textField
 {
-    return [textField endEditing:YES];
+  return [textField endEditing:YES];
 }
+
 -(void)doneWithNumberPad
 {
-    [textbox endEditing:YES];
+  [textbox endEditing:YES];
 }
+
 -(void)setFrame:(CGRect)frame
 {
-    [textbox setFrame:frame];
+  [textbox setFrame:frame];
 }
+
 -(UITextField *)getTextbox
 {
-    return textbox;
+  return textbox;
 }
+
 -(bool)isReadOnly
 {
-    std::vector<onelab::number> number;
-    onelab::server::instance()->get(number,[name UTF8String]);
-    if(number.size() < 1) return YES;
-    return number[0].getReadOnly();
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() < 1) return YES;
+  return number[0].getReadOnly();
 }
+
 +(double)getHeight
 {
-    return 60.f;
+  return 60.f;
 }
 @end
diff --git a/contrib/mobile/iOS/Onelab/ParametersViewController.h b/contrib/mobile/iOS/Onelab/ParametersViewController.h
index d21a964..0589462 100644
--- a/contrib/mobile/iOS/Onelab/ParametersViewController.h
+++ b/contrib/mobile/iOS/Onelab/ParametersViewController.h
@@ -1,11 +1,3 @@
-//
-//  MasterViewController.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 08/04/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <UIKit/UIKit.h>
 #import <Gmsh/onelab.h>
 
@@ -20,7 +12,7 @@
 
     UIBarButtonItem *runButton;
     UIBarButtonItem *stopButton;
-	
+
 	UISegmentedControl *control;
 }
 
diff --git a/contrib/mobile/iOS/Onelab/ParametersViewController.mm b/contrib/mobile/iOS/Onelab/ParametersViewController.mm
index d29af62..ea269e9 100644
--- a/contrib/mobile/iOS/Onelab/ParametersViewController.mm
+++ b/contrib/mobile/iOS/Onelab/ParametersViewController.mm
@@ -1,11 +1,3 @@
-//
-//  MasterViewController.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 08/04/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import "ParametersViewController.h"
 #import "ModelViewController.h"
 #import "OptionsViewController.h"
@@ -21,298 +13,377 @@
 
 - (void)awakeFromNib
 {
-    self.clearsSelectionOnViewWillAppear = NO;
-    self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
-    [super awakeFromNib];
+  self.clearsSelectionOnViewWillAppear = NO;
+  self.preferredContentSize = CGSizeMake(320.0, 600.0);
+  [super awakeFromNib];
 }
 
 - (void)viewDidLoad
 {
-    [super viewDidLoad];
-
-	// Do any additional setup after loading the view, typically from a nib.
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshParameters:) name:@"refreshParameters" object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetParameters:) name:@"resetParameters" object:nil];
-
-	self.navigationItem.title = @"Model";
-    
-    _sections = [[NSMutableArray alloc] init];
-    _sectionstitle = [[NSMutableArray alloc] init];
-	
-	[self.navigationController setToolbarHidden:NO];
-	control = [[UISegmentedControl alloc] initWithItems:[[NSArray alloc] initWithObjects:@"Model", @"Display", nil]];
-	control.segmentedControlStyle = UISegmentedControlStyleBar;
-	UIBarButtonItem *controlBtn = [[UIBarButtonItem alloc] initWithCustomView:control];
-	UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
-	self.toolbarItems = [[NSArray alloc] initWithObjects:flexibleSpace, controlBtn, flexibleSpace, nil];
-	[control addTarget:self action:@selector(indexDidChangeForSegmentedControl:) forControlEvents:UIControlEventValueChanged];
-	if(![[UIDevice currentDevice].model isEqualToString:@"iPad"] && ![[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]){
-        self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self action:@selector(backButtonPressed:)];
-    }
-	self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Reset" style:UIBarButtonItemStyleBordered target:self action:@selector(resetParameters:)];
+  [super viewDidLoad];
+
+  // Do any additional setup after loading the view, typically from a nib.
+  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshParameters:) name:@"refreshParameters" object:nil];
+  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetParameters:) name:@"resetParameters" object:nil];
+
+  self.navigationItem.title = @"Model";
+
+  _sections = [[NSMutableArray alloc] init];
+  _sectionstitle = [[NSMutableArray alloc] init];
+
+  UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
+  lpgr.minimumPressDuration = 1.0;
+  [self.tableView addGestureRecognizer:lpgr];
+
+  [self.navigationController setToolbarHidden:NO];
+  control = [[UISegmentedControl alloc] initWithItems:[[NSArray alloc] initWithObjects:@"Model", @"Display", nil]];
+  UIBarButtonItem *controlBtn = [[UIBarButtonItem alloc] initWithCustomView:control];
+  UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
+  self.toolbarItems = [[NSArray alloc] initWithObjects:flexibleSpace, controlBtn, flexibleSpace, nil];
+  [control addTarget:self action:@selector(indexDidChangeForSegmentedControl:) forControlEvents:UIControlEventValueChanged];
+  if(![[UIDevice currentDevice].model isEqualToString:@"iPad"] && ![[UIDevice currentDevice].model isEqualToString:@"iPad Simulator"]){
+    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self action:@selector(backButtonPressed:)];
+  }
+  self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Reset" style:UIBarButtonItemStyleBordered target:self action:@selector(resetParameters:)];
 }
+
 - (void)viewWillAppear:(BOOL)animated
 {
-    [self refreshParameters:nil];
-	control.selectedSegmentIndex = 0;
-	[super viewWillAppear:animated];
+  [self refreshParameters:nil];
+  control.selectedSegmentIndex = 0;
+  [super viewWillAppear:animated];
 }
 
 -(void)backButtonPressed:(id)sender
 {
-    [self.navigationController popViewControllerAnimated:YES];
+  [self.navigationController popViewControllerAnimated:YES];
+}
+
+-(void)handleLongPress:(UILongPressGestureRecognizer *)sender
+{
+  CGPoint p = [sender locationInView:self.tableView];
+  if(sender.state == UIGestureRecognizerStateCancelled) return;
+  NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
+  if(!indexPath) return;
+  NSMutableArray* section = [_sections objectAtIndex:indexPath.section];
+  if(!section) return;
+  Parameter * parameter = [section objectAtIndex:indexPath.row];
+  if(!parameter) return;
+  NSString *name = [parameter getName];
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[name UTF8String]);
+  if(number.size() && !number[0].getReadOnly()){
+    NSLog(@"Manual edit of parameter '%s' with value '%g'", number[0].getName().c_str(), number[0].getValue());
+    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:@"%s", number[0].getShortName().c_str()] message:name delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
+    alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
+    [alertView textFieldAtIndex:0].text = [NSString stringWithFormat:@"%g", number[0].getValue()];
+    [alertView show];
+  }
+}
+
+-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
+{
+  NSLog(@"%@ -> %@", [alertView message], [alertView textFieldAtIndex:0].text);
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number,[[alertView message] UTF8String]);
+  if(number.size()){
+    double value = [[alertView textFieldAtIndex:0].text doubleValue];
+    number[0].setValue(value);
+    onelab::server::instance()->set(number[0]);
+    if(onelab_cb("check") == 1){
+      [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+      [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshParameters" object:nil];
+    }
+  }
 }
 
 - (void)indexDidChangeForSegmentedControl:(id)sender
 {
-	OptionsViewController *optionsViewController = [[OptionsViewController alloc] init];
-	[self.navigationController pushViewController:optionsViewController animated:YES];
+  OptionsViewController *optionsViewController = [[OptionsViewController alloc] init];
+  [self.navigationController pushViewController:optionsViewController animated:YES];
 }
+
 - (void)addParameterNumber:(onelab::number)p atIndexPath:(NSIndexPath*)indexPath
 {
-	NSMutableArray* section = [_sections objectAtIndex:indexPath.section];
-	if(p.getChoices().size() && p.getChoices().size() == p.getValueLabels().size()) { // enumeration
-        ParameterNumberList *param = [[ParameterNumberList alloc] initWithNumber:p];
-        [section addObject:param];
-    }
-    else if(p.getChoices().size() == 2 && p.getChoices()[0] == 0 && p.getChoices()[1] == 1) { // check box
-        ParameterNumberCheckbox *param = [[ParameterNumberCheckbox alloc] initWithNumber:p];
-        [section addObject:param];
-    }
-    else if(p.getStep() == 0) { // text box
-        ParameterNumberTextbox *param = [[ParameterNumberTextbox alloc] initWithNumber:p];
-        [section addObject:param];
-    }
-    else
-    {
-        ParameterNumberRange *param = [[ParameterNumberRange alloc] initWithNumber:p];
-        [section addObject:param];
-    }
-	[self.tableView beginUpdates];
-	[self.tableView insertRowsAtIndexPaths:[[NSArray alloc] initWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationAutomatic];
-	[self.tableView endUpdates];
+  NSMutableArray* section = [_sections objectAtIndex:indexPath.section];
+  if(p.getChoices().size() && p.getChoices().size() == p.getValueLabels().size()) { // enumeration
+    ParameterNumberList *param = [[ParameterNumberList alloc] initWithNumber:p];
+    [section addObject:param];
+  }
+  else if(p.getChoices().size() == 2 && p.getChoices()[0] == 0 && p.getChoices()[1] == 1) { // check box
+    ParameterNumberCheckbox *param = [[ParameterNumberCheckbox alloc] initWithNumber:p];
+    [section addObject:param];
+  }
+  else if(p.getStep() == 1) { // stepper
+    ParameterNumberStepper *param = [[ParameterNumberStepper alloc] initWithNumber:p];
+    [section addObject:param];
+  }
+  else if(p.getMin() >= p.getMax() ||
+          p.getMin() == -onelab::number::maxNumber() ||
+          p.getMax() == onelab::number::maxNumber() ||
+          p.getReadOnly()) { // text box
+    ParameterNumberTextbox *param = [[ParameterNumberTextbox alloc] initWithNumber:p];
+    [section addObject:param];
+  }
+  else { // slider
+    ParameterNumberRange *param = [[ParameterNumberRange alloc] initWithNumber:p];
+    [section addObject:param];
+  }
+  [self.tableView beginUpdates];
+  [self.tableView insertRowsAtIndexPaths:[[NSArray alloc] initWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationAutomatic];
+  [self.tableView endUpdates];
 }
+
 - (void)addParameterString:(onelab::string)p atIndexPath:(NSIndexPath*)indexPath
 {
-	NSMutableArray* section = [_sections objectAtIndex:indexPath.section];
-	ParameterStringList *param = [[ParameterStringList alloc] initWithString:p];
-    [section addObject:param];
-	[self.tableView beginUpdates];
-	[self.tableView insertRowsAtIndexPaths:[[NSArray alloc] initWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationAutomatic];
-	[self.tableView endUpdates];
+  NSMutableArray* section = [_sections objectAtIndex:indexPath.section];
+  ParameterStringList *param = [[ParameterStringList alloc] initWithString:p];
+  [section addObject:param];
+  [self.tableView beginUpdates];
+  [self.tableView insertRowsAtIndexPaths:[[NSArray alloc] initWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationAutomatic];
+  [self.tableView endUpdates];
 }
-- (void)removeParemeterNumber:(onelab::number)p atIndex:(NSIndexPath*)index
+
+- (void)removeParemeterNumberAtIndex:(NSIndexPath*)index
 {
-	[self.tableView beginUpdates];
-	[self.tableView deleteRowsAtIndexPaths: [NSArray arrayWithObject:index] withRowAnimation:UITableViewRowAnimationAutomatic];
-	[self.tableView endUpdates];
+  [self.tableView beginUpdates];
+  [self.tableView deleteRowsAtIndexPaths: [NSArray arrayWithObject:index] withRowAnimation:UITableViewRowAnimationAutomatic];
+  [self.tableView endUpdates];
 }
+
 - (void)addSection:(NSMutableArray*)s withTitle:(NSString*)t withParameterNumber:(onelab::number)p
 {
-	[_sections addObject:s];
-	[_sectionstitle addObject:t];
-	[self.tableView beginUpdates];
-	[self.tableView insertSections:[[NSIndexSet alloc] initWithIndex:[_sections count]-1] withRowAnimation:UITableViewRowAnimationAutomatic];
-	[self.tableView endUpdates];
-	[self addParameterNumber:p atIndexPath:[NSIndexPath indexPathForRow:0 inSection:[_sections count]-1]];
+  [_sections addObject:s];
+  [_sectionstitle addObject:t];
+  [self.tableView beginUpdates];
+  [self.tableView insertSections:[[NSIndexSet alloc] initWithIndex:[_sections count]-1] withRowAnimation:UITableViewRowAnimationAutomatic];
+  [self.tableView endUpdates];
+  [self addParameterNumber:p atIndexPath:[NSIndexPath indexPathForRow:0 inSection:[_sections count]-1]];
 }
+
 - (void)addSection:(NSMutableArray*)s withTitle:(NSString*)t withParameterString:(onelab::string)p
 {
-	[_sections addObject:s];
-	[_sectionstitle addObject:t];
-	[self.tableView beginUpdates];
-	[self.tableView insertSections:[[NSIndexSet alloc] initWithIndex:[_sections count]-1] withRowAnimation:UITableViewRowAnimationAutomatic];
-	[self.tableView endUpdates];
-	[self addParameterString:p atIndexPath:[NSIndexPath indexPathForRow:0 inSection:[_sections count]-1]];
+  [_sections addObject:s];
+  [_sectionstitle addObject:t];
+  [self.tableView beginUpdates];
+  [self.tableView insertSections:[[NSIndexSet alloc] initWithIndex:[_sections count]-1] withRowAnimation:UITableViewRowAnimationAutomatic];
+  [self.tableView endUpdates];
+  [self addParameterString:p atIndexPath:[NSIndexPath indexPathForRow:0 inSection:[_sections count]-1]];
 }
+
 - (void)refreshTableView
 {
-	std::vector<onelab::number> number;
-    onelab::server::instance()->get(number);
-
-	//
-	for(int i=0;i<number.size();i++) {
-		if(!number[i].getVisible()) continue; // Do not add invisible parameter
-		NSString *name=[NSString stringWithCString:number[i].getName().c_str() encoding:[NSString defaultCStringEncoding]];
-        NSString *sectiontitle = [[name componentsSeparatedByString:@"/"] objectAtIndex:0];
-		Boolean found = false;
-		
-		for(int iSection=0; iSection<[_sectionstitle count]; iSection++) { // Check if the section exist
-			if([sectiontitle isEqualToString:[_sectionstitle objectAtIndex:iSection]]) {
-				NSMutableArray *section = [_sections objectAtIndex:iSection];
-				for(int iparameter = 0; iparameter<[section count]; iparameter++) {
-					if([[[section objectAtIndex: iparameter] getName] isEqualToString:name]) { // The parameter is in the section
-						Parameter * p = [section objectAtIndex: iparameter];
-						if(number[i].getVisible())
-							[p refresh]; // just refresh the parameter
-						else
-							[self removeParemeterNumber:number[i] atIndex:[NSIndexPath indexPathForRow:iparameter inSection:iSection]];
-                        found = true;
-                        break;
-					}
-				}
-				if(!found) // The parameter is not in the section, add it
-					[self addParameterNumber:number[i] atIndexPath:[NSIndexPath indexPathForRow:[section count] inSection:iSection]];
-				found = true; break;
-			}
-		}
-		if(found) continue; // the parameter is in the tableView
-		// The section have to be create
-		NSMutableArray *newSection = [[NSMutableArray alloc] init];
-		[self addSection:newSection withTitle:sectiontitle withParameterNumber:number[0]];
-	}
-	std::vector<onelab::string> string;
-    onelab::server::instance()->get(string);
-	
-	//
-	for(int i=0;i<string.size();i++) {
-		if(!string[i].getVisible() || string[i].getKind() == "file") continue; // Do not add invisible parameter
-		NSString *name=[NSString stringWithCString:string[i].getName().c_str() encoding:[NSString defaultCStringEncoding]];
-        NSString *sectiontitle = [[name componentsSeparatedByString:@"/"] objectAtIndex:0];
-		Boolean found = false;
-		
-		for(int iSection=0; iSection<[_sectionstitle count]; iSection++) { // Check if the section exist
-			if([sectiontitle isEqualToString:[_sectionstitle objectAtIndex:iSection]]) {
-				NSMutableArray *section = [_sections objectAtIndex:iSection];
-				for(int iparameter = 0; iparameter<[section count]; iparameter++) {
-					if([[[section objectAtIndex: iparameter] getName] isEqualToString:name]) { // The parameter is in the section
-						Parameter * p = [section objectAtIndex: iparameter];
-						[p refresh]; // just refresh the parameter
-                        found = true;
-                        break;
-					}
-				}
-				if(!found) // The parameter is not in the section, add it
-					[self addParameterString:string[i] atIndexPath:[NSIndexPath indexPathForRow:[section count] inSection:iSection]];
-				found = true; break;
-			}
-		}
-		if(found) continue; // the parameter is in the tableView
-		// The section have to be create
-		NSMutableArray *newSection = [[NSMutableArray alloc] init];
-		[self addSection:newSection withTitle:sectiontitle withParameterString:string[0]];
-	}
+  std::vector<onelab::number> number;
+  onelab::server::instance()->get(number);
+
+  // check for new/updated parameters (number)
+  for(int i=0;i<number.size();i++) {
+    if(!number[i].getVisible()) continue; // Do not add invisible parameter
+    NSString *name=[NSString stringWithCString:number[i].getName().c_str() encoding:[NSString defaultCStringEncoding]];
+    NSString *sectiontitle = [[name componentsSeparatedByString:@"/"] objectAtIndex:0];
+    Boolean found = false;
+
+    for(int iSection=0; iSection<[_sectionstitle count]; iSection++) { // Check if the section exist
+      if([sectiontitle isEqualToString:[_sectionstitle objectAtIndex:iSection]]) {
+        NSMutableArray *section = [_sections objectAtIndex:iSection];
+        for(int iparameter = 0; iparameter<[section count]; iparameter++) {
+          if([[[section objectAtIndex: iparameter] getName] isEqualToString:name]) { // The parameter is in the section
+            Parameter * p = [section objectAtIndex: iparameter];
+            [p refresh]; // just refresh the parameter
+            found = true;
+            break;
+          }
+        }
+        if(!found) // The parameter is not in the section, add it
+          [self addParameterNumber:number[i] atIndexPath:[NSIndexPath indexPathForRow:[section count] inSection:iSection]];
+        found = true; break;
+      }
+    }
+    if(found) continue; // the parameter is in the tableView
+    // The section has to be created
+    NSMutableArray *newSection = [[NSMutableArray alloc] init];
+    [self addSection:newSection withTitle:sectiontitle withParameterNumber:number[i]];
+  }
+
+  std::vector<onelab::string> string;
+  onelab::server::instance()->get(string);
+
+  // check for new/updated parameters (string)
+  for(int i=0;i<string.size();i++) {
+    if(!string[i].getVisible() || string[i].getKind() == "file") continue; // Do not add invisible parameter
+    NSString *name=[NSString stringWithCString:string[i].getName().c_str() encoding:[NSString defaultCStringEncoding]];
+    NSString *sectiontitle = [[name componentsSeparatedByString:@"/"] objectAtIndex:0];
+    Boolean found = false;
+
+    for(int iSection=0; iSection<[_sectionstitle count]; iSection++) { // Check if the section exist
+      if([sectiontitle isEqualToString:[_sectionstitle objectAtIndex:iSection]]) {
+        NSMutableArray *section = [_sections objectAtIndex:iSection];
+        for(int iparameter = 0; iparameter<[section count]; iparameter++) {
+          if([[[section objectAtIndex: iparameter] getName] isEqualToString:name]) { // The parameter is in the section
+            Parameter * p = [section objectAtIndex: iparameter];
+            [p refresh]; // just refresh the parameter
+            found = true;
+            break;
+          }
+        }
+        if(!found) // The parameter is not in the section, add it
+          [self addParameterString:string[i] atIndexPath:[NSIndexPath indexPathForRow:[section count] inSection:iSection]];
+        found = true; break;
+      }
+    }
+    if(found) continue; // the parameter is in the tableView
+    // The section have to be create
+    NSMutableArray *newSection = [[NSMutableArray alloc] init];
+    [self addSection:newSection withTitle:sectiontitle withParameterString:string[i]];
+  }
+
+  // check for hidden/deleted parameters
+  for(int iSection=0; iSection<[_sectionstitle count]; iSection++) {
+    NSMutableArray *section = [_sections objectAtIndex:iSection];
+    for(int iparameter = 0; iparameter<[section count]; iparameter++) {
+      Parameter * p = [section objectAtIndex: iparameter];
+      std::vector<onelab::number> number;
+      onelab::server::instance()->get(number,[[p getName] UTF8String]);
+      std::vector<onelab::string> string;
+      onelab::server::instance()->get(string,[[p getName] UTF8String]);
+      if((number.size() < 1 && string.size() < 1) ||
+         (number.size() > 0 && !number[0].getVisible()) ||
+         (string.size() > 0 && !string[0].getVisible())){
+        [section removeObjectAtIndex:iparameter];
+        [self removeParemeterNumberAtIndex:[NSIndexPath indexPathForRow:iparameter inSection:iSection]];
+      }
+    }
+  }
 }
 
 - (void)viewDidUnload
 {
-    [super viewDidUnload];
-    // Release any retained subviews of the main view.
+  [super viewDidUnload];
+  // Release any retained subviews of the main view.
 }
 
 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
 {
-    return YES;
+  return YES;
 }
+
 - (void)refreshParameters:(id)sender
 {
-	[self performSelectorOnMainThread:@selector(refreshParameters) withObject:nil waitUntilDone:NO];
+  [self performSelectorOnMainThread:@selector(refreshParameters) withObject:nil waitUntilDone:NO];
 }
+
 - (void)refreshParameters
 {
-	if(!_lastRefresh) _lastRefresh = [NSDate date];
-	else {
-		if([_lastRefresh timeIntervalSinceNow] >= -1) return;
-		_lastRefresh = [NSDate date];
-	}
-	[self refreshTableView]; // Get the param
+  if(!_lastRefresh) _lastRefresh = [NSDate date];
+  else {
+    if([_lastRefresh timeIntervalSinceNow] >= -0.1) return;
+    _lastRefresh = [NSDate date];
+  }
+  [self refreshTableView]; // Get the param
 }
+
 - (void)resetParameters:(id)sender
 {
-	if(((AppDelegate *)[UIApplication sharedApplication].delegate)->compute) {
-        UIAlertView *alert;
-        alert = [[UIAlertView alloc] initWithTitle:@"Can't reset model's parameters" message:@"The compute have to be finished before you can reset model's parameters." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
-        [alert show];
-        return;
-    }
-    onelab_cb("reset");
-    [_sections removeAllObjects];
-    [_sectionstitle removeAllObjects];
-    [self.tableView reloadData];
-	onelab_cb("check");
-    [self refreshTableView];
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  if(((AppDelegate *)[UIApplication sharedApplication].delegate)->compute) {
+    UIAlertView *alert;
+    alert = [[UIAlertView alloc] initWithTitle:@"Can't reset model parameters" message:@"The computation has to complete before you can reset the parameters." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
+    [alert show];
+    return;
+  }
+  onelab_cb("reset");
+  [_sections removeAllObjects];
+  [_sectionstitle removeAllObjects];
+  [self.tableView reloadData];
+  onelab_cb("check");
+  [self refreshTableView];
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
 
 #pragma mark - Table View
 
-
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 {
-    return [_sections count];
+  return [_sections count];
 }
 
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    // Return NO if you do not want the specified item to be editable.
-    return YES;
+  // Return NO if you do not want the specified item to be editable.
+  return YES;
 }
+
 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
-    if([_sections count] < section)
-        return 0;
-    NSMutableArray *mSection = [_sections objectAtIndex:section];
-    return [mSection count];
+  if([_sections count] < section)
+    return 0;
+  NSMutableArray *mSection = [_sections objectAtIndex:section];
+  return [mSection count];
 }
 
 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    // get the param with his name
-	static NSString *CellIdentifier = @"parameterCell";
-	if(indexPath.section >= _sections.count) return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
-    NSMutableArray *sectionContent = [_sections objectAtIndex:[indexPath section]];
-	if(indexPath.row >= sectionContent.count) return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
-    Parameter *tmp = [sectionContent objectAtIndex:[indexPath row]];
-    
-    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
-    if(cell == nil)
-        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
-    else {
-		cell = nil;
-        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
-	}
-	[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
-    [cell setUserInteractionEnabled:!([tmp isReadOnly])];
-    [tmp setLabelFrame:CGRectMake(20, 5, cell.frame.size.width - 40, cell.frame.size.height/2)];
-    [cell addSubview:[tmp getLabel]];
-    if([tmp isKindOfClass:[ParameterStringList class]]) {
-        ParameterStringList *param = (ParameterStringList *)tmp;
-        [param setFrame:CGRectMake(20, 35, cell.frame.size.width - 40, cell.frame.size.height/2)];
-        [cell addSubview:[param getUIView]];
-    }
-    else if([tmp isKindOfClass:[ParameterNumberList class]]) {
-        ParameterNumberList *param = (ParameterNumberList *)tmp;
-        [param setFrame:CGRectMake(20, 35, cell.frame.size.width - 40, cell.frame.size.height/2)];
-        [cell addSubview:[param getUIView]];
-    }
-    else if([tmp isKindOfClass:[ParameterNumberCheckbox class]]) {
-        ParameterNumberCheckbox *param = (ParameterNumberCheckbox *)tmp;
-        [param setLabelFrame:CGRectMake(100, 5, cell.frame.size.width - 110, cell.frame.size.height)];
-        [param setFrame:CGRectMake(20, 5, cell.frame.size.width - 40, cell.frame.size.height)];
-        [cell addSubview:[param getCheckbox]];
-    }
-    else if([tmp isKindOfClass:[ParameterNumberRange class]]) {
-        ParameterNumberRange *param = (ParameterNumberRange *)tmp;
-        [param setFrame:CGRectMake(20, cell.frame.size.height/2+5, cell.frame.size.width - 40, cell.frame.size.height/2)];
-        [cell addSubview:[param getSlider]];
-    }
-    else if([tmp isKindOfClass:[ParameterNumberTextbox class]]) {
-        ParameterNumberTextbox *param = (ParameterNumberTextbox *)tmp;
-        [param setFrame:CGRectMake(20, cell.frame.size.height/2+5, cell.frame.size.width - 40, cell.frame.size.height/2)];
-        [cell addSubview:[param getTextbox]];
-    }
-        
-    return cell;
+  // get the param with his name
+  static NSString *CellIdentifier = @"parameterCell";
+  if(indexPath.section >= _sections.count) return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
+  NSMutableArray *sectionContent = [_sections objectAtIndex:[indexPath section]];
+  if(indexPath.row >= sectionContent.count) return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
+  Parameter *tmp = [sectionContent objectAtIndex:[indexPath row]];
+
+  UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
+  if(cell == nil)
+    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
+  else {
+    cell = nil;
+    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
+  }
+  [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+  [cell setUserInteractionEnabled:!([tmp isReadOnly])];
+  [tmp setLabelFrame:CGRectMake(20, 5, cell.frame.size.width - 40, cell.frame.size.height/2)];
+  [cell addSubview:[tmp getLabel]];
+  if([tmp isKindOfClass:[ParameterStringList class]]) {
+    ParameterStringList *param = (ParameterStringList *)tmp;
+    [param setFrame:CGRectMake(20, 35, cell.frame.size.width - 40, cell.frame.size.height/2)];
+    [cell addSubview:[param getUIView]];
+  }
+  else if([tmp isKindOfClass:[ParameterNumberList class]]) {
+    ParameterNumberList *param = (ParameterNumberList *)tmp;
+    [param setFrame:CGRectMake(20, 35, cell.frame.size.width - 40, cell.frame.size.height/2)];
+    [cell addSubview:[param getUIView]];
+  }
+  else if([tmp isKindOfClass:[ParameterNumberCheckbox class]]) {
+    ParameterNumberCheckbox *param = (ParameterNumberCheckbox *)tmp;
+    [param setLabelFrame:CGRectMake(100, 5, cell.frame.size.width - 110, cell.frame.size.height)];
+    [param setFrame:CGRectMake(20, 5, cell.frame.size.width - 40, cell.frame.size.height)];
+    [cell addSubview:[param getCheckbox]];
+  }
+  else if([tmp isKindOfClass:[ParameterNumberStepper class]]) {
+    ParameterNumberStepper *param = (ParameterNumberStepper *)tmp;
+    [param setFrame:CGRectMake(20, cell.frame.size.height/2+5, cell.frame.size.width - 40, cell.frame.size.height/2)];
+    [cell addSubview:[param getStepper]];
+  }
+  else if([tmp isKindOfClass:[ParameterNumberRange class]]) {
+    ParameterNumberRange *param = (ParameterNumberRange *)tmp;
+    [param setFrame:CGRectMake(20, cell.frame.size.height/2+5, cell.frame.size.width - 40, cell.frame.size.height/2)];
+    [cell addSubview:[param getSlider]];
+  }
+  else if([tmp isKindOfClass:[ParameterNumberTextbox class]]) {
+    ParameterNumberTextbox *param = (ParameterNumberTextbox *)tmp;
+    [param setFrame:CGRectMake(20, cell.frame.size.height/2+5, cell.frame.size.width - 40, cell.frame.size.height/2)];
+    [cell addSubview:[param getTextbox]];
+  }
+
+  return cell;
 }
 
 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 {
-    Parameter *param = [[_sections objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
-    return [[param class] getHeight];
+  Parameter *param = [[_sections objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
+  return [[param class] getHeight];
 }
 
 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
 {
-    return [_sectionstitle objectAtIndex:section];
+  return [_sectionstitle objectAtIndex:section];
 }
+
 @end
diff --git a/contrib/mobile/iOS/Onelab/PostProcessingViewController.h b/contrib/mobile/iOS/Onelab/PostProcessingViewController.h
index 8609173..74a8740 100644
--- a/contrib/mobile/iOS/Onelab/PostProcessingViewController.h
+++ b/contrib/mobile/iOS/Onelab/PostProcessingViewController.h
@@ -1,11 +1,3 @@
-//
-//  PostProcessingViewController.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 22/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <UIKit/UIKit.h>
 
 #include <gmsh/PView.h>
diff --git a/contrib/mobile/iOS/Onelab/PostProcessingViewController.mm b/contrib/mobile/iOS/Onelab/PostProcessingViewController.mm
index 14d4f61..872b3f8 100644
--- a/contrib/mobile/iOS/Onelab/PostProcessingViewController.mm
+++ b/contrib/mobile/iOS/Onelab/PostProcessingViewController.mm
@@ -1,13 +1,7 @@
-//
-//  PostProcessingViewController.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 22/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import "PostProcessingViewController.h"
 
+#include <gmsh/Context.h>
+
 @interface PostProcessingViewController ()
 
 @end
@@ -16,111 +10,126 @@
 
 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
 {
-    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
-    if (self) {
-        // Custom initialization
-    }
-    return self;
+  self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+  if (self) {
+    // Custom initialization
+  }
+  return self;
 }
 
 - (void)setPView:(PView*)p
 {
-    _pview = p;
+  _pview = p;
 }
 
 - (void)viewDidLoad
 {
-    [super viewDidLoad];
-	// Do any additional setup after loading the view.
-    if(_pview)
-    {
-        [_Name setText:[NSString stringWithCString:_pview->getData()->getName().c_str() encoding:[NSString defaultCStringEncoding]]];
-        [_IntervalsType setDataSource:self];
-        [_IntervalsType setDelegate:self];
-        [_Intervals setText:[NSString stringWithFormat:@"%d",_pview->getOptions()->nbIso]];
-        UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
-        numberToolbar.barStyle = UIBarStyleBlackTranslucent;
-        numberToolbar.items = [NSArray arrayWithObjects:
-                               [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
-                               [[UIBarButtonItem alloc]initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneWithNumberPad)],
-                               nil];
-        [numberToolbar sizeToFit];
-        _Intervals.delegate = self;
-        _Intervals.inputAccessoryView = numberToolbar;
-        [_RaiseZ setValue:_pview->getOptions()->raise[2]];
-        [_RaiseZ addTarget:self action:@selector(slideRaiseZ:) forControlEvents:UIControlEventValueChanged];
-        [_IntervalsStepper setStepValue:1];
-        [_IntervalsStepper setValue:_pview->getOptions()->nbIso];
-        [_IntervalsStepper setMaximumValue:1000];
-        [_IntervalsStepper setMinimumValue:1];
-    }
+  [super viewDidLoad];
+  // Do any additional setup after loading the view.
+  if(_pview) {
+    [_Name setText:[NSString stringWithCString:_pview->getData()->getName().c_str() encoding:[NSString defaultCStringEncoding]]];
+    [_IntervalsType setDataSource:self];
+    [_IntervalsType setDelegate:self];
+    [_Intervals setText:[NSString stringWithFormat:@"%d",_pview->getOptions()->nbIso]];
+    UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
+    numberToolbar.items = [NSArray arrayWithObjects:
+                                     [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
+                                   [[UIBarButtonItem alloc]initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneWithNumberPad)],
+                                   nil];
+    [numberToolbar sizeToFit];
+    _Intervals.delegate = self;
+    _Intervals.inputAccessoryView = numberToolbar;
+    [_RaiseZ setValue:_pview->getOptions()->raise[2]];
+
+    double maxval = std::max(fabs(_pview->getData()->getMin()), fabs(_pview->getData()->getMax()));
+    if(!maxval) maxval = 1.;
+    double val2 = 2. * CTX::instance()->lc / maxval;
+    [_RaiseZ setMinimumValue:-val2];
+    [_RaiseZ setMaximumValue:val2];
+    [_RaiseZ addTarget:self action:@selector(slideRaiseZ:) forControlEvents:UIControlEventValueChanged];
+    [_IntervalsStepper setStepValue:1];
+    [_IntervalsStepper setValue:_pview->getOptions()->nbIso];
+    [_IntervalsStepper setMaximumValue:1000];
+    [_IntervalsStepper setMinimumValue:1];
+  }
 }
+
 -(void)viewDidAppear:(BOOL)animated
 {
-    [_IntervalsType selectRow:_pview->getOptions()->intervalsType-1 inComponent:0 animated:YES];
+  [_IntervalsType selectRow:_pview->getOptions()->intervalsType-1 inComponent:0 animated:YES];
 }
+
 - (IBAction)stepperValueChanged:(UIStepper *)sender
 {
-    [_Intervals setText:[NSString stringWithFormat:@"%.0f", [sender value]]];
-    _pview->getOptions()->nbIso = [sender value];
-    _pview->setChanged(true);
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  [_Intervals setText:[NSString stringWithFormat:@"%.0f", [sender value]]];
+  _pview->getOptions()->nbIso = [sender value];
+  _pview->setChanged(true);
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
+
 -(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
 {
-    return 1;
+  return 1;
 }
+
 -(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
 {
-    return 3;
+  return 3;
 }
+
 -(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
 {
-    NSArray *name = [[NSArray alloc] initWithObjects:@"Iso-values", @"Continuous map", @"Filled iso-values", nil];
-    return [name objectAtIndex:row];
+  NSArray *name = [[NSArray alloc] initWithObjects:@"Iso-values", @"Continuous map", @"Filled iso-values", nil];
+  return [name objectAtIndex:row];
 }
+
 -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
 {
-    _pview->getOptions()->intervalsType = 1+row;
-    _pview->setChanged(true);
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  _pview->getOptions()->intervalsType = 1+row;
+  _pview->setChanged(true);
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
+
 - (void)slideRaiseZ:(UISlider*)sender
 {
-    _pview->getOptions()->raise[2] = sender.value;
-    _pview->setChanged(true);
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  _pview->getOptions()->raise[2] = sender.value;
+  _pview->setChanged(true);
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
 }
+
 - (void)didReceiveMemoryWarning
 {
-    [super didReceiveMemoryWarning];
-    // Dispose of any resources that can be recreated.
+  [super didReceiveMemoryWarning];
+  // Dispose of any resources that can be recreated.
 }
 
 -(BOOL)textFieldShouldEndEditing:(UITextField *)textField
 {
-    [_IntervalsStepper setValue:_pview->getOptions()->nbIso];
-    _pview->getOptions()->nbIso = [textField.text integerValue];
-    _pview->setChanged(true);
-    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
-    return YES;
+  [_IntervalsStepper setValue:_pview->getOptions()->nbIso];
+  _pview->getOptions()->nbIso = [textField.text integerValue];
+  _pview->setChanged(true);
+  [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender" object:nil];
+  return YES;
 }
+
 -(BOOL)textFieldShouldReturn:(UITextField *)textField
 {
-    return [_Intervals endEditing:YES];
+  return [_Intervals endEditing:YES];
 }
+
 -(void)doneWithNumberPad
 {
-    [_Intervals endEditing:YES];
+  [_Intervals endEditing:YES];
 }
 
-- (void)viewDidUnload {
-    [self setName:nil];
-    [self setRaiseZ:nil];
-    [self setIntervals:nil];
-    [self setIntervalsType:nil];
-    [self setName:nil];
-    [self setIntervalsStepper:nil];
-    [super viewDidUnload];
+-(void)viewDidUnload
+{
+  [self setName:nil];
+  [self setRaiseZ:nil];
+  [self setIntervals:nil];
+  [self setIntervalsType:nil];
+  [self setName:nil];
+  [self setIntervalsStepper:nil];
+  [super viewDidUnload];
 }
 @end
diff --git a/contrib/mobile/iOS/Onelab/SplitViewController.h b/contrib/mobile/iOS/Onelab/SplitViewController.h
index 70fff38..d882692 100644
--- a/contrib/mobile/iOS/Onelab/SplitViewController.h
+++ b/contrib/mobile/iOS/Onelab/SplitViewController.h
@@ -1,19 +1,11 @@
-//
-//  SplitViewController.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 05/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <UIKit/UIKit.h>
 
 #import "ParametersViewController.h"
 #import "ModelViewController.h"
 
 @interface SplitViewController : UISplitViewController{
-    ModelViewController *modelViewController;
-    ParametersViewController *parametersViewController;
+  ModelViewController *modelViewController;
+  ParametersViewController *parametersViewController;
 }
 
 @property (nonatomic, retain) NSString *initialModel;
diff --git a/contrib/mobile/iOS/Onelab/SplitViewController.mm b/contrib/mobile/iOS/Onelab/SplitViewController.mm
index 7fd3dad..a2bf7ad 100644
--- a/contrib/mobile/iOS/Onelab/SplitViewController.mm
+++ b/contrib/mobile/iOS/Onelab/SplitViewController.mm
@@ -1,11 +1,3 @@
-//
-//  SplitViewController.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 05/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import "SplitViewController.h"
 
 @interface SplitViewController ()
@@ -13,46 +5,46 @@
 @end
 
 @implementation SplitViewController
-	 
+
 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
 {
-    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
-    if (self) {
-        // Custom initialization
-    }
-    return self;
+  self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+  if (self) {
+    // Custom initialization
+  }
+  return self;
 }
 
 - (void)viewDidLoad
 {
-    [super viewDidLoad];
-	// Do any additional setup after loading the view.
-	UINavigationController *right = [self.viewControllers objectAtIndex:1]; // right UINavigationController (Detail)
-    for(UIViewController *v in right.viewControllers){
-        if ([v isKindOfClass:[ModelViewController class]]) {
-            modelViewController = (ModelViewController *)v;
-        }
+  [super viewDidLoad];
+  // Do any additional setup after loading the view.
+  UINavigationController *right = [self.viewControllers objectAtIndex:1]; // right UINavigationController (Detail)
+  for(UIViewController *v in right.viewControllers){
+    if ([v isKindOfClass:[ModelViewController class]]) {
+      modelViewController = (ModelViewController *)v;
+    }
+  }
+  UINavigationController *left = [self.viewControllers objectAtIndex:0]; // left UINavigationController (Master)
+  for(UIViewController *v in left.viewControllers){
+    if ([v isKindOfClass:[ParametersViewController class]]) {
+      parametersViewController = (ParametersViewController *)v;
     }
-    UINavigationController *left = [self.viewControllers objectAtIndex:0]; // left UINavigationController (Master)
-	 for(UIViewController *v in left.viewControllers){
-		 if ([v isKindOfClass:[ParametersViewController class]]) {
-				parametersViewController = (ParametersViewController *)v;
-		 }
-	 }
-	self.delegate = modelViewController;
-	[self setPresentsWithGesture:NO];
+  }
+  self.delegate = modelViewController;
+  [self setPresentsWithGesture:NO];
 }
 
 -(void)viewDidAppear:(BOOL)animated
 {
-	modelViewController.initialModel = self.initialModel;
-	[super viewDidAppear:animated];
+  modelViewController.initialModel = self.initialModel;
+  [super viewDidAppear:animated];
 }
 
 - (void)didReceiveMemoryWarning
 {
-    [super didReceiveMemoryWarning];
-    // Dispose of any resources that can be recreated.
+  [super didReceiveMemoryWarning];
+  // Dispose of any resources that can be recreated.
 }
 
 @end
diff --git a/contrib/mobile/iOS/Onelab/Utils.h b/contrib/mobile/iOS/Onelab/Utils.h
index 5dab5ad..364eb7a 100644
--- a/contrib/mobile/iOS/Onelab/Utils.h
+++ b/contrib/mobile/iOS/Onelab/Utils.h
@@ -1,11 +1,3 @@
-//
-//  Utils.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 06/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <Foundation/Foundation.h>
 
 @interface Utils : NSObject
diff --git a/contrib/mobile/iOS/Onelab/Utils.mm b/contrib/mobile/iOS/Onelab/Utils.mm
index 62f9778..91b06af 100644
--- a/contrib/mobile/iOS/Onelab/Utils.mm
+++ b/contrib/mobile/iOS/Onelab/Utils.mm
@@ -1,35 +1,29 @@
-//
-//  Utils.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 06/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import "Utils.h"
 
 @implementation Utils
 
 + (NSString *) getApplicationDocumentsDirectory
 {
-    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
-    return basePath;
+  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+  NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
+  return basePath;
 }
 
 + (void) copyRes
 {
-    NSString *resPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"files"];
-    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-    NSString *docPath = [paths objectAtIndex:0]; //Get the docs directory
-    
-    NSArray *resContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:resPath error:NULL];
-    
-    for (NSString* obj in resContents){
-        NSError* error;
-        if (![[NSFileManager defaultManager] copyItemAtPath:[resPath stringByAppendingPathComponent:obj] toPath:[docPath stringByAppendingPathComponent:obj] error:&error])
-            NSLog(@"Error: %@", error);;
-    }
+  NSString *resPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"files"];
+  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+  NSString *docPath = [paths objectAtIndex:0]; //Get the docs directory
+  NSArray *resContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:resPath error:NULL];
+  for (NSString *obj in resContents){
+    NSLog(@"Replacing model %@", obj);
+    NSString *modelSrc = [[resPath stringByAppendingString:@"/"] stringByAppendingString:obj];
+    NSString *modelDst = [[docPath stringByAppendingString:@"/"] stringByAppendingString:obj];
+    [[NSFileManager defaultManager] removeItemAtPath:modelDst error:nil];
+    NSError *error;
+    if (![[NSFileManager defaultManager] copyItemAtPath:modelSrc toPath:modelDst error:&error])
+      NSLog(@"Error: %@", error);
+  }
 }
 
 @end
diff --git a/contrib/mobile/iOS/Onelab/emulatorFix.c b/contrib/mobile/iOS/Onelab/emulatorFix.c
index 3d57d08..4af626e 100644
--- a/contrib/mobile/iOS/Onelab/emulatorFix.c
+++ b/contrib/mobile/iOS/Onelab/emulatorFix.c
@@ -16,6 +16,7 @@
 #include <fcntl.h>
 #include <pthread.h>
 #include <sys/time.h>
+#include <time.h>
 
 int getrlimit$UNIX2003( int resource, struct rlimit *rlp)
 {
@@ -27,6 +28,11 @@ FILE *fopen$UNIX2003(const char * filename, const char *mode)
     return fopen(filename, mode);
 }
 
+int fputs$UNIX2003(const char * filename, FILE *file)
+{
+  return fputs(filename, file);
+}
+
 int stat$INODE64(const char * filename, struct stat *buff)
 {
     return stat(filename,buff);
@@ -128,4 +134,9 @@ int fstat$INODE64(int fildes, struct stat *buf)
 ssize_t send$UNIX2003(int socket, const void *buffer, size_t length, int flags)
 {
     return send(socket, buffer, length, flags);
-}
\ No newline at end of file
+}
+
+clock_t clock$UNIX2003()
+{
+    return clock();
+}
diff --git a/contrib/mobile/iOS/Onelab/en.lproj/iPadStoryboard.storyboard b/contrib/mobile/iOS/Onelab/en.lproj/iPadStoryboard.storyboard
index de58736..8150154 100644
--- a/contrib/mobile/iOS/Onelab/en.lproj/iPadStoryboard.storyboard
+++ b/contrib/mobile/iOS/Onelab/en.lproj/iPadStoryboard.storyboard
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="4510" systemVersion="12F37" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="dwa-Pq-2vA">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="5056" systemVersion="13D65" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES" initialViewController="dwa-Pq-2vA">
     <dependencies>
-        <deployment defaultVersion="1536" identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3742"/>
+        <deployment defaultVersion="1792" identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3733"/>
     </dependencies>
     <scenes>
         <!--Navigation Controller-->
@@ -31,23 +31,49 @@
         <scene sceneID="16">
             <objects>
                 <viewController storyboardIdentifier="ModelViewController" title="ONELAB" id="4" customClass="ModelViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="NzN-7G-5eX"/>
+                        <viewControllerLayoutGuide type="bottom" id="EYA-0D-qDB"/>
+                    </layoutGuides>
                     <view key="view" multipleTouchEnabled="YES" contentMode="scaleToFill" id="26" customClass="EAGLView">
                         <rect key="frame" x="0.0" y="0.0" width="703" height="768"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
-                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="HN2-fw-mfe">
-                                <rect key="frame" x="47" y="707" width="636" height="21"/>
-                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HN2-fw-mfe">
+                                <rect key="frame" x="47" y="727" width="636" height="21"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
                                 <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                 <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                 <nil key="highlightedColor"/>
                             </label>
-                            <activityIndicatorView opaque="NO" contentMode="scaleToFill" style="gray" id="BfX-qT-0mL">
-                                <rect key="frame" x="20" y="708" width="20" height="20"/>
-                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                            <activityIndicatorView opaque="NO" contentMode="scaleToFill" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="BfX-qT-0mL">
+                                <rect key="frame" x="20" y="728" width="20" height="20"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
                             </activityIndicatorView>
+                            <button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="right" contentVerticalAlignment="top" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GRU-nz-BNs">
+                                <rect key="frame" x="652" y="80" width="40" height="40"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="40" id="NTn-Hp-n22"/>
+                                    <constraint firstAttribute="width" constant="40" id="lvs-wL-1eu"/>
+                                </constraints>
+                                <state key="normal" image="icon_rotate.png">
+                                    <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="startRotation:" destination="4" eventType="touchUpInside" id="Ufg-Lv-KVt"/>
+                                </connections>
+                            </button>
                         </subviews>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="GRU-nz-BNs" secondAttribute="trailing" constant="20" id="5SK-5e-5sv"/>
+                            <constraint firstItem="GRU-nz-BNs" firstAttribute="top" secondItem="NzN-7G-5eX" secondAttribute="bottom" constant="20" id="Brz-ez-tFA"/>
+                            <constraint firstItem="BfX-qT-0mL" firstAttribute="leading" secondItem="26" secondAttribute="leading" constant="20" id="O3e-fe-oVT"/>
+                            <constraint firstItem="HN2-fw-mfe" firstAttribute="leading" secondItem="BfX-qT-0mL" secondAttribute="trailing" constant="10" id="Q5d-FK-Rq5"/>
+                            <constraint firstItem="EYA-0D-qDB" firstAttribute="top" secondItem="HN2-fw-mfe" secondAttribute="bottom" constant="20" id="eo2-1G-DDU"/>
+                            <constraint firstItem="EYA-0D-qDB" firstAttribute="top" secondItem="BfX-qT-0mL" secondAttribute="bottom" constant="20" id="tlt-kB-Qwe"/>
+                        </constraints>
                         <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
                         <connections>
                             <outletCollection property="gestureRecognizers" destination="Nb5-mS-uY7" appends="YES" id="aF3-Oi-e8B"/>
@@ -57,6 +83,7 @@
                     </view>
                     <toolbarItems/>
                     <navigationItem key="navigationItem" title="ONELAB" id="53"/>
+                    <size key="freeformSize" width="703" height="768"/>
                     <connections>
                         <outlet property="doubleTap" destination="MRc-vF-047" id="mdb-zu-B2d"/>
                         <outlet property="glView" destination="26" id="i7d-I7-Zhz"/>
@@ -121,47 +148,51 @@
         <scene sceneID="inJ-Ob-bP0">
             <objects>
                 <viewController storyboardIdentifier="PostProcessingViewController" id="59P-em-ZXH" customClass="PostProcessingViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="rYq-Fd-aLL"/>
+                        <viewControllerLayoutGuide type="bottom" id="zl2-C9-6GO"/>
+                    </layoutGuides>
                     <view key="view" contentMode="scaleToFill" id="bA2-5p-eQu">
                         <rect key="frame" x="0.0" y="0.0" width="320" height="768"/>
                         <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                         <subviews>
-                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="PView Name" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="zvL-DY-CD8">
-                                <rect key="frame" x="20" y="54" width="280" height="32"/>
+                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" fixedFrame="YES" text="PView Name" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zvL-DY-CD8">
+                                <rect key="frame" x="20" y="75" width="280" height="32"/>
                                 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                 <fontDescription key="fontDescription" type="system" pointSize="24"/>
                                 <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                 <nil key="highlightedColor"/>
                             </label>
-                            <pickerView contentMode="scaleToFill" id="KcQ-1V-heQ">
-                                <rect key="frame" x="0.0" y="94" width="320" height="216"/>
+                            <pickerView contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KcQ-1V-heQ">
+                                <rect key="frame" x="0.0" y="95" width="320" height="216"/>
                                 <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
                             </pickerView>
-                            <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="21" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" id="NrM-45-dY4">
-                                <rect key="frame" x="117" y="318" width="94" height="30"/>
+                            <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="21" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="NrM-45-dY4">
+                                <rect key="frame" x="111" y="318" width="65" height="30"/>
                                 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                 <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                 <textInputTraits key="textInputTraits"/>
                             </textField>
-                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Intervals" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ol0-Ou-YBJ">
-                                <rect key="frame" x="20" y="322" width="89" height="21"/>
+                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" fixedFrame="YES" text="Intervals" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ol0-Ou-YBJ">
+                                <rect key="frame" x="0.0" y="322" width="89" height="21"/>
                                 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                 <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                 <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                 <nil key="highlightedColor"/>
                             </label>
-                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Raise (Z)" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="IVB-fp-jdZ">
-                                <rect key="frame" x="20" y="356" width="89" height="21"/>
+                            <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" fixedFrame="YES" text="Raise (Z)" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IVB-fp-jdZ">
+                                <rect key="frame" x="0.0" y="361" width="89" height="21"/>
                                 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                 <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                 <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                 <nil key="highlightedColor"/>
                             </label>
-                            <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="-5" maxValue="5" id="mjo-81-vMy">
-                                <rect key="frame" x="115" y="355" width="187" height="29"/>
+                            <slider opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="-5" maxValue="5" translatesAutoresizingMaskIntoConstraints="NO" id="mjo-81-vMy">
+                                <rect key="frame" x="109" y="356" width="187" height="31"/>
                                 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                             </slider>
-                            <stepper opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="100" id="p1D-j1-egi">
-                                <rect key="frame" x="219" y="319" width="94" height="23"/>
+                            <stepper opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="p1D-j1-egi">
+                                <rect key="frame" x="200" y="319" width="94" height="29"/>
                                 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                 <connections>
                                     <action selector="stepperValueChanged:" destination="59P-em-ZXH" eventType="valueChanged" id="lia-6x-IaS"/>
@@ -201,7 +232,25 @@
             </objects>
             <point key="canvasLocation" x="-879" y="-806"/>
         </scene>
-        <!--Model List Controller - Models list-->
+        <!--About View Controller-->
+        <scene sceneID="JzC-rN-mWe">
+            <objects>
+                <viewController id="VJs-Jj-MrK" customClass="AboutViewController" sceneMemberID="viewController">
+                    <webView key="view" contentMode="scaleToFill" id="5gX-R5-60b">
+                        <rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                    </webView>
+                    <navigationItem key="navigationItem" id="Jgu-H8-Skt"/>
+                    <connections>
+                        <outlet property="aboutView" destination="5gX-R5-60b" id="C4Z-WU-Ydg"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="aMz-Ds-IMq" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="-879" y="77"/>
+        </scene>
+        <!--Model List Controller - Model list-->
         <scene sceneID="af3-vl-hzw">
             <objects>
                 <tableViewController id="dVI-Oo-Sq4" customClass="ModelListController" sceneMemberID="viewController">
@@ -220,7 +269,10 @@
                             </tableViewCell>
                         </prototypes>
                     </tableView>
-                    <navigationItem key="navigationItem" title="Models list" id="sdX-f6-lSz"/>
+                    <navigationItem key="navigationItem" title="Model list" id="sdX-f6-lSz"/>
+                    <connections>
+                        <segue destination="VJs-Jj-MrK" kind="push" identifier="showAboutSegue" id="s46-1w-abC"/>
+                    </connections>
                 </tableViewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="zLU-RU-aDe" userLabel="First Responder" sceneMemberID="firstResponder"/>
             </objects>
@@ -307,9 +359,12 @@
             <point key="canvasLocation" x="336" y="340"/>
         </scene>
     </scenes>
+    <resources>
+        <image name="icon_rotate.png" width="512" height="512"/>
+    </resources>
     <simulatedMetricsContainer key="defaultSimulatedMetrics">
         <simulatedStatusBarMetrics key="statusBar"/>
         <simulatedOrientationMetrics key="orientation"/>
         <simulatedScreenMetrics key="destination"/>
     </simulatedMetricsContainer>
-</document>
\ No newline at end of file
+</document>
diff --git a/contrib/mobile/iOS/Onelab/en.lproj/iPhoneiPodStoryboard.storyboard b/contrib/mobile/iOS/Onelab/en.lproj/iPhoneiPodStoryboard.storyboard
index 6e80fd2..b462f4f 100644
--- a/contrib/mobile/iOS/Onelab/en.lproj/iPhoneiPodStoryboard.storyboard
+++ b/contrib/mobile/iOS/Onelab/en.lproj/iPhoneiPodStoryboard.storyboard
@@ -1,34 +1,34 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="2.0" toolsVersion="4510" systemVersion="12F37" targetRuntime="iOS.CocoaTouch" variant="6xAndEarlier" propertyAccessControl="none" useAutolayout="YES" initialViewController="vAG-uz-hfU">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="5056" systemVersion="13D65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="vAG-uz-hfU">
     <dependencies>
-        <deployment defaultVersion="1536" identifier="iOS"/>
-        <development version="4600" identifier="xcode"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3742"/>
+        <deployment defaultVersion="1792" identifier="iOS"/>
+        <development version="5100" identifier="xcode"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3733"/>
     </dependencies>
     <scenes>
-        <!--Model List Controller - Models list-->
+        <!--Model List Controller - Models-->
         <scene sceneID="Y4S-jQ-WHz">
             <objects>
                 <tableViewController id="aNd-kg-MlN" customClass="ModelListController" sceneMemberID="viewController">
-                    <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="E1y-UA-Su2">
-                        <rect key="frame" x="0.0" y="64" width="320" height="504"/>
+                    <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="E1y-UA-Su2">
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                         <prototypes>
                             <tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="model" id="8lY-sK-IU2">
-                                <rect key="frame" x="0.0" y="22" width="320" height="44"/>
+                                <rect key="frame" x="0.0" y="86" width="320" height="44"/>
                                 <autoresizingMask key="autoresizingMask"/>
-                                <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="8lY-sK-IU2" id="DGR-CE-eWT">
                                     <rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
                                     <autoresizingMask key="autoresizingMask"/>
-                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
-                                </view>
+                                </tableViewCellContentView>
                             </tableViewCell>
                         </prototypes>
                     </tableView>
-                    <navigationItem key="navigationItem" title="Models list" id="l1y-cb-Mvd"/>
+                    <navigationItem key="navigationItem" title="Models" id="l1y-cb-Mvd"/>
                     <connections>
                         <segue destination="NyB-7w-cP0" kind="push" identifier="showModelSegue" id="urr-vz-3XW"/>
+                        <segue destination="uZG-Bw-GZA" kind="push" identifier="showAboutSegue" id="Ctu-pA-E38"/>
                     </connections>
                 </tableViewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="5qi-J8-Zn2" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -39,32 +39,52 @@
         <scene sceneID="ghQ-lt-1PF">
             <objects>
                 <viewController storyboardIdentifier="ModelViewController" id="NyB-7w-cP0" customClass="ModelViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="B2T-ui-MHS"/>
+                        <viewControllerLayoutGuide type="bottom" id="PQs-jS-IB8"/>
+                    </layoutGuides>
                     <view key="view" contentMode="scaleToFill" id="zrj-Dd-WPc" customClass="EAGLView">
-                        <rect key="frame" x="0.0" y="64" width="320" height="504"/>
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                         <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                         <subviews>
                             <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yT7-IR-qUJ">
-                                <rect key="frame" x="48" y="464" width="252" height="20"/>
+                                <rect key="frame" x="40" y="538" width="260" height="20"/>
                                 <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                 <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                 <nil key="highlightedColor"/>
                             </label>
                             <activityIndicatorView opaque="NO" contentMode="scaleToFill" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Fuh-zG-zVR">
-                                <rect key="frame" x="20" y="464" width="20" height="20"/>
+                                <rect key="frame" x="10" y="538" width="20" height="20"/>
                                 <constraints>
                                     <constraint firstAttribute="width" constant="20" id="f9c-ZY-6q4"/>
                                 </constraints>
                             </activityIndicatorView>
+                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="top" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ct3-iA-CZQ">
+                                <rect key="frame" x="280" y="74" width="30" height="30"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="30" id="59F-eB-IWj"/>
+                                    <constraint firstAttribute="width" constant="30" id="Cor-0l-wdz"/>
+                                </constraints>
+                                <state key="normal" image="icon_rotate.png">
+                                    <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
+                                </state>
+                                <connections>
+                                    <action selector="startRotation:" destination="NyB-7w-cP0" eventType="touchUpInside" id="6fd-R7-3ts"/>
+                                </connections>
+                            </button>
                         </subviews>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                         <gestureRecognizers/>
                         <constraints>
-                            <constraint firstAttribute="trailing" secondItem="yT7-IR-qUJ" secondAttribute="trailing" constant="20" symbolic="YES" type="default" id="02X-Hf-QoA"/>
-                            <constraint firstAttribute="bottom" secondItem="yT7-IR-qUJ" secondAttribute="bottom" constant="20" symbolic="YES" type="default" id="4by-pW-cH0"/>
-                            <constraint firstItem="Fuh-zG-zVR" firstAttribute="centerY" secondItem="yT7-IR-qUJ" secondAttribute="centerY" type="default" id="BLC-3x-kRj"/>
-                            <constraint firstItem="Fuh-zG-zVR" firstAttribute="top" secondItem="yT7-IR-qUJ" secondAttribute="top" type="default" id="REs-y3-luE"/>
-                            <constraint firstItem="yT7-IR-qUJ" firstAttribute="leading" secondItem="Fuh-zG-zVR" secondAttribute="trailing" constant="8" symbolic="YES" type="default" id="oc4-6x-CF7"/>
-                            <constraint firstItem="Fuh-zG-zVR" firstAttribute="leading" secondItem="zrj-Dd-WPc" secondAttribute="leading" constant="20" symbolic="YES" type="default" id="qfh-y2-BuW"/>
+                            <constraint firstItem="yT7-IR-qUJ" firstAttribute="bottom" secondItem="Fuh-zG-zVR" secondAttribute="bottom" id="AP1-zU-goA"/>
+                            <constraint firstAttribute="bottom" secondItem="Fuh-zG-zVR" secondAttribute="bottom" constant="10" id="J47-7T-QdC"/>
+                            <constraint firstAttribute="trailing" secondItem="Ct3-iA-CZQ" secondAttribute="trailing" constant="10" id="Nep-AD-3aJ"/>
+                            <constraint firstAttribute="trailing" secondItem="yT7-IR-qUJ" secondAttribute="trailing" constant="20" symbolic="YES" id="P96-El-NrK"/>
+                            <constraint firstItem="yT7-IR-qUJ" firstAttribute="leading" secondItem="Fuh-zG-zVR" secondAttribute="trailing" constant="10" id="oc4-6x-CF7"/>
+                            <constraint firstItem="Fuh-zG-zVR" firstAttribute="top" secondItem="yT7-IR-qUJ" secondAttribute="top" id="qEd-Tx-ibj"/>
+                            <constraint firstItem="Fuh-zG-zVR" firstAttribute="leading" secondItem="zrj-Dd-WPc" secondAttribute="leading" constant="10" id="qfh-y2-BuW"/>
+                            <constraint firstItem="Ct3-iA-CZQ" firstAttribute="top" secondItem="B2T-ui-MHS" secondAttribute="bottom" constant="10" id="uxn-cS-R2c"/>
                         </constraints>
                         <connections>
                             <outletCollection property="gestureRecognizers" destination="7R3-zZ-cpa" appends="YES" id="K8X-lL-YUb"/>
@@ -99,7 +119,25 @@
                     </connections>
                 </pinchGestureRecognizer>
             </objects>
-            <point key="canvasLocation" x="156" y="160"/>
+            <point key="canvasLocation" x="142" y="160"/>
+        </scene>
+        <!--About View Controller-->
+        <scene sceneID="3Qf-fF-DaH">
+            <objects>
+                <viewController id="uZG-Bw-GZA" customClass="AboutViewController" sceneMemberID="viewController">
+                    <webView key="view" contentMode="scaleToFill" id="EMj-bY-w8n">
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
+                    </webView>
+                    <navigationItem key="navigationItem" id="0mC-fS-N0z"/>
+                    <connections>
+                        <outlet property="aboutView" destination="EMj-bY-w8n" id="YZf-1O-mOo"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="RFr-BW-Q0P" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="166" y="926"/>
         </scene>
         <!--Navigation Controller-->
         <scene sceneID="YFg-Co-Dc2">
@@ -123,19 +161,18 @@
         <scene sceneID="WMF-B6-2e0">
             <objects>
                 <tableViewController id="0h7-h3-thM" customClass="ParametersViewController" sceneMemberID="viewController">
-                    <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="XKe-Ex-Vcl">
-                        <rect key="frame" x="0.0" y="64" width="320" height="504"/>
+                    <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="XKe-Ex-Vcl">
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                         <prototypes>
                             <tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="setting" id="Ryv-6O-Xsf">
-                                <rect key="frame" x="0.0" y="22" width="320" height="44"/>
+                                <rect key="frame" x="0.0" y="86" width="320" height="44"/>
                                 <autoresizingMask key="autoresizingMask"/>
-                                <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Ryv-6O-Xsf" id="e1l-jJ-ItW">
                                     <rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
                                     <autoresizingMask key="autoresizingMask"/>
-                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
-                                </view>
+                                </tableViewCellContentView>
                             </tableViewCell>
                         </prototypes>
                         <connections>
@@ -158,19 +195,18 @@
         <scene sceneID="hN1-wg-Dof">
             <objects>
                 <tableViewController id="tLo-wG-spu" customClass="OptionsViewController" sceneMemberID="viewController">
-                    <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="AUf-bU-fWv">
-                        <rect key="frame" x="0.0" y="64" width="320" height="504"/>
+                    <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="AUf-bU-fWv">
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                         <prototypes>
                             <tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="postProCell" id="7gg-dw-9nK">
-                                <rect key="frame" x="0.0" y="22" width="320" height="44"/>
+                                <rect key="frame" x="0.0" y="86" width="320" height="44"/>
                                 <autoresizingMask key="autoresizingMask"/>
-                                <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
+                                <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="7gg-dw-9nK" id="ejA-3y-SSJ">
                                     <rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
                                     <autoresizingMask key="autoresizingMask"/>
-                                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
-                                </view>
+                                </tableViewCellContentView>
                             </tableViewCell>
                         </prototypes>
                         <connections>
@@ -191,91 +227,92 @@
         <scene sceneID="nXH-mg-3hY">
             <objects>
                 <viewController storyboardIdentifier="PostProcessingViewController" id="pfu-w8-zq5" customClass="PostProcessingViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="KBG-YI-tIA"/>
+                        <viewControllerLayoutGuide type="bottom" id="4M7-bd-GcK"/>
+                    </layoutGuides>
                     <view key="view" contentMode="scaleToFill" id="Lh8-gQ-vBl">
-                        <rect key="frame" x="0.0" y="64" width="320" height="504"/>
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
                         <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                         <subviews>
                             <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="PView Name" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="z3z-Xo-nQF">
-                                <rect key="frame" x="20" y="53" width="280" height="36"/>
+                                <rect key="frame" x="20" y="70" width="280" height="36"/>
                                 <constraints>
-                                    <constraint firstAttribute="height" constant="36" id="Mei-3P-M3i"/>
+                                    <constraint firstAttribute="height" constant="36" id="zTU-8R-I6z"/>
                                 </constraints>
                                 <fontDescription key="fontDescription" type="system" pointSize="24"/>
                                 <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                 <nil key="highlightedColor"/>
                             </label>
                             <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="h3e-8g-CWy">
-                                <rect key="frame" x="14" y="97" width="292" height="387"/>
+                                <rect key="frame" x="14" y="114" width="292" height="434"/>
                                 <subviews>
                                     <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Intervals" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="elK-Av-NO2">
-                                        <rect key="frame" x="-8" y="224" width="91" height="21"/>
+                                        <rect key="frame" x="-8" y="172" width="91" height="21"/>
                                         <constraints>
-                                            <constraint firstAttribute="width" constant="91" id="BzM-Ls-Hjm"/>
+                                            <constraint firstAttribute="width" constant="91" id="g2R-zm-Dt4"/>
                                         </constraints>
                                         <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                         <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                         <nil key="highlightedColor"/>
                                     </label>
                                     <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="rgB-dz-6XG">
-                                        <rect key="frame" x="91" y="224" width="99" height="30"/>
+                                        <rect key="frame" x="91" y="168" width="71" height="30"/>
                                         <constraints>
-                                            <constraint firstAttribute="width" constant="99" id="TZK-Y4-wsY"/>
+                                            <constraint firstAttribute="width" constant="71" id="DMh-ns-x7e"/>
                                         </constraints>
                                         <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                         <textInputTraits key="textInputTraits"/>
                                     </textField>
                                     <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Raise (Z)" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Bfu-t9-dAj">
-                                        <rect key="frame" x="-8" y="265" width="91" height="21"/>
+                                        <rect key="frame" x="-8" y="217" width="91" height="21"/>
                                         <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                         <color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
                                         <nil key="highlightedColor"/>
                                     </label>
                                     <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" minValue="-5" maxValue="5" translatesAutoresizingMaskIntoConstraints="NO" id="BC5-E7-rEF">
-                                        <rect key="frame" x="89" y="264" width="185" height="23"/>
+                                        <rect key="frame" x="89" y="213" width="185" height="31"/>
                                     </slider>
-                                    <pickerView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xW0-cN-kxL">
-                                        <rect key="frame" x="0.0" y="0.0" width="292" height="216"/>
-                                        <constraints>
-                                            <constraint firstAttribute="height" constant="216" id="eIi-6g-osP"/>
-                                        </constraints>
-                                    </pickerView>
                                     <stepper opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" maximumValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="fq0-E8-V07">
-                                        <rect key="frame" x="198" y="225" width="94" height="27"/>
+                                        <rect key="frame" x="178" y="168" width="94" height="29"/>
                                         <connections>
                                             <action selector="stepperValueChanged:" destination="pfu-w8-zq5" eventType="valueChanged" id="d8w-ZF-KcK"/>
                                         </connections>
                                     </stepper>
+                                    <pickerView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xW0-cN-kxL">
+                                        <rect key="frame" x="17" y="0.0" width="258" height="162"/>
+                                    </pickerView>
                                 </subviews>
                                 <constraints>
-                                    <constraint firstItem="xW0-cN-kxL" firstAttribute="centerX" secondItem="h3e-8g-CWy" secondAttribute="centerX" type="default" id="4ni-Yo-p6H"/>
-                                    <constraint firstItem="rgB-dz-6XG" firstAttribute="top" secondItem="xW0-cN-kxL" secondAttribute="bottom" constant="8" symbolic="YES" type="default" id="5BQ-bg-XSg"/>
-                                    <constraint firstItem="BC5-E7-rEF" firstAttribute="top" secondItem="h3e-8g-CWy" secondAttribute="top" constant="264" id="5RQ-va-g48"/>
-                                    <constraint firstItem="BC5-E7-rEF" firstAttribute="leading" secondItem="Bfu-t9-dAj" secondAttribute="trailing" constant="8" symbolic="YES" type="default" id="CNf-Ik-oW4"/>
-                                    <constraint firstAttribute="bottom" secondItem="Bfu-t9-dAj" secondAttribute="bottom" constant="145" id="Gfb-TC-b5E"/>
-                                    <constraint firstAttribute="trailing" secondItem="BC5-E7-rEF" secondAttribute="trailing" constant="20" symbolic="YES" type="default" id="JZF-g0-ZqE"/>
-                                    <constraint firstItem="rgB-dz-6XG" firstAttribute="leading" secondItem="BC5-E7-rEF" secondAttribute="leading" type="default" id="MfT-eG-bon"/>
-                                    <constraint firstItem="fq0-E8-V07" firstAttribute="trailing" secondItem="h3e-8g-CWy" secondAttribute="trailing" type="default" id="XeV-67-kL1"/>
-                                    <constraint firstItem="xW0-cN-kxL" firstAttribute="leading" secondItem="h3e-8g-CWy" secondAttribute="leading" type="default" id="bTj-Wx-jtr"/>
-                                    <constraint firstItem="elK-Av-NO2" firstAttribute="leading" secondItem="Bfu-t9-dAj" secondAttribute="leading" type="default" id="cQP-EU-9zW"/>
-                                    <constraint firstItem="xW0-cN-kxL" firstAttribute="trailing" secondItem="h3e-8g-CWy" secondAttribute="trailing" type="default" id="fmj-d2-e7v"/>
-                                    <constraint firstItem="BC5-E7-rEF" firstAttribute="bottom" secondItem="Bfu-t9-dAj" secondAttribute="bottom" type="default" id="gm4-9E-5uE"/>
-                                    <constraint firstItem="fq0-E8-V07" firstAttribute="leading" secondItem="rgB-dz-6XG" secondAttribute="trailing" constant="8" symbolic="YES" type="default" id="hJn-Fo-JAG"/>
-                                    <constraint firstItem="rgB-dz-6XG" firstAttribute="leading" secondItem="elK-Av-NO2" secondAttribute="trailing" constant="8" symbolic="YES" type="default" id="hj9-gA-iP5"/>
-                                    <constraint firstItem="fq0-E8-V07" firstAttribute="top" secondItem="h3e-8g-CWy" secondAttribute="top" constant="225" id="nIt-Yg-2n5"/>
-                                    <constraint firstItem="xW0-cN-kxL" firstAttribute="top" secondItem="h3e-8g-CWy" secondAttribute="top" type="default" id="sVP-d2-DVC"/>
-                                    <constraint firstItem="elK-Av-NO2" firstAttribute="top" secondItem="xW0-cN-kxL" secondAttribute="bottom" constant="8" symbolic="YES" type="default" id="zjQ-mR-FRi"/>
+                                    <constraint firstItem="BC5-E7-rEF" firstAttribute="leading" secondItem="Bfu-t9-dAj" secondAttribute="trailing" constant="8" symbolic="YES" id="171-4w-6wl"/>
+                                    <constraint firstItem="Bfu-t9-dAj" firstAttribute="leading" secondItem="elK-Av-NO2" secondAttribute="leading" id="1t0-hf-2Hf"/>
+                                    <constraint firstItem="Bfu-t9-dAj" firstAttribute="top" secondItem="elK-Av-NO2" secondAttribute="bottom" constant="24" id="2cz-wD-n92"/>
+                                    <constraint firstItem="xW0-cN-kxL" firstAttribute="top" secondItem="h3e-8g-CWy" secondAttribute="top" id="6Tb-lU-QwA"/>
+                                    <constraint firstItem="elK-Av-NO2" firstAttribute="top" secondItem="xW0-cN-kxL" secondAttribute="bottom" constant="10" id="6dl-PR-DcO"/>
+                                    <constraint firstItem="xW0-cN-kxL" firstAttribute="leading" secondItem="h3e-8g-CWy" secondAttribute="leading" constant="17" id="DQh-yQ-mvn"/>
+                                    <constraint firstItem="elK-Av-NO2" firstAttribute="top" secondItem="rgB-dz-6XG" secondAttribute="top" constant="4" id="HEg-td-wvJ"/>
+                                    <constraint firstItem="xW0-cN-kxL" firstAttribute="centerX" secondItem="h3e-8g-CWy" secondAttribute="centerX" id="HHR-C5-tPS"/>
+                                    <constraint firstAttribute="bottom" secondItem="BC5-E7-rEF" secondAttribute="bottom" constant="136" id="Lwf-Ue-JYj"/>
+                                    <constraint firstItem="elK-Av-NO2" firstAttribute="leading" secondItem="h3e-8g-CWy" secondAttribute="leading" constant="-8" id="NO1-74-SYu"/>
+                                    <constraint firstItem="fq0-E8-V07" firstAttribute="trailing" secondItem="BC5-E7-rEF" secondAttribute="trailing" id="PvF-F6-GGY"/>
+                                    <constraint firstItem="BC5-E7-rEF" firstAttribute="top" secondItem="fq0-E8-V07" secondAttribute="bottom" constant="16" id="Qd9-fY-MEn"/>
+                                    <constraint firstItem="fq0-E8-V07" firstAttribute="leading" secondItem="rgB-dz-6XG" secondAttribute="trailing" constant="16" id="Uce-JP-GEZ"/>
+                                    <constraint firstItem="BC5-E7-rEF" firstAttribute="top" secondItem="rgB-dz-6XG" secondAttribute="bottom" constant="15" id="V0c-P0-Cga"/>
+                                    <constraint firstItem="rgB-dz-6XG" firstAttribute="leading" secondItem="elK-Av-NO2" secondAttribute="trailing" constant="8" symbolic="YES" id="j3z-BG-Bm9"/>
+                                    <constraint firstItem="rgB-dz-6XG" firstAttribute="leading" secondItem="BC5-E7-rEF" secondAttribute="leading" id="mX9-R6-657"/>
+                                    <constraint firstAttribute="trailing" secondItem="fq0-E8-V07" secondAttribute="trailing" constant="20" symbolic="YES" id="xfn-S1-D4x"/>
                                 </constraints>
                             </scrollView>
                         </subviews>
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
                         <constraints>
-                            <constraint firstItem="z3z-Xo-nQF" firstAttribute="leading" secondItem="Lh8-gQ-vBl" secondAttribute="leading" constant="20" symbolic="YES" type="default" id="435-s8-4Es"/>
-                            <constraint firstAttribute="trailing" secondItem="z3z-Xo-nQF" secondAttribute="trailing" constant="20" symbolic="YES" type="default" id="DFn-CU-BmX"/>
-                            <constraint firstItem="h3e-8g-CWy" firstAttribute="centerX" secondItem="z3z-Xo-nQF" secondAttribute="centerX" type="default" id="L5J-u7-VrJ"/>
-                            <constraint firstItem="h3e-8g-CWy" firstAttribute="leading" secondItem="Lh8-gQ-vBl" secondAttribute="leading" constant="14" id="UC0-pZ-0HO"/>
-                            <constraint firstItem="z3z-Xo-nQF" firstAttribute="top" secondItem="Lh8-gQ-vBl" secondAttribute="top" constant="53" id="e9a-2b-RgF"/>
-                            <constraint firstItem="h3e-8g-CWy" firstAttribute="top" secondItem="z3z-Xo-nQF" secondAttribute="bottom" constant="8" symbolic="YES" type="default" id="hsk-ey-mik"/>
-                            <constraint firstAttribute="bottom" secondItem="h3e-8g-CWy" secondAttribute="bottom" constant="20" symbolic="YES" type="default" id="kKd-el-hNE"/>
+                            <constraint firstItem="z3z-Xo-nQF" firstAttribute="top" secondItem="KBG-YI-tIA" secondAttribute="bottom" constant="6" id="3sW-ft-cxl"/>
+                            <constraint firstItem="h3e-8g-CWy" firstAttribute="leading" secondItem="Lh8-gQ-vBl" secondAttribute="leading" constant="14" id="CST-ND-FJF"/>
+                            <constraint firstItem="h3e-8g-CWy" firstAttribute="centerX" secondItem="z3z-Xo-nQF" secondAttribute="centerX" id="TqQ-12-vnX"/>
+                            <constraint firstAttribute="bottom" secondItem="h3e-8g-CWy" secondAttribute="bottom" constant="20" symbolic="YES" id="anm-iu-ift"/>
+                            <constraint firstItem="z3z-Xo-nQF" firstAttribute="leading" secondItem="Lh8-gQ-vBl" secondAttribute="leading" constant="20" symbolic="YES" id="jF4-08-vhZ"/>
+                            <constraint firstAttribute="trailing" secondItem="z3z-Xo-nQF" secondAttribute="trailing" constant="20" symbolic="YES" id="wbV-Vl-wDT"/>
+                            <constraint firstItem="h3e-8g-CWy" firstAttribute="top" secondItem="z3z-Xo-nQF" secondAttribute="bottom" constant="8" symbolic="YES" id="zzS-9L-S8L"/>
                         </constraints>
                     </view>
                     <navigationItem key="navigationItem" id="d15-oM-VRg"/>
@@ -292,9 +329,12 @@
             <point key="canvasLocation" x="1596" y="160"/>
         </scene>
     </scenes>
+    <resources>
+        <image name="icon_rotate.png" width="512" height="512"/>
+    </resources>
     <simulatedMetricsContainer key="defaultSimulatedMetrics">
         <simulatedStatusBarMetrics key="statusBar"/>
         <simulatedOrientationMetrics key="orientation"/>
         <simulatedScreenMetrics key="destination" type="retina4"/>
     </simulatedMetricsContainer>
-</document>
\ No newline at end of file
+</document>
diff --git a/contrib/mobile/iOS/Onelab/files/magnet/Magnetostatics.pro b/contrib/mobile/iOS/Onelab/files/magnet/Magnetostatics.pro
deleted file mode 100644
index c09e3a5..0000000
--- a/contrib/mobile/iOS/Onelab/files/magnet/Magnetostatics.pro
+++ /dev/null
@@ -1,215 +0,0 @@
-Group {
-  // Input groups:
-  DefineGroup[
-    Domain_M = {{},
-      Name "Regions/0Sources/Permanent magnets"},
-    Domain_S = {{},
-      Name "Regions/0Sources/Inductor (imposed j_s)"},
-    Domain_Inf = {{},
-      Name "Regions/0Special regions/Infinite domain (spherical shell)",
-      Closed "1"},
-    Domain_Mag = {{},
-      Name "Regions/Other regions/Passive magnetic regions"},
-    Dirichlet_phi_0 = {{},
-      Name "Regions/0Boundary conditions/h_t = 0", Closed "1"},
-    Dirichlet_a_0 = {{},
-      Name "Regions/0Boundary conditions/b_n = 0"} ];
-
-  DefineGroup[ Domain = {{Domain_Mag, Domain_M, Domain_S, Domain_Inf},
-      Name "Regions/Computational domain", Visible 0} ];
-}
-
-Function{
-  // Input constants:
-  DefineConstant[ Val_Rint, Val_Rext // interior/exterior radius of Domain_Inf
-                  ];
-
-  // Input functions:
-  DefineFunction[ mu, // magnetic permeability
-                  nu, // magnetic reluctivity
-                  hc, // coercive magnetic field
-                  js // source current density
-                  ];
-
-  // remove this: only for demo
-  //DefineConstant[ hcx = {0, Label "Coercive field h_x", Path "Sources"}];
-  //DefineConstant[ hcy = {1000, Label "Coercive field h_y", Path "Sources"}];
-  //hc[] = Vector[hcx,hcy,0];
-  //mu[] = 4*Pi*10^-7;
-  //nu[] = 1/mu[];
-}
-
-Jacobian {
-  { Name JVol ;
-    Case {
-      { Region Domain_Inf ; Jacobian VolSphShell{Val_Rint, Val_Rext} ; }
-      { Region All ; Jacobian Vol ; }
-    }
-  }
-}
-
-Integration {
-  { Name I1 ;
-    Case {
-      { Type Gauss ;
-        Case {
-	  { GeoElement Triangle ; NumberOfPoints 4 ; }
-	  { GeoElement Quadrangle  ; NumberOfPoints 4 ; }
-	}
-      }
-    }
-  }
-}
-
-
-/* --------------------------------------------------------------------------
-   MagSta_phi : Magnetic scalar potential phi formulation
-   -------------------------------------------------------------------------- */
-
-Constraint {
-  { Name phi ;
-    Case {
-      { Region Dirichlet_phi_0 ; Value 0. ; }
-    }
-  }
-}
-
-FunctionSpace {
-  { Name Hgrad_phi ; Type Form0 ;
-    BasisFunction {
-      { Name sn ; NameOfCoef phin ; Function BF_Node ;
-        Support Domain ; Entity NodesOf[ All ] ; }
-    }
-    Constraint {
-      { NameOfCoef phin ; EntityType NodesOf ; NameOfConstraint phi ; }
-    }
-  }
-}
-
-Formulation {
-  { Name MagSta_phi ; Type FemEquation ;
-    Quantity {
-      { Name phi ; Type Local ; NameOfSpace Hgrad_phi ; }
-    }
-    Equation {
-      Galerkin { [ - mu[] * Dof{d phi} , {d phi} ] ;
-                 In Domain ; Jacobian JVol ; Integration I1 ; }
-
-      Galerkin { [ - mu[] * hc[] , {d phi} ] ;
-                 In Domain_M ; Jacobian JVol ; Integration I1 ; }
-    }
-  }
-}
-
-Resolution {
-  { Name MagSta_phi ;
-    System {
-      { Name A ; NameOfFormulation MagSta_phi ; }
-    }
-    Operation {
-      Generate[A] ; Solve[A] ; SaveSolution[A] ;
-    }
-  }
-}
-
-PostProcessing {
-  { Name MagSta_phi ; NameOfFormulation MagSta_phi ;
-    Quantity {
-      { Name b   ; Value { Local { [ - mu[] * {d phi} ] ; In Domain ; Jacobian JVol ; }
-                           Local { [ - mu[] * hc[] ]    ; In Domain_M ; Jacobian JVol ; } } }
-      { Name h   ; Value { Local { [ - {d phi} ]        ; In Domain ; Jacobian JVol ; } } }
-      { Name hc  ; Value { Local { [ hc[] ]             ; In Domain_M ; Jacobian JVol ; } } }
-      { Name phi ; Value { Local { [ {phi} ]            ; In Domain ; Jacobian JVol ; } } }
-    }
-  }
-}
-
-PostOperation {
-  { Name MagSta_phi ; NameOfPostProcessing MagSta_phi;
-    Operation {
-      Print[ b, OnElementsOf Domain, File "MagSta_phi_b.pos" ] ;
-      Print[ h, OnElementsOf Domain, File "MagSta_phi_h.pos" ] ;
-      Print[ hc, OnElementsOf Domain, File "MagSta_a_hc.pos" ] ;
-      Print[ phi, OnElementsOf Domain, File "MagSta_phi_phi.pos" ] ;
-    }
-  }
-}
-
-/* --------------------------------------------------------------------------
-   MagSta_a : Magnetic vector potential a formulation (2D)
-   -------------------------------------------------------------------------- */
-
-Constraint {
-  { Name a ;
-    Case {
-      { Region Dirichlet_a_0 ; Value 0. ; }
-    }
-  }
-}
-
-FunctionSpace {
-
-  { Name Hcurl_a ; Type Form1P ;
-    BasisFunction {
-      { Name se ; NameOfCoef ae ; Function BF_PerpendicularEdge ;
-        Support Domain ; Entity NodesOf[ All ] ; }
-    }
-    Constraint {
-      { NameOfCoef ae ; EntityType NodesOf ; NameOfConstraint a ; }
-    }
-  }
-
-}
-
-Formulation {
-  { Name MagSta_a ; Type FemEquation ;
-    Quantity {
-      { Name a  ; Type Local ; NameOfSpace Hcurl_a ; }
-    }
-    Equation {
-      Galerkin { [ nu[] * Dof{d a} , {d a} ] ;
-                 In Domain ; Jacobian JVol ; Integration I1 ; }
-
-      Galerkin { [ hc[] , {d a} ] ;
-                 In Domain_M ; Jacobian JVol ; Integration I1 ; }
-
-      Galerkin { [ -js[] , {a} ] ;
-                 In Domain_S ; Jacobian JVol ; Integration I1 ; }
-    }
-  }
-}
-
-Resolution {
-  { Name MagSta_a ;
-    System {
-      { Name A ; NameOfFormulation MagSta_a ; }
-    }
-    Operation {
-      Generate[A] ; Solve[A] ; SaveSolution[A];
-    }
-  }
-}
-
-PostProcessing {
-  { Name MagSta_a ; NameOfFormulation MagSta_a ;
-    Quantity {
-      { Name az ; Value { Local { [ CompZ[{a}] ]   ; In Domain ; Jacobian JVol ; } } }
-      { Name b ; Value { Local { [ {d a} ]        ; In Domain ; Jacobian JVol ; } } }
-      { Name a ; Value { Local { [ {a} ]          ; In Domain ; Jacobian JVol ; } } }
-      { Name h ; Value { Local { [ nu[] * {d a} ] ; In Domain ; Jacobian JVol ; }
-                         Local { [ hc[] ]         ; In Domain_M ; Jacobian JVol ; } } }
-      { Name hc  ; Value { Local { [ hc[] ]       ; In Domain_M ; Jacobian JVol ; } } }
-    }
-  }
-}
-
-PostOperation {
-  { Name MagSta_a ; NameOfPostProcessing MagSta_a;
-    Operation {
-      Print[ b, OnElementsOf Domain, File "MagSta_a_b.pos" ] ;
-      Print[ h, OnElementsOf Domain, File "MagSta_a_h.pos" ] ;
-      Print[ hc, OnElementsOf Domain, File "MagSta_a_hc.pos" ] ;
-      Print[ a, OnElementsOf Domain, File "MagSta_a_a.pos" ] ;
-    }
-  }
-}
diff --git a/contrib/mobile/iOS/Onelab/files/magnet/infos.xml b/contrib/mobile/iOS/Onelab/files/magnet/infos.xml
deleted file mode 100644
index bc15d05..0000000
--- a/contrib/mobile/iOS/Onelab/files/magnet/infos.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<models>
-	<model>
-		<title>Magnet</title>
-		<summary>Simple magnet example.</summary>
-		<file type="pro">magnet.pro</file>
-	</model>
-</models>
diff --git a/contrib/mobile/iOS/Onelab/files/magnet/magnet.geo b/contrib/mobile/iOS/Onelab/files/magnet/magnet.geo
deleted file mode 100644
index 6893439..0000000
--- a/contrib/mobile/iOS/Onelab/files/magnet/magnet.geo
+++ /dev/null
@@ -1,88 +0,0 @@
-Include "magnet_data.pro";
-
-DefineConstant[ h = {0.14, Min 0.1, Max 0.2, Step 0.01,
-    Name "Parameters/Geometry/Core height (m)"} ] ;
-
-DefineConstant[ l = {0.14, Min 0.05, Max 0.2, Step 0.01,
-    Name "Parameters/Geometry/Core width (m)"} ] ;
-
-DefineConstant[ d = {0.03, Min 0.01, Max 0.05, Step 0.002,
-    Name "Parameters/Geometry/Core thickness (m)"} ] ;
-
-DefineConstant[ e = {5e-3, Min 5e-4, Max d, Step 1e-3,
-    Name "Parameters/Geometry/Air gap (m)", Highlight "LightYellow"} ] ;
-
-DefineConstant[ ha = {0.03, Min 0.01, Max 0.1, Step 0.01,
-    Name "Parameters/Geometry/Magnet height (m)"} ] ;
-
-lc0 = d / 5 ;
-lc1 = e / 2 ;
-lc2 = (Val_Rext - Val_Rint) / 8. ;
-
-Point(1) = {0, 0, 0, lc0};
-Point(2) = {-l/2, 0, 0, lc0};
-Point(3) = {-l/2, h/2, 0, lc0};
-Point(4) = {l/2, 0, 0, lc1};
-Point(5) = {l/2, h/2, 0, lc0};
-Point(6) = {-l/2, ha/2, 0, lc0};
-Point(7) = {-l/2+d, ha/2, 0, lc0};
-Point(8) = {-l/2+d, 0, 0, lc0};
-Point(9) = {l/2-d, 0, 0, lc1};
-Point(10) = {l/2-d, h/2-d, 0, lc0};
-Point(11) = {-l/2+d, h/2-d, 0, lc0};
-Point(12) = {l/2, e/2, 0, lc1};
-Point(13) = {l/2-d, e/2, 0, lc1};
-
-Point(30) = {Val_Rint, 0, 0, lc2};
-Point(31) = {Val_Rext, 0, 0, lc2};
-Point(32) = {0, Val_Rint, 0, lc2};
-Point(33) = {0, Val_Rext, 0, lc2};
-Point(34) = {-Val_Rext, 0, 0, lc2};
-Point(35) = {-Val_Rint, 0, 0, lc2};
-
-Line(1) = {34, 35};
-Line(2) = {35, 2};
-Line(3) = {2, 8};
-Line(4) = {8, 1};
-Line(5) = {1, 9};
-Line(6) = {9, 4};
-Line(7) = {4, 30};
-Line(8) = {30, 31};
-Line(9) = {2, 6};
-Line(10) = {6, 3};
-Line(11) = {3, 5};
-Line(12) = {5, 12};
-Line(13) = {12, 4};
-Line(14) = {9, 13};
-Line(15) = {13, 10};
-Line(16) = {10, 11};
-Line(17) = {11, 7};
-Line(18) = {7, 8};
-Line(19) = {7, 6};
-Line(20) = {13, 12};
-Circle(21) = {35, 1, 32};
-Circle(22) = {32, 1, 30};
-Circle(23) = {34, 1, 33};
-Circle(24) = {33, 1, 31};
-
-Line Loop(25) = {21, 22, 8, -24, -23, 1};
-Plane Surface(26) = {25};
-Line Loop(27) = - {22, -7, -13, -12, -11, -10, -9, -2, 21};
-Plane Surface(28) = {27};
-Line Loop(29) = - {11, 12, -20, 15, 16, 17, 19, 10};
-Plane Surface(30) = {29};
-Line Loop(31) = {19, -9, 3, -18};
-Plane Surface(32) = {31};
-Line Loop(33) = - {20, 13, -6, 14};
-Plane Surface(34) = {33};
-Line Loop(35) = {15, 16, 17, 18, 4, 5, 14};
-Plane Surface(36) = {35};
-
-// physical entities (for which elements will be saved)
-Physical Surface(AIR) = {28, 36};
-Physical Surface(AIR_INF) = {26};
-Physical Surface(AIR_GAP) = {34};
-Physical Surface(MAGNET) = {32};
-Physical Surface(CORE) = {30};
-Physical Line(LINE_INF) = {23, 24};
-Physical Line(LINE_X) = {1:8};
diff --git a/contrib/mobile/iOS/Onelab/files/magnet/magnet.pro b/contrib/mobile/iOS/Onelab/files/magnet/magnet.pro
deleted file mode 100644
index 1645e94..0000000
--- a/contrib/mobile/iOS/Onelab/files/magnet/magnet.pro
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-   To solve the problem
-   with scalar potential, type 'getdp test -solve MagSta_phi -pos phi'
-   with vector potential, type 'getdp test -solve MagSta_a -pos a'
-*/
-
-Include "magnet_data.pro";
-
-Group {
-  // AIR, AIR_INF, etc. are variables defined in core.txt, and correspond to the
-  // tags of physical regions in the mesh
-  Air     = Region[ AIR ];
-  AirInf  = Region[ AIR_INF ];
-  Core    = Region[ CORE ];
-  AirGap  = Region[ AIR_GAP ];
-  Magnet  = Region[ MAGNET ];
-
-  // These are the generic group names that are used in "Magnetostatics.pro"
-  Domain_S = Region[ {} ] ;
-  Domain_Inf = Region[ AirInf ] ;
-  Domain_M   = Region[ Magnet ] ;
-  Domain_Mag = Region[ {Air, Core, AirGap} ] ;
-  Dirichlet_a_0   = Region[ LINE_INF ] ;
-  Dirichlet_phi_0 = Region[ {LINE_X, LINE_INF} ] ;
-}
-
-Function {
-  mu0 = 4.e-7 * Pi ;
-
-  // DefineConstant is used to define a default value for murCore; this value
-  // can be changed interactively by the ONELAB server
-  DefineConstant[ murCore = {200., Min 1, Max 1000, Step 10,
-      Name "Parameters/Materials/Core relative permeability"} ];
-
-  nu [ Region[{Air, AirInf, AirGap, Magnet}] ] = 1. / mu0 ;
-  nu [ Core ]  = 1. / (murCore * mu0) ;
-
-  mu [ Region[{Air, AirInf, AirGap, Magnet}] ] = mu0 ;
-  mu [ Core ]  = murCore * mu0;
-
-  DefineConstant[ Hc = {920000,
-      Name "Parameters/Materials/hc", Label "Magnet coercive field (A/m)"} ];
-  hc [ Magnet ] = Rotate[ Vector[Hc, 0, 0.], 0, 0, Pi/2] ;
-}
-
-Include "Magnetostatics.pro"
-
-eps = 1.e-5 ;
-
-PostOperation {
-  { Name phi ; NameOfPostProcessing MagSta_phi;
-    Operation {
-      Print[ phi, OnElementsOf Domain, File "phi.pos" ] ;
-      Print[ hc, OnElementsOf Domain, File "hc.pos" ] ;
-      Print[ b, OnElementsOf Domain, File "b_phi.pos" ] ;
-      Print[ b, OnLine {{-0.07,eps,0}{0.09,eps,0}} {500}, File "b_phi.txt", Format Table ] ;
-    }
-  }
-  { Name a ; NameOfPostProcessing MagSta_a;
-    Operation {
-      Print[ a, OnElementsOf Domain, File "a.pos"] ;
-      Print[ b, OnElementsOf Domain, File "b_a.pos" ] ;
-      Print[ h, OnElementsOf Domain, File "h_a.pos" ] ;
-      Print[ b, OnLine {{-0.07,eps,0}{0.09,eps,0}} {500}, File "b_a.txt" , Format Table ] ;
-    }
-  }
-}
diff --git a/contrib/mobile/iOS/Onelab/files/magnet/magnet_data.pro b/contrib/mobile/iOS/Onelab/files/magnet/magnet_data.pro
deleted file mode 100644
index 23f28a1..0000000
--- a/contrib/mobile/iOS/Onelab/files/magnet/magnet_data.pro
+++ /dev/null
@@ -1,14 +0,0 @@
-
-DefineConstant[ Val_Rint = {0.15, Min 0.2, Max 1, Step 0.1,
-    Name "Parameters/Geometry/1Internal shell radius (m)"} ];
-
-DefineConstant[ Val_Rext = {0.25, Min Val_Rint, Max 0.5, Step 0.1,
-    Name "Parameters/Geometry/2External shell radius (m)"}];
-
-AIR = 100;
-AIR_INF = 101;
-AIR_GAP = 102;
-MAGNET = 103;
-CORE = 104;
-LINE_INF = 105;
-LINE_X = 106;
diff --git a/contrib/mobile/iOS/Onelab/files/pmsm/BH.pro b/contrib/mobile/iOS/Onelab/files/pmsm/BH.pro
deleted file mode 100644
index e3783b1..0000000
--- a/contrib/mobile/iOS/Onelab/files/pmsm/BH.pro
+++ /dev/null
@@ -1,87 +0,0 @@
-Function{
-  // nu = 100. + 10. * exp ( 1.8 * b * b )
-  // analytical
-  nu_1a[] = 100. + 10. * Exp[1.8*SquNorm[$1]] ;
-  dnudb2_1a[] = 18. * Exp[1.8*SquNorm[$1]] ;
-  h_1a[] = nu_1a[$1]*$1 ;
-  dhdb_1a[] = TensorDiag[1,1,1] * nu_1a[$1#1] + 2*dnudb2_1a[#1] * SquDyadicProduct[#1]  ;
-  dhdb_1a_NL[] = 2*dnudb2_1a[$1#1] * SquDyadicProduct[#1]  ;
-
-  // interpolated
-  Mat1_h = {
-    0.0000e+00, 5.5023e+00, 1.1018e+01, 1.6562e+01, 2.2149e+01, 2.7798e+01, 3.3528e+01,
-    3.9363e+01, 4.5335e+01, 5.1479e+01, 5.7842e+01, 6.4481e+01, 7.1470e+01, 7.8906e+01,
-    8.6910e+01, 9.5644e+01, 1.0532e+02, 1.1620e+02, 1.2868e+02, 1.4322e+02, 1.6050e+02,
-    1.8139e+02, 2.0711e+02, 2.3932e+02, 2.8028e+02, 3.3314e+02, 4.0231e+02, 4.9395e+02,
-    6.1678e+02, 7.8320e+02, 1.0110e+03, 1.3257e+03, 1.7645e+03, 2.3819e+03, 3.2578e+03,
-    4.5110e+03, 6.3187e+03, 8.9478e+03, 1.2802e+04, 1.8500e+04, 2.6989e+04, 3.9739e+04,
-    5.9047e+04, 8.8520e+04, 1.3388e+05, 2.0425e+05, 3.1434e+05, 4.8796e+05, 7.6403e+05
-  } ;
-  Mat1_b = {
-    0.0000e+00, 5.0000e-02, 1.0000e-01, 1.5000e-01, 2.0000e-01, 2.5000e-01, 3.0000e-01,
-    3.5000e-01, 4.0000e-01, 4.5000e-01, 5.0000e-01, 5.5000e-01, 6.0000e-01, 6.5000e-01,
-    7.0000e-01, 7.5000e-01, 8.0000e-01, 8.5000e-01, 9.0000e-01, 9.5000e-01, 1.0000e+00,
-    1.0500e+00, 1.1000e+00, 1.1500e+00, 1.2000e+00, 1.2500e+00, 1.3000e+00, 1.3500e+00,
-    1.4000e+00, 1.4500e+00, 1.5000e+00, 1.5500e+00, 1.6000e+00, 1.6500e+00, 1.7000e+00,
-    1.7500e+00, 1.8000e+00, 1.8500e+00, 1.9000e+00, 1.9500e+00, 2.0000e+00, 2.0500e+00,
-    2.1000e+00, 2.1500e+00, 2.2000e+00, 2.2500e+00, 2.3000e+00, 2.3500e+00, 2.4000e+00
-  } ;
-
-  Mat1_b2 = List[Mat1_b]^2;
-  Mat1_nu = List[Mat1_h]/List[Mat1_b];
-  Mat1_nu(0) = Mat1_nu(1);
-
-  Mat1_nu_b2  = ListAlt[Mat1_b2, Mat1_nu] ;
-  nu_1[] = InterpolationLinear[ SquNorm[$1] ]{List[Mat1_nu_b2]} ;
-  dnudb2_1[] = dInterpolationLinear[SquNorm[$1]]{List[Mat1_nu_b2]} ;
-  h_1[] = nu_1[$1] * $1 ;
-  dhdb_1[] = TensorDiag[1,1,1] * nu_1[$1#1] + 2*dnudb2_1[#1] * SquDyadicProduct[#1]  ;
-  dhdb_1_NL[] = 2*dnudb2_1[$1#1] * SquDyadicProduct[#1] ;
-
-
-  // nu = 123. + 0.0596 * exp ( 3.504 * b * b )
-  // analytical 3kW machine
-  nu_3kWa[] = 123. + 0.0596 * Exp[3.504*SquNorm[$1]] ;
-  dnudb2_3kWa[] = 0.0596*3.504 * Exp[3.504*SquNorm[$1]] ;
-  h_3kWa[] = nu_3kWa[$1]*$1 ;
-  dhdb_3kWa[] = TensorDiag[1,1,1] * nu_3kWa[$1#1] + 2*dnudb2_3kWa[#1] * SquDyadicProduct[$1]  ;
-  dhdb_3kWa_NL[] = 2*dnudb2_3kWa[$1#1] * SquDyadicProduct[#1]  ;
-
-  // interpolated
-  Mat3kW_h = {
-    0.0000e+00, 6.1465e+00, 1.2293e+01, 1.8440e+01, 2.4588e+01, 3.0736e+01, 3.6886e+01,
-    4.3037e+01, 4.9190e+01, 5.5346e+01, 6.1507e+01, 6.7673e+01, 7.3848e+01, 8.0036e+01,
-    8.6241e+01, 9.2473e+01, 9.8745e+01, 1.0508e+02, 1.1150e+02, 1.1806e+02, 1.2485e+02,
-    1.3199e+02, 1.3971e+02, 1.4836e+02, 1.5856e+02, 1.7137e+02, 1.8864e+02, 2.1363e+02,
-    2.5219e+02, 3.1498e+02, 4.2161e+02, 6.0888e+02, 9.4665e+02, 1.5697e+03, 2.7417e+03,
-    4.9870e+03, 9.3633e+03, 1.8037e+04, 3.5518e+04, 7.1329e+04, 1.4591e+05, 3.0380e+05,
-    6.4363e+05, 1.3872e+06, 3.0413e+06, 6.7826e+06, 1.5386e+07, 3.5504e+07, 8.3338e+07
-  } ;
-  Mat3kW_b = {
-    0.0000e+00, 5.0000e-02, 1.0000e-01, 1.5000e-01, 2.0000e-01, 2.5000e-01, 3.0000e-01,
-    3.5000e-01, 4.0000e-01, 4.5000e-01, 5.0000e-01, 5.5000e-01, 6.0000e-01, 6.5000e-01,
-    7.0000e-01, 7.5000e-01, 8.0000e-01, 8.5000e-01, 9.0000e-01, 9.5000e-01, 1.0000e+00,
-    1.0500e+00, 1.1000e+00, 1.1500e+00, 1.2000e+00, 1.2500e+00, 1.3000e+00, 1.3500e+00,
-    1.4000e+00, 1.4500e+00, 1.5000e+00, 1.5500e+00, 1.6000e+00, 1.6500e+00, 1.7000e+00,
-    1.7500e+00, 1.8000e+00, 1.8500e+00, 1.9000e+00, 1.9500e+00, 2.0000e+00, 2.0500e+00,
-    2.1000e+00, 2.1500e+00, 2.2000e+00, 2.2500e+00, 2.3000e+00, 2.3500e+00, 2.4000e+00
-  } ;
-
-  Mat3kW_b2 = List[Mat3kW_b]^2;
-  Mat3kW_nu = List[Mat3kW_h]/List[Mat3kW_b];
-  Mat3kW_nu(0) = Mat3kW_nu(1);
-
-  Mat3kW_nu_b2  = ListAlt[Mat3kW_b2, Mat3kW_nu] ;
-  nu_3kW[] = InterpolationLinear[SquNorm[$1]]{List[Mat3kW_nu_b2]} ;
-  dnudb2_3kW[] = dInterpolationLinear[SquNorm[$1]]{List[Mat3kW_nu_b2]} ;
-  h_3kW[] = nu_3kW[$1] * $1 ;
-  dhdb_3kW[] = TensorDiag[1,1,1]*nu_3kW[$1#1] + 2*dnudb2_3kW[#1] * SquDyadicProduct[#1] ;
-  dhdb_3kW_NL[] = 2*dnudb2_3kW[$1] * SquDyadicProduct[$1] ;
-
-}
-
-
-
-
-
-
diff --git a/contrib/mobile/iOS/Onelab/files/pmsm/infos.xml b/contrib/mobile/iOS/Onelab/files/pmsm/infos.xml
deleted file mode 100644
index fe97ea0..0000000
--- a/contrib/mobile/iOS/Onelab/files/pmsm/infos.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<models>
-	<model>
-		<title>Eight-pole permanent magnet synchronous machine</title>
-		<summary></summary>
-		<file type="geo">pmsm.geo</file>
-		<preview type="png">screenshot1_512.png</preview>
-		<url>http://onelab.info/wiki/Electric_Machines</url>
-	</model>
-</models>
diff --git a/contrib/mobile/iOS/Onelab/files/pmsm/machine_magstadyn_a.pro b/contrib/mobile/iOS/Onelab/files/pmsm/machine_magstadyn_a.pro
deleted file mode 100644
index 03b4e01..0000000
--- a/contrib/mobile/iOS/Onelab/files/pmsm/machine_magstadyn_a.pro
+++ /dev/null
@@ -1,1091 +0,0 @@
-/*
-  This template file contains a generic getdp/onelab template for 2D models of
-  rotating electrical machines.  Fields are computed with a vector potential
-  formulation. Motion is solved with the moving band technique.
-
-  The template begins with a section devoted to the declaration of all potential
-  interface variables, i.e. template variables that can be accessed/redefined
-  from outside the template. Interface variables are either
-  - groups (declared with DefineGroup[...])
-  - functions (declared with DefineFunction[...])
-  - constants (declared with DefineConstant[...])
-
-  This declaration mechanism
-  - allows the user to define the quantities of interest only, the others being
-  assigned a default value (zero or "empty" if no value given in the declaration
-  sentence)
-  - avoids irrelevant error messages being produced when referencing to the
-  unused variables in the template
-
-  Redeclarations are ignored.
-*/
-
-//-------------------------------------------------------------------------------------
-// Groups:
-// The groups declared in this section can be defined by the user according to
-// the characteristics of the modelled machine in a "model.pro" file including
-// this template file.
-
-Group {
-  DefineGroup[
-    Stator_Inds, StatorC, StatorCC, Stator_Air, Stator_Airgap, Stator_Magnets,
-    Rotor_Inds, RotorC, RotorCC, Rotor_Air, Rotor_Airgap, Rotor_Magnets, Rotor_Bars,
-    Stator_IndsP, Stator_IndsN, Rotor_IndsP, Rotor_IndsN,
-    Stator_Al, Rotor_Al, Stator_Cu, Rotor_Cu, Stator_Fe, Rotor_Fe,
-    Stator_Bnd_MB, Rotor_Bnd_MBaux, Rotor_Bnd_MB,
-    Surf_bn0, Surf_Inf, Point_ref,
-    PhaseA, PhaseB, PhaseC, PhaseA_pos, PhaseB_pos, PhaseC_pos,
-    Resistance_Cir, Inductance_Cir, Capacitance_Cir, DomainZt_Cir, DomainSource_Cir
-  ];
-  // Exception: the group 'MovingBand_PhysicalNb' needs contain exactly one region
-  // to pass a test done by the parser. It is declared with a dummy region "0".
-  MovingBand_PhysicalNb = #0 ;
-}
-
-//-------------------------------------------------------------------------------------
-// Constants:
-// Interface constants are declared in this section. Constants declared with
-// a DefineConstant[...] AND with a `Name' attribute are automatically added to
-// the ONELAB parameter database. Any previous declaration in another file of a
-// ONELAB paramater with the same name will link to the corresponding template
-// parameter.
-
-DefineConstant[
-  // Analysis type
-  Flag_AnalysisType = 0,
-  // Symmetry
-  AxialLength = 1,
-  SymmetryFactor = 1,
-  Flag_Symmetry = (SymmetryFactor==1) ? 0 : 1,
-  Term_vxb = 0,
-  // Time and frequency
-  Freq = 534,
-  Period = 1/Freq,
-  time0 = 0,
-  NbrPeriod = 1,
-  timemax = NbrPeriod * Period,
-  NbSteps = 1,
-  delta_time = Period / NbSteps,
-  // Material characteristics
-  mur_fe = 1.0e3,
-  sigma_al = 3.72e7, // conductivity of aluminum [S/m]
-  sigma_cu = 5.9e7  // conductivity of copper [S/m]
-  sigma_fe = 1.0e7, // conductivity of iron [S/m]
-  // Nonlinear iterations
-  Flag_NL = 0,
-  Flag_NL_law_Type = 0,
-  Nb_max_iter = {30, Name "Nonlinear solver/Max. num. iterations", Visible 0},
-  relaxation_factor = {1, Name "Nonlinear solver/Relaxation factor", Visible 0},
-  stop_criterion = {1e-5, Name "Nonlinear solver/Stopping criterion", Visible 0},
-  // Coil system
-  NbrPhases = 3,
-  FillFactor_Winding = 1,
-  Factor_R_3DEffects = 1,
-  // Electrical circuit
-  Flag_Cir = 0,
-  Flag_ParkTransformation = 0,
-  Flag_ConstantSource = 0,
-  Flag_SrcType_Stator = 0,
-  Flag_SrcType_Rotor = 0, Flag_Cir_RotorCage = 0,
-  II = 0, VV = 0, wr = 0,
-  Ia = II,
-  Ib = II,
-  Ic = II,
-  Va = VV,
-  Vb = VV,
-  Vc = VV,
-  pA = 0, pB = 0, pC = 0, Ie = 0, ID = 0, IQ = 0, I0 = 0,
-  variableFrequencyLoop = wr,
-  initialFrequencyLoop = 0,
-  Flag_SrcType_StatorA = Flag_SrcType_Stator,
-  Flag_SrcType_StatorB = Flag_SrcType_Stator,
-  Flag_SrcType_StatorC = Flag_SrcType_Stator,
-  // Mechanical equation
-  Inertia = 0,
-  Flag_ImposedSpeed = 1,
-  // Simulation parameters
-  Flag_SaveAllSteps = {0, Name "Input/00Save all time steps", Choices {0,1}},
-  Clean_Results = {1, Name "Input/01Remove previous result files", Choices {0,1}},
-  ResDir = "res/",
-  ExtGmsh = ".pos",
-  ExtGnuplot = ".dat"
-  R_ = {"Analysis", Name "GetDP/1ResolutionChoices", Visible 0},
-  C_ = {"-solve -v 3 -v2", Name "GetDP/9ComputeCommand", Visible 0},
-  P_ = {"", Name "GetDP/2PostOperationChoices", Visible 0}
-];
-
-//-------------------------------------------------------------------------------------
-// Function declaration:
-// Functions that can be defined explicitly outside the template in a calling .pro file
-// are declared here so that their identifiers exist and can be referred to
-// (but cannot be used) in other objects.
-
-Function{
-  DefineFunction[
-    br, js,
-    Resistance, Inductance, Capacitance, NbWires, SurfCoil,
-    Theta_Park, Theta_Park_deg,
-    RotorPosition, RotorPosition_deg, Friction, Torque_mec
-  ];
-}
-
-// End of declarations
-//-------------------------------------------------------------------------------------
-
-
-//-------------------------------------------------------------------------------------
-// Defninition of "template groups"
-// Template groups represent the regions in terms of which the assembly or not
-// of FE terms and the postprocessing calculations are controlled.  Template
-// groups are defined in this section in terms of the above declared "user
-// defined groups".
-
-Group {
-  //   DomainC    : with massive conductors
-  //   DomainCC   : non-conducting domain
-  //   DomainM    : with permanent magnets
-  //   DomainB    : with inductors
-  //   DomainS    : with imposed current density
-  //   DomainL    : with linear permeability (no jacobian matrix)
-  //   DomainNL   : with nonlinear permeability (jacobian matrix)
-  //   DomainV    : with additional vxb term
-  //   DomainKin  : region number for mechanical equation
-  //   Dummy      : region number for postpro with functions
-
-  Inds = Region[ {Stator_Inds, Rotor_Inds} ] ;
-
-  DomainB = Region[ {Inds} ] ;
-  DomainM = Region[ {Stator_Magnets, Rotor_Magnets} ] ;
-  DomainS = Region[{}];
-  Dummy = Region[{}];
-
-  Stator  = Region[{ StatorC, StatorCC }] ;
-  Rotor   = Region[{ RotorC,  RotorCC }] ;
-
-  Rotor_Moving = Region[{ Rotor, Rotor_Air, Rotor_Airgap, Rotor_Inds, Rotor_Bnd_MBaux} ] ;
-  // used in ChangeOfCoordinates
-
-  MB  = MovingBand2D[ MovingBand_PhysicalNb, Stator_Bnd_MB, Rotor_Bnd_MB, SymmetryFactor] ;
-  Air = Region[{ Rotor_Air, Rotor_Airgap, Stator_Air, Stator_Airgap, MB } ] ;
-
-  DomainCC = Region[{ Air, Inds, StatorCC, RotorCC }];
-  DomainC  = Region[{ StatorC, RotorC }];
-  Domain  = Region[{ DomainCC, DomainC }] ;
-
-  DomainNL = Region[{}];
-  If(Flag_NL)
-    DomainNL = Region[ {Stator_Fe, Rotor_Fe } ];
-    DomainL  = Region[ {Domain,-DomainNL} ];
-  EndIf
-
-  DomainV = Region[{}];
-  If(Term_vxb) // or not dynamics in time domain + mechanics
-    DomainV = Region[{ RotorC }];
-  EndIf
-
-  DomainKin = #1234 ; // Dummy region number for mechanical equation
-  DomainDummy = #12345 ; // Dummy region number for postpro with functions
-}
-
-
-
-//-------------------------------------------------------------------------------------
-// Defninition of functions and variables only used internally
-
-Include "BH.pro"; // nonlinear BH caracteristic of magnetic material
-
-Function {
-  mu0 = 4.e-7 * Pi ;
-  nu0 = 1. / mu0 ;
-  nu [#{Air, Inds, Stator_Al, Rotor_Al, Stator_Cu, Rotor_Cu, Rotor_Magnets, Rotor_Bars}]=nu0;
-
-  If(!Flag_NL)
-    nu [#{Stator_Fe, Rotor_Fe }]  = 1 / (mur_fe * mu0) ;
-    dhdb_NL [] = 0;
-  EndIf
-  If(Flag_NL)
-    If(Flag_NL_law_Type==0)
-      nu [#{Stator_Fe, Rotor_Fe }] = nu_1a[$1] ;
-      dhdb_NL [ DomainNL ] = dhdb_1a_NL[$1];
-    EndIf
-    If(Flag_NL_law_Type==1)
-      nu [#{Stator_Fe, Rotor_Fe }] = nu_1[$1] ;
-      dhdb_NL [ DomainNL ] = dhdb_1_NL[$1];
-    EndIf
-    If(Flag_NL_law_Type==2)
-       nu [#{Stator_Fe, Rotor_Fe }] = nu_3kWa[$1] ;
-       dhdb_NL [ DomainNL ] = dhdb_3kWa_NL[$1];
-    EndIf
-    If(Flag_NL_law_Type==3)
-       nu [#{Stator_Fe, Rotor_Fe }] = nu_3kW[$1] ;
-       dhdb_NL [ DomainNL ] = dhdb_3kW_NL[$1];
-    EndIf
-  EndIf
-
-  sigma[#{Rotor_Fe, Stator_Fe}] = sigma_fe ;
-  sigma[#{Rotor_Al, Stator_Al}] = sigma_al ;
-  sigma[#{Rotor_Cu, Stator_Cu}] = sigma_cu ;
-  sigma[#{Inds}] = sigma_cu ;
-
-  rho[] = 1/sigma[] ;
-
-  Rb[] = Factor_R_3DEffects*AxialLength*FillFactor_Winding*NbWires[]^2/SurfCoil[]/sigma[] ;
-  Resistance[#{Stator_Inds, Rotor_Inds}] = Rb[] ;
-
-  Idir[#{Stator_IndsP, Rotor_IndsP}] =  1 ;
-  Idir[#{Stator_IndsN, Rotor_IndsN}] = -1 ;
-
-  Idq0[] = Vector[ ID, IQ, I0 ] ;
-  Pinv[] = Tensor[ Sin[Theta_Park[]],        Cos[Theta_Park[]],        1,
-                   Sin[Theta_Park[]-2*Pi/3], Cos[Theta_Park[]-2*Pi/3], 1,
-                   Sin[Theta_Park[]+2*Pi/3], Cos[Theta_Park[]+2*Pi/3], 1 ];
-
-  P[] = 2/3 * Tensor[ Sin[Theta_Park[]], Sin[Theta_Park[]-2*Pi/3], Sin[Theta_Park[]+2*Pi/3],
-                      Cos[Theta_Park[]], Cos[Theta_Park[]-2*Pi/3], Cos[Theta_Park[]+2*Pi/3],
-                      1/2, 1/2, 1/2 ] ;
-
-  Iabc[]     = Pinv[] * Idq0[] ;
-  Flux_dq0[] = P[] * Vector[#11, #22, #33] ;
-
-  If(Flag_ParkTransformation)
-    II = 1. ;
-    IA[] = CompX[ Iabc[] ] ;
-    IB[] = CompY[ Iabc[] ] ;
-    IC[] = CompZ[ Iabc[] ] ;
-  EndIf
-  If(!Flag_ParkTransformation)
-    If(!Flag_ConstantSource)
-      IA[] = F_Sin_wt_p[]{2*Pi*Freq, pA} ;
-      IB[] = F_Sin_wt_p[]{2*Pi*Freq, pB} ;
-      IC[] = F_Sin_wt_p[]{2*Pi*Freq, pC} ;
-    EndIf
-    If(Flag_ConstantSource)
-      IA[] = 1. ;
-      IB[] = 1. ;
-      IC[] = 1. ;
-      Frelax[] =1;
-    EndIf
-
-    js[PhaseA] = II * NbWires[]/SurfCoil[] * IA[] * Idir[] * Vector[0, 0, 1] ;
-    js[PhaseB] = II * NbWires[]/SurfCoil[] * IB[] * Idir[] * Vector[0, 0, 1] ;
-    js[PhaseC] = II * NbWires[]/SurfCoil[] * IC[] * Idir[] * Vector[0, 0, 1] ;
-  EndIf
-
-  Velocity[] = wr*XYZ[]/\Vector[0,0,-1] ;
-
-  // Maxwell stress tensor
-  T_max[] = ( SquDyadicProduct[$1] - SquNorm[$1] * TensorDiag[0.5, 0.5, 0.5] ) / mu0 ;
-  T_max_cplx[] = Re[0.5*(TensorV[CompX[$1]*Conj[$1], CompY[$1]*Conj[$1], CompZ[$1]*Conj[$1]]
-      - $1*Conj[$1] * TensorDiag[0.5, 0.5, 0.5] ) / mu0] ;
-  T_max_cplx_2f[] = 0.5*(TensorV[CompX[$1]*$1, CompY[$1]*$1, CompZ[$1]*$1] -
-    $1*$1 * TensorDiag[0.5, 0.5, 0.5] ) / mu0 ; // To check ????
-
-  AngularPosition[] = (Atan2[$Y,$X]#7 >= 0.)? #7 : #7+2*Pi ;
-
-  RotatePZ[] = Rotate[ Vector[$X,$Y,$Z], 0, 0, $1 ] ; //Watch out: Do not use XYZ[]!
-
-  // Torque computed in postprocessing (Trotor in #54, Tstator in #55, Tmb in #56)
-  Torque_mag[] = #55 ;
-}
-
-
-//-------------------------------------------------------------------------------------
-
-Jacobian {
-  { Name Vol; Case { { Region All ; Jacobian Vol; } } }
-}
-
-Integration {
-  { Name I1 ; Case {
-      { Type Gauss ;
-        Case {
-          { GeoElement Triangle   ; NumberOfPoints  6 ; }
-	  { GeoElement Quadrangle ; NumberOfPoints  4 ; }
-	  { GeoElement Line       ; NumberOfPoints  13 ; }
-        }
-      }
-    }
-  }
-}
-
-//-------------------------------------------------------------------------------------
-
-Constraint {
-
-  { Name MVP_2D ;
-    Case {
-      { Region Surf_Inf ; Type Assign; Value 0. ; }
-      { Region Surf_bn0 ; Type Assign; Value 0. ; }
-
-      If(Flag_Symmetry)
-        { Region Surf_cutA1; SubRegion Region[{Surf_Inf,Surf_bn0, Point_ref}]; Type Link;
-          RegionRef Surf_cutA0; SubRegionRef Region[{Surf_Inf,Surf_bn0, Point_ref}];
-          Coefficient ((NbrPolesInModel%2)?-1:1) ;
-	  Function RotatePZ[-NbrPolesInModel*2*Pi/NbrPolesTot]; }
-        { Region Surf_cutA1; Type Link; RegionRef Surf_cutA0;
-          Coefficient (NbrPolesInModel%2)?-1:1 ;
-	  Function RotatePZ[-NbrPolesInModel*2*Pi/NbrPolesTot]; }
-
-        //For the moving band
-        For k In {1:SymmetryFactor-1}
-        { Region Rotor_Bnd_MB~{k+1} ;
-	  SubRegion Rotor_Bnd_MB~{(k!=SymmetryFactor-1)?k+2:1}; Type Link;
-          RegionRef Rotor_Bnd_MB_1; SubRegionRef Rotor_Bnd_MB_2;
-          Coefficient ((NbrPolesInModel%2)?-1:1)^(k);
-	  Function RotatePZ[-k*NbrPolesInModel*2*Pi/NbrPolesTot]; }
-        EndFor
-
-      EndIf
-    }
-  }
-
-  { Name Current_2D ;
-    Case {
-      If(Flag_SrcType_Stator==1)
-        { Region PhaseA     ; Value Ia*Idir[] ; TimeFunction IA[]; }
-        { Region PhaseB     ; Value Ib*Idir[] ; TimeFunction IB[]; }
-        { Region PhaseC     ; Value Ic*Idir[] ; TimeFunction IC[]; }
-      EndIf
-      If(Flag_SrcType_Rotor==1)
-        { Region Rotor_Inds ; Value Ie*Idir[] ; }
-      EndIf
-    }
-  }
-
-  { Name Voltage_2D ;
-    Case {
-      If(!Flag_Cir_RotorCage)
-        { Region RotorC  ; Value 0. ; }
-      EndIf
-      { Region StatorC ; Value 0. ; }
-    }
-  }
-
-  { Name Current_Cir ;
-    Case {
-      If(Flag_Cir && Flag_SrcType_Stator==1)
-        { Region Input1  ; Value Ia  ; TimeFunction IA[]; }
-        { Region Input2  ; Value Ib  ; TimeFunction IB[]; }
-        { Region Input3  ; Value Ic  ; TimeFunction IC[]; }
-      EndIf
-    }
-  }
-
-  { Name Voltage_Cir ;
-    Case {
-      If(Flag_Cir && Flag_SrcType_Stator==2)
-        { Region Input1  ; Value Va  ; TimeFunction IA[]*Frelax[]; }
-        { Region Input2  ; Value Vb  ; TimeFunction IB[]*Frelax[]; }
-        { Region Input3  ; Value Vc  ; TimeFunction IC[]*Frelax[]; }
-      EndIf
-    }
-  }
-
-
-  //Kinetics
-  { Name CurrentPosition ; // [m]
-    Case {
-      { Region DomainKin ; Type Init ; Value 0.#66 ; }
-    }
-  }
-
-  { Name CurrentVelocity ; // [rad/s]
-    Case {
-      { Region DomainKin ; Type Init ; Value 0. ; }
-    }
-  }
-
-}
-
-//-------------------------------------------------------------------------------------------
-
-FunctionSpace {
-  // Magnetic Vector Potential
-  { Name Hcurl_a_2D ; Type Form1P ;
-    BasisFunction {
-      { Name se1 ; NameOfCoef ae1 ; Function BF_PerpendicularEdge ;
-        Support Region[{ Domain, Rotor_Bnd_MBaux }] ; Entity NodesOf [ All ] ; }
-   }
-    Constraint {
-      { NameOfCoef ae1 ; EntityType NodesOf ; NameOfConstraint MVP_2D ; }
-    }
-  }
-
-  // Gradient of Electric scalar potential (2D)
-  { Name Hregion_u_Mag_2D ; Type Form1P ;
-    BasisFunction {
-      { Name sr ; NameOfCoef ur ; Function BF_RegionZ ;
-        Support DomainC ; Entity DomainC ; }
-    }
-    GlobalQuantity {
-      { Name U ; Type AliasOf        ; NameOfCoef ur ; }
-      { Name I ; Type AssociatedWith ; NameOfCoef ur ; }
-    }
-    Constraint {
-      { NameOfCoef U ; EntityType GroupsOfNodesOf ; NameOfConstraint Voltage_2D ; }
-      { NameOfCoef I ; EntityType GroupsOfNodesOf ; NameOfConstraint Current_2D ; }
-    }
-  }
-
-  { Name Hregion_i_Mag_2D ; Type Vector ;
-    BasisFunction {
-      { Name sr ; NameOfCoef ir ; Function BF_RegionZ ;
-        Support DomainB ; Entity DomainB ; }
-    }
-    GlobalQuantity {
-      { Name Ib ; Type AliasOf        ; NameOfCoef ir ; }
-      { Name Ub ; Type AssociatedWith ; NameOfCoef ir ; }
-    }
-    Constraint {
-      { NameOfCoef Ub ; EntityType Region ; NameOfConstraint Voltage_2D ; }
-      { NameOfCoef Ib ; EntityType Region ; NameOfConstraint Current_2D ; }
-    }
-  }
-
-  // For circuit equations
-  { Name Hregion_Z ; Type Scalar ;
-    BasisFunction {
-      { Name sr ; NameOfCoef ir ; Function BF_Region ;
-        Support DomainZt_Cir ; Entity DomainZt_Cir ; }
-    }
-    GlobalQuantity {
-      { Name Iz ; Type AliasOf        ; NameOfCoef ir ; }
-      { Name Uz ; Type AssociatedWith ; NameOfCoef ir ; }
-    }
-    Constraint {
-      { NameOfCoef Uz ; EntityType Region ; NameOfConstraint Voltage_Cir ; }
-      { NameOfCoef Iz ; EntityType Region ; NameOfConstraint Current_Cir ; }
-    }
-  }
-
-  // For mechanical equation
-  { Name Position ; Type Scalar ;
-    BasisFunction {
-      { Name sr ; NameOfCoef pr ; Function BF_Region ;
-        Support DomainKin ; Entity DomainKin ; }
-    }
-    GlobalQuantity {
-      { Name P ; Type AliasOf  ; NameOfCoef pr ; }
-    }
-    Constraint {
-      { NameOfCoef P ; EntityType Region ; NameOfConstraint CurrentPosition ; }
-    }
-  }
-
-
-  { Name Velocity ; Type Scalar ;
-    BasisFunction {
-      { Name sr ; NameOfCoef vr ; Function BF_Region ;
-        Support DomainKin ; Entity DomainKin ; } }
-    GlobalQuantity {
-      { Name V ; Type AliasOf ; NameOfCoef vr ; }
-    }
-    Constraint {
-      { NameOfCoef V ; EntityType Region ; NameOfConstraint CurrentVelocity ; }
-    }
-  }
-
-}
-
-//-------------------------------------------------------------------------------------------
-
-Formulation {
-
-  { Name MagStaDyn_a_2D ; Type FemEquation ;
-    Quantity {
-      { Name a  ; Type Local  ; NameOfSpace Hcurl_a_2D ; }
-      { Name ur ; Type Local  ; NameOfSpace Hregion_u_Mag_2D ; }
-      { Name I  ; Type Global ; NameOfSpace Hregion_u_Mag_2D [I] ; }
-      { Name U  ; Type Global ; NameOfSpace Hregion_u_Mag_2D [U] ; }
-
-      { Name ir ; Type Local  ; NameOfSpace Hregion_i_Mag_2D ; }
-      { Name Ub ; Type Global ; NameOfSpace Hregion_i_Mag_2D [Ub] ; }
-      { Name Ib ; Type Global ; NameOfSpace Hregion_i_Mag_2D [Ib] ; }
-
-      { Name Uz ; Type Global ; NameOfSpace Hregion_Z [Uz] ; }
-      { Name Iz ; Type Global ; NameOfSpace Hregion_Z [Iz] ; }
-    }
-    Equation {
-      Galerkin { [ nu[{d a}] * Dof{d a}  , {d a} ] ;
-        In Domain ; Jacobian Vol ; Integration I1 ; }
-      Galerkin { JacNL [ dhdb_NL[{d a}] * Dof{d a} , {d a} ] ;
-        In DomainNL ; Jacobian Vol ; Integration I1 ; }
-
-      // DO NOT REMOVE!!!
-      // Keeping track of Dofs in auxiliar line of MB if Symmetry==1
-      Galerkin {  [  0*Dof{d a} , {d a} ]  ;
-        In Rotor_Bnd_MBaux; Jacobian Vol; Integration I1; }
-
-      Galerkin { [ -nu[] * br[] , {d a} ] ;
-        In DomainM ; Jacobian Vol ; Integration I1 ; }
-
-      Galerkin { DtDof[ sigma[] * Dof{a} , {a} ] ;
-        In DomainC ; Jacobian Vol ; Integration I1 ; }
-      Galerkin { [ sigma[] * Dof{ur}, {a} ] ;
-        In DomainC ; Jacobian Vol ; Integration I1 ; }
-
-      Galerkin { [ -sigma[] * (Velocity[] *^ Dof{d a}) , {a} ] ;
-        In DomainV ; Jacobian Vol ; Integration I1 ; }
-
-      Galerkin { [ -js[] , {a} ] ;
-        In DomainS ; Jacobian Vol ; Integration I1 ; }
-
-      Galerkin { DtDof[ sigma[] * Dof{a} , {ur} ] ;
-        In DomainC ; Jacobian Vol ; Integration I1 ; }
-      Galerkin { [ sigma[] * Dof{ur} , {ur} ] ;
-        In DomainC ; Jacobian Vol ; Integration I1 ; }
-      GlobalTerm { [ Dof{I} , {U} ] ; In DomainC ; }
-
-      Galerkin { [ -NbWires[]/SurfCoil[] * Dof{ir} , {a} ] ;
-        In DomainB ; Jacobian Vol ; Integration I1 ; }
-      Galerkin { DtDof [ AxialLength * NbWires[]/SurfCoil[] * Dof{a} , {ir} ] ;
-        In DomainB ; Jacobian Vol ; Integration I1 ; }
-      GlobalTerm { [ Dof{Ub}/SymmetryFactor , {Ib} ] ; In DomainB ; }
-      Galerkin { [ Rb[]/SurfCoil[]* Dof{ir} , {ir} ] ;
-        In DomainB ; Jacobian Vol ; Integration I1 ; } // Resistance term
-
-      // GlobalTerm { [ Resistance[]  * Dof{Ib} , {Ib} ] ; In DomainB ; }
-      // The above term can replace the resistance term:
-      // if we have an estimation of the resistance of DomainB, via e.g. measurements
-      // which is better to account for the end windings...
-
-      If(Flag_Cir)
-	GlobalTerm { NeverDt[ Dof{Uz}                , {Iz} ] ; In Resistance_Cir ; }
-        GlobalTerm { NeverDt[ Resistance[] * Dof{Iz} , {Iz} ] ; In Resistance_Cir ; }
-
-	GlobalTerm { [ Dof{Uz}                      , {Iz} ] ; In Inductance_Cir ; }
-	GlobalTerm { DtDof [ Inductance[] * Dof{Iz} , {Iz} ] ; In Inductance_Cir ; }
-
-	GlobalTerm { NeverDt[ Dof{Iz}        , {Iz} ] ; In Capacitance_Cir ; }
-	GlobalTerm { DtDof [ Capacitance[] * Dof{Uz} , {Iz} ] ; In Capacitance_Cir ; }
-
-	GlobalTerm { [ 0. * Dof{Iz} , {Iz} ] ; In DomainZt_Cir ; }
-        GlobalTerm { [ 0. * Dof{Uz} , {Iz} ] ; In DomainZt_Cir ; }
-
-        GlobalEquation {
-          Type Network ; NameOfConstraint ElectricalCircuit ;
-          { Node {I};  Loop {U};  Equation {I};  In DomainC ; }
-          { Node {Ib}; Loop {Ub}; Equation {Ub}; In DomainB ; }
-          { Node {Iz}; Loop {Uz}; Equation {Uz}; In DomainZt_Cir ; }
-         }
-      EndIf
-    }
-  }
-
- //-------------------------------------------------------------------------------------------
-// Mechanics
-
-  { Name Mechanical ; Type FemEquation ;
-    Quantity {
-      { Name V ; Type Global ; NameOfSpace Velocity [V] ; } // velocity
-      { Name P ; Type Global ; NameOfSpace Position [P] ; } // position
-    }
-    Equation {
-      GlobalTerm { DtDof [ Inertia * Dof{V} , {V} ] ; In DomainKin ; }
-      GlobalTerm { [ Friction[] * Dof{V} , {V} ] ; In DomainKin ; }
-      GlobalTerm { [        Torque_mec[] , {V} ] ; In DomainKin ; }
-      GlobalTerm { [       -Torque_mag[] , {V} ] ; In DomainKin ; }
-
-      GlobalTerm { DtDof [ Dof{P} , {P} ] ; In DomainKin ; }
-      GlobalTerm {       [-Dof{V} , {P} ] ; In DomainKin ; }
-    }
-  }
-
-}
-
-//-----------------------------------------------------------------------------------------
-
-Resolution {
-
-  { Name Analysis ;
-    System {
-      If(Flag_AnalysisType==2)
-        { Name A ; NameOfFormulation MagStaDyn_a_2D ; Type ComplexValue ; Frequency Freq ; }
-      EndIf
-      If(Flag_AnalysisType<2)
-        { Name A ; NameOfFormulation MagStaDyn_a_2D ; }
-        If(!Flag_ImposedSpeed) // Full dynamics
-          { Name M ; NameOfFormulation Mechanical ; }
-        EndIf
-      EndIf
-    }
-    Operation {
-      CreateDir["res/"];
-      If(Clean_Results==1 && variableFrequencyLoop == initialFrequencyLoop)
-	// FIXME == > variable controlling loop in Onelab
-
-	DeleteFile[StrCat[ResDir, StrCat["temp",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Tr",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Ts",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Tmb",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Ua",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Ub",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Uc",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Ia",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Ib",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Ic",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Flux_a",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Flux_b",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Flux_c",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Flux_d",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Flux_q",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Flux_0",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["JL",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["JL_Fe",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["P",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["V",ExtGnuplot]]];
-	DeleteFile[StrCat[ResDir, StrCat["Irotor",ExtGnuplot]]];
-      EndIf
-
-      If(Flag_AnalysisType==0 || Flag_AnalysisType==2)
-        If(Flag_AnalysisType==2)
-          SetTime[variableFrequencyLoop];
-        EndIf
-
-        InitMovingBand2D[MB] ;
-        MeshMovingBand2D[MB] ;
-        InitSolution[A] ;
-
-        If(Flag_ParkTransformation && Flag_SrcType_Stator==1)
-          PostOperation[ThetaPark_IABC] ;
-        EndIf
-        If(!Flag_NL)
-          Generate[A] ; Solve[A] ;
-        EndIf
-        If(Flag_NL)
-          IterativeLoop[Nb_max_iter, stop_criterion, relaxation_factor]{
-            GenerateJac[A] ; SolveJac[A] ; }
-        EndIf
-        SaveSolution[A] ;
-
-        PostOperation[Get_LocalFields] ;
-        PostOperation[Get_GlobalQuantities] ;
-        If(Flag_AnalysisType==0)
-          PostOperation[Get_Torque];
-        EndIf
-        If(Flag_AnalysisType==2)
-          PostOperation[Get_Torque_cplx];
-        EndIf
-      EndIf // End Flag_AnalysisType==0 (Static) Flag_AnalysisType==2 (Frequency)
-
-      If(Flag_AnalysisType==1)
-        InitMovingBand2D[MB];
-        MeshMovingBand2D[MB];
-        InitSolution[A];
-
-        If(!Flag_ImposedSpeed) // Full dynamics
-          InitSolution[M];
-	  InitSolution[M]; // Twice for avoiding warning (a = d_t^2 x)
-        EndIf
-
-        TimeLoopTheta[time0, timemax, delta_time, 1.]{
-	  // Euler implicit (1) -- Crank-Nicolson (0.5)
-	  // FIXME like this theta cannot be controlled by the user
-          If(Flag_ParkTransformation && Flag_SrcType_Stator==1)
-            PostOperation[ThetaPark_IABC];
-          EndIf
-          If(!Flag_NL)
-            Generate[A]; Solve[A];
-          EndIf
-          If(Flag_NL)
-            IterativeLoop[Nb_max_iter, stop_criterion, relaxation_factor] {
-              GenerateJac[A] ; SolveJac[A] ; }
-          EndIf
-          SaveSolution[A];
-
-          PostOperation[Get_LocalFields] ;
-          Test[ $TimeStep > 1 ]{
-            PostOperation[Get_GlobalQuantities];
-            PostOperation[Get_Torque] ;
-          }
-
-          If(!Flag_ImposedSpeed)
-            Generate[M]; Solve[M]; SaveSolution[M];
-            PostOperation[Mechanical] ;
-          EndIf
-
-          ChangeOfCoordinates[ NodesOf[Rotor_Moving], RotatePZ[delta_theta[]]];
-          If(!Flag_ImposedSpeed)
-            Evaluate[ #77#66 ]; //Keep track of previous angular position
-          EndIf
-          MeshMovingBand2D[MB] ;
-        }
-      EndIf // End Flag_AnalysisType==1 (Time domain)
-    }
-  }
-}
-
-//-------------------------------------------------------------------------------------------
-
-PostProcessing {
-
-  { Name MagStaDyn_a_2D ; NameOfFormulation MagStaDyn_a_2D ;
-   PostQuantity {
-     { Name a  ; Value { Term { [ {a} ] ; In Domain ; Jacobian Vol ; } } }
-     { Name az ; Value { Term { [ CompZ[{a}] ] ; In Domain ; Jacobian Vol ; } } }
-
-     { Name b  ; Value { Term { [ {d a} ] ; In Domain ; Jacobian Vol ; } } }
-     { Name boundary  ; Value { Term { [ 1 ] ; In Dummy ; Jacobian Vol ; } } } // Dummy quantity - for visualization
-     { Name b_radial ;
-       Value { Term { [ {d a}* Vector[  Cos[AngularPosition[]#4], Sin[#4], 0.] ] ;
-	   In Domain ; Jacobian Vol ; } } }
-     { Name b_tangent ;
-       Value { Term { [ {d a}* Vector[ -Sin[AngularPosition[]#4], Cos[#4], 0.] ] ;
-	   In Domain ; Jacobian Vol ; } } }
-
-     { Name js ; Value { Term { [ js[] ] ; In DomainS ; Jacobian Vol ; } } }
-     { Name br ; Value { Term { [ br[] ] ; In DomainM ; Jacobian Vol ; } } }
-
-     { Name j  ; Value {
-         Term { [ -sigma[]*(Dt[{a}]+{ur}) ]        ; In DomainC ; Jacobian Vol ; }
-         Term { [  sigma[]*(Velocity[] *^ {d a}) ] ; In DomainV ; Jacobian Vol ; }
-       }
-     }
-     { Name ir ; Value { Term { [ {ir} ] ; In Inds ; Jacobian Vol ; } } }
-
-     { Name jz ; Value {
-         Term { [ CompZ[-sigma[]*(Dt[{a}]+{ur})] ]       ; In DomainC ; Jacobian Vol ; }
-         Term { [ CompZ[ sigma[]*(Velocity[]*^{d a}) ] ] ; In DomainV ; Jacobian Vol ; }
-       }
-     }
-
-     { Name rhoj2 ;
-       Value {
-         Term { [ sigma[]*SquNorm[ Dt[{a}]+{ur}] ] ;
-	   In Region[{DomainC,-DomainV}] ; Jacobian Vol ; }
-         Term { [ sigma[]*SquNorm[ Dt[{a}]+{ur}-Velocity[]*^{d a} ] ] ;
-	   In DomainV ; Jacobian Vol ; }
-         Term { [ 1./sigma[]*SquNorm[ IA[]*{ir} ] ] ; In PhaseA  ; Jacobian Vol ; }
-         Term { [ 1./sigma[]*SquNorm[ IB[]*{ir} ] ] ; In PhaseB  ; Jacobian Vol ; }
-         Term { [ 1./sigma[]*SquNorm[ IC[]*{ir} ] ] ; In PhaseC  ; Jacobian Vol ; }
-       }
-     }
-
-     { Name JouleLosses ;
-       Value {
-         Integral { [ sigma[] * SquNorm[ Dt[{a}]+{ur} ] ] ;
-	   In Region[{DomainC,-DomainV}] ; Jacobian Vol ; Integration I1 ; }
-         Integral { [ sigma[] * SquNorm[ Dt[{a}]+{ur}-Velocity[]*^{d a} ] ] ;
-	   In DomainV ; Jacobian Vol ; Integration I1 ; }
-         Integral { [ 1./sigma[]*SquNorm[ IA[]*{ir} ] ] ;
-	   In PhaseA ; Jacobian Vol ; Integration I1 ; }
-         Integral { [ 1./sigma[]*SquNorm[ IB[]*{ir} ] ] ;
-	   In PhaseB  ; Jacobian Vol ; Integration I1 ; }
-         Integral { [ 1./sigma[]*SquNorm[ IC[]*{ir} ] ] ;
-	   In PhaseC  ; Jacobian Vol ; Integration I1 ; }
-       }
-     }
-
-     { Name Flux ;
-       Value {
-	 Integral { [ SymmetryFactor*AxialLength*Idir[]*NbWires[]/SurfCoil[]* CompZ[{a}] ] ;
-           In Inds  ; Jacobian Vol ; Integration I1 ; } } }
-
-     { Name Force_vw ;
-       // Force computation by Virtual Works
-       Value {
-         Integral {
-           Type Global ; [ 0.5 * nu[] * VirtualWork [{d a}] * AxialLength ];
-           In ElementsOf[Rotor_Airgap, OnOneSideOf Rotor_Bnd_MB];
-	   Jacobian Vol ; Integration I1 ; }
-       }
-     }
-
-     { Name Torque_vw ; Value {
-	 // Torque computation via Virtual Works
-         Integral { Type Global ;
-           [ CompZ[ 0.5 * nu[] * XYZ[] /\ VirtualWork[{d a}] ] * AxialLength ];
-           In ElementsOf[Rotor_Airgap, OnOneSideOf Rotor_Bnd_MB];
-	   Jacobian Vol ; Integration I1 ; }
-       }
-     }
-
-     { Name Torque_Maxwell ;
-       // Torque computation via Maxwell stress tensor
-       Value {
-         Integral {
-           [ CompZ [ XYZ[] /\ (T_max[{d a}] * XYZ[]) ] * 2*Pi*AxialLength/SurfaceArea[] ] ;
-           In Domain ; Jacobian Vol  ; Integration I1; }
-       }
-     }
-
-     { Name Torque_Maxwell_cplx ;
-       // Torque computation via Maxwell stress tensor - frequency domain
-       Value {
-         Integral {
-           [ CompZ [ XYZ[] /\ (T_max_cplx[{d a}] * XYZ[]) ] * 2*Pi*AxialLength/SurfaceArea[] ] ;
-           In Domain ; Jacobian Vol  ; Integration I1; }
-       }
-     }
-
-     { Name Torque_Maxwell_cplx_2f ;
-       // Torque computation via Maxwell stress tensor, component at twice the frequency
-       Value {
-         Integral {
-           [ CompZ [ XYZ[] /\ (T_max_cplx_2f[{d a}] * XYZ[]) ] * 2*Pi*AxialLength/SurfaceArea[] ] ;
-           In Domain ; Jacobian Vol  ; Integration I1; }
-       }
-     }
-
-     { Name ComplexPower ;
-       // S = P + i*Q
-       Value {
-         Integral { [ Complex[ sigma[]*SquNorm[Dt[{a}]+{ur}], nu[]*SquNorm[{d a}] ] ] ;
-           In Region[{DomainC,-DomainV}] ; Jacobian Vol ; Integration I1 ; }
-         Integral { [ Complex[ sigma[]*SquNorm[Dt[{a}]+{ur}-Velocity[]*^{d a}], nu[]*SquNorm[{d a}] ] ] ;
-           In DomainV ; Jacobian Vol ; Integration I1 ; }
-       }
-     }
-
-     { Name U ; Value {
-         Term { [ {U} ]   ; In DomainC ; }
-         Term { [ {Ub} ]  ; In DomainB ; }
-         Term { [ {Uz} ]  ; In DomainZt_Cir ; }
-     } }
-
-     { Name I ; Value {
-         Term { [ {I} ]   ; In DomainC ; }
-         Term { [ {Ib} ]  ; In DomainB ; }
-         Term { [ {Iz} ]  ; In DomainZt_Cir ; }
-     } }
-
-     { Name S ; Value {
-         Term { [ {U}*Conj[{I}] ]    ; In DomainC ; }
-         Term { [ {Ub}*Conj[{Ib}] ]  ; In DomainB ; }
-         Term { [ {Uz}*Conj[{Iz}] ]  ; In DomainZt_Cir ; }
-     } }
-
-     { Name Velocity  ; Value {
-         Term { [ Velocity[] ] ; In Domain ; Jacobian Vol ; }
-       }
-     }
-
-     { Name RotorPosition_deg ;
-       Value { Term { Type Global; [ RotorPosition_deg[] ] ; In DomainDummy ; } } }
-     { Name Theta_Park_deg ;
-       Value { Term { Type Global; [ Theta_Park_deg[] ] ; In DomainDummy ; } } }
-     { Name IA  ;
-       Value { Term { Type Global; [ IA[] ] ; In DomainDummy ; } } }
-     { Name IB  ;
-       Value { Term { Type Global; [ IB[] ] ; In DomainDummy ; } } }
-     { Name IC  ;
-       Value { Term { Type Global; [ IC[] ] ; In DomainDummy ; } } }
-     { Name Flux_d  ;
-       Value { Term { Type Global; [ CompX[Flux_dq0[]] ] ; In DomainDummy ; } } }
-     { Name Flux_q  ;
-       Value { Term { Type Global; [ CompY[Flux_dq0[]] ] ; In DomainDummy ; } } }
-     { Name Flux_0  ;
-       Value { Term { Type Global; [ CompZ[Flux_dq0[]] ] ; In DomainDummy ; } } }
-   }
- }
-
- { Name Mechanical ; NameOfFormulation Mechanical ;
-   PostQuantity {
-     { Name P ; Value { Term { [ {P} ]  ; In DomainKin ; } } } // Position [rad]
-     { Name Pdeg ; Value { Term { [ {P}*180/Pi ]  ; In DomainKin ; } } } // Position [deg]
-     { Name V ; Value { Term { [ {V} ]  ; In DomainKin ; } } } // Velocity [rad/s]
-     { Name Vrpm ; Value { Term { [ {V}*30/Pi ]  ; In DomainKin ; } } } // Velocity [rpm]
-   }
- }
-
-}
-
-//-------------------------------------------------------------------------------------------
-
-po      = "Output - Electromagnetics/";
-poI     = StrCat[po,"0Current [A]/"];
-poV     = StrCat[po,"1Voltage [V]/"];
-poF     = StrCat[po,"2Flux linkage [Vs]/"];
-poJL    = StrCat[po,"3Joule Losses [W]/"];
-po_mec  = "Output - Mechanics/";
-po_mecT = StrCat[po_mec,"0Torque [Nm]/"];
-
-//-------------------------------------------------------------------------------------------
-
-PostOperation Get_LocalFields UsingPost MagStaDyn_a_2D {
-  Print[ ir, OnElementsOf Stator_Inds,
-	 File StrCat[ResDir, StrCat["ir_stator",ExtGmsh]], LastTimeStepOnly,
-	 AppendTimeStepToFileName Flag_SaveAllSteps] ;
-  Print[ ir, OnElementsOf Rotor_Inds,
-	 File StrCat[ResDir, StrCat["ir_rotor",ExtGmsh]], LastTimeStepOnly,
-	 AppendTimeStepToFileName Flag_SaveAllSteps] ;
-  Print[ jz, OnElementsOf DomainC,
-	 File StrCat[ResDir, StrCat["jz",ExtGmsh]], LastTimeStepOnly,
-	 AppendTimeStepToFileName Flag_SaveAllSteps ] ;
-  Print[ b,  OnElementsOf Domain,
-	 File StrCat[ResDir, StrCat["b",ExtGmsh]], LastTimeStepOnly,
-	 AppendTimeStepToFileName Flag_SaveAllSteps] ;
-  Print[ boundary, OnElementsOf Dummy,
-	 File StrCat[ResDir, StrCat["bnd",ExtGmsh]], LastTimeStepOnly,
-	 AppendTimeStepToFileName Flag_SaveAllSteps] ;
-  Print[ az, OnElementsOf Domain,
-	 File StrCat[ResDir, StrCat["a",ExtGmsh]], LastTimeStepOnly,
-	 AppendTimeStepToFileName Flag_SaveAllSteps ] ;
-}
-
-PostOperation Get_GlobalQuantities UsingPost MagStaDyn_a_2D {
-  If(!Flag_Cir)
-    If(!Flag_ParkTransformation)
-      Print[ I, OnRegion PhaseA_pos, Format Table,
-	     File > StrCat[ResDir, StrCat["Ia",ExtGnuplot]], LastTimeStepOnly,
-	     SendToServer StrCat[poI,"A"], Color "Pink" ];
-      If(NbrPhases==3)
-        Print[ I, OnRegion PhaseB_pos, Format Table,
-	       File > StrCat[ResDir, StrCat["Ib",ExtGnuplot]], LastTimeStepOnly,
-	       SendToServer StrCat[poI,"B"], Color "Yellow" ];
-        Print[ I, OnRegion PhaseC_pos, Format Table,
-	       File > StrCat[ResDir, StrCat["Ic",ExtGnuplot]], LastTimeStepOnly,
-	       SendToServer StrCat[poI,"C"], Color "LightGreen" ];
-      EndIf
-    EndIf
-
-    Print[ U, OnRegion PhaseA_pos, Format Table,
-	   File > StrCat[ResDir, StrCat["Ua",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poV,"A"], Color "Pink" ];
-    If(NbrPhases==3)
-      Print[ U, OnRegion PhaseB_pos, Format Table,
-	     File > StrCat[ResDir, StrCat["Ub",ExtGnuplot]], LastTimeStepOnly,
-	     SendToServer StrCat[poV,"B"], Color "Yellow" ];
-      Print[ U, OnRegion PhaseC_pos, Format Table,
-	     File > StrCat[ResDir, StrCat["Uc",ExtGnuplot]], LastTimeStepOnly,
-	     SendToServer StrCat[poV,"C"], Color "LightGreen" ];
-    EndIf
-  EndIf
-  If(Flag_Cir && Flag_SrcType_StatorA==2)
-    Print[ I, OnRegion Input1, Format Table,
-	   File > StrCat[ResDir, StrCat["Ia",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poI,"A"], Color "Pink" ];
-    Print[ U, OnRegion Input1, Format Table,
-	   File > StrCat[ResDir, StrCat["Ua",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poV,"A"], Color "Pink" ];
-  EndIf
-  If(Flag_Cir && Flag_SrcType_StatorB==2)
-    Print[ I, OnRegion Input2, Format Table,
-	   File > StrCat[ResDir, StrCat["Ib",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poI,"B"], Color "Yellow" ];
-    Print[ U, OnRegion Input2, Format Table,
-	   File > StrCat[ResDir, StrCat["Ub",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poV,"B"], Color "Yellow" ];
-  EndIf
-  If(Flag_Cir && Flag_SrcType_StatorB==2)
-    Print[ I, OnRegion Input3, Format Table,
-	   File > StrCat[ResDir, StrCat["Ic",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poI,"C"], Color "LightGreen" ];
-    Print[ U, OnRegion Input3, Format Table,
-	   File > StrCat[ResDir, StrCat["Uc",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poV,"C"], Color "LightGreen" ];
-  EndIf
-  If(Flag_Cir && Flag_SrcType_StatorA==0)
-    Print[ I, OnRegion R1, Format Table,
-	   File > StrCat[ResDir, StrCat["Ia",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poI,"A"], Color "Pink" ];
-    Print[ U, OnRegion R1, Format Table,
-	   File > StrCat[ResDir, StrCat["Ua",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poV,"A"], Color "Pink" ];
-  EndIf
-  If(Flag_Cir && Flag_SrcType_StatorB==0)
-    Print[ I, OnRegion R2, Format Table,
-	   File > StrCat[ResDir, StrCat["Ib",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poI,"B"], Color "Yellow" ];
-    Print[ U, OnRegion R2, Format Table,
-	   File > StrCat[ResDir, StrCat["Ub",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poV,"B"], Color "Yellow" ];
-  EndIf
-  If(Flag_Cir && Flag_SrcType_StatorC==0)
-    Print[ I, OnRegion R3, Format Table,
-	   File > StrCat[ResDir, StrCat["Ic",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poI,"C"], Color "LightGreen" ];
-    Print[ U, OnRegion R3, Format Table,
-	   File > StrCat[ResDir, StrCat["Uc",ExtGnuplot]], LastTimeStepOnly,
-	   SendToServer StrCat[poV,"C"], Color "LightGreen" ];
-  EndIf
-
-  Print[ I, OnRegion RotorC, Format Table,
-	 File > StrCat[ResDir, StrCat["Irotor",ExtGnuplot]], LastTimeStepOnly,
-	 SendToServer StrCat[poI,"rotor"], Color "LightCyan" ];
-
-  If(Flag_SrcType_Stator)
-    Print[ Flux[PhaseA], OnGlobal, Format TimeTable,
-	   File > StrCat[ResDir, StrCat["Flux_a",ExtGnuplot]], LastTimeStepOnly, Store 11,
-	   SendToServer StrCat[poF,"A"],  Color "Pink" ];
-    If(NbrPhases==3)
-      Print[ Flux[PhaseB], OnGlobal, Format TimeTable,
-	     File > StrCat[ResDir, StrCat["Flux_b",ExtGnuplot]], LastTimeStepOnly, Store 22,
-	     SendToServer StrCat[poF,"B"],  Color "Yellow" ];
-      Print[ Flux[PhaseC], OnGlobal, Format TimeTable,
-	     File > StrCat[ResDir, StrCat["Flux_c",ExtGnuplot]], LastTimeStepOnly, Store 33,
-	     SendToServer StrCat[poF,"C"], Color "LightGreen"];
-    EndIf
-    If(Flag_ParkTransformation && Flag_SrcType_Stator)
-      Print[ Flux_d, OnRegion DomainDummy, Format TimeTable,
-	     File > StrCat[ResDir, StrCat["Flux_d",ExtGnuplot]], LastTimeStepOnly,
-	     SendToServer StrCat[poF,"d"], Color "LightYellow" ];
-      Print[ Flux_q, OnRegion DomainDummy, Format TimeTable,
-	     File > StrCat[ResDir, StrCat["Flux_q",ExtGnuplot]], LastTimeStepOnly,
-	     SendToServer StrCat[poF,"q"], Color "LightYellow" ];
-      Print[ Flux_0, OnRegion DomainDummy, Format TimeTable,
-	     File > StrCat[ResDir, StrCat["Flux_0",ExtGnuplot]], LastTimeStepOnly,
-	     SendToServer StrCat[poF,"0"], Color "LightYellow" ];
-    EndIf
-  EndIf
-
-  Print[ JouleLosses[Rotor], OnGlobal, Format TimeTable,
-	 File > StrCat[ResDir, StrCat["JL",ExtGnuplot]], LastTimeStepOnly,
-	 SendToServer StrCat[poJL,"rotor"], Color "LightYellow" ];
-  Print[ JouleLosses[Rotor_Fe], OnGlobal, Format TimeTable,
-	 File > StrCat[ResDir, StrCat["JL_Fe",ExtGnuplot]], LastTimeStepOnly,
-	 SendToServer StrCat[poJL,"rotor_fe"], Color "LightYellow" ];
-}
-
-PostOperation Get_Torque UsingPost MagStaDyn_a_2D {
-  Print[ Torque_Maxwell[Rotor_Airgap], OnGlobal, Format TimeTable,
-    File > StrCat[ResDir, StrCat["Tr",ExtGnuplot]], LastTimeStepOnly, Store 54,
-	 SendToServer StrCat[po_mecT, "rotor"], Color "Ivory" ];
-  Print[ Torque_Maxwell[Stator_Airgap], OnGlobal, Format TimeTable,
-    File > StrCat[ResDir, StrCat["Ts",ExtGnuplot]], LastTimeStepOnly, Store 55,
-	 SendToServer StrCat[po_mecT, "stator"], Color "Ivory" ];
-}
-
-PostOperation Get_Torque_cplx UsingPost MagStaDyn_a_2D {
-  Print[ Torque_Maxwell_cplx[Rotor_Airgap], OnGlobal, Format TimeTable,
-	 File > StrCat[ResDir, StrCat["Tr",ExtGnuplot]], Store 54,
-	 SendToServer StrCat[po_mecT, "rotor"], Color "Ivory" ];
-  Print[ Torque_Maxwell_cplx[Stator_Airgap], OnGlobal, Format TimeTable,
-	 File > StrCat[ResDir, StrCat["Ts",ExtGnuplot]], Store 55,
-	 SendToServer StrCat[po_mecT,"stator"], Color "Ivory" ];
-}
-
-PostOperation Mechanical UsingPost Mechanical {
-  Print[ P, OnRegion DomainKin, Format Table,
-	 File > StrCat[ResDir, StrCat["P", ExtGnuplot]], LastTimeStepOnly, Store 77,
-	 SendToServer StrCat[po_mec,"11Position [rad]"], Color "Ivory"] ;
-  Print[ Pdeg, OnRegion DomainKin, Format Table,
-	 File > StrCat[ResDir, StrCat["P_deg", ExtGnuplot]], LastTimeStepOnly,
-	 SendToServer StrCat[po_mec,"10Position [deg]"], Color "Ivory"] ;
-  Print[ V, OnRegion DomainKin, Format Table,
-	 File > StrCat[ResDir, StrCat["V", ExtGnuplot]], LastTimeStepOnly,
-	 SendToServer StrCat[po_mec,"21Velocity [rad\s]"], Color "Ivory"] ;//MediumPurple1
-  Print[ Vrpm, OnRegion DomainKin, Format Table,
-	 File > StrCat[ResDir, StrCat["Vrpm", ExtGnuplot]], LastTimeStepOnly,
-	 SendToServer StrCat[po_mec,"20Velocity [rpm]"], Color "Ivory"] ;//MediumPurple1
-}
-
-If (Flag_ParkTransformation)
-PostOperation ThetaPark_IABC UsingPost MagStaDyn_a_2D {
-  Print[ RotorPosition_deg, OnRegion DomainDummy, Format Table, LastTimeStepOnly,
-	 File StrCat[ResDir, StrCat["temp",ExtGnuplot]],
-	 SendToServer StrCat[po,"10Rotor position"], Color "LightYellow" ];
-  Print[ Theta_Park_deg, OnRegion DomainDummy, Format Table, LastTimeStepOnly,
-	 File StrCat[ResDir, StrCat["temp",ExtGnuplot]],
-	 SendToServer StrCat[po,"11Theta park"], Color "LightYellow" ];
-  Print[ IA, OnRegion DomainDummy, Format Table, LastTimeStepOnly,
-	 File StrCat[ResDir, StrCat["temp",ExtGnuplot]],
-	 SendToServer StrCat[poI,"A"], Color "Pink" ];
-  Print[ IB, OnRegion DomainDummy, Format Table, LastTimeStepOnly,
-	 File StrCat[ResDir, StrCat["temp",ExtGnuplot]],
-	 SendToServer StrCat[poI,"B"], Color "Yellow" ];
-  Print[ IC, OnRegion DomainDummy, Format Table, LastTimeStepOnly,
-	 File StrCat[ResDir, StrCat["temp",ExtGnuplot]],
-	 SendToServer StrCat[poI,"C"], Color "LightGreen"  ];
-}
-EndIf
diff --git a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm.geo b/contrib/mobile/iOS/Onelab/files/pmsm/pmsm.geo
deleted file mode 100644
index 076d49a..0000000
--- a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm.geo
+++ /dev/null
@@ -1,96 +0,0 @@
-Include "pmsm_data.geo";
-
-Mesh.Algorithm = 6; // 2D mesh algorithm (1=MeshAdapt, 2=Automatic, 5=Delaunay, 6=Frontal, 7=bamg, 8=delquad)
-
-Geometry.CopyMeshingMethod = 1;
-//Mesh.CharacteristicLengthFactor = 0.5 ;
-
-fact_trans = Mesh.CharacteristicLengthFactor ;
-
-
-// Mesh characteristic lengths
-s = 0.4 ;
-pR1=(rR2-rR1)/6.*s;
-pR2=(rR2-rR1)/6.*s;
-
-pS1=(rS7-rS1)/7.*s;
-pS2=(rS7-rS1)/12.*s;
-pS3=(rS6-rS3)/10.*s;
-
-NbrDivMB = 2*Ceil[2*Pi*rRext/8/pR1/fact_trans] ; //1/8 Moving band
-
-//--------------------------------------------------------------------------------
-//--------------------------------------------------------------------------------
-
-cen = newp ; Point(cen)={0,0,0,pR1};
-nicepos_rotor[] = {};
-nicepos_stator[] = {};
-
-Include "pmsm_rotor.geo";
-Include "pmsm_stator.geo";
-
-
-// For nice visualisation...
-//Mesh.Light = 0 ;
-//Mesh.SurfaceFaces = 1; Mesh.SurfaceEdges=0;
-
-Hide { Point{ Point '*' }; }
-Hide { Line{ Line '*' }; }
-Show { Line{ nicepos_rotor[], nicepos_stator[] }; }
-
-Physical Line(NICEPOS) = { nicepos_rotor[], nicepos_stator[] };
-
-//For post-processing...
-//View[0].Light = 0;
-View[0].NbIso = 25; // Number of intervals
-View[0].IntervalsType = 1;
-
-DefineConstant[ Flag_AddInfo = {0, Choices{0,1},
-    Name "Input/02Add info about phases and axis"} ];
-
-For i In {PostProcessing.NbViews-1 : 0 : -1}
-  If(StrFind(View[i].Attributes, "tmp"))
-    Delete View[i];
-  EndIf
-EndFor
-
-If(Flag_AddInfo)
-  rr = 1.25 * rS3 ;
-  For k In {0:NbrPolesInModel-1}
-    xa[] += rr*Cos(1*Pi/24+k*Pi/4) ; ya[] += rr*Sin(1*Pi/24+k*Pi/4) ;
-    xb[] += rr*Cos(3*Pi/24+k*Pi/4) ; yb[] += rr*Sin(3*Pi/24+k*Pi/4) ;
-    xc[] += rr*Cos(5*Pi/24+k*Pi/4) ; yc[] += rr*Sin(5*Pi/24+k*Pi/4) ;
-  EndFor
-
-  // Adding some axes
-  rr0 = 0.3 * rS7 ;
-  rr1 = 1.3 * rS7 ;
-  th_d = InitialRotorAngle ;
-  th_q = th_d + 22.5 * deg2rad ;
-
-  th_a = 30 * deg2rad ;
-  th_b = (30 + 120/4) * deg2rad ;
-  th_c = (30 + 240/4) * deg2rad ;
-
-  ff = 0.9;
-
-  xd[0] = rr0*Cos(th_d) ;    yd[0] = rr0*Sin(th_d) ;
-  xd[1] = ff*rr1*Cos(th_d) ; yd[1] = ff*rr1*Sin(th_d) ;
-  xq[0] = rr0*Cos(th_q) ;    yq[0] = rr0*Sin(th_q) ;
-  xq[1] = ff*rr1*Cos(th_q) ; yq[1] = ff*rr1*Sin(th_q) ;
-
-  xaa[0] = rr0*Cos(th_a) ; yaa[0] = rr0*Sin(th_a) ;
-  xaa[1] = rr1*Cos(th_a) ; yaa[1] = rr1*Sin(th_a) ;
-  xbb[0] = rr0*Cos(th_b) ; ybb[0] = rr0*Sin(th_b) ;
-  xbb[1] = rr1*Cos(th_b) ; ybb[1] = rr1*Sin(th_b) ;
-  xcc[0] = rr0*Cos(th_c) ; ycc[0] = rr0*Sin(th_c) ;
-  xcc[1] = rr1*Cos(th_c) ; ycc[1] = rr1*Sin(th_c) ;
-
-
-  Include "info_view.geo";
-
-EndIf
-
-
-
-
diff --git a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm.pro b/contrib/mobile/iOS/Onelab/files/pmsm/pmsm.pro
deleted file mode 100644
index e54ac84..0000000
--- a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm.pro
+++ /dev/null
@@ -1,185 +0,0 @@
-//
-// Permanent Magnet Synchronous Generator
-//
-
-Include "pmsm_data.geo";
-
-DefineConstant[
-  Flag_AnalysisType = {1,  Choices{0="Static",  1="Time domain"},
-    Name "Input/19Type of analysis", Highlight "Blue",
-    Help Str["- Use 'Static' to compute static fields created in the machine",
-      "- Use 'Time domain' to compute the dynamic response of the machine"]} ,
-  Flag_SrcType_Stator = { 0, Choices{0="None",1="Current"},
-    Name "Input/41Source type in stator", Highlight "Blue"},
-  Flag_NL = { 1, Choices{0,1},
-    Name "Input/60Nonlinear BH-curve"},
-  Flag_NL_law_Type = { 0, Choices{
-      0="Analytical", 1="Interpolated",
-      2="Analytical VH800-65D", 3="Interpolated VH800-65D"},
-    Name "Input/61BH-curve", Highlight "Blue", Visible Flag_NL}
-];
-
-Flag_Cir = !Flag_SrcType_Stator ;
-
-Group {
-  Stator_Fe     = #STATOR_FE ;
-  Stator_Al     = #{};
-  Stator_Cu     = #{};
-  Stator_Air    = #STATOR_AIR ;
-  Stator_Airgap = #STATOR_AIRGAP ;
-  Stator_Bnd_A0 = #STATOR_BND_A0 ;
-  Stator_Bnd_A1 = #STATOR_BND_A1 ;
-
-  Rotor_Fe     = #ROTOR_FE ;
-  Rotor_Al     = #{};
-  Rotor_Cu     = #{};
-  Rotor_Fe     = #ROTOR_FE ;
-  Rotor_Air    = #ROTOR_AIR ;
-  Rotor_Airgap = #ROTOR_AIRGAP ;
-  Rotor_Bnd_A0 = #ROTOR_BND_A0 ;
-  Rotor_Bnd_A1 = #ROTOR_BND_A1 ;
-
-  MovingBand_PhysicalNb = #MOVING_BAND ;  // Fictitious number for moving band, not in the geo file
-  Surf_Inf = #SURF_EXT ;
-  Surf_bn0 = #SURF_INT ;
-  Surf_cutA0 = #{STATOR_BND_A0, ROTOR_BND_A0};
-  Surf_cutA1 = #{STATOR_BND_A1, ROTOR_BND_A1};
-
-  Dummy = #NICEPOS;
-
-  nbMagnets = NbrPolesTot/SymmetryFactor ;
-  For k In {1:nbMagnets}
-    Rotor_Magnet~{k} = Region[ (ROTOR_MAGNET+k-1) ];
-    Rotor_Magnets += Region[ Rotor_Magnet~{k} ];
-  EndFor
-
-  nbInds = (Flag_Symmetry) ? NbrPolesInModel*NbrSectTotStator/NbrPolesTot : NbrSectTotStator ;
-  Printf("NbrPolesInModel=%g, nbInds=%g SymmetryFactor=%g",
-	 NbrPolesInModel, nbInds, SymmetryFactor);
-
-  Stator_Ind_Ap = #{};              Stator_Ind_Am = #{STATOR_IND_AM};
-  Stator_Ind_Bp = #{};              Stator_Ind_Bm = #{STATOR_IND_BM};
-  Stator_Ind_Cp = #{STATOR_IND_CP}; Stator_Ind_Cm = #{};
-  If(NbrPolesInModel > 1)
-    Stator_Ind_Ap += #STATOR_IND_AP;
-    Stator_Ind_Bp += #STATOR_IND_BP;
-    Stator_Ind_Cm += #STATOR_IND_CM;
-  EndIf
-
-  PhaseA = Region[{ Stator_Ind_Ap, Stator_Ind_Am }];
-  PhaseB = Region[{ Stator_Ind_Bp, Stator_Ind_Bm }];
-  PhaseC = Region[{ Stator_Ind_Cp, Stator_Ind_Cm }];
-
-  // FIXME: Just one physical region for nice graph in Onelab
-  PhaseA_pos = Region[{ Stator_Ind_Am }];
-  PhaseB_pos = Region[{ Stator_Ind_Bm }];
-  PhaseC_pos = Region[{ Stator_Ind_Cp }];
-
-  Stator_IndsP = Region[{ Stator_Ind_Ap, Stator_Ind_Bp, Stator_Ind_Cp }];
-  Stator_IndsN = Region[{ Stator_Ind_Am, Stator_Ind_Bm, Stator_Ind_Cm }];
-
-  Stator_Inds = Region[ {PhaseA, PhaseB, PhaseC} ] ;
-  Rotor_Inds  = Region[ {} ] ;
-
-  StatorC  = Region[{ }] ;
-  StatorCC = Region[{ Stator_Fe }] ;
-  RotorC   = Region[{ }] ;
-  RotorCC  = Region[{ Rotor_Fe, Rotor_Magnets }] ;
-
-  // Moving band:  with or without symmetry, these BND lines must be complete
-  Stator_Bnd_MB = #STATOR_BND_MOVING_BAND;
-  For k In {1:SymmetryFactor}
-    Rotor_Bnd_MB~{k} = Region[ (ROTOR_BND_MOVING_BAND+k-1) ];
-    Rotor_Bnd_MB += Region[ Rotor_Bnd_MB~{k} ];
-  EndFor
-  Rotor_Bnd_MBaux = Region[ {Rotor_Bnd_MB, -Rotor_Bnd_MB~{1}}];
-
-}
-
-// --------------------------------------------------------------------------
-// --------------------------------------------------------------------------
-
-Function {
-
-  NbrPhases = 3 ;
-
-  // For a radial remanent b
-  For k In {1:nbMagnets}
-    br[ Rotor_Magnet~{k} ] = (-1)^(k-1) * b_remanent * Vector[ Cos[Atan2[Y[],X[]]], Sin[Atan2[Y[],X[]]], 0 ];
-  EndFor
-
-
-  //Data for modeling a stranded inductor
-  NbWires[]  = 104 ; // Number of wires per slot
-  // STATOR_IND_AM comprises all the slots in that phase, we need thus to divide by the number of slots
-  nbSlots[] = Ceil[nbInds/NbrPhases/2] ;
-  SurfCoil[] = SurfaceArea[]{STATOR_IND_AM}/nbSlots[] ;//All inductors have the same surface
-
-  FillFactor_Winding = 0.5 ; // percentage of Cu in the surface coil side, smaller than 1
-  Factor_R_3DEffects = 1.5 ; // bigger than Adding 50% of resistance
-
-  DefineConstant[ rpm = { rpm_nominal,
-      Name "Input/7speed in rpm",
-      Highlight "AliceBlue", Visible (Flag_AnalysisType==1)} ]; // speed in rpm
-  wr = rpm/60*2*Pi ; // speed in rad_mec/s
-
-  // supply at fixed position
-  DefineConstant[ Freq = { wr*NbrPolePairs/(2*Pi), ReadOnly 1,
-      Name "Output/1Freq", Highlight "LightYellow" } ];
-  Omega = 2*Pi*Freq ;
-  T = 1/Freq ;
-
-  DefineConstant[
-    thetaMax_deg = { 180, Name "Input/21End rotor angle (loop)",
-      Highlight "AliceBlue", Visible (Flag_AnalysisType==1) }
-  ];
-
-  theta0   = InitialRotorAngle + 0. ;
-  thetaMax = thetaMax_deg * deg2rad ; // end rotor angle (used in doing a loop)
-
-  DefineConstant[
-    NbTurns  = { (thetaMax-theta0)/(2*Pi), Name "Input/24Number of revolutions",
-      Highlight "LightGrey", ReadOnly 1, Visible (Flag_AnalysisType==1)},
-    delta_theta_deg = { 1., Name "Input/22Step [deg]",
-      Highlight "AliceBlue", Visible (Flag_AnalysisType==1)}
-  ];
-
-  delta_theta[] = delta_theta_deg * deg2rad ;
-
-  time0 = 0 ; // at initial rotor position
-  delta_time = delta_theta_deg * deg2rad/wr;
-  timemax = thetaMax/wr;
-
-  DefineConstant[
-    NbSteps = { Ceil[(timemax-time0)/delta_time], Name "Input/23Number of steps",
-      Highlight "LightGrey", ReadOnly 1, Visible (Flag_AnalysisType==1)}
-  ];
-
-  RotorPosition[] = InitialRotorAngle + $Time * wr ;
-  RotorPosition_deg[] = RotorPosition[]*180/Pi;
-
-  Flag_ParkTransformation = 1 ;
-  Theta_Park[] = ((RotorPosition[] + Pi/8) - Pi/6) * NbrPolePairs; // electrical degrees
-  Theta_Park_deg[] = Theta_Park[]*180/Pi;
-
-  DefineConstant[
-    ID = { 0, Name "Input/50Id stator current",
-      Highlight "AliceBlue", Visible (Flag_SrcType_Stator==1)},
-    IQ = { Inominal, Name "Input/51Iq stator current",
-      Highlight "AliceBlue", Visible (Flag_SrcType_Stator==1)}
-  ] ;
-}
-
-// --------------------------------------------------------------------------
-// --------------------------------------------------------------------------
-// --------------------------------------------------------------------------
-
-If(Flag_SrcType_Stator)
-  UndefineConstant["Input/8Load resistance"];
-EndIf
-
-If(Flag_Cir)
-  Include "pmsm_8p_circuit.pro" ;
-EndIf
-Include "machine_magstadyn_a.pro" ;
-
diff --git a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_8p_circuit.pro b/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_8p_circuit.pro
deleted file mode 100644
index fa1b32f..0000000
--- a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_8p_circuit.pro
+++ /dev/null
@@ -1,122 +0,0 @@
-//
-// Circuit for Permanent Magnet Synchronous Generator
-//
-
-Group{
-  R1 = #55551 ;
-  R2 = #55552 ;
-  R3 = #55553 ;
-
-  Input1 = #10001 ;
-  Input2 = #10002 ;
-  Input3 = #10003 ;
-  Input4 = #10004 ;
-
-  Resistance_Cir  = Region[{R1, R2, R3}];
-  DomainZ_Cir = Region[ {Resistance_Cir} ];
-
-  DomainSource_Cir = Region[ {} ] ;
-  If(Flag_SrcType_Stator>1)
-    DomainSource_Cir += Region[ {Input1, Input2, Input3} ] ;
-  EndIf
-
-  DomainZt_Cir = Region[ {DomainZ_Cir, DomainSource_Cir} ];
-}
-
-// --------------------------------------------------------------------------
-// --------------------------------------------------------------------------
-
-Function {
-  // Open circuit - load - short circuit
-  DefineConstant[ ZR = {200, Choices{1e-8, 200, 1e8},
-      Name "Input/8Load resistance", Highlight "AliceBlue"} ];
-  Resistance[#{R1, R2, R3}]  = ZR ;
-}
-
-// --------------------------------------------------------------------------
-
-Constraint {
-
-  If (SymmetryFactor<8)
-    If(Flag_SrcType_Stator==0)
-      { Name ElectricalCircuit ; Type Network ;
-        Case Circuit1 {
-          { Region Stator_Ind_Ap ; Branch {100,102} ; }
-          { Region Stator_Ind_Am ; Branch {103,102} ; }
-          { Region R1            ; Branch {103,100} ; }
-        }
-        Case Circuit2 {
-          { Region Stator_Ind_Bp ; Branch {200,202} ; }
-          { Region Stator_Ind_Bm ; Branch {203,202} ; }
-          { Region R2            ; Branch {203,200} ; }
-        }
-        Case Circuit3 {
-          { Region Stator_Ind_Cp ; Branch {300,302} ; }
-          { Region Stator_Ind_Cm ; Branch {303,302} ; }
-          { Region R3            ; Branch {303,300} ; }
-        }
-      }
-    EndIf
-    If (Flag_SrcType_Stator==2)
-      { Name ElectricalCircuit ; Type Network ;
-        Case Circuit1 {
-          { Region Input1        ; Branch {100,101} ; }
-          { Region Stator_Ind_Ap ; Branch {101,102} ; }
-          { Region Stator_Ind_Am ; Branch {103,102} ; }
-          { Region R1            ; Branch {103,100} ; }
-        }
-        Case Circuit2 {
-          { Region Input2        ; Branch {200,201} ; }
-          { Region Stator_Ind_Bp ; Branch {201,202} ; }
-          { Region Stator_Ind_Bm ; Branch {203,202} ; }
-          { Region R2            ; Branch {203,200} ; }
-        }
-        Case Circuit3 {
-          { Region Input3        ; Branch {300,301} ; }
-          { Region Stator_Ind_Cp ; Branch {301,302} ; }
-          { Region Stator_Ind_Cm ; Branch {303,302} ; }
-          { Region R3            ; Branch {303,300} ; }
-        }
-      }
-    EndIf
-  EndIf
-
-  If(SymmetryFactor==8)
-    If(Flag_SrcType_Stator==0) // Only one physical region in geo allow per branch
-      { Name ElectricalCircuit ; Type Network ;
-        Case Circuit1 {
-          { Region PhaseA        ; Branch {100,102} ; }
-          { Region R1            ; Branch {102,100} ; }
-        }
-        Case Circuit2 {
-          { Region PhaseB        ; Branch {200,202} ; }
-          { Region R2            ; Branch {202,200} ; }
-        }
-        Case Circuit3 {
-          { Region PhaseC        ; Branch {300,302} ; }
-          { Region R3            ; Branch {302,300} ; }
-        }
-      }
-    EndIf
-    If(Flag_SrcType_Stator==2) // Only one physical region in geo allow per branch
-      { Name ElectricalCircuit ; Type Network ;
-        Case Circuit1 {
-          { Region Input1        ; Branch {100,101} ; }
-          { Region PhaseA        ; Branch {101,102} ; }
-          { Region R1            ; Branch {102,100} ; }
-        }
-        Case Circuit2 {
-          { Region Input2        ; Branch {200,201} ; }
-          { Region PhaseB        ; Branch {201,202} ; }
-          { Region R2            ; Branch {202,200} ; }
-        }
-        Case Circuit3 {
-          { Region Input3        ; Branch {300,301} ; }
-          { Region PhaseC        ; Branch {302,301} ; }
-          { Region R3            ; Branch {302,300} ; }
-        }
-      }
-    EndIf
-  EndIf
-}
-
diff --git a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_data.geo b/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_data.geo
deleted file mode 100644
index f7545f8..0000000
--- a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_data.geo
+++ /dev/null
@@ -1,122 +0,0 @@
-// Permanent magnet synchronous machine
-// Example of Prof. Dr. Mauricio Valencia Ferreira da Luz (Florianopolis, August 23, 2010)
-
-// Modified and customised for Onelab by Ruth V. Sabariego (February, 2013)
-
-mm = 1e-3 ;
-deg2rad = Pi/180 ;
-
-pp = "Input/Constructive parameters/";
-
-DefineConstant[
-  NbrPolesInModel = { 1, Choices {1="1", 2="2", 4="4", 8="8"},
-    Name "Input/20Number of poles in FE model",
-    Highlight "Blue", Visible 1},
-  InitialRotorAngle_deg = {7.5,
-    Name "Input/21Start rotor angle [deg]",
-    Highlight "AliceBlue"}
-] ;
-
-//--------------------------------------------------------------------------------
-
-InitialRotorAngle = InitialRotorAngle_deg*deg2rad ; // initial rotor angle, 0 if aligned
-
-//------------------------------------------------
-//------------------------------------------------
-NbrPolesTot = 8 ; // number of poles in complete cross-section
-NbrPolePairs = NbrPolesTot/2 ;
-
-SymmetryFactor = NbrPolesTot/NbrPolesInModel ;
-Flag_Symmetry = (SymmetryFactor==1)?0:1 ;
-
-NbrSectTot = NbrPolesTot ; // number of "rotor teeth"
-NbrSect = NbrSectTot*NbrPolesInModel/NbrPolesTot ; // number of "rotor teeth" in FE model
-//--------------------------------------------------------------------------------
-
-//------------------------------------------------
-// Stator
-//------------------------------------------------
-NbrSectTotStator  = 24; // number of stator teeth
-NbrSectStator   = NbrSectTotStator*NbrPolesInModel/NbrPolesTot; // number of stator teeth in FE model
-//--------------------------------------------------------------------------------
-
-DefineConstant[
-  lm = {2.352*mm , Name StrCat[pp, "Magnet height [m]"], Closed 0}
-];
-
-Th_magnet = 32.67 *deg2rad ;  // angle in degrees 0 < Th_magnet < 45
-
-//--------------------------------------------------------------------------------
-
-rRext = 25.6*mm;
-rR1 = 10.5*mm;
-rR2 = (rRext-lm); //23.243e-03;
-rR3 = (rRext-0.7389*lm); //23.862e-03;
-rR4 = (rRext-0.72278*lm); //23.9e-03;
-rR5 = rRext; //25.6e-03;
-
-//Gap = rS1-rR5;
-DefineConstant[
-  AxialLength = {35*mm,  Name StrCat[pp, "Axial length [m]"], Closed 1},
-  Gap = {(26.02-25.6)*mm, Name StrCat[pp, "Airgap width [m]"], Closed 0}
-];
-
-rS1 = rR5 + Gap;     //rS1 = 26.02*mm;
-rS2 = rS1 + 0.6*mm;  //rS2 = 26.62*mm;
-rS3 = rS2 + 0.34*mm; //rS3 = 26.96*mm;
-rS4 = rS3 + 11.2*mm; //rS4 = 38.16*mm;
-rS5 = rS4 + 0.11*mm; //rS5 = 38.27*mm;
-rS6 = rS5 + 1.75*mm; //rS6 = 40.02*mm;
-rS7 = rS6 + 5.98*mm; //rS7 = 46.00*mm;
-
-rB1  = rR5+Gap/3;
-rB1b = rB1;
-rB2  = rR5+Gap*2/3;
-
-
-A0 =  45 * deg2rad ; // with this choice, axis A of stator is at 30 degrees with regard to horizontal axis
-A1 =   0 * deg2rad ; // Rotor initial aligned position, current position in angRot
-
-sigma_fe = 0. ; // laminated steel
-DefineConstant[
-  mur_fe = {1000, Name StrCat[pp, "Relative permeability for linear case"]},
-  b_remanent = {1.2, Name StrCat[pp, "Remanent induction [T]"] }
-];
-
-rpm_nominal = 500 ;
-Inominal = 3.9 ; // Nominal current
-Tnominal = 2.5 ; // Nominal torque
-
-// ----------------------------------------------------
-// Numbers for physical regions in .geo and .pro files
-// ----------------------------------------------------
-// Rotor
-ROTOR_FE     = 1000 ;
-ROTOR_AIR    = 1001 ;
-ROTOR_AIRGAP = 1002 ;
-ROTOR_MAGNET = 1010 ; // Index for first Magnet (1/8 model->1; full model->8)
-
-ROTOR_BND_MOVING_BAND = 1100 ; // Index for first line (1/8 model->1; full model->8)
-ROTOR_BND_A0 = 1200 ;
-ROTOR_BND_A1 = 1201 ;
-SURF_INT     = 1202 ;
-
-// Stator
-STATOR_FE     = 2000 ;
-STATOR_AIR    = 2001 ;
-STATOR_AIRGAP = 2002 ;
-
-STATOR_BND_MOVING_BAND = 2100 ;// Index for first line (1/8 model->1; full model->8)
-STATOR_BND_A0          = 2200 ;
-STATOR_BND_A1          = 2201 ;
-
-STATOR_IND = 2300 ; //Index for first Ind (1/8 model->3; full model->24)
-STATOR_IND_AP = STATOR_IND + 1 ; STATOR_IND_BM = STATOR_IND + 2 ;STATOR_IND_CP = STATOR_IND + 3 ;
-STATOR_IND_AM = STATOR_IND + 4 ; STATOR_IND_BP = STATOR_IND + 5 ;STATOR_IND_CM = STATOR_IND + 6 ;
-
-SURF_EXT = 3000 ; // outer boundary
-
-
-MOVING_BAND = 9999 ;
-
-NICEPOS = 111111 ;
diff --git a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_rotor.geo b/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_rotor.geo
deleted file mode 100644
index 2280f90..0000000
--- a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_rotor.geo
+++ /dev/null
@@ -1,164 +0,0 @@
-//--------------------------------------------------------------------------------
-// Rotor PMSM
-//--------------------------------------------------------------------------------
-A = InitialRotorAngle-45/2*deg2rad + A1; // with Theta_Park
-
-sinA = Sin(A); cosA = Cos(A);
-pntR[]+=newp; Point(newp)={rR1*cosA, rR1*sinA, 0, pR1};
-pntR[]+=newp; Point(newp)={rR2*cosA, rR2*sinA, 0, pR1};
-pntR[]+=newp; Point(newp)={rR4*cosA, rR4*sinA, 0, pR1};
-pntR[]+=newp; Point(newp)={rR5*cosA, rR5*sinA, 0, pR1};
-pntR[]+=newp; Point(newp)={rB1*cosA, rB1*sinA, 0, pR2};
-
-For k In {0:#pntR[]-2}
- linR0[]+=newl; Line(newl) = {pntR[k], pntR[k+1]};
-EndFor
-
-Transfinite Line{linR0[0]} = Ceil[(rR2-rR1)/pR1/fact_trans] ;
-Transfinite Line{linR0[1]} = Ceil[(rR4-rR2)/pR1/fact_trans] ;
-Transfinite Line{linR0[2]} = Ceil[(rR5-rR4)/pR1/fact_trans] ;
-Transfinite Line{linR0[3]} = Ceil[(rB1-rR5)/pR1/fact_trans] ;
-
-
-For k In {0:#linR0[]-1}
- linR1[] += Rotate {{0, 0, 1}, {0, 0, 0}, A0+A1} { Duplicata{Line{linR0[k]};} };
-EndFor
-
-AA[] = {(A0-Th_magnet)/2+A1, Th_magnet, (A0-Th_magnet)/2+A1} ;
-
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[0]} { Point{pntR[0]}; };
-cirR[]+=lin[1];
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[1]} { Point{lin[0]}; };
-cirR[]+=lin[1];
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[2]} { Point{lin[0]}; };
-cirR[]+=lin[1];
-
-surfint[]=cirR[{0,1,2}] ; // boundary conditions
-
-pMagnet[] = Rotate {{0, 0, 1}, {0, 0, 0}, AA[0]} { Duplicata{Point{pntR[1]};} };
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[1]} { Point{pMagnet[0]}; };
-pMagnet[] += lin[0];
-cirR[] += lin[1] ;
-
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[0]} { Point{pntR[2]}; };
-cirR[]+=lin[1]; pMagnet[] += lin[0];
-pMagnet[] += Rotate {{0, 0, 1}, {0, 0, 0}, AA[1]} { Duplicata{Point{lin[0]};} };
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[2]} { Point{pMagnet[3]}; };
-cirR[]+=lin[1];
-
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[0]} { Point{pntR[3]}; };
-cirR[]+=lin[1];
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[1]} { Point{lin[0]}; };
-cirR[]+=lin[1];
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, AA[2]} { Point{lin[0]}; };
-cirR[]+=lin[1];
-
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, A0+A1} { Point{pntR[4]}; };
-cirR[]+=lin[1];
-
-linR2[] = Rotate {{0, 0, 1}, {0, 0, 0}, (A0-Th_magnet)/2+A1} { Duplicata{Line{linR0[{1,2}]};} };
-linR3[] = Rotate {{0, 0, 1}, {0, 0, 0},-(A0-Th_magnet)/2+A1} { Duplicata{Line{linR1[{1,2}]};} };
-
-// surfaces rotor
-Line Loop(newll) = {linR0[{0,1}], cirR[4], -linR2[0], cirR[3], linR3[0], cirR[5], -linR1[{1,0}], -cirR[{2,1,0}]};
-srotor[0]=news; Plane Surface(srotor[0]) = {newll-1};
-
-Line Loop(newl) = {linR2[1], cirR[7], -linR3[{1,0}], -cirR[3], linR2[0]};
-smagnet[0]=news; Plane Surface(smagnet[0]) = {newll-1};
-
-nn = #cirR[]-1 ;
-Line Loop(newll) = {cirR[{nn-5}], linR2[1], -cirR[{nn-3}], -linR0[2]};
-sairrotor[]+=news; Plane Surface(news) = -{newll-1};
-Line Loop(newll) = {cirR[{nn-4}], linR1[2], -cirR[{nn-1}], -linR3[1]};
-sairrotor[]+=news; Plane Surface(news) = -{newll-1};
-
-Line Loop(newll) = {linR0[3], cirR[nn], -linR1[3], -cirR[{nn-1:nn-3:-1}]};
-sairrotormb[]+=news; Plane Surface(news) = {newll-1};
-
-// -------------------------------------------------------------------------------
-// Moving band == AirGap rotor side
-// -------------------------------------------------------------------------------
-Transfinite Line{cirR[nn]} = NbrDivMB+1 ;
-
-//Filling the gap for the whole 2*Pi
-lineMBrotor[]=cirR[{nn}];
-For k In {1:NbrPolesTot-1}
-  lineMBrotoraux[]+=Rotate {{0, 0, 1}, {0, 0, 0}, k*A0} { Duplicata{Line{lineMBrotor[]};} };
-EndFor
-
-// -------------------------------------------------------------------------------
-// -------------------------------------------------------------------------------
-If(SymmetryFactor<8)
-// FULL MODEL ==> Rotation of NbrPolesTot*Pi/4
-// For simplicity: rotating first the interior and exterior boundaries
-
-  If (SymmetryFactor>1)
-    For k In {0:#linR1[]-1}
-      linR1_[] += Rotate {{0, 0, 1}, {0, 0, 0}, 2*Pi/SymmetryFactor-Pi/4} { Duplicata{Line{linR1[k]};} };
-    EndFor
-    linR1[] = linR1_[];
-  EndIf
-
-  For k In {1:NbrPolesInModel-1}
-    surfint[] += Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Line{surfint[{0:2}]};} };
-  EndFor
-  For k In {1:NbrPolesInModel-1}
-    srotor[] += Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{srotor[0]};} };
-    smagnet[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{smagnet[0]};} };
-    sairrotor[]  += Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sairrotor[{0,1}]};} };
-    sairrotormb[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sairrotormb[0]};} };
-  EndFor
-EndIf
-
-
-// -------------------------------------------------------------------------------
-// Physical regions
-// -------------------------------------------------------------------------------
-
-Physical Surface(ROTOR_FE)     = {srotor[]};     // Rotor
-Physical Surface(ROTOR_AIR)    = {sairrotor[]};  // AirRotor
-Physical Surface(ROTOR_AIRGAP) = {sairrotormb[]};// AirRotor for possible torque computation with Maxwell stress tensor
-
-NN = (Flag_Symmetry)?NbrPolesInModel:NbrPolesTot;
-For k In {0:NN-1}
-  Physical Surface(ROTOR_MAGNET+k) = {smagnet[k]}; // Magnets
-EndFor
-
-Physical Line(SURF_INT) = {surfint[]}; // SurfInt
-
-
-If(Flag_Symmetry)  //Lines for symmetry link
-  Physical Line(ROTOR_BND_A0)  = linR0[];
-  Physical Line(ROTOR_BND_A1)  = linR1[];
-EndIf
-
-lineMBrotor[] += lineMBrotoraux[] ;
-If(!Flag_Symmetry)
-  Physical Line(ROTOR_BND_MOVING_BAND)  = {lineMBrotor[]};
-EndIf
-If(Flag_Symmetry)
-  nr = #lineMBrotor[];
-  nnp = nr/(NbrPolesTot/NbrSect) ;
-  For k In {1:Floor[NbrPolesTot/NbrSect]}
-    kk= ((k*nnp-1) > nr) ? nr-1 : k*nnp-1 ;
-    Physical Line(ROTOR_BND_MOVING_BAND+k-1) = lineMBrotor[{(k-1)*nnp:kk}] ;
-  EndFor
-  k1 = Floor[NbrPolesTot/NbrSect];
-  k2 = Ceil[NbrPolesTot/NbrSect];
-  If (k2 > k1)
-    Physical Line(ROTOR_BND_MOVING_BAND+k2-1) = lineMBrotor[{(k2-1)*nnp:#lineMBrotor[]-1}] ;
-  EndIf
-EndIf
-
-// For nice visualisation...
-linRotor[]  = CombinedBoundary{Surface{srotor[]};};
-linMagnet[] = Boundary{Surface{smagnet[]};};
-
-nicepos_rotor[] += { linRotor[], linMagnet[] };
-
-Color SteelBlue {Surface{srotor[]};}
-Color SkyBlue {Surface{sairrotor[], sairrotormb[]};}
-Color Orchid {Surface{smagnet[{0:#smagnet[]-1:2}]};}
-If(#smagnet[]>1)
-Color Purple {Surface{smagnet[{1:#smagnet[]-1:2}]};}
-EndIf
diff --git a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_stator.geo b/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_stator.geo
deleted file mode 100644
index f005f48..0000000
--- a/contrib/mobile/iOS/Onelab/files/pmsm/pmsm_stator.geo
+++ /dev/null
@@ -1,217 +0,0 @@
-// -------------------------------------------------------------------------------
-// Moving band == AirGap stator side
-// -------------------------------------------------------------------------------
-pntG[]+=newp; Point(newp) = {rB2, 0., 0., pS1}; // aligned with the stator
-circ[] = Extrude {{0, 0, 1}, {0, 0, 0}, A0} { Point{pntG[0]}; };
-pntG[]+=circ[0];
-lineMBstator[]=circ[1];
-
-Transfinite Line{lineMBstator[0]} = NbrDivMB+1 ;
-
-
-//Filling the gap for the whole 2*Pi
-For k In {1:NbrPolesTot-1}
-  lineMBstatoraux[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*A0} { Duplicata{Line{lineMBstator[0]};} };
-EndFor
-
-// -------------------------------------------------------------------------------
-// Stator
-// -------------------------------------------------------------------------------
-
-pntS[] = newp; Point(newp)={rS1, 0, 0, pS1};
-linS[] = newl; Line(newl) = {pntG[0], pntS[0]};
-linS[]+= Rotate {{0, 0, 1}, {0, 0, 0}, A0} { Duplicata{Line{linS[0]};} };
-
-pntS[]+=newp; Point(newp)={rS7,0,0,pS2};
-points[]=Boundary{Line{linS[1]};};
-pntS[]+=points[1];
-
-lin[] = Extrude {{0, 0, 1}, {0, 0, 0}, A0} { Point{pntS[1]}; };
-cirS[]= lin[1]; pntS[]+=lin[0];
-
-linS[]+=newl; Line(newl) = {pntS[0], pntS[1]};
-linS[]+=newl; Line(newl) = {pntS[2], pntS[3]};
-
-// -------------------------------------------------------------------------------
-// Slots
-// -------------------------------------------------------------------------------
-
-A2 = 0.0;
-AA[]=deg2rad*{2.77+A2, 4.0+A2, 5.52+A2, 5.56+A2, 5.65+A2, 9.35+A2, 9.44+A2, 9.48+A2, 11+A2, 12.23+A2} ;
-
-For k In {0:#AA[]-1}
-  cosAA[]+=Cos(AA[k]); sinAA[]+=Sin(AA[k]);
-EndFor
-
-pntSlot[]+=newp; Point(newp)={rS5*cosAA[0], rS5*sinAA[0], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS3*cosAA[1], rS3*sinAA[1], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS1*cosAA[2], rS1*sinAA[2], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS2*cosAA[3], rS2*sinAA[3], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS4*cosAA[3], rS4*sinAA[3], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS6*cosAA[4], rS6*sinAA[4], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS6*cosAA[5], rS6*sinAA[5], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS4*cosAA[6], rS4*sinAA[6], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS2*cosAA[6], rS2*sinAA[6], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS1*cosAA[7], rS1*sinAA[7], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS3*cosAA[8], rS3*sinAA[8], 0., pS3};
-pntSlot[]+=newp; Point(newp)={rS5*cosAA[9], rS5*sinAA[9], 0., pS3};
-
-// air slot 1
-linASlot[]+=newl ; Line(newl)={pntSlot[2], pntSlot[3]};
-linASlot[]+=newl ; Line(newl)={pntSlot[3], pntSlot[1]};
-linASlot[]+=newl ; Circle(newl)={pntSlot[1], cen, pntSlot[10]};
-linASlot[]+=newl ; Line(newl)={pntSlot[10], pntSlot[8]};
-linASlot[]+=newl ; Line(newl)={pntSlot[8], pntSlot[9]};
-linASlot[]+=newl ; Circle(newl)={pntSlot[9], cen, pntSlot[2]};
-
-Line Loop(newll) = {linASlot[]};
-sairslot[] += news ; Plane Surface(sairslot[0]) = {newll-1};
-
-// coil slot 1
-linSlot[]+=newl ; Line(newl)={pntSlot[1], pntSlot[0]};
-linSlot[]+=newl ; Circle(newl)= {pntSlot[0], pntSlot[4], pntSlot[5]};
-linSlot[]+=newl ; Line(newl)={pntSlot[5], pntSlot[6]};
-linSlot[]+=newl ; Circle(newl)={pntSlot[6], pntSlot[7],pntSlot[11]};
-linSlot[]+=newl ; Line(newl)={pntSlot[11], pntSlot[10]};
-
-Line Loop(newll) = {-linASlot[2],linSlot[]};
-sslot[] += news ; Plane Surface(sslot[0]) = {newll-1};
-
-// slots 2 and 3
-A2 = 15*deg2rad;
-
-pntSlot0[0] = pntSlot[2];
-pntSlot1[0] = pntSlot[9];
-For k In{1:2}
-  pntSlot0[] += Rotate {{0, 0, 1}, {0, 0, 0}, A2} { Duplicata{Point{pntSlot0[k-1]};} };
-  pntSlot1[] += Rotate {{0, 0, 1}, {0, 0, 0}, A2} { Duplicata{Point{pntSlot1[k-1]};} };
-EndFor
-
-For k In{1:2}
-  sslot[] += Rotate {{0, 0, 1}, {0, 0, 0}, A2} { Duplicata{Surface{sslot[k-1]};} };
-  sairslot[] += Rotate {{0, 0, 1}, {0, 0, 0}, A2} { Duplicata{Surface{sairslot[k-1]};} };
-EndFor
-
-cSlot[]+=newl; Circle(newl) = {pntS[0], cen, pntSlot[2]};
-cSlot[]+=newl; Circle(newl) = {pntSlot1[0], cen, pntSlot0[1]};
-cSlot[]+=newl; Circle(newl) = {pntSlot1[1], cen, pntSlot0[2]};
-cSlot[]+=newl; Circle(newl) = {pntSlot1[2], cen, pntS[2]};
-
-linesslot0[] = CombinedBoundary{ Surface{ sslot[0], sairslot[0] } ;};
-linesslot1[] = CombinedBoundary{ Surface{ sslot[1], sairslot[1] } ;};
-linesslot2[] = CombinedBoundary{ Surface{ sslot[2], sairslot[2] } ;};
-
-Line Loop(newll) = {-lineMBstator[0],linS[0], cSlot[0],-linesslot0[{4}],
-                    cSlot[1],-linesslot1[{9}],
-                    cSlot[2],-linesslot2[{9}], cSlot[3], -linS[1]};
-sairgapS[0]=news; Plane Surface(sairgapS[0]) = {newll-1};
-
-linesslot0[] -= linesslot0[{4}];
-linesslot1[] -= linesslot1[{9}];
-linesslot2[] -= linesslot2[{9}];
-Line Loop(newll) = { cSlot[0], linesslot0[],
-                     cSlot[1], linesslot1[],
-                     cSlot[2], linesslot2[],
-                     cSlot[3], linS[3], -cirS[0], -linS[2]};
-sstator[0]=news; Plane Surface(sstator[0]) = -{newll-1};
-
-// -------------------------------------------------------------------------------
-// -------------------------------------------------------------------------------
-
-auxlink[]=linS[{1,3}]; // A1
-
-If(SymmetryFactor<8)
-  // FULL MODEL ==> Rotation of NbrPolesTot*Pi/4
-  // For simplicity: rotating the interior and exterior boundaries
-
- If (SymmetryFactor>1)
-    For k In {0:#auxlink[]-1}
-      auxlink_[] += Rotate {{0, 0, 1}, {0, 0, 0}, 2*Pi/SymmetryFactor-Pi/4} { Duplicata{Line{auxlink[k]};} };
-    EndFor
-    auxlink[] = auxlink_[];
-  EndIf
-
-  For k In {1:NbrPolesInModel-1}
-    cirS[] += Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Line{cirS[{0}]};} };
-  EndFor
-  For k In {1:NbrPolesInModel-1}
-    sstator[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sstator[0]};} };
-    sairgapS[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sairgapS[0]};} };
-    sairslot[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sairslot[{0:2}]};} };
-    sslot[]+= Rotate {{0, 0, 1}, {0, 0, 0}, k*Pi/4} { Duplicata{ Surface{sslot[{0:2}]};} };
-  EndFor
-EndIf
-
-
-
-// -------------------------------------------------------------------------------
-// -------------------------------------------------------------------------------
-// Physical regions
-// -------------------------------------------------------------------------------
-// -------------------------------------------------------------------------------
-
-Physical Surface(STATOR_FE)     = {sstator[]};  // Stator
-Physical Surface(STATOR_AIR)    = {sairslot[]}; // AirStator
-Physical Surface(STATOR_AIRGAP) = {sairgapS[]}; // AirStator for possible torque computation with Maxwell stress tensor
-
-NN = (Flag_Symmetry)?NbrSectStator:NbrSectTotStator;
-//For k In {0:NN-1}
-//  Physical Surface(STATOR_IND+k) = {sslot[k]}; //Inds
-//EndFor
-
-Physical Surface(STATOR_IND_AM) = {sslot[{0:NN-1:6}]};
-Physical Surface(STATOR_IND_CP) = {sslot[{1:NN-1:6}]};
-Physical Surface(STATOR_IND_BM) = {sslot[{2:NN-1:6}]};
-If(NbrSectStator>2)
-  Physical Surface(STATOR_IND_AP) = {sslot[{3:NN-1:6}]};
-  Physical Surface(STATOR_IND_CM) = {sslot[{4:NN-1:6}]};
-  Physical Surface(STATOR_IND_BP) = {sslot[{5:NN-1:6}]};
-EndIf
-
-Color Pink         {Surface{ sslot[{0:NN-1:6}] };} // A-
-Color ForestGreen  {Surface{ sslot[{1:NN-1:6}] };} // C+
-Color PaleGoldenrod{Surface{ sslot[{2:NN-1:6}] };} // B-
-If (#sslot[]>=6)
-Color Red        {Surface{ sslot[{3:NN-1:6}] };} // A+
-Color SpringGreen{Surface{ sslot[{4:NN-1:6}] };} // C-
-Color Gold       {Surface{ sslot[{5:NN-1:6}] };} // B+
-EndIf
-
-
-Physical Line(SURF_EXT) = {cirS[]}; // SurfExt
-
-If(Flag_Symmetry) //Lines for symmetry link
-  Physical Line(STATOR_BND_A0) = linS[{0,2}];
-  Physical Line(STATOR_BND_A1) = auxlink[] ;
-EndIf
-
-
-lineMBstator[] += lineMBstatoraux[] ;
-If(!Flag_Symmetry)
-  Physical Line(STATOR_BND_MOVING_BAND) = {lineMBstator[]};
-EndIf
-If(Flag_Symmetry)
-ns = #lineMBstator[];
-nns = ns/SymmetryFactor ;
-For k In {1:SymmetryFactor}
-  kk= ((k*nns-1) > ns) ? ns-1 : k*nns-1 ;
-  Physical Line(STATOR_BND_MOVING_BAND+k-1) = {lineMBstator[{(k-1)*nns:kk}]};
-EndFor
-  k1 = Floor[NbrPolesTot/NbrSect];
-  k2 = Ceil[NbrPolesTot/NbrSect];
-  If (k2 > k1)
-    Physical Line(STATOR_BND_MOVING_BAND+k2-1) = lineMBstator[{(k2-1)*nns:#lineMBstator[]-1}] ;
-  EndIf
-EndIf
-
-
-// For nice visualisation...
-linStator[] = CombinedBoundary{Surface{sstator[]};};
-linSlot[] = CombinedBoundary{Surface{sslot[]};};
-
-nicepos_stator[] += {linStator[],linSlot[] };
-
-Color SteelBlue {Surface{sstator[]};}
-Color SkyBlue {Surface{sairslot[],sairgapS[]};}
-
-
diff --git a/contrib/mobile/iOS/Onelab/icon_onelab.png b/contrib/mobile/iOS/Onelab/icon_onelab.png
new file mode 100644
index 0000000..262b7f5
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/icon_onelab.png differ
diff --git a/contrib/mobile/iOS/Onelab/icon_rotate.png b/contrib/mobile/iOS/Onelab/icon_rotate.png
new file mode 100644
index 0000000..28ae466
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/icon_rotate.png differ
diff --git a/contrib/mobile/iOS/Onelab/icon_translate.png b/contrib/mobile/iOS/Onelab/icon_translate.png
new file mode 100644
index 0000000..acde225
Binary files /dev/null and b/contrib/mobile/iOS/Onelab/icon_translate.png differ
diff --git a/contrib/mobile/iOS/Onelab/main.mm b/contrib/mobile/iOS/Onelab/main.mm
index 4f84a87..d645c72 100644
--- a/contrib/mobile/iOS/Onelab/main.mm
+++ b/contrib/mobile/iOS/Onelab/main.mm
@@ -1,18 +1,10 @@
-//
-//  main.m
-//  Onelab
-//
-//  Created by Maxime Graulich on 08/04/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #import <UIKit/UIKit.h>
 
 #import "AppDelegate.h"
 
 int main(int argc, char *argv[])
 {
-    @autoreleasepool {
-        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
-    }
+  @autoreleasepool {
+    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+  }
 }
diff --git a/contrib/mobile/iosGModel.cpp b/contrib/mobile/iosGModel.cpp
index e5b1fa2..5237306 100644
--- a/contrib/mobile/iosGModel.cpp
+++ b/contrib/mobile/iosGModel.cpp
@@ -1,22 +1,15 @@
-//
-//  iosGModel.cpp
-//  Onelab
-//
-//  Created by Maxime Graulich on 05/08/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #include "iosGModel.h"
 
 static void * objc;
 
-void getBitmapFromString(const char *text, int textsize, unsigned char **map, int *height, int *width, int *realWidth)
+void getBitmapFromString(const char *text, int textsize, unsigned char **map,
+                         int *height, int *width, int *realWidth)
 {
-    getBitmap(objc, text, textsize, map, height, width, realWidth);
+  getBitmap(objc, text, textsize, map, height, width, realWidth);
 }
 
 void setObjCBridge(void *objcObject)
 {
-    objc = objcObject;
-    Msg::SetCallback((GmshMessage*)new MobileMessage(objcObject));
-}
\ No newline at end of file
+  objc = objcObject;
+  Msg::SetCallback((GmshMessage*)new MobileMessage(objcObject));
+}
diff --git a/contrib/mobile/iosGModel.h b/contrib/mobile/iosGModel.h
index 4479d61..261be38 100644
--- a/contrib/mobile/iosGModel.h
+++ b/contrib/mobile/iosGModel.h
@@ -1,11 +1,3 @@
-//
-//  iosGModel.h
-//  Onelab
-//
-//  Created by Maxime Graulich on 07/05/13.
-//  Copyright (c) 2013 Maxime Graulich. All rights reserved.
-//
-
 #ifndef __Onelab__iosGModel__
 #define __Onelab__iosGModel__
 
@@ -15,21 +7,23 @@
 #include <Gmsh/GmshMessage.h>
 
 void messageFromCpp (void *self, std::string level, std::string msg);
-void getBitmap(void *self, const char *text, int textsize, unsigned char **map, int *height, int *width, int *realWidth=NULL);
-void getBitmapFromString(const char *text, int textsize, unsigned char **map, int *height, int *width, int *realWidth=NULL);
+void getBitmap(void *self, const char *text, int textsize, unsigned char **map,
+               int *height, int *width, int *realWidth=NULL);
+void getBitmapFromString(const char *text, int textsize, unsigned char **map,
+                         int *height, int *width, int *realWidth=NULL);
 void setObjCBridge(void *objcObject);
 
 class MobileMessage : GmshMessage
 {
 private:
-    void* _objcObject;
+  void* _objcObject;
 public:
-    MobileMessage(void* objcObject){_objcObject = objcObject;}
-    ~MobileMessage(){}
-    void operator()(std::string level, std::string message)
-    {
-        messageFromCpp(_objcObject, level, message);
-    }
+  MobileMessage(void* objcObject){_objcObject = objcObject;}
+  ~MobileMessage(){}
+  void operator()(std::string level, std::string message)
+  {
+    messageFromCpp(_objcObject, level, message);
+  }
 };
 
-#endif /* defined(__Onelab__iosGModel__) */
+#endif
diff --git a/contrib/mobile/movePosition.h b/contrib/mobile/movePosition.h
index b8e62cc..c7402ea 100644
--- a/contrib/mobile/movePosition.h
+++ b/contrib/mobile/movePosition.h
@@ -1,3 +1,6 @@
+#ifndef _MOVE_POSITION_H_
+#define _MOVE_POSITION_H_
+
 class movePosition {
  public:
   float win[3]; // window coordinates
@@ -18,7 +21,8 @@ class movePosition {
       t[i] = instance.t[i];
     }
   }
-  void set(float scale[3], float translate[3], float vxmax, float vxmin, float vymin, float vymax, int width, int height, int x, int y)
+  void set(float scale[3], float translate[3], float vxmax, float vxmin,
+           float vymin, float vymax, int width, int height, int x, int y)
   {
     for(int i = 0; i < 3; i++){
       s[i] = scale[i];
@@ -43,3 +47,4 @@ class movePosition {
   }
 };
 
+#endif
diff --git a/contrib/mobile/utils/Android.cmake b/contrib/mobile/utils/Android.cmake
new file mode 100644
index 0000000..6b9917a
--- /dev/null
+++ b/contrib/mobile/utils/Android.cmake
@@ -0,0 +1,1125 @@
+# ------------------------------------------------------------------------------
+#  Android CMake toolchain file, for use with the Android NDK r5-r8
+#  Requires cmake 2.6.3 or newer (2.8.5 or newer is recommended).
+#  See home page: http://code.google.com/p/android-cmake/
+#
+#  The file is mantained by the OpenCV project. And also can be found at
+#  http://code.opencv.org/projects/opencv/repository/revisions/master/changes/android/android.toolchain.cmake
+#
+#  Usage Linux:
+#   $ export ANDROID_NDK=/absolute/path/to/the/android-ndk
+#   $ mkdir build && cd build
+#   $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
+#   $ make -j8
+#
+#  Usage Linux (using standalone toolchain):
+#   $ export ANDROID_STANDALONE_TOOLCHAIN=/absolute/path/to/android-toolchain
+#   $ mkdir build && cd build
+#   $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake ..
+#   $ make -j8
+#
+#  Usage Windows:
+#     You need native port of make to build your project.
+#     Android NDK r7 (or newer) already has make.exe on board.
+#     For older NDK you have to install it separately.
+#     For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm
+#
+#   $ SET ANDROID_NDK=C:\absolute\path\to\the\android-ndk
+#   $ mkdir build && cd build
+#   $ cmake.exe -G"MinGW Makefiles"
+#       -DCMAKE_TOOLCHAIN_FILE=path\to\the\android.toolchain.cmake
+#       -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows\bin\make.exe" ..
+#   $ "%ANDROID_NDK%\prebuilt\windows\bin\make.exe"
+#
+#
+#  Options (can be set as cmake parameters: -D<option_name>=<value>):
+#    ANDROID_NDK=/opt/android-ndk - path to the NDK root.
+#      Can be set as environment variable. Can be set only at first cmake run.
+#
+#    ANDROID_STANDALONE_TOOLCHAIN=/opt/android-toolchain - path to the
+#      standalone toolchain. This option is not used if full NDK is found
+#      (ignored if ANDROID_NDK is set).
+#      Can be set as environment variable. Can be set only at first cmake run.
+#
+#    ANDROID_ABI=armeabi-v7a -  specifies the target Application Binary
+#      Interface (ABI). This option nearly matches to the APP_ABI variable
+#      used by ndk-build tool from Android NDK.
+#
+#      Possible targets are:
+#        "armeabi" - matches to the NDK ABI with the same name.
+#           See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation.
+#        "armeabi-v7a" - matches to the NDK ABI with the same name.
+#           See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation.
+#        "armeabi-v7a with NEON" - same as armeabi-v7a, but
+#            sets NEON as floating-point unit
+#        "armeabi-v7a with VFPV3" - same as armeabi-v7a, but
+#            sets VFPV3 as floating-point unit (has 32 registers instead of 16).
+#        "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP.
+#        "x86" - matches to the NDK ABI with the same name.
+#            See ${ANDROID_NDK}/docs/CPU-ARCH-ABIS.html for the documentation.
+#        "mips" - matches to the NDK ABI with the same name
+#            (not testes on real devices)
+#
+#    ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for.
+#      Option is read-only when standalone toolchain used.
+#
+#    ANDROID_FORCE_ARM_BUILD=OFF - set true to generate 32-bit ARM instructions
+#      instead of Thumb-1. Is not available for "x86" (inapplicable) and
+#      "armeabi-v6 with VFP" (forced) ABIs.
+#
+#    ANDROID_NO_UNDEFINED=ON - set true to show all undefined symbols as linker
+#      errors even if they are not used.
+#
+#    ANDROID_SO_UNDEFINED=OFF - set true to allow undefined symbols in shared
+#      libraries. Automatically turned on for NDK r5x and r6x due to GLESv2
+#      problems.
+#
+#    LIBRARY_OUTPUT_PATH_ROOT=${CMAKE_SOURCE_DIR} - where to output binary
+#      files. See additional details below.
+#
+#    ANDROID_SET_OBSOLETE_VARIABLES=ON - it set, then toolchain defines some
+#      obsolete variables which were set by previous versions of this file for
+#      backward compatibility.
+#
+#
+#  What?:
+#    android-cmake toolchain searches for NDK/toolchain in the following order:
+#      ANDROID_NDK - cmake parameter
+#      ANDROID_NDK - environment variable
+#      ANDROID_STANDALONE_TOOLCHAIN - cmake parameter
+#      ANDROID_STANDALONE_TOOLCHAIN - environment variable
+#      ANDROID_NDK - default locations
+#      ANDROID_STANDALONE_TOOLCHAIN - default locations
+#
+#    Make sure to do the following in your scripts:
+#      SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" )
+#      SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" )
+#      The flags will be prepopulated with critical flags, so don't loose them.
+#      Also be aware that toolchain also sets configuration-specific compiler
+#      flags and linker flags.
+#
+#    ANDROID and BUILD_ANDROID will be set to true, you may test any of these
+#    variables to make necessary Android-specific configuration changes.
+#
+#    Also ARMEABI or ARMEABI_V7A or X86 will be set true, mutually exclusive.
+#    NEON option will be set true if VFP is set to NEON.
+#
+#    LIBRARY_OUTPUT_PATH_ROOT should be set in cache to determine where Android
+#    libraries will be installed.
+#    Default is ${CMAKE_SOURCE_DIR}, and the android libs will always be
+#    under the ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}
+#    (depending on the target ABI). This is convenient for Android packaging.
+#
+#  Authors:
+#    Ethan Rublee ethan.ruble at gmail.com
+#    Andrey Kamaev andrey.kamaev at itseez.com
+#
+#  Change Log:
+#   - initial version December 2010
+#   - modified April 2011
+#     [+] added possibility to build with NDK (without standalone toolchain)
+#     [+] support cross-compilation on Windows (native, no cygwin support)
+#     [+] added compiler option to force "char" type to be signed
+#     [+] added toolchain option to compile to 32-bit ARM instructions
+#     [+] added toolchain option to disable SWIG search
+#     [+] added platform "armeabi-v7a with VFPV3"
+#     [~] ARM_TARGETS renamed to ARM_TARGET
+#     [+] EXECUTABLE_OUTPUT_PATH is set by toolchain (required on Windows)
+#     [~] Fixed bug with ANDROID_API_LEVEL variable
+#     [~] turn off SWIG search if it is not found first time
+#   - modified May 2011
+#     [~] ANDROID_LEVEL is renamed to ANDROID_API_LEVEL
+#     [+] ANDROID_API_LEVEL is detected by toolchain if not specified
+#     [~] added guard to prevent changing of output directories on the first
+#         cmake pass
+#     [~] toolchain exits with error if ARM_TARGET is not recognized
+#   - modified June 2011
+#     [~] default NDK path is updated for version r5c
+#     [+] variable CMAKE_SYSTEM_PROCESSOR is set based on ARM_TARGET
+#     [~] toolchain install directory is added to linker paths
+#     [-] removed SWIG-related stuff from toolchain
+#     [+] added macro find_host_package, find_host_program to search
+#         packages/programs on the host system
+#     [~] fixed path to STL library
+#   - modified July 2011
+#     [~] fixed options caching
+#     [~] search for all supported NDK versions
+#     [~] allowed spaces in NDK path
+#   - modified September 2011
+#     [~] updated for NDK r6b
+#   - modified November 2011
+#     [*] rewritten for NDK r7
+#     [+] x86 toolchain support (experimental)
+#     [+] added "armeabi-v6 with VFP" ABI for ARMv6 processors.
+#     [~] improved compiler and linker flags management
+#     [+] support different build flags for Release and Debug configurations
+#     [~] by default compiler flags the same as used by ndk-build (but only
+#         where reasonable)
+#     [~] ANDROID_NDK_TOOLCHAIN_ROOT is splitted to ANDROID_STANDALONE_TOOLCHAIN
+#         and ANDROID_TOOLCHAIN_ROOT
+#     [~] ARM_TARGET is renamed to ANDROID_ABI
+#     [~] ARMEABI_NDK_NAME is renamed to ANDROID_NDK_ABI_NAME
+#     [~] ANDROID_API_LEVEL is renamed to ANDROID_NATIVE_API_LEVEL
+#   - modified January 2012
+#     [+] added stlport_static support (experimental)
+#     [+] added special check for cygwin
+#     [+] filtered out hidden files (starting with .) while globbing inside NDK
+#     [+] automatically applied GLESv2 linkage fix for NDK revisions 5-6
+#     [+] added ANDROID_GET_ABI_RAWNAME to get NDK ABI names by CMake flags
+#   - modified February 2012
+#     [+] updated for NDK r7b
+#     [~] fixed cmake try_compile() command
+#     [~] Fix for missing install_name_tool on OS X
+#   - modified March 2012
+#     [~] fixed incorrect C compiler flags
+#     [~] fixed CMAKE_SYSTEM_PROCESSOR change on ANDROID_ABI change
+#     [+] improved toolchain loading speed
+#     [+] added assembler language support (.S)
+#     [+] allowed preset search paths and extra search suffixes
+#   - modified April 2012
+#     [+] updated for NDK r7c
+#     [~] fixed most of problems with compiler/linker flags and caching
+#     [+] added option ANDROID_FUNCTION_LEVEL_LINKING
+#   - modified May 2012
+#     [+] updated for NDK r8
+#     [+] added mips architecture support
+#   - modified August 2012
+#     [+] updated for NDK r8b
+#     [~] all intermediate files generated by toolchain are moved into CMakeFiles
+#     [~] libstdc++ and libsupc are removed from explicit link libraries
+# ------------------------------------------------------------------------------
+
+cmake_minimum_required( VERSION 2.6.3 )
+
+if( DEFINED CMAKE_CROSSCOMPILING )
+ # subsequent toolchain loading is not really needed
+ return()
+endif()
+
+get_property(_CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
+if( _CMAKE_IN_TRY_COMPILE )
+ include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL )
+endif()
+
+# this one is important
+set( CMAKE_SYSTEM_NAME Linux )
+# this one not so much
+set( CMAKE_SYSTEM_VERSION 1 )
+
+set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" )
+if(NOT DEFINED ANDROID_NDK_SEARCH_PATHS)
+ if( CMAKE_HOST_WIN32 )
+  file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS )
+  set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}/android-ndk" "$ENV{SystemDrive}/NVPACK/android-ndk" )
+ else()
+  file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS )
+  set( ANDROID_NDK_SEARCH_PATHS /opt/android-ndk "${ANDROID_NDK_SEARCH_PATHS}/NVPACK/android-ndk" )
+ endif()
+endif()
+if(NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH)
+ set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain )
+endif()
+
+set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" )
+set( ANDROID_SUPPORTED_ABIS_x86 "x86" )
+set( ANDROID_SUPPORTED_ABIS_mipsel "mips" )
+
+set( ANDROID_DEFAULT_NDK_API_LEVEL 8 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 )
+
+
+macro( __LIST_FILTER listvar regex )
+ if( ${listvar} )
+  foreach( __val ${${listvar}} )
+   if( __val MATCHES "${regex}" )
+    list( REMOVE_ITEM ${listvar} "${__val}" )
+   endif()
+  endforeach()
+ endif()
+endmacro()
+
+macro( __INIT_VARIABLE var_name )
+ set( __test_path 0 )
+ foreach( __var ${ARGN} )
+  if( __var STREQUAL "PATH" )
+   set( __test_path 1 )
+   break()
+  endif()
+ endforeach()
+ if( __test_path AND NOT EXISTS "${${var_name}}" )
+  unset( ${var_name} CACHE )
+ endif()
+ if( "${${var_name}}" STREQUAL "" )
+  set( __values 0 )
+  foreach( __var ${ARGN} )
+   if( __var STREQUAL "VALUES" )
+    set( __values 1 )
+   elseif( NOT __var STREQUAL "PATH" )
+    set( __obsolete 0 )
+    if( __var MATCHES "^OBSOLETE_.*$" )
+     string( REPLACE "OBSOLETE_" "" __var "${__var}" )
+     set( __obsolete 1 )
+    endif()
+    if( __var MATCHES "^ENV_.*$" )
+     string( REPLACE "ENV_" "" __var "${__var}" )
+     set( __value "$ENV{${__var}}" )
+    elseif( DEFINED ${__var} )
+     set( __value "${${__var}}" )
+    else()
+     if( __values )
+      set( __value "${__var}" )
+     else()
+      set( __value "" )
+     endif()
+    endif()
+    if( NOT "${__value}" STREQUAL "" )
+     if( __test_path )
+      if( EXISTS "${__value}" )
+       set( ${var_name} "${__value}" )
+       if( __obsolete )
+        message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." )
+       endif()
+       break()
+      endif()
+     else()
+      set( ${var_name} "${__value}" )
+       if( __obsolete )
+        message( WARNING "Using value of obsolete variable ${__var} as initial value for ${var_name}. Please note, that ${__var} can be completely removed in future versions of the toolchain." )
+       endif()
+      break()
+     endif()
+    endif()
+   endif()
+  endforeach()
+  unset( __value )
+  unset( __values )
+  unset( __obsolete )
+ endif()
+ unset( __test_path )
+endmacro()
+
+macro( __DETECT_NATIVE_API_LEVEL _var _path )
+ SET( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*$" )
+ FILE( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" )
+ if( NOT __apiFileContent )
+  message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." )
+ endif()
+ string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" )
+ unset( __apiFileContent )
+ unset( __ndkApiLevelRegex )
+endmacro()
+
+macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root )
+ file( GLOB __gccExePath "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" )
+ __LIST_FILTER( __gccExePath "bin/[.].*-gcc${TOOL_OS_SUFFIX}$" )
+ list( LENGTH __gccExePath __gccExePathsCount )
+ if( NOT __gccExePathsCount EQUAL 1 )
+  message( WARNING "Could not uniquely determine machine name for compiler from ${_root}." )
+  set( ${_var} "" )
+ else()
+  get_filename_component( __gccExeName "${__gccExePath}" NAME_WE )
+  string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" )
+ endif()
+ unset( __gccExePath )
+ unset( __gccExePathsCount )
+ unset( __gccExeName )
+endmacro()
+
+macro( __COPY_IF_DIFFERENT _source _destination )
+ execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${_source}" "${_destination}" RESULT_VARIABLE __fileCopyProcess )
+ if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${_destination}")
+  message( SEND_ERROR "Failed copying of ${_source} to the ${_destination}" )
+ endif()
+ unset( __fileCopyProcess )
+endmacro()
+
+
+# stl version: by default gnustl_static will be used
+set( ANDROID_USE_STLPORT FALSE CACHE BOOL "Experimental: use stlport_static instead of gnustl_static")
+mark_as_advanced( ANDROID_USE_STLPORT )
+
+# fight against cygwin
+set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools")
+mark_as_advanced( ANDROID_FORBID_SYGWIN )
+if( ANDROID_FORBID_SYGWIN )
+ if( CYGWIN )
+  message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." )
+ endif()
+
+ if( CMAKE_HOST_WIN32 )
+  # remove cygwin from PATH
+  set( __new_path "$ENV{PATH}")
+  __LIST_FILTER( __new_path "cygwin" )
+  set(ENV{PATH} "${__new_path}")
+  unset(__new_path)
+ endif()
+endif()
+
+# detect current host platform
+set( TOOL_OS_SUFFIX "" )
+if( CMAKE_HOST_APPLE )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86" )
+elseif( CMAKE_HOST_WIN32 )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME "windows" )
+ set( TOOL_OS_SUFFIX ".exe" )
+elseif( CMAKE_HOST_UNIX )
+ set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86" )
+else()
+ message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" )
+endif()
+
+# see if we have path to Android NDK
+__INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK )
+if( NOT ANDROID_NDK )
+ # see if we have path to Android standalone toolchain
+ __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN OBSOLETE_ANDROID_NDK_TOOLCHAIN_ROOT OBSOLETE_ENV_ANDROID_NDK_TOOLCHAIN_ROOT )
+
+ if( NOT ANDROID_STANDALONE_TOOLCHAIN )
+  #try to find Android NDK in one of the the default locations
+  set( __ndkSearchPaths )
+  foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} )
+   foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} )
+    list( APPEND __ndkSearchPaths "${__ndkSearchPath}${suffix}" )
+   endforeach()
+  endforeach()
+  __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} )
+  unset( __ndkSearchPaths )
+
+  if( ANDROID_NDK )
+   message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" )
+   message( STATUS "  If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" )
+  else()
+   #try to find Android standalone toolchain in one of the the default locations
+   __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH )
+
+   if( ANDROID_STANDALONE_TOOLCHAIN )
+    message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" )
+    message( STATUS "  If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" )
+   endif( ANDROID_STANDALONE_TOOLCHAIN )
+  endif( ANDROID_NDK )
+ endif( NOT ANDROID_STANDALONE_TOOLCHAIN )
+endif( NOT ANDROID_NDK )
+
+# remember found paths
+if( ANDROID_NDK )
+ get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE )
+ # try to detect change
+ if( CMAKE_AR )
+  string( LENGTH "${ANDROID_NDK}" __length )
+  string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath )
+  if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK )
+   message( FATAL_ERROR "It is not possible to change path to the NDK on subsequent run." )
+  endif()
+  unset( __androidNdkPreviousPath )
+  unset( __length )
+ endif()
+ set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" )
+ set( BUILD_WITH_ANDROID_NDK True )
+elseif( ANDROID_STANDALONE_TOOLCHAIN )
+ get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE )
+ # try to detect change
+ if( CMAKE_AR )
+  string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length )
+  string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath )
+  if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN )
+   message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." )
+  endif()
+  unset( __androidStandaloneToolchainPreviousPath )
+  unset( __length )
+ endif()
+ set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" )
+ set( BUILD_WITH_STANDALONE_TOOLCHAIN True )
+else()
+ list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH)
+ message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolcahin.
+    You should either set an environment variable:
+      export ANDROID_NDK=~/my-android-ndk
+    or
+      export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain
+    or put the toolchain or NDK in the default path:
+      sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}
+      sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" )
+endif()
+
+# get all the details about standalone toolchain
+if( BUILD_WITH_STANDALONE_TOOLCHAIN )
+ __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" )
+ set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
+ set( __availableToolchains "standalone" )
+ __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" )
+ if( NOT __availableToolchainMachines )
+  message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." )
+ endif()
+ if( __availableToolchainMachines MATCHES i686 )
+  set( __availableToolchainArchs "x86" )
+ elseif( __availableToolchainMachines MATCHES arm )
+  set( __availableToolchainArchs "arm" )
+ elseif( __availableToolchainMachines MATCHES mipsel )
+  set( __availableToolchainArchs "mipsel" )
+ endif()
+ if( ANDROID_COMPILER_VERSION )
+  # do not run gcc every time because it is relatevely expencive
+  set( __availableToolchainCompilerVersions "${ANDROID_COMPILER_VERSION}" )
+ else()
+  execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" --version
+   OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE )
+  string( REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" )
+ endif()
+endif()
+
+# get all the details about NDK
+if( BUILD_WITH_ANDROID_NDK )
+ file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" )
+ string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" )
+ file( GLOB __availableToolchains RELATIVE "${ANDROID_NDK}/toolchains" "${ANDROID_NDK}/toolchains/*" )
+ __LIST_FILTER( __availableToolchains "^[.]" )
+ set( __availableToolchainMachines "" )
+ set( __availableToolchainArchs "" )
+ set( __availableToolchainCompilerVersions "" )
+ foreach( __toolchain ${__availableToolchains} )
+  __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK}/toolchains/${__toolchain}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" )
+  if( __machine )
+   string( REGEX MATCH "[0-9]+[.][0-9]+[.]*[0-9]*$" __version "${__toolchain}" )
+   string( REGEX MATCH "^[^-]+" __arch "${__toolchain}" )
+   list( APPEND __availableToolchainMachines "${__machine}" )
+   list( APPEND __availableToolchainArchs "${__arch}" )
+   list( APPEND __availableToolchainCompilerVersions "${__version}" )
+  else()
+   list( REMOVE_ITEM __availableToolchains "${__toolchain}" )
+  endif()
+ endforeach()
+ if( NOT __availableToolchains )
+  message( FATAL_ERROR "Could not any working toolchain in the NDK. Probably your Android NDK is broken." )
+ endif()
+endif()
+
+# build list of available ABIs
+if( NOT ANDROID_SUPPORTED_ABIS )
+ set( ANDROID_SUPPORTED_ABIS "" )
+ set( __uniqToolchainArchNames ${__availableToolchainArchs} )
+ list( REMOVE_DUPLICATES __uniqToolchainArchNames )
+ list( SORT __uniqToolchainArchNames )
+ foreach( __arch ${__uniqToolchainArchNames} )
+  list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} )
+ endforeach()
+ unset( __uniqToolchainArchNames )
+ if( NOT ANDROID_SUPPORTED_ABIS )
+  message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." )
+ endif()
+endif()
+
+# choose target ABI
+__INIT_VARIABLE( ANDROID_ABI OBSOLETE_ARM_TARGET OBSOLETE_ARM_TARGETS VALUES ${ANDROID_SUPPORTED_ABIS} )
+# verify that target ABI is supported
+list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx )
+if( __androidAbiIdx EQUAL -1 )
+ string( REPLACE ";" "\", \"" , PRINTABLE_ANDROID_SUPPORTED_ABIS  "${ANDROID_SUPPORTED_ABIS}" )
+ message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain.
+   Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\"
+   " )
+endif()
+unset( __androidAbiIdx )
+
+# remember target ABI
+set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE )
+
+# set target ABI options
+if( ANDROID_ABI STREQUAL "x86" )
+ set( X86 true )
+ set( ANDROID_NDK_ABI_NAME "x86" )
+ set( ANDROID_ARCH_NAME "x86" )
+ set( ANDROID_ARCH_FULLNAME "x86" )
+ set( CMAKE_SYSTEM_PROCESSOR "i686" )
+elseif( ANDROID_ABI STREQUAL "mips" )
+ set( MIPS true )
+ set( ANDROID_NDK_ABI_NAME "mips" )
+ set( ANDROID_ARCH_NAME "mips" )
+ set( ANDROID_ARCH_FULLNAME "mipsel" )
+ set( CMAKE_SYSTEM_PROCESSOR "mips" )
+elseif( ANDROID_ABI STREQUAL "armeabi" )
+ set( ARMEABI true )
+ set( ANDROID_NDK_ABI_NAME "armeabi" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_ARCH_FULLNAME "arm" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv5te" )
+elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" )
+ set( ARMEABI_V6 true )
+ set( ANDROID_NDK_ABI_NAME "armeabi" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_ARCH_FULLNAME "arm" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv6" )
+ # need always fallback to older platform
+ set( ARMEABI true )
+elseif( ANDROID_ABI STREQUAL "armeabi-v7a")
+ set( ARMEABI_V7A true )
+ set( ANDROID_NDK_ABI_NAME "armeabi-v7a" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_ARCH_FULLNAME "arm" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv7-a" )
+elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" )
+ set( ARMEABI_V7A true )
+ set( ANDROID_NDK_ABI_NAME "armeabi-v7a" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_ARCH_FULLNAME "arm" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv7-a" )
+ set( VFPV3 true )
+elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" )
+ set( ARMEABI_V7A true )
+ set( ANDROID_NDK_ABI_NAME "armeabi-v7a" )
+ set( ANDROID_ARCH_NAME "arm" )
+ set( ANDROID_ARCH_FULLNAME "arm" )
+ set( CMAKE_SYSTEM_PROCESSOR "armv7-a" )
+ set( VFPV3 true )
+ set( NEON true )
+else()
+ message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." )
+endif()
+
+if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" )
+ # really dirty hack
+ # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run...
+ file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" )
+endif()
+
+set( ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_FULLNAME}} CACHE INTERNAL "ANDROID_ABI can be changed only to one of these ABIs. Changing to any other ABI requires to reset cmake cache." )
+if( CMAKE_VERSION VERSION_GREATER "2.8" )
+ list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_FULLNAME} )
+ set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_FULLNAME}} )
+endif()
+
+if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 )
+ __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD OBSOLETE_FORCE_ARM VALUES OFF )
+ set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE )
+ mark_as_advanced( ANDROID_FORCE_ARM_BUILD )
+else()
+ unset( ANDROID_FORCE_ARM_BUILD CACHE )
+endif()
+
+# choose toolchain
+if( ANDROID_TOOLCHAIN_NAME )
+ list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx )
+ if( __toolchainIdx EQUAL -1 )
+  message( FATAL_ERROR "Previously selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing. You need to remove CMakeCache.txt and rerun cmake manually to change the toolchain" )
+ endif()
+ list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch )
+ if( NOT __toolchainArch STREQUAL ANDROID_ARCH_FULLNAME )
+  message( SEND_ERROR "Previously selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." )
+ endif()
+else()
+ set( __toolchainIdx -1 )
+ set( __applicableToolchains "" )
+ set( __toolchainMaxVersion "0.0.0" )
+ list( LENGTH __availableToolchains __availableToolchainsCount )
+ math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" )
+ foreach( __idx RANGE ${__availableToolchainsCount} )
+  list( GET __availableToolchainArchs ${__idx} __toolchainArch )
+  if( __toolchainArch STREQUAL ANDROID_ARCH_FULLNAME )
+   list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion )
+   if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion )
+    set( __toolchainMaxVersion "${__toolchainVersion}" )
+    set( __toolchainIdx ${__idx} )
+   endif()
+  endif()
+ endforeach()
+ unset( __availableToolchainsCount )
+ unset( __toolchainMaxVersion )
+ unset( __toolchainVersion )
+endif()
+unset( __toolchainArch )
+if( __toolchainIdx EQUAL -1 )
+ message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." )
+endif()
+list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME )
+list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME )
+list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION )
+set( ANDROID_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" CACHE INTERNAL "Name of toolchain used" )
+set( ANDROID_COMPILER_VERSION "${ANDROID_COMPILER_VERSION}" CACHE INTERNAL "compiler version from selected toolchain" )
+unset( __toolchainIdx )
+unset( __availableToolchains )
+unset( __availableToolchainMachines )
+unset( __availableToolchainArchs )
+unset( __availableToolchainCompilerVersions )
+
+# choose native API level
+__INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL )
+string( REGEX MATCH "[0-9]+" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" )
+# validate
+list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx )
+if( __levelIdx EQUAL -1 )
+ message( SEND_ERROR "Specified Android native API level (${ANDROID_NATIVE_API_LEVEL}) is not supported by your NDK/toolchain." )
+endif()
+unset( __levelIdx )
+if( BUILD_WITH_ANDROID_NDK )
+ __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" )
+ if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL )
+  message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." )
+ endif()
+ unset( __realApiLevel )
+endif()
+set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE )
+if( CMAKE_VERSION VERSION_GREATER "2.8" )
+ list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS )
+ set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} )
+endif()
+
+# setup paths
+if( BUILD_WITH_STANDALONE_TOOLCHAIN )
+ set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" )
+ set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" )
+ set( __stlLibPath "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" )
+endif()
+if( BUILD_WITH_ANDROID_NDK )
+ set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK}/toolchains/${ANDROID_TOOLCHAIN_NAME}/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" )
+ set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" )
+ if( ANDROID_USE_STLPORT )
+  set( __stlIncludePath "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" )
+  set( __stlLibPath "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}" )
+ else()
+  if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" )
+   set( __stlIncludePath "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/include" )
+   set( __stlLibPath "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}" )
+  else()
+   set( __stlIncludePath "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/include" )
+   set( __stlLibPath "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}" )
+  endif()
+ endif()
+endif()
+
+# specify the cross compiler
+set( CMAKE_C_COMPILER   "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}"     CACHE PATH "gcc" )
+set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}"     CACHE PATH "g++" )
+set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}"     CACHE PATH "Assembler" )
+if( CMAKE_VERSION VERSION_LESS 2.8.5 )
+ set( CMAKE_ASM_COMPILER_ARG1 "-c" )
+endif()
+# there may be a way to make cmake deduce these TODO deduce the rest of the tools
+set( CMAKE_STRIP        "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}"   CACHE PATH "strip" )
+set( CMAKE_AR           "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}"      CACHE PATH "archive" )
+set( CMAKE_LINKER       "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}"      CACHE PATH "linker" )
+set( CMAKE_NM           "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}"      CACHE PATH "nm" )
+set( CMAKE_OBJCOPY      "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" )
+set( CMAKE_OBJDUMP      "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" )
+set( CMAKE_RANLIB       "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}"  CACHE PATH "ranlib" )
+set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" )
+if( APPLE )
+ find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool )
+ if( NOT CMAKE_INSTALL_NAME_TOOL )
+  message( FATAL_ERROR "Could not find install_name_tool, please check your installation." )
+ endif()
+ mark_as_advanced( CMAKE_INSTALL_NAME_TOOL )
+endif()
+
+# export directories
+set( ANDROID_SYSTEM_INCLUDE_DIRS "" )
+set( ANDROID_SYSTEM_LIB_DIRS "" )
+
+# setup output directories
+set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "root for library output, set this to change where android libs are installed to" )
+set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" )
+
+if(NOT _CMAKE_IN_TRY_COMPILE)
+ if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" )
+  set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" )
+ else()
+  set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" )
+ endif()
+ set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "path for android libs" )
+endif()
+
+# includes
+list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${ANDROID_SYSROOT}/usr/include" )
+if( __stlIncludePath AND EXISTS "${__stlIncludePath}" )
+ list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${__stlIncludePath}" )
+endif()
+
+# c++ bits includes
+if( __stlLibPath AND EXISTS "${__stlLibPath}/include" )
+ list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${__stlLibPath}/include" )
+endif()
+if( ANDROID_ARCH_NAME STREQUAL "arm" AND EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/thumb/bits" )
+ list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/thumb" )
+elseif( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" )
+ list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" )
+elseif( ANDROID_ARCH_NAME STREQUAL "arm" AND EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" )
+ list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" )
+elseif( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/bits" )
+ list( APPEND ANDROID_SYSTEM_INCLUDE_DIRS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" )
+endif()
+
+# flags and definitions
+if(ANDROID_SYSROOT MATCHES "[ ;\"]")
+ set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" )
+ # quotes will break try_compile and compiler identification
+ message(WARNING "Your Android system root has non-alphanumeric symbols. It can break compiler features detection and the whole build.")
+else()
+ set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" )
+endif()
+
+remove_definitions( -DANDROID )
+add_definitions( -DANDROID )
+
+# Force set compilers because standard identification works badly for us
+include( CMakeForceCompiler )
+CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU )
+set( CMAKE_C_PLATFORM_ID Linux )
+set( CMAKE_C_SIZEOF_DATA_PTR 4 )
+set( CMAKE_C_HAS_ISYSROOT 1 )
+set( CMAKE_C_COMPILER_ABI ELF )
+CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU )
+set( CMAKE_CXX_PLATFORM_ID Linux )
+set( CMAKE_CXX_SIZEOF_DATA_PTR 4 )
+set( CMAKE_CXX_HAS_ISYSROOT 1 )
+set( CMAKE_CXX_COMPILER_ABI ELF )
+# force ASM compiler (required for CMake < 2.8.5)
+set( CMAKE_ASM_COMPILER_ID_RUN TRUE )
+set( CMAKE_ASM_COMPILER_ID GNU )
+set( CMAKE_ASM_COMPILER_WORKS TRUE )
+set( CMAKE_ASM_COMPILER_FORCED TRUE )
+set( CMAKE_COMPILER_IS_GNUASM 1)
+
+# NDK flags
+if( ARMEABI OR ARMEABI_V7A )
+ # NDK also defines -ffunction-sections -funwind-tables but they result in worse OpenCV performance
+ set( _CMAKE_CXX_FLAGS "-fPIC -Wno-psabi" )
+ set( _CMAKE_C_FLAGS "-fPIC -Wno-psabi" )
+ remove_definitions( -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ )
+ add_definitions( -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ )
+ # extra arm-specific flags
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" )
+elseif( X86 )
+ set( _CMAKE_CXX_FLAGS "-funwind-tables" )
+ set( _CMAKE_C_FLAGS "-funwind-tables" )
+elseif( MIPS )
+ set( _CMAKE_CXX_FLAGS "-fpic -Wno-psabi -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0 -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" )
+ set( _CMAKE_CXX_FLAGS "-fpic -Wno-psabi -fno-strict-aliasing -finline-functions -ffunction-sections -funwind-tables -fmessage-length=0 -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" )
+else()
+ set( _CMAKE_CXX_FLAGS "" )
+ set( _CMAKE_C_FLAGS "" )
+endif()
+
+if( ANDROID_USE_STLPORT )
+ set( _CMAKE_CXX_FLAGS "${_CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions" )
+ set( _CMAKE_C_FLAGS "${_CMAKE_C_FLAGS} -fno-exceptions" )
+else()
+ set( _CMAKE_CXX_FLAGS "${_CMAKE_CXX_FLAGS} -frtti -fexceptions" )
+ set( _CMAKE_C_FLAGS "${_CMAKE_C_FLAGS} -fexceptions" )
+endif()
+
+# release and debug flags
+if( ARMEABI OR ARMEABI_V7A )
+ if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 )
+  # It is recommended to use the -mthumb compiler flag to force the generation
+  # of 16-bit Thumb-1 instructions (the default being 32-bit ARM ones).
+  # O3 instead of O2/Os in release mode - like cmake sets for desktop gcc
+  set( _CMAKE_CXX_FLAGS_RELEASE "-mthumb -O3" )
+  set( _CMAKE_C_FLAGS_RELEASE   "-mthumb -O3" )
+  set( _CMAKE_CXX_FLAGS_DEBUG "-marm -Os -finline-limit=64" )
+  set( _CMAKE_C_FLAGS_DEBUG   "-marm -Os -finline-limit=64" )
+ else()
+  # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI
+  # O3 instead of O2/Os in release mode - like cmake sets for desktop gcc
+  set( _CMAKE_CXX_FLAGS_RELEASE "-marm -O3 -fstrict-aliasing" )
+  set( _CMAKE_C_FLAGS_RELEASE   "-marm -O3 -fstrict-aliasing" )
+  set( _CMAKE_CXX_FLAGS_DEBUG "-marm -O0 -finline-limit=300" )
+  set( _CMAKE_C_FLAGS_DEBUG   "-marm -O0 -finline-limit=300" )
+ endif()
+elseif( X86 )
+ set( _CMAKE_CXX_FLAGS_RELEASE "-O3 -fstrict-aliasing" )
+ set( _CMAKE_C_FLAGS_RELEASE   "-O3 -fstrict-aliasing" )
+ set( _CMAKE_CXX_FLAGS_DEBUG "-O0 -finline-limit=300" )
+ set( _CMAKE_C_FLAGS_DEBUG   "-O0 -finline-limit=300" )
+elseif( MIPS )
+ set( _CMAKE_CXX_FLAGS_RELEASE "-O3 -funswitch-loops -finline-limit=300" )
+ set( _CMAKE_C_FLAGS_RELEASE   "-O3 -funswitch-loops -finline-limit=300" )
+ set( _CMAKE_CXX_FLAGS_DEBUG "-O0 -g" )
+ set( _CMAKE_C_FLAGS_DEBUG   "-O0 -g" )
+endif()
+set( _CMAKE_CXX_FLAGS_RELEASE "${_CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer -DNDEBUG" )
+set( _CMAKE_C_FLAGS_RELEASE   "${_CMAKE_C_FLAGS_RELEASE}   -fomit-frame-pointer -DNDEBUG" )
+set( _CMAKE_CXX_FLAGS_DEBUG "${_CMAKE_CXX_FLAGS_DEBUG} -fno-strict-aliasing -fno-omit-frame-pointer -DDEBUG -D_DEBUG" )
+set( _CMAKE_C_FLAGS_DEBUG   "${_CMAKE_C_FLAGS_DEBUG}   -fno-strict-aliasing -fno-omit-frame-pointer -DDEBUG -D_DEBUG" )
+
+# ABI-specific flags
+if( ARMEABI_V7A )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" )
+ if( NEON )
+  set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" )
+ elseif( VFPV3 )
+  set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" )
+ else()
+  set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfp" )
+ endif()
+elseif( ARMEABI_V6 )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" )
+elseif( ARMEABI )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" )
+elseif( X86 )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" )#sse?
+endif()
+
+# linker flags
+if( NOT DEFINED __ndklibspath )
+ set( __ndklibspath "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/ndklibs/${ANDROID_NDK_ABI_NAME}" )
+endif()
+list( APPEND ANDROID_SYSTEM_LIB_DIRS "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" )
+set( ANDROID_LINKER_FLAGS "" )
+
+# STL
+if( ANDROID_USE_STLPORT )
+ if( EXISTS "${__stlLibPath}/libstlport_static.a" )
+  set( CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES> \"${__stlLibPath}/libstlport_static.a\"")
+  set( CMAKE_CXX_CREATE_SHARED_MODULE  "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES> \"${__stlLibPath}/libstlport_static.a\"")
+ endif()
+else( ANDROID_USE_STLPORT )
+ if( EXISTS "${__stlLibPath}/libgnustl_static.a" )
+  __COPY_IF_DIFFERENT( "${__stlLibPath}/libgnustl_static.a" "${__ndklibspath}/libstdc++.a" )
+ elseif( ANDROID_ARCH_NAME STREQUAL "arm" AND EXISTS "${__stlLibPath}/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" )
+  __COPY_IF_DIFFERENT( "${__stlLibPath}/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" "${__ndklibspath}/libstdc++.a" )
+ elseif( ANDROID_ARCH_NAME STREQUAL "arm" AND EXISTS "${__stlLibPath}/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" )
+  __COPY_IF_DIFFERENT( "${__stlLibPath}/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" "${__ndklibspath}/libstdc++.a" )
+ elseif( ANDROID_ARCH_NAME STREQUAL "arm" AND EXISTS "${__stlLibPath}/thumb/libstdc++.a" )
+  __COPY_IF_DIFFERENT( "${__stlLibPath}/thumb/libstdc++.a" "${__ndklibspath}/libstdc++.a" )
+ elseif( EXISTS "${__stlLibPath}/libstdc++.a" )
+  __COPY_IF_DIFFERENT( "${__stlLibPath}/libstdc++.a" "${__ndklibspath}/libstdc++.a" )
+ endif()
+ if( EXISTS "${__stlLibPath}/libsupc++.a" )
+  __COPY_IF_DIFFERENT( "${__stlLibPath}/libsupc++.a" "${__ndklibspath}/libsupc++.a" )
+ elseif( ANDROID_ARCH_NAME STREQUAL "arm" AND EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" )
+  __COPY_IF_DIFFERENT( "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" "${__ndklibspath}/libsupc++.a" )
+ elseif( ANDROID_ARCH_NAME STREQUAL "arm" AND EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" )
+  __COPY_IF_DIFFERENT( "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" "${__ndklibspath}/libsupc++.a" )
+ elseif( ANDROID_ARCH_NAME STREQUAL "arm" AND EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" )
+  __COPY_IF_DIFFERENT( "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" "${__ndklibspath}/libsupc++.a" )
+ elseif( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" )
+  __COPY_IF_DIFFERENT( "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" "${__ndklibspath}/libsupc++.a" )
+ endif()
+ list( APPEND ANDROID_SYSTEM_LIB_DIRS "${__ndklibspath}" )
+endif( ANDROID_USE_STLPORT )
+
+# cleanup for STL search
+unset( __stlIncludePath )
+unset( __stlLibPath )
+
+# other linker flags
+__INIT_VARIABLE( ANDROID_NO_UNDEFINED OBSOLETE_NO_UNDEFINED VALUES ON )
+set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" FORCE )
+mark_as_advanced( ANDROID_NO_UNDEFINED )
+if( ANDROID_NO_UNDEFINED )
+ set( ANDROID_LINKER_FLAGS "-Wl,--no-undefined ${ANDROID_LINKER_FLAGS}" )
+endif()
+
+if (ANDROID_NDK MATCHES "-r[56].?$")
+ # libGLESv2.so in NDK's prior to r7 refers to exteranal symbols. So this flag option is required for all projects using OpenGL from native.
+ __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON )
+else()
+ __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF )
+endif()
+
+set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" FORCE )
+mark_as_advanced( ANDROID_SO_UNDEFINED )
+if( ANDROID_SO_UNDEFINED )
+ set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" )
+endif()
+
+__INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON )
+set( ANDROID_FUNCTION_LEVEL_LINKING ON CACHE BOOL "Allows or disallows undefined symbols in shared libraries" FORCE )
+mark_as_advanced( ANDROID_FUNCTION_LEVEL_LINKING )
+if( ANDROID_FUNCTION_LEVEL_LINKING )
+ set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" )
+ set( ANDROID_LINKER_FLAGS "-Wl,--gc-sections ${ANDROID_LINKER_FLAGS}" )
+endif()
+
+if( ARMEABI_V7A )
+ # this is *required* to use the following linker flags that routes around
+ # a CPU bug in some Cortex-A8 implementations:
+ set( ANDROID_LINKER_FLAGS "-Wl,--fix-cortex-a8 ${ANDROID_LINKER_FLAGS}" )
+endif()
+
+# cache flags
+set( CMAKE_CXX_FLAGS "${_CMAKE_CXX_FLAGS}" CACHE STRING "c++ flags" )
+set( CMAKE_C_FLAGS "${_CMAKE_C_FLAGS}" CACHE STRING "c flags" )
+set( CMAKE_CXX_FLAGS_RELEASE "${_CMAKE_CXX_FLAGS_RELEASE}" CACHE STRING "c++ Release flags" )
+set( CMAKE_C_FLAGS_RELEASE "${_CMAKE_C_FLAGS_RELEASE}" CACHE STRING "c Release flags" )
+set( CMAKE_CXX_FLAGS_DEBUG "${_CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING "c++ Debug flags" )
+set( CMAKE_C_FLAGS_DEBUG "${_CMAKE_C_FLAGS_DEBUG}" CACHE STRING "c Debug flags" )
+set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "linker flags" )
+set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "linker flags" )
+set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "linker flags" )
+
+include_directories( SYSTEM ${ANDROID_SYSTEM_INCLUDE_DIRS} )
+link_directories( ${ANDROID_SYSTEM_LIB_DIRS} )
+
+# finish flags
+set( ANDROID_CXX_FLAGS    "${ANDROID_CXX_FLAGS}"    CACHE INTERNAL "Extra Android compiler flags")
+set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Extra Android linker flags")
+set( CMAKE_CXX_FLAGS           "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" )
+set( CMAKE_C_FLAGS             "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" )
+if( MIPS AND BUILD_WITH_ANDROID_NDK )
+ set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK}/toolchains/${ANDROID_TOOLCHAIN_NAME}/mipself.xsc ${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" )
+ set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK}/toolchains/${ANDROID_TOOLCHAIN_NAME}/mipself.xsc ${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" )
+ set( CMAKE_EXE_LINKER_FLAGS    "-Wl,-T,${ANDROID_NDK}/toolchains/${ANDROID_TOOLCHAIN_NAME}/mipself.x ${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" )
+else()
+ set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" )
+ set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" )
+ set( CMAKE_EXE_LINKER_FLAGS    "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" )
+endif()
+
+# set these global flags for cmake client scripts to change behavior
+set( ANDROID True )
+set( BUILD_ANDROID True )
+
+# where is the target environment
+set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" )
+
+# only search for libraries and includes in the ndk toolchain
+set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
+set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
+set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
+
+
+# macro to find packages on the host OS
+macro( find_host_package )
+ set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
+ set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER )
+ set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER )
+ if( CMAKE_HOST_WIN32 )
+  SET( WIN32 1 )
+  SET( UNIX )
+ elseif( CMAKE_HOST_APPLE )
+  SET( APPLE 1 )
+  SET( UNIX )
+ endif()
+ find_package( ${ARGN} )
+ SET( WIN32 )
+ SET( APPLE )
+ SET( UNIX 1 )
+ set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
+ set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
+ set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
+endmacro()
+
+
+# macro to find programs on the host OS
+macro( find_host_program )
+ set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
+ set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER )
+ set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER )
+ if( CMAKE_HOST_WIN32 )
+  SET( WIN32 1 )
+  SET( UNIX )
+ elseif( CMAKE_HOST_APPLE )
+  SET( APPLE 1 )
+  SET( UNIX )
+ endif()
+ find_program( ${ARGN} )
+ SET( WIN32 )
+ SET( APPLE )
+ SET( UNIX 1 )
+ set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
+ set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
+ set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
+endmacro()
+
+
+macro( ANDROID_GET_ABI_RAWNAME TOOLCHAIN_FLAG VAR )
+ if( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI" )
+  set( ${VAR} "armeabi" )
+ elseif( "${TOOLCHAIN_FLAG}" STREQUAL "ARMEABI_V7A" )
+    set( ${VAR} "armeabi-v7a" )
+ elseif( "${TOOLCHAIN_FLAG}" STREQUAL "X86" )
+    set( ${VAR} "x86" )
+ else()
+    set( ${VAR} "unknown" )
+ endif()
+endmacro()
+
+
+# export toolchain settings for the try_compile() command
+if( NOT PROJECT_NAME STREQUAL "CMAKE_TRY_COMPILE" )
+ set( __toolchain_config "")
+ foreach( __var ANDROID_ABI ANDROID_FORCE_ARM_BUILD ANDROID_NATIVE_API_LEVEL ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_SET_OBSOLETE_VARIABLES LIBRARY_OUTPUT_PATH_ROOT ANDROID_USE_STLPORT ANDROID_FORBID_SYGWIN ANDROID_NDK ANDROID_STANDALONE_TOOLCHAIN ANDROID_FUNCTION_LEVEL_LINKING __ndklibspath )
+  if( DEFINED ${__var} )
+   if( "${__var}" MATCHES " ")
+    set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" )
+   else()
+    set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" )
+   endif()
+  endif()
+ endforeach()
+ file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" )
+ unset( __toolchain_config )
+ unset( __ndklibspath )
+endif()
+
+
+# set some obsolete variables for backward compatibility
+set( ANDROID_SET_OBSOLETE_VARIABLES ON CACHE BOOL "Define obsolete Andrid-specific cmake variables" )
+mark_as_advanced( ANDROID_SET_OBSOLETE_VARIABLES )
+if( ANDROID_SET_OBSOLETE_VARIABLES )
+ set( ANDROID_API_LEVEL ${ANDROID_NATIVE_API_LEVEL} )
+ set( ARM_TARGET "${ANDROID_ABI}" )
+ set( ARMEABI_NDK_NAME "${ANDROID_NDK_ABI_NAME}" )
+endif()
+
+
+# Variables controlling behavior or set by cmake toolchain:
+#   ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips"
+#   ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14 (depends on NDK version)
+#   ANDROID_SET_OBSOLETE_VARIABLES : ON/OFF
+#   ANDROID_USE_STLPORT : OFF/ON - EXPERIMENTAL!!!
+#   ANDROID_FORBID_SYGWIN : ON/OFF
+#   ANDROID_NO_UNDEFINED : ON/OFF
+#   ANDROID_SO_UNDEFINED : OFF/ON  (default depends on NDK version)
+#   ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF
+# Variables that takes effect only at first run:
+#   ANDROID_FORCE_ARM_BUILD : ON/OFF
+#   LIBRARY_OUTPUT_PATH_ROOT : <any valid path>
+# Can be set only at the first run:
+#   ANDROID_NDK
+#   ANDROID_STANDALONE_TOOLCHAIN
+#   ANDROID_TOOLCHAIN_NAME : "arm-linux-androideabi-4.4.3" or "arm-linux-androideabi-4.6" or "mipsel-linux-android-4.4.3" or "mipsel-linux-android-4.6" or "x86-4.4.3" or "x86-4.6"
+# Obsolete:
+#   ANDROID_API_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL
+#   ARM_TARGET : superseded by ANDROID_ABI
+#   ARM_TARGETS : superseded by ANDROID_ABI (can be set only)
+#   ANDROID_NDK_TOOLCHAIN_ROOT : superseded by ANDROID_STANDALONE_TOOLCHAIN (can be set only)
+#   ANDROID_LEVEL : superseded by ANDROID_NATIVE_API_LEVEL (completely removed)
+#
+# Primary read-only variables:
+#   ANDROID : always TRUE
+#   ARMEABI : TRUE for arm v6 and older devices
+#   ARMEABI_V6 : TRUE for arm v6
+#   ARMEABI_V7A : TRUE for arm v7a
+#   NEON : TRUE if NEON unit is enabled
+#   VFPV3 : TRUE if VFP version 3 is enabled
+#   X86 : TRUE if configured for x86
+#   BUILD_ANDROID : always TRUE
+#   BUILD_WITH_ANDROID_NDK : TRUE if NDK is used
+#   BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used
+#   ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform
+#   ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a" or "x86" depending on ANDROID_ABI
+#   ANDROID_ARCH_NAME : "arm" or "x86" or "mips" depending on ANDROID_ABI
+#   TOOL_OS_SUFFIX : "" or ".exe" depending on host platform
+#   ANDROID_SYSROOT : path to the compiler sysroot
+#   ANDROID_SYSTEM_INCLUDE_DIRS
+#   ANDROID_SYSTEM_LIB_DIRS
+# Obsolete:
+#   ARMEABI_NDK_NAME : superseded by ANDROID_NDK_ABI_NAME
+#
+# Secondary (less stable) read-only variables:
+#   ANDROID_COMPILER_VERSION : GCC version used
+#   ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform
+#   ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI
+#   ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux"
+#   ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK)
+#   ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK
+#
+# Defaults:
+#   ANDROID_DEFAULT_NDK_API_LEVEL
+#   ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH}
+#   ANDROID_NDK_SEARCH_PATHS
+#   ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH
+#   ANDROID_SUPPORTED_ABIS_${ARCH}
+#   ANDROID_SUPPORTED_NDK_VERSIONS
diff --git a/contrib/mobile/utils/android_petsc_reconfigure-armv7-android-linux.py b/contrib/mobile/utils/android_petsc_reconfigure-armv7-android-linux.py
new file mode 100755
index 0000000..d920a1b
--- /dev/null
+++ b/contrib/mobile/utils/android_petsc_reconfigure-armv7-android-linux.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python2
+if __name__ == '__main__':
+  import sys
+  import os
+  sys.path.insert(0, os.path.abspath('config'))
+  import configure
+  configure_options = [
+    '--AR=/opt/android-ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-ar',
+    '--CC=/opt/android-ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc',
+    '--CFLAGS=--sysroot=/opt/android-ndk/platforms/android-8/arch-arm',
+    '--CPP=/opt/android-ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-cpp',
+    '--CPPFLAGS=--sysroot=/opt/android-ndk/platforms/android-8/arch-arm',
+    '--CXX=/opt/android-ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-g++',
+    '--CXXFLAGS=--sysroot=/opt/android-ndk/platforms/android-8/arch-arm -fsigned-char -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fdata-sections -ffunction-sections -fPIC -Wno-psabi -frtti -fexceptions -mthumb -O3 -fomit-frame-pointer -DNDEBUG -fPIC -isystem /opt/android-ndk/platforms/android-8/arch-arm/usr/include -isystem /opt/android-ndk/sources/cxx-stl/gnu-libstdc++/4.6/include -isystem /opt/android-ndk/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include -lstdc++',
+    '--LDFLAGS= -L/opt/android-ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/user/libs/armeabi-v7a  -L/home/maxime/Stage/_gmsh/CMakeFiles/ndklibs/armeabi-v7a  -L/home/maxime/Stage/petsc-3.3-p6/armv7-unknown-linux/lib',
+    '--LD_SHARED=/opt/android-ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-ld',
+    '--download-blacs=0',
+    '--download-mumps=0',
+    '--download-parmetis=0',
+    '--download-scalapack=0',
+    '--download-umfpack=0',
+    '--known-bits-per-byte=8',
+    '--known-endian=little',
+    '--known-level1-dcache-assoc=1',
+    '--known-level1-dcache-linesize=16',
+    '--known-level1-dcache-size=4000',
+    '--known-memcmp-ok=1',
+    '--known-sizeof-char=1',
+    '--known-sizeof-double=8',
+    '--known-sizeof-float=4',
+    '--known-sizeof-int=4',
+    '--known-sizeof-long-long=8',
+    '--known-sizeof-long=8',
+    '--known-sizeof-short=2',
+    '--known-sizeof-size_t=8',
+    '--known-sizeof-void-p=8',
+    '--with-blas-lib=/home/maxime/Stage/petsc-3.3-p6/externalpackages/f2cblaslapack-3.1.1.q/libf2cblas.so',
+    '--with-clanguage=cxx',
+    '--with-cmake=1',
+    '--with-debugging=0',
+    '--with-fc=0',
+    '--with-lapack-lib=/home/maxime/Stage/petsc-3.3-p6/externalpackages/f2clapacklapack-3.1.1.q/libf2clapack.so',
+    '--with-mpi=0',
+    '--with-shared-libraries=1',
+    '--with-x=0',
+    '-I/opt/android-ndk/sources/cxx-stl/gnu-libstdc++/include/',
+    '-I/opt/android-ndk/sources/cxx-stl/gnu-libstdc++/include/backward',
+    '-I/opt/android-ndk/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include',
+    '-lstdc++',
+    '-with-batch=1',
+    'PETSC_ARCH=armv7-android-linux',
+  ]
+  configure.petsc_configure(configure_options)
diff --git a/contrib/mobile/utils/ant.properties b/contrib/mobile/utils/ant.properties
new file mode 100644
index 0000000..4a9188d
--- /dev/null
+++ b/contrib/mobile/utils/ant.properties
@@ -0,0 +1,4 @@
+key.store=${user.home}/.geuzaine.keystore
+key.store.password=Gmsh2013
+key.alias=cgeuzaine
+key.alias.password=Gmsh2013
diff --git a/contrib/mobile/utils/iOS.cmake b/contrib/mobile/utils/iOS.cmake
new file mode 100644
index 0000000..5c79dd1
--- /dev/null
+++ b/contrib/mobile/utils/iOS.cmake
@@ -0,0 +1,131 @@
+# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
+# files which are included with CMake 2.8.4
+# It has been altered for iOS development
+
+# Options:
+#
+# IOS_PLATFORM = OS (default) or SIMULATOR
+#   This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
+#   OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
+#   SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.
+#
+# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
+#   By default this location is automatcially chosen based on the IOS_PLATFORM value above.
+#   If set manually, it will override the default location and force the user of a particular Developer Platform
+#
+# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
+#   By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.
+#   In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.
+#   If set manually, this will force the use of a specific SDK version
+
+# Standard settings
+set (CMAKE_SYSTEM_NAME Darwin)
+set (CMAKE_SYSTEM_VERSION 1 )
+set (UNIX True)
+set (APPLE True)
+set (IOS True)
+
+# Force the compilers to gcc for iOS
+include (CMakeForceCompiler)
+CMAKE_FORCE_C_COMPILER (gcc gcc)
+CMAKE_FORCE_CXX_COMPILER (g++ g++)
+
+# Skip the platform compiler checks for cross compiling
+set (CMAKE_CXX_COMPILER_WORKS TRUE)
+set (CMAKE_C_COMPILER_WORKS TRUE)
+
+# All iOS/Darwin specific settings - some may be redundant
+set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
+set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
+set (CMAKE_SHARED_MODULE_PREFIX "lib")
+set (CMAKE_SHARED_MODULE_SUFFIX ".so")
+set (CMAKE_MODULE_EXISTS 1)
+set (CMAKE_DL_LIBS "")
+
+set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
+set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
+set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
+
+# Hidden visibilty is required for cxx on iOS 
+set (CMAKE_C_FLAGS "-O2")
+set (CMAKE_CXX_FLAGS "-O2 -headerpad_max_install_names -fvisibility=hidden -fvisibility-inlines-hidden")
+
+set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
+set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
+
+set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
+set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
+set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
+set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
+set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
+set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
+
+# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
+# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
+# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
+# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
+if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
+	find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
+endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
+
+# Setup iOS platform
+if (NOT DEFINED IOS_PLATFORM)
+	set (IOS_PLATFORM "OS")
+endif (NOT DEFINED IOS_PLATFORM)
+set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform")
+
+# Check the platform selection and setup for developer root
+if (${IOS_PLATFORM} STREQUAL "OS")
+	set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
+elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
+	set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
+else (${IOS_PLATFORM} STREQUAL "OS")
+	message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR")
+endif (${IOS_PLATFORM} STREQUAL "OS")
+
+# Setup iOS developer location
+if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
+	set (CMAKE_IOS_DEVELOPER_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
+endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
+set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform")
+
+# Find and use the most recent iOS sdk 
+if (NOT DEFINED CMAKE_IOS_SDK_ROOT)
+	file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*")
+	if (_CMAKE_IOS_SDKS) 
+		list (SORT _CMAKE_IOS_SDKS)
+		list (REVERSE _CMAKE_IOS_SDKS)
+		list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT)
+	else (_CMAKE_IOS_SDKS)
+		message (FATAL_ERROR "No iOS SDK's found in default seach path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.")
+	endif (_CMAKE_IOS_SDKS)
+	message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}")
+endif (NOT DEFINED CMAKE_IOS_SDK_ROOT)
+set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
+
+# Set the sysroot default to the most recent SDK
+set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
+
+# set the architecture for iOS - using ARCHS_STANDARD_32_BIT sets armv6,armv7 and appears to be XCode's standard. 
+# The other value that works is ARCHS_UNIVERSAL_IPHONE_OS but that sets armv7 only
+set (CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD_32_BIT)" CACHE string  "Build architecture for iOS")
+
+# Set the find root to the iOS developer roots and to user defined paths
+set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string  "iOS find search path root")
+
+# default to searching for frameworks first
+set (CMAKE_FIND_FRAMEWORK FIRST)
+
+# set up the default search directories for frameworks
+set (CMAKE_SYSTEM_FRAMEWORK_PATH
+	${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
+	${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
+	${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
+)
+
+# only search the iOS sdks, not the remainder of the host filesystem
+set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
diff --git a/contrib/mobile/utils/icon_rotate.svg b/contrib/mobile/utils/icon_rotate.svg
new file mode 100644
index 0000000..179914a
--- /dev/null
+++ b/contrib/mobile/utils/icon_rotate.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<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"
+   version="1.1"
+   id="Layer_3"
+   x="0px"
+   y="0px"
+   width="512"
+   height="512"
+   viewBox="0 0 512 512"
+   enable-background="new 0 0 100 100"
+   xml:space="preserve"
+   inkscape:version="0.48.2 r9819"
+   sodipodi:docname="icon_rotate.svg"><metadata
+   id="metadata9"><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 /></cc:Work></rdf:RDF></metadata><defs
+   id="defs7" /><sodipodi:namedview
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1"
+   objecttolerance="10"
+   gridtolerance="10"
+   guidetolerance="10"
+   inkscape:pageopacity="0"
+   inkscape:pageshadow="2"
+   inkscape:window-width="1222"
+   inkscape:window-height="811"
+   id="namedview5"
+   showgrid="true"
+   inkscape:zoom="1.1773328"
+   inkscape:cx="123.31917"
+   inkscape:cy="232.25322"
+   inkscape:window-x="101"
+   inkscape:window-y="13"
+   inkscape:window-maximized="0"
+   inkscape:current-layer="Layer_3"
+   showguides="false"><inkscape:grid
+     type="xygrid"
+     id="grid3075"
+     empspacing="5"
+     visible="true"
+     enabled="true"
+     snapvisiblegridlinesonly="true" /></sodipodi:namedview>
+<g
+   id="g3034"
+   transform="translate(-1.3697408,411.47927)" />
+<path
+   style="fill:#007aff;fill-opacity:0.39215687"
+   inkscape:connector-curvature="0"
+   d="m 425.65,251.19 c 0,47.895 -21.025,93.085 -57.675,123.985 l -31.84,-37.77 c 25.49,-21.49 40.11,-52.915 40.11,-86.215 0,-59.895 -46.995,-108.875 -106.03,-112.355 H 246.05 l 20.35,51.52 c 0.685,1.725 0.125,3.695 -1.355,4.81 -1.48,1.12 -3.53,1.115 -5,-0.02 L 158.85,117.34 c -1.015,-0.785 -1.615,-1.985 -1.615,-3.275 0,-1.285 0.6,-2.495 1.615,-3.275 l 101.2,-77.8 c 0.74,-0.57 1.625,-0.85 2.515,-0.85 0.88,0 1.75,0.275 2.49,0.83 1.48,1.115 2.035,3.09 1.355,4.815 l -20.35,51.515 17.5,0.05  [...]
+   id="path3134" /></svg>
\ No newline at end of file
diff --git a/contrib/mobile/utils/icon_translate.svg b/contrib/mobile/utils/icon_translate.svg
new file mode 100644
index 0000000..30650a9
--- /dev/null
+++ b/contrib/mobile/utils/icon_translate.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+
+<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"
+   version="1.1"
+   id="Layer_3"
+   x="0px"
+   y="0px"
+   width="512"
+   height="512"
+   viewBox="0 0 512 512"
+   enable-background="new 0 0 100 100"
+   xml:space="preserve"
+   inkscape:version="0.48.2 r9819"
+   sodipodi:docname="icon_translate.svg"><metadata
+   id="metadata9"><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 /></cc:Work></rdf:RDF></metadata><defs
+   id="defs7" /><sodipodi:namedview
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1"
+   objecttolerance="10"
+   gridtolerance="10"
+   guidetolerance="10"
+   inkscape:pageopacity="0"
+   inkscape:pageshadow="2"
+   inkscape:window-width="1223"
+   inkscape:window-height="851"
+   id="namedview5"
+   showgrid="true"
+   inkscape:zoom="1.1773328"
+   inkscape:cx="1.858191"
+   inkscape:cy="266.22832"
+   inkscape:window-x="101"
+   inkscape:window-y="13"
+   inkscape:window-maximized="0"
+   inkscape:current-layer="Layer_3"
+   showguides="false"><inkscape:grid
+     type="xygrid"
+     id="grid3075"
+     empspacing="5"
+     visible="true"
+     enabled="true"
+     snapvisiblegridlinesonly="true" /></sodipodi:namedview>
+<g
+   id="g3034"
+   transform="translate(-1.3697408,411.47927)" />
+<path
+   style="fill:#007aff;fill-opacity:0.39215687"
+   inkscape:connector-curvature="0"
+   d="m 279.795,276.695 0,114.165 51.52,-20.35 c 1.725,-0.685 3.695,-0.125 4.81,1.355 1.12,1.48 1.115,3.53 -0.02,5 L 258.3,478.06 c -0.785,1.015 -1.985,1.615 -3.275,1.615 -1.285,0 -2.495,-0.6 -3.275,-1.615 l -77.8,-101.2 c -0.57,-0.74 -0.85,-1.625 -0.85,-2.515 0,-0.88 0.275,-1.75 0.83,-2.49 1.115,-1.48 3.09,-2.035 4.815,-1.355 l 51.515,20.35 0.05,-17.5 -0.26,-100 c 24.6704,-94.46905 5.19182,-149.0134 49.745,3.345 z m -49.54,-44.04 0,-114.165 -51.52,20.35 c -1.725,0.685 -3.695,0.125 -4.81 [...]
+   id="path3144" /></svg>
\ No newline at end of file
diff --git a/contrib/mobile/utils/ios_f2cblaslapack_makefile b/contrib/mobile/utils/ios_f2cblaslapack_makefile
new file mode 100644
index 0000000..96ea5a6
--- /dev/null
+++ b/contrib/mobile/utils/ios_f2cblaslapack_makefile
@@ -0,0 +1,48 @@
+
+
+########################################################################################
+# f2cblaslapack: BLAS/LAPACK in C
+########################################################################################
+
+ALL: blas_lib lapack_lib
+
+########################################################################################
+# Specify options to compile and create libraries
+########################################################################################
+ARCH       = "armv7"
+CC         = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
+COPTFLAGS  = -O -arch $(ARCH) -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk -miphoneos-version-min=7.0
+CNOOPT     = -O0 -arch $(ARCH) -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk -miphoneos-version-min=7.0
+RM         = /bin/rm
+AR         = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar
+AR_FLAGS   = cr
+LIB_SUFFIX = a
+RANLIB     = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib
+
+########################################################################################
+# compile the source files and create the blas and lapack libs
+########################################################################################
+
+BLAS_LIB_NAME       = libf2cblas.$(LIB_SUFFIX)
+LAPACK_LIB_NAME     = libf2clapack.$(LIB_SUFFIX)
+MAKE_OPTIONS        =  CC="$(CC)" COPTFLAGS="$(COPTFLAGS)" CNOOPT="$(CNOOPT)" AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" RM="$(RM)"
+MAKE_OPTIONS_BLAS   = $(MAKE_OPTIONS) LIBNAME="$(BLAS_LIB_NAME)"
+MAKE_OPTIONS_LAPACK = $(MAKE_OPTIONS) LIBNAME="$(LAPACK_LIB_NAME)"
+
+blas_lib:
+	- at cd blas;   $(MAKE) lib $(MAKE_OPTIONS_BLAS)
+	-@$(RANLIB) $(BLAS_LIB_NAME)
+	- at mv $(BLAS_LIB_NAME) $(ARCH)-unknown-darwin/
+
+lapack_lib:
+	- at cd lapack; $(MAKE) lib $(MAKE_OPTIONS_LAPACK)
+	-@$(RANLIB) $(LAPACK_LIB_NAME)
+	- at mv $(LAPACK_LIB_NAME) $(ARCH)-unknown-darwin/
+
+clean: cleanblaslapck cleanlib
+
+cleanblaslapck:
+	$(RM) */*.o
+
+cleanlib:
+	$(RM) ./*.a ./*.lib
diff --git a/contrib/mobile/utils/ios_petsc_reconfigure-arm64-unknown-darwin.py b/contrib/mobile/utils/ios_petsc_reconfigure-arm64-unknown-darwin.py
new file mode 100755
index 0000000..a27fcd1
--- /dev/null
+++ b/contrib/mobile/utils/ios_petsc_reconfigure-arm64-unknown-darwin.py
@@ -0,0 +1,41 @@
+#!/opt/local/bin/python
+if __name__ == '__main__':
+  import sys
+  import os
+  sys.path.insert(0, os.path.abspath('config'))
+  import configure
+  configure_options = [
+    '--CC=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang',
+    '--CFLAGS=-arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk -miphoneos-version-min=7.0',
+    '--CXX=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++',
+    '--CXXFLAGS=-arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk -miphoneos-version-min=7.0',
+    '--known-bits-per-byte=8',
+    '--known-endian=little',
+    '--known-level1-dcache-assoc=1',
+    '--known-level1-dcache-linesize=16',
+    '--known-level1-dcache-size=4000',
+    '--known-memcmp-ok=1',
+    '--known-sizeof-char=1',
+    '--known-sizeof-double=8',
+    '--known-sizeof-float=4',
+    '--known-sizeof-int=4',
+    '--known-sizeof-long-long=8',
+    '--known-sizeof-long=8',
+    '--known-sizeof-short=2',
+    '--known-sizeof-size_t=8',
+    '--known-sizeof-void-p=8',
+    '--with-batch=1',
+    '--with-blas-lib=/path/to/libf2cblas.a',
+    '--with-clanguage=cxx',
+    '--with-cmake=1',
+    '--with-debugging=0',
+    '--with-fc=0',
+    '--with-lapack-lib=/path/to/libf2clapack.a',
+    '--with-mpi=0',
+    '--with-parmetis=0',
+    '--with-scalapack=0',
+    '--with-shared-libraries=0',
+    '--with-x=0',
+    'PETSC_ARCH=arm64-unknown-darwin',
+  ]
+  configure.petsc_configure(configure_options)
diff --git a/contrib/mobile/utils/make_icon_ios.sh b/contrib/mobile/utils/make_icon_ios.sh
index e772101..64338fd 100755
--- a/contrib/mobile/utils/make_icon_ios.sh
+++ b/contrib/mobile/utils/make_icon_ios.sh
@@ -2,8 +2,8 @@
 
 mkdir -p ios.iconset
 # App icons (iPad)
-convert -scale 152 ../../../utils/icons/gmsh_1024x1024.png ios.iconset/icon_app_ipad_retina.png
-convert -scale 76 ../../../utils/icons/gmsh_1024x1024.png ios.iconset/icon_app_ipad.png
+convert -scale 152 ../../../utils/icons/gmsh_mobile_master.png ios.iconset/icon_app_ipad_retina.png
+convert -scale 76 ../../../utils/icons/gmsh_mobile_master.png ios.iconset/icon_app_ipad.png
 
-# App icons (iPhone)
-convert -scale 120 ../../../utils/icons/gmsh_1024x1024.png ios.iconset/icon_app_iphone_retina.png
+# App icon (iPhone)
+convert -scale 120 ../../../utils/icons/gmsh_mobile_master.png ios.iconset/icon_app_iphone_retina.png
diff --git a/contrib/mobile/utils/onelab_android.sh b/contrib/mobile/utils/onelab_android.sh
deleted file mode 100644
index b3cadea..0000000
--- a/contrib/mobile/utils/onelab_android.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env bash
-
-function checkError {
-        if [ $# == 2 ]; then
-                if [ $1 == 0 ]; then return; fi
-                echo -e "\033[31m[-] $2 \033[0m"
-                exit $1
-        fi
-}
-
-if [ -z "$ANDROID_NDK" ]; then
-        echo "ERROR: You must specify android NDK path: export ANDROID_NDK=/path/to/android-ndk/"
-        exit 1
-fi
-if [ -z "$ANDROID_SDK" ]; then
-        echo "ERROR: You must specify android SDK path: export ANDROID_SDK=/path/to/android-sdk/"
-        exit 1
-fi
-if [ -z "$ANDROID_TOOLCHAIN" ] || [ ! -f "$ANDROID_TOOLCHAIN" ]; then
-        echo "ERROR: You must specify a valid android toolchain: export ANDROID_TOOLCHAIN=/path/to/android.toolchain.cmake"
-        exit 1
-fi
-
-echo -e "\033[1m[+] Take the last version of Gmsh and GetDP from svn\033[0m"
-if [ ! -d "gmsh" ]; then svn --username gmsh --password gmsh co https://geuz.org/svn/gmsh/trunk gmsh; else svn up gmsh; fi
-if [ ! -d "getdp" ]; then svn --username gmsh --password gmsh co https://geuz.org/svn/getdp/trunk getdp; else svn up getdp; fi
-
-if [ ! -d "gmsh.android" ]; then mkdir gmsh.android; fi
-if [ ! -d "getdp.android" ]; then mkdir getdp.android; fi
-if [ ! -d "onelab.android" ]; then mkdir onelab.android; fi
-if [ ! -f "petsc.android/libpetsc.so" ] || [ ! -f "petsc.android/libf2clapack.so" ] || [ ! -f "petsc.android/libf2cblas.so" ] || [ ! -d "petsc.android/include/" ]; then 
-	echo "ERROR: petsc.android do not exist or is incomplete (need blas, lapack and petsc)"
-	exit 1
-fi
-
-cd gmsh.android
-echo -e "\033[1m[+] Make Gmsh library\033[0m"
-cmake -DDEFAULT=0 -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN -DENABLE_BLAS_LAPACK=1 -DENABLE_BUILD_ANDROID=1 -DENABLE_MESH=1 -DENABLE_ONELAB=1 -DENABLE_PARSER=1 -DENABLE_POST=1 -DCMAKE_BUILD_TYPE=Release -DBLAS_LIB=../petsc.android/libf2cblas.so -DLAPACK_LIB=../petsc.android/libf2clapack.so ../gmsh
-checkError $?  "CMake fail (Gmsh)"
-make androidGmsh -j3
-checkError $? "make fail (Gmsh)"
-make getHeaders
-checkError $? "make getHeaders fail (Gmsh)"
-
-cd ../getdp.android
-echo -e "\033[1m[+] Make GetDP library\033[0m"
-cmake -DDEFAULT=0 -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN -DENABLE_FORTRAN=0 -DENABLE_BUILD_ANDROID=1 -DENABLE_GMSH=1 -DENABLE_LEGACY=1 -DENABLE_PETSC=1 -DCMAKE_BUILD_TYPE=Release -DGMSH_INC=..//gmsh.android/Headers -DGMSH_LIB=../gmsh.android/libs/libGmsh.so -DPETSC_INC=../petsc.android/include/ -DPETSC_LIBS=../petsc.android/libpetsc.so ../getdp
-checkError $? "CMake fail (GetDP)"
-make androidGetdp -j3
-checkError $? "make fail (GetDP)"
-make getHeaders
-checkError $? "make getHeaders fail (GetDP)"
-
-cd ../onelab.android
-echo -e "\033[1m[+] Make Onelab interface library\033[0m"
-cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_TOOLCHAIN -DENABLE_BUILD_ANDROID=1 -DGETDP_LIB=../getdp.android/libs/libGetDP.so -DGETDP_INC=../getdp.android/Headers/ -DGMSH_LIB=../gmsh.android/libs/libGmsh.so -DGMSH_INC=../gmsh.android/Headers/ -DPETSC_LIB=../petsc.android/libpetsc.so -DBLAS_LIB=../petsc.android/libf2cblas.so -DLAPACK_LIB=../petsc.android/libf2clapack.so ../gmsh/contrib/mobile/
-checkError $? "CMake fail (Onelab)"
-make androidOnelab -j3
-checkError $? "make fail (Onelab)"
-make androidProject
-checkError $? "make Android project fail (Onelab)"
-
-echo -e "\033[1m[+] Build Android application (java)\033[0m"
-cd Onelab/
-if [ ! -d "libs/armeabi-v7a/" ]; then mkdir -p libs/armeabi-v7a/; fi
-target=1
-count=0
-while read line; do
-        read line # Name
-        target_name=$(echo $line | awk '{print $2}')
-        target_version=$(echo $line | awk '{print $3}')
-        read line # Type
-        read line # API level
-        target_api=$(echo $line | awk '{print $3}')
-        read line # Revision
-        read line # Skins
-        if [ $target_api -ge 14 ]; then
-                echo -e "\n\nBuild $target_name $target_version (target id: $target)"
-                $ANDROID_SDK/tools/android update project --name Onelab --path . --target $target
-                ant -quiet release
-		checkError $? "ant fail ($(echo $target_name $target_version))"
-                cp bin/Onelab-release.apk ../../../../Onelab-$(echo $target_name)_$(echo $target_version).apk
-		if [ $? -ne 0 ]; then
-                	cp bin/Onelab-release-unsigned.apk ../../../../Onelab-unsigned-$(echo $target_name)_$(echo $target_version).apk
-		fi
-		count=$(($count+1))
-		break # build only for the first target
-        fi
-        read line # HACK
-        target=$(($target+1))
-done < <($ANDROID_SDK/tools/android list target | grep -A 5 "id:")
-echo -e "\033[1m[V] Build $count apk(s)\033[0m"
-exit 0
diff --git a/contrib/mobile/utils/onelab_android_build.sh b/contrib/mobile/utils/onelab_android_build.sh
new file mode 100755
index 0000000..3a85946
--- /dev/null
+++ b/contrib/mobile/utils/onelab_android_build.sh
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+
+gmsh_svn="${HOME}/src/gmsh"
+getdp_svn="${HOME}/src/getdp"
+frameworks_dir="${HOME}/src/gmsh/contrib/mobile/frameworks_android"
+
+petsc_lib="$frameworks_dir/petsc"
+slepc_lib="$frameworks_dir/slepc"
+android_ndk="${HOME}/android-ndk-r8b/"
+android_sdk="${HOME}/android-sdk/"
+
+cmake_default="-DDEFAULT=0 -DCMAKE_TOOLCHAIN_FILE=$gmsh_svn/contrib/mobile/utils/Android.cmake -DENABLE_BUILD_ANDROID=1 -DCMAKE_BUILD_TYPE=Release"
+cmake_thread=6
+
+function check {
+  return_code=$?
+  if [ $return_code != 0 ]; then
+    echo "last command failed (return $return_code)"
+    exit $return_cod
+  fi
+}
+
+# PETSc and BLAS/LAPACK
+if [ ! -f "$petsc_lib/libpetsc.so" ] || [ ! -f "$petsc_lib/libf2clapack.so" ] || [ ! -f "$petsc_lib/libf2cblas.so" ] || [ ! -d "$petsc_lib/Headers/" ]; then 
+  echo -e "ERROR: Need BLAS (f2c), LAPACK (f2c) and PETSc\ncheck android_petsc_reconfigure-armv7-android-linux.py for compile options\n"
+  exit 1
+fi
+
+export ANDROID_NDK=$android_ndk 
+
+# Gmsh
+cd $gmsh_svn
+svn up
+if [ ! -d "$gmsh_svn/build_android" ] || [ ! -f "$gmsh_svn/build_android/CMakeCache.txt" ]; then
+  mkdir $gmsh_svn/build_android
+fi
+cd $gmsh_svn/build_android
+cmake $cmake_default -DENABLE_BLAS_LAPACK=1 -DENABLE_BUILD_SHARED=1 -DENABLE_MATHEX=1 -DENABLE_MESH=1 -DENABLE_ONELAB=1 -DENABLE_PARSER=1 -DENABLE_POST=1 -DENABLE_TETGEN=1 -DBLAS_LIB="$petsc_lib/libf2cblas.so" -DLAPACK_LIB="$petsc_lib/libf2clapack.so" ..
+check
+make androidGmsh -j$cmake_thread
+check
+make get_headers
+check
+
+# GetDP
+cd $getdp_svn
+svn up
+if [ ! -d "$getdp_svn/build_android" ] || [ ! -f "$getdp_svn/build_android/CMakeCache.txt" ]; then
+  mkdir $getdp_svn/build_android
+fi
+cd $getdp_svn/build_android
+PETSC_DIR= PETSC_ARCH= SLEPC_DIR= cmake $cmake_default -DENABLE_BLAS_LAPACK=1 -DENABLE_BUILD_SHARED=1 -DENABLE_GMSH=1 -DENABLE_LEGACY=1 -DENABLE_PETSC=1 -DPETSC_INC="$petsc_lib/Headers;$petsc_lib/Headers/mpiuni" -DPETSC_LIBS="$petsc_lib/libpetsc.so" -DENABLE_SLEPC=1 -DSLEPC_INC="$slepc_lib/Headers/" -DSLEPC_LIB="$slepc_lib/libslepc.a" -DGMSH_INC="$gmsh_svn/build_android/Headers/" -DGMSH_LIB="$gmsh_svn/build_android/libs/libGmsh.so" -DBLAS_LAPACK_LIBRARIES="$petsc_lib/libf2cblas.so;$petsc [...]
+check
+make androidGetdp -j$cmake_thread
+check
+make get_headers
+check
+
+# Onelab/Mobile interface
+if [ ! -d "$gmsh_svn/contrib/mobile/build_android" ] || [ ! -f "$gmsh_svn/contrib/mobile/build_android/CMakeCache.txt" ]; then
+  mkdir $gmsh_svn/contrib/mobile/build_android
+fi
+cd $gmsh_svn/contrib/mobile/build_android
+cmake $cmake_default \
+      -DCMAKE_INCLUDE_PATH="$getdp_svn/" \
+      -DBLAS_LIB="$petsc_lib/libf2cblas.so" -DLAPACK_LIB="$petsc_lib/libf2clapack.so" \
+      -DPETSC_LIB="$petsc_lib/libpetsc.so" \
+      -DGMSH_INC="$gmsh_svn/build_android/Headers" -DGMSH_LIB="$gmsh_svn/build_android/libs/libGmsh.so" \
+      -DBENCHMARKSDIR="$getdp_svn/" \
+      -DGETDP_INC="$getdp_svn/build_android/Headers" -DGETDP_LIB="$getdp_svn/build_android/libs/libGetDP.so" ..
+check
+make androidOnelab -j$cmake_thread
+check
+make androidProject
+check
+
+# Onelab/Mobile package
+cd Onelab
+if [ ! -d "libs/armeabi-v7a/" ]; then mkdir -p libs/armeabi-v7a/; fi
+target=1
+while read line; do
+  read line # Name
+  target_name=$(echo $line | awk '{print $2}')
+  target_version=$(echo $line | awk '{print $3}')
+  read line # Type
+  read line # API level
+  target_api=$(echo $line | awk '{print $3}')
+  read line # Revision
+  read line # Skins
+  if [ $target_api -ge 14 ]; then
+    $android_sdk/tools/android update project --name Onelab --path . --target $target
+    check
+    ant release
+    check
+    break
+  fi
+  read line # HACK
+  target=$(($target+1))
+done < <($android_sdk/tools/android list target | grep -A 5 "id:")
+
+# to re-install on the device:
+# $android_sdk/platform-tools/adb install -r $gmsh_svn/contrib/mobile/build_android/Onelab/bin/Onelab-release.apk
+
+# to launch the app on the device:
+# $android_sdk/platform-tools/adb shell am start -n org.geuz.onelab/org.geuz.onelab.SplashScreen
+
+# to debug and check the log:
+# $android_sdk/tools/ddms
diff --git a/contrib/mobile/utils/onelab_ios_build.sh b/contrib/mobile/utils/onelab_ios_build.sh
new file mode 100755
index 0000000..73e5b8e
--- /dev/null
+++ b/contrib/mobile/utils/onelab_ios_build.sh
@@ -0,0 +1,85 @@
+#/usr/bin/env bash
+
+gmsh_svn="${HOME}/src/gmsh/"
+getdp_svn="${HOME}/src/getdp/"
+frameworks_dir="${HOME}/src/gmsh/contrib/mobile/frameworks_ios/"
+
+petsc_framework="$frameworks_dir/petsc.framework"
+slepc_framework="$frameworks_dir/slepc.framework"
+
+cmake_default="-DDEFAULT=0 -DCMAKE_TOOLCHAIN_FILE=$gmsh_svn/contrib/mobile/utils/iOS.cmake -DENABLE_BUILD_IOS=1 -DCMAKE_BUILD_TYPE=Release -GXcode"
+
+build_cmd="xcodebuild -verbose -target lib -configuration Release"
+headers_cmd="xcodebuild -verbose -target get_headers -configuration Release"
+
+function check {
+  return_code=$?
+  if [ $return_code != 0 ]; then
+    echo "last command failed (return $return_code)"
+    exit $return_code
+  fi
+}
+
+function build_gmsh {
+  if [ $# -ne 1 ]; then
+    echo "You must specify an architecture (e.g. armv7, armv7s, arm64, ...)"
+    return
+  fi
+  if [ ! -d "$gmsh_svn/build_ios_$1" ]; then
+    mkdir $gmsh_svn/build_ios_$1
+  fi
+  cd $gmsh_svn/build_ios_$1
+  cmake $cmake_default -DENABLE_BLAS_LAPACK=1 -DENABLE_BUILD_LIB=1 -DENABLE_MATHEX=1 -DENABLE_MESH=1 -DENABLE_ONELAB=1 -DENABLE_PARSER=1 -DENABLE_POST=1 -DENABLE_TETGEN=1 -DCMAKE_OSX_ARCHITECTURES="$1" ..
+  check
+  $build_cmd
+  check
+  $headers_cmd
+  cd -
+}
+function build_getdp {
+  if [ $# -ne 1 ]; then
+    echo "You must specify an architecture (e.g. armv7, armv7s, arm64, ...)"
+    return
+  fi
+  if [ ! -d "$getdp_svn/build_ios_$1" ]; then
+    mkdir $getdp_svn/build_ios_$1
+  fi
+  cd $getdp_svn/build_ios_$1
+  PETSC_DIR= PETSC_ARCH= SLEPC_DIR= cmake $cmake_default -DENABLE_BLAS_LAPACK=1 -DENABLE_BUILD_LIB=1 -DENABLE_GMSH=1 -DENABLE_LEGACY=1 -DENABLE_PETSC=1 -DPETSC_INC="$petsc_framework/Headers/" -DPETSC_LIBS="$petsc_framework/petsc" -DENABLE_SLEPC=1 -DSLEPC_INC="$slepc_framework/Headers/" -DSLEPC_LIB="$slepc_framework/slepc" -DGMSH_INC="$gmsh_svn/build_ios_$1/Headers/" -DGMSH_LIB="$gmsh_svn/build_ios_$1/Release-iphoneos/libGmsh.a" -DCMAKE_OSX_ARCHITECTURES="$1" ..
+  check
+  $build_cmd
+  check
+  $headers_cmd
+  cd -
+}
+
+# build gmsh framework
+cd $gmsh_svn && svn up
+build_gmsh armv7
+build_gmsh armv7s
+build_gmsh arm64
+mkdir -p $frameworks_dir/Gmsh.framework/Headers
+lipo -create $gmsh_svn/build_ios_armv7/Release-iphoneos/libGmsh.a $gmsh_svn/build_ios_arm64/Release-iphoneos/libGmsh.a $gmsh_svn/build_ios_armv7s/Release-iphoneos/libGmsh.a -output $frameworks_dir/Gmsh.framework/Gmsh
+cd $frameworks_dir/Gmsh.framework/Headers
+cp $gmsh_svn/build_ios_armv7/Headers/gmsh/* .
+ln -s . gmsh
+
+# build getdp framework
+cd $getdp_svn && svn up
+build_getdp armv7
+build_getdp armv7s
+build_getdp arm64
+mkdir -p $frameworks_dir/GetDP.framework/Headers
+lipo -create $getdp_svn/build_ios_armv7/Release-iphoneos/libGetDP.a $getdp_svn/build_ios_arm64/Release-iphoneos/libGetDP.a $getdp_svn/build_ios_armv7s/Release-iphoneos/libGetDP.a -output $frameworks_dir/GetDP.framework/GetDP
+cd $frameworks_dir/GetDP.framework/Headers
+cp $getdp_svn/build_ios_armv7/Headers/getdp/* .
+
+# create xcode project
+mkdir $gmsh_svn/contrib/mobile/build_ios
+cd $gmsh_svn/contrib/mobile/build_ios
+cmake -DCMAKE_INCLUDE_PATH="$frameworks_dir;$getdp_svn" ..
+make xcodeProject
+
+#TODO
+#xcodebuild -project "Onelab" -target "Onelab" -configuration Release
+#xcrun -sdk iphoneos PackageApplication -v "Onelab.app" -o "Onelab.ipa" --sign "iPhone Distribution: Your Signature\" --embed enterprise.mobileprovision
diff --git a/contrib/mobile/utils/onelab_iossimulator_build.sh b/contrib/mobile/utils/onelab_iossimulator_build.sh
new file mode 100755
index 0000000..77ea8e6
--- /dev/null
+++ b/contrib/mobile/utils/onelab_iossimulator_build.sh
@@ -0,0 +1,57 @@
+#/usr/bin/env bash
+
+gmsh_svn="${HOME}/src/gmsh/"
+getdp_svn="${HOME}/src/getdp/"
+frameworks_dir="${HOME}/src/gmsh/contrib/mobile/frameworks_iossimulator/"
+
+petsc_framework="$frameworks_dir/petsc.framework"
+slepc_framework="$frameworks_dir/slepc.framework"
+
+cmake_default="-DDEFAULT=0 -DCMAKE_C_FLAGS='-m32' -DCMAKE_CXX_FLAGS='-m32'"
+
+build_cmd="make lib -j4"
+headers_cmd="make get_headers"
+
+function build_gmsh {
+  if [ ! -d "$gmsh_svn/build_iossimulator" ]; then
+    mkdir $gmsh_svn/build_iossimulator
+  fi
+  cd $gmsh_svn/build_iossimulator
+  cmake $cmake_default -DENABLE_BLAS_LAPACK=1 -DENABLE_BUILD_LIB=1 -DENABLE_MATHEX=1 -DENABLE_MESH=1 -DENABLE_ONELAB=1 -DENABLE_PARSER=1 -DENABLE_POST=1 -DENABLE_TETGEN=1 ..
+  $build_cmd
+  $headers_cmd
+  cd -
+}
+function build_getdp {
+  if [ ! -d "$getdp_svn/build_iossimulator" ]; then
+    mkdir $getdp_svn/build_iossimulator
+  fi
+  cd $getdp_svn/build_iossimulator
+  PETSC_DIR= PETSC_ARCH= SLEPC_DIR= cmake $cmake_default -DENABLE_BLAS_LAPACK=1 -DENABLE_BUILD_LIB=1 -DENABLE_GMSH=1 -DENABLE_LEGACY=1 -DENABLE_PETSC=1 -DPETSC_INC="$petsc_framework/Headers/" -DPETSC_LIBS="$petsc_framework/petsc" -DENABLE_SLEPC=1 -DSLEPC_INC="$slepc_framework/Headers/" -DSLEPC_LIB="$slepc_framework/slepc" -DGMSH_INC="$gmsh_svn/build_iossimulator/Headers/" -DGMSH_LIB="$gmsh_svn/build_iossimulator/libGmsh.a" ..
+  $build_cmd
+  $headers_cmd
+  cd -
+}
+
+# build gmsh framework
+cd $gmsh_svn && svn up
+build_gmsh
+mkdir -p $frameworks_dir/Gmsh.framework/Headers
+cp $gmsh_svn/build_iossimulator/libGmsh.a $frameworks_dir/Gmsh.framework/Gmsh
+cd $frameworks_dir/Gmsh.framework/Headers
+cp $gmsh_svn/build_iossimulator/Headers/gmsh/* .
+ln -s . gmsh
+
+# build getdp framework
+cd $getdp_svn && svn up
+build_getdp
+mkdir -p $frameworks_dir/GetDP.framework/Headers
+cp $getdp_svn/build_iossimulator/libGetDP.a $frameworks_dir/GetDP.framework/GetDP
+cd $frameworks_dir/GetDP.framework/Headers
+cp $getdp_svn/build_iossimulator/Headers/getdp/* .
+
+# create xcode project
+mkdir $gmsh_svn/contrib/mobile/build_iossimulator
+cd $gmsh_svn/contrib/mobile/build_iossimulator
+cmake -DCMAKE_INCLUDE_PATH="$frameworks_dir;$getdp_svn" ..
+make xcodeProject
diff --git a/contrib/onelab/OLMakefile b/contrib/onelab/OLMakefile
deleted file mode 100644
index 0079571..0000000
--- a/contrib/onelab/OLMakefile
+++ /dev/null
@@ -1,61 +0,0 @@
-SOLVERS=loader
-SOURCES=myOS StringUtils mathex OnelabClients OnelabMessage OnelabParser metamodel
-
-COMMON_DIR=$(GMSH_DIR)/Common
-ONELAB_DIR=$(GMSH_DIR)/contrib/onelab
-MATHEX_DIR=$(GMSH_DIR)/contrib/MathEx
-CPPFLAGS+= $(shell python-config --includes) -fPIC
-
-OBJDIR=objects
-
-ifeq ($(STATICLINUX), 32)
-	LDFLAGS+=-static-libgcc -static-libstdc++ -static -m32
-	CPPFLAGS+= -m32
-	OBJDIR=objects-static-linux32
-	EXESUFFIX=32
-endif
-ifeq ($(STATICLINUX), 64)
-	LDFLAGS+=-static-libgcc -static-libstdc++ -static
-	OBJDIR=objects-static-linux64
-	EXESUFFIX=64
-endif
-ifeq ($(MINGW), 32)
-	CXX=i686-w64-mingw32-g++
-	LDFLAGS+=-static-libgcc -static-libstdc++ -static -lws2_32
-	OBJDIR=objects-mingw32
-	EXESUFFIX=32.exe
-endif
-ifeq ($(MINGW), 64)
-	CXX=x86_64-w64-mingw32-g++
-	LDFLAGS+=-static-libgcc -static-libstdc++ -static -lws2_32
-	OBJDIR=objects-mingw64
-	EXESUFFIX=64.exe
-endif
-
-TARGETS=$(SOLVERS:=_onelab$(EXESUFFIX))
-all : $(TARGETS)
-ifndef GMSH_DIR
-	@echo '"The environment variable GMSH_DIR is not set."'
-	@exit
-endif
-
-CPPFLAGS+=-g -DONELAB_LOADER -I$(COMMON_DIR) -I$(ONELAB_DIR) -I$(MATHEX_DIR)
-VPATH=$(ONELAB_DIR):$(COMMON_DIR):$(MATHEX_DIR)
-
-OBJECTS=$(foreach OBJ, $(SOURCES), $(OBJDIR)/$(OBJ).o)
-$(OBJDIR)/%.o : %.cpp $(ONELAB_DIR)/*.h
-	@mkdir -p $(OBJDIR) 
-	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
-
-%_onelab$(EXESUFFIX) : $(OBJDIR)/%.o $(OBJECTS)
-	$(CXX) $< $(OBJECTS) $(LDFLAGS) -o $@
-
-clean :
-	$(RM) $(TARGETS) $(OBJDIR)/*.o
-
-onelab_wrap.cpp : onelab.i
-	swig -python -c++ -o $@ $<
-
-_onelab.so : $(OBJECTS) $(OBJDIR)/onelab_wrap.o
-	$(CXX) -bundle -flat_namespace -undefined suppress $(OBJECTS) $(OBJDIR)/onelab_wrap.o -o _onelab.so
-.PRECIOUS: $(OBJDIR)/%.o
diff --git a/contrib/onelab/OnelabParser.cpp b/contrib/onelab/OnelabParser.cpp
index bd42b12..24159fd 100644
--- a/contrib/onelab/OnelabParser.cpp
+++ b/contrib/onelab/OnelabParser.cpp
@@ -1,7 +1,10 @@
-#include "OnelabClients.h"
+
 #include <algorithm>
 #include "mathex.h"
 
+#include "OnelabClients.h"
+
+
 // reserved keywords for the onelab parser
 
 namespace olkey{
@@ -126,6 +129,7 @@ void MetaModel::saveCommandLines(){
   outfile.close();
 }
 
+
 int enclosed(const std::string &in, std::vector<std::string> &arguments,
 	     size_t &end){
   // syntax: (arguments[Ø], arguments[1], ... , arguments[n])
@@ -1435,7 +1439,7 @@ void localSolverClient::convert_oneline(std::string line, std::ifstream &infile,
 void localSolverClient::convert_onefile(std::string fileName, std::ofstream &outfile) {
   std::ifstream infile(fileName.c_str());
   if (infile.is_open()){
-    OLMsg::Info("Convert file <%s>",fileName.c_str());
+    //OLMsg::Info("Convert file <%s>",fileName.c_str());
     while ( infile.good() ) {
       std::string line;
       getline (infile,line);
diff --git a/contrib/onelab/python/onelab.py b/contrib/onelab/python/onelab.py
index cabd186..6bed104 100755
--- a/contrib/onelab/python/onelab.py
+++ b/contrib/onelab/python/onelab.py
@@ -1,5 +1,5 @@
 """
-OneLab - Copyright (C) 2011-2013 ULg-UCL
+OneLab - Copyright (C) 2011-2014 ULg-UCL
 
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
@@ -28,7 +28,7 @@ Please report all bugs and problems to the public mailing list
 """
 
 import socket, struct, os, sys, subprocess
-_VERSION = '1.05'
+_VERSION = '1.1'
 
 def file_exist(filename):
   try:
@@ -56,9 +56,9 @@ def path(ref,inp=''):
 class _parameter() :
   _membersbase = [
     ('name', 'string'), ('label', 'string', ''), ('help', 'string', ''),
-    ('neverChanged', 'int', 0), ('changed', 'int', 1), ('visible', 'int', 1),
-    ('readOnly', 'int', 0), ('attributes', ('dict', 'string', 'string'), {}),
-    ('clients', ('list', 'string'), [])
+    ('neverChanged', 'int', 0), ('visible', 'int', 1), ('readOnly', 'int', 0), 
+    ('attributes', ('dict', 'string', 'string'), {}),
+    ('clients', ('dict', 'string', 'int'), {})
   ]
   _members = {
     'string' : _membersbase + [
@@ -114,9 +114,13 @@ class _parameter() :
     return self
 
   def modify(self, **param) :
+    ## updates the parameter with the content of param, attributes are merged
     for i in _parameter._members[self.type] :
       if i[0] in param :
-        setattr(self, i[0], param[i[0]]) #NB: no else statement => update
+        if i[0] == 'attributes' :
+          self.attributes.update(param['attributes'])
+        else :
+          setattr(self, i[0], param[i[0]])
 
 
 class client :
@@ -135,6 +139,18 @@ class client :
   _GMSH_PARAMETER_NOT_FOUND = 29
   _GMSH_PARAMETER_CLEAR = 31
   _GMSH_PARAMETER_UPDATE = 32
+  _GMSH_OPEN_PROJECT = 33
+  _GMSH_CLIENT_CHANGED = 34
+
+  def _createSocket(self) :
+    addr = self.addr
+    if '/' in addr or '\\' in addr or ':' not in addr :
+      self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+      self.socket.connect(addr)
+    else :
+      self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+      s = addr.split(':')
+      self.socket.connect((s[0], int(s[1])))
 
   def _receive(self) :
     def buffered_receive(l) :
@@ -164,33 +180,37 @@ class client :
       self._createSocket()
       self.socket.send(struct.pack('ii%is' %len(m), t, len(m), m))
 
-  def _defineParameter(self, param) :
+  def _defineParameter(self, p) :
     if not self.socket :
-      return param.value
-    self._send(self._GMSH_PARAMETER_QUERY, param.tochar())
+      return p.value
+    self._send(self._GMSH_PARAMETER_QUERY, p.tochar())
     (t, msg) = self._receive() 
     if t == self._GMSH_PARAMETER :
-      self._send(self._GMSH_PARAMETER_UPDATE, param.tochar()) #enrich a previous decl.
-      return param.fromchar(msg).value # use value from server
+      self._send(self._GMSH_PARAMETER_UPDATE, p.tochar())
+      return p.fromchar(msg).value
     elif t == self._GMSH_PARAMETER_NOT_FOUND :
-      self._send(self._GMSH_PARAMETER, param.tochar()) #declaration
-      return param.value
-    
+      self._send(self._GMSH_PARAMETER, p.tochar())
+      return p.value
+        
+  def _getParameter(self, param, warn_if_not_found=True) :
+    if not self.socket :
+      return
+    self._send(self._GMSH_PARAMETER_QUERY, param.tochar())
+    (t, msg) = self._receive() 
+    if t == self._GMSH_PARAMETER :
+      param.fromchar(msg)
+    elif t == self._GMSH_PARAMETER_NOT_FOUND and warn_if_not_found :
+      print ('Unknown parameter %s' %(param.name))
+
   def defineNumber(self, name, **param):
     if 'labels' in param :
       param["choices"] = param["labels"].keys()
     p = _parameter('number', name=name, **param)
-    if 'value' not in param : #make the parameter readOnly
-      p.readOnly = 1
-      p.attributes={'Highlight':'AliceBlue'}
     value = self._defineParameter(p)
     return value
 
   def defineString(self, name, **param):
     p = _parameter('string', name=name, **param)
-    if 'value' not in param : #make the parameter readOnly
-      p.readOnly = 1
-      p.attributes={'Highlight':'AliceBlue'}
     value = self._defineParameter(p)
     return value
   
@@ -218,27 +238,32 @@ class client :
       p.modify(**param)
     self._send(self._GMSH_PARAMETER, p.tochar())
 
-  def addNumberChoice(self, name, value):
+  def clear(self, name) :
+    if not self.socket :
+      return
+    self._send(self._GMSH_PARAMETER_CLEAR, str(name))
+
+  def _setNumberChoices(self, name, val):
     if not self.socket :
       return
     p = _parameter('number', name=name)
     self._send(self._GMSH_PARAMETER_QUERY, p.tochar())
     (t, msg) = self._receive() 
     if t == self._GMSH_PARAMETER :
-      p.fromchar(msg).choices.append(value)
+      if len(val) : # add new choices
+        p.fromchar(msg).value = val[0]
+        p.choices.extend(val)
+      else : # reset choices list
+        p.fromchar(msg).choices = ()
     elif t == self._GMSH_PARAMETER_NOT_FOUND :
       print ('Unknown parameter %s' %(param.name))
     self._send(self._GMSH_PARAMETER, p.tochar())
+    
+  def resetNumberChoices(self, name):
+    self._setNumberChoices(name,[])
 
-  def _getParameter(self, param, warn_if_not_found=True) :
-    if not self.socket :
-      return
-    self._send(self._GMSH_PARAMETER_QUERY, param.tochar())
-    (t, msg) = self._receive() 
-    if t == self._GMSH_PARAMETER :
-      param.fromchar(msg)
-    elif t == self._GMSH_PARAMETER_NOT_FOUND and warn_if_not_found :
-      print ('Unknown parameter %s' %(param.name))
+  def addNumberChoice(self, name, value):
+    self._setNumberChoices(name,[value])
 
   def getNumber(self, name, warn_if_not_found=True):
     param = _parameter('number', name=name)
@@ -250,16 +275,32 @@ class client :
     self._getParameter(param, warn_if_not_found)
     return param.value
 
+  def getNumberChoices(self, name, warn_if_not_found=True):
+    param = _parameter('number', name=name)
+    self._getParameter(param, warn_if_not_found)
+    return param.choices
+
+  def getStringChoices(self, name, warn_if_not_found=True):
+    param = _parameter('string', name=name)
+    self._getParameter(param, warn_if_not_found)
+    return param.choices
+
   def show(self, name) :
-    if not self.socket :
+    if not self.socket or not name:
       return
     param = _parameter('number', name=name)
     self._send(self._GMSH_PARAMETER_QUERY, param.tochar())
     (t, msg) = self._receive() 
     if t == self._GMSH_PARAMETER :
-      print (msg)
+      print (msg.replace('\0','|'))
     elif t == self._GMSH_PARAMETER_NOT_FOUND :
-      print ('Unknown parameter %s' %(name))
+      param = _parameter('string', name=name)
+      self._send(self._GMSH_PARAMETER_QUERY, param.tochar())
+      (t, msg) = self._receive() 
+      if t == self._GMSH_PARAMETER :
+        print (msg.replace('\0','|'))
+      elif t == self._GMSH_PARAMETER_NOT_FOUND :
+        print('Unknown parameter %s' %(name))
 
   def sendCommand(self, command) :
     if not self.socket :
@@ -271,18 +312,10 @@ class client :
       return
     self._send(self._GMSH_MERGE_FILE, filename)
 
-  def reloadGeometry(self, filename) :
-    if not self.socket or not filename :
-      return
-    if os.path.splitext(filename)[1] == '.geo' :
-      self._send(self._GMSH_PARSE_STRING, "Delete All;")
-      self._send(self._GMSH_MERGE_FILE, filename)
-
-  def mesh(self, filename) :
+  def openProject(self, filename) :
     if not self.socket or not filename :
       return
-    self._send(self._GMSH_PARSE_STRING, 'Mesh 3; Save "' + filename + ' ;')
-    self._send(self._GMSH_MERGE_FILE, filename)
+    self._send(self._GMSH_OPEN_PROJECT, filename)
     
   def sendInfo(self, msg) :
     if not self.socket :
@@ -302,23 +335,33 @@ class client :
       return
     self._send(self._GMSH_ERROR, str(msg))
 
-  def preProcess(self, filename) :
+  def preProcess(self, name, filename) :
     if not self.socket :
       return
-    self._send(self._GMSH_OLPARSE, filename)
+    msg = [name, filename]
+    self._send(self._GMSH_OLPARSE, '\0'.join(msg))
     (t, msg) = self._receive() 
     if t == self._GMSH_OLPARSE :
-      print (msg)
+      if msg == "true" :
+          return True
+    return False
 
-  def _createSocket(self) :
-    addr = self.addr
-    if '/' in addr or '\\' in addr or ':' not in addr :
-      self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-      self.socket.connect(addr)
-    else :
-      self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-      s = addr.split(':')
-      self.socket.connect((s[0], int(s[1])))
+  def isChanged(self, name) :
+    if not self.socket :
+      return
+    msg = ["get", name]
+    self._send(self._GMSH_CLIENT_CHANGED, '\0'.join(msg))
+    (t, msg) = self._receive() 
+    if t == self._GMSH_CLIENT_CHANGED :
+      if msg == "true" :
+          return True
+    return False
+
+  def setChanged(self, name, changed) :
+    if not self.socket :
+      return
+    msg = ["set", name, 'true' if changed else 'false']
+    self._send(self._GMSH_CLIENT_CHANGED, '\0'.join(msg))
 
   def waitOnSubClients(self):
     if not self.socket :
@@ -329,8 +372,7 @@ class client :
         self._numSubClients -= 1
 
   def runNonBlockingSubClient(self, name, command, arguments=''):
-    # create command line
-    if self.action == "check":
+    if self.action == 'check':
       cmd = command
     else:
       cmd = command + ' ' + arguments
@@ -343,6 +385,8 @@ class client :
   def runSubClient(self, name, command, arguments=''):
     self.runNonBlockingSubClient(name, command, arguments)
     self.waitOnSubClients() # makes the subclient blocking
+    if self.action == 'compute': 
+      self.setChanged(name, False)
 
   def run(self, name, command, arguments=''):
     self.runSubClient(name, command, arguments)
@@ -358,8 +402,12 @@ class client :
         self.addr = sys.argv[i + 2]
         self._createSocket()
         self._send(self._GMSH_START, str(os.getpid()))
-    self.action = self.getString(self.name + '/Action')
+    self.action = "compute" # default (subclients have no client.Action defined)
+    self.action = self.getString(self.name + '/Action', False)
     self.setNumber('IsPyMetamodel',value=1,visible=0)
+    #self.defineNumber('0Metamodel/Loop',value=0,visible=0)
+    self.loop = self.getNumber('0Metamodel/Loop', warn_if_not_found=False)
+    self.batch = self.getNumber('0Metamodel/Batch', warn_if_not_found=False)
     self.sendInfo("Performing OneLab '" + self.action + "'")
     if self.action == "initialize": 
       self.finalize()
@@ -377,7 +425,7 @@ class client :
   def __del__(self):
     self.finalize()
 
-  def call(self, cmdline, remote='', rundir='', logfile=''):
+  def call(self, name, cmdline, remote='', rundir='', logfile=''):
     cwd = None
     if not remote :
       argv = cmdline.rsplit(' ')
@@ -398,9 +446,13 @@ class client :
         print(line.rstrip())
     result = call.wait()
     if result == 0 :
-      self._send(self._GMSH_INFO, 'call \"' + ''.join(argv) + '\"')
+      self._send(self._GMSH_INFO, 'call \"' + ' '.join(argv) + '\"')
+      if self.action == 'compute':
+        self.setChanged(name, False)
     else :
-      self._send(self._GMSH_ERROR, 'call failed !!\n' + call.stderr.read().encode('utf-8'))
+      for line in iter(call.stderr.readline, b''):
+        self._send(self._GMSH_ERROR, line.rstrip().encode('utf-8'))
+      sys.exit(1)
       
   def upload(self, here, there, remote='') :
     if not here or not there :
@@ -416,9 +468,8 @@ class client :
       self._send(self._GMSH_INFO, 'upload: ' + ' '.join(argv))
     else :
       print(call.stderr.read())
-      ## self._send(self._GMSH_ERROR, 'upload failed !!\n' + call.stderr.read().encode('utf-8'))
 
-  def download(self, here, there, remote='') :
+  def download(self, there, here, remote='') :
     if not here or not there :
       return
     if remote :
@@ -432,5 +483,33 @@ class client :
       self._send(self._GMSH_INFO, 'download: ' + ' '.join(argv))
     else :
       print(call.stderr.read())
-      ##self._send(self._GMSH_ERROR, 'download failed !!\n' + call.stderr.read().encode('utf-8'))
       
+  def solutionFiles(self, list) :
+    self.defineNumber('0Metamodel/9Use restored solution', value=0, choices=[0,1])
+    self.defineString('0Metamodel/9Tag', value='')
+    if list :
+      if self.getNumber('0Metamodel/9Use restored solution') :
+        return self.getStringChoices('0Metamodel/9Solution files')  
+      else :
+        self.setString('0Metamodel/9Solution files', value=list[0],
+                       choices=list, readOnly=1)      
+    return list
+
+  def restoreSolution(self) :
+    return self.getNumber('0Metamodel/9Use restored solution')
+
+  def outputFiles(self, list) :
+    if list :
+      self.setString(self.name+'/9Output files', value=list[0],
+                     choices=list, visible=0)
+
+# tool to extract the (i, j)th element in an array file
+from rlcompleter import readline
+def extract(filename,i,j):
+    input = open(filename,'r')
+    all_lines = input.readlines()
+    input.close()
+    if i == -1:
+        i = len(all_lines) # last line
+    items = all_lines[i-1].split()
+    return float(items[j-1])
diff --git a/contrib/onelab/python/test.py b/contrib/onelab/python/test.py
index e551ace..04bcf7d 100755
--- a/contrib/onelab/python/test.py
+++ b/contrib/onelab/python/test.py
@@ -14,7 +14,7 @@ B = OL.defineNumber('Group/B', value=0, min = -10, max = 10, step = 1)
 C = OL.defineNumber('Group/C', value=2, choices = [0, 1, 2, 3], attributes={'Highlight':'Pink'})
 D = OL.defineNumber('Group/D', value=3, labels = {0:'zero', 1:'un', 2:'deux', 3:'trois'}, attributes={'Highlight':'Blue'})
 
-OL.openGeometry(modelName + '.geo')
+OL.reloadGeometry(modelName + '.geo')
 OL.preProcess(modelName + '.txt.ol')
 
 if OL.action == 'compute' :
diff --git a/contrib/onelab/python/wrappers/Makefile b/contrib/onelab/python/wrappers/Makefile
deleted file mode 100644
index e397889..0000000
--- a/contrib/onelab/python/wrappers/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-all: _onelab.so
-GMSH_DIR=../../../../
-COMMON_DIR=$(GMSH_DIR)/Common
-CPPFLAGS+= $(shell python-config --includes) -I$(COMMON_DIR) -DONELAB_LOADER
-
-onelab_wrap.cpp : onelab.i
-	swig -python -c++ ${CPPFLAGS} -o $@ $<
-
-_onelab.so : onelab_wrap.cpp
-	$(CXX) -shared onelab_wrap.cpp -o $@ $(CPPFLAGS) -fPIC -DSWIG
-.PRECIOUS: $(OBJDIR)/%.o
diff --git a/contrib/onelab/python/wrappers/OnelabClient.py b/contrib/onelab/python/wrappers/OnelabClient.py
deleted file mode 100755
index 3677a6a..0000000
--- a/contrib/onelab/python/wrappers/OnelabClient.py
+++ /dev/null
@@ -1,59 +0,0 @@
-import onelab
-import sys
-
-class client :
-
-  def get_number(self, name, default, label = '', min = -sys.float_info.max, max = sys.float_info.max, step = 0, choices = [], labels = [], attributes = {}, help = "", visible = 1, read_only = 0) :
-    if not self.client :
-      return default
-    n = onelab.number(name, default)
-    n.setLabel(label)
-    n.setVisible(visible)
-    n.setReadOnly(read_only)
-    n.setMin(min)
-    n.setMax(max)
-    n.setStep(step)
-    n.setHelp(help)
-    n.setChoices(choices)
-    if labels :
-      n.setChoices([k for k in labels.keys()])
-      n.setChoiceLabels([v for v in labels.values()])
-    for k,v in attributes.items() :
-      n.setAttribute(k, v)
-    r = onelab.OnelabNumberVector()
-    self.client.get(r, n.getName())
-    if r :
-      return r[0].getValue()
-    else :
-      self.client.set(n)
-      return default
-
-  def get_string(self, name, default, choices = [], help ="", label = "", visible = 1, read_only = 0, kind = "generic", attributes = {}) :
-    if not self.client :
-      return default
-    n = onelab.string(name, default)
-    n.setChoices(choices)
-    n.setReadOnly(read_only)
-    n.setVisible(visible)
-    n.setLabel(label)
-    n.setHelp(help)
-    n.setKind(kind)
-    r = onelab.OnelabStringVector()
-    for k,v in attributes.items() :
-      n.setAttribute(k, v)
-    self.client.get(r, n.getName())
-    if r :
-      return r[0].getValue()
-    else :
-      self.client.set(n)
-      return default
-
-  def __init__(self):
-    self.client = None
-    self.name = ""
-    for i, v in enumerate(sys.argv) :
-      if v == '-onelab':
-        self.name = sys.argv[i + 1]
-        self.client = onelab.remoteNetworkClient(self.name, sys.argv[i+2])
-    self.action = self.get_string(self.name + '/Action', 'compute')
-    if self.action == "initialize": exit(0)
diff --git a/contrib/onelab/python/wrappers/onelab.i b/contrib/onelab/python/wrappers/onelab.i
deleted file mode 100644
index 21c18c2..0000000
--- a/contrib/onelab/python/wrappers/onelab.i
+++ /dev/null
@@ -1,15 +0,0 @@
-%module onelab
-%{
-#include "onelab.h"
-onelab::server *onelab::server::_server = 0;
-%}
- 
-%include std_string.i
-%include std_vector.i
-%include std_map.i
-%template(OnelabNumberVector) std::vector<onelab::number>;
-%template(OnelabStringVector) std::vector<onelab::string>;
-%template(DoubleVector) std::vector<double>;
-%template(StringVector) std::vector<std::string>;
-%template(DoubleStringMap) std::map<double, std::string>;
-%include "onelab.h"
diff --git a/contrib/onelab/python/wrappers/test.ol b/contrib/onelab/python/wrappers/test.ol
deleted file mode 100755
index 79463f5..0000000
--- a/contrib/onelab/python/wrappers/test.ol
+++ /dev/null
@@ -1,2 +0,0 @@
-Native.register(native, ./test.py);
-Native.run();
diff --git a/contrib/onelab/python/wrappers/test.py b/contrib/onelab/python/wrappers/test.py
deleted file mode 100755
index 631bb70..0000000
--- a/contrib/onelab/python/wrappers/test.py
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env python
-#coding=utf-8
-import OnelabClient
-
-oc = OnelabClient.client()
-
-#name and default value are required
-A = oc.get_number('A', 10)
-#other attributes are optionals
-B = oc.get_number('Group/B', 0, min = -10, max = 10, step = 1)
-C = oc.get_number('Group/C', 2, choices = [0, 1, 2, 3], attributes={'Highlight':'Pink'})
-D = oc.get_number('Group/D', 2, labels = {0:'zero', 1:'un', 2:'deux', 3:'trois'}, attributes={'Highlight':'Blue'})
-#utf-8 are allowed everywhere (should be prefixed by 'u' in python 2, not required in python 3)
-Omega = oc.get_string(u'Ω', u'∫(∂φ/∂α)³dx', help=u'ask someone at universe.org', choices = ['oui', 'non', u'peut-être'])
-
-if oc.action != 'compute' :
-  exit(0)
-
-#this is the solver code
-print (A, B, C, str(Omega))
diff --git a/demos/piece-extr-rec.geo b/demos/piece-extr-rec.geo
index 6de76bb..f5bf6d2 100644
--- a/demos/piece-extr-rec.geo
+++ b/demos/piece-extr-rec.geo
@@ -36,12 +36,12 @@ i = 0 ;
 
 For(1:4)
 
-  i+=1 ; 
+  i+=1 ;
 
   Rotate {{0.0,0.0,1.0},{0.0,0.0,0.0}, i*r} {
     Duplicata {
-      Line{1}; Line{2}; Line{3}; 
-      Line{4}; Line{5}; Line{6}; 
+      Line{1}; Line{2}; Line{3};
+      Line{4}; Line{5}; Line{6};
       Point{10};
     }
   }
@@ -82,17 +82,17 @@ Plane Surface(49) = {48,46};
 ones[]={1,1,1,1,1,1,1,1,1,1};
 ep[]={0.01, 0.05, 0.1, 0.2, 0.5, 0.8, 0.9, 0.95, 0.99, 1};
 For i In {0:4}
-  ep2[i]=2*ep[i]; 
+  ep2[i]=2*ep[i];
 EndFor
 
-Recombine Surface {47,49,91};
+Recombine Surface {47,49};
 
-Extrude {0,0,0.2}{ 
-  Surface{47,49}; Layers{ ones[], ep[] }; Recombine; 
+Extrude {0,0,0.2}{
+  Surface{47,49}; Layers{ ones[], ep[] }; Recombine;
 }
 Extrude {0,0,0.2}{
-  Surface{91}; Layers{ ones[{0:4}], ep2[] }; Recombine; 
+  Surface{91}; Layers{ ones[{0:4}], ep2[] }; Recombine;
 }
 Extrude {0,0,-0.2}{
-  Surface{47}; Layers{ ones[{0:4}], ep2[] }; Recombine; 
+  Surface{47}; Layers{ ones[{0:4}], ep2[] }; Recombine;
 }
diff --git a/doc/CREDITS.txt b/doc/CREDITS.txt
index 861a14b..24bc6a5 100644
--- a/doc/CREDITS.txt
+++ b/doc/CREDITS.txt
@@ -21,8 +21,10 @@ Ruth Sabariego (pyramids), Stephen Guzik (CGNS and partitioners), Bastien
 Gorissen (parallel remote post-processing), Eric Bechet (solver), Gilles
 Marckmann (camera and stero mode), Ashish Negi (Salome/Netgen CAD healing),
 Trevor Strickler (structured/unstructured coupling with pyramids), Amaury Johnen
-(Bezier), Benjamin Ruard (Java wrappers). See comments in the sources for more
-information. If we forgot to list your contributions please send us an email!
+(Bezier), Benjamin Ruard (Java wrappers), Maxime Graulich (iOS/Android port),
+Francois Henrotte (onelab metamodels), Sebastian Eiser (PGF output), Alexis
+Salzman (compressed IO). See comments in the sources for more information. If we
+forgot to list your contributions please send us an email!
 
 The AVL tree code (Common/avl.*) and the YUV image code (Graphics/gl2yuv.*) are
 copyright (C) 1988-1993, 1995 The Regents of the University of
@@ -128,4 +130,4 @@ Van den Abeele, Simon Vun, Simon Corbin, Thomas De-Soza, Marcus Drosson, Antoine
 Dechaume, Jose Paulo Moitinho de Almeida, Thomas Pinchard, Corrado Chisari, Axel
 Hackbarth, Peter Wainwright, Jiri Hnidek, Thierry Thomas, Konstantinos Poulios,
 Laurent Van Miegroet, Shahrokh Ghavamian, Geordie McBain, Jose Paulo Moitinho de
-Almeida, Guillaume Demesy, Wendy Merks-Swolfs.
+Almeida, Guillaume Demesy, Wendy Merks-Swolfs, Cosmin Stefan Deaconu.
diff --git a/doc/VERSIONS.txt b/doc/VERSIONS.txt
index 5b35861..07c88d2 100644
--- a/doc/VERSIONS.txt
+++ b/doc/VERSIONS.txt
@@ -1,6 +1,12 @@
+2.8.5 (Jul 9, 2014): improved stability and error handling, better Coherence
+function, updated onelab API version and inline parameter definitions, new
+background image modes, more robust Triangulate/Tetrahedralize plugins, new PGF
+output, improved support for string~index variable names in parser, small
+improvements and bug fixes all over the place.
+
 2.8.4 (Feb 7, 2014): better reproductibility of 2D meshes; new mandatory 'Name'
-attribute to define onelab variables in DefineConstant[] & co; small
-improvements and bug fixes.
+attribute to define onelab variables in DefineConstant[] & co; new
+-setnumber/-setstring command line arguments; small improvements and bug fixes.
 
 2.8.3 (Sep 27, 2013): new quick access menu and multiple view selection in GUI;
 enhanced animation creation; many small enhancements and bug fixes.
diff --git a/doc/gmsh.html b/doc/gmsh.html
index 630bf5f..871f9ff 100644
--- a/doc/gmsh.html
+++ b/doc/gmsh.html
@@ -29,7 +29,7 @@ generator with built-in pre- and post-processing facilities</h1>
 
 <h4 align="center">Christophe Geuzaine and Jean-Fran�ois Remacle</h4>
 
-<h4 align="center">Version 2.8.4, February 7 2014</h4>
+<h4 align="center">Version 2.8.5, July 9 2014</h4>
 
 <center>
   <a href="#Description">Description</a> |
@@ -69,14 +69,14 @@ the <a href="doc/LICENSE.txt">GNU General Public License
   <li>
     <p class="highlight">
       <strong>Current stable release</strong>: Windows
-      <a href="bin/Windows/gmsh-2.8.4-Windows.zip"><strong>32 bit</strong></a> /
-      <a href="bin/Windows/gmsh-2.8.4-Windows64.zip"><strong>64 bit</strong></a>,
+      <a href="bin/Windows/gmsh-2.8.5-Windows.zip"><strong>32 bit</strong></a> /
+      <a href="bin/Windows/gmsh-2.8.5-Windows64.zip"><strong>64 bit</strong></a>,
       Linux
-      <a href="bin/Linux/gmsh-2.8.4-Linux.tgz"><strong>32 bit</strong></a> /
-      <a href="bin/Linux/gmsh-2.8.4-Linux64.tgz"><strong>64 bit</strong></a>,
-      <a href="bin/MacOSX/gmsh-2.8.4-MacOSX.dmg"><strong>Mac OS X</strong></a>
+      <a href="bin/Linux/gmsh-2.8.5-Linux.tgz"><strong>32 bit</strong></a> /
+      <a href="bin/Linux/gmsh-2.8.5-Linux64.tgz"><strong>64 bit</strong></a>,
+      <a href="bin/MacOSX/gmsh-2.8.5-MacOSX.dmg"><strong>Mac OS X</strong></a>
       and
-      <a href="src/gmsh-2.8.4-source.tgz"><strong>source code</strong></a>
+      <a href="src/gmsh-2.8.5-source.tgz"><strong>source code</strong></a>
     </p>
     <p>
       <em>A <a href="doc/texinfo/gmsh.html#Tutorial"><strong>tutorial</strong></a>
@@ -255,9 +255,12 @@ alt="Screenshot thumbnail"></a>
   <li>Gmsh's cross-platform graphical user interface is based
     on <a href="http://www.fltk.org/">FLTK</a>
     and <a href="http://www.opengl.org/">OpenGL</a>.
-  <li>Make sure to also check out <a href="/getdp/">GetDP</a>, a rather
-    general finite element code that can be used right from Gmsh's
-    graphical user interface.
+  <li>Gmsh implements a <a href="http://onelab.info">ONELAB</a> server to drive
+    external solvers, as for example the open source finite
+    solver <a href="/getdp/">GetDP</a>. 
+  <li>Gmsh and GetDP are bundled in the
+    <a href="http://onelab.info/wiki/Mobile">Onelab/Mobile</a> app for iPhone,
+    iPad and Android devices.
 </ul>
 
 <h2><a name="References"></a>References</h2>
@@ -265,99 +268,99 @@ alt="Screenshot thumbnail"></a>
 <div class="small">
   Gmsh
   <ul class="small">
-    <li>C. Geuzaine and J.-F. Remacle. <em>Gmsh: a three-dimensional finite
-      element mesh generator with built-in pre- and post-processing
-      facilities</em>. International Journal for Numerical Methods in
-      Engineering 79(11), pp. 1309-1331, 2009.
-      (<a href="doc/preprints/gmsh_paper_preprint.pdf">PDF</a>)
+    <li>C. Geuzaine and
+      J.-F. Remacle. <em><a href="doc/preprints/gmsh_paper_preprint.pdf">Gmsh: a
+      three-dimensional finite element mesh generator with built-in pre- and
+      post-processing facilities</a></em>. International Journal for Numerical
+      Methods in Engineering 79(11), pp. 1309-1331, 2009.
     </li>
   </ul>
   Cross-patch and STL meshing (Compounds)
   <ul class="small">
     <li>J.-F. Remacle, C. Geuzaine, G. Comp�re and
-      E. Marchandise. <em>High-quality surface remeshing using harmonic
-      maps</em>.  International Journal for Numerical Methods in Engineering
-      83(4), pp. 403-425, 2010.
-      (<a href="doc/preprints/gmsh_stl_preprint.pdf">PDF</a>)
+      E. Marchandise. <em><a href="doc/preprints/gmsh_stl_preprint.pdf">High-quality
+      surface remeshing using harmonic maps</a></em>.  International Journal for
+      Numerical Methods in Engineering 83(4), pp. 403-425, 2010.
     <li>E. Marchandise, C. Carton de Wiart, W. G. Vos, C. Geuzaine and
-      J.-F. Remacle.  <em>High quality surface remeshing using harmonic
-      maps. Part II: surfaces with high genus and of large aspect ratio</em>.
-      International Journal for Numerical Methods in Engineering 86(11),
-      pp. 1303-1321, 2011.
-      (<a href="doc/preprints/gmsh_stl2_preprint.pdf">PDF</a>)
-    <li>E. Marchandise, J.-F. Remacle and C. Geuzaine. <em>Optimal
-      parametrizations for surface remeshing</em>. Engineering with Computers,
-      December 2012, pp. 1-20.
-      (<a href="doc/preprints/gmsh_stl3_preprint.pdf">PDF</a>)
+      J.-F. Remacle.  <em><a href="doc/preprints/gmsh_stl2_preprint.pdf">High
+      quality surface remeshing using harmonic maps. Part II: surfaces with high
+      genus and of large aspect ratio</a></em>.  International Journal for Numerical
+      Methods in Engineering 86(11), pp. 1303-1321, 2011.
+    <li>E. Marchandise, J.-F. Remacle and
+      C. Geuzaine. <em><a href="doc/preprints/gmsh_stl3_preprint.pdf">Optimal
+      parametrizations for surface remeshing</a></em>. Engineering with
+      Computers, December 2012, pp. 1-20.
   </ul>
   Quad meshing (Blossom and DelQuad)
   <ul class="small">
     <li>
       J.-F. Remacle, J. Lambrechts, B. Seny, E. Marchandise, A. Johnen and
-      C. Geuzaine. <em>Blossom-Quad: a non-uniform quadrilateral mesh generator
-      using a minimum cost perfect matching algorithm</em>.  International
-      Journal for Numerical Methods in Engineering 89, pp. 1102-1119, 2012.
-      (<a href="doc/preprints/gmsh_quad_preprint.pdf">PDF</a>)
+      C. Geuzaine. <em><a href="doc/preprints/gmsh_quad_preprint.pdf">Blossom-Quad:
+      a non-uniform quadrilateral mesh generator using a minimum cost perfect
+      matching algorithm</a></em>.  International Journal for Numerical Methods
+      in Engineering 89, pp. 1102-1119, 2012.
     <li>J.-F. Remacle, F. Henrotte, T. Carrier-Baudouin, E. B�chet,
-      E. Marchandise, C. Geuzaine and T. Mouton. <em>A frontal Delaunay quad
-      mesh generator using the L∞ norm</em>.  International Journal for
-      Numerical Methods in Engineering, 94(5), pp. 494-512, 2013.
-      (<a href="doc/preprints/gmsh_quad2_preprint.pdf">PDF</a>)
+      E. Marchandise, C. Geuzaine and
+      T. Mouton. <em><a href="doc/preprints/gmsh_quad2_preprint.pdf">A frontal
+      Delaunay quad mesh generator using the L∞ norm</a></em>.
+      International Journal for Numerical Methods in Engineering, 94(5),
+      pp. 494-512, 2013.
   </ul>
   High-order meshing
   <ul class="small">
-    <li>A. Johnen, J.-F. Remacle and C. Geuzaine. <em>Geometric validity of
-      high-Order triangular finite elements</em>. Engineering with Computers, in
-      press, 2012.
-      (<a href="doc/preprints/gmsh_curved2_preprint.pdf">PDF</a>)
-    <li>A. Johnen, J.-F. Remacle and C. Geuzaine. <em>Geometric validity of
-        curvilinear finite elements</em>. Journal of Computational Physics, in
-      press, 2012.
-      (<a href="doc/preprints/gmsh_curved_preprint.pdf">PDF</a>)
-    <li>T. Toulorge, C. Geuzaine, J.-F. Remacle, J. Lambrechts. <em>Robust
-        untangling of curvilinear meshes</em>. Journal of Computational Physics
-      254, pp. 8-26, 2013.
-      (<a href="doc/preprints/gmsh_untangling_preprint.pdf">PDF</a>)
+    <li>A. Johnen, J.-F. Remacle and
+      C. Geuzaine. <em><a href="doc/preprints/gmsh_curved2_preprint.pdf">Geometric
+      validity of high-Order triangular finite elements</a></em>. Engineering
+      with Computers, in press, 2012.
+    <li>A. Johnen, J.-F. Remacle and
+        C. Geuzaine. <em><a href="doc/preprints/gmsh_curved_preprint.pdf">Geometric
+        validity of curvilinear finite elements</a></em>. Journal of
+        Computational Physics, in press, 2012.
+    <li>T. Toulorge, C. Geuzaine, J.-F. Remacle,
+        J. Lambrechts. <em><a href="doc/preprints/gmsh_untangling_preprint.pdf">Robust
+        untangling of curvilinear meshes</a></em>. Journal of Computational
+        Physics 254, pp. 8-26, 2013.
   </ul>
   High-order visualization
   <ul class="small">
     <li>J.-F. Remacle, N. Chevaugeon, E. Marchandise and
-      C. Geuzaine. <em>Efficient visualization of high-order finite
-      elements</em>. International Journal for Numerical Methods in Engineering
-      69(4), pp. 750-771, 2007. (<a href="doc/preprints/gmsh_visu_preprint.pdf">PDF</a>)
+      C. Geuzaine. <em><a href="doc/preprints/gmsh_visu_preprint.pdf">Efficient
+      visualization of high-order finite elements</a></em>. International Journal
+      for Numerical Methods in Engineering 69(4), pp. 750-771, 2007.
   </ul>
   Homology solver
   <ul class="small">
-    <li>M. Pellikka, S. Suuriniemi, L. Kettunen and C. Geuzaine. <em>Homology
-      and cohomology computation in finite element modeling</em>. SIAM Journal
-      on Scientific Computing 35(5), pp. 1195-1214, 2013.
-      (<a href="doc/preprints/gmsh_homology_preprint.pdf">PDF</a>)
+    <li>M. Pellikka, S. Suuriniemi, L. Kettunen and
+      C. Geuzaine. <em><a href="doc/preprints/gmsh_homology_preprint.pdf">Homology
+      and cohomology computation in finite element modeling</a></em>. SIAM
+      Journal on Scientific Computing 35(5), pp. 1195-1214, 2013.
   </ul>
 <!--
   Ocean meshing
   <ul class="small">
     <li>J. Lambrechts, R. Comblen, V. Legat, C. Geuzaine and
-      J.-F. Remacle. <em>Multiscale mesh generation on the sphere</em>. Ocean
+      J.-F. Remacle. <em><a href="doc/preprints/gmsh_ocean_preprint.pdf">Multiscale
+       mesh generation on the sphere</a></em>. Ocean
       Dynamics, 58, pp. 461-473, 2008. 
-      (<a href="doc/preprints/gmsh_ocean_preprint.pdf">PDF</a>)
   </ul>
   Biomedical meshing
   <ul class="small">
     <li>E. Marchandise, G. Comp�re, M. Willemet, G. Bricteux, C. Geuzaine and
-      J-F Remacle. <em>Quality meshing based on STL triangulations for
-      biomedical simulations</em>. International Journal for Numerical Methods
-      in Biomedical Engineering 26(7), pp. 876-889,
-      2010. (<a href="doc/preprints/gmsh_bio_preprint.pdf">PDF</a>)
+      J-F Remacle. <em><a href="doc/preprints/gmsh_bio_preprint.pdf">Quality
+      meshing based on STL triangulations for biomedical simulations</a></em>.
+      International Journal for Numerical Methods in Biomedical Engineering
+      26(7), pp. 876-889, 2010.
     <li>E. Marchandise, P. Crosetto, C. Geuzaine, J.-F. Remacle and
-      E. Sauvage. <em>Quality open source mesh generation for cardiovascular
-      flow simulations</em>, in Modelling Physiological Flow, Springer Series on
-      Modeling, Simulation and Applications (Editors: D. Ambrosi, A. Quarteroni,
+      E. Sauvage. <em><a href="doc/preprints/gmsh_bio2_preprint.pdf">Quality
+      open source mesh generation for cardiovascular flow simulations</a></em>,
+      in Modelling Physiological Flow, Springer Series on Modeling, Simulation
+      and Applications (Editors: D. Ambrosi, A. Quarteroni,
       G. Rozza). Springer-Verlag, Berlin Heidelberg, 2011.
-      (<a href="doc/preprints/gmsh_bio2_preprint.pdf">PDF</a>)
-    <li>E. Marchandise, C. Geuzaine and J.-F. Remacle. <em>Cardiovascular and
-      lung mesh generation based on centerlines</em>. International Journal for
-      Numerical Methods in Biomedical Engineering, submitted,
-      2012. (<a href="doc/preprints/gmsh_bio3_preprint.pdf">PDF</a>)
+    <li>E. Marchandise, C. Geuzaine and
+      J.-F. Remacle. <em><a href="doc/preprints/gmsh_bio3_preprint.pdf">Cardiovascular
+      and lung mesh generation based on centerlines</a></em>. International
+      Journal for Numerical Methods in Biomedical Engineering, submitted,
+      2012.
   </ul>
 -->
 </div>
diff --git a/doc/texinfo/commandline.texi b/doc/texinfo/commandline.texi
index 99be7c0..bc9b014 100644
--- a/doc/texinfo/commandline.texi
+++ b/doc/texinfo/commandline.texi
@@ -35,7 +35,7 @@ Save all elements (discard physical group definitions)
 @item -parametric
 Save vertices with their parametric coordinates
 @item -algo string
-Select mesh algorithm (meshadapt, del2d, front2d, delquad, del3d, front3d, mmg3d)
+Select mesh algorithm (meshadapt, del2d, front2d, delquad, del3d, front3d, mmg3d, pack)
 @item -smooth int
 Set number of mesh smoothing steps
 @item -order int
@@ -71,7 +71,7 @@ Load background mesh from file
 @item -check
 Perform various consistency checks on mesh
 @item -mpass int
-Do several passes on the mesh for complex backround fields
+Do several passes on the mesh for complex background fields
 @item -ignorePartBound
 Ignore partitions boundaries
 @end ftable
@@ -121,6 +121,8 @@ Print process id on stdout
 Always listen to incoming connection requests
 @item -watch pattern
 Pattern of files to merge as they become available
+ at item -bg file
+Load background (image or PDF) file
 @item -v int
 Set verbosity level
 @item -nopopup
diff --git a/doc/texinfo/gmsh.texi b/doc/texinfo/gmsh.texi
index 4057c4e..a16b3e8 100644
--- a/doc/texinfo/gmsh.texi
+++ b/doc/texinfo/gmsh.texi
@@ -22,7 +22,7 @@
 @c %**start of header
 @setfilename gmsh.info
 @set GMSH-VERSION 2.8
- at set COPYRIGHT @copyright{} 1997-2013 Christophe Geuzaine, Jean-Fran@,{c}ois Remacle
+ at set COPYRIGHT @copyright{} 1997-2014 Christophe Geuzaine, Jean-Fran@,{c}ois Remacle
 @settitle Gmsh @value{GMSH-VERSION}
 @footnotestyle separate
 @setchapternewpage odd
@@ -982,7 +982,10 @@ parsing of the script file:
   StrFind(@var{char-expression}, @var{char-expression}) |
   StrCmp(@var{char-expression}, @var{char-expression}) |
   TextAttributes(@var{char-expression}<, at var{char-expression}@dots{}>) |
-  GetValue("@var{string}", @var{expression})
+  Exists(@var{string}) | Exists(@var{string}~@{ @var{expression} @}) |
+  FileExists(@var{char-expression}) |
+  DefineNumber(@var{expression}, @var{onelab-options})
+  GetValue("@var{string}", @var{expression}) |
 @end example
 
 Such @w{@var{expression}s} are used in most of Gmsh's scripting
@@ -1004,8 +1007,8 @@ x_2 = 2;
 x_3 = 3;
 @end example
 
-The brackets @code{[]} permit to extract one item from a list and to get
-the size of a list, respectively. The operators
+The brackets @code{[]} permit to extract one item from a list. The
+ at code{#} permits to get the size of a list. The operators
 @var{operator-unary-left}, @var{operator-unary-right},
 @var{operator-binary}, @var{operator-ternary-left} and
 @var{operator-ternary-right} are defined in @ref{Operators}. For the
@@ -1016,7 +1019,15 @@ for any occurrence of the second @var{char-expression}. @code{StrCmp}
 compares the two strings (returns an integer greater than, equal to, or
 less than 0, according as the first string is greater than, equal to, or
 less than the second string).  @code{TextAttributes} creates attributes
-for text strings.
+for text strings. @code{Exists} checks if a variable with the given name
+exists (i.e., has been defined previously), and @code{FileExists} checks
+if the file with the given name exists.
+
+ at code{DefineNumber} allows to define a ONELAB variable in-line. The
+ at var{expression} given as the first argument is the default value; this
+is followed by the various ONELAB options. See
+ at uref{http://onelab.info/wiki/ONELAB_Syntax_for_Gmsh_and_GetDP} for more
+information.
 
 The last case in the definition allows to ask the user for a value
 interactively. For example, inserting @code{GetValue("Value of parameter
@@ -1095,7 +1106,7 @@ Character expressions are defined as:
 @example
 @var{char-expression}:
   "@var{string}" |
-  Today |
+  Today | OnelabAction |
   StrPrefix ( @var{char-expression} ) |
   StrRelative ( @var{char-expression} ) |
   StrCat ( @var{char-expression} , @var{char-expression} ) |
@@ -1106,6 +1117,7 @@ Character expressions are defined as:
   GetEnv ( @var{char-expression} ) |
   GetString ( @var{char-expression} , @var{char-expression} ) | 
   StrReplace ( @var{char-expression} , @var{char-expression} , @var{char-expression} ) 
+  DefineString(@var{char-expression}, @var{onelab-options})
 @end example
 
 @noindent @code{StrPrefix} and @code{StrRelative} permit to take the
@@ -1123,6 +1135,12 @@ string, old substring, new substring. at footnote{For compatibility with GetDP
 (@uref{http://geuz.org/getdp/}), parentheses can be replaced by brackets
 @code{[]} in @code{Str} and @code{Sprintf}.}
 
+ at code{DefineString} allows to define a ONELAB variable in-line. The
+ at var{char-expression} given as the first argument is the default value; this
+is followed by the various ONELAB options. See
+ at uref{http://onelab.info/wiki/ONELAB_Syntax_for_Gmsh_and_GetDP} for more
+information.
+
 Character expressions are mostly used to specify non-numeric options and
 input/output file names. See @ref{t8.geo}, for an interesting usage of
 @w{@var{char-expression}s} in an animation script.
@@ -1516,6 +1534,9 @@ Returns the current CPU time (in seconds).
 @item Memory
 Returns the current memory usage (in Mb).
 
+ at item TotalMemory
+Returns the total memory available (in Mb).
+
 @item newp
 Returns the next available point number. As explained in @ref{Geometry
 module}, a unique number must be associated with every geometrical point:
@@ -1607,6 +1628,16 @@ Divides and affects, item per item, the right hand side
 Creates a new character expression identifier @code{@var{string}} with a
 given @var{char-expression}.
 
+ at item DefineConstant[ @var{string} = @var{expression}|@var{char-expression} <, ...>];
+Creates a new expression identifier @var{string}, with value
+ at var{expression}, only if has not been defined before.
+
+ at item DefineConstant[ @var{string} = @{ @var{expression}|@var{char-expression}, @var{onelab-options} @} <, ...>];
+Same as the previous case, except that the variable is also exchanged
+with the ONELAB database if it has not been defined before. See
+ at uref{http://onelab.info/wiki/ONELAB_Syntax_for_Gmsh_and_GetDP} for more
+information.
+
 @item @var{real-option} = @var{expression};
 Affects @var{expression} to a real option.
 
@@ -2856,6 +2887,9 @@ Saves the mesh in a file named @var{char-expression}, using the current
 @var{char-expression} is not absolute, @var{char-expression} is appended
 to the path of the current file.
 
+ at item CreateDir @var{char-expression};
+Create the directory @var{char-expression}.
+
 @item < Recursive > Show @{ Point | Line | Surface | Volume @{ @var{expression-list} @}; @dots{} @}
 Shows the mesh of the entities in @var{expression-list}, if
 @code{General.VisibilityMode} is set to @code{0} or @code{2}.
@@ -4674,6 +4708,23 @@ repository, go in the gmsh directory and type:
 svn commit
 @end example
 
+ at item
+If you want to remove part of the tree from being downloaded, you can
+change its ``ambiant'' depth to ``empty''. For example, if you don't
+want to upate the ``projects'' subdirectory (as well as its
+subdirectories), type:
+
+ at example
+cd projects
+svn update --set-depth empty
+ at end example
+
+To later restore the projects for recursive updating, type:
+ at example
+cd projects
+svn update --set-depth infinity
+ at end example
+
 @end enumerate
 
 Once you have the source code, you need to run CMake to configure your
diff --git a/doc/texinfo/opt_fields.texi b/doc/texinfo/opt_fields.texi
index 35f445c..9bee17c 100644
--- a/doc/texinfo/opt_fields.texi
+++ b/doc/texinfo/opt_fields.texi
@@ -374,6 +374,16 @@ type: integer@*
 default value: @code{0}
 @end table
 
+ at item IntersectAniso
+Take the intersection of 2 anisotropic fields according to Alauzet.@*
+Options:@*
+ at table @code
+ at item FieldsList
+Field indices@*
+type: list@*
+default value: @code{@{@}}
+ at end table
+
 @item Laplacian
 Compute finite difference the Laplacian of Field[IField]:@*
 @*
@@ -589,6 +599,39 @@ type: list@*
 default value: @code{@{@}}
 @end table
 
+ at item Sphere
+The value of this field is VIn inside a sphere, VOut outside. The sphere is given by@*
+@*
+  ||dX||^2 < R^2 &&@*
+  dX = (X - XC)^2 + (Y-YC)^2 + (Z-ZC)^2@*
+Options:@*
+ at table @code
+ at item Radius
+Radius@*
+type: float@*
+default value: @code{0}
+ at item VIn
+Value inside the sphere@*
+type: float@*
+default value: @code{0}
+ at item VOut
+Value outside the sphere@*
+type: float@*
+default value: @code{0}
+ at item XCenter
+X coordinate of the sphere center@*
+type: float@*
+default value: @code{0}
+ at item YCenter
+Y coordinate of the sphere center@*
+type: float@*
+default value: @code{0}
+ at item ZCenter
+Z coordinate of the sphere center@*
+type: float@*
+default value: @code{0}
+ at end table
+
 @item Structured
 Linearly interpolate between data provided on a 3D rectangular structured grid.@*
 @*
diff --git a/doc/texinfo/opt_general.texi b/doc/texinfo/opt_general.texi
index 396fbd4..54f2d57 100644
--- a/doc/texinfo/opt_general.texi
+++ b/doc/texinfo/opt_general.texi
@@ -35,7 +35,7 @@ Default value: @code{""}@*
 Saved in: @code{General.OptionsFileName}
 
 @item General.BackgroundImageFileName
-Background image file in JPEG or PNG format@*
+Background image file in JPEG, PNG or PDF format@*
 Default value: @code{""}@*
 Saved in: @code{General.OptionsFileName}
 
@@ -254,14 +254,39 @@ Draw background gradient (0=none, 1=vertical, 2=horizontal, 3=radial)@*
 Default value: @code{1}@*
 Saved in: @code{General.OptionsFileName}
 
+ at item General.BackgroundImage3D
+Create background image in the 3D model (units = model units) or as 2D background (units = pixels)@*
+Default value: @code{0}@*
+Saved in: @code{General.OptionsFileName}
+
+ at item General.BackgroundImagePage
+Page to render in the background image (for multi-page PDFs)@*
+Default value: @code{0}@*
+Saved in: @code{General.OptionsFileName}
+
 @item General.BackgroundImagePositionX
-X position (in pixels) of background image (< 0: measure from right edge; >= 1e5: centered)@*
-Default value: @code{100000}@*
+X position of background image (for 2D background: < 0: measure from right window edge; >= 1e5: centered)@*
+Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
 @item General.BackgroundImagePositionY
-Y position (in pixels) of background image (< 0: measure from bottom edge; >= 1e5: centered)@*
-Default value: @code{100000}@*
+Y position of background image (for 2D background: < 0: measure from bottom window edge; >= 1e5: centered)@*
+Default value: @code{0}@*
+Saved in: @code{General.OptionsFileName}
+
+ at item General.BackgroundImageWidth
+Width of background image (0: actual width if height = 0, natural scaling if not; -1: graphic window width)@*
+Default value: @code{-1}@*
+Saved in: @code{General.OptionsFileName}
+
+ at item General.BackgroundImageHeight
+Height of background image (0: actual height if width = 0, natural scaling if not; -1: graphic window height)@*
+Default value: @code{-1}@*
+Saved in: @code{General.OptionsFileName}
+
+ at item General.BoundingBoxSize
+Overall bounding box size (read-only)@*
+Default value: @code{1}@*
 Saved in: @code{General.OptionsFileName}
 
 @item General.Camera
@@ -965,12 +990,12 @@ Default value: @code{1}@*
 Saved in: @code{General.OptionsFileName}
 
 @item General.SmallAxesPositionX
-X position (in pixels) of small axes (< 0: measure from right edge; >= 1e5: centered)@*
+X position (in pixels) of small axes (< 0: measure from right window edge; >= 1e5: centered)@*
 Default value: @code{-60}@*
 Saved in: @code{General.OptionsFileName}
 
 @item General.SmallAxesPositionY
-Y position (in pixels) of small axes (< 0: measure from bottom edge; >= 1e5: centered)@*
+Y position (in pixels) of small axes (< 0: measure from bottom window edge; >= 1e5: centered)@*
 Default value: @code{-40}@*
 Saved in: @code{General.OptionsFileName}
 
diff --git a/doc/texinfo/opt_geometry.texi b/doc/texinfo/opt_geometry.texi
index 8d8eb3b..327f996 100644
--- a/doc/texinfo/opt_geometry.texi
+++ b/doc/texinfo/opt_geometry.texi
@@ -5,7 +5,7 @@
 
 @ftable @code
 @item Geometry.AutoCoherence
-Should all duplicate entities be automatically removed?@*
+Should all duplicate entities be automatically removed? (if ==2, also remove degenerate entities)@*
 Default value: @code{1}@*
 Saved in: @code{General.OptionsFileName}
 
@@ -19,6 +19,11 @@ Copy meshing method (unstructured or transfinite) when duplicating geometrical e
 Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
+ at item Geometry.CopyDisplayAttributes
+Copy display attributes (visibiliy, color) when duplicating geometrical entities?@*
+Default value: @code{0}@*
+Saved in: @code{General.OptionsFileName}
+
 @item Geometry.ExactExtrusion
 Use exact extrusion formula in interpolations (set to 0 to allow geometrical transformations of extruded entities)@*
 Default value: @code{1}@*
diff --git a/doc/texinfo/opt_mesh.texi b/doc/texinfo/opt_mesh.texi
index 0861c0f..8ff1a05 100644
--- a/doc/texinfo/opt_mesh.texi
+++ b/doc/texinfo/opt_mesh.texi
@@ -339,11 +339,6 @@ Split MSH file by mesh partition (0: no, 1: yes, 2: create physicals by partitio
 Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
- at item Mesh.MultiplePassesMeshes
-Do a first simple mesh and use it for complex background meshes (curvatures...)@*
-Default value: @code{0}@*
-Saved in: @code{General.OptionsFileName}
-
 @item Mesh.PartitionHexWeight
 Weight of hexahedral element for METIS load balancing@*
 Default value: @code{1}@*
diff --git a/doc/texinfo/opt_plugin.texi b/doc/texinfo/opt_plugin.texi
index 948e5e6..bba5e25 100644
--- a/doc/texinfo/opt_plugin.texi
+++ b/doc/texinfo/opt_plugin.texi
@@ -5,52 +5,44 @@
 
 @ftable @code
 @item Plugin(AnalyseCurvedMesh)
-Plugin(AnalyseCurvedMesh) check the jacobian of all elements of dimension 'Dim' or the greater model dimension if 'Dim' is either <0 or >3.
-
- Analysis : 0 do nothing
-          +1 find invalid elements (*)
-          +2 compute J_min and J_max of all elements and print some statistics
-
-Effect (for *) : 0 do nothing
-                +1 print a list of invalid elements
-                +2 print some statistics
-                +4 hide valid elements (for GUI)
-
-MaxDepth = 0,1,...
-         0 : only sample the jacobian
-         1 : compute Bezier coefficients
-        2+ : execute a maximum of 1+ subdivision(s)
-
-JacBreak = [0,1[ : if a value of the jacobian <= 'JacBreak' is found, the element is said to be invalid
-
-BezBreak = [0,JacBreak[ : if all Bezier coefficients are > 'BezBreak', the element is said to be valid
-
-Tolerance = R+ , << 1 : tolerance (relatively to J_min and J_max) used during the computation of J_min and J_max
+Plugin(AnalyseCurvedMesh) analyse all elements of a given dimension. It computes, min(J) where J is the scaled Jacobian determinant. Eventually, it computes min(R) where R is the ratio between the smaller and the greater of the eigenvalues of the metric. It creates one or more PView and hides elements for which min(@{J, R@}) < 'Hidding threshold'.@*
+@*
+Parameters:@*
+@*
+- Show [...] = @{0, 1@}: If 0, computes Jacobian and shows min(J). If 1, computes Jacobian and metric and shows min(R).@*
+@*
+- Number of PView = @{0, 1, 2@}: If 1, create one PView with all elements. If 2, create two PView, one with straight-sided elements and one with curved elements.@*
+@*
+- Hidding threshold = [0,1]: Hides all element for which min(R) or min(J) is strictly greater than the threshold. If = 1, no effect, if = 0 hide all elements except invalid.@*
+@*
+- Dimension = @{-1, 1, 2, 3@}: If = -1, analyse element of the greater dimension.@*
+@*
+- Recompute = @{0,1@}: If the mesh has changed, set to 1 to recompute the bounds.@*
+@*
+- Tolerance = ]0, 1[: Tolerance on the computation of min(R) or min(J). It should be at most 0.01 but it can be set to 1 to just check the validity of the mesh.
 Numeric options:
 @table @code
- at item Dim
-Default value: @code{-1}
- at item Analysis
+ at item Show: (0) Jacobian, (1) Metric
+Default value: @code{1}
+ at item Number of PView
 Default value: @code{2}
- at item Effect (1)
-Default value: @code{6}
- at item JacBreak (1)
-Default value: @code{0}
- at item BezBreak (1)
+ at item Hidding threshold
+Default value: @code{0.1}
+ at item Dimension of elements
+Default value: @code{-1}
+ at item Recompute bounds
 Default value: @code{0}
- at item MaxDepth (1,2)
-Default value: @code{20}
- at item Tolerance (2)
+ at item Tolerance
 Default value: @code{0.001}
 @end table
 
 @item Plugin(Annotate)
-Plugin(Annotate) adds the text string `Text', in font `Font' and size `FontSize', in the view `View'. The string is aligned according to `Align'.
-
-If `ThreeD' is equal to 1, the plugin inserts the string in model coordinates at the position (`X',`Y',`Z'). If `ThreeD' is equal to 0, the plugin inserts the string in screen coordinates at the position (`X',`Y').
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Annotate) adds the text string `Text', in font `Font' and size `FontSize', in the view `View'. The string is aligned according to `Align'.@*
+@*
+If `ThreeD' is equal to 1, the plugin inserts the string in model coordinates at the position (`X',`Y',`Z'). If `ThreeD' is equal to 0, the plugin inserts the string in screen coordinates at the position (`X',`Y').@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Annotate) is executed in-place for list-based datasets or creates a new view for other datasets.
 String options:
 @table @code
@@ -78,8 +70,8 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Bubbles)
-Plugin(Bubbles) constructs a geometry consisting of `bubbles' inscribed in the Voronoi of an input triangulation. `ShrinkFactor' allows to change the size of the bubbles. The plugin expects a triangulation in the `z = 0' plane to exist in the current model.
-
+Plugin(Bubbles) constructs a geometry consisting of `bubbles' inscribed in the Voronoi of an input triangulation. `ShrinkFactor' allows to change the size of the bubbles. The plugin expects a triangulation in the `z = 0' plane to exist in the current model.@*
+@*
 Plugin(Bubbles) creates one `.geo' file.
 String options:
 @table @code
@@ -105,10 +97,10 @@ Default value: @code{0}
 @end table
 
 @item Plugin(Curl)
-Plugin(Curl) computes the curl of the field in the view `View'.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Curl) computes the curl of the field in the view `View'.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Curl) creates one new view.
 Numeric options:
 @table @code
@@ -116,17 +108,20 @@ Numeric options:
 Default value: @code{-1}
 @end table
 
- at item Plugin(CutBox)
-Plugin(CutBox) cuts the view `View' with a rectangular box defined by the 4 points (`X0',`Y0',`Z0') (origin), (`X1',`Y1',`Z1') (axis of U), (`X2',`Y2',`Z2') (axis of V) and (`X3',`Y3',`Z3') (axis of W).
-
-The number of points along U, V, W is set with the options `NumPointsU', `NumPointsV' and `NumPointsW'.
-
-If `ConnectPoints' is zero, the plugin creates points; otherwise, the plugin generates hexahedra, quadrangles, lines or points depending on the values of `NumPointsU', `NumPointsV' and `NumPointsW'.
-
-If `Boundary' is zero, the plugin interpolates the view inside the box; otherwise the plugin interpolates the view at its boundary.
-
-If `View' < 0, the plugin is run on the current view.
+ at item Plugin(CurvedBndDist)
+Plugin(CurvedBndDist) ...
 
+ at item Plugin(CutBox)
+Plugin(CutBox) cuts the view `View' with a rectangular box defined by the 4 points (`X0',`Y0',`Z0') (origin), (`X1',`Y1',`Z1') (axis of U), (`X2',`Y2',`Z2') (axis of V) and (`X3',`Y3',`Z3') (axis of W).@*
+@*
+The number of points along U, V, W is set with the options `NumPointsU', `NumPointsV' and `NumPointsW'.@*
+@*
+If `ConnectPoints' is zero, the plugin creates points; otherwise, the plugin generates hexahedra, quadrangles, lines or points depending on the values of `NumPointsU', `NumPointsV' and `NumPointsW'.@*
+@*
+If `Boundary' is zero, the plugin interpolates the view inside the box; otherwise the plugin interpolates the view at its boundary.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(CutBox) creates one new view.
 Numeric options:
 @table @code
@@ -169,14 +164,14 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(CutGrid)
-Plugin(CutGrid) cuts the view `View' with a rectangular grid defined by the 3 points (`X0',`Y0',`Z0') (origin), (`X1',`Y1',`Z1') (axis of U) and (`X2',`Y2',`Z2') (axis of V).
-
-The number of points along U and V is set with the options `NumPointsU' and `NumPointsV'.
-
-If `ConnectPoints' is zero, the plugin creates points; otherwise, the plugin generates quadrangles, lines or points depending on the values of `NumPointsU' and `NumPointsV'.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(CutGrid) cuts the view `View' with a rectangular grid defined by the 3 points (`X0',`Y0',`Z0') (origin), (`X1',`Y1',`Z1') (axis of U) and (`X2',`Y2',`Z2') (axis of V).@*
+@*
+The number of points along U and V is set with the options `NumPointsU' and `NumPointsV'.@*
+@*
+If `ConnectPoints' is zero, the plugin creates points; otherwise, the plugin generates quadrangles, lines or points depending on the values of `NumPointsU' and `NumPointsV'.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(CutGrid) creates one new view.
 Numeric options:
 @table @code
@@ -210,12 +205,12 @@ Default value: @code{-1}
 
 
 @item Plugin(CutParametric)
-Plugin(CutParametric) cuts the view `View' with the parametric function (`X'(u,v), `Y'(u,v), `Z'(u,v)), using `NumPointsU' values of the parameter u in [`MinU', `MaxU'] and `NumPointsV' values of the parameter v in [`MinV', `MaxV'].
-
-If `ConnectPoints' is set, the plugin creates surface or line elements; otherwise, the plugin generates points.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(CutParametric) cuts the view `View' with the parametric function (`X'(u,v), `Y'(u,v), `Z'(u,v)), using `NumPointsU' values of the parameter u in [`MinU', `MaxU'] and `NumPointsV' values of the parameter v in [`MinV', `MaxV'].@*
+@*
+If `ConnectPoints' is set, the plugin creates surface or line elements; otherwise, the plugin generates points.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(CutParametric) creates one new view.
 String options:
 @table @code
@@ -247,12 +242,12 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(CutPlane)
-Plugin(CutPlane) cuts the view `View' with the plane `A'*X + `B'*Y + `C'*Z + `D' = 0.
-
-If `ExtractVolume' is nonzero, the plugin extracts the elements on one side of the plane (depending on the sign of `ExtractVolume').
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(CutPlane) cuts the view `View' with the plane `A'*X + `B'*Y + `C'*Z + `D' = 0.@*
+@*
+If `ExtractVolume' is nonzero, the plugin extracts the elements on one side of the plane (depending on the sign of `ExtractVolume').@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(CutPlane) creates one new view.
 Numeric options:
 @table @code
@@ -275,12 +270,12 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(CutSphere)
-Plugin(CutSphere) cuts the view `View' with the sphere (X-`Xc')^2 + (Y-`Yc')^2 + (Z-`Zc')^2 = `R'^2.
-
-If `ExtractVolume' is nonzero, the plugin extracts the elements inside (if `ExtractVolume' < 0) or outside (if `ExtractVolume' > 0) the sphere.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(CutSphere) cuts the view `View' with the sphere (X-`Xc')^2 + (Y-`Yc')^2 + (Z-`Zc')^2 = `R'^2.@*
+@*
+If `ExtractVolume' is nonzero, the plugin extracts the elements inside (if `ExtractVolume' < 0) or outside (if `ExtractVolume' > 0) the sphere.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(CutSphere) creates one new view.
 Numeric options:
 @table @code
@@ -311,14 +306,14 @@ Default value: @code{10}
 @end table
 
 @item Plugin(Distance)
-Plugin(Distance) computes distances to physical entities in a mesh.
-
-Define the physical entities to which the distance is computed. If Point=0, Line=0, and Surface=0, then the distance is computed to all the boundaries of the mesh (edges in 2D and faces in 3D).
-
-Computation<0. computes the geometrical euclidian distance (warning: different than the geodesic distance), and  Computation=a>0.0 solves a PDE on the mesh with the diffusion constant mu = a*bbox, with bbox being the max size of the bounding box of the mesh (see paper Legrand 2006).
-
-Min Scale and max Scale, scale the distance function. If min Scale<0 and max Scale<0, then no scaling is applied to the distance function.
-
+Plugin(Distance) computes distances to physical entities in a mesh.@*
+@*
+Define the physical entities to which the distance is computed. If Point=0, Line=0, and Surface=0, then the distance is computed to all the boundaries of the mesh (edges in 2D and faces in 3D).@*
+@*
+Computation<0. computes the geometrical euclidian distance (warning: different than the geodesic distance), and  Computation=a>0.0 solves a PDE on the mesh with the diffusion constant mu = a*bbox, with bbox being the max size of the bounding box of the mesh (see paper Legrand 2006).@*
+@*
+Min Scale and max Scale, scale the distance function. If min Scale<0 and max Scale<0, then no scaling is applied to the distance function.@*
+@*
 Plugin(Distance) creates a new distance view and also saves the view in the fileName.pos file.
 String options:
 @table @code
@@ -344,10 +339,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Divergence)
-Plugin(Divergence) computes the divergence of the field in the view `View'.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Divergence) computes the divergence of the field in the view `View'.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Divergence) creates one new view.
 Numeric options:
 @table @code
@@ -356,10 +351,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Eigenvalues)
-Plugin(Eigenvalues) computes the three real eigenvalues of each tensor in the view `View'.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Eigenvalues) computes the three real eigenvalues of each tensor in the view `View'.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Eigenvalues) creates three new scalar views.
 Numeric options:
 @table @code
@@ -368,12 +363,12 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Eigenvectors)
-Plugin(Eigenvectors) computes the three (right) eigenvectors of each tensor in the view `View' and sorts them according to the value of the associated eigenvalues.
-
-If `ScaleByEigenvalues' is set, each eigenvector is scaled by its associated eigenvalue. The plugin gives an error if the eigenvectors are complex.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Eigenvectors) computes the three (right) eigenvectors of each tensor in the view `View' and sorts them according to the value of the associated eigenvalues.@*
+@*
+If `ScaleByEigenvalues' is set, each eigenvector is scaled by its associated eigenvalue. The plugin gives an error if the eigenvectors are complex.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Eigenvectors) creates three new vector view.
 Numeric options:
 @table @code
@@ -384,8 +379,8 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(ExtractEdges)
-Plugin(ExtractEdges) extracts sharp edges from a triangular mesh.
-
+Plugin(ExtractEdges) extracts sharp edges from a triangular mesh.@*
+@*
 Plugin(ExtractEdges) creates one new view.
 Numeric options:
 @table @code
@@ -396,10 +391,10 @@ Default value: @code{1}
 @end table
 
 @item Plugin(ExtractElements)
-Plugin(ExtractElements) extracts some elements from the view `View'. If `MinVal' != `MaxVal', it extracts the elements whose `TimeStep'-th values (averaged by element) are comprised between `MinVal' and `MaxVal'. If `Visible' != 0, it extracts visible elements. 
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(ExtractElements) extracts some elements from the view `View'. If `MinVal' != `MaxVal', it extracts the elements whose `TimeStep'-th values (averaged by element) are comprised between `MinVal' and `MaxVal'. If `Visible' != 0, it extracts visible elements. @*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(ExtractElements) creates one new view.
 Numeric options:
 @table @code
@@ -418,12 +413,12 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(FaultZone)
-Plugin(FaultZone) convert all the embedded lines of an existing surfacic mesh to flat quadrangles. Flat quadrangles represent joint elements suitable to model a fault zone with Code_Aster.
-
-`SurfaceTag' must be an existing plane surface containing embedded lines. Embedded lines must have been added to the surface via the command Line In Surface. The surface must be meshed with quadratic incomplete elements.
-
-`Thickness' is the thichness of the flat quadrangles. Set a value different to zero can be helpfull to check the connectivity. 
-
+Plugin(FaultZone) convert all the embedded lines of an existing surfacic mesh to flat quadrangles. Flat quadrangles represent joint elements suitable to model a fault zone with Code_Aster.@*
+@*
+`SurfaceTag' must be an existing plane surface containing embedded lines. Embedded lines must have been added to the surface via the command Line In Surface. The surface must be meshed with quadratic incomplete elements.@*
+@*
+`Thickness' is the thichness of the flat quadrangles. Set a value different to zero can be helpfull to check the connectivity. @*
+@*
 `Prefix' is the prefix of the name of physicals containing the new embedded. All physicals containing embedded lines are replaced by physicals containing the coresponding joint elements.
 String options:
 @table @code
@@ -439,10 +434,10 @@ Default value: @code{0}
 @end table
 
 @item Plugin(FieldFromAmplitudePhase)
-Plugin(FieldFromAmplitudePhase) builds a complex field 'u' from amplitude 'a' (complex) and phase 'phi' given in two different 'Views' u = a * exp(k*phi), with k the wavenumber. 
-
-The result is to be interpolated in a sufficiently fine mesh: 'MeshFile'. 
-
+Plugin(FieldFromAmplitudePhase) builds a complex field 'u' from amplitude 'a' (complex) and phase 'phi' given in two different 'Views' u = a * exp(k*phi), with k the wavenumber. @*
+@*
+The result is to be interpolated in a sufficiently fine mesh: 'MeshFile'. @*
+@*
 Plugin(FieldFromAmplitudePhase) generates one new view.
 String options:
 @table @code
@@ -460,10 +455,10 @@ Default value: @code{1}
 @end table
 
 @item Plugin(Gradient)
-Plugin(Gradient) computes the gradient of the field in the view `View'.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Gradient) computes the gradient of the field in the view `View'.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Gradient) creates one new view.
 Numeric options:
 @table @code
@@ -472,14 +467,14 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(HarmonicToTime)
-Plugin(HarmonicToTime) takes the values in the time steps `RealPart' and `ImaginaryPart' of the view `View', and creates a new view containing
-
-`View'[`RealPart'] * cos(p) - `View'[`ImaginaryPart'] * sin(p)
-
-with p = 2*Pi*k/`NumSteps', k = 0, ..., `NumSteps'-1.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(HarmonicToTime) takes the values in the time steps `RealPart' and `ImaginaryPart' of the view `View', and creates a new view containing@*
+@*
+`View'[`RealPart'] * cos(p) - `View'[`ImaginaryPart'] * sin(p)@*
+@*
+with p = 2*Pi*k/`NumSteps', k = 0, ..., `NumSteps'-1.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(HarmonicToTime) creates one new view.
 Numeric options:
 @table @code
@@ -494,10 +489,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(HomologyComputation)
-Plugin(HomologyComputation) computes representative chains of basis elements of (relative) homology and cohomology spaces.
-
-Define physical groups in order to specify the computation domain and the relative subdomain. Otherwise the whole mesh is the domain and the relative subdomain is empty. 
-
+Plugin(HomologyComputation) computes representative chains of basis elements of (relative) homology and cohomology spaces.@*
+@*
+Define physical groups in order to specify the computation domain and the relative subdomain. Otherwise the whole mesh is the domain and the relative subdomain is empty. @*
+@*
 Plugin(HomologyComputation) creates new views, one for each basis element. The resulting basis chains of desired dimension together with the mesh are saved to the given file.
 String options:
 @table @code
@@ -535,23 +530,23 @@ Default value: @code{1}
 @end table
 
 @item Plugin(HomologyPostProcessing)
-Plugin(HomologyPostProcessing) operates on representative basis chains of homology and cohomology spaces. Functionality:
-
-1. (co)homology basis transformation:
- 'TransformationMatrix': Integer matrix of the transformation.
- 'PhysicalGroupsOfOperatedChains': (Co)chains of a (co)homology space basis to be transformed.
- Results a new (co)chain basis that is an integer cobination of the given basis. 
-
-2. Make basis representations of a homology space and a cohomology space compatible: 
-'PhysicalGroupsOfOperatedChains': Chains of a homology space basis.
-'PhysicalGroupsOfOperatedChains2': Cochains of a cohomology space basis.
-Results a new basis for the homology space such that the incidence matrix of the new basis and the basis of the cohomology space is the identity matrix.
-
-Options:
-'PhysicalGroupsToTraceResults': Trace the resulting (co)chains to the given physical groups.
-'PhysicalGroupsToProjectResults': Project the resulting (co)chains to the complement of the given physical groups.
-'NameForResultChains': Post-processing view name prefix for the results.
-'ApplyBoundaryOperatorToResults': Apply boundary operator to the resulting chains.
+Plugin(HomologyPostProcessing) operates on representative basis chains of homology and cohomology spaces. Functionality:@*
+@*
+1. (co)homology basis transformation:@*
+ 'TransformationMatrix': Integer matrix of the transformation.@*
+ 'PhysicalGroupsOfOperatedChains': (Co)chains of a (co)homology space basis to be transformed.@*
+ Results a new (co)chain basis that is an integer cobination of the given basis. @*
+@*
+2. Make basis representations of a homology space and a cohomology space compatible: @*
+'PhysicalGroupsOfOperatedChains': Chains of a homology space basis.@*
+'PhysicalGroupsOfOperatedChains2': Cochains of a cohomology space basis.@*
+Results a new basis for the homology space such that the incidence matrix of the new basis and the basis of the cohomology space is the identity matrix.@*
+@*
+Options:@*
+'PhysicalGroupsToTraceResults': Trace the resulting (co)chains to the given physical groups.@*
+'PhysicalGroupsToProjectResults': Project the resulting (co)chains to the complement of the given physical groups.@*
+'NameForResultChains': Post-processing view name prefix for the results.@*
+'ApplyBoundaryOperatorToResults': Apply boundary operator to the resulting chains.@*
 
 String options:
 @table @code
@@ -575,12 +570,12 @@ Default value: @code{0}
 @end table
 
 @item Plugin(Integrate)
-Plugin(Integrate) integrates a scalar field over all the elements of the view `View' (if `Dimension' < 0), or over all elements of the prescribed dimension (if `Dimension' > 0). If the field is a vector field,the circulation/flux of the field over line/surface elements is calculated.
-
-If `View' < 0, the plugin is run on the current view.
-
-If `OverTime' = 1 , the plugin integrates the scalar view over time instead of over space.
-
+Plugin(Integrate) integrates a scalar field over all the elements of the view `View' (if `Dimension' < 0), or over all elements of the prescribed dimension (if `Dimension' > 0). If the field is a vector field,the circulation/flux of the field over line/surface elements is calculated.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
+If `OverTime' = 1 , the plugin integrates the scalar view over time instead of over space.@*
+@*
 Plugin(Integrate) creates one new view.
 Numeric options:
 @table @code
@@ -593,14 +588,14 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Isosurface)
-Plugin(Isosurface) extracts the isosurface of value `Value' from the view `View', and draws the `OtherTimeStep'-th step of the view `OtherView' on this isosurface.
-
-If `ExtractVolume' is nonzero, the plugin extracts the isovolume with values greater (if `ExtractVolume' > 0) or smaller (if `ExtractVolume' < 0) than the isosurface `Value'.
-
-If `OtherTimeStep' < 0, the plugin uses, for each time step in `View', the corresponding time step in `OtherView'. If `OtherView' < 0, the plugin uses `View' as the value source.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Isosurface) extracts the isosurface of value `Value' from the view `View', and draws the `OtherTimeStep'-th step of the view `OtherView' on this isosurface.@*
+@*
+If `ExtractVolume' is nonzero, the plugin extracts the isovolume with values greater (if `ExtractVolume' > 0) or smaller (if `ExtractVolume' < 0) than the isosurface `Value'.@*
+@*
+If `OtherTimeStep' < 0, the plugin uses, for each time step in `View', the corresponding time step in `OtherView'. If `OtherView' < 0, the plugin uses `View' as the value source.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Isosurface) creates as many views as there are time steps in `View'.
 Numeric options:
 @table @code
@@ -621,14 +616,14 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Lambda2)
-Plugin(Lambda2) computes the eigenvalues Lambda(1,2,3) of the tensor (S_ik S_kj + Om_ik Om_kj), where S_ij = 0.5 (ui,j + uj,i) and Om_ij = 0.5 (ui,j - uj,i) are respectively the symmetric and antisymmetric parts of the velocity gradient tensor.
-
-Vortices are well represented by regions where Lambda(2) is negative.
-
-If `View' contains tensor elements, the plugin directly uses the tensors as the values of the velocity gradient tensor; if `View' contains vector elements, the plugin uses them as the velocities from which to derive the velocity gradient tensor.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Lambda2) computes the eigenvalues Lambda(1,2,3) of the tensor (S_ik S_kj + Om_ik Om_kj), where S_ij = 0.5 (ui,j + uj,i) and Om_ij = 0.5 (ui,j - uj,i) are respectively the symmetric and antisymmetric parts of the velocity gradient tensor.@*
+@*
+Vortices are well represented by regions where Lambda(2) is negative.@*
+@*
+If `View' contains tensor elements, the plugin directly uses the tensors as the values of the velocity gradient tensor; if `View' contains vector elements, the plugin uses them as the velocities from which to derive the velocity gradient tensor.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Lambda2) creates one new view.
 Numeric options:
 @table @code
@@ -639,10 +634,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(LongitudeLatitude)
-Plugin(LongituteLatitude) projects the view `View' in longitude-latitude.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(LongituteLatitude) projects the view `View' in longitude-latitude.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(LongituteLatitude) is executed in place.
 Numeric options:
 @table @code
@@ -651,10 +646,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(MakeSimplex)
-Plugin(MakeSimplex) decomposes all non-simplectic elements (quadrangles, prisms, hexahedra, pyramids) in the view `View' into simplices (triangles, tetrahedra).
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(MakeSimplex) decomposes all non-simplectic elements (quadrangles, prisms, hexahedra, pyramids) in the view `View' into simplices (triangles, tetrahedra).@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(MakeSimplex) is executed in-place.
 Numeric options:
 @table @code
@@ -663,24 +658,24 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(MathEval)
-Plugin(MathEval) creates a new view using data from the time step `TimeStep' in the view `View'.
-
-If only `Expression0' is given (and `Expression1', ..., `Expression8' are all empty), the plugin creates a scalar view. If `Expression0', `Expression1' and/or `Expression2' are given (and `Expression3', ..., `Expression8' are all empty) the plugin creates a vector view. Otherwise the plugin creates a tensor view.
-
-In addition to the usual mathematical functions (Exp, Log, Sqrt, Sin, Cos, Fabs, etc.) and operators (+, -, *, /, ^), all expressions can contain:
-
-- the symbols v0, v1, v2, ..., vn, which represent the n components in `View';
-
-- the symbols w0, w1, w2, ..., wn, which represent the n components of `OtherView', at time step `OtherTimeStep';
-
-- the symbols x, y and z, which represent the three spatial coordinates.
-
-If `TimeStep' < 0, the plugin extracts data from all the time steps in the view.
-
-If `View' < 0, the plugin is run on the current view.
-
-Plugin(MathEval) creates one new view.If `PhysicalRegion' < 0, the plugin is run on all physical regions.
-
+Plugin(MathEval) creates a new view using data from the time step `TimeStep' in the view `View'.@*
+@*
+If only `Expression0' is given (and `Expression1', ..., `Expression8' are all empty), the plugin creates a scalar view. If `Expression0', `Expression1' and/or `Expression2' are given (and `Expression3', ..., `Expression8' are all empty) the plugin creates a vector view. Otherwise the plugin creates a tensor view.@*
+@*
+In addition to the usual mathematical functions (Exp, Log, Sqrt, Sin, Cos, Fabs, etc.) and operators (+, -, *, /, ^), all expressions can contain:@*
+@*
+- the symbols v0, v1, v2, ..., vn, which represent the n components in `View';@*
+@*
+- the symbols w0, w1, w2, ..., wn, which represent the n components of `OtherView', at time step `OtherTimeStep';@*
+@*
+- the symbols x, y and z, which represent the three spatial coordinates.@*
+@*
+If `TimeStep' < 0, the plugin extracts data from all the time steps in the view.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
+Plugin(MathEval) creates one new view.If `PhysicalRegion' < 0, the plugin is run on all physical regions.@*
+@*
 Plugin(MathEval) creates one new view.
 String options:
 @table @code
@@ -720,14 +715,14 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(MinMax)
-Plugin(MinMax) computes the min/max of a view.
-
-If `View' < 0, the plugin is run on the current view.
-
-If `OverTime' = 1, calculates the min/max over space AND time
-
-If `Argument' = 1, calculates the min/max AND the argmin/argmax
-
+Plugin(MinMax) computes the min/max of a view.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
+If `OverTime' = 1, calculates the min/max over space AND time@*
+@*
+If `Argument' = 1, calculates the min/max AND the argmin/argmax@*
+@*
 Plugin(MinMax) creates two new views.
 Numeric options:
 @table @code
@@ -740,35 +735,35 @@ Default value: @code{0}
 @end table
 
 @item Plugin(ModifyComponent)
-Plugin(ModifyComponent) sets the `Component'-th component of the `TimeStep'-th time step in the view `View' to the expression `Expression'.
-
-`Expression' can contain:
-
-- the usual mathematical functions (Log, Sqrt, Sin, Cos, Fabs, ...) and operators (+, -, *, /, ^);
-
-- the symbols x, y and z, to retrieve the coordinates of the current node;
-
-- the symbols Time and TimeStep, to retrieve the current time and time step values;
-
-- the symbol v, to retrieve the `Component'-th component of the field in `View' at the `TimeStep'-th time step;
-
-- the symbols v0, v1, v2, ..., v8, to retrieve each component of the field in `View' at the `TimeStep'-th time step;
-
-- the symbol w, to retrieve the `Component'-th component of the field in `OtherView' at the `OtherTimeStep'-th time step. If `OtherView' and `View' are based on different spatial grids, or if their data types are different, `OtherView' is interpolated onto `View';
-
-- the symbols w0, w1, w2, ..., w8, to retrieve each component of the field in `OtherView' at the `OtherTimeStep'-th time step.
-
-If `TimeStep' < 0, the plugin automatically loops over all the time steps in `View' and evaluates `Expression' for each one.
-
-If `OtherTimeStep' < 0, the plugin uses `TimeStep' instead.
-
-If `Component' < 0, the plugin automatically  ops
-over all the components in the view and evaluates `Expression' for each one.
-
-If `View' < 0, the plugin is run on the current view.
-
-If `OtherView' < 0, the plugin uses `View' instead.
-
+Plugin(ModifyComponent) sets the `Component'-th component of the `TimeStep'-th time step in the view `View' to the expression `Expression'.@*
+@*
+`Expression' can contain:@*
+@*
+- the usual mathematical functions (Log, Sqrt, Sin, Cos, Fabs, ...) and operators (+, -, *, /, ^);@*
+@*
+- the symbols x, y and z, to retrieve the coordinates of the current node;@*
+@*
+- the symbols Time and TimeStep, to retrieve the current time and time step values;@*
+@*
+- the symbol v, to retrieve the `Component'-th component of the field in `View' at the `TimeStep'-th time step;@*
+@*
+- the symbols v0, v1, v2, ..., v8, to retrieve each component of the field in `View' at the `TimeStep'-th time step;@*
+@*
+- the symbol w, to retrieve the `Component'-th component of the field in `OtherView' at the `OtherTimeStep'-th time step. If `OtherView' and `View' are based on different spatial grids, or if their data types are different, `OtherView' is interpolated onto `View';@*
+@*
+- the symbols w0, w1, w2, ..., w8, to retrieve each component of the field in `OtherView' at the `OtherTimeStep'-th time step.@*
+@*
+If `TimeStep' < 0, the plugin automatically loops over all the time steps in `View' and evaluates `Expression' for each one.@*
+@*
+If `OtherTimeStep' < 0, the plugin uses `TimeStep' instead.@*
+@*
+If `Component' < 0, the plugin automatically  ops@*
+over all the components in the view and evaluates `Expression' for each one.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
+If `OtherView' < 0, the plugin uses `View' instead.@*
+@*
 Plugin(ModifyComponent) is executed in-place.
 String options:
 @table @code
@@ -792,10 +787,10 @@ Default value: @code{0}
 @end table
 
 @item Plugin(ModulusPhase)
-Plugin(ModulusPhase) interprets the time steps `realPart' and `imaginaryPart' in the view `View' as the real and imaginary parts of a complex field and replaces them with their corresponding modulus and phase.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(ModulusPhase) interprets the time steps `realPart' and `imaginaryPart' in the view `View' as the real and imaginary parts of a complex field and replaces them with their corresponding modulus and phase.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(ModulusPhase) is executed in-place.
 Numeric options:
 @table @code
@@ -808,10 +803,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(NearToFarField)
-Plugin(NearToFarField) computes the far field pattern from the near electric E and magnetic H fields on a surface enclosing the radiating device (antenna).
-
-Parameters: the wavenumber, the angular discretisation (phi in [0, 2*Pi] and theta in [0, Pi]) of the far field sphere and the indices of the views containing the complex-valued E and H fields. If `Normalize' is set, the far field is normalized to 1. If `dB' is set, the far field is computed in dB. If `NegativeTime' is set, E and H are assumed to have exp(-iwt) time dependency; otherwise they are assume to have exp(+iwt) time dependency. If `MatlabOutputFile' is given the raw far field d [...]
-
+Plugin(NearToFarField) computes the far field pattern from the near electric E and magnetic H fields on a surface enclosing the radiating device (antenna).@*
+@*
+Parameters: the wavenumber, the angular discretisation (phi in [0, 2*Pi] and theta in [0, Pi]) of the far field sphere and the indices of the views containing the complex-valued E and H fields. If `Normalize' is set, the far field is normalized to 1. If `dB' is set, the far field is computed in dB. If `NegativeTime' is set, E and H are assumed to have exp(-iwt) time dependency; otherwise they are assume to have exp(+iwt) time dependency. If `MatlabOutputFile' is given the raw far field d [...]
+@*
 Plugin(NearToFarField) creates one new view.
 String options:
 @table @code
@@ -849,10 +844,10 @@ Default value: @code{0}
 @end table
 
 @item Plugin(NearestNeighbor)
-Plugin(NearestNeighbor) computes the distance from each point in `View' to its nearest neighbor.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(NearestNeighbor) computes the distance from each point in `View' to its nearest neighbor.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(NearestNeighbor) is executed in-place.
 Numeric options:
 @table @code
@@ -869,20 +864,20 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Particles)
-Plugin(Particles) computes the trajectory of particules in the force field given by the `TimeStep'-th time step of a vector view `View'.
-
-The plugin takes as input a grid defined by the 3 points (`X0',`Y0',`Z0') (origin), (`X1',`Y1',`Z1') (axis of U) and (`X2',`Y2',`Z2') (axis of V).
-
-The number of particles along U and V that are to be transported is set with the options `NumPointsU' and `NumPointsV'. The equation
-
-A2 * d^2X(t)/dt^2 + A1 * dX(t)/dt + A0 * X(t) = F
-
-is then solved with the initial conditions X(t=0) chosen as the grid, dX/dt(t=0)=0, and with F interpolated from the vector view.
-
-Time stepping is done using a Newmark scheme with step size `DT' and `MaxIter' maximum number of iterations.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Particles) computes the trajectory of particules in the force field given by the `TimeStep'-th time step of a vector view `View'.@*
+@*
+The plugin takes as input a grid defined by the 3 points (`X0',`Y0',`Z0') (origin), (`X1',`Y1',`Z1') (axis of U) and (`X2',`Y2',`Z2') (axis of V).@*
+@*
+The number of particles along U and V that are to be transported is set with the options `NumPointsU' and `NumPointsV'. The equation@*
+@*
+A2 * d^2X(t)/dt^2 + A1 * dX(t)/dt + A0 * X(t) = F@*
+@*
+is then solved with the initial conditions X(t=0) chosen as the grid, dX/dt(t=0)=0, and with F interpolated from the vector view.@*
+@*
+Time stepping is done using a Newmark scheme with step size `DT' and `MaxIter' maximum number of iterations.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Particles) creates one new view containing multi-step vector points.
 Numeric options:
 @table @code
@@ -925,10 +920,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Probe)
-Plugin(Probe) gets the value of the view `View' at the point (`X',`Y',`Z').
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Probe) gets the value of the view `View' at the point (`X',`Y',`Z').@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Probe) creates one new view.
 Numeric options:
 @table @code
@@ -943,10 +938,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Remove)
-Plugin(Remove) removes the marked items from the view `View'.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Remove) removes the marked items from the view `View'.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Remove) is executed in-place.
 Numeric options:
 @table @code
@@ -980,10 +975,39 @@ Default value: @code{1}
 Default value: @code{-1}
 @end table
 
- at item Plugin(Scal2Vec)
-Plugin(Scal2Vec) converts the scalar fields of 'ViewX', 'ViewY' and/or 'ViewZ' into a vectorial field. The new view 'NameNewView' contains it.
+ at item Plugin(Scal2Tens)
+Plugin(Scal2Tens) converts some scalar fields into a tensor field. The number of components must be given (max. 9). The new view 'NameNewView' contains the new tensor field. If the number of a view is -1, the value of the corresponding component is 0.
+String options:
+ at table @code
+ at item NameNewView
+Default value: @code{"NewView"}
+ at end table
+Numeric options:
+ at table @code
+ at item NumberOfComponents
+Default value: @code{9}
+ at item View0
+Default value: @code{-1}
+ at item View1
+Default value: @code{-1}
+ at item View2
+Default value: @code{-1}
+ at item View3
+Default value: @code{-1}
+ at item View4
+Default value: @code{-1}
+ at item View5
+Default value: @code{-1}
+ at item View6
+Default value: @code{-1}
+ at item View7
+Default value: @code{-1}
+ at item View8
+Default value: @code{-1}
+ at end table
 
-If the value of 'ViewX', 'ViewY' or 'ViewZ' is -1, the value of the vectorial field in the corresponding direction is 0.
+ at item Plugin(Scal2Vec)
+Plugin(Scal2Vec) converts the scalar fields into a vectorial field. The new view 'NameNewView' contains it. If the number of a view is -1, the value of the corresponding component of the vector field is 0.
 String options:
 @table @code
 @item NameNewView
@@ -1017,7 +1041,7 @@ Default value: @code{1}
 @end table
 
 @item Plugin(Skin)
-Plugin(Skin) extracts the boundary (skin) of the current mesh (if `FromMesh' = 1), or from the the view `View' (in which case it creates a new view). If `View' < 0 and `FromMesh' = 0, the plugin is run on the current view.
+Plugin(Skin) extracts the boundary (skin) of the current mesh (if `FromMesh' = 1), or from the the view `View' (in which case it creates a new view). If `View' < 0 and `FromMesh' = 0, the plugin is run on the current view.@*
 If `Visible' is set, the plugin only extracts the skin of visible entities.
 Numeric options:
 @table @code
@@ -1030,10 +1054,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Smooth)
-Plugin(Smooth) averages the values at the nodes of the view `View'.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Smooth) averages the values at the nodes of the view `View'.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Smooth) is executed in-place.
 Numeric options:
 @table @code
@@ -1042,14 +1066,14 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(SphericalRaise)
-Plugin(SphericalRaise) transforms the coordinates of the elements in the view `View' using the values associated with the `TimeStep'-th time step.
-
-Instead of elevating the nodes along the X, Y and Z axes as with the View[`View'].RaiseX, View[`View'].RaiseY and View[`View'].RaiseZ options, the raise is applied along the radius of a sphere centered at (`Xc', `Yc', `Zc').
-
-To produce a standard radiation pattern, set `Offset' to minus the radius of the sphere the original data lives on.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(SphericalRaise) transforms the coordinates of the elements in the view `View' using the values associated with the `TimeStep'-th time step.@*
+@*
+Instead of elevating the nodes along the X, Y and Z axes as with the View[`View'].RaiseX, View[`View'].RaiseY and View[`View'].RaiseZ options, the raise is applied along the radius of a sphere centered at (`Xc', `Yc', `Zc').@*
+@*
+To produce a standard radiation pattern, set `Offset' to minus the radius of the sphere the original data lives on.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(SphericalRaise) is executed in-place.
 Numeric options:
 @table @code
@@ -1070,22 +1094,22 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(StreamLines)
-Plugin(StreamLines) computes stream lines from the `TimeStep'-th time step of a vector view `View' and optionally interpolates the scalar view `OtherView' on the resulting stream lines.
-
-The plugin takes as input a grid defined by the 3 points (`X0',`Y0',`Z0') (origin), (`X1',`Y1',`Z1') (axis of U) and (`X2',`Y2',`Z2') (axis of V).
-
-The number of points along U and V that are to be transported is set with the options `NumPointsU' and `NumPointsV'. The equation
-
-dX(t)/dt = V(x,y,z)
-
-is then solved with the initial condition X(t=0) chosen as the grid and with V(x,y,z) interpolated on the vector view.
-
-The time stepping scheme is a RK44 with step size `DT' and `MaxIter' maximum number of iterations.
-
-If `TimeStep' < 0, the plugin tries to compute streamlines of the unsteady flow.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(StreamLines) computes stream lines from the `TimeStep'-th time step of a vector view `View' and optionally interpolates the scalar view `OtherView' on the resulting stream lines.@*
+@*
+The plugin takes as input a grid defined by the 3 points (`X0',`Y0',`Z0') (origin), (`X1',`Y1',`Z1') (axis of U) and (`X2',`Y2',`Z2') (axis of V).@*
+@*
+The number of points along U and V that are to be transported is set with the options `NumPointsU' and `NumPointsV'. The equation@*
+@*
+dX(t)/dt = V(x,y,z)@*
+@*
+is then solved with the initial condition X(t=0) chosen as the grid and with V(x,y,z) interpolated on the vector view.@*
+@*
+The time stepping scheme is a RK44 with step size `DT' and `MaxIter' maximum number of iterations.@*
+@*
+If `TimeStep' < 0, the plugin tries to compute streamlines of the unsteady flow.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(StreamLines) creates one new view. This view contains multi-step vector points if `OtherView' < 0, or single-step scalar lines if `OtherView' >= 0.
 Numeric options:
 @table @code
@@ -1124,10 +1148,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Tetrahedralize)
-Plugin(Tetrahedralize) tetrahedralizes the points in the view `View'.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Tetrahedralize) tetrahedralizes the points in the view `View'.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Tetrahedralize) creates one new view.
 Numeric options:
 @table @code
@@ -1136,16 +1160,16 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Transform)
-Plugin(Transform) transforms the homogeneous node coordinates (x,y,z,1) of the elements in the view `View' by the matrix
-
-[`A11' `A12' `A13' `Tx']
-[`A21' `A22' `A23' `Ty']
-[`A31' `A32' `A33' `Tz'].
-
-If `SwapOrientation' is set, the orientation of the elements is reversed.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Transform) transforms the homogeneous node coordinates (x,y,z,1) of the elements in the view `View' by the matrix@*
+@*
+[`A11' `A12' `A13' `Tx']@*
+[`A21' `A22' `A23' `Ty']@*
+[`A31' `A32' `A33' `Tz'].@*
+@*
+If `SwapOrientation' is set, the orientation of the elements is reversed.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Transform) is executed in-place.
 Numeric options:
 @table @code
@@ -1180,10 +1204,10 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Triangulate)
-Plugin(Triangulate) triangulates the points in the view `View', assuming that all the points belong to a surface that can be projected one-to-one onto a plane.
-
-If `View' < 0, the plugin is run on the current view.
-
+Plugin(Triangulate) triangulates the points in the view `View', assuming that all the points belong to a surface that can be projected one-to-one onto a plane.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
 Plugin(Triangulate) creates one new view.
 Numeric options:
 @table @code
@@ -1192,12 +1216,12 @@ Default value: @code{-1}
 @end table
 
 @item Plugin(Warp)
-Plugin(Warp) transforms the elements in the view `View' by adding to their node coordinates the vector field stored in the `TimeStep'-th time step of the view `OtherView', scaled by `Factor'.
-
-If `View' < 0, the plugin is run on the current view.
-
-If `OtherView' < 0, the vector field is taken as the field of surface normals multiplied by the `TimeStep' value in `View'. (The smoothing of the surface normals is controlled by the `SmoothingAngle' parameter.)
-
+Plugin(Warp) transforms the elements in the view `View' by adding to their node coordinates the vector field stored in the `TimeStep'-th time step of the view `OtherView', scaled by `Factor'.@*
+@*
+If `View' < 0, the plugin is run on the current view.@*
+@*
+If `OtherView' < 0, the vector field is taken as the field of surface normals multiplied by the `TimeStep' value in `View'. (The smoothing of the surface normals is controlled by the `SmoothingAngle' parameter.)@*
+@*
 Plugin(Warp) is executed in-place.
 Numeric options:
 @table @code
diff --git a/doc/texinfo/opt_print.texi b/doc/texinfo/opt_print.texi
index 376c82e..b1ce1d0 100644
--- a/doc/texinfo/opt_print.texi
+++ b/doc/texinfo/opt_print.texi
@@ -30,7 +30,7 @@ Default value: @code{10}@*
 Saved in: @code{General.OptionsFileName}
 
 @item Print.Background
-Print background?@*
+Print background (gradient and image)?@*
 Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
@@ -39,6 +39,21 @@ Composite all window tiles in the same output image (for bitmap output only)@*
 Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
+ at item Print.PgfTwoDim
+Output PGF format for two dimensions. Mostly irrelevant if `PgfExportAxis=0`. Default `1` (yes).@*
+Default value: @code{1}@*
+Saved in: @code{General.OptionsFileName}
+
+ at item Print.PgfExportAxis
+Include axis in export pgf code (not in the png). Default `0` (no).@*
+Default value: @code{0}@*
+Saved in: @code{General.OptionsFileName}
+
+ at item Print.PgfHorizontalBar
+Use a horizontal color bar in the pgf output. Default `0` (no).@*
+Default value: @code{0}@*
+Saved in: @code{General.OptionsFileName}
+
 @item Print.DeleteTemporaryFiles
 Delete temporary files used during printing@*
 Default value: @code{1}@*
diff --git a/doc/texinfo/opt_solver.texi b/doc/texinfo/opt_solver.texi
index 648c43b..c655dd4 100644
--- a/doc/texinfo/opt_solver.texi
+++ b/doc/texinfo/opt_solver.texi
@@ -180,7 +180,7 @@ Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
 @item Solver.AutoMesh
-Automatically mesh if necesssary@*
+Automatically mesh if necesssary (0: never remesh; 1: on startup, use existing mesh on disk if available; 2: always remesh)@*
 Default value: @code{1}@*
 Saved in: @code{General.OptionsFileName}
 
@@ -189,9 +189,9 @@ Automatically merge result files@*
 Default value: @code{1}@*
 Saved in: @code{General.OptionsFileName}
 
- at item Solver.AutoHideNewViews
-Automcatically hide newly merged results@*
-Default value: @code{0}@*
+ at item Solver.AutoShowViews
+Automcatically show newly merged results (0: none; 1: all; 2: last one)@*
+Default value: @code{2}@*
 Saved in: @code{General.OptionsFileName}
 
 @item Solver.AutoShowLastStep
diff --git a/doc/texinfo/shortcuts.texi b/doc/texinfo/shortcuts.texi
index 3ee3586..6e4fd29 100644
--- a/doc/texinfo/shortcuts.texi
+++ b/doc/texinfo/shortcuts.texi
@@ -72,6 +72,8 @@ Rename project file
 Save file as
 @item Shift+Ctrl+c
 Show clipping plane window
+ at item Shift+Ctrl+h
+Show current options and workspace window
 @item Shift+Ctrl+j
 Save options as default
 @item Shift+Ctrl+m
diff --git a/utils/converters/matlab/gmsh2pdetoolbox.m b/utils/converters/matlab/gmsh2pdetoolbox.m
new file mode 100644
index 0000000..d920fe2
--- /dev/null
+++ b/utils/converters/matlab/gmsh2pdetoolbox.m
@@ -0,0 +1,287 @@
+%GMSH2PDETOOLBOX Reads a mesh in msh format, version 1 or 2 and returns the
+%arrays p, e and t according to the MATLAB pde toolbox syntax. Filename
+%refers to the .msh file. Note that only triangular 2D mesh are processed
+%since these are the only elements allowed in pde toolbox.
+%
+%SEE ALSO load_gmsh load_gmsh4 initmesh
+%
+% Copyright (C) 2014 Arthur Levy. https://github.com/arthurlevy/
+%
+% This fucntion uses the routine load_gmsh4 in load_gmsh2.m: Copyright (C)
+% 2007  JP Moitinho de Almeida (moitinho at civil.ist.utl.pt) and  R
+% Lorphevre(r(point)lorphevre(at)ulg(point)ac(point)be) It is based on
+% load_gmsh.m supplied with gmsh-2.0
+function [p, e, t] = gmsh2pdetoolbox(filename)
+
+%loads the gmsh file using JP Moitinho de Almeida (moitinho at civil.ist.utl.pt)
+% and  R Lorphevre(r(point)lorphevre(at)ulg(point)ac(point)be) code.
+mesh_structure = load_gmsh4(filename,-1);
+
+
+%% NODES
+%nodes positions
+disp('importing nodes');
+p = mesh_structure.POS(:,1:2)';
+
+
+%% EDGES
+disp('importing edges');
+%find the edges (ie dimension 1)
+is_edge = (mesh_structure.ELE_INFOS(:,2)==1);
+%add edge data
+e = mesh_structure.ELE_NODES(is_edge,1:2)';
+e(3,:) = 0;
+e(4,:) = 1;
+%tag is important for applying boundary conditions
+e(5,:) = mesh_structure.ELE_TAGS(is_edge,1)';
+e(6,:) = 1;
+e(7,:) = 0;
+
+%% TRIANGLES
+disp('importing triangles')
+is_triangle = (mesh_structure.ELE_INFOS(:,2)==2);
+t = mesh_structure.ELE_NODES(is_triangle,1:3)';
+t(4,:) = 2;
+
+
+
+
+
+function msh = load_gmsh4(filename, which)
+
+%% Reads a mesh in msh format, version 1 or 2
+%
+% Usage: 
+% To define all variables m.LINES, M.TRIANGLES, etc 
+% (Warning: This creates a very large structure. Do you really need it?)
+%            m = load_gmsh4('a.msh')
+%
+% To define only certain variables (for example TETS and HEXS)
+%            m = load_gmsh4('a.msh', [ 5 6])
+%
+% To define no variables (i.e. if you prefer to use m.ELE_INFOS(i,2))
+%            m = load_gmsh4('a.msh', -1)
+%            m = load_gmsh4('a.msh', [])
+%
+% Copyright (C) 2007  JP Moitinho de Almeida (moitinho at civil.ist.utl.pt)
+% and  R Lorphevre(r(point)lorphevre(at)ulg(point)ac(point)be)
+%
+% based on load_gmsh.m supplied with gmsh-2.0
+%
+% Structure msh always has the following elements:
+%
+% msh.MIN, msh.MAX - Bounding box
+% msh.nbNod - Number of nodes
+% msh.nbElm - Total number of elements
+% msh.nbType(i) - Number of elements of type i (i in 1:19)
+% msh.POS(i,j) - j'th coordinate of node i (j in 1:3, i in 1:msh.nbNod)
+% msh.ELE_INFOS(i,1) - id of element i (i in 1:msh.nbElm)
+% msh.ELE_INFOS(i,2) - type of element i
+% msh.ELE_INFOS(i,3) - number of tags for element i
+% msh.ELE_INFOS(i,4) - Dimension (0D, 1D, 2D or 3D) of element i
+% msh.ELE_TAGS(i,j) - Tags of element i (j in 1:msh.ELE_INFOS(i,3))
+% msh.ELE_NODES(i,j) - Nodes of element i (j in 1:k, with
+%                       k = msh.NODES_PER_TYPE_OF_ELEMENT(msh.ELE_INFOS(i,2)))
+%
+% These elements are created if requested:
+%
+% msh.nbLines - number of 2 node lines
+% msh.LINES(i,1:2) - nodes of line i
+% msh.LINES(i,3) - tag (WHICH ?????) of line i
+%
+% msh.nbTriangles - number of 2 node triangles
+% msh.TRIANGLES(i,1:3) - nodes of triangle i
+% msh.TRIANGLES(i,4) - tag (WHICH ?????) of triangle i
+%
+% Etc
+
+% These definitions need to be updated when new elemens types are added to gmsh
+%
+% msh.Types{i}{1} Number of an element of type i
+% msh.Types{i}{2} Dimension (0D, 1D, 2D or 3D) of element of type i
+% msh.Types{i}{3} Name to add to the structure with elements of type i
+% msh.Types{i}{4} Name to add to the structure with the number of elements of type i
+%
+
+nargchk(1, 2, nargin);
+
+msh.Types = { ...
+    { 2, 1, 'LINES', 'nbLines'}, ... % 1
+    { 3,  2, 'TRIANGLES', 'nbTriangles'}, ...
+    { 4,  2, 'QUADS', 'nbQuads'}, ...  
+    { 4,  3, 'TETS', 'nbTets'}, ...
+    { 8,  3, 'HEXAS', 'nbHexas'}, ... %5
+    { 6,  3, 'PRISMS', 'nbPrisms'}, ...
+    { 5,  3, 'PYRAMIDS', 'nbPyramids'}, ...
+    { 3,  1, 'LINES3', 'nbLines3'}, ...
+    { 6,  2, 'TRIANGLES6', 'nbTriangles6'}, ...
+    { 9,  2, 'QUADS9', 'nbQuads9'}, ... % 10
+    { 10,  3, 'TETS10', 'nbTets10'}, ...
+    { 27,  3, 'HEXAS27', 'nbHexas27'}, ...
+    { 18,  3, 'PRISMS18', 'nbPrisms18'}, ...
+    { 14,  3, 'PYRAMIDS14', 'nbPyramids14'}, ...
+    { 1,  0, 'POINTS', 'nbPoints'}, ... % 15
+    { 8,  3, 'QUADS8', 'nbQuads8'}, ...
+    { 20,  3, 'HEXAS20', 'nbHexas20'}, ...
+    { 15,  3, 'PRISMS15', 'nbPrisms15'}, ...
+    { 13,  3, 'PYRAMIDS13', 'nbPyramids13'}, ...
+};
+                     
+ntypes = length(msh.Types);
+
+if (nargin==1)
+    which = 1:ntypes;
+else
+    if isscalar(which) && which == -1
+        which = [];
+    end
+end
+
+% Could check that "which" is properlly defined....
+
+fid = fopen(filename, 'r');
+fileformat = 0; % Assume wrong file
+
+tline = fgetl(fid);
+if (feof(fid))
+    disp (sprintf('Empty file: %s',  filename));
+    msh = [];
+    return;
+end
+
+%% Read mesh type
+if (strcmp(tline, '$NOD'))
+    fileformat = 1;
+elseif (strcmp(tline, '$MeshFormat'))
+    fileformat = 2;
+    tline = fgetl(fid);
+    if (feof(fid))
+        disp (sprintf('Syntax error (no version) in: %s',  filename));
+        fileformat = 0;
+    end
+    [ form ] = sscanf( tline, '%f %d %d');
+%    if (form(1) ~= 2)
+%        disp (sprintf('Unknown mesh format: %s', tline));
+%        fileformat = 0;
+%    end
+    if (form(2) ~= 0)
+        disp ('Sorry, this program can only read ASCII format');
+        fileformat = 0;
+    end
+    fgetl(fid);    % this should be $EndMeshFormat
+    if (feof(fid))
+        disp (sprintf('Syntax error (no $EndMeshFormat) in: %s',  filename));
+        fileformat = 0;
+    end
+    tline = fgetl(fid);    % this should be $Nodes
+    if (feof(fid))
+        disp (sprintf('Syntax error (no $Nodes) in: %s',  filename));
+        fileformat = 0;
+    end
+end
+
+if (~fileformat)
+    msh = [];
+    return
+end
+
+%% Read nodes
+
+if strcmp(tline, '$NOD') || strcmp(tline, '$Nodes')
+    msh.nbNod = fscanf(fid, '%d', 1);
+    aux = fscanf(fid, '%g', [4 msh.nbNod]);
+    msh.POS = aux(2:4,:)';
+    numids = max(aux(1,:));
+    IDS = zeros(1, numids);
+    IDS(aux(1,:)) = 1:msh.nbNod; % This may not be an identity
+    msh.MAX = max(msh.POS);
+    msh.MIN = min(msh.POS);
+    fgetl(fid); % End previous line
+    fgetl(fid); % Has to be $ENDNOD $EndNodes
+else
+    disp (sprintf('Syntax error (no $Nodes/$NOD) in: %s',  filename));
+    fileformat = 0;
+end
+
+%% Read elements
+tline = fgetl(fid);
+if strcmp(tline,'$ELM') || strcmp(tline, '$Elements')
+    msh.nbElm = fscanf(fid, '%d', 1);
+    % read all info about elements into aux (it is faster!)
+    aux = fscanf(fid, '%g', inf);
+    start = 1;
+    msh.ELE_INFOS = zeros(msh.nbElm, 4); % 1 - id, 2 - type, 3 - ntags, 4 - Dimension
+    msh.ELE_NODES = zeros(msh.nbElm,6); % i - Element, j - ElNodes
+    if (fileformat == 1)
+        ntags = 2;
+    else
+        ntags = 3; % just a prediction
+    end
+    msh.ELE_TAGS = zeros(msh.nbElm, ntags); % format 1: 1 - physical number, 2 - geometrical number
+                                            % format 2: 1 - physical number, 2 - geometrical number, 3 - mesh partition number
+    msh.nbType = zeros(ntypes,1);
+    for I = 1:msh.nbElm
+        if (fileformat == 2)
+            finnish = start + 2; 
+            msh.ELE_INFOS(I, 1:3) = aux(start:finnish); 
+            ntags = aux(finnish); 
+            start = finnish + 1;
+            finnish = start + ntags -1;
+            msh.ELE_TAGS(I, 1:ntags) = aux(start:finnish); 
+            start = finnish + 1;
+        else
+            finnish = start + 1;
+            msh.ELE_INFOS(I, 1:2) = aux(start:finnish); 
+            start = finnish + 1; % the third element is nnodes, which we get from the type
+            msh.ELE_INFOS(I, 3) = 2; 
+            finnish = start + 1;
+            msh.ELE_TAGS(I, 1:2) = aux(start:finnish); 
+            start = finnish + 2;
+        end
+        type = msh.ELE_INFOS(I, 2);
+        msh.nbType(type) = msh.nbType(type) + 1;
+        msh.ELE_INFOS(I, 4) = msh.Types{type}{2};
+        nnodes = msh.Types{type}{1};
+        finnish = start + nnodes - 1;
+        msh.ELE_NODES(I, 1:nnodes) = IDS(aux(start:finnish));
+        start=finnish + 1;
+    end
+    fgetl(fid); % Has to be $ENDELM or $EndElements
+else
+    disp (sprintf('Syntax error (no $Elements/$ELM) in: %s',  filename));
+    fileformat = 0;
+end
+
+if (fileformat == 0)
+    msh = [];
+end
+
+fclose(fid);
+
+%% This is used to create the explicit lists for types of elements
+
+for i = which
+    if (~isempty(msh.Types{i}{3}))
+        cmd = sprintf('msh.%s=msh.nbType(%d);', msh.Types{i}{4}, i);
+        eval(cmd);
+        % Dimension
+        cmd = sprintf('msh.%s=zeros(%d,%d);', msh.Types{i}{3}, msh.nbType(i), msh.Types{i}{1}+1);
+        eval(cmd);
+        % Clear nbType for counting, next loop will recompute it
+        msh.nbType(i) = 0;
+    end
+end
+
+for i = 1:msh.nbElm
+    type = msh.ELE_INFOS(i,2);
+    if (find(which == type))
+        if (~isempty(msh.Types{type}{3}))
+            msh.nbType(type) = msh.nbType(type)+1;
+            aux=[ msh.ELE_NODES(i,1:msh.Types{type}{1}), msh.ELE_TAGS(i,1) ];
+            cmd = sprintf('msh.%s(%d,:)=aux;', msh.Types{type}{3}, msh.nbType(type));
+            eval(cmd);
+        end
+    end
+end
+
+return;
diff --git a/utils/icons/apple-touch-icon.png b/utils/icons/apple-touch-icon.png
deleted file mode 100644
index 973bf6b..0000000
Binary files a/utils/icons/apple-touch-icon.png and /dev/null differ
diff --git a/utils/icons/gmsh.xcf b/utils/icons/gmsh.xcf
index 53c07bc..3b22671 100644
Binary files a/utils/icons/gmsh.xcf and b/utils/icons/gmsh.xcf differ
diff --git a/utils/icons/gmsh_mobile_master.png b/utils/icons/gmsh_mobile_master.png
new file mode 100644
index 0000000..08299ae
Binary files /dev/null and b/utils/icons/gmsh_mobile_master.png differ
diff --git a/utils/misc/package_gmsh_getdp.sh b/utils/misc/package_gmsh_getdp.sh
index 90d6344..44c3950 100755
--- a/utils/misc/package_gmsh_getdp.sh
+++ b/utils/misc/package_gmsh_getdp.sh
@@ -14,8 +14,8 @@ up-to-date versions, documentation and examples." > /tmp/README.txt
 GMSH=svn
 GETDP=svn
 
-#GMSH=2.8.3
-#GETDP=2.4.2
+#GMSH=2.8.4
+#GETDP=2.4.3
 
 rm -rf gmsh-getdp-Windows64
 mkdir gmsh-getdp-Windows64
diff --git a/utils/solvers/c++/GmshSocket.h b/utils/solvers/c++/GmshSocket.h
index 8aa0324..312d160 100644
--- a/utils/solvers/c++/GmshSocket.h
+++ b/utils/solvers/c++/GmshSocket.h
@@ -22,7 +22,8 @@
 // ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 // OF THIS SOFTWARE.
 //
-// Please report all bugs and problems to the public mailing list <gmsh at geuz.org>.
+// Please report all bugs and problems to the public mailing list
+// <gmsh at geuz.org>.
 
 #ifndef _GMSH_SOCKET_H_
 #define _GMSH_SOCKET_H_
@@ -80,6 +81,7 @@ class GmshSocket{
     GMSH_SPEED_TEST          = 30,
     GMSH_PARAMETER_CLEAR     = 31,
     GMSH_PARAMETER_UPDATE    = 32,
+    GMSH_OPEN_PROJECT        = 33,
     GMSH_OPTION_1            = 100,
     GMSH_OPTION_2            = 101,
     GMSH_OPTION_3            = 102,
@@ -188,6 +190,7 @@ class GmshSocket{
   void Error(const char *str){ SendString(GMSH_ERROR, str); }
   void Progress(const char *str){ SendString(GMSH_PROGRESS, str); }
   void MergeFile(const char *str){ SendString(GMSH_MERGE_FILE, str); }
+  void OpenProject(const char *str){ SendString(GMSH_OPEN_PROJECT, str); }
   void ParseString(const char *str){ SendString(GMSH_PARSE_STRING, str); }
   void SpeedTest(const char *str){ SendString(GMSH_SPEED_TEST, str); }
   void Option(int num, const char *str)
@@ -200,7 +203,6 @@ class GmshSocket{
   {
     *swap = 0;
     if(_ReceiveData(type, sizeof(int)) > 0){
-      if(*type < 0) return 0;
       if(*type > 65535){
         // the data comes from a machine with different endianness and
         // we must swap the bytes
@@ -208,7 +210,6 @@ class GmshSocket{
         _SwapBytes((char*)type, sizeof(int), 1);
       }
       if(_ReceiveData(len, sizeof(int)) > 0){
-        if(*len < 0) return 0;
         if(*swap) _SwapBytes((char*)len, sizeof(int), 1);
         return 1;
       }
@@ -367,7 +368,7 @@ class GmshServer : public GmshSocket{
 #if !defined(WIN32) || defined(__CYGWIN__)
       if(tmpsock < 0)
 #else
-	if(tmpsock == (int)INVALID_SOCKET)
+      if(tmpsock == (int)INVALID_SOCKET)
 #endif
         throw "Couldn't create socket";
       // bind the socket to its name
diff --git a/utils/solvers/c++/onelab.h b/utils/solvers/c++/onelab.h
index c7a3d8a..615b4da 100644
--- a/utils/solvers/c++/onelab.h
+++ b/utils/solvers/c++/onelab.h
@@ -1,4 +1,4 @@
-// OneLab - Copyright (C) 2011-2013 ULg-UCL
+// ONELAB - Copyright (C) 2011-2014 ULg-UCL
 //
 // Permission is hereby granted, free of charge, to any person
 // obtaining a copy of this software and associated documentation
@@ -53,13 +53,11 @@ namespace onelab{
     std::string _label;
     // a help string
     std::string _help;
-    // clients that use this parameter
-    std::set<std::string> _clients;
-    // flag to check if the value of the parameter has been changed since the
-    // last computation (normally this is reset after all the clients have been
-    // run)
-    bool _changed;
-    // flag indicating that the _changed flag of this parameter will always be
+    // map of clients that use this parameter, associated with a "changed" flag
+    // (set to false if the client has already been run with the current value of
+    // the parameter)
+    std::map<std::string, bool> _clients;
+    // flag indicating that the "changed" flags of this parameter will always be
     // reset to false when the parameter is updated
     bool _neverChanged;
     // should the parameter be visible in the interface?
@@ -72,13 +70,24 @@ namespace onelab{
   public:
     parameter(const std::string &name="", const std::string &label="",
               const std::string &help="")
-      : _name(name), _label(label), _help(help), _changed(true),
-        _neverChanged(false), _visible(true), _readOnly(false) {}
+      : _name(name), _label(label), _help(help), _neverChanged(false),
+        _visible(true), _readOnly(false) {}
     virtual ~parameter(){}
     void setName(const std::string &name){ _name = name; }
     void setLabel(const std::string &label){ _label = label; }
     void setHelp(const std::string &help){ _help = help; }
-    void setChanged(bool changed){ _changed = changed; }
+    void setChanged(bool changed, const std::string &client="")
+    {
+      if(client.size()){
+        std::map<std::string, bool>::iterator it = _clients.find(client);
+        if(it != _clients.end()) it->second = changed;
+      }
+      else{
+        for(std::map<std::string, bool>::iterator it = _clients.begin();
+            it != _clients.end(); it++)
+          it->second = changed;
+      }
+    }
     void setNeverChanged(bool never){ _neverChanged = never; }
     void setVisible(bool visible){ _visible = visible; }
     void setReadOnly(bool readOnly){ _readOnly = readOnly; }
@@ -90,9 +99,13 @@ namespace onelab{
     {
       _attributes = attributes;
     }
-    void setClients(const std::set<std::string> &clients){ _clients = clients; }
-    void addClient(const std::string &client){ _clients.insert(client); }
-    void addClients(const std::set<std::string> &clients)
+    void setClients(const std::map<std::string, bool> &clients){ _clients = clients; }
+    void addClient(const std::string &client, bool changed)
+    {
+      if(_clients.find(client) == _clients.end())
+        _clients[client] = changed;
+    }
+    void addClients(const std::map<std::string, bool> &clients)
     {
       _clients.insert(clients.begin(), clients.end());
     }
@@ -100,6 +113,7 @@ namespace onelab{
     {
       return (_clients.find(client) != _clients.end());
     }
+    int getNumClients() { return (int)_clients.size(); };
     virtual std::string getType() const = 0;
     const std::string &getName() const { return _name; }
     const std::string &getLabel() const { return _label; }
@@ -122,7 +136,21 @@ namespace onelab{
         s = s.substr(1);
       return s;
     }
-    bool getChanged() const { return _changed; }
+    bool getChanged(const std::string &client="") const
+    {
+      if(client.size()){
+        std::map<std::string, bool>::const_iterator it = _clients.find(client);
+        if(it != _clients.end()) return it->second;
+        else return false;
+      }
+      else{
+        for(std::map<std::string, bool>::const_iterator it = _clients.begin();
+            it != _clients.end(); it++){
+          if(it->second) return true;
+        }
+        return false;
+      }
+    }
     bool getNeverChanged() const { return _neverChanged; }
     bool getVisible() const { return _visible; }
     bool getReadOnly() const { return _readOnly; }
@@ -136,10 +164,10 @@ namespace onelab{
     {
       return _attributes;
     }
-    const std::set<std::string> &getClients() const { return _clients; }
+    const std::map<std::string, bool> &getClients() const { return _clients; }
     static char charSep() { return '\0'; }
     static double maxNumber() { return 1e200; }
-    static std::string version() { return "1.05"; }
+    static std::string version() { return "1.1"; }
     static std::string getNextToken(const std::string &msg,
                                     std::string::size_type &first,
                                     char separator=charSep())
@@ -185,7 +213,6 @@ namespace onelab{
               << sanitize(getLabel()) << charSep()
               << sanitize(getHelp()) << charSep()
               << (getNeverChanged() ? 1 : 0) << charSep()
-              << (getChanged() ? 1 : 0) << charSep()
               << (getVisible() ? 1 : 0) << charSep()
               << (getReadOnly() ? 1 : 0) << charSep()
               << _attributes.size() << charSep();
@@ -194,9 +221,10 @@ namespace onelab{
         sstream << sanitize(it->first) << charSep()
                 << sanitize(it->second) << charSep();
       sstream << getClients().size() << charSep();
-      for(std::set<std::string>::const_iterator it = getClients().begin();
+      for(std::map<std::string, bool>::const_iterator it = getClients().begin();
           it != getClients().end(); it++)
-        sstream << sanitize(*it) << charSep();
+        sstream << sanitize(it->first) << charSep()
+                << (it->second ? 1 : 0) << charSep();
       return sstream.str();
     }
     virtual std::string::size_type fromChar(const std::string &msg)
@@ -208,7 +236,6 @@ namespace onelab{
       setLabel(getNextToken(msg, pos));
       setHelp(getNextToken(msg, pos));
       setNeverChanged(atoi(getNextToken(msg, pos).c_str()));
-      setChanged(atoi(getNextToken(msg, pos).c_str()));
       setVisible(atoi(getNextToken(msg, pos).c_str()));
       setReadOnly(atoi(getNextToken(msg, pos).c_str()));
       int numAttributes = atoi(getNextToken(msg, pos).c_str());
@@ -219,7 +246,8 @@ namespace onelab{
       int numClients = atoi(getNextToken(msg, pos).c_str());
       for(int i = 0; i < numClients; i++){
         std::string client(getNextToken(msg, pos));
-        addClient(client);
+        int changed = atoi(getNextToken(msg, pos).c_str());
+        addClient(client, changed ? true : false);
       }
       return pos;
     }
@@ -254,7 +282,7 @@ namespace onelab{
     {
       time_t now;
       time(&now);
-      fprintf(fp, "OneLab database created by %s on %s",
+      fprintf(fp, "ONELAB database created by %s on %s",
               creator.c_str(), ctime(&now));
       for(unsigned int i = 0; i < msg.size(); i++){
         fprintf(fp, "%d ", (int)msg[i].size());
@@ -329,7 +357,7 @@ namespace onelab{
     }
     void update(const number &p)
     {
-      addClients(p.getClients()); // complete the list of clients
+      addClients(p.getClients());
       setLabel(p.getLabel());
       setHelp(p.getHelp());
       setVisible(p.getVisible());
@@ -654,19 +682,20 @@ namespace onelab{
       return false;
     }
     // set a parameter in the parameter space; if it already exists, update it
-    // (adding new clients if necessary). This needs to be locked to avoid race
-    // conditions when several clients try to set a parameter at the same time.
+    // (adding new clients if necessary). This would need to be locked to avoid
+    // race conditions when several clients try to set a parameter at the same
+    // time.
     template <class T> bool _set(const T &p, const std::string &client,
                                  std::set<T*, parameterLessThan> &ps)
     {
       typename std::set<T*, parameterLessThan>::iterator it = ps.find((T*)&p);
       if(it != ps.end()){
         (*it)->update(p);
-        if(client.size()) (*it)->addClient(client);
+        if(client.size()) (*it)->addClient(client, true);
       }
       else{
         T* newp = new T(p);
-        if(client.size()) newp->addClient(client);
+        if(client.size()) newp->addClient(client, true);
         ps.insert(newp);
       }
       return true;
@@ -674,7 +703,7 @@ namespace onelab{
     // get the parameter matching the given name, or all the parameters in the
     // category if no name is given. If we find a given parameter by name, we
     // add the client requesting the parameter to the list of clients for this
-    // parameter. This also needs to be locked.
+    // parameter. This would also need to be locked.
     template <class T> bool _get(std::vector<T> &p, const std::string &name,
                                  const std::string &client,
                                  std::set<T*, parameterLessThan> &ps)
@@ -689,7 +718,7 @@ namespace onelab{
         T tmp(name);
         typename std::set<T*, parameterLessThan>::iterator it = ps.find(&tmp);
         if(it != ps.end()){
-          if(client.size()) (*it)->addClient(client);
+          if(client.size()) (*it)->addClient(client, true);
           p.push_back(**it);
         }
       }
@@ -763,23 +792,21 @@ namespace onelab{
       _getAllParameters(ps);
       for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin();
           it != ps.end(); it++){
-        if((client.empty() || (*it)->hasClient(client)) && (*it)->getChanged()){
+        if((*it)->getChanged(client)){
           return true;
         }
       }
       return false;
     }
-    // set the changed flag for all parameters (optionnally only affect those
-    // parameters that depend on a given client)
-    bool setChanged(bool changed, const std::string &client="")
+    // set the changed flag for all the parameters that depend on the give
+    // client (or for all parameters if no client name is provided)
+    void setChanged(bool changed, const std::string &client="")
     {
       std::set<parameter*, parameterLessThan> ps;
       _getAllParameters(ps);
       for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin();
           it != ps.end(); it++)
-        if(client.empty() || (*it)->hasClient(client))
-          (*it)->setChanged(changed);
-      return true;
+        (*it)->setChanged(changed, client);
     }
     // serialize the parameter space (optionally only serialize those parameters
     // that depend on the given client)
@@ -849,6 +876,7 @@ namespace onelab{
     virtual void sendError(const std::string &msg){ std::cerr << msg << std::endl; }
     virtual void sendProgress(const std::string &msg){ std::cout << msg << std::endl; }
     virtual void sendMergeFileRequest(const std::string &msg){}
+    virtual void sendOpenProjectRequest(const std::string &msg){}
     virtual void sendParseStringRequest(const std::string &msg){}
     virtual void sendVertexArray(const std::string &msg){}
     virtual bool clear(const std::string &name) = 0;
@@ -1137,7 +1165,8 @@ namespace onelab{
       }
       return true;
     }
-    void _waitOnSubClients()
+  public:
+    void waitOnSubClients()
     {
       if(!_gmshClient) return;
       while(_numSubClients > 0){
@@ -1180,7 +1209,7 @@ namespace onelab{
     virtual ~remoteNetworkClient()
     {
       if(_gmshClient){
-        _waitOnSubClients();
+        waitOnSubClients();
         _gmshClient->Stop();
         _gmshClient->Disconnect();
         delete _gmshClient;
@@ -1229,11 +1258,15 @@ namespace onelab{
     {
       if(_gmshClient) _gmshClient->MergeFile(msg.c_str());
     }
+    void sendOpenProjectRequest(const std::string &msg)
+    {
+      if(_gmshClient) _gmshClient->OpenProject(msg.c_str());
+    }
     void sendParseStringRequest(const std::string &msg)
     {
       if(_gmshClient) _gmshClient->ParseString(msg.c_str());
     }
-    void runSubClient(const std::string &name, const std::string &command)
+    void runNonBlockingSubClient(const std::string &name, const std::string &command)
     {
       if(!_gmshClient){
         system(command.c_str());
@@ -1242,7 +1275,11 @@ namespace onelab{
       std::string msg = name + parameter::charSep() + command;
       _gmshClient->SendMessage(GmshSocket::GMSH_CONNECT, msg.size(), &msg[0]);
       _numSubClients += 1;
-      _waitOnSubClients();
+    }
+    void runSubClient(const std::string &name, const std::string &command)
+    {
+      runNonBlockingSubClient(name, command);
+      waitOnSubClients();
     }
   };
 
diff --git a/wrappers/gmshpy/gmshGeo.i b/wrappers/gmshpy/gmshGeo.i
index da667b3..67e3432 100644
--- a/wrappers/gmshpy/gmshGeo.i
+++ b/wrappers/gmshpy/gmshGeo.i
@@ -58,6 +58,7 @@ namespace std {
   %template(DoubleVector) std::vector<double, std::allocator<double> >;
   %template(DoubleVectorVector) std::vector<std::vector<double, std::allocator<double> > >;
   %template(StringVector) std::vector<std::string, std::allocator<std::string> >;
+  %template(SPoint3Vector) std::vector<SPoint3, std::allocator<SPoint3> >;
 }
 
 %include "GmshConfig.h"
@@ -72,6 +73,8 @@ namespace std {
 %include "GPoint.h"  
 %include "GEntity.h"
 %include "GVertex.h"
+%apply std::vector<double> &OUTPUT{std::vector<double> &ts}
+%apply std::vector<SPoint3> &OUTPUT{std::vector<SPoint3> &dpts}
 %include "GEdge.h"
 %include "GFace.h"
 %include "GRegion.h"
@@ -80,6 +83,7 @@ namespace std {
 %include "discreteEdge.h"
 %include "discreteVertex.h"
 %include "discreteRegion.h"
+%include "SPoint3.h"
 %include "MElement.h"
 %include "MVertex.h"
 %include "MTriangle.h"
@@ -91,7 +95,6 @@ namespace std {
 %include "MFace.h"
 %include "MPoint.h"
 %include "SVector3.h"
-%include "SPoint3.h"
 %include "SPoint2.h"
 %include "SBoundingBox3d.h"
 %include "Curvature.h"
@@ -138,3 +141,10 @@ namespace std {
 
 }
 
+%extend MElement {
+  SPoint3 pnt(double xi0, double xi1, double xi2) {
+    SPoint3 p;
+    $self->pnt(xi0, xi1, xi2, p);
+    return p;
+  }
+}
diff --git a/wrappers/gmshpy/gmshSolver.i b/wrappers/gmshpy/gmshSolver.i
index 2743ac5..881d8ad 100644
--- a/wrappers/gmshpy/gmshSolver.i
+++ b/wrappers/gmshpy/gmshSolver.i
@@ -38,5 +38,6 @@
 %template(linearSystemPETScDouble) linearSystemPETSc<double>;
 %template(linearSystemPETScBlockDouble) linearSystemPETSc<fullMatrix<double> >;
 #endif
+%template(vectorComplexDouble) std::vector<std::complex<double> >;
 %include "eigenSolver.h"
 #endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/gmsh.git



More information about the debian-science-commits mailing list