diff --git a/Doc/changelog.docu b/Doc/changelog.docu
index 9c615cf5..6c4922c6 100644
--- a/Doc/changelog.docu
+++ b/Doc/changelog.docu
@@ -20,6 +20,10 @@
PLY Reader: Fixed endless loop on unknown property list type
+Tools
+
+- SmartTagger: Added the SmartTagger class to tag primitives (O(1) reset )
+
diff --git a/Doc/tools.docu b/Doc/tools.docu
index 5da44bcd..7ae8c68a 100644
--- a/Doc/tools.docu
+++ b/Doc/tools.docu
@@ -6,6 +6,7 @@
\li \subpage subdivider_docu
\li \subpage vdpm_docu
\li \subpage smoother_docu
+\li \subpage smarttagger_docu
\li Miscellaneous
OpenMesh::StripifierT
diff --git a/src/OpenMesh/Tools/SmartTagger/SmartTaggerT.cc b/src/OpenMesh/Tools/SmartTagger/SmartTaggerT.cc
new file mode 100644
index 00000000..b75e4cef
--- /dev/null
+++ b/src/OpenMesh/Tools/SmartTagger/SmartTaggerT.cc
@@ -0,0 +1,212 @@
+/* ========================================================================= *
+ * *
+ * OpenMesh *
+ * Copyright (c) 2001-2015, RWTH-Aachen University *
+ * Department of Computer Graphics and Multimedia *
+ * All rights reserved. *
+ * www.openmesh.org *
+ * *
+ *---------------------------------------------------------------------------*
+ * This file is part of OpenMesh. *
+ *---------------------------------------------------------------------------*
+ * *
+ * Redistribution and use in source and binary forms, with or without *
+ * modification, are permitted provided that the following conditions *
+ * are met: *
+ * *
+ * 1. Redistributions of source code must retain the above copyright notice, *
+ * this list of conditions and the following disclaimer. *
+ * *
+ * 2. Redistributions in binary form must reproduce the above copyright *
+ * notice, this list of conditions and the following disclaimer in the *
+ * documentation and/or other materials provided with the distribution. *
+ * *
+ * 3. Neither the name of the copyright holder nor the names of its *
+ * contributors may be used to endorse or promote products derived from *
+ * this software without specific prior written permission. *
+ * *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
+ * *
+ * ========================================================================= */
+
+/*===========================================================================*\
+ * *
+ * $Revision$ *
+ * $Date$ *
+ * *
+\*===========================================================================*/
+
+#define OPENMESH_SMARTTAGGERT_C
+
+//== INCLUDES =================================================================
+
+#include "SmartTaggerT.hh"
+
+#include
+#include
+
+//== NAMESPACES ===============================================================
+
+namespace OpenMesh {
+
+//== IMPLEMENTATION ==========================================================
+
+template
+SmartTaggerT::
+SmartTaggerT(Mesh& _mesh, unsigned int _tag_range)
+ : mesh_(_mesh),
+ current_base_(0),
+ tag_range_(_tag_range)
+{
+ // add new property
+ mesh_.add_property(ep_tag_);
+
+ // reset all tags once
+ all_tags_to_zero();
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+template
+SmartTaggerT::
+~SmartTaggerT()
+{
+ mesh_.remove_property(ep_tag_);
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+template
+void
+SmartTaggerT::
+untag_all()
+{
+ unsigned int max_uint = std::numeric_limits::max();
+
+ if( current_base_ < max_uint - 2*tag_range_)
+ current_base_ += tag_range_;
+ else
+ {
+ //overflow -> reset all tags
+#ifdef STV_DEBUG_CHECKS
+ std::cerr << "Tagging Overflow occured...\n";
+#endif
+ current_base_ = 0;
+ all_tags_to_zero();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+template
+void
+SmartTaggerT::
+untag_all( const unsigned int _new_tag_range)
+{
+ set_tag_range(_new_tag_range);
+}
+
+
+//-----------------------------------------------------------------------------
+
+template
+void
+SmartTaggerT::
+set_tag ( const EHandle _eh, unsigned int _tag)
+{
+#ifdef STV_DEBUG_CHECKS
+ if( _tag > tag_range_)
+ std::cerr << "ERROR in set_tag tag range!!!\n";
+#endif
+
+ mesh_.property(ep_tag_, _eh) = current_base_ + _tag;
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+template
+unsigned int
+SmartTaggerT::
+get_tag ( const EHandle _eh) const
+{
+ unsigned int t = mesh_.property(ep_tag_, _eh);
+
+#ifdef STV_DEBUG_CHECKS
+ if( t > current_base_ + tag_range_)
+ std::cerr << "ERROR in get_tag tag range!!!\n";
+#endif
+
+ if( t<= current_base_) return 0;
+ else return t-current_base_;
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+template
+bool
+SmartTaggerT::
+is_tagged( const EHandle _eh) const
+{
+ return bool(get_tag(_eh));
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+template
+void
+SmartTaggerT::
+set_tag_range( const unsigned int _tag_range)
+{
+ if( _tag_range <= tag_range_)
+ {
+ untag_all();
+ tag_range_ = _tag_range;
+ }
+ else
+ {
+ tag_range_ = _tag_range;
+ untag_all();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+
+
+template
+void
+SmartTaggerT::
+all_tags_to_zero()
+{
+ // iterate over property vector
+ for(unsigned int i=0; i
+#include
+
+
+//== DEFINES ==================================================================
+
+#define STV_DEBUG_CHECKS
+
+//== NAMESPACES ===============================================================
+
+namespace OpenMesh {
+
+//== FORWARD DECLARATIONS =====================================================
+
+// Smarttagging for vertices
+template< class Mesh> class SmartTaggerVT;
+// Smarttagging for edges
+template< class Mesh> class SmartTaggerET;
+// Smarttagging for faces
+template< class Mesh> class SmartTaggerFT;
+// Smarttagging for halfedges
+template< class Mesh> class SmartTaggerHT;
+
+
+//== CLASS DEFINITION =========================================================
+
+
+/** \page smarttagger_docu Smart Tagger
+
+The smart tagger can be used to tag vertices/halfedges/edges/faces on the mesh. It provides
+an O(1) reset function to untag all primitives at once.
+
+Usage:
+
+\code
+SmartTaggerVT< MeshType > tagger(mesh);
+
+// Reset tagged flag on all vertices
+tagger.untag_all();
+
+// Check if something is tagged
+bool tag = tagger.is_tagged(vh);
+
+// Set tagged:
+tagger.set_tag(vh);
+\endcode
+
+For details see OpenMesh::SmartTaggerT
+
+*/
+
+
+/** \brief Smart Tagger
+ *
+ * A tagger class to be used on OpenMesh. It provides an O(1) reset function for the property.
+ * - Smarttagging for vertices: SmartTaggerVT;
+ * - Smarttagging for edges: SmartTaggerET;
+ * - Smarttagging for faces: SmartTaggerFT;
+ * - Smarttagging for halfedges: SmartTaggerHT;
+ *
+ * Usage:
+ *
+ * \code
+ * SmartTaggerVT< MeshType >* tagger = new SmartTaggerVT< MeshType > (mesh_);
+ *
+ * // Reset tagged flag on all vertices
+ * tagger.untag_all();
+ *
+ * // Check if something is tagged
+ * bool tag = tagger.is_tagged(vh);
+ *
+ * // Set tagged:
+ * tagger.set_tag(vh);
+ * \endcode
+ */
+template
+class SmartTaggerT
+{
+public:
+
+ /// Constructor
+ SmartTaggerT(Mesh& _mesh, unsigned int _tag_range = 1);
+
+ /// Destructor
+ ~SmartTaggerT();
+
+ /** \brief untag all elements
+ *
+ */
+ inline void untag_all();
+
+ /** \brief untag all elements and set new tag_range
+ *
+ * @param _new_tag_range New tag range of the tagger
+ */
+ inline void untag_all( const unsigned int _new_tag_range);
+
+ /** \brief set tag to a value in [0..tag_range]
+ *
+ * @param _eh Edge handle for the tag
+ * @param _tag Tag value
+ */
+ inline void set_tag ( const EHandle _eh, unsigned int _tag = 1);
+
+ /** \brief get tag value in range [0..tag_range]
+ *
+ * @param _eh Edge handle for the tag
+ * @return Current tag value at that edge
+ */
+ inline unsigned int get_tag ( const EHandle _eh) const;
+
+ /** \brief overloaded member for boolean tags
+ *
+ * @param _eh Edge handle for the tag
+ * @return Current tag value at that edge
+ */
+ inline bool is_tagged( const EHandle _eh) const;
+
+ /** \brief set new tag range and untag_all
+ *
+ * Set new tag range and reset tagger
+ *
+ * @param _tag_range New tag range of the tagger
+ */
+ inline void set_tag_range( const unsigned int _tag_range);
+
+protected:
+
+ inline void all_tags_to_zero();
+
+protected:
+
+ // Reference to Mesh
+ Mesh& mesh_;
+
+ // property which holds the current tags
+ EPHandle ep_tag_;
+
+ // current tags range is [current_base_+1...current_base_+tag_range_]
+ unsigned int current_base_;
+
+ // number of different tagvalues available
+ unsigned int tag_range_;
+};
+
+
+//== SPECIALIZATION ===========================================================
+
+// define standard Tagger
+template< class Mesh>
+class SmartTaggerVT
+ : public SmartTaggerT< Mesh, typename Mesh::VertexHandle, OpenMesh::VPropHandleT >
+{
+public:
+ typedef SmartTaggerT< Mesh, typename Mesh::VertexHandle, OpenMesh::VPropHandleT > BaseType;
+ SmartTaggerVT(Mesh& _mesh, unsigned int _tag_range = 1) : BaseType(_mesh, _tag_range) {}
+};
+
+template< class Mesh>
+class SmartTaggerET
+ : public SmartTaggerT< Mesh, typename Mesh::EdgeHandle, OpenMesh::EPropHandleT >
+{
+public:
+ typedef SmartTaggerT< Mesh, typename Mesh::EdgeHandle, OpenMesh::EPropHandleT > BaseType;
+ SmartTaggerET(Mesh& _mesh, unsigned int _tag_range = 1) : BaseType(_mesh, _tag_range) {}
+};
+
+template< class Mesh>
+class SmartTaggerFT
+ : public SmartTaggerT< Mesh, typename Mesh::FaceHandle, OpenMesh::FPropHandleT >
+{
+public:
+ typedef SmartTaggerT< Mesh, typename Mesh::FaceHandle, OpenMesh::FPropHandleT > BaseType;
+ SmartTaggerFT(Mesh& _mesh, unsigned int _tag_range = 1): BaseType(_mesh, _tag_range) {}
+};
+
+template< class Mesh>
+class SmartTaggerHT
+ : public SmartTaggerT< Mesh, typename Mesh::HalfedgeHandle, OpenMesh::HPropHandleT >
+{
+public:
+ typedef SmartTaggerT< Mesh, typename Mesh::HalfedgeHandle, OpenMesh::HPropHandleT > BaseType;
+ SmartTaggerHT(Mesh& _mesh, unsigned int _tag_range = 1): BaseType(_mesh, _tag_range){}
+};
+
+
+//=============================================================================
+} // namespace OpenMesh
+//=============================================================================
+#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SMARTTAGGERT_C)
+#define OPENMESH_SMARTTAGGERT_TEMPLATES
+#include "SmartTaggerT.cc"
+#endif
+
diff --git a/src/Unittests/unittests_smarttagger.cc b/src/Unittests/unittests_smarttagger.cc
new file mode 100644
index 00000000..112fbf74
--- /dev/null
+++ b/src/Unittests/unittests_smarttagger.cc
@@ -0,0 +1,252 @@
+#include
+#include
+#include
+#include
+
+namespace {
+
+class OpenMeshSmartTagger : public OpenMeshBase {
+
+ protected:
+
+ // This function is called before each test is run
+ virtual void SetUp() {
+
+ // Do some initial stuff with the member data here...
+ }
+
+ // This function is called after all tests are through
+ virtual void TearDown() {
+
+ // Do some final stuff with the member data here...
+ }
+
+ // Member already defined in OpenMeshBase
+ //Mesh mesh_;
+};
+
+/*
+ * ====================================================================
+ * Define tests below
+ * ====================================================================
+ */
+
+/* Checks SmartTagger on vertices
+ */
+TEST_F(OpenMeshSmartTagger, SmartTaggerVertices) {
+
+ mesh_.clear();
+
+ // Add some vertices
+ Mesh::VertexHandle vhandle[7];
+
+ vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
+ vhandle[1] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
+ vhandle[2] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
+ vhandle[3] = mesh_.add_vertex(Mesh::Point(0,-1, 0));
+ vhandle[4] = mesh_.add_vertex(Mesh::Point(2,-1, 0));
+ vhandle[5] = mesh_.add_vertex(Mesh::Point(3, 0, 0));
+
+
+ // Add two faces
+ std::vector face_vhandles;
+
+ face_vhandles.push_back(vhandle[0]);
+ face_vhandles.push_back(vhandle[1]);
+ face_vhandles.push_back(vhandle[2]);
+ mesh_.add_face(face_vhandles);
+
+ face_vhandles.clear();
+
+ face_vhandles.push_back(vhandle[1]);
+ face_vhandles.push_back(vhandle[3]);
+ face_vhandles.push_back(vhandle[4]);
+ mesh_.add_face(face_vhandles);
+
+ face_vhandles.clear();
+
+ face_vhandles.push_back(vhandle[0]);
+ face_vhandles.push_back(vhandle[3]);
+ face_vhandles.push_back(vhandle[1]);
+ mesh_.add_face(face_vhandles);
+
+ face_vhandles.clear();
+
+ face_vhandles.push_back(vhandle[2]);
+ face_vhandles.push_back(vhandle[1]);
+ face_vhandles.push_back(vhandle[4]);
+ mesh_.add_face(face_vhandles);
+
+ face_vhandles.clear();
+
+ face_vhandles.push_back(vhandle[5]);
+ face_vhandles.push_back(vhandle[2]);
+ face_vhandles.push_back(vhandle[4]);
+ mesh_.add_face(face_vhandles);
+
+ /* Test setup:
+ 0 ==== 2
+ |\ /|\
+ | \ / | \
+ | 1 | 5
+ | / \ | /
+ |/ \|/
+ 3 ==== 4
+
+ */
+
+
+ OpenMesh::SmartTaggerVT< Mesh > tagger(mesh_);
+
+
+ EXPECT_FALSE( tagger.is_tagged(vhandle[0] ) ) << "Vertex should be untagged after init!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[1] ) ) << "Vertex should be untagged after init!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[2] ) ) << "Vertex should be untagged after init!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[3] ) ) << "Vertex should be untagged after init!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[4] ) ) << "Vertex should be untagged after init!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[5] ) ) << "Vertex should be untagged after init!";
+
+ // Reset tagged flag on all vertices
+ tagger.untag_all();
+
+ EXPECT_FALSE( tagger.is_tagged(vhandle[0] ) ) << "Vertex should be untagged after first untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[1] ) ) << "Vertex should be untagged after first untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[2] ) ) << "Vertex should be untagged after first untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[3] ) ) << "Vertex should be untagged after first untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[4] ) ) << "Vertex should be untagged after first untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[5] ) ) << "Vertex should be untagged after first untag_all!";
+
+
+ // Set tagged:
+ tagger.set_tag(vhandle[2]);
+ tagger.set_tag(vhandle[4]);
+
+ EXPECT_FALSE( tagger.is_tagged(vhandle[0] ) ) << "Vertex should be untagged!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[1] ) ) << "Vertex should be untagged!";
+ EXPECT_TRUE( tagger.is_tagged(vhandle[2] ) ) << "Vertex should be tagged!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[3] ) ) << "Vertex should be untagged!";
+ EXPECT_TRUE( tagger.is_tagged(vhandle[4] ) ) << "Vertex should be tagged!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[5] ) ) << "Vertex should be untagged!";
+
+ // Reset tagged flag on all vertices
+ tagger.untag_all();
+
+ EXPECT_FALSE( tagger.is_tagged(vhandle[0] ) ) << "Vertex should be untagged after second untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[1] ) ) << "Vertex should be untagged after second untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[2] ) ) << "Vertex should be untagged after second untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[3] ) ) << "Vertex should be untagged after second untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[4] ) ) << "Vertex should be untagged after second untag_all!";
+ EXPECT_FALSE( tagger.is_tagged(vhandle[5] ) ) << "Vertex should be untagged after second untag_all!";
+
+}
+
+/* Checks SmartTagger on vertices
+ */
+TEST_F(OpenMeshSmartTagger, SmartTaggerFaces) {
+
+ mesh_.clear();
+
+ // Add some vertices
+ Mesh::VertexHandle vhandle[7];
+
+ vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
+ vhandle[1] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
+ vhandle[2] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
+ vhandle[3] = mesh_.add_vertex(Mesh::Point(0,-1, 0));
+ vhandle[4] = mesh_.add_vertex(Mesh::Point(2,-1, 0));
+ vhandle[5] = mesh_.add_vertex(Mesh::Point(3, 0, 0));
+
+
+ // Add two faces
+ std::vector face_vhandles;
+
+ face_vhandles.push_back(vhandle[0]);
+ face_vhandles.push_back(vhandle[1]);
+ face_vhandles.push_back(vhandle[2]);
+ Mesh::FaceHandle fh1 = mesh_.add_face(face_vhandles);
+
+ face_vhandles.clear();
+
+ face_vhandles.push_back(vhandle[1]);
+ face_vhandles.push_back(vhandle[3]);
+ face_vhandles.push_back(vhandle[4]);
+ Mesh::FaceHandle fh2 = mesh_.add_face(face_vhandles);
+
+ face_vhandles.clear();
+
+ face_vhandles.push_back(vhandle[0]);
+ face_vhandles.push_back(vhandle[3]);
+ face_vhandles.push_back(vhandle[1]);
+ Mesh::FaceHandle fh3 = mesh_.add_face(face_vhandles);
+
+ face_vhandles.clear();
+
+ face_vhandles.push_back(vhandle[2]);
+ face_vhandles.push_back(vhandle[1]);
+ face_vhandles.push_back(vhandle[4]);
+ Mesh::FaceHandle fh4 = mesh_.add_face(face_vhandles);
+
+ face_vhandles.clear();
+
+ face_vhandles.push_back(vhandle[5]);
+ face_vhandles.push_back(vhandle[2]);
+ face_vhandles.push_back(vhandle[4]);
+ Mesh::FaceHandle fh5 = mesh_.add_face(face_vhandles);
+
+ /* Test setup:
+ 0 ==== 2
+ |\ /|\
+ | \ / | \
+ | 1 | 5
+ | / \ | /
+ |/ \|/
+ 3 ==== 4
+
+ */
+
+
+ OpenMesh::SmartTaggerFT< Mesh > tagger(mesh_);
+
+
+ EXPECT_FALSE( tagger.is_tagged( fh1 ) ) << "Face should be untagged after init!";
+ EXPECT_FALSE( tagger.is_tagged( fh2 ) ) << "Face should be untagged after init!";
+ EXPECT_FALSE( tagger.is_tagged( fh3 ) ) << "Face should be untagged after init!";
+ EXPECT_FALSE( tagger.is_tagged( fh4 ) ) << "Face should be untagged after init!";
+ EXPECT_FALSE( tagger.is_tagged( fh5 ) ) << "Face should be untagged after init!";
+
+
+ // Reset tagged flag on all vertices
+ tagger.untag_all();
+
+ EXPECT_FALSE( tagger.is_tagged( fh1 ) ) << "Face should be untagged after first untag_all!";
+ EXPECT_FALSE( tagger.is_tagged( fh2 ) ) << "Face should be untagged after first untag_all!";
+ EXPECT_FALSE( tagger.is_tagged( fh3 ) ) << "Face should be untagged after first untag_all!";
+ EXPECT_FALSE( tagger.is_tagged( fh4 ) ) << "Face should be untagged after first untag_all!";
+ EXPECT_FALSE( tagger.is_tagged( fh5 ) ) << "Face should be untagged after first untag_all!";
+
+
+
+ // Set tagged:
+ tagger.set_tag(fh3);
+ tagger.set_tag(fh5);
+
+
+ EXPECT_FALSE( tagger.is_tagged(fh1 ) ) << "Face should be untagged!";
+ EXPECT_FALSE( tagger.is_tagged(fh2 ) ) << "Face should be untagged!";
+ EXPECT_TRUE( tagger.is_tagged(fh3 ) ) << "Face should be tagged!";
+ EXPECT_FALSE( tagger.is_tagged(fh4 ) ) << "Face should be tagged!";
+ EXPECT_TRUE( tagger.is_tagged(fh5 ) ) << "Face should be tagged!";
+
+
+ // Reset tagged flag on all vertices
+ tagger.untag_all();
+
+ EXPECT_FALSE( tagger.is_tagged( fh1 ) ) << "Face should be untagged after second untag_all!";
+ EXPECT_FALSE( tagger.is_tagged( fh2 ) ) << "Face should be untagged after second untag_all!";
+ EXPECT_FALSE( tagger.is_tagged( fh3 ) ) << "Face should be untagged after second untag_all!";
+ EXPECT_FALSE( tagger.is_tagged( fh4 ) ) << "Face should be untagged after second untag_all!";
+ EXPECT_FALSE( tagger.is_tagged( fh5 ) ) << "Face should be untagged after second untag_all!";
+
+}
+
+}