Salome HOME
23636: EDF 18217 - Problem when suppressing CAD
[modules/smesh.git] / src / SMESH_I / SMESH_2smeshpy.cxx
index 60c0b2491a8bff050377059d5e62baf3a723e1e7..69b3b0f760514430b6c1374a5750e495167de815 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2013  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -6,7 +6,7 @@
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 #include <LDOMParser.hxx>
 
-#ifdef WNT
+#ifdef WIN32
 #include <windows.h>
 #else
 #include <unistd.h>
 #endif
 
-
-IMPLEMENT_STANDARD_HANDLE (_pyObject          ,Standard_Transient);
-IMPLEMENT_STANDARD_HANDLE (_pyCommand         ,Standard_Transient);
-IMPLEMENT_STANDARD_HANDLE (_pyHypothesisReader,Standard_Transient);
-IMPLEMENT_STANDARD_HANDLE (_pyGen             ,_pyObject);
-IMPLEMENT_STANDARD_HANDLE (_pyMesh            ,_pyObject);
-IMPLEMENT_STANDARD_HANDLE (_pySubMesh         ,_pyObject);
-IMPLEMENT_STANDARD_HANDLE (_pyMeshEditor      ,_pyObject);
-IMPLEMENT_STANDARD_HANDLE (_pyHypothesis      ,_pyObject);
-IMPLEMENT_STANDARD_HANDLE (_pySelfEraser      ,_pyObject);
-IMPLEMENT_STANDARD_HANDLE (_pyGroup           ,_pyObject);
-IMPLEMENT_STANDARD_HANDLE (_pyFilter          ,_pyObject);
-IMPLEMENT_STANDARD_HANDLE (_pyAlgorithm       ,_pyHypothesis);
-IMPLEMENT_STANDARD_HANDLE (_pyComplexParamHypo,_pyHypothesis);
-IMPLEMENT_STANDARD_HANDLE (_pyNumberOfSegmentsHyp,_pyHypothesis);
-
 IMPLEMENT_STANDARD_RTTIEXT(_pyObject          ,Standard_Transient);
 IMPLEMENT_STANDARD_RTTIEXT(_pyCommand         ,Standard_Transient);
 IMPLEMENT_STANDARD_RTTIEXT(_pyHypothesisReader,Standard_Transient);
@@ -88,7 +72,7 @@ using SMESH::TPythonDump;
 
 /*!
  * \brief Container of commands into which the initial script is split.
- *        It also contains data coresponding to SMESH_Gen contents
+ *        It also contains data corresponding to SMESH_Gen contents
  */
 static Handle(_pyGen) theGen;
 
@@ -183,7 +167,8 @@ namespace {
     if ( cmd->GetString().Location( TPythonDump::NotPublishedObjectName(), 1, cmd->Length() ))
     {
       bool isResultPublished = false;
-      for ( int i = 0; i < cmd->GetNbResultValues(); i++ )
+      const int nbRes = cmd->GetNbResultValues();
+      for ( int i = 0; i < nbRes; i++ )
       {
         _pyID objID = cmd->GetResultValue( i+1 );
         if ( cmd->IsStudyEntry( objID ))
@@ -198,8 +183,17 @@ namespace {
     }
     // check if an Object was created in the script
     _AString comment;
-    const _pyID& obj = cmd->GetObject();
-    if ( !obj.IsEmpty() && cmd->IsStudyEntry( obj ) && !presentObjects.count( obj ))
+
+    _pyID obj = cmd->GetObject();
+    if ( obj.Search( "print(" ) == 1 )
+      return; // print statement
+
+    if ( !obj.IsEmpty() && obj.Value( obj.Length() ) == ')' )
+      // remove an accessor method
+      obj = _pyCommand( obj ).GetObject();
+
+    const bool isMethodCall = cmd->IsMethodCall();
+    if ( !obj.IsEmpty() && isMethodCall && !presentObjects.count( obj ) )
     {
       comment = "not created Object";
       theGen->ObjectCreationRemoved( obj );
@@ -218,6 +212,8 @@ namespace {
           comment += *id + " has not been yet created";
           break;
         }
+      // if ( idList.empty() && cmd->IsID( arg ) && !presentObjects.count( arg ))
+      //   comment += arg + " has not been yet created";
     }
     // treat result objects
     const _pyID& result = cmd->GetResultValue();
@@ -226,10 +222,14 @@ namespace {
       list< _pyID > idList = cmd->GetStudyEntries( result );
       list< _pyID >::iterator id = idList.begin();
       for ( ; id != idList.end(); ++id )
+      {
         if ( comment.IsEmpty() )
           presentObjects.insert( *id );
         else
           theGen->ObjectCreationRemoved( *id ); // objID.SetName( name ) is not needed
+      }
+      if ( idList.empty() && cmd->IsID( result ))
+        presentObjects.insert( result );
     }
     // comment the command
     if ( !comment.IsEmpty() )
@@ -290,6 +290,14 @@ namespace {
     //   - FT_EntityType            = 36
     // v 7.3.0: FT_Undefined == 46, new items:
     //   - FT_ConnectedElements     = 39
+    // v 7.6.0: FT_Undefined == 47, new items:
+    //   - FT_BelongToMeshGroup     = 22
+    // v 8.1.0: FT_Undefined == 48, new items:
+    //   - FT_NodeConnectivityNumber= 22
+    // v 8.5.0: FT_Undefined == 49, new items:
+    //   - FT_Deflection2D          = 22
+    // v 9.3.0: FT_Undefined == 50, new items:
+    //   - FT_Length3D              = 22
     //
     // It's necessary to continue recording this history and to fill
     // undef2newItems (see below) accordingly.
@@ -310,6 +318,10 @@ namespace {
       undef2newItems[ 44 ].push_back( 37 );
       undef2newItems[ 45 ].push_back( 36 );
       undef2newItems[ 46 ].push_back( 39 );
+      undef2newItems[ 47 ].push_back( 22 );
+      undef2newItems[ 48 ].push_back( 22 );
+      undef2newItems[ 49 ].push_back( 22 );
+      undef2newItems[ 50 ].push_back( 22 );
 
       ASSERT( undef2newItems.rbegin()->first == SMESH::FT_Undefined );
     }
@@ -351,12 +363,12 @@ namespace {
   //================================================================================
   /*!
    * \brief Replaces "SMESH.PointStruct(x,y,z)" and "SMESH.DirStruct( SMESH.PointStruct(x,y,z))"
-   *        arguments of a given command by a list "[x,y,z]" if the list is accesible
+   *        arguments of a given command by a list "[x,y,z]" if the list is accessible
    *        type of argument.
    */
   //================================================================================
 
-  void StructToList( Handle( _pyCommand)& theCommand )
+  void StructToList( Handle( _pyCommand)& theCommand, const bool checkMethod=true )
   {
     static TStringSet methodsAcceptingList;
     if ( methodsAcceptingList.empty() ) {
@@ -368,13 +380,14 @@ namespace {
         "ExtrusionSweepObjectMakeGroups","ExtrusionSweepObject0D",
         "ExtrusionSweepObject1D","ExtrusionSweepObject1DMakeGroups",
         "ExtrusionSweepObject2D","ExtrusionSweepObject2DMakeGroups",
+        "ExtrusionSweepObjects","RotationSweepObjects","ExtrusionAlongPathObjects",
         "Translate","TranslateMakeGroups","TranslateMakeMesh",
         "TranslateObject","TranslateObjectMakeGroups", "TranslateObjectMakeMesh",
-        "ExtrusionAlongPathX","ExtrusionAlongPathObjX"
+        "ExtrusionAlongPathX","ExtrusionAlongPathObjX","SplitHexahedraIntoPrisms"
         ,"" }; // <- mark of the end
       methodsAcceptingList.Insert( methodNames );
     }
-    if ( methodsAcceptingList.Contains( theCommand->GetMethod() ))
+    if ( !checkMethod || methodsAcceptingList.Contains( theCommand->GetMethod() ))
     {
       for ( int i = theCommand->GetNbArgs(); i > 0; --i )
       {
@@ -402,7 +415,7 @@ namespace {
   //================================================================================
   /*!
    * \brief Replaces "mesh.GetIDSource([id1,id2])" argument of a given command by
-   *        a list "[id1,id2]" if the list is an accesible type of argument.
+   *        a list "[id1,id2]" if the list is an accessible type of argument.
    */
   //================================================================================
 
@@ -415,7 +428,8 @@ namespace {
         "ExportCGNS","ExportGMF",
         "Create0DElementsOnAllNodes","Reorient2D","QuadTo4Tri",
         "ScaleMakeGroups","Scale","ScaleMakeMesh",
-        "FindCoincidentNodesOnPartBut","DoubleElements"
+        "FindCoincidentNodesOnPartBut","DoubleElements",
+        "ExtrusionSweepObjects","RotationSweepObjects","ExtrusionAlongPathObjects"
         ,"" }; // <- mark of the end
       methodsAcceptingList.Insert( methodNames );
     }
@@ -432,64 +446,67 @@ namespace {
       }
     }
   }
+
+  bool _FilterArg( const _AString& theArg  )
+  {
+    static std::list<_AString> filteredArgs;
+    static bool initialized = false;
+    if ( !initialized ) {
+      initialized = true;
+      filteredArgs.push_back( "SMESH.MED_V2_1" );
+      filteredArgs.push_back( "SMESH.MED_V2_2" );
+    }  
+    return std::find( filteredArgs.begin(), filteredArgs.end(), theArg ) != filteredArgs.end();
+  }
 }
 
 //================================================================================
 /*!
  * \brief Convert a python script using commands of smeshBuilder.py
- *  \param theScript - Input script
+ *  \param theScriptLines - Lines of the input script
  *  \param theEntry2AccessorMethod - returns method names to access to
  *         objects wrapped with python class
  *  \param theObjectNames - names of objects
  *  \param theRemovedObjIDs - entries of objects whose created commands were removed
  *  \param theHistoricalDump - true means to keep all commands, false means
  *         to exclude commands relating to objects removed from study
- *  \retval TCollection_AsciiString - Convertion result
+ *  \retval TCollection_AsciiString - Conversion result
  */
 //================================================================================
 
-TCollection_AsciiString
-SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScript,
+void
+SMESH_2smeshpy::ConvertScript(std::list< TCollection_AsciiString >&     theScriptLines,
                               Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod,
                               Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
                               std::set< TCollection_AsciiString >&      theRemovedObjIDs,
-                              SALOMEDS::Study_ptr&                      theStudy,
                               const bool                                theToKeepAllCommands)
 {
-  theGen = new _pyGen( theEntry2AccessorMethod,
-                       theObjectNames,
-                       theRemovedObjIDs,
-                       theStudy,
-                       theToKeepAllCommands );
+  std::list< TCollection_AsciiString >::iterator lineIt;
+  // process notebook variables
+  {
+    SMESH_NoteBook aNoteBook;
 
-  // split theScript into separate commands
+    for ( lineIt = theScriptLines.begin(); lineIt != theScriptLines.end(); ++lineIt )
+      aNoteBook.AddCommand( *lineIt );
 
-  SMESH_NoteBook * aNoteBook = new SMESH_NoteBook();
+    theScriptLines.clear();
 
-  int from = 1, end = theScript.Length(), to;
-  while ( from < end && ( to = theScript.Location( "\n", from, end )))
-  {
-    if ( to != from )
-      // cut out and store a command
-      aNoteBook->AddCommand( theScript.SubString( from, to - 1 ));
-    from = to + 1;
+    aNoteBook.ReplaceVariables();
+
+    aNoteBook.GetResultLines( theScriptLines );
   }
 
-  aNoteBook->ReplaceVariables();
+  // convert to smeshBuilder.py API
 
-  TCollection_AsciiString aNoteScript = aNoteBook->GetResultScript();
-  delete aNoteBook;
-  aNoteBook = 0;
+  theGen = new _pyGen( theEntry2AccessorMethod,
+                       theObjectNames,
+                       theRemovedObjIDs,
+                       theToKeepAllCommands );
 
-  // split theScript into separate commands
-  from = 1, end = aNoteScript.Length();
-  while ( from < end && ( to = aNoteScript.Location( "\n", from, end )))
-  {
-    if ( to != from )
-      // cut out and store a command
-      theGen->AddCommand( aNoteScript.SubString( from, to - 1 ));
-    from = to + 1;
-  }
+  for ( lineIt = theScriptLines.begin(); lineIt != theScriptLines.end(); ++lineIt )
+    theGen->AddCommand( *lineIt );
+
+  theScriptLines.clear();
 
   // finish conversion
   theGen->Flush();
@@ -497,7 +514,7 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScrip
   MESSAGE_BEGIN ( std::endl << " ######## RESULT ######## " << std::endl<< std::endl );
 #endif
 
-  // clean commmands of removed objects depending on myIsPublished flag
+  // clean commands of removed objects depending on myIsPublished flag
   theGen->ClearCommands();
 
   // reorder commands after conversion
@@ -511,8 +528,10 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScrip
   } while ( orderChanges );
 
   // concat commands back into a script
-  TCollection_AsciiString aScript, aPrevCmd;
+  TCollection_AsciiString aPrevCmd;
   set<_pyID> createdObjects;
+  createdObjects.insert( "smeshBuilder" );
+  createdObjects.insert( "smesh" );
   for ( cmd = theGen->GetCommands().begin(); cmd != theGen->GetCommands().end(); ++cmd )
   {
 #ifdef DUMP_CONVERSION
@@ -520,17 +539,15 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScrip
 #endif
     if ( !(*cmd)->IsEmpty() && aPrevCmd != (*cmd)->GetString()) {
       CheckObjectPresence( *cmd, createdObjects );
-      aPrevCmd = (*cmd)->GetString();
-      aScript += "\n";
-      aScript += aPrevCmd;
+      if ( !(*cmd)->IsEmpty() ) {
+        aPrevCmd = (*cmd)->GetString();
+        theScriptLines.push_back( aPrevCmd );
+      }
     }
   }
-  aScript += "\n";
 
   theGen->Free();
   theGen.Nullify();
-
-  return aScript;
 }
 
 //================================================================================
@@ -542,7 +559,6 @@ SMESH_2smeshpy::ConvertScript(const TCollection_AsciiString&            theScrip
 _pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod,
                Resource_DataMapOfAsciiStringAsciiString& theObjectNames,
                std::set< TCollection_AsciiString >&      theRemovedObjIDs,
-               SALOMEDS::Study_ptr&                      theStudy,
                const bool                                theToKeepAllCommands)
   : _pyObject( new _pyCommand( "", 0 )),
     myNbCommands( 0 ),
@@ -551,7 +567,6 @@ _pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod
     myRemovedObjIDs( theRemovedObjIDs ),
     myNbFilters( 0 ),
     myToKeepAllCommands( theToKeepAllCommands ),
-    myStudy( SALOMEDS::Study::_duplicate( theStudy )),
     myGeomIDNb(0), myGeomIDIndex(-1)
 {
   // make that GetID() to return TPythonDump::SMESHGenName()
@@ -560,11 +575,11 @@ _pyGen::_pyGen(Resource_DataMapOfAsciiStringAsciiString& theEntry2AccessorMethod
   GetCreationCmd()->GetString() += "=";
 
   // Find 1st digit of study entry by which a GEOM object differs from a SMESH object
-  if ( !theObjectNames.IsEmpty() && !CORBA::is_nil( theStudy ))
+  if ( !theObjectNames.IsEmpty() )
   {
     // find a GEOM entry
     _pyID geomID;
-    SALOMEDS::SComponent_wrap geomComp = theStudy->FindComponent("GEOM");
+    SALOMEDS::SComponent_wrap geomComp = SMESH_Gen_i::getStudyServant()->FindComponent("GEOM");
     if ( geomComp->_is_nil() ) return;
     CORBA::String_var entry = geomComp->GetID();
     geomID = entry.in();
@@ -601,7 +616,7 @@ const char* _pyGen::AccessorMethod() const
 //================================================================================
 /*!
  * \brief Convert a command using a specific converter
 * \param theCommand - the command to convert
 \param theCommand - the command to convert
  */
 //================================================================================
 
@@ -630,15 +645,36 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   // Method( SMESH.PointStruct(x,y,z)... -> Method( [x,y,z]...
   StructToList( aCommand );
 
+  const TCollection_AsciiString& method = aCommand->GetMethod();
+
   // not to erase _pySelfEraser's etc. used as args in some commands
-  std::list< _pyID >::const_iterator id = myKeepAgrCmdsIDs.begin();
-  for ( ; id != myKeepAgrCmdsIDs.end(); ++id )
-    if ( *id != objID && theCommand.Search( *id ) > id->Length() )
+  {
+#ifdef USE_STRING_FAMILY
+    std::list<_pyID>  objIDs;
+    if ( myKeepAgrCmdsIDs.IsInArgs( aCommand, objIDs ))
     {
-      Handle(_pyObject) obj = FindObject( *id );
-      if ( !obj.IsNull() )
-        obj->AddArgCmd( aCommand );
+      std::list<_pyID>::iterator objID = objIDs.begin();
+      for ( ; objID != objIDs.end(); ++objID )
+      {
+        Handle(_pyObject) obj = FindObject( *objID );
+        if ( !obj.IsNull() )
+        {
+          obj->AddArgCmd( aCommand );
+          //cout << objID << " found in " << theCommand << endl;
+        }
+      }
     }
+#else
+    std::list< _pyID >::const_iterator id = myKeepAgrCmdsIDs.begin();
+    for ( ; id != myKeepAgrCmdsIDs.end(); ++id )
+      if ( *id != objID && theCommand.Search( *id ) > id->Length() )
+      {
+        Handle(_pyObject) obj = FindObject( *id );
+        if ( !obj.IsNull() )
+          obj->AddArgCmd( aCommand );
+      }
+#endif
+  }
 
   // Find an object to process theCommand
 
@@ -656,6 +692,25 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
   {
     //id_mesh->second->AddProcessedCmd( aCommand );
 
+    // Wrap Export*() into try-except
+    if ( aCommand->MethodStartsFrom("Export"))
+    {
+      _AString    tab = "\t";
+      _AString indent = aCommand->GetIndentation();
+      _AString tryStr = indent + "try:";
+      _AString newCmd = indent + tab + ( aCommand->GetString().ToCString() + indent.Length() );
+      _AString pasCmd = indent + tab + "pass"; // to keep valid if newCmd is erased
+      _AString excStr = indent + "except:";
+      _AString msgStr = indent + "\tprint('"; msgStr += method + "() failed. Invalid file name?')";
+
+      myCommands.insert( --myCommands.end(), new _pyCommand( tryStr, myNbCommands ));
+      aCommand->Clear();
+      aCommand->GetString() = newCmd;
+      aCommand->SetOrderNb( ++myNbCommands );
+      myCommands.push_back( new _pyCommand( pasCmd, ++myNbCommands ));
+      myCommands.push_back( new _pyCommand( excStr, ++myNbCommands ));
+      myCommands.push_back( new _pyCommand( msgStr, ++myNbCommands ));
+    }
     // check for mesh editor object
     if ( aCommand->GetMethod() == "GetMeshEditor" ) { // MeshEditor creation
       _pyID editorID = aCommand->GetResultValue();
@@ -667,8 +722,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
     else if ( aCommand->GetMethod() == "GetSubMesh" ) { // SubMesh creation
       _pyID subMeshID = aCommand->GetResultValue();
       Handle(_pySubMesh) subMesh = new _pySubMesh( aCommand );
-      CheckObjectIsReCreated( subMesh );
-      myObjects.insert( make_pair( subMeshID, subMesh ));
+      AddObject( subMesh );
     }
 
     // Method( mesh.GetIDSource([id1,id2]) -> Method( [id1,id2]
@@ -690,8 +744,6 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
 
     //addFilterUser( aCommand, theGen ); // protect filters from clearing
 
-    const TCollection_AsciiString& method = aCommand->GetMethod();
-
     // some commands of SMESH_MeshEditor create meshes and groups
     _pyID meshID, groups;
     if ( method.Search("MakeMesh") != -1 )
@@ -701,15 +753,16 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
     else if ( method == "MakeBoundaryElements")
       meshID = aCommand->GetResultValue(2);
 
-    if ( method.Search("MakeGroups") != -1  ||
-         method == "ExtrusionAlongPathX"    ||
-         method == "ExtrusionAlongPathObjX" ||
-         method == "DoubleNodeGroupNew"     ||
-         method == "DoubleNodeGroupsNew"    ||
-         method == "DoubleNodeElemGroupNew" ||
-         method == "DoubleNodeElemGroupsNew"||
-         method == "DoubleNodeElemGroup2New"||
-         method == "DoubleNodeElemGroups2New"
+    if ( method.Search("MakeGroups") != -1      ||
+         method == "ExtrusionAlongPathX"        ||
+         method == "ExtrusionAlongPathObjX"     ||
+         method == "DoubleNodeGroupNew"         ||
+         method == "DoubleNodeGroupsNew"        ||
+         method == "DoubleNodeElemGroupNew"     ||
+         method == "DoubleNodeElemGroupsNew"    ||
+         method == "DoubleNodeElemGroup2New"    ||
+         method == "DoubleNodeElemGroups2New"   ||
+         method == "AffectedElemGroupsInRegion"
          )
       groups = aCommand->GetResultValue();
     else if ( method == "MakeBoundaryMesh" )
@@ -818,8 +871,8 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
       aCommand->GetString() += tmpCmd.GetString();
     }
     // IMP issue 0021014
-    // set GetCriterion(elementType,CritType,Compare,Treshold,UnaryOp,BinaryOp,Tolerance)
-    //                  1           2        3       4        5       6        7
+    // set GetCriterion(elementType,CritType,Compare,Threshold,UnaryOp,BinaryOp,Tolerance)
+    //                  1           2        3       4         5       6        7
     // instead of "SMESH.Filter.Criterion(
     // Type,Compare,Threshold,ThresholdStr,ThresholdID,UnaryOp,BinaryOp,Tolerance,TypeOfElement,Precision)
     // 1    2       3         4            5           6       7        8         9             10
@@ -860,27 +913,37 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
       if ( Type == "SMESH.FT_ElemGeomType" )
       {
         // set SMESH.GeometryType instead of a numerical Threshold
-        const char* types[SMESH::Geom_BALL+1] = {
+        const int nbTypes = SMESH::Geom_LAST;
+        const char* types[] = {
           "Geom_POINT", "Geom_EDGE", "Geom_TRIANGLE", "Geom_QUADRANGLE", "Geom_POLYGON",
           "Geom_TETRA", "Geom_PYRAMID", "Geom_HEXA", "Geom_PENTA", "Geom_HEXAGONAL_PRISM",
           "Geom_POLYHEDRA", "Geom_BALL" };
-        if ( -1 < iGeom && iGeom < SMESH::Geom_POLYHEDRA+1 )
+        if ( -1 < iGeom && iGeom < nbTypes )
           Threshold = SMESH + types[ iGeom ];
+#ifdef _DEBUG_
+        // is types complete? (compilation failure mains that enum GeometryType changed)
+        int _asrt[( sizeof(types) / sizeof(const char*) == nbTypes ) ? 2 : -1 ]; _asrt[0]=_asrt[1];
+#endif
       }
       if (Type == "SMESH.FT_EntityType")
       {
         // set SMESH.EntityType instead of a numerical Threshold
-        const char* types[SMESH::Entity_Ball+1] = {
+        const int nbTypes = SMESH::Entity_Last;
+        const char* types[] = {
           "Entity_Node", "Entity_0D", "Entity_Edge", "Entity_Quad_Edge",
           "Entity_Triangle", "Entity_Quad_Triangle", "Entity_BiQuad_Triangle",
           "Entity_Quadrangle", "Entity_Quad_Quadrangle", "Entity_BiQuad_Quadrangle",
           "Entity_Polygon", "Entity_Quad_Polygon", "Entity_Tetra", "Entity_Quad_Tetra",
           "Entity_Pyramid", "Entity_Quad_Pyramid",
           "Entity_Hexa", "Entity_Quad_Hexa", "Entity_TriQuad_Hexa",
-          "Entity_Penta", "Entity_Quad_Penta", "Entity_Hexagonal_Prism",
+          "Entity_Penta", "Entity_Quad_Penta", "Entity_BiQuad_Penta", "Entity_Hexagonal_Prism",
           "Entity_Polyhedra", "Entity_Quad_Polyhedra", "Entity_Ball" };
-        if ( -1 < iGeom && iGeom < SMESH::Entity_Quad_Polyhedra+1 )
+        if ( -1 < iGeom && iGeom < nbTypes )
           Threshold = SMESH + types[ iGeom ];
+#ifdef _DEBUG_
+        // is 'types' complete? (compilation failure mains that enum EntityType changed)
+        int _asrt[( sizeof(types) / sizeof(const char*) == nbTypes ) ? 2 : -1 ]; _asrt[0]=_asrt[1];
+#endif
       }
     }
     if ( ThresholdID.Length() != 2 ) // neither '' nor ""
@@ -917,7 +980,7 @@ Handle(_pyCommand) _pyGen::AddCommand( const TCollection_AsciiString& theCommand
 //================================================================================
 /*!
  * \brief Convert the command or remember it for later conversion
 * \param theCommand - The python command calling a method of SMESH_Gen
 \param theCommand - The python command calling a method of SMESH_Gen
  */
 //================================================================================
 
@@ -946,16 +1009,16 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
     AddObject( mesh );
     return;
   }
-  if( method == "CreateMeshesFromMED" ||
-      method == "CreateMeshesFromSAUV"||
-      method == "CreateMeshesFromCGNS" ||
-      method == "CreateMeshesFromGMF" ) // command result is ( [mesh1,mesh2], status )
+  if ( method == "CreateMeshesFromMED" ||
+       method == "CreateMeshesFromSAUV"||
+       method == "CreateMeshesFromCGNS" ||
+       method == "CreateMeshesFromGMF" ) // command result is ( [mesh1,mesh2], status )
   {
-    for ( int ind = 0; ind < theCommand->GetNbResultValues(); ind++ )
+    std::list< _pyID > meshIDs = theCommand->GetStudyEntries( theCommand->GetResultValue() );
+    std::list< _pyID >::iterator meshID = meshIDs.begin();
+    for ( ; meshID != meshIDs.end(); ++meshID )
     {
-      _pyID meshID = theCommand->GetResultValue(ind+1);
-      if ( !theCommand->IsStudyEntry( meshID ) ) continue;
-      Handle(_pyMesh) mesh = new _pyMesh( theCommand, theCommand->GetResultValue(ind+1));
+      Handle(_pyMesh) mesh = new _pyMesh( theCommand, *meshID );
       AddObject( mesh );
     }
     if ( method == "CreateMeshesFromGMF" )
@@ -967,6 +1030,12 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
       theCommand->SetArg( 1, file );
     }
   }
+  if ( method == "CopyMeshWithGeom" )
+  {
+    std::list< _pyID > entries = theCommand->GetStudyEntries( theCommand->GetResultValue() );
+    Handle(_pyMesh) mesh = new _pyMesh( theCommand, entries.front() );
+    AddObject( mesh );
+  }
 
   // CreateHypothesis()
   if ( method == "CreateHypothesis" )
@@ -1023,7 +1092,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
        method == "CreateMeasurements" )
   {
     Handle(_pyObject) obj = new _pySelfEraser( theCommand );
-    if ( !myObjects.insert( make_pair( obj->GetID(), obj )).second )
+    if ( !AddObject( obj ) )
       theCommand->Clear(); // already created
   }
   // Concatenate( [mesh1, ...], ... )
@@ -1052,7 +1121,7 @@ void _pyGen::Process( const Handle(_pyCommand)& theCommand )
   static TStringSet smeshpyMethods;
   if ( smeshpyMethods.empty() ) {
     const char * names[] =
-      { "SetEmbeddedMode","IsEmbeddedMode","SetCurrentStudy","GetCurrentStudy",
+      { "SetEmbeddedMode","IsEmbeddedMode","UpdateStudy","GetStudy",
         "GetPattern","GetSubShapesId",
         "" }; // <- mark of array end
     smeshpyMethods.Insert( names );
@@ -1119,10 +1188,15 @@ void _pyGen::Flush()
         id_hyp->second->GetCreationCmd()->SetObject( SMESH_2smeshpy::GenName() );
     }
 
-  // Flush other objects
-  for ( id_obj = myObjects.begin(); id_obj != myObjects.end(); ++id_obj )
-    if ( ! id_obj->second.IsNull() )
-      id_obj->second->Flush();
+  // Flush other objects. 2 times, for objects depending on Flush() of later created objects
+  std::list< Handle(_pyObject) >::reverse_iterator robj = myOrderedObjects.rbegin();
+  for ( ; robj != myOrderedObjects.rend(); ++robj )
+    if ( ! robj->IsNull() )
+      (*robj)->Flush();
+  std::list< Handle(_pyObject) >::iterator obj = myOrderedObjects.begin();
+  for ( ; obj != myOrderedObjects.end(); ++obj )
+    if ( ! obj->IsNull() )
+      (*obj)->Flush();
 
   myLastCommand->SetOrderNb( ++myNbCommands );
   myCommands.push_back( myLastCommand );
@@ -1137,28 +1211,28 @@ void _pyGen::Flush()
 
 void _pyGen::PlaceSubmeshAfterItsCreation( Handle(_pyCommand) theCmdUsingSubmesh ) const
 {
-  map< _pyID, Handle(_pyObject) >::const_iterator id_obj = myObjects.begin();
-  for ( ; id_obj != myObjects.end(); ++id_obj )
-  {
-    if ( !id_obj->second->IsKind( STANDARD_TYPE( _pySubMesh ))) continue;
-    for ( int iArg = theCmdUsingSubmesh->GetNbArgs(); iArg; --iArg )
-    {
-      const _pyID& arg = theCmdUsingSubmesh->GetArg( iArg );
-      if ( arg.IsEmpty() || arg.Value( 1 ) == '"' || arg.Value( 1 ) == '\'' )
-        continue;
-      list< _pyID > idList = theCmdUsingSubmesh->GetStudyEntries( arg );
-      list< _pyID >::iterator id = idList.begin();
-      for ( ; id != idList.end(); ++id )
-        if ( id_obj->first == *id )
-          // _pySubMesh::Process() does what we need
-          Handle(_pySubMesh)::DownCast( id_obj->second )->Process( theCmdUsingSubmesh );
-    }
-  }
+  // map< _pyID, Handle(_pyObject) >::const_iterator id_obj = myObjects.begin();
+  // for ( ; id_obj != myObjects.end(); ++id_obj )
+  // {
+  //   if ( !id_obj->second->IsKind( STANDARD_TYPE( _pySubMesh ))) continue;
+  //   for ( int iArg = theCmdUsingSubmesh->GetNbArgs(); iArg; --iArg )
+  //   {
+  //     const _pyID& arg = theCmdUsingSubmesh->GetArg( iArg );
+  //     if ( arg.IsEmpty() || arg.Value( 1 ) == '"' || arg.Value( 1 ) == '\'' )
+  //       continue;
+  //     list< _pyID > idList = theCmdUsingSubmesh->GetStudyEntries( arg );
+  //     list< _pyID >::iterator id = idList.begin();
+  //     for ( ; id != idList.end(); ++id )
+  //       if ( id_obj->first == *id )
+  //         // _pySubMesh::Process() does what we need
+  //         Handle(_pySubMesh)::DownCast( id_obj->second )->Process( theCmdUsingSubmesh );
+  //   }
+  // }
 }
 
 //================================================================================
 /*!
- * \brief Clean commmands of removed objects depending on myIsPublished flag
+ * \brief Clean commands of removed objects depending on myIsPublished flag
  */
 //================================================================================
 
@@ -1173,9 +1247,15 @@ void _pyGen::ClearCommands()
     if ( !id_hyp->second.IsNull() )
       id_hyp->second->ClearCommands();
 
-  map< _pyID, Handle(_pyObject) >::iterator id_obj = myObjects.begin();
-  for ( ; id_obj != myObjects.end(); ++id_obj )
-    id_obj->second->ClearCommands();
+  // Other objects. 2 times, for objects depending on ClearCommands() of later created objects
+  std::list< Handle(_pyObject) >::reverse_iterator robj = myOrderedObjects.rbegin();
+  for ( ; robj != myOrderedObjects.rend(); ++robj )
+    if ( ! robj->IsNull() )
+      (*robj)->ClearCommands();
+  std::list< Handle(_pyObject) >::iterator obj = myOrderedObjects.begin();
+  for ( ; obj != myOrderedObjects.end(); ++obj )
+    if ( ! obj->IsNull() )
+      (*obj)->ClearCommands();
 }
 
 //================================================================================
@@ -1208,13 +1288,15 @@ void _pyGen::Free()
   myHypos.clear();
 
   myFile2ExportedMesh.clear();
+
+  //myKeepAgrCmdsIDs.Print();
 }
 
 //================================================================================
 /*!
  * \brief Add access method to mesh that is an argument
 * \param theCmd - command to add access method
 * \retval bool - true if added
 \param theCmd - command to add access method
+ * \retval bool - true if added
  */
 //================================================================================
 
@@ -1232,8 +1314,8 @@ bool _pyGen::AddMeshAccessorMethod( Handle(_pyCommand) theCmd ) const
 //================================================================================
 /*!
  * \brief Add access method to algo that is an object or an argument
 * \param theCmd - command to add access method
 * \retval bool - true if added
 \param theCmd - command to add access method
+ * \retval bool - true if added
  */
 //================================================================================
 
@@ -1254,8 +1336,8 @@ bool _pyGen::AddAlgoAccessorMethod( Handle(_pyCommand) theCmd ) const
 //================================================================================
 /*!
  * \brief Find hypothesis by ID (entry)
 * \param theHypID - The hypothesis ID
 * \retval Handle(_pyHypothesis) - The found hypothesis
 \param theHypID - The hypothesis ID
+ * \retval Handle(_pyHypothesis) - The found hypothesis
  */
 //================================================================================
 
@@ -1272,10 +1354,10 @@ Handle(_pyHypothesis) _pyGen::FindHyp( const _pyID& theHypID )
 //================================================================================
 /*!
  * \brief Find algorithm able to create a hypothesis
 * \param theGeom - The shape ID the algorithm was created on
 * \param theMesh - The mesh ID that created the algorithm
 * \param theHypothesis - The hypothesis the algorithm sould be able to create
 * \retval Handle(_pyHypothesis) - The found algo
 \param theGeom - The shape ID the algorithm was created on
 \param theMesh - The mesh ID that created the algorithm
*  \param theHypothesis - The hypothesis the algorithm should be able to create
+ * \retval Handle(_pyHypothesis) - The found algo
  */
 //================================================================================
 
@@ -1296,8 +1378,8 @@ Handle(_pyHypothesis) _pyGen::FindAlgo( const _pyID& theGeom, const _pyID& theMe
 //================================================================================
 /*!
  * \brief Find subMesh by ID (entry)
 * \param theSubMeshID - The subMesh ID
 * \retval Handle(_pySubMesh) - The found subMesh
 \param theSubMeshID - The subMesh ID
+ * \retval Handle(_pySubMesh) - The found subMesh
  */
 //================================================================================
 
@@ -1313,8 +1395,8 @@ Handle(_pySubMesh) _pyGen::FindSubMesh( const _pyID& theSubMeshID )
 //================================================================================
 /*!
  * \brief Change order of commands in the script
 * \param theCmd1 - One command
 * \param theCmd2 - Another command
 \param theCmd1 - One command
 \param theCmd2 - Another command
  */
 //================================================================================
 
@@ -1331,15 +1413,15 @@ void _pyGen::ExchangeCommands( Handle(_pyCommand) theCmd1, Handle(_pyCommand) th
   int nb1 = theCmd1->GetOrderNb();
   theCmd1->SetOrderNb( theCmd2->GetOrderNb() );
   theCmd2->SetOrderNb( nb1 );
-//   cout << "BECOME " << theCmd1->GetOrderNb() << "\t" << theCmd1->GetString() << endl
-//        << "BECOME " << theCmd2->GetOrderNb() << "\t" << theCmd2->GetString() << endl << endl;
+  //   cout << "BECOME " << theCmd1->GetOrderNb() << "\t" << theCmd1->GetString() << endl
+  //        << "BECOME " << theCmd2->GetOrderNb() << "\t" << theCmd2->GetString() << endl << endl;
 }
 
 //================================================================================
 /*!
  * \brief Set one command after the other
 * \param theCmd - Command to move
 * \param theAfterCmd - Command ater which to insert the first one
 \param theCmd - Command to move
 \param theAfterCmd - Command ater which to insert the first one
  */
 //================================================================================
 
@@ -1351,8 +1433,8 @@ void _pyGen::SetCommandAfter( Handle(_pyCommand) theCmd, Handle(_pyCommand) theA
 //================================================================================
 /*!
  * \brief Set one command before the other
 * \param theCmd - Command to move
 * \param theBeforeCmd - Command before which to insert the first one
 \param theCmd - Command to move
 \param theBeforeCmd - Command before which to insert the first one
  */
 //================================================================================
 
@@ -1364,8 +1446,8 @@ void _pyGen::SetCommandBefore( Handle(_pyCommand) theCmd, Handle(_pyCommand) the
 //================================================================================
 /*!
  * \brief Set one command before or after the other
 * \param theCmd - Command to move
 * \param theOtherCmd - Command ater or before which to insert the first one
 \param theCmd - Command to move
 \param theOtherCmd - Command ater or before which to insert the first one
  */
 //================================================================================
 
@@ -1392,7 +1474,7 @@ void _pyGen::setNeighbourCommand( Handle(_pyCommand)& theCmd,
 
 // void _pyGen::addFilterUser( Handle(_pyCommand)& theCommand, const Handle(_pyObject)& user )
 // {
-  // No more needed after adding _pyObject::myArgCommands
+// No more needed after adding _pyObject::myArgCommands
 
 //   const char filterPrefix[] = "aFilter0x";
 //   if ( theCommand->GetString().Search( filterPrefix ) < 1 )
@@ -1418,7 +1500,7 @@ void _pyGen::setNeighbourCommand( Handle(_pyCommand)& theCmd,
 //================================================================================
 /*!
  * \brief Set command be last in list of commands
 * \param theCmd - Command to be last
 \param theCmd - Command to be last
  */
 //================================================================================
 
@@ -1430,8 +1512,8 @@ Handle(_pyCommand)& _pyGen::GetLastCommand()
 //================================================================================
 /*!
  * \brief Set method to access to object wrapped with python class
 * \param theID - The wrapped object entry
 * \param theMethod - The accessor method
 \param theID - The wrapped object entry
 \param theMethod - The accessor method
  */
 //================================================================================
 
@@ -1443,7 +1525,7 @@ void _pyGen::SetAccessorMethod(const _pyID& theID, const char* theMethod )
 //================================================================================
 /*!
  * \brief Generated new ID for object and assign with existing name
 * \param theID - ID of existing object
 \param theID - ID of existing object
  */
 //================================================================================
 
@@ -1456,9 +1538,10 @@ _pyID _pyGen::GenerateNewID( const _pyID& theID )
   }
   while ( myObjectNames.IsBound( aNewID ) );
 
-  myObjectNames.Bind( aNewID, myObjectNames.IsBound( theID )
-                      ? (myObjectNames.Find( theID ) + _pyID( "_" ) + _pyID( index-1 ))
-                      : _pyID( "A" ) + aNewID );
+  if ( myObjectNames.IsBound( theID ) )
+    myObjectNames.Bind( aNewID, ( myObjectNames.Find( theID ) + _pyID( "_" ) + _pyID( index-1 ) ) );
+  else
+    myObjectNames.Bind( aNewID, ( _pyID( "A" ) + aNewID ) );
   return aNewID;
 }
 
@@ -1468,20 +1551,27 @@ _pyID _pyGen::GenerateNewID( const _pyID& theID )
  */
 //================================================================================
 
-void _pyGen::AddObject( Handle(_pyObject)& theObj )
+bool _pyGen::AddObject( Handle(_pyObject)& theObj )
 {
-  if ( theObj.IsNull() ) return;
+  if ( theObj.IsNull() ) return false;
 
   CheckObjectIsReCreated( theObj );
 
-  if ( theObj->IsKind( STANDARD_TYPE( _pyMesh )))
-    myMeshes.insert( make_pair( theObj->GetID(), Handle(_pyMesh)::DownCast( theObj )));
-
-  else if ( theObj->IsKind( STANDARD_TYPE( _pyMeshEditor )))
-    myMeshEditors.insert( make_pair( theObj->GetID(), Handle(_pyMeshEditor)::DownCast( theObj )));
+  bool add;
 
-  else
-    myObjects.insert( make_pair( theObj->GetID(), theObj ));
+  if ( theObj->IsKind( STANDARD_TYPE( _pyMesh ))) {
+    add = myMeshes.insert( make_pair( theObj->GetID(),
+                                      Handle(_pyMesh)::DownCast( theObj ))).second;
+  }
+  else if ( theObj->IsKind( STANDARD_TYPE( _pyMeshEditor ))) {
+    add = myMeshEditors.insert( make_pair( theObj->GetID(),
+                                           Handle(_pyMeshEditor)::DownCast( theObj ))).second;
+  }
+  else {
+    add = myObjects.insert( make_pair( theObj->GetID(), theObj )).second;
+    if ( add ) myOrderedObjects.push_back( theObj );
+  }
+  return add;
 }
 
 //================================================================================
@@ -1497,8 +1587,11 @@ void _pyGen::CheckObjectIsReCreated( Handle(_pyObject)& theObj )
     return;
 
   const bool isHyp = theObj->IsKind( STANDARD_TYPE( _pyHypothesis ));
-  Handle(_pyObject) existing =
-    isHyp ? FindHyp( theObj->GetID() ) : FindObject( theObj->GetID() );
+  Handle(_pyObject) existing;
+  if( isHyp )
+    existing = FindHyp( theObj->GetID() );
+  else
+    existing = FindObject( theObj->GetID() );
   if ( !existing.IsNull() && existing != theObj )
   {
     existing->SetRemovedFromStudy( true );
@@ -1554,7 +1647,8 @@ Handle(_pyObject) _pyGen::FindObject( const _pyID& theObjID )  const
       return id_obj->second;
   }
   {
-    map< _pyID, Handle(_pyMesh) >::const_iterator id_obj = myMeshes.find( theObjID );
+    _pyGen* me = const_cast< _pyGen* >( this );
+    map< _pyID, Handle(_pyMesh) >::iterator id_obj = me->myMeshes.find( theObjID );
     if ( id_obj != myMeshes.end() )
       return id_obj->second;
   }
@@ -1599,7 +1693,7 @@ bool _pyGen::IsNotPublished(const _pyID& theObjID) const
   // either the SMESH object is not in study or it is a GEOM object
   if ( IsGeomObject( theObjID ))
   {
-    SALOMEDS::SObject_wrap so = myStudy->FindObjectID( theObjID.ToCString() );
+    SALOMEDS::SObject_wrap so = SMESH_Gen_i::getStudyServant()->FindObjectID( theObjID.ToCString() );
     if ( so->_is_nil() ) return true;
     CORBA::Object_var obj = so->GetObject();
     return CORBA::is_nil( obj );
@@ -1715,7 +1809,7 @@ _pyMesh::_pyMesh(const Handle(_pyCommand) theCreationCmd, const _pyID& meshId):
 //================================================================================
 /*!
  * \brief Convert an IDL API command of SMESH::SMESH_Mesh to a method call of python Mesh
 * \param theCommand - Engine method called for this mesh
 \param theCommand - Engine method called for this mesh
  */
 //================================================================================
 
@@ -1743,10 +1837,29 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
       list< Handle(_pyHypothesis) >::iterator hyp;
       if ( !myLastComputeCmd.IsNull() )
       {
-        for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp )
-          (*hyp)->ComputeDiscarded( myLastComputeCmd );
+        // check if the previously computed mesh has been edited,
+        // if so then we do not clear the previous Compute()
+        bool toClear = true;
+        if ( myLastComputeCmd->GetMethod() == "Compute" )
+        {
+          list< Handle(_pyMeshEditor)>::iterator e = myEditors.begin();
+          for ( ; e != myEditors.end() && toClear; ++e )
+          {
+            list< Handle(_pyCommand)>& cmds = (*e)->GetProcessedCmds();
+            list< Handle(_pyCommand) >::reverse_iterator cmd = cmds.rbegin();
+            if ( cmd != cmds.rend() &&
+                 (*cmd)->GetOrderNb() > myLastComputeCmd->GetOrderNb() )
+              toClear = false;
+          }
+        }
+        if ( toClear )
+        {
+          // clear hyp commands called before myLastComputeCmd
+          for ( hyp = myHypos.begin(); hyp != myHypos.end(); ++hyp )
+            (*hyp)->ComputeDiscarded( myLastComputeCmd );
 
-        myLastComputeCmd->Clear();
+          myLastComputeCmd->Clear();
+        }
       }
       myLastComputeCmd = theCommand;
 
@@ -1790,7 +1903,7 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
     }
   }
   // ----------------------------------------------------------------------
-  else if ( method == "GetSubMesh" ) { // collect submeshes of the mesh
+  else if ( method == "GetSubMesh" ) { // collect sub-meshes of the mesh
     Handle(_pySubMesh) subMesh = theGen->FindSubMesh( theCommand->GetResultValue() );
     if ( !subMesh.IsNull() ) {
       subMesh->SetCreator( this );
@@ -1798,6 +1911,10 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
     }
   }
   // ----------------------------------------------------------------------
+  else if ( method == "GetSubMeshes" ) { // clear as the command does nothing (0023156)
+    theCommand->Clear();
+  }
+  // ----------------------------------------------------------------------
   else if ( method == "AddHypothesis" ) { // mesh.AddHypothesis(geom, HYPO )
     myAddHypCmds.push_back( theCommand );
     // set mesh to hypo
@@ -1812,7 +1929,8 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
   // ----------------------------------------------------------------------
   else if ( method == "CreateGroup" ||
             method == "CreateGroupFromGEOM" ||
-            method == "CreateGroupFromFilter" )
+            method == "CreateGroupFromFilter" ||
+            method == "CreateDimGroup" )
   {
     Handle(_pyGroup) group = new _pyGroup( theCommand );
     myGroups.push_back( group );
@@ -1826,7 +1944,7 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
     TCollection_AsciiString grIDs = theCommand->GetResultValue();
     list< _pyID >          idList = theCommand->GetStudyEntries( grIDs );
     list< _pyID >::iterator  grID = idList.begin();
-    const int nbGroupsBefore = myGroups.size();
+    const size_t nbGroupsBefore = myGroups.size();
     Handle(_pyObject) obj;
     for ( ; grID != idList.end(); ++grID )
     {
@@ -1878,16 +1996,26 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
   // ----------------------------------------------------------------------
   else if ( theCommand->MethodStartsFrom( "Export" ))
   {
-    if ( method == "ExportToMED" ||  // ExportToMED()  --> ExportMED()
-         method == "ExportToMEDX" )  // ExportToMEDX() --> ExportMED()
+    if ( method == "ExportToMED"  || // ExportToMED()  --> ExportMED()
+         method == "ExportToMEDX" || // ExportToMEDX() --> ExportMED()
+         method == "ExportMED" )
     {
       theCommand->SetMethod( "ExportMED" );
-      if ( theCommand->GetNbArgs() == 5 )
+      // filter out deprecated version parameter
+      vector< _AString > args;
+      for ( int i = 1; i <= theCommand->GetNbArgs(); i++ ) {
+        if ( !_FilterArg( theCommand->GetArg( i ) ) )
+          args.push_back( theCommand->GetArg( i ) );
+      }
+      theCommand->RemoveArgs();
+      for ( unsigned int i = 0; i < args.size(); i++ )
+        theCommand->SetArg( i+1, args[i] );
+      if ( theCommand->GetNbArgs() == 4 )
       {
         // ExportToMEDX(...,autoDimension) -> ExportToMEDX(...,meshPart=None,autoDimension)
-        _AString autoDimension = theCommand->GetArg( 5 );
-        theCommand->SetArg( 5, "None" );
-        theCommand->SetArg( 6, autoDimension );
+        _AString autoDimension = theCommand->GetArg( 4 );
+        theCommand->SetArg( 4, "None" );
+        theCommand->SetArg( 5, autoDimension );
       }
     }
     else if ( method == "ExportCGNS" )
@@ -1911,14 +2039,34 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
       //
       // remove "PartTo" from the method
       TCollection_AsciiString newMethod = method;
-      newMethod.Remove( 7, 6 );
+      newMethod.Remove( /*where=*/7, /*howmany=*/6 );
       theCommand->SetMethod( newMethod );
-      // make the 1st arg be the last one (or last but one for ExportMED())
-      _pyID partID = theCommand->GetArg( 1 );
-      int nbArgs = theCommand->GetNbArgs() - (newMethod == "ExportMED");
-      for ( int i = 2; i <= nbArgs; ++i )
-        theCommand->SetArg( i-1, theCommand->GetArg( i ));
-      theCommand->SetArg( nbArgs, partID );
+      // replace version parameter by minor
+      std::list< _AString > args;
+      for ( int i = 1; i <= theCommand->GetNbArgs(); i++ ) {
+        if ( _FilterArg( theCommand->GetArg( i )))
+          args.push_back( "minor=0");
+        else
+          args.push_back( theCommand->GetArg( i ));
+      }
+      // check the 1st arg meshPart, it must be SMESH_IDSource
+      _AString meshPart = args.front();
+      if ( _pyCommand::IsStudyEntry( meshPart ) ||
+           meshPart.Search( "Filter"      ) > 0 ||
+           meshPart.Search( "GetIDSource" ) > 0 ||
+           meshPart.Search( "meshPart"    ) > 0 )
+      {
+        // set the 1st arg meshPart
+        // - to 5th place for ExportMED command
+        // - to last place for the rest commands
+        std::list< _AString >::iterator newPos = args.end();
+        if ( newMethod == "ExportMED" )
+          std::advance( newPos = args.begin(), 5 );
+        args.splice( newPos, args, args.begin() );
+      }
+      std::list< _AString >::iterator a = args.begin();
+      for ( unsigned int i = 1; a != args.end(); ++i, ++a )
+        theCommand->SetArg( i, *a );
     }
     // remember file name
     theGen->AddExportedMesh( theCommand->GetArg( 1 ),
@@ -1952,10 +2100,18 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
         {
           addCmd = *cmd;
           cmd    = addHypCmds.erase( cmd );
-          if ( !theGen->IsToKeepAllCommands() ) {
+          if ( !theGen->IsToKeepAllCommands() /*&& CanClear()*/ ) {
             addCmd->Clear();
             theCommand->Clear();
           }
+          else
+          {
+            // mesh.AddHypothesis(geom, hyp) --> mesh.AddHypothesis(hyp, geom=0)
+            addCmd->RemoveArgs();
+            addCmd->SetArg( 1, hypID );
+            if ( isLocal )
+              addCmd->SetArg( 2, geomID );
+          }
         }
         else
         {
@@ -1979,7 +2135,7 @@ void _pyMesh::Process( const Handle(_pyCommand)& theCommand )
   else if ( method == "GetMeshOrder" || method == "SetMeshOrder" )
   {
     // make commands GetSubMesh() returning sub-meshes be before using sub-meshes
-    // by GetMeshOrder() and SetMeshOrder(), since by defalut GetSubMesh()
+    // by GetMeshOrder() and SetMeshOrder(), since by default GetSubMesh()
     // commands are moved at the end of the script
     TCollection_AsciiString subIDs =
       ( method == "SetMeshOrder" ) ? theCommand->GetArg(1) : theCommand->GetResultValue();
@@ -2015,8 +2171,8 @@ bool _pyMesh::NeedMeshAccess( const Handle(_pyCommand)& theCommand )
   if ( sameMethods.empty() ) {
     const char * names[] =
       { "ExportDAT","ExportUNV","ExportSTL","ExportSAUV", "RemoveGroup","RemoveGroupWithContents",
-        "GetGroups","UnionGroups","IntersectGroups","CutGroups","GetLog","GetId","ClearLog",
-        "GetStudyId","HasDuplicatedGroupNamesMED","GetMEDMesh","NbNodes","NbElements",
+        "GetGroups","UnionGroups","IntersectGroups","CutGroups","CreateDimGroup","GetLog","GetId",
+        "ClearLog","HasDuplicatedGroupNamesMED","GetMEDMesh","NbNodes","NbElements",
         "NbEdges","NbEdgesOfOrder","NbFaces","NbFacesOfOrder","NbTriangles",
         "NbTrianglesOfOrder","NbQuadrangles","NbQuadranglesOfOrder","NbPolygons","NbVolumes",
         "NbVolumesOfOrder","NbTetras","NbTetrasOfOrder","NbHexas","NbHexasOfOrder",
@@ -2025,6 +2181,7 @@ bool _pyMesh::NeedMeshAccess( const Handle(_pyCommand)& theCommand )
         "GetSubMeshElementsId","GetSubMeshNodesId","GetSubMeshElementType","Dump","GetNodeXYZ",
         "GetNodeInverseElements","GetShapeID","GetShapeIDForElem","GetElemNbNodes",
         "GetElemNode","IsMediumNode","IsMediumNodeOfAnyElem","ElemNbEdges","ElemNbFaces",
+        "GetElemFaceNodes", "GetFaceNormal", "FindElementByNodes",
         "IsPoly","IsQuadratic","BaryCenter","GetHypothesisList", "SetAutoColor", "GetAutoColor",
         "Clear", "ConvertToStandalone", "GetMeshOrder", "SetMeshOrder"
         ,"" }; // <- mark of end
@@ -2054,7 +2211,7 @@ void _pyMesh::Flush()
     for ( ; m != fatherMeshes.end(); ++m )
       addFatherMesh( *m );
     // if ( removedGeom )
-    //     SetRemovedFromStudy(); // as reffered geometry not in study
+    //     SetRemovedFromStudy(); // as referred geometry not in study
   }
   if ( myGeomNotInStudy )
     return;
@@ -2310,24 +2467,26 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand)
       "AddNode","Add0DElement","AddEdge","AddFace","AddPolygonalFace","AddBall",
       "AddVolume","AddPolyhedralVolume","AddPolyhedralVolumeByFaces",
       "MoveNode", "MoveClosestNodeToPoint",
-      "InverseDiag","DeleteDiag","Reorient","ReorientObject",
+      "InverseDiag","DeleteDiag","Reorient","ReorientObject","Reorient2DBy3D",
       "TriToQuad","TriToQuadObject", "QuadTo4Tri", "SplitQuad","SplitQuadObject",
       "BestSplit","Smooth","SmoothObject","SmoothParametric","SmoothParametricObject",
       "ConvertToQuadratic","ConvertFromQuadratic","RenumberNodes","RenumberElements",
       "RotationSweep","RotationSweepObject","RotationSweepObject1D","RotationSweepObject2D",
       "ExtrusionSweep","AdvancedExtrusion","ExtrusionSweepObject","ExtrusionSweepObject1D",
-      "ExtrusionSweepObject2D","ExtrusionAlongPath","ExtrusionAlongPathObject",
+      "ExtrusionByNormal", "ExtrusionSweepObject2D","ExtrusionAlongPath","ExtrusionAlongPathObject",
       "ExtrusionAlongPathX","ExtrusionAlongPathObject1D","ExtrusionAlongPathObject2D",
+      "ExtrusionSweepObjects","RotationSweepObjects","ExtrusionAlongPathObjects",
       "Mirror","MirrorObject","Translate","TranslateObject","Rotate","RotateObject",
-      "FindCoincidentNodes","MergeNodes","FindEqualElements",
+      "FindCoincidentNodes","MergeNodes","FindEqualElements","FillHole",
       "MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders",
+      "FindCoincidentFreeBorders", "SewCoincidentFreeBorders",
       "SewBorderToSide","SewSideElements","ChangeElemNodes","GetLastCreatedNodes",
-      "GetLastCreatedElems",
+      "GetLastCreatedElems", "FaceGroupsSeparatedByEdges",
       "MirrorMakeMesh","MirrorObjectMakeMesh","TranslateMakeMesh","TranslateObjectMakeMesh",
       "Scale","ScaleMakeMesh","RotateMakeMesh","RotateObjectMakeMesh","MakeBoundaryMesh",
-      "MakeBoundaryElements", "SplitVolumesIntoTetra",
+      "MakeBoundaryElements", "SplitVolumesIntoTetra","SplitHexahedraIntoPrisms",
       "DoubleElements","DoubleNodes","DoubleNode","DoubleNodeGroup","DoubleNodeGroups",
-      "DoubleNodeElem","DoubleNodeElemInRegion","DoubleNodeElemGroup",
+      "DoubleNodeElem","DoubleNodeElemInRegion","DoubleNodeElemGroup","AffectedElemGroupsInRegion",
       "DoubleNodeElemGroupInRegion","DoubleNodeElemGroups","DoubleNodeElemGroupsInRegion",
       "DoubleNodesOnGroupBoundaries","CreateFlatElementsOnFacesGroups","CreateHoleSkin"
       ,"" }; // <- mark of the end
@@ -2510,7 +2669,7 @@ bool _pyMeshEditor::CanClear()
 //================================================================================
 /*!
  * \brief _pyHypothesis constructor
 * \param theCreationCmd -
 \param theCreationCmd -
  */
 //================================================================================
 
@@ -2523,8 +2682,8 @@ _pyHypothesis::_pyHypothesis(const Handle(_pyCommand)& theCreationCmd):
 //================================================================================
 /*!
  * \brief Creates algorithm or hypothesis
 * \param theCreationCmd - The engine command creating a hypothesis
 * \retval Handle(_pyHypothesis) - Result _pyHypothesis
 \param theCreationCmd - The engine command creating a hypothesis
+ * \retval Handle(_pyHypothesis) - Result _pyHypothesis
  */
 //================================================================================
 
@@ -2581,6 +2740,8 @@ Handle(_pyHypothesis) _pyHypothesis::NewHypothesis( const Handle(_pyCommand)& th
     hyp->SetConvMethodAndType( "SetGrid", "Cartesian_3D");
     for ( int iArg = 0; iArg < 4; ++iArg )
       hyp->setCreationArg( iArg+1, "[]");
+    hyp->AddAccumulativeMethod( "SetGrid" );
+    hyp->AddAccumulativeMethod( "SetGridSpacing" );
   }
   else
   {
@@ -2611,9 +2772,9 @@ bool _pyHypothesis::IsWrappable(const _pyID& theMesh) const
 //================================================================================
 /*!
  * \brief Convert the command adding a hypothesis to mesh into a smesh command
 * \param theCmd - The command like mesh.AddHypothesis( geom, hypo )
 * \param theAlgo - The algo that can create this hypo
 * \retval bool - false if the command cant be converted
 \param theCmd - The command like mesh.AddHypothesis( geom, hypo )
 \param theAlgo - The algo that can create this hypo
* \retval bool - false if the command can't be converted
  */
 //================================================================================
 
@@ -2676,7 +2837,7 @@ bool _pyHypothesis::Addition2Creation( const Handle(_pyCommand)& theCmd,
 //================================================================================
 /*!
  * \brief Remember hypothesis parameter values
- * \param theCommand - The called hypothesis method
+ *  \param theCommand - The called hypothesis method
  */
 //================================================================================
 
@@ -2697,7 +2858,7 @@ void _pyHypothesis::Process( const Handle(_pyCommand)& theCommand)
           myArgCommands.push_back( theCommand );
         usedCommand = true;
         while ( crMethod.myArgs.size() < i+1 )
-          crMethod.myArgs.push_back( "[]" );
+          crMethod.myArgs.push_back( "None" );
         crMethod.myArgs[ i ] = theCommand->GetArg( crMethod.myArgNb[i] );
       }
     }
@@ -2738,7 +2899,7 @@ void _pyHypothesis::Flush()
 
 //================================================================================
 /*!
- * \brief clear creation, arg and unkown commands
+ * \brief clear creation, arg and unknown commands
  */
 //================================================================================
 
@@ -2900,7 +3061,7 @@ void _pyHypothesis::rememberCmdOfParameter( const Handle(_pyCommand) & theComman
   // parameters are discriminated by method name
   _AString method = theCommand->GetMethod();
   if ( myAccumulativeMethods.count( method ))
-    return; // this method adds values and not override the previus value
+    return; // this method adds values and not override the previous value
 
   // discriminate commands setting different parameters via one method
   // by passing parameter names like e.g. SetOption("size", "0.2")
@@ -3016,7 +3177,7 @@ void _pyHypothesis::setCreationArg( const int argNb, const _AString& arg )
 {
   if ( myCurCrMethod )
   {
-    while ( myCurCrMethod->myArgs.size() < argNb )
+    while ( (int) myCurCrMethod->myArgs.size() < argNb )
       myCurCrMethod->myArgs.push_back( "None" );
     if ( arg.IsEmpty() )
       myCurCrMethod->myArgs[ argNb-1 ] = "None";
@@ -3029,7 +3190,7 @@ void _pyHypothesis::setCreationArg( const int argNb, const _AString& arg )
 //================================================================================
 /*!
  * \brief Remember hypothesis parameter values
- * \param theCommand - The called hypothesis method
+ *  \param theCommand - The called hypothesis method
  */
 //================================================================================
 
@@ -3039,9 +3200,11 @@ void _pyComplexParamHypo::Process( const Handle(_pyCommand)& theCommand)
   {
     // CartesianParameters3D hyp
 
-    if ( theCommand->GetMethod() == "SetSizeThreshold" )
+    if ( theCommand->GetMethod() == "SetSizeThreshold"  ||
+         theCommand->GetMethod() == "SetToAddEdges" )
     {
-      setCreationArg( 4, theCommand->GetArg( 1 ));
+      int iEdges = ( theCommand->GetMethod().Value( 4 ) == 'T' );
+      setCreationArg( 4+iEdges, theCommand->GetArg( 1 ));
       myArgCommands.push_back( theCommand );
       return;
     }
@@ -3063,7 +3226,9 @@ void _pyComplexParamHypo::Process( const Handle(_pyCommand)& theCommand)
         myCurCrMethod->myArgs[ iArg ] += "]";
       }
       myArgCommands.push_back( theCommand );
-      rememberCmdOfParameter( theCommand );
+      //rememberCmdOfParameter( theCommand ); -- these commands are marked as
+      //                                  accumulative, else, if the creation
+      //                 is not converted, commands for axes 1 and 2 are lost
       return;
     }
   }
@@ -3079,9 +3244,9 @@ void _pyComplexParamHypo::Process( const Handle(_pyCommand)& theCommand)
     for ( ; type2meth != myAlgoType2CreationMethod.end(); ++type2meth )
     {
       CreationMethod& crMethod = type2meth->second;
-        while ( crMethod.myArgs.size() < i+1 )
-          crMethod.myArgs.push_back( "[]" );
-        crMethod.myArgs[ i ] = theCommand->GetArg( 1 ); // arg value
+      while ( (int) crMethod.myArgs.size() < i+1 )
+        crMethod.myArgs.push_back( "[]" );
+      crMethod.myArgs[ i ] = theCommand->GetArg( 1 ); // arg value
     }
     myArgCommands.push_back( theCommand );
   }
@@ -3098,19 +3263,34 @@ void _pyComplexParamHypo::Process( const Handle(_pyCommand)& theCommand)
 
 void _pyComplexParamHypo::Flush()
 {
+  list < Handle(_pyCommand) >::iterator cmd;
   if ( IsWrapped() )
   {
-    list < Handle(_pyCommand) >::iterator cmd = myUnusedCommands.begin();
-    for ( ; cmd != myUnusedCommands.end(); ++cmd )
+    for ( cmd = myUnusedCommands.begin(); cmd != myUnusedCommands.end(); ++cmd )
       if ((*cmd)->GetMethod() == "SetObjectEntry" )
         (*cmd)->Clear();
   }
+
+  // if ( GetAlgoType() == "Cartesian_3D" )
+  // {
+  //   _pyID algo = myCreationCmd->GetObject();
+  //   for ( cmd = myProcessedCmds.begin(); cmd != myProcessedCmds.end(); ++cmd )
+  //   {
+  //     if ( IsWrapped() )
+  //     {
+  //       StructToList( *cmd, /*checkMethod=*/false );
+  //       const _AString & method = (*cmd)->GetMethod();
+  //       if ( method == "SetFixedPoint" )
+  //         (*cmd)->SetObject( algo );
+  //     }
+  //   }
+  // }
 }
 
 //================================================================================
 /*!
  * \brief Convert methods of 1D hypotheses to my own methods
 * \param theCommand - The called hypothesis method
 \param theCommand - The called hypothesis method
  */
 //================================================================================
 
@@ -3147,9 +3327,9 @@ void _pyLayerDistributionHypo::Process( const Handle(_pyCommand)& theCommand)
 //================================================================================
 /*!
  * \brief
 * \param theAdditionCmd - command to be converted
 * \param theMesh - mesh instance
 * \retval bool - status
 \param theAdditionCmd - command to be converted
 \param theMesh - mesh instance
+ * \retval bool - status
  */
 //================================================================================
 
@@ -3251,9 +3431,9 @@ void _pyLayerDistributionHypo::Flush()
 //================================================================================
 /*!
  * \brief additionally to Addition2Creation, clears SetDistrType() command
 * \param theCmd - AddHypothesis() command
 * \param theMesh - mesh to which a hypothesis is added
 * \retval bool - convertion result
 \param theCmd - AddHypothesis() command
 \param theMesh - mesh to which a hypothesis is added
* \retval bool - conversion result
  */
 //================================================================================
 
@@ -3333,9 +3513,9 @@ void _pyNumberOfSegmentsHyp::Flush()
 /*!
  * \brief Convert the command adding "SegmentLengthAroundVertex" to mesh
  * into regular1D.LengthNearVertex( length, vertex )
 * \param theCmd - The command like mesh.AddHypothesis( vertex, SegmentLengthAroundVertex )
 * \param theMesh - The mesh needing this hypo
 * \retval bool - false if the command cant be converted
 \param theCmd - The command like mesh.AddHypothesis( vertex, SegmentLengthAroundVertex )
 \param theMesh - The mesh needing this hypo
* \retval bool - false if the command can't be converted
  */
 //================================================================================
 
@@ -3346,28 +3526,31 @@ bool _pySegmentLengthAroundVertexHyp::Addition2Creation( const Handle(_pyCommand
 
     _pyID vertex = theCmd->GetArg( 1 );
 
-    // the problem here is that segment algo will not be found
+    // the problem here is that segment algo can be not found
     // by pyHypothesis::Addition2Creation() for <vertex>, so we try to find
     // geometry where segment algorithm is assigned
-    Handle(_pyHypothesis) algo;
     _pyID geom = vertex;
+    Handle(_pyHypothesis) algo = theGen->FindAlgo( geom, theMeshID, this );
     while ( algo.IsNull() && !geom.IsEmpty()) {
       // try to find geom as a father of <vertex>
       geom = FatherID( geom );
       algo = theGen->FindAlgo( geom, theMeshID, this );
     }
-    if ( algo.IsNull() )
+    if ( algo.IsNull() || geom.IsEmpty() )
       return false; // also possible to find geom as brother of veretex...
+
     // set geom instead of vertex
     theCmd->SetArg( 1, geom );
 
-    // set vertex as a second arg
-    if ( myCurCrMethod->myArgs.size() < 1) setCreationArg( 1, "1" ); // :(
-    setCreationArg( 2, vertex );
-
     // mesh.AddHypothesis(vertex, SegmentLengthAroundVertex) -->
-    // theMeshID.LengthNearVertex( length, vertex )
-    return _pyHypothesis::Addition2Creation( theCmd, theMeshID );
+    // SegmentLengthAroundVertex = Regular_1D.LengthNearVertex( length )
+    if ( _pyHypothesis::Addition2Creation( theCmd, theMeshID ))
+    {
+      // set vertex as a second arg
+      theCmd->SetArg( 2, vertex );
+
+      return true;
+    }
   }
   return false;
 }
@@ -3375,7 +3558,7 @@ bool _pySegmentLengthAroundVertexHyp::Addition2Creation( const Handle(_pyCommand
 //================================================================================
 /*!
  * \brief _pyAlgorithm constructor
- * \param theCreationCmd - The command like "algo = smeshgen.CreateHypothesis(type,lib)"
+ *  \param theCreationCmd - The command like "algo = smeshgen.CreateHypothesis(type,lib)"
  */
 //================================================================================
 
@@ -3388,9 +3571,9 @@ _pyAlgorithm::_pyAlgorithm(const Handle(_pyCommand)& theCreationCmd)
 //================================================================================
 /*!
  * \brief Convert the command adding an algorithm to mesh
 * \param theCmd - The command like mesh.AddHypothesis( geom, algo )
 * \param theMesh - The mesh needing this algo
 * \retval bool - false if the command cant be converted
 \param theCmd - The command like mesh.AddHypothesis( geom, algo )
 \param theMesh - The mesh needing this algo
* \retval bool - false if the command can't be converted
  */
 //================================================================================
 
@@ -3408,12 +3591,12 @@ bool _pyAlgorithm::Addition2Creation( const Handle(_pyCommand)& theCmd,
 //================================================================================
 /*!
  * \brief Return starting position of a part of python command
 * \param thePartIndex - The index of command part
 * \retval int - Part position
 \param thePartIndex - The index of command part
+ * \retval int - Part position
  */
 //================================================================================
 
-int _pyCommand::GetBegPos( int thePartIndex )
+int _pyCommand::GetBegPos( int thePartIndex ) const
 {
   if ( IsEmpty() )
     return EMPTY;
@@ -3426,8 +3609,8 @@ int _pyCommand::GetBegPos( int thePartIndex )
 //================================================================================
 /*!
  * \brief Store starting position of a part of python command
 * \param thePartIndex - The index of command part
 * \param thePosition - Part position
 \param thePartIndex - The index of command part
 \param thePosition - Part position
  */
 //================================================================================
 
@@ -3442,24 +3625,24 @@ void _pyCommand::SetBegPos( int thePartIndex, int thePosition )
 //================================================================================
 /*!
  * \brief Returns whitespace symbols at the line beginning
 * \retval TCollection_AsciiString - result
+ * \retval TCollection_AsciiString - result
  */
 //================================================================================
 
 TCollection_AsciiString _pyCommand::GetIndentation()
 {
   int end = 1;
-  if ( GetBegPos( RESULT_IND ) == UNKNOWN )
-    GetWord( myString, end, true );
-  else
-    end = GetBegPos( RESULT_IND );
-  return myString.SubString( 1, end - 1 );
+  //while ( end <= Length() && isblank( myString.Value( end )))
+  //ANA: isblank() function isn't provided in VC2010 compiler
+  while ( end <= Length() && ( myString.Value( end ) == ' ' || myString.Value( end ) == '\t') )
+    ++end;
+  return ( end == 1 ) ? _AString("") : myString.SubString( 1, end - 1 );
 }
 
 //================================================================================
 /*!
  * \brief Return substring of python command looking like ResultValue = Obj.Meth()
 * \retval const TCollection_AsciiString & - ResultValue substring
+ * \retval const TCollection_AsciiString & - ResultValue substring
  */
 //================================================================================
 
@@ -3493,16 +3676,8 @@ const TCollection_AsciiString & _pyCommand::GetResultValue()
 
 int _pyCommand::GetNbResultValues()
 {
-  int nb     = 0;
-  int begPos = 1;
-  int endPos = myString.Location( "=", 1, Length() );
-  while ( begPos < endPos )
-  {
-    _AString str = GetWord( myString, begPos, true );
-    begPos = begPos+ str.Length();
-    nb++;
-  }
-  return (nb-1);
+  GetResultValue(1);
+  return myResults.Length();
 }
 
 
@@ -3513,32 +3688,38 @@ int _pyCommand::GetNbResultValues()
  * \retval const TCollection_AsciiString & - ResultValue with res index substring
  */
 //================================================================================
-TCollection_AsciiString _pyCommand::GetResultValue(int res)
+const _AString& _pyCommand::GetResultValue(int res)
 {
-  int begPos = 1;
-  if ( SkipSpaces( myString, begPos ) && myString.Value( begPos ) == '[' )
-    ++begPos; // skip [, else the whole list is returned
-  int endPos = myString.Location( "=", 1, Length() );
-  int Nb=0;
-  while ( begPos < endPos) {
-    _AString result = GetWord( myString, begPos, true );
-    begPos = begPos + result.Length();
-    Nb++;
-    if(res == Nb) {
-      result.RemoveAll('[');
-      result.RemoveAll(']');
-      return result;
+  if ( GetResultValue().IsEmpty() )
+    return theEmptyString;
+
+  if ( myResults.IsEmpty() )
+  {
+    int begPos = 1;
+    if ( SkipSpaces( myRes, begPos ) && myRes.Value( begPos ) == '[' )
+      ++begPos; // skip [, else the whole list is returned
+    while ( begPos < myRes.Length() ) {
+      _AString result = GetWord( myRes, begPos, true );
+      begPos += result.Length();
+      // if(res == Nb) {
+      //   result.RemoveAll('[');
+      //   result.RemoveAll(']');
+      //   return result;
+      // }
+      // if(Nb>res)
+      //   break;
+      myResults.Append( result );
     }
-    if(Nb>res)
-      break;
   }
+  if ( res > 0 && res <= myResults.Length() )
+    return myResults( res );
   return theEmptyString;
 }
 
 //================================================================================
 /*!
  * \brief Return substring of python command looking like ResVal = Object.Meth()
 * \retval const TCollection_AsciiString & - Object substring
+ * \retval const TCollection_AsciiString & - Object substring
  */
 //================================================================================
 
@@ -3551,17 +3732,17 @@ const TCollection_AsciiString & _pyCommand::GetObject()
     if ( begPos < 1 ) {
       begPos = myString.Location( "=", 1, Length() ) + 1;
       // is '=' in the string argument (for example, name) or not
-      int nb1 = 0; // number of ' character at the left of =
-      int nb2 = 0; // number of " character at the left of =
-      for ( int i = 1; i < begPos-1; i++ ) {
-        if ( myString.Value( i )=='\'' )
-          nb1 += 1;
-        else if ( myString.Value( i )=='"' )
-          nb2 += 1;
-      }
-      // if number of ' or " is not divisible by 2,
+      int nb[4] = { 0, 0, 0, 0 }; // number of '"() character at the left of =
+      for ( int i = 1; i < begPos-1; i++ )
+        switch ( myString.Value( i )) {
+        case '\'': nb[0]++; break;
+        case '"' : nb[1]++; break;
+        case '(' : nb[2]++; break;
+        case ')' : nb[3]++; break;
+        }
+      // if = is inside a string or a list
       // then get an object at the start of the command
-      if ( nb1 % 2 != 0 || nb2 % 2 != 0 )
+      if ( nb[0] % 2 != 0 || nb[1] % 2 != 0 || nb[2] != nb[3])
         begPos = 1;
     }
     else {
@@ -3601,7 +3782,7 @@ const TCollection_AsciiString & _pyCommand::GetObject()
 //================================================================================
 /*!
  * \brief Return substring of python command looking like ResVal = Obj.Method()
 * \retval const TCollection_AsciiString & - Method substring
+ * \retval const TCollection_AsciiString & - Method substring
  */
 //================================================================================
 
@@ -3610,12 +3791,15 @@ const TCollection_AsciiString & _pyCommand::GetMethod()
   if ( GetBegPos( METHOD_IND ) == UNKNOWN )
   {
     // beginning
-    int begPos = GetBegPos( OBJECT_IND ) + myObj.Length();
+    int begPos = GetBegPos( OBJECT_IND );
     bool forward = true;
     if ( begPos < 1 ) {
       begPos = myString.Location( "(", 1, Length() ) - 1;
       forward = false;
     }
+    else {
+      begPos += myObj.Length();
+    }
     // store
     myMeth = GetWord( myString, begPos, forward );
     SetBegPos( METHOD_IND, begPos );
@@ -3624,10 +3808,24 @@ const TCollection_AsciiString & _pyCommand::GetMethod()
   return myMeth;
 }
 
+//================================================================================
+/*!
+ * \brief Returns true if there are brackets after the method
+ */
+//================================================================================
+
+bool _pyCommand::IsMethodCall()
+{
+  if ( GetMethod().IsEmpty() )
+    return false;
+  const char* s = myString.ToCString() + GetBegPos( METHOD_IND ) + myMeth.Length() - 1;
+  return ( s[0] == '(' || s[1] == '(' );
+}
+
 //================================================================================
 /*!
  * \brief Return substring of python command looking like ResVal = Obj.Meth(Arg1,...)
 * \retval const TCollection_AsciiString & - Arg<index> substring
+ * \retval const TCollection_AsciiString & - Arg<index> substring
  */
 //================================================================================
 
@@ -3707,11 +3905,29 @@ const TCollection_AsciiString & _pyCommand::GetArg( int index )
   return myArgs( index );
 }
 
+//================================================================================
+/*!
+ * \brief Return position where arguments begin
+ */
+//================================================================================
+
+int _pyCommand::GetArgBeginning() const
+{
+  int pos = GetBegPos( ARG1_IND );
+  if ( pos == UNKNOWN )
+  {
+    pos = GetBegPos( METHOD_IND ) + myMeth.Length();
+    if ( pos < 1 )
+      pos = myString.Location( "(", 4, Length() ); // 4 = strlen("b.c(")
+  }
+  return pos;
+}
+
 //================================================================================
 /*!
  * \brief Check if char is a word part
 * \param c - The character to check
 * \retval bool - The check result
 \param c - The character to check
+ * \retval bool - The check result
  */
 //================================================================================
 
@@ -3724,10 +3940,10 @@ static inline bool isWord(const char c, const bool dotIsWord)
 //================================================================================
 /*!
  * \brief Looks for a word in the string and returns word's beginning
 * \param theString - The input string
 * \param theStartPos - The position to start the search, returning word's beginning
 * \param theForward - The search direction
 * \retval TCollection_AsciiString - The found word
 \param theString - The input string
 \param theStartPos - The position to start the search, returning word's beginning
 \param theForward - The search direction
+ * \retval TCollection_AsciiString - The found word
  */
 //================================================================================
 
@@ -3812,7 +4028,27 @@ bool _pyCommand::IsStudyEntry( const TCollection_AsciiString& str )
 
 //================================================================================
 /*!
- * \brief Finds entries in a sting
+ * \brief Returns true if the string looks like an object ID but not like a list,
+ *        string, command etc.
+ */
+//================================================================================
+
+bool _pyCommand::IsID( const TCollection_AsciiString& str )
+{
+  if ( str.Length() < 1 ) return false;
+
+  const char* s = str.ToCString();
+
+  for ( int i = 0; i < str.Length(); ++i )
+    if ( !IsIDChar( s[i] ))
+      return false;
+
+  return true;
+}
+
+//================================================================================
+/*!
+ * \brief Finds entries in a string
  */
 //================================================================================
 
@@ -3838,9 +4074,9 @@ std::list< _pyID > _pyCommand::GetStudyEntries( const TCollection_AsciiString& s
 //================================================================================
 /*!
  * \brief Look for position where not space char is
 * \param theString - The string
 * \param thePos - The position to search from and which returns result
 * \retval bool - false if there are only space after thePos in theString
 \param theString - The string
 \param thePos - The position to search from and which returns result
+ * \retval bool - false if there are only space after thePos in theString
  */
 //================================================================================
 
@@ -3858,14 +4094,14 @@ bool _pyCommand::SkipSpaces( const TCollection_AsciiString & theString, int & th
 //================================================================================
 /*!
  * \brief Modify a part of the command
 * \param thePartIndex - The index of the part
 * \param thePart - The new part string
 * \param theOldPart - The old part
 \param thePartIndex - The index of the part
 \param thePart - The new part string
 \param theOldPart - The old part
  */
 //================================================================================
 
 void _pyCommand::SetPart(int thePartIndex, const TCollection_AsciiString& thePart,
-                        TCollection_AsciiString& theOldPart)
+                         TCollection_AsciiString& theOldPart)
 {
   int pos = GetBegPos( thePartIndex );
   if ( pos <= Length() && theOldPart != thePart)
@@ -3897,9 +4133,9 @@ void _pyCommand::SetPart(int thePartIndex, const TCollection_AsciiString& thePar
 
 //================================================================================
 /*!
- * \brief Set agrument
 * \param index - The argument index, it counts from 1
 * \param theArg - The argument string
+ * \brief Set argument
 \param index - The argument index, it counts from 1
 \param theArg - The argument string
  */
 //================================================================================
 
@@ -3971,9 +4207,9 @@ void _pyCommand::Comment()
     myString.Insert( i, "#" );
     for ( int iPart = 1; iPart <= myBegPos.Length(); ++iPart )
     {
-      int begPos = GetBegPos( iPart + 1 );
-      if ( begPos != UNKNOWN )
-        SetBegPos( iPart + 1, begPos + 1 );
+      int begPos = GetBegPos( iPart );
+      if ( begPos != UNKNOWN && begPos != EMPTY )
+        SetBegPos( iPart, begPos + 1 );
     }
   }
 }
@@ -4000,9 +4236,9 @@ bool _pyCommand::SetDependentCmdsAfter() const
 //================================================================================
 /*!
  * \brief Insert accessor method after theObjectID
 * \param theObjectID - id of the accessed object
 * \param theAcsMethod - name of the method giving access to the object
 * \retval bool - false if theObjectID is not found in the command string
 \param theObjectID - id of the accessed object
 \param theAcsMethod - name of the method giving access to the object
+ * \retval bool - false if theObjectID is not found in the command string
  */
 //================================================================================
 
@@ -4021,7 +4257,8 @@ bool _pyCommand::AddAccessorMethod( _pyID theObjectID, const char* theAcsMethod
     // check that theObjectID is not just a part of a longer ID
     int afterEnd = beg + theObjectID.Length();
     Standard_Character c = myString.Value( afterEnd );
-    if ( !isalnum( c ) && c != ':' ) {
+    if ( !IsIDChar( c ))
+    {
       // check if accessor method already present
       if ( c != '.' ||
            myString.Location( (char*) theAcsMethod, afterEnd, Length() ) != afterEnd+1) {
@@ -4038,7 +4275,7 @@ bool _pyCommand::AddAccessorMethod( _pyID theObjectID, const char* theAcsMethod
         added = true;
       }
     }
-    beg = afterEnd; // is a part - next search
+    beg = afterEnd; // is a part -> next search
   }
   return added;
 }
@@ -4089,7 +4326,7 @@ void _pyObject::ClearCommands()
 //================================================================================
 /*!
  * \brief Return method name giving access to an interaface object wrapped by python class
 * \retval const char* - method name
+ * \retval const char* - method name
  */
 //================================================================================
 
@@ -4113,7 +4350,8 @@ _pyID _pyObject::FatherID(const _pyID & childID)
 
 //================================================================================
 /*!
- * \brief SelfEraser erases creation command if no more it's commands invoked
+ * \brief SelfEraser erases creation command if none of it's commands invoked
+ *        (e.g. filterManager) or it's not used as a command argument (e.g. a filter)
  */
 //================================================================================
 
@@ -4126,11 +4364,12 @@ _pySelfEraser::_pySelfEraser(const Handle(_pyCommand)& theCreationCmd)
 
 //================================================================================
 /*!
- * \brief SelfEraser erases creation command if no more it's commands invoked
+ * \brief SelfEraser erases creation command if none of it's commands invoked
+ *        (e.g. filterManager) or it's not used as a command argument (e.g. a filter)
  */
 //================================================================================
 
-void _pySelfEraser::Flush()
+bool _pySelfEraser::CanClear()
 {
   bool toErase = false;
   if ( myIgnoreOwnCalls ) // check if this obj is used as argument
@@ -4138,23 +4377,58 @@ void _pySelfEraser::Flush()
     int nbArgUses = 0;
     list< Handle(_pyCommand) >::iterator cmd = myArgCmds.begin();
     for ( ; cmd != myArgCmds.end(); ++cmd )
-      nbArgUses += !(*cmd)->IsEmpty();
+      nbArgUses += IsAliveCmd( *cmd );
+
     toErase = ( nbArgUses < 1 );
   }
   else
   {
-    int nbCalls = GetNbCalls();
-    if ( nbCalls > 0 )
-    {
-      // ignore cleared commands
-      std::list< Handle(_pyCommand) >& cmds = GetProcessedCmds();
-      std::list< Handle(_pyCommand) >::const_iterator cmd = cmds.begin();
-      for ( ; cmd != cmds.end(); ++cmd )
-        nbCalls -= (*cmd)->IsEmpty();
-    }
+    int nbCalls = 0;
+    std::list< Handle(_pyCommand) >& cmds = GetProcessedCmds();
+    std::list< Handle(_pyCommand) >::iterator cmd = cmds.begin();
+    for ( ; cmd != cmds.end();  )
+      // check of cmd emptiness is not enough as object can change
+      if (( *cmd )->GetString().Search( GetID() ) > 0 )
+        ++nbCalls, ++cmd;
+      else
+        cmd = cmds.erase( cmd ); // save the cmd from clearing
+
     toErase = ( nbCalls < 1 );
   }
-  if ( toErase )
+  return toErase;
+}
+
+//================================================================================
+/*!
+ * \brief Check if a command is or can be cleared
+ */
+//================================================================================
+
+bool _pySelfEraser::IsAliveCmd( const Handle(_pyCommand)& theCmd )
+{
+  if ( theCmd->IsEmpty() )
+    return false;
+
+  if ( !theGen->IsToKeepAllCommands() )
+  {
+    const _pyID& objID = theCmd->GetObject();
+    Handle( _pyObject ) obj = theGen->FindObject( objID );
+    if ( !obj.IsNull() )
+      return !obj->CanClear();
+  }
+  return true;
+}
+
+//================================================================================
+/*!
+ * \brief SelfEraser erases creation command if none of it's commands invoked
+ *        (e.g. filterManager) or it's not used as a command argument (e.g. a filter)
+ */
+//================================================================================
+
+void _pySelfEraser::Flush()
+{
+  if ( CanClear() )
   {
     myIsPublished = false;
     _pyObject::ClearCommands();
@@ -4167,11 +4441,12 @@ void _pySelfEraser::Flush()
  */
 //================================================================================
 
-_pySubMesh::_pySubMesh(const Handle(_pyCommand)& theCreationCmd):
+_pySubMesh::_pySubMesh(const Handle(_pyCommand)& theCreationCmd, bool toKeepAgrCmds):
   _pyObject(theCreationCmd)
 {
   myMesh = ObjectToMesh( theGen->FindObject( theCreationCmd->GetObject() ));
-  theGen->KeepAgrCmds( GetID() ); // ask to fill myArgCmds
+  if ( toKeepAgrCmds )
+    theGen->KeepAgrCmds( GetID() ); // ask to fill myArgCmds
 }
 
 //================================================================================
@@ -4183,39 +4458,39 @@ _pySubMesh::_pySubMesh(const Handle(_pyCommand)& theCreationCmd):
 bool _pySubMesh::CanBeArgOfMethod(const _AString& theMethodName)
 {
   return false;
-//   // names of all methods where a sub-mesh can be used as argument
-//   static TStringSet methods;
-//   if ( methods.empty() ) {
-//     const char * names[] = {
-//       // methods of SMESH_Gen
-//       "CopyMesh",
-//       // methods of SMESH_Group
-//       "AddFrom",
-//       // methods of SMESH_Measurements
-//       "MinDistance",
-//       // methods of SMESH_Mesh
-//       "ExportPartToMED","ExportCGNS","ExportPartToDAT","ExportPartToUNV","ExportPartToSTL",
-//       "RemoveSubMesh",
-//       // methods of SMESH_MeshEditor
-//       "ReorientObject","Reorient2D","TriToQuadObject","QuadToTriObject","SplitQuadObject",
-//       "SplitVolumesIntoTetra","SmoothObject","SmoothParametricObject","ConvertFromQuadraticObject",
-//       "RotationSweepObject","RotationSweepObjectMakeGroups","RotationSweepObject1D",
-//       "RotationSweepObject1DMakeGroups","RotationSweepObject2D","RotationSweepObject2DMakeGroups",
-//       "ExtrusionSweepObject","ExtrusionSweepObjectMakeGroups","ExtrusionSweepObject0D",
-//       "ExtrusionSweepObject0DMakeGroups","ExtrusionSweepObject1D","ExtrusionSweepObject2D",
-//       "ExtrusionSweepObject1DMakeGroups","ExtrusionSweepObject2DMakeGroups",
-//       "ExtrusionAlongPathObjX","ExtrusionAlongPathObject","ExtrusionAlongPathObjectMakeGroups",
-//       "ExtrusionAlongPathObject1D","ExtrusionAlongPathObject1DMakeGroups",
-//       "ExtrusionAlongPathObject2D","ExtrusionAlongPathObject2DMakeGroups","MirrorObject",
-//       "MirrorObjectMakeGroups","MirrorObjectMakeMesh","TranslateObject","Scale",
-//       "TranslateObjectMakeGroups","TranslateObjectMakeMesh","ScaleMakeGroups","ScaleMakeMesh",
-//       "RotateObject","RotateObjectMakeGroups","RotateObjectMakeMesh","FindCoincidentNodesOnPart",
-//       "FindCoincidentNodesOnPartBut","FindEqualElements","FindAmongElementsByPoint",
-//       "MakeBoundaryMesh","Create0DElementsOnAllNodes",
-//       "" }; // <- mark of end
-//     methods.Insert( names );
-//   }
-//   return methods.Contains( theMethodName );
+  // names of all methods where a sub-mesh can be used as argument
+  // static TStringSet methods;
+  // if ( methods.empty() ) {
+  //   const char * names[] = {
+  //     // methods of SMESH_Gen
+  //     "CopyMesh",
+  //     // methods of SMESH_Group
+  //     "AddFrom",
+  //     // methods of SMESH_Measurements
+  //     "MinDistance",
+  //     // methods of SMESH_Mesh
+  //     "ExportPartToMED","ExportCGNS","ExportPartToDAT","ExportPartToUNV","ExportPartToSTL",
+  //     "RemoveSubMesh",
+  //     // methods of SMESH_MeshEditor
+  //     "ReorientObject","Reorient2D","TriToQuadObject","QuadToTriObject","SplitQuadObject",
+  //     "SplitVolumesIntoTetra","SmoothObject","SmoothParametricObject","ConvertFromQuadraticObject",
+  //     "RotationSweepObject","RotationSweepObjectMakeGroups","RotationSweepObject1D",
+  //     "RotationSweepObject1DMakeGroups","RotationSweepObject2D","RotationSweepObject2DMakeGroups",
+  //     "ExtrusionSweepObject","ExtrusionSweepObjectMakeGroups","ExtrusionSweepObject0D",
+  //     "ExtrusionSweepObject0DMakeGroups","ExtrusionSweepObject1D","ExtrusionSweepObject2D",
+  //     "ExtrusionSweepObject1DMakeGroups","ExtrusionSweepObject2DMakeGroups",
+  //     "ExtrusionAlongPathObjX","ExtrusionAlongPathObject","ExtrusionAlongPathObjectMakeGroups",
+  //     "ExtrusionAlongPathObject1D","ExtrusionAlongPathObject1DMakeGroups",
+  //     "ExtrusionAlongPathObject2D","ExtrusionAlongPathObject2DMakeGroups","MirrorObject",
+  //     "MirrorObjectMakeGroups","MirrorObjectMakeMesh","TranslateObject","Scale",
+  //     "TranslateObjectMakeGroups","TranslateObjectMakeMesh","ScaleMakeGroups","ScaleMakeMesh",
+  //     "RotateObject","RotateObjectMakeGroups","RotateObjectMakeMesh","FindCoincidentNodesOnPart",
+  //     "FindCoincidentNodesOnPartBut","FindEqualElements","FindAmongElementsByPoint",
+  //     "MakeBoundaryMesh","Create0DElementsOnAllNodes",
+  //     "" }; // <- mark of end
+  //   methods.Insert( names );
+  // }
+  // return methods.Contains( theMethodName );
 }
 
 //================================================================================
@@ -4257,7 +4532,7 @@ void _pySubMesh::Flush()
 //================================================================================
 
 _pyGroup::_pyGroup(const Handle(_pyCommand)& theCreationCmd, const _pyID & id)
-  :_pySubMesh(theCreationCmd)
+  :_pySubMesh(theCreationCmd, /*toKeepAgrCmds=*/false)
 {
   if ( !id.IsEmpty() )
     setID( id );
@@ -4282,13 +4557,13 @@ _pyGroup::_pyGroup(const Handle(_pyCommand)& theCreationCmd, const _pyID & id)
     //}
     //else {
     // ------------------------->>>>> GroupOnGeom( geom, name, typ )
-      _pyID type = theCreationCmd->GetArg( 1 );
-      _pyID name = theCreationCmd->GetArg( 2 );
-      theCreationCmd->SetMethod( "GroupOnGeom" );
-      theCreationCmd->RemoveArgs();
-      theCreationCmd->SetArg( 1, geom );
-      theCreationCmd->SetArg( 2, name );
-      theCreationCmd->SetArg( 3, type );
+    _pyID type = theCreationCmd->GetArg( 1 );
+    _pyID name = theCreationCmd->GetArg( 2 );
+    theCreationCmd->SetMethod( "GroupOnGeom" );
+    theCreationCmd->RemoveArgs();
+    theCreationCmd->SetArg( 1, geom );
+    theCreationCmd->SetArg( 2, name );
+    theCreationCmd->SetArg( 3, type );
     //}
   }
   else if ( method == "CreateGroupFromFilter" )
@@ -4512,6 +4787,8 @@ void _pyFilter::Process( const Handle(_pyCommand)& theCommand)
     GetCreationCmd()->GetString() = theCommand->GetString();
     theCommand->Clear();
     theCommand->AddDependantCmd( GetCreationCmd() );
+    // why swap? -- it's needed
+    //GetCreationCmd()->Clear();
   }
   else if ( theCommand->GetMethod() == "SetMesh" )
   {
@@ -4734,3 +5011,219 @@ _pyHypothesisReader::GetHypothesis(const _AString&           hypType,
   }
   return resHyp;
 }
+
+//================================================================================
+/*!
+ * \brief Adds an object ID to some family of IDs with a common prefix
+ *  \param [in] str - the object ID
+ *  \return bool - \c false if \a str does not have the same prefix as \a this family
+ *          (for internal usage)
+ */
+//================================================================================
+
+bool _pyStringFamily::Add( const char* str )
+{
+  if ( strncmp( str, _prefix.ToCString(), _prefix.Length() ) != 0 )
+    return false; // expected prefix is missing
+
+  str += _prefix.Length(); // skip _prefix
+
+  // try to add to some of child falimies
+  std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+  for ( ; itSub != _subFams.end(); ++itSub )
+    if ( itSub->Add( str ))
+      return true;
+
+  // no suitable family found - add str to _strings or create a new child family
+
+  // look for a proper place within sorted _strings
+  std::list< _AString >::iterator itStr = _strings.begin();
+  while ( itStr != _strings.end() && itStr->IsLess( str ))
+    ++itStr;
+  if ( itStr != _strings.end() && itStr->IsEqual( str ))
+    return true; // same ID already kept
+
+  const int minPrefixSize = 4;
+
+  // count "smaller" strings with the same prefix
+  std::list< _AString >::iterator itLess = itStr; --itLess;
+  int nbLess = 0;
+  for ( ; itLess != _strings.end(); --itLess )
+    if ( strncmp( str, itLess->ToCString(), minPrefixSize ) == 0 )
+      ++nbLess;
+    else
+      break;
+  ++itLess;
+  // count "greater" strings with the same prefix
+  std::list< _AString >::iterator itMore = itStr;
+  int nbMore = 0;
+  for ( ; itMore != _strings.end(); ++itMore )
+    if ( strncmp( str, itMore->ToCString(), minPrefixSize ) == 0 )
+      ++nbMore;
+    else
+      break;
+  --itMore;
+  if ( nbLess + nbMore > 1 ) // ------- ADD a NEW CHILD FAMILY -------------
+  {
+    // look for a maximal prefix length
+    // int lessPrefSize = 3, morePrefSize = 3;
+    // if ( nbLess > 0 )
+    //   while( itLess->ToCString()[ lessPrefSize ] == str[ lessPrefSize ]  )
+    //     ++lessPrefSize;
+    // if ( nbMore > 0 )
+    //   while ( itMore->ToCString()[ morePrefSize ] == str[ morePrefSize ] )
+    //     ++morePrefSize;
+    // int prefixSize = 3;
+    // if ( nbLess == 0 )
+    //   prefixSize = morePrefSize;
+    // else if ( nbMore == 0 )
+    //   prefixSize = lessPrefSize;
+    // else
+    //   prefixSize = Min( lessPrefSize, morePrefSize );
+    int prefixSize = minPrefixSize;
+    _AString newPrefix ( str, prefixSize );
+
+    // look for a proper place within _subFams sorted by _prefix
+    for ( itSub = _subFams.begin(); itSub != _subFams.end(); ++itSub )
+      if ( !itSub->_prefix.IsLess( newPrefix ))
+        break;
+
+    // add the new _pyStringFamily
+    itSub = _subFams.insert( itSub, _pyStringFamily());
+    _pyStringFamily& newSubFam = *itSub;
+    newSubFam._prefix = newPrefix;
+
+    // pass this->_strings to newSubFam._strings
+    for ( itStr = itLess; nbLess > 0; --nbLess, ++itStr )
+      newSubFam._strings.push_back( itStr->ToCString() + prefixSize );
+    newSubFam._strings.push_back( str + prefixSize );
+    for ( ; nbMore > 0; --nbMore, ++itStr )
+      newSubFam._strings.push_back( itStr->ToCString() + prefixSize );
+
+    _strings.erase( itLess, ++itMore );
+  }
+  else // too few string to make a family for them
+  {
+    _strings.insert( itStr, str );
+  }
+  return true;
+}
+
+//================================================================================
+/*!
+ * \brief Finds an object ID in the command
+ *  \param [in] longStr - the command string
+ *  \param [out] subStr - the found object ID
+ *  \return bool - \c true if the object ID found
+ */
+//================================================================================
+
+bool _pyStringFamily::IsInArgs( Handle( _pyCommand)& cmd, std::list<_AString>& subStr )
+{
+  const _AString& longStr = cmd->GetString();
+  const char*           s = longStr.ToCString();
+
+  // look in _subFams
+  std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+  int nbFound = 0, pos, len, from, argBeg = cmd->GetArgBeginning();
+  if ( argBeg < 4 || argBeg > longStr.Length() )
+    return false;
+  for ( ; itSub != _subFams.end(); ++itSub )
+  {
+    from = argBeg;
+    while (( pos = longStr.Location( itSub->_prefix, from, longStr.Length() )))
+      if (( len = itSub->isIn( s + pos-1 + itSub->_prefix.Length() )) >= 0 )
+      {
+        subStr.push_back( _AString( s + pos-1, len + itSub->_prefix.Length() ));
+        from = pos + len + itSub->_prefix.Length();
+        nbFound++;
+      }
+      else
+      {
+        from += itSub->_prefix.Length();
+      }
+  }
+  // look among _strings
+  std::list< _AString >::iterator itStr = _strings.begin();
+  for ( ; itStr != _strings.end(); ++itStr )
+    if (( pos = longStr.Location( *itStr, argBeg, longStr.Length() )))
+      // check that object ID does not continue after len
+      if ( !cmd->IsIDChar( s[ pos + itStr->Length() - 1 ] ))
+      {
+        subStr.push_back( *itStr );
+        nbFound++;
+      }
+  return nbFound;
+}
+
+//================================================================================
+/*!
+ * \brief Return remainder length of the object ID after my _prefix
+ *  \param [in] str - remainder of the command after my _prefix
+ *  \return int - length of the object ID or -1 if not found
+ */
+//================================================================================
+
+int _pyStringFamily::isIn( const char* str )
+{
+  std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+  int len = -1;
+  for ( ; itSub != _subFams.end(); ++itSub )
+  {
+    int cmp = strncmp( str, itSub->_prefix.ToCString(), itSub->_prefix.Length() );
+    if ( cmp == 0 )
+    {
+      if (( len = itSub->isIn( str + itSub->_prefix.Length() )) >= 0 )
+        return itSub->_prefix.Length() + len;
+    }
+    else if ( cmp < 0 )
+      break;
+  }
+  if ( !_strings.empty() )
+  {
+    std::list< _AString >::iterator itStr = _strings.begin();
+    bool firstEmpty = itStr->IsEmpty();
+    if ( firstEmpty )
+      ++itStr, len = 0;
+    for ( ; itStr != _strings.end(); ++itStr )
+    {
+      int cmp = strncmp( str, itStr->ToCString(), itStr->Length() );
+      if ( cmp == 0 )
+      {
+        len = itStr->Length();
+        break;
+      }
+      else if ( cmp < 0 )
+      {
+        break;
+      }
+    }
+
+    // check that object ID does not continue after len
+    if ( len >= 0 && _pyCommand::IsIDChar( str[len] ))
+      len = -1;
+  }
+
+  return len;
+}
+
+//================================================================================
+/*!
+ * \brief DEBUG
+ */
+//================================================================================
+
+void _pyStringFamily::Print( int level )
+{
+  cout << string( level, ' ' ) << "prefix = '" << _prefix << "' : ";
+  std::list< _AString >::iterator itStr = _strings.begin();
+  for ( ; itStr != _strings.end(); ++itStr )
+    cout << *itStr << " | ";
+  cout << endl;
+  std::list< _pyStringFamily >::iterator itSub = _subFams.begin();
+  for ( ; itSub != _subFams.end(); ++itSub )
+    itSub->Print( level + 1 );
+  if ( level == 0 )
+    cout << string( 70, '-' ) << endl;
+}
+