diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index b33f25bc73bba616361407962ae32fb8c2572304..c81b31c02be113b251bec359139ad5506d506287 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -1,4 +1,4 @@
-// $Id: GModel.cpp,v 1.67 2008-02-24 14:55:36 geuzaine Exp $
+// $Id: GModel.cpp,v 1.68 2008-03-08 22:03:12 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -38,7 +38,8 @@ extern Context_T CTX;
 std::vector<GModel*> GModel::list;
 
 GModel::GModel(std::string name)
-  : _geo_internals(0), _occ_internals(0), modelName(name), normals(0)
+  : _maxVertexDataIndex(-1), _geo_internals(0), _occ_internals(0), 
+    modelName(name), normals(0)
 {
   list.push_back(this);
   // at the moment we always create (at least an empty) GEO model
@@ -95,6 +96,7 @@ void GModel::destroy()
 
   _vertexVectorCache.clear();
   _vertexMapCache.clear();
+  _maxVertexDataIndex = -1;
 
   MVertex::resetGlobalNumber();
   MElement::resetGlobalNumber();
@@ -287,7 +289,7 @@ void GModel::deletePhysicalGroup(int dim, int num)
   }
 }
 
-int GModel::maxPhysicalNumber()
+int GModel::getMaxPhysicalNumber()
 {
   int num = 0;
   for(viter it = firstVertex(); it != lastVertex(); ++it)
@@ -314,7 +316,7 @@ int GModel::setPhysicalName(std::string name, int number)
     ++it;
   }
   // if no number is given, find the next available one
-  if(!number) number = maxPhysicalNumber() + 1;
+  if(!number) number = getMaxPhysicalNumber() + 1;
   physicalNames[number] = name;
   return number;
 }
diff --git a/Geo/GModel.h b/Geo/GModel.h
index 14f6c67422fdf4416f357dee41245632fda8df14..89ff9f056d83596f8a023d7f0a49f1a761381257 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -41,6 +41,7 @@ class GModel
   // post-processing I/O)
   std::vector<MVertex*> _vertexVectorCache;
   std::map<int, MVertex*> _vertexMapCache;
+  int _maxVertexDataIndex;
 
   GEO_Internals *_geo_internals;
   void createGEOInternals();
@@ -126,7 +127,7 @@ class GModel
   void deletePhysicalGroup(int dim, int num);
 
   // Returns the highest number associated with a physical entity
-  int maxPhysicalNumber();
+  int getMaxPhysicalNumber();
 
   // Get an iterator on the physical name
   piter firstPhysicalName() { return physicalNames.begin(); }
@@ -162,6 +163,10 @@ class GModel
   // Renumber all the (used) mesh vertices in a continuous sequence
   int renumberMeshVertices(bool saveAll);
 
+  // Get/set the maximum data index used in mesh vertices
+  int getMaxVertexDataIndex(){ return _maxVertexDataIndex; }
+  void setMaxVertexDataIndex(int n){ _maxVertexDataIndex = n; }
+
   // Deletes all invisble mesh elements
   void removeInvisibleElements();
 
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index f80268ca45fb35ff48eeea97070d7a0bf0462955..8538698231f4a5c00f54ec128ee079aa0d7851cb 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: GModelIO_Mesh.cpp,v 1.39 2008-03-01 01:32:02 geuzaine Exp $
+// $Id: GModelIO_Mesh.cpp,v 1.40 2008-03-08 22:03:12 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -262,6 +262,18 @@ static void createElementMSH(GModel *m, int num, int type, int physical,
   if(part) m->getMeshPartitions().insert(part);
 }
 
+std::string extractDoubleQuotedString(char *str, int len)
+{
+  char *c = strstr(str, "\"");
+  if(!c) return "";
+  std::string ret;
+  for(int i = 1; i < len; i++) {
+    if(c[i] == '"' || c[i] == EOF || c[i] == '\n' || c[i] == '\r') break;
+    ret.push_back(c[i]);
+  }
+  return ret;
+}
+
 int GModel::readMSH(const std::string &name)
 {
   FILE *fp = fopen(name.c_str(), "rb");
@@ -318,18 +330,8 @@ int GModel::readMSH(const std::string &name)
 	int num;
 	if(fscanf(fp, "%d", &num) != 1) return 0;
 	if(!fgets(str, sizeof(str), fp)) return 0;
-	char *c = strstr(str, "\"");
-	if(c){
-	  char name[256];
-	  int i = 0;
-	  while (*(++c) != '"') {
-	    if(*c == EOF || *c == '\n' || *c == '\r') break;
-	    if(i > 255) break;
-	    name[i++] = *c;
-	  }
-	  name[i] = '\0';
-	  setPhysicalName(std::string(name), num);
-	}
+	std::string name = extractDoubleQuotedString(str, 256);
+	if(name.size()) setPhysicalName(name, num);
       }
 
     }
diff --git a/Geo/OCCEdge.h b/Geo/OCCEdge.h
index ed22bfdaf1346ffa3133ff8f879ccdc7dec8c780..4366a63f91e930e05095c2054b550c91660bfbcd 100644
--- a/Geo/OCCEdge.h
+++ b/Geo/OCCEdge.h
@@ -33,7 +33,7 @@ class OCCEdge : public GEdge {
  protected:
   TopoDS_Edge c;
   TopoDS_Edge c_rev;
-  double s0,s1;
+  double s0, s1;
   Handle(Geom_Curve) curve;
   mutable Handle(Geom2d_Curve) curve2d;
   mutable GFace *trimmed;
diff --git a/Graphics/Post.cpp b/Graphics/Post.cpp
index 0b69dc3cb2a9ebeffde99b75adfa2b262d45d22a..47e085ccf663347b36f1fbcdeff79d8df0d83a5e 100644
--- a/Graphics/Post.cpp
+++ b/Graphics/Post.cpp
@@ -1,4 +1,4 @@
-// $Id: Post.cpp,v 1.154 2008-03-01 01:32:02 geuzaine Exp $
+// $Id: Post.cpp,v 1.155 2008-03-08 22:03:12 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -894,7 +894,7 @@ void addElementsInArrays(PView *p, bool preprocessNormalsOnly)
   for(int ent = 0; ent < data->getNumEntities(); ent++){
     if(data->skipEntity(ent)) continue;
     for(int i = 0; i < data->getNumElements(ent); i++){
-      if(data->skipElement(ent, i)) continue;
+      if(data->skipElement(ent, i, opt->TimeStep)) continue;
       int numEdges = data->getNumEdges(ent, i);
       if(opt->skipElement(numEdges)) continue;
       int numComp = data->getNumComponents(ent, i);
@@ -1133,7 +1133,7 @@ void drawGlyphs(PView *p)
   for(int ent = 0; ent < data->getNumEntities(); ent++){
     if(data->skipEntity(ent)) continue;
     for(int i = 0; i < data->getNumElements(ent); i++){
-      if(data->skipElement(ent, i)) continue;
+      if(data->skipElement(ent, i, opt->TimeStep)) continue;
       int numEdges = data->getNumEdges(ent, i);
       if(opt->skipElement(numEdges)) continue;
       int dim = data->getDimension(ent, i);
diff --git a/Mesh/BDS.h b/Mesh/BDS.h
index 68230870ba0ad64e86c1d6d2c36c06bf14a4e7f0..124d5d872ec5c952be95cf6af9e1af6dd27a9cd3 100644
--- a/Mesh/BDS.h
+++ b/Mesh/BDS.h
@@ -1,3 +1,6 @@
+#ifndef _BDS_H_
+#define _BDS_H_
+
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
 // This program is free software; you can redistribute it and/or modify
@@ -22,9 +25,6 @@
 // points may know the normals to the surface they are classified on
 // default values are 0,0,1
 
-#ifndef _BDS_GMSH_H_
-#define _BDS_GMSH_H_
-
 #include <string>
 #include <set>
 #include <map>
diff --git a/Mesh/meshGRegionLocalMeshMod.h b/Mesh/meshGRegionLocalMeshMod.h
index 7dc39e545597cf9b4a0d850afb5a727db026dc45..f17c2e0aadcea287beafb541dbb4d6a714b1e06b 100644
--- a/Mesh/meshGRegionLocalMeshMod.h
+++ b/Mesh/meshGRegionLocalMeshMod.h
@@ -1,5 +1,5 @@
-#ifndef _MESHGREGIONLOCALMESHMOD_H_
-#define _MESHGREGIONLOCALMESHMOD_H_
+#ifndef _MESH_GREGION_LOCAL_MESH_MOD_H_
+#define _MESH_GREGION_LOCAL_MESH_MOD_H_
 
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -22,48 +22,36 @@
 
 #include "meshGRegionDelaunayInsertion.h"
 #include "qualityMeasures.h"
-// local mesh modification operators. Those
-// operators only apply to the "bulk" of the
-// mesh and cannot be applied to boudnaries.
-// I'm working on it
 
-enum gmshLocalMeshModAction {GMSH_DOIT,GMSH_EVALONLY};
+// Local mesh modification operators. Those operators only apply to
+// the "bulk" of the mesh and cannot be applied to boudnaries.  I'm
+// working on it
 
-bool gmshEdgeSwap (std::vector<MTet4 *> &newTets,
-		   MTet4 *tet, 
-		   int iLocalEdge,
-		   const gmshQualityMeasure4Tet &cr);
+enum gmshLocalMeshModAction {GMSH_DOIT, GMSH_EVALONLY};
 
-bool gmshFaceSwap (std::vector<MTet4 *> &newTets,
-		   MTet4 *tet, 
-		   int iLocalFace,
-		   const gmshQualityMeasure4Tet &cr);
+bool gmshEdgeSwap(std::vector<MTet4*> &newTets, MTet4 *tet, 
+		  int iLocalEdge, const gmshQualityMeasure4Tet &cr);
 
-bool gmshSmoothVertex ( MTet4 *t, 
-			int iLocalVertex,
-			const gmshQualityMeasure4Tet &cr);
+bool gmshFaceSwap(std::vector<MTet4*> &newTets, MTet4 *tet, 
+		  int iLocalFace, const gmshQualityMeasure4Tet &cr);
 
-bool gmshSmoothVertexOptimize ( MTet4 *t, 
-				int iVertex,
-				const gmshQualityMeasure4Tet &cr);
+bool gmshSmoothVertex(MTet4 *t, int iLocalVertex,
+		      const gmshQualityMeasure4Tet &cr);
 
-bool gmshCollapseVertex ( std::vector<MTet4 *> &newTets,
-			  MTet4 *t, 
-			  int iVertex,
-			  int iTarget,
-			  const gmshQualityMeasure4Tet &cr,
-			  const gmshLocalMeshModAction = GMSH_DOIT,
-			  double *result = 0);
+bool gmshSmoothVertexOptimize(MTet4 *t, int iVertex,
+			      const gmshQualityMeasure4Tet &cr);
 
-bool gmshEdgeSplit (std::vector<MTet4 *> &newTets,
-		    MTet4 *tet,
-		    MVertex *newVertex,
-		    int iLocalEdge,
-		    const gmshQualityMeasure4Tet &cr);
+bool gmshCollapseVertex(std::vector<MTet4*> &newTets, MTet4 *t, 
+			int iVertex, int iTarget,
+			const gmshQualityMeasure4Tet &cr,
+			const gmshLocalMeshModAction = GMSH_DOIT,
+			double *result = 0);
 
-bool gmshSliverRemoval ( std::vector<MTet4 *> &newTets,
-			 MTet4 *t, 
-			 const gmshQualityMeasure4Tet &cr);
-#endif
+bool gmshEdgeSplit(std::vector<MTet4*> &newTets, MTet4 *tet,
+		   MVertex *newVertex, int iLocalEdge,
+		   const gmshQualityMeasure4Tet &cr);
 
+bool gmshSliverRemoval(std::vector<MTet4*> &newTets, MTet4 *t, 
+		       const gmshQualityMeasure4Tet &cr);
 
+#endif
diff --git a/Numeric/GaussLegendre1D.h b/Numeric/GaussLegendre1D.h
index a3da4ddd3e6f5c7cff6e957b07e9dcafc0f371c2..75513954642f4e29cfe60933a3f87d67e5a02389 100644
--- a/Numeric/GaussLegendre1D.h
+++ b/Numeric/GaussLegendre1D.h
@@ -1,5 +1,5 @@
-#ifndef _GMSH_GAUSS_LEGENDRE_1D_H_
-#define _GMSH_GAUSS_LEGENDRE_1D_H_
+#ifndef _GAUSS_LEGENDRE_1D_H_
+#define _GAUSS_LEGENDRE_1D_H_
 
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -68,7 +68,7 @@ static double _GL_pt6[6]={
 static double _GL_wt6[6]={
   1.713244923791705e-01, 3.607615730481386e-01, 4.679139345726913e-01, 4.679139345726913e-01, 3.607615730481386e-01, 1.713244923791705e-01};
 
-inline void gmshGaussLegendre1D(int nbQuadPoints , double **t, double **w)
+inline void gmshGaussLegendre1D(int nbQuadPoints, double **t, double **w)
 {
   switch (nbQuadPoints){
   case 1:
diff --git a/Post/PView.cpp b/Post/PView.cpp
index d017befc217cbd3a21f917c4c4be67bfb59f1738..1207219a5e0165773d862e6abbd9fbb6b2642629 100644
--- a/Post/PView.cpp
+++ b/Post/PView.cpp
@@ -1,4 +1,4 @@
-// $Id: PView.cpp,v 1.19 2008-03-03 22:04:22 geuzaine Exp $
+// $Id: PView.cpp,v 1.20 2008-03-08 22:03:12 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -211,10 +211,13 @@ void PView::combine(bool time, int how, bool remove)
       delete *it;
 }
 
-PView *PView::getViewByName(std::string name)
+PView *PView::getViewByName(std::string name, int noTimeStep)
 {
-  for(unsigned int i = 0; i < list.size(); i++)
-    if(list[i]->getData()->getName() == name) return list[i];
+  for(unsigned int i = 0; i < list.size(); i++){
+    if(list[i]->getData()->getName() == name &&
+       (noTimeStep < 0 || noTimeStep >= list[i]->getData()->getNumTimeSteps()))
+      return list[i];
+  }
   return 0;
 }
 
@@ -299,6 +302,8 @@ bool PView::readPOS(std::string filename, int fileIndex)
   return true;
 }
 
+extern std::string extractDoubleQuotedString(char *str, int len);
+
 bool PView::readMSH(std::string filename, int fileIndex)
 {
   FILE *fp = fopen(filename.c_str(), "rb");
@@ -308,8 +313,8 @@ bool PView::readMSH(std::string filename, int fileIndex)
   }
 
   char str[256];
-  double version;
-  int format, size, index = -1;
+  int index = -1;
+  bool binary = false, swap = false;
 
   while(1) {
 
@@ -321,28 +326,47 @@ bool PView::readMSH(std::string filename, int fileIndex)
     if(feof(fp))
       break;
 
-    if(!strncmp(&str[1], "NodeData", 8)) {
+    if(!strncmp(&str[1], "MeshFormat", 10)) {
+      double version;
+      int format, size;
+      if(fscanf(fp, "%lf %d %d", &version, &format, &size) != 3) return 0;
+      if(format){
+	binary = true;
+	Msg(INFO, "Mesh is in binary format");
+	int one;
+	if(fread(&one, sizeof(int), 1, fp) != 1) return 0;
+	if(one != 1){
+	  swap = true;
+	  Msg(INFO, "Swapping bytes from binary file");
+	}
+      }
+    }
+    else if(!strncmp(&str[1], "NodeData", 8)) {
       index++;
       if(fileIndex < 0 || fileIndex == index){
+	// read data info
+	if(!fgets(str, sizeof(str), fp)) return 0;
+	std::string name = extractDoubleQuotedString(str, 256);
+	int timeStep, numComp, numNodes;
+	double time;
+	if(fscanf(fp, "%d %lf %d %d", &timeStep, &time, &numComp, &numNodes) != 4)
+	  return 0;
 	// either get existing viewData, or create new one
-	// check timestep storage limit, do magic if exceeded
-	PView *p = 0;
-	PViewDataGModel *d;
-	// read view name and timestep
-	// if append
-	//   p = getView
-	//   d = p->getData()
-	// else
-   	d = new PViewDataGModel(GModel::current());
-	if(!d->readMSH(fp)){
+	PView *p = getViewByName(name, timeStep);
+	PViewDataGModel *d = 0;
+	if(p) d = dynamic_cast<PViewDataGModel*>(p->getData());
+	bool create = d ? false : true;
+	if(create) d = new PViewDataGModel(GModel::current());
+	if(!d->readMSH(fp, binary, swap, timeStep, time, numComp, numNodes)){
 	  Msg(GERROR, "Could not read data in msh file");
-	  delete d;
+	  if(create) delete d;
 	  return false;
 	}
 	else{
+	  d->setName(name);
 	  d->setFileName(filename);
 	  d->setFileIndex(index);
-	  if(!p) new PView(d);
+	  if(create) new PView(d);
 	}
       }
     }
diff --git a/Post/PView.h b/Post/PView.h
index 4813d122cc74703915293da0fd92e50d6729d62e..b1d52300f3138f9c763278341d61c40a15349015 100644
--- a/Post/PView.h
+++ b/Post/PView.h
@@ -80,8 +80,9 @@ class PView{
   // combine view
   static void combine(bool time, int how, bool remove);
 
-  // combine view
-  static PView *getViewByName(std::string name);
+  // find view by name (if noTimeStep >= 0, return view only if it
+  // does *not* contain that timestep)
+  static PView *getViewByName(std::string name, int noTimeStep=-1);
 
   // read view(s) in list format from a file
   static bool readPOS(std::string filename, int fileIndex=-1);
diff --git a/Post/PViewData.h b/Post/PViewData.h
index 751b7ac473c388cffcd226a66b86ea0b1480560e..b4da85e1e92fe1b2b5378667aac41b55659dca8c 100644
--- a/Post/PViewData.h
+++ b/Post/PViewData.h
@@ -24,6 +24,8 @@
 #include <vector>
 #include "SBoundingBox3d.h"
 
+#define VAL_INF 1.e200
+
 class nameData;
 
 // abstract interface to post-processing view data
@@ -101,7 +103,7 @@ class PViewData {
   virtual bool combineSpace(nameData &nd){ return false; }
   virtual bool isAdaptive(){ return false; }
   virtual bool skipEntity(int ent){ return false; }
-  virtual bool skipElement(int ent, int ele){ return false; }
+  virtual bool skipElement(int ent, int ele, int step){ return false; }
 
   // I/O routines
   virtual bool writeSTL(std::string name);
diff --git a/Post/PViewDataGModel.cpp b/Post/PViewDataGModel.cpp
index b10b4e7c066b107000d21fa7f174aef8cf94dfd9..3498baa50a405a136f48564bfaa07027b3401abe 100644
--- a/Post/PViewDataGModel.cpp
+++ b/Post/PViewDataGModel.cpp
@@ -1,4 +1,4 @@
-// $Id: PViewDataGModel.cpp,v 1.21 2008-03-04 08:51:14 geuzaine Exp $
+// $Id: PViewDataGModel.cpp,v 1.22 2008-03-08 22:03:13 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -25,7 +25,8 @@
 #include "PViewDataGModel.h"
 #include "MElement.h"
 
-PViewDataGModel::PViewDataGModel(GModel *model) : _model(model)
+PViewDataGModel::PViewDataGModel(GModel *model) 
+  : _model(model), _min(VAL_INF), _max(-VAL_INF)
 
 {
   // store vector of GEntities so we can index them efficiently
@@ -35,67 +36,52 @@ PViewDataGModel::PViewDataGModel(GModel *model) : _model(model)
     _entities.push_back(*it);
   for(GModel::riter it = _model->firstRegion(); it != _model->lastRegion(); ++it)
     _entities.push_back(*it);
-  
-  /* 
-     class data{
-      public:
-       time_t lastUsed; // to determine which one to free first?
-       std::string fileName; // we allow to read steps from different files
-       int fileIndex;
-       double time;
-       // vector of data, indexed by dataIndex
-       std::vector<std::vector<double> > values;
-     }
-     std::vector<data*> nodeData, elementData;
-     
-     When reading a .msh file:
-
-     if(nodeData[step - 1].size())
-       nodeData[step].values.resize(nodeData[step - 1].size());
-     else
-       nodeData[step].values.resize(numDataInFile);
-     loop over lines:
-       * get node number in file
-       * get vertex pointer from _model->getMeshVertexByTag(num)
-       * if MVertex has no dataIndex:
-           increment it (need global value stored in GModel)
-         else
-           use the one that's stored
-       * if(dataIndex > nodeData[step].size()) nodeData[step].resize(dataIndex + 1)
-       * fill nodeData[step].value[dataIndex]
-
-     .msh file format:
-
-     $NodeData
-     "name"
-     time-step time-value precision num-components num-nodes
-     num-node values...
-     num-node values...
-     ...
-     $EndNodeData
-
-     The number of time steps stored should be an option. We should be
-     able to dynamically load/unload time step data on-the-fly.
-  */
 }
 
 PViewDataGModel::~PViewDataGModel()
 {
+  for(unsigned int i = 0; i < _nodeData.size(); i++)
+    if(_nodeData[i]) delete _nodeData[i];
+}
+
+bool PViewDataGModel::finalize()
+{
+  _min = VAL_INF;
+  _max = -VAL_INF;
+  for(unsigned int i = 0; i < _nodeData.size(); i++){
+    if(_nodeData[i]){
+      _min = std::min(_min, _nodeData[i]->min);
+      _max = std::max(_max, _nodeData[i]->max);
+    }
+  }
+  setDirty(false);
+  return true;
+}
+
+int PViewDataGModel::getNumTimeSteps()
+{
+  return std::max(_nodeData.size(), _elementData.size());
 }
 
 double PViewDataGModel::getTime(int step)
 {
-  return 0;
+  if(step < _nodeData.size() && _nodeData[step])
+    return _nodeData[step]->time;
+  return 0.;
 }
 
 double PViewDataGModel::getMin(int step)
 {
-  return 0;
+  if(step < 0) return _min;
+  if(step < _nodeData.size() && _nodeData[step]) return _nodeData[step]->min;
+  return 0.;
 }
 
 double PViewDataGModel::getMax(int step)
 {
-  return 1;
+  if(step < 0) return _max;
+  if(step < _nodeData.size() && _nodeData[step]) return _nodeData[step]->max;
+  return 0.;
 }
 
 int PViewDataGModel::getNumEntities()
@@ -129,13 +115,18 @@ void PViewDataGModel::getNode(int ent, int ele, int nod, double &x, double &y, d
 
 int PViewDataGModel::getNumComponents(int ent, int ele)
 {
-  return 1; 
+  MVertex *v = _entities[ent]->getMeshElement(ele)->getVertex(0);
+  int index = v->getDataIndex();
+  // no range check here: we assume this call is guarded by skipElement()
+  return _nodeData[0]->values[index].size();
 }
 
 void PViewDataGModel::getValue(int ent, int ele, int nod, int comp, int step, double &val)
 {
   MVertex *v = _entities[ent]->getMeshElement(ele)->getVertex(nod);
-  val = v->z();
+  int index = v->getDataIndex();
+  // no range check here: we assume this call is guarded by skipElement()
+  val = _nodeData[step]->values[index][comp];
 }
 
 int PViewDataGModel::getNumEdges(int ent, int ele)
@@ -148,8 +139,15 @@ bool PViewDataGModel::skipEntity(int ent)
   return !_entities[ent]->getVisibility();
 }
 
-bool PViewDataGModel::skipElement(int ent, int ele)
+bool PViewDataGModel::skipElement(int ent, int ele, int step)
 {
-  return !_entities[ent]->getMeshElement(ele)->getVisibility();
+  if(step >= _nodeData.size() || !_nodeData[step]) return true;
+  MElement *e = _entities[ent]->getMeshElement(ele);
+  if(!e->getVisibility()) return true;
+  for(int i = 0; i < e->getNumVertices(); i++){
+    int index = e->getVertex(i)->getDataIndex();
+    if(index < 0 || index >= _nodeData[step]->values.size()) return true;
+    if(_nodeData[step]->values[index].empty()) return true;
+  }
+  return false;
 }
-
diff --git a/Post/PViewDataGModel.h b/Post/PViewDataGModel.h
index e39d533e8b86751bce681d05f75aef2684a998e0..63231058775979c0c78b0cc90bb379951d4e9158 100644
--- a/Post/PViewDataGModel.h
+++ b/Post/PViewDataGModel.h
@@ -25,16 +25,31 @@
 #include "GModel.h"
 #include "SBoundingBox3d.h"
 
+template<class real>
+class stepData{
+ public:
+  std::string fileName; // we allow to read steps from different files
+  int fileIndex;
+  double time, min, max;
+  // vector of data, indexed by dataIndex
+  std::vector<std::vector<real> > values;
+  stepData() : fileIndex(0), time(0.), min(VAL_INF), max(-VAL_INF){}
+  ~stepData() {}
+};
+
 // data container using elements from a GModel
 class PViewDataGModel : public PViewData {
  private:
   GModel *_model;
   std::vector<GEntity*> _entities;
+  std::vector<stepData<double>*> _nodeData, _elementData;
   PViewDataList *_cloneToList(); // create old-style data from this
+  double _min, _max;
  public:
   PViewDataGModel(GModel *model);
   ~PViewDataGModel();
-  int getNumTimeSteps(){ return 1; }
+  bool finalize();
+  int getNumTimeSteps();
   double getTime(int step);
   double getMin(int step=-1);
   double getMax(int step=-1);
@@ -48,10 +63,11 @@ class PViewDataGModel : public PViewData {
   void getValue(int ent, int ele, int node, int comp, int step, double &val);
   int getNumEdges(int ent, int ele);
   bool skipEntity(int ent);
-  bool skipElement(int ent, int ele);
+  bool skipElement(int ent, int ele, int step);
 
   // I/O routines
-  bool readMSH(FILE *fp);
+  bool readMSH(FILE *fp, bool binary, bool swap, int timeStep, double time, 
+	       int numComp, int numNodes);
 };
 
 #endif
diff --git a/Post/PViewDataGModelIO.cpp b/Post/PViewDataGModelIO.cpp
index 48c71a2ada5228abedd0084dcc1b46accc375c9d..72a66a098e36057bd2a9127c481963ad6b987c84 100644
--- a/Post/PViewDataGModelIO.cpp
+++ b/Post/PViewDataGModelIO.cpp
@@ -1,4 +1,4 @@
-// $Id: PViewDataGModelIO.cpp,v 1.2 2008-03-01 01:32:03 geuzaine Exp $
+// $Id: PViewDataGModelIO.cpp,v 1.3 2008-03-08 22:03:13 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -25,27 +25,49 @@
 #include <string.h>
 #include "Message.h"
 #include "PViewDataGModel.h"
+#include "MVertex.h"
+#include "Numeric.h"
 
-/*
-  if(!fgets(str, sizeof(str), fp)) return 0;
-  // name = str[1] + remove final "
-  int timeStep, numData, numComponents;
-  double time;
-  if(fscanf(fp, "%d %lf %d %d", &timeStep, &time, &numData, &numComponents) != 4)
-    return 0;
-  Msg(INFO, "%d node data", numData);
-  fill in data
-*/
-
-bool PViewDataGModel::readMSH(FILE *fp)
+bool PViewDataGModel::readMSH(FILE *fp, bool binary, bool swap, int timeStep, double time, 
+			      int numComp, int numNodes)
 {
-  Msg(INFO, "Filling PViewDataGModel...");
-  
-  MVertex *v = _model->getMeshVertexByTag(10);
-  if(v){
-    printf("vertex 10 in mesh is %p\n", v);
-  }
+  Msg(INFO, "Reading step %d (time %g): %d nodes", timeStep, time, numNodes);
+
+  while(timeStep >= _nodeData.size()) _nodeData.push_back(0);
+
+  if(!_nodeData[timeStep]) _nodeData[timeStep] = new stepData<double>();
 
+  _nodeData[timeStep]->time = time;
+  _nodeData[timeStep]->values.resize(numNodes);
+
+  if(binary){
+    Msg(GERROR, "not ready yet for binary");
+    return 0;
+  }
+  else{
+    for(int i = 0; i < numNodes; i++){
+      int num;
+      if(fscanf(fp, "%d", &num) != 1) return 0;
+      MVertex *v = _model->getMeshVertexByTag(num);
+      if(!v) return 0;
+      if(v->getDataIndex() < 0){
+	int max = _model->getMaxVertexDataIndex();
+	_model->setMaxVertexDataIndex(max + 1);
+	v->setDataIndex(max + 1);
+      }
+      int index = v->getDataIndex();
+      if(index >= _nodeData[timeStep]->values.size())
+	_nodeData[timeStep]->values.resize(index + 1);
+      for(int j = 0; j < numComp; j++){
+	double val;
+	if(fscanf(fp, "%lf", &val) != 1) return 0;
+	_nodeData[timeStep]->values[index].push_back(val);
+      }
+      double s = ComputeScalarRep(numComp, &_nodeData[timeStep]->values[index][0]);
+      _nodeData[timeStep]->min = std::min(_nodeData[timeStep]->min, s);
+      _nodeData[timeStep]->max = std::max(_nodeData[timeStep]->max, s);
+    }
+  }
   finalize();
   return true;
 }
diff --git a/Post/PViewDataList.cpp b/Post/PViewDataList.cpp
index e02891d08216f4c807964bada6ece5b237bf5154..9b76dc5282b7ff788d8bcdd978584a24b11365eb 100644
--- a/Post/PViewDataList.cpp
+++ b/Post/PViewDataList.cpp
@@ -1,4 +1,4 @@
-// $Id: PViewDataList.cpp,v 1.14 2008-02-27 17:02:47 geuzaine Exp $
+// $Id: PViewDataList.cpp,v 1.15 2008-03-08 22:03:13 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -252,13 +252,7 @@ void PViewDataList::_stat(List_T *list, int nbcomp, int nbelm, int nbnod)
     
     // update min/max
     for(int j = 0; j < N; j += nbcomp) {
-      double l0;
-      if(nbcomp == 1)
-	l0 = V[j];
-      else if(nbcomp == 3)
-	l0 = sqrt(DSQR(V[j]) + DSQR(V[j + 1]) + DSQR(V[j + 2]));
-      else
-	l0 = ComputeVonMises(V + j); // FIXME: can do better?
+      double l0 = ComputeScalarRep(nbcomp, &V[j]);
       Min = std::min(l0, Min);
       Max = std::max(l0, Max);
       int ts = j / (nbcomp * nbnod);
diff --git a/Post/PViewDataList.h b/Post/PViewDataList.h
index 191b1a95c1aaba8e57b5fc09aa4dc9b461197cc4..b2f86b974754f3cc87feaed3ca2041ad6c85b681 100644
--- a/Post/PViewDataList.h
+++ b/Post/PViewDataList.h
@@ -27,8 +27,6 @@
 #include "SBoundingBox3d.h"
 #include "List.h"
 
-#define VAL_INF 1.e200
-
 // list-based datasets (all elements are discontinuous)
 class PViewDataList : public PViewData {
  public: 
diff --git a/Post/PViewDataListIO.cpp b/Post/PViewDataListIO.cpp
index e7c1d7d57ce11c27adf8f2ed846dbb6e1fd732da..de37fd672eccfcd71db5e3c138a9acf50b450675 100644
--- a/Post/PViewDataListIO.cpp
+++ b/Post/PViewDataListIO.cpp
@@ -1,4 +1,4 @@
-// $Id: PViewDataListIO.cpp,v 1.12 2008-03-03 22:04:22 geuzaine Exp $
+// $Id: PViewDataListIO.cpp,v 1.13 2008-03-08 22:03:13 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -609,7 +609,7 @@ bool PViewDataList::writeMSH(std::string name)
   if(numNodes){
     fprintf(fp, "$NodeData\n");
     fprintf(fp, "\"%s\"\n", getName().c_str());
-    int timeStep = 1, numComp = nodes.begin()->Val.size();
+    int timeStep = 0, numComp = nodes.begin()->Val.size();
     double time = 0.;
     fprintf(fp, "%d %.16g %d %d\n", timeStep, time, numComp, numNodes);
     for(std::set<pVertex, pVertexLessThan>::iterator it = nodes.begin();