merge
authorGustavo J. A. M. Carneiro <gjc@inescporto.pt>
Mon, 08 Oct 2007 11:24:16 +0100
changeset 1764 04f2a1dd7e45
parent 1763 4624d5aba98f (current diff)
parent 1694 fc22854fc549 (diff)
child 1765 763f8d1bb058
merge
src/simulator/wscript
utils/wscript
wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-random-walk.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,61 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include <vector>
+
+#include "ns3/ptr.h"
+#include "ns3/mobility-model.h"
+#include "ns3/mobility-model-notifier.h"
+#include "ns3/random-topology.h"
+#include "ns3/default-value.h"
+#include "ns3/command-line.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/node.h"
+#include "ns3/node-list.h"
+
+using namespace ns3;
+
+static void 
+CourseChange (ns3::TraceContext const&, Ptr<const MobilityModel> mobility)
+{
+  Position pos = mobility->Get ();
+  Speed vel = mobility->GetSpeed ();
+  std::cout << Simulator::Now () << ", model=" << mobility << ", POS: x=" << pos.x << ", y=" << pos.y
+            << ", z=" << pos.z << "; VEL:" << vel.dx << ", y=" << vel.dy
+            << ", z=" << vel.dz << std::endl;
+}
+
+int main (int argc, char *argv[])
+{
+  DefaultValue::Bind ("RandomWalk2dMode", "Time");
+  DefaultValue::Bind ("RandomWalk2dTime", "2s");
+  DefaultValue::Bind ("RandomWalk2dSpeed", "Constant:1.0");
+  DefaultValue::Bind ("RandomWalk2dBounds", "0:200:0:100");
+
+  DefaultValue::Bind ("RandomDiscPositionX", "100");
+  DefaultValue::Bind ("RandomDiscPositionY", "50");
+  DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30");
+
+  DefaultValue::Bind ("RandomTopologyPositionType", "RandomDiscPosition");
+  DefaultValue::Bind ("RandomTopologyMobilityType", "RandomWalk2dMobilityModel");
+
+  CommandLine::Parse (argc, argv);
+
+  RandomTopology topology;
+
+  for (uint32_t i = 0; i < 100; i++)
+    {
+      Ptr<Node> node = Create<Node> ();
+      node->AddInterface (Create<MobilityModelNotifier> ());
+    }
+
+  topology.Layout (NodeList::Begin (), NodeList::End ());
+  NodeList::Connect ("/nodes/*/$MobilityModelNotifier/course-change", 
+                     MakeCallback (&CourseChange));
+
+  Simulator::StopAt (Seconds (100.0));
+
+  Simulator::Run ();
+  
+  return 0;
+}
--- a/samples/wscript	Mon Oct 08 11:23:53 2007 +0100
+++ b/samples/wscript	Mon Oct 08 11:24:16 2007 +0100
@@ -41,3 +41,6 @@
                                  ['core', 'simulator', 'mobility'])
     obj.source = 'main-random-topology.cc'
 
+    obj = bld.create_ns3_program('main-random-walk',
+                                 ['core', 'simulator', 'mobility'])
+    obj.source = 'main-random-walk.cc'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/int-to-type.h	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,19 @@
+#ifndef INT_TO_TYPE_H
+#define INT_TO_TYPE_H
+
+namespace ns3 {
+
+/**
+ * This trivial template is extremely useful, as explained in
+ * "Modern C++ Design", p29, section 2.4, 
+ * "Mapping Integral Constants to Types"
+ */
+template <int v>
+struct IntToType
+{
+  enum {value = v};
+};
+
+} // namespace ns3
+
+#endif /* INT_TO_TYPE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/type-traits-test.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,40 @@
+#include "type-traits.h"
+#include "test.h"
+
+#ifdef RUN_SELF_TESTS
+
+namespace ns3 {
+
+class TypeTraitsTest : public Test
+{
+public:
+  TypeTraitsTest ();
+  virtual bool RunTests (void);
+};
+
+TypeTraitsTest::TypeTraitsTest ()
+  : Test ("TypeTraits")
+{}
+bool 
+TypeTraitsTest::RunTests (void)
+{
+  bool result = true;
+
+  //TypeTraits<int &>::ReferencedType ir;
+  //TypeTraits<const int>::NonConstType uci;
+  NS_TEST_ASSERT_EQUAL (TypeTraits<void (TypeTraitsTest::*) (void)>::IsPointerToMember, 1);
+  NS_TEST_ASSERT_EQUAL (TypeTraits<void (TypeTraitsTest::*) (void) const>::IsPointerToMember, 1);
+  NS_TEST_ASSERT_EQUAL (TypeTraits<void (TypeTraitsTest::*) (int)>::IsPointerToMember, 1);
+  NS_TEST_ASSERT_EQUAL (TypeTraits<void (TypeTraitsTest::*) (int) const>::IsPointerToMember, 1);
+  NS_TEST_ASSERT_EQUAL (TypeTraits<void (TypeTraitsTest::*) (void) const>::PointerToMemberTraits::nArgs, 0);
+  NS_TEST_ASSERT_EQUAL (TypeTraits<void (TypeTraitsTest::*) (int) const>::PointerToMemberTraits::nArgs, 1);
+
+  return result;
+}
+
+static TypeTraitsTest g_typeTraitsTest;
+
+} // namespace ns3
+
+#endif /* RUN_SELF_TESTS */
+
--- a/src/core/type-traits.h	Mon Oct 08 11:23:53 2007 +0100
+++ b/src/core/type-traits.h	Mon Oct 08 11:24:16 2007 +0100
@@ -2,24 +2,293 @@
 #define TYPE_TRAITS_H
 
 template <typename T>
-struct TypeTraits;
-
-template <typename T>
 struct TypeTraits
 {
-  typedef T ReferencedType;
-};
+private:
+  struct NullType {};
+  template <typename U> struct UnConst
+  {
+    typedef U Result;
+  };
+  template <typename U> struct UnConst<const U>
+  {
+    typedef U Result;
+  };
+  template <typename U> struct ReferenceTraits
+  {
+    enum {IsReference = 0};
+    typedef U ReferencedType;
+  };
+  template <typename U> struct ReferenceTraits<U&>
+  {
+    enum {IsReference = 1};
+    typedef U ReferencedType;
+  };
+  template <typename U> struct PointerTraits
+  {
+    enum {IsPointer = 0};
+    typedef U PointeeType;
+  };
+  template <typename U> struct PointerTraits<U *>
+  {
+    enum {IsPointer = 1};
+    typedef U PointeeType;
+  };
+  template <typename U> struct FunctionPtrTraits
+  {
+    enum {IsFunctionPointer = 0};
+  };
+  template <typename U> 
+  struct FunctionPtrTraits <U (*) (void)>
+  {
+    enum {IsFunctionPointer = 1};
+    enum {nArgs = 0};
+    typedef U ReturnType;
+  };
+  template <typename U, typename V1> 
+  struct FunctionPtrTraits <U (*) (V1)>
+  {
+    enum {IsFunctionPointer = 1};
+    enum {nArgs = 1};
+    typedef U ReturnType;
+    typedef V1 Arg1Type;
+  };
+  template <typename U, typename V1, typename V2> 
+  struct FunctionPtrTraits <U (*) (V1,V2)>
+  {
+    enum {IsFunctionPointer = 1};
+    enum {nArgs = 2};
+    typedef U ReturnType;
+    typedef V1 Arg1Type;
+    typedef V2 Arg2Type;
+  };
+  template <typename U, typename V1, typename V2,
+            typename V3> 
+  struct FunctionPtrTraits <U (*) (V1,V2,V3)>
+  {
+    enum {IsFunctionPointer = 1};
+    enum {nArgs = 3};
+    typedef U ReturnType;
+    typedef V1 Arg1Type;
+    typedef V2 Arg2Type;
+    typedef V3 Arg3Type;
+  };
+  template <typename U, typename V1, typename V2,
+            typename V3, typename V4> 
+  struct FunctionPtrTraits <U (*) (V1,V2,V3,V4)>
+  {
+    enum {IsFunctionPointer = 1};
+    enum {nArgs = 4};
+    typedef U ReturnType;
+    typedef V1 Arg1Type;
+    typedef V2 Arg2Type;
+    typedef V3 Arg3Type;
+    typedef V4 Arg4Type;
+  };
+  template <typename U, typename V1, typename V2,
+            typename V3, typename V4,
+            typename V5> 
+  struct FunctionPtrTraits <U (*) (V1,V2,V3,V4,V5)>
+  {
+    enum {IsFunctionPointer = 1};
+    enum {nArgs = 5};
+    typedef U ReturnType;
+    typedef V1 Arg1Type;
+    typedef V2 Arg2Type;
+    typedef V3 Arg3Type;
+    typedef V4 Arg4Type;
+    typedef V5 Arg5Type;
+  };
+  template <typename U, typename V1, typename V2,
+            typename V3, typename V4,
+            typename V5, typename V6> 
+  struct FunctionPtrTraits <U (*) (V1,V2,V3,V4,V5,V6)>
+  {
+    enum {IsFunctionPointer = 1};
+    enum {nArgs = 6};
+    typedef U ReturnType;
+    typedef V1 Arg1Type;
+    typedef V2 Arg2Type;
+    typedef V3 Arg3Type;
+    typedef V4 Arg4Type;
+    typedef V5 Arg5Type;
+    typedef V6 Arg6Type;
+  };
+  template <typename U> struct PtrToMemberTraits
+  {
+    enum {IsPointerToMember = 0};
+  };
+  template <typename U, typename V> 
+  struct PtrToMemberTraits <U (V::*) (void)>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 0};
+    typedef U ReturnType;
+  };
+  template <typename U, typename V> 
+  struct PtrToMemberTraits <U (V::*) (void) const>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 0};
+    typedef U ReturnType;
+  };
+  template <typename U, typename V,typename W1> 
+  struct PtrToMemberTraits <U (V::*) (W1)>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 1};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+  };
+  template <typename U, typename V,typename W1> 
+  struct PtrToMemberTraits <U (V::*) (W1) const>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 1};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+  };
+  template <typename U, typename V,typename W1, typename W2> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2)>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 2};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+  };
+  template <typename U, typename V,typename W1, typename W2> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2) const>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 2};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+  };
+  template <typename U, typename V,
+            typename W1, typename W2,
+            typename W3> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2,W3)>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 3};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+    typedef W3 Arg3Type;
+  };
+  template <typename U, typename V,
+            typename W1, typename W2,
+            typename W3> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2,W3) const>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 3};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+    typedef W3 Arg3Type;
+  };
+  template <typename U, typename V,
+            typename W1, typename W2,
+            typename W3, typename W4> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2,W3,W4)>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 4};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+    typedef W3 Arg3Type;
+    typedef W4 Arg4Type;
+  };
+  template <typename U, typename V,
+            typename W1, typename W2,
+            typename W3, typename W4> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2,W3,W4) const>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 4};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+    typedef W3 Arg3Type;
+    typedef W4 Arg4Type;
+  };
+  template <typename U, typename V,
+            typename W1, typename W2,
+            typename W3, typename W4,
+            typename W5> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2,W3,W4,W5)>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 5};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+    typedef W3 Arg3Type;
+    typedef W4 Arg4Type;
+    typedef W5 Arg5Type;
+  };
+  template <typename U, typename V,
+            typename W1, typename W2,
+            typename W3, typename W4,
+            typename W5> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2,W3,W4,W5) const>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 5};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+    typedef W3 Arg3Type;
+    typedef W4 Arg4Type;
+    typedef W5 Arg5Type;
+  };
+  template <typename U, typename V,
+            typename W1, typename W2,
+            typename W3, typename W4,
+            typename W5, typename W6> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2,W3,W4,W5,W6)>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 6};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+    typedef W3 Arg3Type;
+    typedef W4 Arg4Type;
+    typedef W5 Arg5Type;
+    typedef W6 Arg6Type;
+  };
+  template <typename U, typename V,
+            typename W1, typename W2,
+            typename W3, typename W4,
+            typename W5, typename W6> 
+  struct PtrToMemberTraits <U (V::*) (W1,W2,W3,W4,W5,W6) const>
+  {
+    enum {IsPointerToMember = 1};
+    enum {nArgs = 6};
+    typedef U ReturnType;
+    typedef W1 Arg1Type;
+    typedef W2 Arg2Type;
+    typedef W3 Arg3Type;
+    typedef W4 Arg4Type;
+    typedef W5 Arg5Type;
+    typedef W6 Arg6Type;
+  };
 
-template <typename T>
-struct TypeTraits<const T &>
-{
-  typedef T ReferencedType;
-};
-
-template <typename T>
-struct TypeTraits<T &>
-{
-  typedef T ReferencedType;
+public:
+  typedef typename UnConst<T>::Result NonConstType;
+  typedef typename ReferenceTraits<T>::ReferencedType ReferencedType;
+  typedef typename PointerTraits<T>::PointeeType PointeeType;
+  enum {IsPointerToMember = PtrToMemberTraits<T>::IsPointerToMember};
+  enum {IsPointer = PointerTraits<T>::IsPointer};
+  enum {IsReference = ReferenceTraits<T>::IsReference};
+  enum {IsFunctionPointer = FunctionPtrTraits<T>::IsFunctionPointer};
+  typedef PtrToMemberTraits<T> PointerToMemberTraits;
+  typedef FunctionPtrTraits<T> FunctionPointerTraits;
 };
 
 
--- a/src/core/wscript	Mon Oct 08 11:23:53 2007 +0100
+++ b/src/core/wscript	Mon Oct 08 11:24:16 2007 +0100
@@ -51,6 +51,7 @@
         'composite-trace-resolver.cc',
         'trace-doc.cc',
         'trace-source.cc',
+        'type-traits-test.cc',
         ]
 
     if sys.platform == 'win32':
@@ -94,5 +95,6 @@
         'composite-trace-resolver.h',
         'array-trace-resolver.h',
         'trace-doc.h',
+        'int-to-type.h',
         ]
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/ns2-mobility-file-topology.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,145 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include <fstream>
+#include <sstream>
+#include "ns3/debug.h"
+#include "ns3/simulator.h"
+#include "ns3/node-list.h"
+#include "ns3/node.h"
+#include "ns2-mobility-file-topology.h"
+#include "static-speed-mobility-model.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("Ns2MobilityFileTopology");
+
+namespace ns3 {
+
+
+Ns2MobilityFileTopology::Ns2MobilityFileTopology (std::string filename)
+  : m_filename (filename)
+{}
+
+
+Ptr<StaticSpeedMobilityModel>
+Ns2MobilityFileTopology::GetMobilityModel (std::string idString, const ObjectStore &store) const
+{
+  std::istringstream iss;
+  iss.str (idString);
+  uint32_t id;
+  iss >> id;
+  Ptr<Object> object = store.Get (id);
+  if (object == 0)
+    {
+      return 0;
+    }
+  Ptr<StaticSpeedMobilityModel> model = 
+    object->QueryInterface<StaticSpeedMobilityModel> (StaticSpeedMobilityModel::iid);
+  if (model == 0)
+    {
+      model = Create<StaticSpeedMobilityModel> ();
+      object->AddInterface (model);
+    }
+  return model;
+}
+
+double
+Ns2MobilityFileTopology::ReadDouble (std::string valueString) const
+{
+  std::istringstream iss;
+  iss.str (valueString);
+  double value;
+  iss >> value;
+  return value;
+}
+
+void 
+Ns2MobilityFileTopology::LayoutObjectStore (const ObjectStore &store) const
+{
+  std::ifstream file (m_filename.c_str (), std::ios::in);
+  if (file.is_open())
+    {
+      while (!file.eof() )
+	{
+	  std::string line;
+	  getline (file, line);
+	  std::string::size_type startNodeId = line.find_first_of ("(");
+	  std::string::size_type endNodeId = line.find_first_of (")");
+	  if (startNodeId == std::string::npos ||
+	      endNodeId == std::string::npos)
+	    {
+	      continue;
+	    }
+	  Ptr<StaticSpeedMobilityModel> model = GetMobilityModel (line.substr (startNodeId + 1, 
+									       endNodeId - startNodeId), 
+								  store);
+	  if (model == 0)
+	    {
+	      continue;
+	    }
+	  if (startNodeId == 6)
+	    {
+	      double value = ReadDouble (line.substr (endNodeId + 9, std::string::npos));
+	      std::string coordinate = line.substr (endNodeId + 6, 1);
+              Position position = model->Get ();
+	      if (coordinate == "X")
+		{
+                  position.x = value;
+		  NS_DEBUG ("X=" << value);
+		}
+	      else if (coordinate == "Y")
+		{
+                  position.y = value;
+		  NS_DEBUG ("Y=" << value);
+		}
+	      else if (coordinate == "Z")
+		{
+                  position.z = value;
+		  NS_DEBUG ("Z=" << value);
+		}
+              else
+                {
+                  continue;
+                }
+              model->Set (position);
+	    }
+	  else 
+	    {
+	      double at = ReadDouble (line.substr (8, startNodeId - 17));
+	      std::string::size_type xSpeedEnd = line.find_first_of (" ", endNodeId + 10);
+	      std::string::size_type ySpeedEnd = line.find_first_of (" ", xSpeedEnd + 1);
+	      double xSpeed = ReadDouble (line.substr (endNodeId + 10, xSpeedEnd - endNodeId - 10));
+	      double ySpeed = ReadDouble (line.substr (xSpeedEnd + 1, ySpeedEnd - xSpeedEnd - 1));
+	      double zSpeed = ReadDouble (line.substr (ySpeedEnd + 1, std::string::npos));
+	      NS_DEBUG ("at=" << at << "xSpeed=" << xSpeed << ", ySpeed=" << ySpeed << ", zSpeed=" << zSpeed);
+	      Simulator::Schedule (Seconds (at), &StaticSpeedMobilityModel::SetSpeed, model,
+				   Speed (xSpeed, ySpeed, zSpeed));
+	    }
+	}
+      file.close();
+    }
+}
+
+void 
+Ns2MobilityFileTopology::Layout (void) const
+{
+  Layout (NodeList::Begin (), NodeList::End ());
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/ns2-mobility-file-topology.h	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,113 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef NS2_MOBILITY_FILE_TOPOLOGY_H
+#define NS2_MOBILITY_FILE_TOPOLOGY_H
+
+#include <string>
+#include <stdint.h>
+#include "ns3/ptr.h"
+#include "ns3/object.h"
+#include "static-speed-mobility-model.h"
+
+namespace ns3 {
+
+/**
+ * \brief a topology object which can read ns2's movement files
+ *        generated by the CMU setdest tool.
+ */
+class Ns2MobilityFileTopology
+{
+public:
+  /**
+   * \param filename filename of file which contains the
+   *        ns2 movement trace.
+   */
+  Ns2MobilityFileTopology (std::string filename);
+
+  /**
+   * Read the ns2 trace file and configure the movement
+   * patterns of all nodes contained in the global ns3::NodeList
+   * whose nodeId is matches the nodeId of the nodes in the trace
+   * file.
+   */
+  void Layout (void) const;
+
+  /**
+   * \param begin an iterator which points to the start of the input
+   *        object array.
+   * \param end an iterator which points to the end of the input
+   *        object array.
+   *
+   * Read the ns2 trace file and configure the movement
+   * patterns of all input objects. Each input object
+   * is identified by a unique node id which reflects
+   * the index of the object in the input array.
+   */
+  template <typename T>
+  void Layout (T begin, T end) const;
+private:
+  class ObjectStore
+  {
+  public:
+    virtual ~ObjectStore () {}
+    virtual Ptr<Object> Get (uint32_t i) const = 0;
+  };
+  void LayoutObjectStore (const ObjectStore &store) const;
+  Ptr<StaticSpeedMobilityModel> GetMobilityModel (std::string idString, const ObjectStore &store) const;
+  double ReadDouble (std::string valueString) const;
+  std::string m_filename;
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void 
+Ns2MobilityFileTopology::Layout (T begin, T end) const
+{
+  class MyObjectStore : public ObjectStore
+  {
+  public:
+    MyObjectStore (T begin, T end)
+      : m_begin (begin),
+      m_end (end)
+	{}
+    virtual Ptr<Object> Get (uint32_t i) const {
+      T iterator = m_begin;
+      iterator += i;
+      if (iterator >= m_end)
+	{
+	  return 0;
+	}
+      return *iterator;
+    }
+  private:
+    T m_begin;
+    T m_end;
+  };
+  LayoutObjectStore (MyObjectStore (begin, end));
+}
+
+
+} // namespace ns3
+
+#endif /* NS2_MOBILITY_FILE_TOPOLOGY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/random-direction-2d-mobility-model.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,210 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "ns3/random-variable-default-value.h"
+#include "ns3/rectangle-default-value.h"
+#include "ns3/simulator.h"
+#include <algorithm>
+#include <cmath>
+#include "random-direction-2d-mobility-model.h"
+#include "ns3/log.h"
+
+NS_LOG_COMPONENT_DEFINE ("RandomDirection2dMobilityModel");
+
+namespace ns3 {
+
+const double RandomDirection2dMobilityModel::PI = 3.14159265358979323846;
+const ClassId RandomDirection2dMobilityModel::cid = 
+  MakeClassId<RandomDirection2dMobilityModel> ("RandomDirection2dMobilityModel",
+                                               MobilityModel::iid);
+
+
+static RandomVariableDefaultValue 
+  g_speedVariable ("RandomDirection2dSpeed",
+		   "A random variable to control the speed of a RandomDirection2d mobility model.",
+		   "Uniform:1:2");
+
+static RandomVariableDefaultValue
+  g_pauseVariable ("RandomDirection2dPause",
+		   "A random variable to control the duration "
+                   "of the pause of a RandomDiretion mobility model.",
+		   "Constant:2");
+
+static RectangleDefaultValue
+  g_bounds ("RandomDirection2dArea",
+	       "The bounding area for the RandomDirection2d model.",
+	       -100, 100, -100, 100);
+
+
+RandomDirection2dMobilityModelParameters::RandomDirection2dMobilityModelParameters ()
+  : m_bounds (g_bounds.GetValue ()),
+    m_speedVariable (g_speedVariable.GetCopy ()),
+    m_pauseVariable (g_pauseVariable.GetCopy ())
+    
+{}
+RandomDirection2dMobilityModelParameters::RandomDirection2dMobilityModelParameters 
+(const Rectangle &bounds,
+ const RandomVariable &speedVariable,
+ const RandomVariable &pauseVariable)
+  : m_bounds (bounds),
+    m_speedVariable (speedVariable.Copy ()),
+    m_pauseVariable (pauseVariable.Copy ())
+{}
+
+RandomDirection2dMobilityModelParameters::~RandomDirection2dMobilityModelParameters ()
+{
+  delete m_speedVariable;
+  delete m_pauseVariable;
+  m_speedVariable = 0;
+  m_pauseVariable = 0;
+}
+
+void 
+RandomDirection2dMobilityModelParameters::SetSpeed (const RandomVariable &speedVariable)
+{
+  delete m_speedVariable;
+  m_speedVariable = speedVariable.Copy ();
+}
+void 
+RandomDirection2dMobilityModelParameters::SetPause (const RandomVariable &pauseVariable)
+{
+  delete m_pauseVariable;
+  m_pauseVariable = pauseVariable.Copy ();
+}
+void 
+RandomDirection2dMobilityModelParameters::SetBounds (const Rectangle &bounds)
+{
+  m_bounds = bounds;
+}
+
+Ptr<RandomDirection2dMobilityModelParameters> 
+RandomDirection2dMobilityModelParameters::GetCurrent (void)
+{
+  static Ptr<RandomDirection2dMobilityModelParameters> parameters = 0;
+  if (parameters == 0 ||
+      g_bounds.IsDirty () ||
+      g_speedVariable.IsDirty () ||
+      g_pauseVariable.IsDirty ())
+    {
+      parameters = Create<RandomDirection2dMobilityModelParameters> ();
+      g_bounds.ClearDirtyFlag ();
+      g_speedVariable.ClearDirtyFlag ();
+      g_pauseVariable.ClearDirtyFlag ();
+    }
+  return parameters;
+}
+
+
+RandomDirection2dMobilityModel::RandomDirection2dMobilityModel ()
+  : m_parameters (RandomDirection2dMobilityModelParameters::GetCurrent ())
+{
+  SetInterfaceId (RandomDirection2dMobilityModel::iid);
+  m_event = Simulator::ScheduleNow (&RandomDirection2dMobilityModel::Start, this);
+}
+RandomDirection2dMobilityModel::RandomDirection2dMobilityModel 
+(Ptr<RandomDirection2dMobilityModelParameters> parameters)
+  : m_parameters (parameters)
+{
+  SetInterfaceId (RandomDirection2dMobilityModel::iid);
+  m_event = Simulator::ScheduleNow (&RandomDirection2dMobilityModel::Start, this);
+}
+void 
+RandomDirection2dMobilityModel::DoDispose (void)
+{
+  m_parameters = 0;
+  // chain up.
+  MobilityModel::DoDispose ();
+}
+void
+RandomDirection2dMobilityModel::Start (void)
+{
+  double direction = UniformVariable::GetSingleValue (0, 2 * PI);
+  SetDirectionAndSpeed (direction);
+}
+
+void
+RandomDirection2dMobilityModel::BeginPause (void)
+{
+  Time pause = Seconds (m_parameters->m_pauseVariable->GetValue ());
+  m_helper.Pause ();
+  m_event = Simulator::Schedule (pause, &RandomDirection2dMobilityModel::ResetDirectionAndSpeed, this);
+  NotifyCourseChange ();
+}
+
+void
+RandomDirection2dMobilityModel::SetDirectionAndSpeed (double direction)
+{
+  NS_LOG_FUNCTION;
+  double speed = m_parameters->m_speedVariable->GetValue ();
+  const Speed vector (std::cos (direction) * speed,
+                      std::sin (direction) * speed,
+                      0.0);
+  Position position = m_helper.GetCurrentPosition (m_parameters->m_bounds);
+  m_helper.Reset (vector);
+  Position next = m_parameters->m_bounds.CalculateIntersection (position, vector);
+  Time delay = Seconds (CalculateDistance (position, next) / speed);
+  m_event = Simulator::Schedule (delay,
+				 &RandomDirection2dMobilityModel::BeginPause, this);
+  NotifyCourseChange ();
+}
+void
+RandomDirection2dMobilityModel::ResetDirectionAndSpeed (void)
+{
+  double direction = UniformVariable::GetSingleValue (0, PI);
+  
+  Position position = m_helper.GetCurrentPosition (m_parameters->m_bounds);
+  switch (m_parameters->m_bounds.GetClosestSide (position))
+    {
+    case Rectangle::RIGHT:
+      direction += PI / 2;
+      break;
+    case Rectangle::LEFT:
+      direction += - PI / 2;
+      break;
+    case Rectangle::TOP:
+      direction += PI;
+      break;
+    case Rectangle::BOTTOM:
+      direction += 0.0;
+      break;
+    }
+  SetDirectionAndSpeed (direction);
+}
+Position
+RandomDirection2dMobilityModel::DoGet (void) const
+{
+  return m_helper.GetCurrentPosition (m_parameters->m_bounds);
+}
+void
+RandomDirection2dMobilityModel::DoSet (const Position &position)
+{
+  m_helper.InitializePosition (position);
+  Simulator::Remove (m_event);
+  m_event = Simulator::ScheduleNow (&RandomDirection2dMobilityModel::Start, this);
+}
+Speed 
+RandomDirection2dMobilityModel::DoGetSpeed (void) const
+{
+  return m_helper.GetSpeed ();
+}
+
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/random-direction-2d-mobility-model.h	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,121 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef RANDOM_DIRECTION_MOBILITY_MODEL_H
+#define RANDOM_DIRECTION_MOBILITY_MODEL_H
+
+#include "ns3/object.h"
+#include "ns3/ptr.h"
+#include "ns3/nstime.h"
+#include "ns3/event-id.h"
+#include "ns3/component-manager.h"
+#include "ns3/rectangle.h"
+#include "mobility-model.h"
+#include "static-speed-helper.h"
+
+namespace ns3 {
+
+class RandomVariable;
+
+/**
+ * \brief the parameters to control a RandomDirection mobility model.
+ */
+class RandomDirection2dMobilityModelParameters : public Object
+{
+ public:
+  /**
+   * Create a default parameter object from Bind default values.
+   */
+  RandomDirection2dMobilityModelParameters ();
+  /**
+   * \param bounds the 2d bounds of the mobility model
+   * \param speedVariable the random variable used to pick a random speed
+   * \param pauseVariable the random variable used to pick a random pause delay
+   */
+  RandomDirection2dMobilityModelParameters (const Rectangle &bounds,
+                               const RandomVariable &speedVariable,
+                               const RandomVariable &pauseVariable);
+  virtual ~RandomDirection2dMobilityModelParameters ();
+
+  /**
+   * \param speedVariable the random variable used to pick a random speed.
+   */
+  void SetSpeed (const RandomVariable &speedVariable);
+  /**
+   * \param pauseVariable the random variable used to pick a random pause delay.
+   */
+  void SetPause (const RandomVariable &pauseVariable);
+  /**
+   * \param bounds the 2d bounds of the mobility model.
+   */
+  void SetBounds (const Rectangle &bounds);
+ private:
+  friend class RandomDirection2dMobilityModel;
+
+  static Ptr<RandomDirection2dMobilityModelParameters> GetCurrent (void);
+
+  Rectangle m_bounds;
+  RandomVariable *m_speedVariable;
+  RandomVariable *m_pauseVariable;
+};
+
+/**
+ * \brief a RandomDirection mobility model
+ *
+ * The movement of objects is based on random directions: each object
+ * pauses for a specific delay, chooses a random direction and speed and 
+ * then travels in the specific direction until it reaches one of
+ * the boundaries of the model. When it reaches the boundary, it pauses,
+ * selects a new direction and speed, aso.
+ */
+class RandomDirection2dMobilityModel : public MobilityModel
+{
+ public:
+  static const ClassId cid;
+
+  /**
+   * Create a RandomDirection model from the default Bind values.
+   */
+  RandomDirection2dMobilityModel ();
+  /**
+   * \param parameters the parameters which control the behavior of the model.
+   * Create a RandomDirection model using the parameters specified.
+   */
+  RandomDirection2dMobilityModel (Ptr<RandomDirection2dMobilityModelParameters> parameters);
+ private:
+  void Start (void);
+  void ResetDirectionAndSpeed (void);
+  void BeginPause (void);
+  void SetDirectionAndSpeed (double direction);
+  void InitializeDirectionAndSpeed (void);
+  virtual void DoDispose (void);
+  virtual Position DoGet (void) const;
+  virtual void DoSet (const Position &position);
+  virtual Speed DoGetSpeed (void) const;
+
+  static const double PI;
+  Ptr<RandomDirection2dMobilityModelParameters> m_parameters;
+  EventId m_event;
+  StaticSpeedHelper m_helper;
+};
+
+} // namespace ns3
+
+#endif /* RANDOM_DIRECTION_MOBILITY_MODEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/random-walk-2d-mobility-model.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,233 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include "random-walk-2d-mobility-model.h"
+#include "ns3/default-value.h"
+#include "ns3/time-default-value.h"
+#include "ns3/rectangle-default-value.h"
+#include "ns3/random-variable-default-value.h"
+#include "ns3/simulator.h"
+#include "ns3/debug.h"
+#include <cmath>
+
+NS_DEBUG_COMPONENT_DEFINE ("RandomWalk2d");
+
+namespace ns3 {
+
+const ClassId RandomWalk2dMobilityModel::cid = 
+  MakeClassId<RandomWalk2dMobilityModel> ("RandomWalk2dMobilityModel", RandomWalk2dMobilityModel::iid);
+
+
+static EnumDefaultValue<RandomWalk2dMobilityModelParameters::Mode> 
+g_mode ("RandomWalk2dMode",
+        "The mode indicates the condition used to "
+        "change the current speed and direction",
+        RandomWalk2dMobilityModelParameters::MODE_DISTANCE, "Distance",
+        RandomWalk2dMobilityModelParameters::MODE_TIME, "Time",
+        0, (void*)0);
+
+static NumericDefaultValue<double>
+g_modeDistance ("RandomWalk2dDistance",
+                "Change current direction and speed after moving this distance.",
+                2.0);
+
+static TimeDefaultValue
+g_modeTime ("RandomWalk2dTime",
+             "Change current direction and speed after moving for this delay.",
+             Seconds (1.0));
+
+static RandomVariableDefaultValue
+g_speed ("RandomWalk2dSpeed",
+         "A random variable used to pick the speed.",
+         "Uniform:2:4");
+static RandomVariableDefaultValue
+g_direction ("RandomWalk2dDirection",
+             "A random variable used to pick the direction (gradients).",
+             "Uniform:0.0:6.283184");
+
+static RectangleDefaultValue
+g_rectangle ("RandomWalk2dBounds",
+             "Bounds of the area to cruise.",
+             0.0, 0.0, 100.0, 100.0);
+
+RandomWalk2dMobilityModelParameters::RandomWalk2dMobilityModelParameters ()
+  : m_mode (g_mode.GetValue ()),
+    m_modeDistance (g_modeDistance.GetValue ()),
+    m_modeTime (g_modeTime.GetValue ()),
+    m_speed (g_speed.GetCopy ()),
+    m_direction (g_direction.GetCopy ()),
+    m_bounds (g_rectangle.GetValue ())
+{}
+
+RandomWalk2dMobilityModelParameters::~RandomWalk2dMobilityModelParameters ()
+{
+  delete m_speed;
+  delete m_direction;
+  m_speed = 0;
+  m_direction = 0;
+}
+
+void 
+RandomWalk2dMobilityModelParameters::SetSpeed (const RandomVariable &speed)
+{
+  delete m_speed;
+  m_speed = speed.Copy ();
+}
+void 
+RandomWalk2dMobilityModelParameters::SetDirection (const RandomVariable &direction)
+{
+  delete m_direction;
+  m_direction = direction.Copy ();
+}
+void 
+RandomWalk2dMobilityModelParameters::SetModeDistance (double distance)
+{
+  m_mode = RandomWalk2dMobilityModelParameters::MODE_DISTANCE;
+  m_modeDistance = distance;
+}
+void 
+RandomWalk2dMobilityModelParameters::SetModeTime (Time time)
+{
+  m_mode = RandomWalk2dMobilityModelParameters::MODE_TIME;
+  m_modeTime = time;
+}
+void 
+RandomWalk2dMobilityModelParameters::SetBounds (const Rectangle &bounds)
+{
+  m_bounds = bounds;
+}
+
+Ptr<RandomWalk2dMobilityModelParameters> 
+RandomWalk2dMobilityModelParameters::GetCurrent (void)
+{
+  static Ptr<RandomWalk2dMobilityModelParameters> parameters = 0;
+  if (parameters == 0 ||
+      g_speed.IsDirty () ||
+      g_direction.IsDirty () ||
+      g_mode.IsDirty () ||
+      g_modeDistance.IsDirty () ||
+      g_modeTime.IsDirty () ||
+      g_rectangle.IsDirty ())
+    {
+      parameters = Create<RandomWalk2dMobilityModelParameters> ();
+    }
+  return parameters;
+}
+
+RandomWalk2dMobilityModel::RandomWalk2dMobilityModel ()
+  : m_parameters (RandomWalk2dMobilityModelParameters::GetCurrent ())
+{
+  SetInterfaceId (RandomWalk2dMobilityModel::iid);
+  m_event = Simulator::ScheduleNow (&RandomWalk2dMobilityModel::Start, this);
+}
+
+void
+RandomWalk2dMobilityModel::Start (void)
+{
+  double speed = m_parameters->m_speed->GetValue ();
+  double direction = m_parameters->m_direction->GetValue ();
+  Speed vector (std::cos (direction) * speed,
+                std::sin (direction) * speed,
+                0.0);
+  m_helper.Reset (vector);
+
+  Time delayLeft;
+  if (m_parameters->m_mode == RandomWalk2dMobilityModelParameters::MODE_TIME)
+    {
+      delayLeft = m_parameters->m_modeTime;
+    }
+  else
+    {
+      delayLeft = Seconds (m_parameters->m_modeDistance / speed); 
+    }
+  DoWalk (delayLeft);
+}
+
+void
+RandomWalk2dMobilityModel::DoWalk (Time delayLeft)
+{
+  Position position = m_helper.GetCurrentPosition ();
+  Speed speed = m_helper.GetSpeed ();
+  Position nextPosition = position;
+  nextPosition.x += speed.dx * delayLeft.GetSeconds ();
+  nextPosition.y += speed.dy * delayLeft.GetSeconds ();
+  if (m_parameters->m_bounds.IsInside (nextPosition))
+    {
+      m_event = Simulator::Schedule (delayLeft, &RandomWalk2dMobilityModel::Start, this);
+    }
+  else
+    {
+      nextPosition = m_parameters->m_bounds.CalculateIntersection (position, speed);
+      Time delay = Seconds ((nextPosition.x - position.x) / speed.dx);
+      m_event = Simulator::Schedule (delay, &RandomWalk2dMobilityModel::Rebound, this,
+                                     delayLeft - delay);      
+    }  
+  NotifyCourseChange ();
+}
+
+void
+RandomWalk2dMobilityModel::Rebound (Time delayLeft)
+{
+  Position position = m_helper.GetCurrentPosition (m_parameters->m_bounds);
+  Speed speed = m_helper.GetSpeed ();
+  switch (m_parameters->m_bounds.GetClosestSide (position))
+    {
+    case Rectangle::RIGHT:
+    case Rectangle::LEFT:
+      speed.dx = - speed.dx;
+      break;
+    case Rectangle::TOP:
+    case Rectangle::BOTTOM:
+      speed.dy = - speed.dy;
+      break;
+    }
+  m_helper.Reset (speed);
+  DoWalk (delayLeft);
+}
+
+void
+RandomWalk2dMobilityModel::DoDispose (void)
+{
+  m_parameters = 0;
+  // chain up
+  MobilityModel::DoDispose ();
+}
+Position
+RandomWalk2dMobilityModel::DoGet (void) const
+{
+  return m_helper.GetCurrentPosition (m_parameters->m_bounds);
+}
+void
+RandomWalk2dMobilityModel::DoSet (const Position &position)
+{
+  NS_ASSERT (m_parameters->m_bounds.IsInside (position));
+  m_helper.InitializePosition (position);
+  Simulator::Remove (m_event);
+  m_event = Simulator::ScheduleNow (&RandomWalk2dMobilityModel::Start, this);
+}
+Speed 
+RandomWalk2dMobilityModel::DoGetSpeed (void) const
+{
+  return m_helper.GetSpeed ();
+}
+
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/random-walk-2d-mobility-model.h	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,147 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef RANDOM_WALK_2D_MOBILITY_MODEL_H
+#define RANDOM_WALK_2D_MOBILITY_MODEL_H
+
+#include "ns3/object.h"
+#include "ns3/nstime.h"
+#include "ns3/component-manager.h"
+#include "ns3/event-id.h"
+#include "ns3/rectangle.h"
+#include "mobility-model.h"
+#include "static-speed-helper.h"
+
+namespace ns3 {
+
+class RandomVariable;
+
+/**
+ * \brief parameters to control a random walk 2d model
+ *
+ * A single parameter object can be shared by multiple random
+ * walk models.
+ */
+class RandomWalk2dMobilityModelParameters : public Object
+{
+ public:
+  /**
+   * Instantiate a set of RandomWalk parameters initialized
+   * with the Bind default values.
+   */
+  RandomWalk2dMobilityModelParameters ();
+  virtual ~RandomWalk2dMobilityModelParameters ();
+  /**
+   * \param speed the random variable used to pick a new
+   *        speed when the direction is changed.
+   *
+   */
+  void SetSpeed (const RandomVariable &speed);
+  /**
+   * \param direction the random variable used to pick a new
+   *        direction.
+   */
+  void SetDirection (const RandomVariable &direction);
+  /**
+   * \param distance the distance before a direction change
+   *
+   * Unit is meters.
+   * "time" mode is incompatible with "distance" mode.
+   */
+  void SetModeDistance (double distance);
+  /**
+   * \param time the delay before a direction change.
+   *
+   * "time" mode is incompatible with "distance" mode.
+   */
+  void SetModeTime (Time time);
+
+  /**
+   * \param bounds the bounds of the random walk
+   */
+  void SetBounds (const Rectangle &bounds);
+
+
+  // needed public for internal default value code.
+  enum Mode  {
+    MODE_DISTANCE,
+    MODE_TIME
+  };
+ private:
+  friend class RandomWalk2dMobilityModel;
+  static Ptr<RandomWalk2dMobilityModelParameters> GetCurrent (void);
+
+  enum Mode m_mode;
+  double m_modeDistance;
+  Time m_modeTime;
+  RandomVariable *m_speed;
+  RandomVariable *m_direction;
+  Rectangle m_bounds;
+};
+
+/**
+ * \brief a 2D random walk position model
+ *
+ * Each instance moves with a speed and direction choosen at random
+ * with the user-provided random variables until
+ * either a fixed distance has been walked or until a fixed amount
+ * of time.
+ *
+ * The parameters of the model can be specified either with the ns3::Bind
+ * function and the variables "RandomWalk2dSpeed", "RandomWalk2dMode", 
+ * "RandomWalk2dDistance", "RandomWalk2dTime", and, "RandomWalk2dBounds" or
+ * with an instance of the RandomWalk2dMobilityModelParameters class which
+ * must be fed to the RandomWalk2dMobilityModel constructors.
+ */
+class RandomWalk2dMobilityModel : public MobilityModel 
+{
+ public:
+  static const ClassId cid;
+  /**
+   * Create a new position object located at position (0,0,0)
+   */
+  RandomWalk2dMobilityModel ();
+  /**
+   * \param parameters the parameters to use to control
+   * the movement of this mobile object.
+   *
+   * Create a new position object located at position (0,0,0) with
+   * the specified parameters.
+   */
+  RandomWalk2dMobilityModel (Ptr<RandomWalk2dMobilityModelParameters> parameters);
+
+ private:
+  void Start (void);
+  void Rebound (Time timeLeft);
+  void DoWalk (Time timeLeft);
+  virtual void DoDispose (void);
+  virtual Position DoGet (void) const;
+  virtual void DoSet (const Position &position);
+  virtual Speed DoGetSpeed (void) const;
+
+  StaticSpeedHelper m_helper;
+  EventId m_event;
+  Ptr<RandomWalk2dMobilityModelParameters> m_parameters;
+};
+
+
+} // namespace ns3
+
+#endif /* RANDOM_WALK_2D_MOBILITY_MODEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/random-waypoint-mobility-model.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,163 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include <cmath>
+#include "ns3/simulator.h"
+#include "ns3/random-variable.h"
+#include "ns3/random-variable-default-value.h"
+#include "ns3/component-manager.h"
+#include "random-waypoint-mobility-model.h"
+#include "random-position.h"
+
+namespace ns3 {
+
+static RandomVariableDefaultValue
+g_speed ("RandomWaypointSpeed",
+	 "A random variable used to pick the speed of a random waypoint model.",
+	 "Uniform:0.3:0.7");
+
+static RandomVariableDefaultValue
+g_pause ("RandomWaypointPause",
+	 "A random variable used to pick the pause of a random waypoint model.",
+	 "Constant:2");
+
+static ClassIdDefaultValue
+g_position ("RandomWaypointPosition",
+	    "A random position model used to pick the next waypoint position.",
+	    RandomPosition::iid,
+	    "RandomRectanglePosition");
+
+const ClassId RandomWaypointMobilityModel::cid = 
+  MakeClassId<RandomWaypointMobilityModel> ("RandomWaypointMobilityModel", MobilityModel::iid);
+
+RandomWaypointMobilityModelParameters::RandomWaypointMobilityModelParameters ()
+  : m_speed (g_speed.GetCopy ()),
+    m_pause (g_pause.GetCopy ())
+{
+  m_position = ComponentManager::Create<RandomPosition> (g_position.GetValue (), 
+							 RandomPosition::iid);
+}
+RandomWaypointMobilityModelParameters::RandomWaypointMobilityModelParameters (Ptr<RandomPosition> randomPosition,
+									      const RandomVariable &speed,
+									      const RandomVariable &pause)
+  : m_speed (speed.Copy ()),
+    m_pause (pause.Copy ()),
+    m_position (randomPosition)
+{}
+void 
+RandomWaypointMobilityModelParameters::SetWaypointPositionModel (Ptr<RandomPosition> randomPosition)
+{
+  m_position = randomPosition;
+}
+void 
+RandomWaypointMobilityModelParameters::SetSpeed (const RandomVariable &speed)
+{
+  delete m_speed;
+  m_speed = speed.Copy ();
+}
+void 
+RandomWaypointMobilityModelParameters::SetPause (const RandomVariable &pause)
+{
+  delete m_pause;
+  m_pause = pause.Copy ();
+}
+void 
+RandomWaypointMobilityModelParameters::DoDispose (void)
+{
+  m_position = 0;
+  delete m_pause;
+  delete m_speed;
+  m_pause = 0;
+  m_speed = 0;  
+}
+
+Ptr<RandomWaypointMobilityModelParameters>
+RandomWaypointMobilityModelParameters::GetCurrent (void)
+{
+  static Ptr<RandomWaypointMobilityModelParameters> parameters = 0;
+  if (parameters == 0 ||
+      g_position.IsDirty () ||
+      g_pause.IsDirty () ||
+      g_speed.IsDirty ())
+    {
+      parameters = Create<RandomWaypointMobilityModelParameters> ();
+    }
+  return parameters;
+}
+
+RandomWaypointMobilityModel::RandomWaypointMobilityModel ()
+  : m_parameters (RandomWaypointMobilityModelParameters::GetCurrent ())
+{
+  Simulator::ScheduleNow (&RandomWaypointMobilityModel::Start, this);
+}
+
+RandomWaypointMobilityModel::RandomWaypointMobilityModel (Ptr<RandomWaypointMobilityModelParameters> parameters)
+  : m_parameters (parameters)
+{
+  Simulator::ScheduleNow (&RandomWaypointMobilityModel::Start, this);
+  NotifyCourseChange ();
+}
+
+void
+RandomWaypointMobilityModel::BeginWalk (void)
+{
+  Position m_current = m_helper.GetCurrentPosition ();
+  Position destination = m_parameters->m_position->Get ();
+  double speed = m_parameters->m_speed->GetValue ();
+  double dx = (destination.x - m_current.x);
+  double dy = (destination.y - m_current.y);
+  double dz = (destination.z - m_current.z);
+  double k = speed / std::sqrt (dx*dx + dy*dy + dz*dz);
+
+  m_helper.Reset (Speed (k*dx, k*dy, k*dz));
+  Time travelDelay = Seconds (CalculateDistance (destination, m_current) / speed);
+  m_event = Simulator::Schedule (travelDelay,
+				 &RandomWaypointMobilityModel::Start, this);
+  NotifyCourseChange ();
+}
+
+void
+RandomWaypointMobilityModel::Start (void)
+{
+  Time pause = Seconds (m_parameters->m_pause->GetValue ());
+  m_helper.Pause ();
+  NotifyCourseChange ();
+  m_event = Simulator::Schedule (pause, &RandomWaypointMobilityModel::BeginWalk, this);
+}
+
+Position 
+RandomWaypointMobilityModel::DoGet (void) const
+{
+  return m_helper.GetCurrentPosition ();
+}
+void 
+RandomWaypointMobilityModel::DoSet (const Position &position)
+{
+  m_helper.InitializePosition (position);
+  Simulator::Remove (m_event);
+  Simulator::ScheduleNow (&RandomWaypointMobilityModel::Start, this);
+}
+Speed 
+RandomWaypointMobilityModel::DoGetSpeed (void) const
+{
+  return m_helper.GetSpeed ();
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mobility/random-waypoint-mobility-model.h	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,112 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef RANDOM_WAYPOINT_MOBILITY_MODEL_H
+#define RANDOM_WAYPOINT_MOBILITY_MODEL_H
+
+#include "static-speed-helper.h"
+#include "mobility-model.h"
+#include "random-position.h"
+#include "ns3/ptr.h"
+
+namespace ns3 {
+
+class RandomVariable;
+
+/**
+ * \brief the parameters which control the behavior of a random waypoint
+ *        mobility model.
+ */
+class RandomWaypointMobilityModelParameters : public Object
+{
+public:
+  /**
+   * Defaults parameters based on the Bind values.
+   */
+  RandomWaypointMobilityModelParameters ();
+  /**
+   * \param randomPosition a random position model to choose the position of waypoints.
+   * \param speed a random variable to choose the speed
+   * \param pause a random variable to choose the pause delay
+   */
+  RandomWaypointMobilityModelParameters (Ptr<RandomPosition> randomPosition,
+                                         const RandomVariable &speed,
+                                         const RandomVariable &pause);
+  /**
+   * \param randomPosition a random position model to choose the position of waypoints.
+   */
+  void SetWaypointPositionModel (Ptr<RandomPosition> randomPosition);
+  /**
+   * \param speed a random variable to choose the speed
+   */
+  void SetSpeed (const RandomVariable &speed);
+  /**
+   * \param pause a random variable to choose the pause delay
+   */
+  void SetPause (const RandomVariable &pause);
+private:
+  friend class RandomWaypointMobilityModel;
+  static Ptr<RandomWaypointMobilityModelParameters> GetCurrent (void);
+  virtual void DoDispose (void);
+  RandomVariable *m_speed;
+  RandomVariable *m_pause;
+  Ptr<RandomPosition> m_position;
+};
+
+/**
+ * \brief a random waypoint mobility model
+ *
+ * Each object chooses a random destination "waypoint", a random speed,
+ * and a random pause time: it then pauses for the specified pause time,
+ * and starts moving towards the specified destination with the specified
+ * speed. Once the destination is reached the process starts again.
+ *
+ * The implementation of this model is not 2d-specific. i.e. if you provide
+ * a 3d random waypoint position model to this mobility model, the model 
+ * will still work.
+ */
+class RandomWaypointMobilityModel : public MobilityModel
+{
+public:
+  static const ClassId cid;
+
+  /**
+   * Create a waypoint mobility model from the Bind default values.
+   */
+  RandomWaypointMobilityModel ();
+  /**
+   * \param parameters the parameters which control the behavior of this model.
+   */
+  RandomWaypointMobilityModel (Ptr<RandomWaypointMobilityModelParameters> parameters);
+private:
+  void Start (void);
+  void BeginWalk (void);
+  virtual Position DoGet (void) const;
+  virtual void DoSet (const Position &position);
+  virtual Speed DoGetSpeed (void) const;
+
+  StaticSpeedHelper m_helper;
+  Ptr<RandomWaypointMobilityModelParameters> m_parameters;
+  EventId m_event;
+};
+
+} // namespace ns3
+
+#endif /* RANDOM_WAYPOINT_MOBILITY_MODEL_H */
--- a/src/mobility/rectangle.cc	Mon Oct 08 11:23:53 2007 +0100
+++ b/src/mobility/rectangle.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -45,17 +45,17 @@
 Rectangle::IsInside (const Position &position) const
 {
   return 
-    position.x <= xMax && position.x >= xMin &&
-    position.y <= yMax && position.y >= yMin;
+    position.x <= this->xMax && position.x >= this->xMin &&
+    position.y <= this->yMax && position.y >= this->yMin;
 }
 
 Rectangle::Side 
 Rectangle::GetClosestSide (const Position &position) const
 {
-  double xMinDist = std::abs (position.x - xMin);
-  double xMaxDist = std::abs (xMax - position.x);
-  double yMinDist = std::abs (position.y - yMin);
-  double yMaxDist = std::abs (yMax - position.y);
+  double xMinDist = std::abs (position.x - this->xMin);
+  double xMaxDist = std::abs (this->xMax - position.x);
+  double yMinDist = std::abs (position.y - this->yMin);
+  double yMaxDist = std::abs (this->yMax - position.y);
   double minX = std::min (xMinDist, xMaxDist);
   double minY = std::min (yMinDist, yMaxDist);
   if (minX < minY)
@@ -85,29 +85,29 @@
 Position
 Rectangle::CalculateIntersection (const Position &current, const Speed &speed) const
 {
-  double xMaxY = current.y + (xMax - current.x) / speed.dx * speed.dy;
-  double xMinY = current.y + (xMin - current.x) / speed.dx * speed.dy;
-  double yMaxX = current.x + (yMax - current.y) / speed.dy * speed.dx;
-  double yMinX = current.x + (yMin - current.y) / speed.dy * speed.dx;
-  bool xMaxOk = xMaxY <= yMax && xMaxY >= yMin;
-  bool xMinOk = xMinY <= yMax && xMinY >= yMin;
-  bool yMaxOk = yMaxX <= xMax && yMaxX >= xMin;
-  bool yMinOk = yMinX <= xMax && yMinX >= xMin;
-  if (xMaxOk && speed.dx >= 0)
+  double xMaxY = current.y + (this->xMax - current.x) / speed.dx * speed.dy;
+  double xMinY = current.y + (this->xMin - current.x) / speed.dx * speed.dy;
+  double yMaxX = current.x + (this->yMax - current.y) / speed.dy * speed.dx;
+  double yMinX = current.x + (this->yMin - current.y) / speed.dy * speed.dx;
+  bool xMaxYOk = (xMaxY <= this->yMax && xMaxY >= this->yMin);
+  bool xMinYOk = (xMinY <= this->yMax && xMinY >= this->yMin);
+  bool yMaxXOk = (yMaxX <= this->xMax && yMaxX >= this->xMin);
+  bool yMinXOk = (yMinX <= this->xMax && yMinX >= this->xMin);
+  if (xMaxYOk && speed.dx >= 0)
     {
-      return Position (xMax, xMaxY, 0.0);
+      return Position (this->xMax, xMaxY, 0.0);
     }
-  else if (xMinOk && speed.dx <= 0)
+  else if (xMinYOk && speed.dx <= 0)
     {
-      return Position (xMin, xMinY, 0.0);
+      return Position (this->xMin, xMinY, 0.0);
     }
-  else if (yMaxOk && speed.dy >= 0)
+  else if (yMaxXOk && speed.dy >= 0)
     {
-      return Position (yMaxX, yMax, 0.0);
+      return Position (yMaxX, this->yMax, 0.0);
     }
-  else if (yMinOk && speed.dy <= 0)
+  else if (yMinXOk && speed.dy <= 0)
     {
-      return Position (yMinX, yMin, 0.0);
+      return Position (yMinX, this->yMin, 0.0);
     }
   else
     {
--- a/src/mobility/static-speed-helper.cc	Mon Oct 08 11:23:53 2007 +0100
+++ b/src/mobility/static-speed-helper.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -31,7 +31,8 @@
 StaticSpeedHelper::StaticSpeedHelper (const Position &position,
 				      const Speed &speed)
   : m_position (position),
-    m_speed (speed)
+    m_speed (speed),
+    m_paused (true)
 {}
 void 
 StaticSpeedHelper::InitializePosition (const Position &position)
@@ -41,14 +42,7 @@
   m_speed.dy = 0.0;
   m_speed.dz = 0.0;
   m_lastUpdate = Simulator::Now ();
-  m_pauseEnd = Simulator::Now ();
-}
-
-void
-StaticSpeedHelper::Reset (const Speed &speed, const Time &pauseDelay)
-{
-  Reset (speed);
-  m_pauseEnd = Simulator::Now () + pauseDelay;
+  m_paused = true;
 }
 
 Position 
@@ -61,7 +55,7 @@
 Speed 
 StaticSpeedHelper::GetSpeed (void) const
 {
-  return m_speed;
+  return m_paused? Speed (0, 0, 0) : m_speed;
 }
 void 
 StaticSpeedHelper::SetSpeed (const Speed &speed)
@@ -73,17 +67,13 @@
 void
 StaticSpeedHelper::Update (void) const
 {
-  Time now = Simulator::Now ();
-  if (m_pauseEnd > now)
+  if (m_paused)
     {
       return;
     }
-  Time last = std::max (now, m_pauseEnd);
-  if (m_lastUpdate >= last)
-    {
-      return;
-    }
-  Time deltaTime = now - last;
+  Time now = Simulator::Now ();
+  NS_ASSERT (m_lastUpdate <= now);
+  Time deltaTime = now - m_lastUpdate;
   m_lastUpdate = now;
   double deltaS = deltaTime.GetSeconds ();
   m_position.x += m_speed.dx * deltaS;
@@ -96,7 +86,7 @@
 {
   Update ();
   m_speed = speed;
-  m_pauseEnd = Simulator::Now ();
+  Unpause ();
 }
 void
 StaticSpeedHelper::UpdateFull (const Rectangle &bounds) const
@@ -115,5 +105,21 @@
   return m_position;
 }
 
+void 
+StaticSpeedHelper::Pause (void)
+{
+  Update ();
+  m_paused = true;
+}
+
+void 
+StaticSpeedHelper::Unpause (void)
+{
+  if (m_paused)
+    {
+      m_lastUpdate = Simulator::Now ();
+      m_paused = false;
+    }
+}
 
 } // namespace ns3
--- a/src/mobility/static-speed-helper.h	Mon Oct 08 11:23:53 2007 +0100
+++ b/src/mobility/static-speed-helper.h	Mon Oct 08 11:24:16 2007 +0100
@@ -37,12 +37,13 @@
 		     const Speed &speed);
   void InitializePosition (const Position &position);
 
-  void Reset (const Speed &speed, const Time &pauseDelay);
   void Reset (const Speed &speed);
   Position GetCurrentPosition (const Rectangle &bounds) const;
   Position GetCurrentPosition (void) const;
   Speed GetSpeed (void) const;
   void SetSpeed (const Speed &speed);
+  void Pause (void);
+  void Unpause (void);
 
  private:
   void Update (void) const;
@@ -50,7 +51,7 @@
   mutable Time m_lastUpdate;
   mutable Position m_position;
   Speed m_speed;
-  Time m_pauseEnd;
+  bool m_paused;
 };
 
 } // namespace ns3
--- a/src/mobility/wscript	Mon Oct 08 11:23:53 2007 +0100
+++ b/src/mobility/wscript	Mon Oct 08 11:24:16 2007 +0100
@@ -16,6 +16,10 @@
         'static-mobility-model.cc',
         'static-speed-helper.cc',
         'static-speed-mobility-model.cc',
+        'random-waypoint-mobility-model.cc',
+        'random-walk-2d-mobility-model.cc',
+        'random-direction-2d-mobility-model.cc',
+        'ns2-mobility-file-topology.cc',
         ]
 
     headers = bld.create_obj('ns3header')
@@ -33,4 +37,8 @@
         'static-mobility-model.h',
         'static-speed-helper.h',
         'static-speed-mobility-model.h',
+        'random-waypoint-mobility-model.h',
+        'random-walk-2d-mobility-model.h',
+        'random-direction-2d-mobility-model.h',
+        'ns2-mobility-file-topology.h',
         ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/event-garbage-collector.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,152 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INESC Porto
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Gustavo J. A. M. Carneiro  <gjc@inescporto.pt>
+ */
+#include "event-garbage-collector.h"
+
+#define CLEANUP_CHUNK_MIN_SIZE 8
+#define CLEANUP_CHUNK_MAX_SIZE 128
+
+
+namespace ns3 {
+
+
+EventGarbageCollector::EventGarbageCollector () :
+  m_nextCleanupSize (CLEANUP_CHUNK_MIN_SIZE)
+{}
+
+void
+EventGarbageCollector::Track (EventId event)
+{
+  m_events.push_back (event);
+  if (m_events.size () >= m_nextCleanupSize)
+    Cleanup ();
+}
+
+inline bool
+EventExpiredPredicate (const EventId &event)
+{
+  return event.IsExpired ();
+}
+
+void
+EventGarbageCollector::Grow ()
+{
+  m_nextCleanupSize += (m_nextCleanupSize < CLEANUP_CHUNK_MAX_SIZE?
+                        m_nextCleanupSize : CLEANUP_CHUNK_MAX_SIZE);
+}
+
+void
+EventGarbageCollector::Shrink ()
+{
+  while (m_nextCleanupSize > m_events.size ())
+    m_nextCleanupSize >>= 1;
+  Grow ();
+}
+
+// Called when a new event was added and the cleanup limit was exceeded in consequence.
+void
+EventGarbageCollector::Cleanup ()
+{
+  m_events.remove_if (EventExpiredPredicate);
+
+  // If after cleanup we are still over the limit, increase the limit.
+  if (m_events.size () >= m_nextCleanupSize)
+    Grow ();
+  else
+    Shrink ();
+}
+
+
+EventGarbageCollector::~EventGarbageCollector ()
+{
+  for (std::list<EventId>::iterator event = m_events.begin ();
+       event != m_events.end (); event++)
+    {
+      Simulator::Cancel (*event);
+    }
+}
+
+}; // namespace ns3
+
+
+
+#ifdef RUN_SELF_TESTS
+
+#include "ns3/test.h"
+
+namespace ns3 {
+
+class EventGarbageCollectorTests : public Test
+{
+  int m_counter;
+  EventGarbageCollector *m_events;
+
+  void EventGarbageCollectorCallback ();
+
+public:
+
+  EventGarbageCollectorTests ();
+  virtual ~EventGarbageCollectorTests ();
+  virtual bool RunTests (void);
+};
+
+EventGarbageCollectorTests::EventGarbageCollectorTests ()
+  : Test ("EventGarbageCollector"), m_counter (0), m_events (0)
+{}
+
+EventGarbageCollectorTests::~EventGarbageCollectorTests ()
+{}
+
+void
+EventGarbageCollectorTests::EventGarbageCollectorCallback ()
+{
+  m_counter++;
+  if (m_counter == 50)
+    {
+      // this should cause the remaining (50) events to be cancelled
+      delete m_events;
+      m_events = 0;
+    }
+}
+
+bool EventGarbageCollectorTests::RunTests (void)
+{
+  bool result = true;
+
+  m_events = new EventGarbageCollector ();
+
+  for (int n = 0; n < 100; n++)
+    {
+      m_events->Track (Simulator::Schedule
+                       (Simulator::Now (),
+                        &EventGarbageCollectorTests::EventGarbageCollectorCallback,
+                        this));
+    }
+  Simulator::Run ();
+  NS_TEST_ASSERT_EQUAL (m_events, 0);
+  NS_TEST_ASSERT_EQUAL (m_counter, 50);
+  return result;
+}
+
+static EventGarbageCollectorTests g_eventCollectorTests;
+    
+};
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/event-garbage-collector.h	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,62 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INESC Porto
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Gustavo J. A. M. Carneiro  <gjc@inescporto.pt>
+ */
+#ifndef EVENT_GARBAGE_COLLECTOR_H
+#define EVENT_GARBAGE_COLLECTOR_H
+
+#include <list>
+#include "event-id.h"
+#include "simulator.h"
+
+namespace ns3 {
+
+/**
+ * \brief An object that tracks scheduled events and automatically
+ * cancels them when it is destroyed.  It is useful in situations
+ * where multiple instances of the same type of event can
+ * simultaneously be scheduled, and when the events should be limited
+ * to the lifetime of a container object.
+ */
+class EventGarbageCollector
+{
+public:
+
+  EventGarbageCollector ();
+
+  /**
+   * \brief Tracks a new event
+   */
+  void Track (EventId event);
+
+  ~EventGarbageCollector ();
+
+private:
+
+  std::list<EventId>::size_type m_nextCleanupSize;
+  std::list<EventId> m_events;
+
+  void Cleanup ();
+  void Grow ();
+  void Shrink ();
+};
+
+}; // namespace ns3
+
+#endif /* EVENT_GARBAGE_COLLECTOR_H */
--- a/src/simulator/simulator.cc	Mon Oct 08 11:23:53 2007 +0100
+++ b/src/simulator/simulator.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -67,9 +67,10 @@
   EventId ScheduleDestroy (const Ptr<EventImpl> &event);
   void Remove (const EventId &ev);
   void Cancel (const EventId &ev);
-  bool IsExpired (const EventId &ev);
+  bool IsExpired (const EventId &ev) const;
   void Run (void);
   Time Now (void) const;
+  Time GetDelayLeft (const EventId &id) const;
 
 private:
   void ProcessOneEvent (void);
@@ -251,6 +252,18 @@
 {
   return TimeStep (m_currentTs);
 }
+Time 
+SimulatorPrivate::GetDelayLeft (const EventId &id) const
+{
+  if (IsExpired (id))
+    {
+      return TimeStep (0);
+    }
+  else
+    {
+      return TimeStep (id.GetTs () - m_currentTs);
+    }
+}
 
 void
 SimulatorPrivate::Remove (const EventId &ev)
@@ -293,12 +306,12 @@
 }
 
 bool
-SimulatorPrivate::IsExpired (const EventId &ev)
+SimulatorPrivate::IsExpired (const EventId &ev) const
 {
   if (ev.GetUid () == 2)
     {
       // destroy events.
-      for (DestroyEvents::iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
+      for (DestroyEvents::const_iterator i = m_destroyEvents.begin (); i != m_destroyEvents.end (); i++)
         {
           if (*i == ev)
             {
@@ -411,6 +424,11 @@
 {
   return GetPriv ()->Now ();
 }
+Time
+Simulator::GetDelayLeft (const EventId &id)
+{
+  return GetPriv ()->GetDelayLeft (id);
+}
 
 Ptr<EventImpl>
 Simulator::MakeEvent (void (*f) (void))
--- a/src/simulator/simulator.h	Mon Oct 08 11:23:53 2007 +0100
+++ b/src/simulator/simulator.h	Mon Oct 08 11:24:16 2007 +0100
@@ -552,6 +552,13 @@
    * Return the "current simulation time".
    */
   static Time Now (void);
+  /**
+   * \param id the event id to analyse
+   * \returns the delay left until the input event id expires.
+   *          if the event is not running, this method returns
+   *          zero.
+   */
+  static Time GetDelayLeft (const EventId &id);
 private:
   Simulator ();
   ~Simulator ();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/timer.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,325 @@
+#include "timer.h"
+#include "simulator.h"
+#include "simulation-singleton.h"
+#include "event-garbage-collector.h"
+
+namespace ns3 {
+
+Timer::Timer ()
+  : m_flags (0),
+    m_delay (FemtoSeconds (0)),
+    m_event (),
+    m_impl (0)
+{}
+
+Timer::Timer (enum SchedulePolicy schedulePolicy, 
+	      enum DestroyPolicy destroyPolicy)
+  : m_flags (schedulePolicy | destroyPolicy),
+    m_delay (FemtoSeconds (0)),
+    m_event (),
+    m_impl (0)
+{}
+
+Timer::Timer (enum GarbageCollectPolicy policy)
+  : m_flags (GARBAGE_COLLECT),
+    m_delay (FemtoSeconds (0)),
+    m_event (),
+    m_impl (0)
+{}
+
+Timer::~Timer ()
+{
+  if (m_flags & CHECK_ON_DESTROY)
+    {
+      if (m_event.IsRunning ())
+	{
+	  NS_FATAL_ERROR ("Event is still running while destroying.");
+	}
+    }
+  else if (m_flags & CANCEL_ON_DESTROY)
+    {
+      m_event.Cancel ();
+    }
+  else if (m_flags & REMOVE_ON_DESTROY)
+    {
+      Simulator::Remove (m_event);
+    }
+  delete m_impl;
+}
+
+void 
+Timer::SetDelay (const Time &time)
+{
+  m_delay = time;
+}
+Time 
+Timer::GetDelay (void) const
+{
+  return m_delay;
+}
+Time
+Timer::GetDelayLeft (void) const
+{
+  switch (GetState ()) {
+  case Timer::RUNNING:
+    return Simulator::GetDelayLeft (m_event);
+    break;
+  case Timer::EXPIRED:
+    return TimeStep (0);
+    break;
+  case Timer::SUSPENDED:
+    return m_delayLeft;
+    break;
+  default:
+    NS_ASSERT (false);
+    return TimeStep (0);
+    break;
+  }
+}
+
+void 
+Timer::Cancel (void)
+{
+  Simulator::Cancel (m_event);
+}
+void 
+Timer::Remove (void)
+{
+  Simulator::Remove (m_event);
+}
+bool 
+Timer::IsExpired (void) const
+{
+  return !IsSuspended () && m_event.IsExpired ();
+}
+bool 
+Timer::IsRunning (void) const
+{
+  return !IsSuspended () && m_event.IsRunning ();
+}
+bool
+Timer::IsSuspended (void) const
+{
+  return (m_flags & TIMER_SUSPENDED) == TIMER_SUSPENDED;
+}
+enum Timer::State 
+Timer::GetState (void) const
+{
+  if (IsRunning ())
+    {
+      return Timer::RUNNING;
+    }
+  else if (IsExpired ())
+    {
+      return Timer::EXPIRED;
+    }
+  else 
+    {
+      NS_ASSERT (IsSuspended ());
+      return Timer::SUSPENDED;
+    }
+}
+
+void 
+Timer::Schedule (void)
+{
+  Schedule (m_delay);
+}
+
+void 
+Timer::Schedule (Time delay)
+{
+  NS_ASSERT (m_impl != 0);
+  if (m_flags & CHECK_ON_SCHEDULE)
+    {
+      if (m_event.IsRunning ())
+	{
+	  NS_FATAL_ERROR ("Event is still running while re-scheduling.");
+	}
+    }
+  else if (m_flags & CANCEL_ON_SCHEDULE)
+    {
+      m_event.Cancel ();
+    }
+  else if (m_flags & REMOVE_ON_SCHEDULE)
+    {
+      Simulator::Remove (m_event);
+    }
+  m_event = m_impl->Schedule (delay);
+  if (m_flags & GARBAGE_COLLECT)
+    {
+      SimulationSingleton<EventGarbageCollector>::Get ()->Track (m_event);
+    }
+}
+
+void
+Timer::Suspend (void)
+{
+  NS_ASSERT (IsRunning ());
+  m_delayLeft = Simulator::GetDelayLeft (m_event);
+  Simulator::Remove (m_event);
+  m_flags |= TIMER_SUSPENDED;
+}
+
+void
+Timer::Resume (void)
+{
+  NS_ASSERT (m_flags & TIMER_SUSPENDED);
+  m_event = m_impl->Schedule (m_delayLeft);
+  m_flags &= ~TIMER_SUSPENDED;
+}
+
+
+} // namespace ns3
+
+
+#ifdef RUN_SELF_TESTS
+#include "ns3/test.h"
+
+namespace {
+void bari (int)
+{}
+void bar2i (int, int)
+{}
+void bar3i (int, int, int)
+{}
+void bar4i (int, int, int, int)
+{}
+void bar5i (int, int, int, int, int)
+{}
+void bar6i (int, int, int, int, int, int)
+{}
+void barcir (const int &)
+{}
+void barir (int &)
+{}
+void barip (int *)
+{}
+void barcip (const int *)
+{}
+}
+
+namespace ns3 {
+
+class TimerTests : public Test
+{
+public:
+  TimerTests ();
+  virtual bool RunTests (void);
+  void bazi (int) {}
+  void baz2i (int, int) {}
+  void baz3i (int, int, int) {}
+  void baz4i (int, int, int, int) {}
+  void baz5i (int, int, int, int, int) {}
+  void baz6i (int, int, int, int, int, int) {}
+  void bazcir (const int&) {}
+  void bazir (int&) {}
+  void bazip (int *) {}
+  void bazcip (const int *) {}
+};
+
+TimerTests::TimerTests ()
+  : Test ("Timer")
+{}
+
+bool
+TimerTests::RunTests (void)
+{
+  bool result = true;
+
+  Timer timer;
+
+  timer.SetFunction (&bari);
+  timer.SetArguments (1);
+  timer.SetDelay (Seconds (10.0));
+  NS_TEST_ASSERT (!timer.IsRunning ());
+  NS_TEST_ASSERT (timer.IsExpired ());
+  NS_TEST_ASSERT (!timer.IsSuspended ());
+  NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::EXPIRED);
+  timer.Schedule ();
+  NS_TEST_ASSERT (timer.IsRunning ());
+  NS_TEST_ASSERT (!timer.IsExpired ());
+  NS_TEST_ASSERT (!timer.IsSuspended ());
+  NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::RUNNING);
+  timer.Suspend ();
+  NS_TEST_ASSERT (!timer.IsRunning ());
+  NS_TEST_ASSERT (!timer.IsExpired ());
+  NS_TEST_ASSERT (timer.IsSuspended ());
+  NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::SUSPENDED);
+  timer.Resume ();
+  NS_TEST_ASSERT (timer.IsRunning ());
+  NS_TEST_ASSERT (!timer.IsExpired ());
+  NS_TEST_ASSERT (!timer.IsSuspended ());
+  NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::RUNNING);
+  timer.Cancel ();
+  NS_TEST_ASSERT (!timer.IsRunning ());
+  NS_TEST_ASSERT (timer.IsExpired ());
+  NS_TEST_ASSERT (!timer.IsSuspended ());
+  NS_TEST_ASSERT_EQUAL (timer.GetState (), Timer::EXPIRED);
+
+  int a = 0;
+  int &b = a;
+  const int &c = a;
+
+  timer.SetFunction (&bari);
+  timer.SetArguments (2);
+  timer.SetArguments (a);
+  timer.SetArguments (b);
+  timer.SetArguments (c);
+  timer.SetFunction (&barir);
+  timer.SetArguments (2);
+  timer.SetArguments (a);
+  timer.SetArguments (b);
+  timer.SetArguments (c);
+  timer.SetFunction (&barcir);
+  timer.SetArguments (2);
+  timer.SetArguments (a);
+  timer.SetArguments (b);
+  timer.SetArguments (c);
+  // the following call cannot possibly work and is flagged by
+  // a runtime error.
+  //timer.SetArguments (0.0);
+  timer.SetDelay (Seconds (1.0));
+  timer.Schedule ();
+
+  timer.SetFunction (&TimerTests::bazi, this);
+  timer.SetArguments (3);
+  timer.SetFunction (&TimerTests::bazir, this);
+  timer.SetArguments (3);
+  timer.SetFunction (&TimerTests::bazcir, this);
+  timer.SetArguments (3);
+
+  timer.SetFunction (&bar2i);
+  timer.SetArguments (1, 1);
+  timer.SetFunction (&bar3i);
+  timer.SetArguments (1, 1, 1);
+  timer.SetFunction (&bar4i);
+  timer.SetArguments (1, 1, 1, 1);
+  timer.SetFunction (&bar5i);
+  timer.SetArguments (1, 1, 1, 1, 1);
+  //timer.SetFunction (&bar6i);
+  //timer.SetArguments (1, 1, 1, 1, 1, 1);
+
+  timer.SetFunction (&TimerTests::baz2i, this);
+  timer.SetArguments (1, 1);
+  timer.SetFunction (&TimerTests::baz3i, this);
+  timer.SetArguments (1, 1, 1);
+  timer.SetFunction (&TimerTests::baz4i, this);
+  timer.SetArguments (1, 1, 1, 1);
+  timer.SetFunction (&TimerTests::baz5i, this);
+  timer.SetArguments (1, 1, 1, 1, 1);
+  //timer.SetFunction (&TimerTests::baz6i, this);
+  //timer.SetArguments (1, 1, 1, 1, 1, 1);
+
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+		  
+  return result;
+}
+
+TimerTests g_tests;
+
+} // namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simulator/timer.h	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,991 @@
+#ifndef TIMER_H
+#define TIMER_H
+
+#include "ns3/fatal-error.h"
+#include "nstime.h"
+#include "event-id.h"
+#include "ns3/int-to-type.h"
+
+namespace ns3 {
+
+class TimerImpl;
+
+/**
+ * \brief a simple Timer class
+ *
+ * A timer is used to hold together a delay, a function to invoke
+ * when the delay expires, and a set of arguments to pass to the function
+ * when the delay expires.
+ *
+ * A timer can also be used to enforce a set of predefined event lifetime
+ * management policies. These policies are specified at construction time
+ * and cannot be changed after.
+ */
+class Timer 
+{
+public:
+  enum SchedulePolicy {
+    /**
+     * This policy cancels the event before scheduling a new event 
+     * for each call to Timer::Schedule.
+     */
+    CANCEL_ON_SCHEDULE = (1<<0),
+    /**
+     * This policy removes the event from the simulation event list 
+     * before scheduling a new event for each call to Timer::Schedule. 
+     */
+    REMOVE_ON_SCHEDULE = (1<<1),
+    /**
+     * This policy enforces a check before each call to Timer::Schedule
+     * to verify that the timer has already expired.
+     */
+    CHECK_ON_SCHEDULE = (1<<2),
+  };
+  enum DestroyPolicy {
+    /**
+     * This policy cancels the event from the destructor of the Timer
+     * to verify that the event has already expired.
+     */
+    CANCEL_ON_DESTROY = (1<<3),
+    /**
+     * This policy removes the event from the simulation event list
+     * when the destructor of the Timer is invoked.
+     */
+    REMOVE_ON_DESTROY = (1<<4),
+    /**
+     * This policy enforces a check from the destructor of the Timer
+     * to verify that the timer has already expired.
+     */
+    CHECK_ON_DESTROY = (1<<5)
+  };
+  enum GarbageCollectPolicy {
+    /**
+     * Every event scheduled with this policy is kept track of by an
+     * event garbage collector which makes sure that all events
+     * of timers with a GARBAGE_COLLECT policy are cancelled at the
+     * end of the simulation.
+     */
+    GARBAGE_COLLECT = (1<<6)
+  };
+  enum State {
+    RUNNING,
+    EXPIRED,
+    SUSPENDED,
+  };
+  /**
+   * create a timer with a default event lifetime management policy:
+   *  - CHECK_ON_SCHEDULE
+   *  - CHECK_ON_DESTROY
+   */
+  Timer ();
+  /**
+   * \param scheduleFlags the event lifetime management policies to use for schedule events
+   * \param destroyFlags the event lifetime management policies to use for destroy events
+   */
+  Timer (enum SchedulePolicy schedulePolicy, 
+	 enum DestroyPolicy destroyPolicy);
+  /**
+   * \param policy the garbage collect policy. Only one
+   *        value is possible.
+   */
+  Timer (enum GarbageCollectPolicy policy);
+  ~Timer ();
+
+  /**
+   * \param fn the function
+   *
+   * Store this function in this Timer for later use by Timer::Schedule.
+   */
+  template <typename FN>
+  void SetFunction (FN fn);
+
+  /**
+   * \param memPtr the member function pointer
+   * \param objPtr the pointer to object
+   *
+   * Store this function and object in this Timer for later use by Timer::Schedule.
+   */
+  template <typename MEM_PTR, typename OBJ_PTR>
+  void SetFunction (MEM_PTR memPtr, OBJ_PTR objPtr);
+
+
+  /**
+   * \param a1 the first argument
+   *
+   * Store this argument in this Timer for later use by Timer::Schedule.
+   */
+  template <typename T1>
+  void SetArguments (T1 a1);
+  /**
+   * \param a1 the first argument
+   * \param a2 the second argument
+   *
+   * Store these arguments in this Timer for later use by Timer::Schedule.
+   */
+  template <typename T1, typename T2>
+  void SetArguments (T1 a1, T2 a2);
+  /**
+   * \param a1 the first argument
+   * \param a2 the second argument
+   * \param a3 the third argument
+   *
+   * Store these arguments in this Timer for later use by Timer::Schedule.
+   */
+  template <typename T1, typename T2, typename T3>
+  void SetArguments (T1 a1, T2 a2, T3 a3);
+  /**
+   * \param a1 the first argument
+   * \param a2 the second argument
+   * \param a3 the third argument
+   * \param a4 the fourth argument
+   *
+   * Store these arguments in this Timer for later use by Timer::Schedule.
+   */
+  template <typename T1, typename T2, typename T3, typename T4>
+  void SetArguments (T1 a1, T2 a2, T3 a3, T4 a4);
+  /**
+   * \param a1 the first argument
+   * \param a2 the second argument
+   * \param a3 the third argument
+   * \param a4 the fourth argument
+   * \param a5 the fifth argument
+   *
+   * Store these arguments in this Timer for later use by Timer::Schedule.
+   */
+  template <typename T1, typename T2, typename T3, typename T4, typename T5>
+  void SetArguments (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  /**
+   * \param a1 the first argument
+   * \param a2 the second argument
+   * \param a3 the third argument
+   * \param a4 the fourth argument
+   * \param a5 the fifth argument
+   * \param a6 the sixth argument
+   *
+   * Store these arguments in this Timer for later use by Timer::Schedule.
+   */
+  template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+  void SetArguments (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6);
+
+  /**
+   * \param delay the delay
+   *
+   * The next call to Schedule will schedule the timer with this delay.
+   */
+  void SetDelay (const Time &delay);
+  /**
+   * \returns the currently-configured delay for the next Schedule.
+   */
+  Time GetDelay (void) const;
+  /**
+   * \returns the amount of time left until this timer expires.
+   *
+   * This method returns zero if the timer is in EXPIRED state.
+   */
+  Time GetDelayLeft (void) const;
+  /**
+   * Cancel the currently-running event if there is one. Do nothing
+   * otherwise.
+   */
+  void Cancel (void);
+  /**
+   * Remove from the simulation event-list the currently-running event 
+   * if there is one. Do nothing otherwise.
+   */
+  void Remove (void);
+  /**
+   * \return true if there is no currently-running event, false otherwise.
+   */
+  bool IsExpired (void) const;
+  /**
+   * \return true if there is a currently-running event, false otherwise.
+   */
+  bool IsRunning (void) const;
+  /**
+   * \returns true if this timer was suspended and not yet resumed, false
+   *          otherwise.
+   */
+  bool IsSuspended (void) const;
+  /**
+   * \returns the current state of the timer.
+   */
+  enum Timer::State GetState (void) const;
+  /**
+   * Schedule a new event using the currently-configured delay, function, 
+   * and arguments.
+   */
+  void Schedule (void);
+  /**
+   * \param delay the delay to use
+   *
+   * Schedule a new event using the specified delay (ignore the delay set by 
+   * Timer::SetDelay), function, and arguments.
+   */
+  void Schedule (Time delay);
+
+  /**
+   * Cancel the timer and save the amount of time left until it was
+   * set to expire.
+   * Calling Suspend on a non-running timer is an error.
+   */
+  void Suspend (void);
+  /**
+   * Restart the timer to expire within the amount of time left saved
+   * during Suspend.
+   * Calling Resume without a prior call to Suspend is an error.
+   */
+  void Resume (void);
+
+private:
+  template <typename FN>
+  void DoSetFunction (IntToType<0>, FN fn);
+  template <typename FN>
+  void DoSetFunction (IntToType<1>, FN fn);
+  template <typename FN>
+  void DoSetFunction (IntToType<2>, FN fn);
+  template <typename FN>
+  void DoSetFunction (IntToType<3>, FN fn);
+  template <typename FN>
+  void DoSetFunction (IntToType<4>, FN fn);
+  template <typename FN>
+  void DoSetFunction (IntToType<5>, FN fn);
+  template <typename FN>
+  void DoSetFunction (IntToType<6>, FN fn);
+
+  template <typename MEM_PTR, typename OBJ_PTR>
+  void DoSetFunction (IntToType<0>, MEM_PTR memPtr, OBJ_PTR objPtr);
+  template <typename MEM_PTR, typename OBJ_PTR>
+  void DoSetFunction (IntToType<1>, MEM_PTR memPtr, OBJ_PTR objPtr);
+  template <typename MEM_PTR, typename OBJ_PTR>
+  void DoSetFunction (IntToType<2>, MEM_PTR memPtr, OBJ_PTR objPtr);
+  template <typename MEM_PTR, typename OBJ_PTR>
+  void DoSetFunction (IntToType<3>, MEM_PTR memPtr, OBJ_PTR objPtr);
+  template <typename MEM_PTR, typename OBJ_PTR>
+  void DoSetFunction (IntToType<4>, MEM_PTR memPtr, OBJ_PTR objPtr);
+  template <typename MEM_PTR, typename OBJ_PTR>
+  void DoSetFunction (IntToType<5>, MEM_PTR memPtr, OBJ_PTR objPtr);
+  template <typename MEM_PTR, typename OBJ_PTR>
+  void DoSetFunction (IntToType<6>, MEM_PTR memPtr, OBJ_PTR objPtr);
+
+  enum {
+    TIMER_SUSPENDED = (1<<7)
+  };
+
+  int m_flags;
+  Time m_delay;
+  EventId m_event;
+  TimerImpl *m_impl;
+  Time m_delayLeft;
+};
+
+} // namespace ns3
+
+
+// The actual implementation.
+#include "simulator.h"
+#include "ns3/type-traits.h"
+
+namespace ns3 {
+
+
+template <typename T>
+struct TimerTraits
+{
+  typedef typename TypeTraits<typename TypeTraits<T>::ReferencedType>::NonConstType StoredType;
+  typedef const StoredType &ParameterType;
+};
+
+class TimerImpl
+{
+public:
+  virtual ~TimerImpl () {}
+  virtual EventId Schedule (const Time &delay) = 0;
+};
+
+
+template <typename T1>
+struct TimerImplOne : public TimerImpl
+{
+  virtual void SetArguments (T1 a1) = 0;
+};
+template <typename T1, typename T2>
+struct TimerImplTwo : public TimerImpl
+{
+  virtual void SetArguments (T1 a1,T2 a2) = 0;
+};
+template <typename T1, typename T2, typename T3>
+struct TimerImplThree : public TimerImpl
+{
+  virtual void SetArguments (T1 a1,T2 a2,T3 a3) = 0;
+};
+template <typename T1, typename T2, typename  T3, typename T4>
+struct TimerImplFour : public TimerImpl
+{
+  virtual void SetArguments (T1 a1,T2 a2,T3 a3, T4 a4) = 0;
+};
+template <typename T1, typename T2, typename  T3, typename T4, typename T5>
+struct TimerImplFive : public TimerImpl
+{
+  virtual void SetArguments (T1 a1,T2 a2,T3 a3, T4 a4, T5 a5) = 0;
+};
+template <typename T1, typename T2, typename  T3, typename T4, typename T5, typename T6>
+struct TimerImplSix : public TimerImpl
+{
+  virtual void SetArguments (T1 a1,T2 a2,T3 a3, T4 a4, T5 a5, T6 a6) = 0;
+};
+
+
+template <typename FN>
+void 
+Timer::SetFunction (FN fn)
+{
+  NS_ASSERT (TypeTraits<FN>::IsFunctionPointer);
+  DoSetFunction (IntToType<TypeTraits<FN>::FunctionPointerTraits::nArgs> (), fn);
+}
+
+template <typename FN>
+void 
+Timer::DoSetFunction (IntToType<0>, FN fn)
+{
+  struct FnTimerImplZero : public TimerImpl
+  {
+    FnTimerImplZero (FN fn) 
+      : m_fn (fn) {}
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_fn);
+    }
+    FN m_fn;
+  } *function = new FnTimerImplZero (fn);
+  delete m_impl;
+  m_impl = function;
+}
+
+template <typename FN>
+void 
+Timer::DoSetFunction (IntToType<1>, FN fn)
+{
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+
+  struct FnTimerImplOne : public TimerImplOne<T1Parameter>
+  {
+    FnTimerImplOne (FN fn) 
+      : m_fn (fn) {}
+    virtual void SetArguments (T1Parameter a1) {
+      m_a1 = a1;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_fn, m_a1);
+    }
+    FN m_fn;
+    T1Stored m_a1;
+  } *function = new FnTimerImplOne (fn);
+  delete m_impl;
+  m_impl = function;  
+}
+
+template <typename FN>
+void 
+Timer::DoSetFunction (IntToType<2>, FN fn)
+{
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+
+  struct FnTimerImplTwo : public TimerImplTwo<T1Parameter,T2Parameter>
+  {
+    FnTimerImplTwo (FN fn) 
+      : m_fn (fn) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2) {
+      m_a1 = a1;
+      m_a2 = a2;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_fn, m_a1, m_a2);
+    }
+    FN m_fn;
+    T1Stored m_a1;
+    T2Stored m_a2;
+  } *function = new FnTimerImplTwo (fn);
+  delete m_impl;
+  m_impl = function;  
+}
+
+template <typename FN>
+void 
+Timer::DoSetFunction (IntToType<3>, FN fn)
+{
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg3Type T3;
+  typedef typename TimerTraits<T3>::ParameterType T3Parameter;
+  typedef typename TimerTraits<T3>::StoredType T3Stored;
+
+  struct FnTimerImplThree : public TimerImplThree<T1Parameter,T2Parameter,T3Parameter>
+  {
+    FnTimerImplThree (FN fn) 
+      : m_fn (fn) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3) {
+      m_a1 = a1;
+      m_a2 = a2;
+      m_a3 = a3;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_fn, m_a1, m_a2, m_a3);
+    }
+    FN m_fn;
+    T1Stored m_a1;
+    T2Stored m_a2;
+    T3Stored m_a3;
+  } *function = new FnTimerImplThree (fn);
+  delete m_impl;
+  m_impl = function;  
+}
+
+template <typename FN>
+void 
+Timer::DoSetFunction (IntToType<4>, FN fn)
+{
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg3Type T3;
+  typedef typename TimerTraits<T3>::ParameterType T3Parameter;
+  typedef typename TimerTraits<T3>::StoredType T3Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg4Type T4;
+  typedef typename TimerTraits<T4>::ParameterType T4Parameter;
+  typedef typename TimerTraits<T4>::StoredType T4Stored;
+
+  struct FnTimerImplFour : public TimerImplFour<T1Parameter,T2Parameter,T3Parameter,T4Parameter>
+  {
+    FnTimerImplFour (FN fn) 
+      : m_fn (fn) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4) {
+      m_a1 = a1;
+      m_a2 = a2;
+      m_a3 = a3;
+      m_a4 = a4;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_fn, m_a1, m_a2, m_a3, m_a4);
+    }
+    FN m_fn;
+    T1Stored m_a1;
+    T2Stored m_a2;
+    T3Stored m_a3;
+    T4Stored m_a4;
+  } *function = new FnTimerImplFour (fn);
+  delete m_impl;
+  m_impl = function;  
+}
+
+template <typename FN>
+void 
+Timer::DoSetFunction (IntToType<5>, FN fn)
+{
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg3Type T3;
+  typedef typename TimerTraits<T3>::ParameterType T3Parameter;
+  typedef typename TimerTraits<T3>::StoredType T3Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg4Type T4;
+  typedef typename TimerTraits<T4>::ParameterType T4Parameter;
+  typedef typename TimerTraits<T4>::StoredType T4Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg5Type T5;
+  typedef typename TimerTraits<T5>::ParameterType T5Parameter;
+  typedef typename TimerTraits<T5>::StoredType T5Stored;
+
+  struct FnTimerImplFive : public TimerImplFive<T1Parameter,T2Parameter,T3Parameter,T4Parameter,T5Parameter>
+  {
+    FnTimerImplFive (FN fn) 
+      : m_fn (fn) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4, T5Parameter a5) {
+      m_a1 = a1;
+      m_a2 = a2;
+      m_a3 = a3;
+      m_a4 = a4;
+      m_a5 = a5;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_fn, m_a1, m_a2, m_a3, m_a4, m_a5);
+    }
+    FN m_fn;
+    T1Stored m_a1;
+    T2Stored m_a2;
+    T3Stored m_a3;
+    T4Stored m_a4;
+    T5Stored m_a5;
+  } *function = new FnTimerImplFive (fn);
+  delete m_impl;
+  m_impl = function;  
+}
+
+template <typename FN>
+void 
+Timer::DoSetFunction (IntToType<6>, FN fn)
+{
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg3Type T3;
+  typedef typename TimerTraits<T3>::ParameterType T3Parameter;
+  typedef typename TimerTraits<T3>::StoredType T3Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg4Type T4;
+  typedef typename TimerTraits<T4>::ParameterType T4Parameter;
+  typedef typename TimerTraits<T4>::StoredType T4Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg5Type T5;
+  typedef typename TimerTraits<T5>::ParameterType T5Parameter;
+  typedef typename TimerTraits<T5>::StoredType T5Stored;
+  typedef typename TypeTraits<FN>::FunctionPointerTraits::Arg6Type T6;
+  typedef typename TimerTraits<T6>::ParameterType T6Parameter;
+  typedef typename TimerTraits<T6>::StoredType T6Stored;
+
+  struct FnTimerImplSix : public TimerImplSix<T1Parameter,T2Parameter,T3Parameter,T4Parameter,T5Parameter,T6Parameter>
+  {
+    FnTimerImplSix (FN fn) 
+      : m_fn (fn) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4, T5Parameter a5, T6Parameter a6) {
+      m_a1 = a1;
+      m_a2 = a2;
+      m_a3 = a3;
+      m_a4 = a4;
+      m_a5 = a5;
+      m_a6 = a6;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_fn, m_a1, m_a2, m_a3, m_a4, m_a5, m_a6);
+    }
+    FN m_fn;
+    T1Stored m_a1;
+    T2Stored m_a2;
+    T3Stored m_a3;
+    T4Stored m_a4;
+    T5Stored m_a5;
+    T6Stored m_a6;
+  } *function = new FnTimerImplSix (fn);
+  delete m_impl;
+  m_impl = function;  
+}
+
+template <typename MEM_PTR, typename OBJ_PTR>
+void 
+Timer::SetFunction (MEM_PTR memPtr, OBJ_PTR objPtr)
+{
+  NS_ASSERT (TypeTraits<MEM_PTR>::IsPointerToMember);
+  DoSetFunction (IntToType<TypeTraits<MEM_PTR>::PointerToMemberTraits::nArgs> () , memPtr, objPtr);
+}
+
+template <typename MEM_PTR, typename OBJ_PTR>
+void 
+Timer::DoSetFunction (IntToType<0>, MEM_PTR memPtr, OBJ_PTR objPtr)
+{
+  struct MemFnTimerImplZero : public TimerImpl
+  {
+    MemFnTimerImplZero (MEM_PTR memPtr, OBJ_PTR objPtr) 
+      : m_memPtr (memPtr), m_objPtr (objPtr) {}
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_memPtr, m_objPtr);
+    }
+    MEM_PTR m_memPtr;
+    OBJ_PTR m_objPtr;
+  } *function = new MemFnTimerImplZero (memPtr, objPtr);
+  delete m_impl;
+  m_impl = function;    
+}
+
+template <typename MEM_PTR, typename OBJ_PTR>
+void 
+Timer::DoSetFunction (IntToType<1>, MEM_PTR memPtr, OBJ_PTR objPtr)
+{
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  
+  struct MemFnTimerImplOne : public TimerImplOne<T1Parameter>
+  {
+    MemFnTimerImplOne (MEM_PTR memPtr, OBJ_PTR objPtr) 
+      : m_memPtr (memPtr), m_objPtr (objPtr) {}
+    virtual void SetArguments (T1Parameter a1) {
+      m_a1 = a1;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1);
+    }
+    MEM_PTR m_memPtr;
+    OBJ_PTR m_objPtr;
+    T1Stored m_a1;
+  } *function = new MemFnTimerImplOne (memPtr, objPtr);
+  delete m_impl;
+  m_impl = function;    
+}
+
+template <typename MEM_PTR, typename OBJ_PTR>
+void 
+Timer::DoSetFunction (IntToType<2>, MEM_PTR memPtr, OBJ_PTR objPtr)
+{
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+  
+  struct MemFnTimerImplTwo : public TimerImplTwo<T1Parameter,T2Parameter>
+  {
+    MemFnTimerImplTwo (MEM_PTR memPtr, OBJ_PTR objPtr) 
+      : m_memPtr (memPtr), m_objPtr (objPtr) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2) {
+      m_a1 = a1;
+      m_a2 = a2;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2);
+    }
+    MEM_PTR m_memPtr;
+    OBJ_PTR m_objPtr;
+    T1Stored m_a1;
+    T2Stored m_a2;
+  } *function = new MemFnTimerImplTwo (memPtr, objPtr);
+  delete m_impl;
+  m_impl = function;    
+}
+
+template <typename MEM_PTR, typename OBJ_PTR>
+void 
+Timer::DoSetFunction (IntToType<3>, MEM_PTR memPtr, OBJ_PTR objPtr)
+{
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg3Type T3;
+  typedef typename TimerTraits<T3>::ParameterType T3Parameter;
+  typedef typename TimerTraits<T3>::StoredType T3Stored;
+  
+  struct MemFnTimerImplThree : public TimerImplThree<T1Parameter,T2Parameter,T3Parameter>
+  {
+    MemFnTimerImplThree (MEM_PTR memPtr, OBJ_PTR objPtr) 
+      : m_memPtr (memPtr), m_objPtr (objPtr) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3) {
+      m_a1 = a1;
+      m_a2 = a2;
+      m_a3 = a3;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3);
+    }
+    MEM_PTR m_memPtr;
+    OBJ_PTR m_objPtr;
+    T1Stored m_a1;
+    T2Stored m_a2;
+    T3Stored m_a3;
+  } *function = new MemFnTimerImplThree (memPtr, objPtr);
+  delete m_impl;
+  m_impl = function;    
+}
+
+template <typename MEM_PTR, typename OBJ_PTR>
+void 
+Timer::DoSetFunction (IntToType<4>, MEM_PTR memPtr, OBJ_PTR objPtr)
+{
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg3Type T3;
+  typedef typename TimerTraits<T3>::ParameterType T3Parameter;
+  typedef typename TimerTraits<T3>::StoredType T3Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg4Type T4;
+  typedef typename TimerTraits<T4>::ParameterType T4Parameter;
+  typedef typename TimerTraits<T4>::StoredType T4Stored;
+  
+  struct MemFnTimerImplFour : public TimerImplFour<T1Parameter,T2Parameter,T3Parameter,T4Parameter>
+  {
+    MemFnTimerImplFour (MEM_PTR memPtr, OBJ_PTR objPtr) 
+      : m_memPtr (memPtr), m_objPtr (objPtr) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4) {
+      m_a1 = a1;
+      m_a2 = a2;
+      m_a3 = a3;
+      m_a4 = a4;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3, m_a4);
+    }
+    MEM_PTR m_memPtr;
+    OBJ_PTR m_objPtr;
+    T1Stored m_a1;
+    T2Stored m_a2;
+    T3Stored m_a3;
+    T4Stored m_a4;
+  } *function = new MemFnTimerImplFour (memPtr, objPtr);
+  delete m_impl;
+  m_impl = function;    
+}
+
+template <typename MEM_PTR, typename OBJ_PTR>
+void 
+Timer::DoSetFunction (IntToType<5>, MEM_PTR memPtr, OBJ_PTR objPtr)
+{
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg3Type T3;
+  typedef typename TimerTraits<T3>::ParameterType T3Parameter;
+  typedef typename TimerTraits<T3>::StoredType T3Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg4Type T4;
+  typedef typename TimerTraits<T4>::ParameterType T4Parameter;
+  typedef typename TimerTraits<T4>::StoredType T4Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg5Type T5;
+  typedef typename TimerTraits<T5>::ParameterType T5Parameter;
+  typedef typename TimerTraits<T5>::StoredType T5Stored;
+  
+  struct MemFnTimerImplFive : public TimerImplFive<T1Parameter,T2Parameter,T3Parameter,T4Parameter,T5Parameter>
+  {
+    MemFnTimerImplFive (MEM_PTR memPtr, OBJ_PTR objPtr) 
+      : m_memPtr (memPtr), m_objPtr (objPtr) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4,T5Parameter a5) {
+      m_a1 = a1;
+      m_a2 = a2;
+      m_a3 = a3;
+      m_a4 = a4;
+      m_a5 = a5;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3, m_a4, m_a5);
+    }
+    MEM_PTR m_memPtr;
+    OBJ_PTR m_objPtr;
+    T1Stored m_a1;
+    T2Stored m_a2;
+    T3Stored m_a3;
+    T4Stored m_a4;
+    T5Stored m_a5;
+  } *function = new MemFnTimerImplFive (memPtr, objPtr);
+  delete m_impl;
+  m_impl = function;    
+}
+
+template <typename MEM_PTR, typename OBJ_PTR>
+void 
+Timer::DoSetFunction (IntToType<6>, MEM_PTR memPtr, OBJ_PTR objPtr)
+{
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg1Type T1;
+  typedef typename TimerTraits<T1>::ParameterType T1Parameter;
+  typedef typename TimerTraits<T1>::StoredType T1Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg2Type T2;
+  typedef typename TimerTraits<T2>::ParameterType T2Parameter;
+  typedef typename TimerTraits<T2>::StoredType T2Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg3Type T3;
+  typedef typename TimerTraits<T3>::ParameterType T3Parameter;
+  typedef typename TimerTraits<T3>::StoredType T3Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg4Type T4;
+  typedef typename TimerTraits<T4>::ParameterType T4Parameter;
+  typedef typename TimerTraits<T4>::StoredType T4Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg5Type T5;
+  typedef typename TimerTraits<T5>::ParameterType T5Parameter;
+  typedef typename TimerTraits<T5>::StoredType T5Stored;
+  typedef typename TypeTraits<MEM_PTR>::PointerToMemberTraits::Arg6Type T6;
+  typedef typename TimerTraits<T6>::ParameterType T6Parameter;
+  typedef typename TimerTraits<T6>::StoredType T6Stored;
+  
+  struct MemFnTimerImplSix : public TimerImplSix<T1Parameter,T2Parameter,T3Parameter,T4Parameter,T5Parameter,T6Parameter>
+  {
+    MemFnTimerImplSix (MEM_PTR memPtr, OBJ_PTR objPtr) 
+      : m_memPtr (memPtr), m_objPtr (objPtr) {}
+    virtual void SetArguments (T1Parameter a1, T2Parameter a2, T3Parameter a3, T4Parameter a4,T5Parameter a5,T6Parameter a6) {
+      m_a1 = a1;
+      m_a2 = a2;
+      m_a3 = a3;
+      m_a4 = a4;
+      m_a5 = a5;
+      m_a6 = a6;
+    }
+    virtual EventId Schedule (const Time &delay) {
+      return Simulator::Schedule (delay, m_memPtr, m_objPtr, m_a1, m_a2, m_a3, m_a4, m_a5, m_a6);
+    }
+    MEM_PTR m_memPtr;
+    OBJ_PTR m_objPtr;
+    T1Stored m_a1;
+    T2Stored m_a2;
+    T3Stored m_a3;
+    T4Stored m_a4;
+    T5Stored m_a5;
+    T6Stored m_a6;
+  } *function = new MemFnTimerImplSix (memPtr, objPtr);
+  delete m_impl;
+  m_impl = function;    
+}
+
+
+template <typename T1>
+void 
+Timer::SetArguments (T1 a1)
+{
+  if (m_impl == 0)
+    {
+      NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function.");
+      return;
+    }
+  typedef struct TimerImplOne<
+    typename TimerTraits<T1>::ParameterType
+    > TimerImplBase;
+  TimerImplBase *impl = dynamic_cast<TimerImplBase *> (m_impl);
+  if (impl == 0)
+    {
+      NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function.");
+      return;
+    }
+  impl->SetArguments (a1);
+}
+
+template <typename T1, typename T2>
+void 
+Timer::SetArguments (T1 a1, T2 a2)
+{
+  if (m_impl == 0)
+    {
+      NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function.");
+      return;
+    }
+  typedef struct TimerImplTwo<
+    typename TimerTraits<T1>::ParameterType,
+    typename TimerTraits<T2>::ParameterType
+    > TimerImplBase;
+  TimerImplBase *impl = dynamic_cast<TimerImplBase *> (m_impl);
+  if (impl == 0)
+    {
+      NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function.");
+      return;
+    }
+  impl->SetArguments (a1, a2);
+}
+
+template <typename T1, typename T2, typename T3>
+void 
+Timer::SetArguments (T1 a1, T2 a2, T3 a3)
+{
+  if (m_impl == 0)
+    {
+      NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function.");
+      return;
+    }
+  typedef struct TimerImplThree<
+    typename TimerTraits<T1>::ParameterType,
+    typename TimerTraits<T2>::ParameterType,
+    typename TimerTraits<T3>::ParameterType
+    > TimerImplBase;
+  TimerImplBase *impl = dynamic_cast<TimerImplBase *> (m_impl);
+  if (impl == 0)
+    {
+      NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function.");
+      return;
+    }
+  impl->SetArguments (a1, a2, a3);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+void 
+Timer::SetArguments (T1 a1, T2 a2, T3 a3, T4 a4)
+{
+  if (m_impl == 0)
+    {
+      NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function.");
+      return;
+    }
+  typedef struct TimerImplFour<
+    typename TimerTraits<T1>::ParameterType,
+    typename TimerTraits<T2>::ParameterType,
+    typename TimerTraits<T3>::ParameterType,
+    typename TimerTraits<T4>::ParameterType
+    > TimerImplBase;
+  TimerImplBase *impl = dynamic_cast<TimerImplBase *> (m_impl);
+  if (impl == 0)
+    {
+      NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function.");
+      return;
+    }
+  impl->SetArguments (a1, a2, a3, a4);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+void 
+Timer::SetArguments (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
+{
+  if (m_impl == 0)
+    {
+      NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function.");
+      return;
+    }
+  typedef struct TimerImplFive<
+    typename TimerTraits<T1>::ParameterType,
+    typename TimerTraits<T2>::ParameterType,
+    typename TimerTraits<T3>::ParameterType,
+    typename TimerTraits<T4>::ParameterType,
+    typename TimerTraits<T5>::ParameterType
+    > TimerImplBase;
+  TimerImplBase *impl = dynamic_cast<TimerImplBase *> (m_impl);
+  if (impl == 0)
+    {
+      NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function.");
+      return;
+    }
+  impl->SetArguments (a1, a2, a3, a4, a5);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
+void 
+Timer::SetArguments (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
+{
+  if (m_impl == 0)
+    {
+      NS_FATAL_ERROR ("You cannot set the arguments of a Timer before setting its function.");
+      return;
+    }
+  typedef struct TimerImplSix<
+    typename TimerTraits<T1>::ParameterType,
+    typename TimerTraits<T2>::ParameterType,
+    typename TimerTraits<T3>::ParameterType,
+    typename TimerTraits<T4>::ParameterType,
+    typename TimerTraits<T5>::ParameterType,
+    typename TimerTraits<T6>::ParameterType
+    > TimerImplBase;
+  TimerImplBase *impl = dynamic_cast<TimerImplBase *> (m_impl);
+  if (impl == 0)
+    {
+      NS_FATAL_ERROR ("You tried to set Timer arguments incompatible with its function.");
+      return;
+    }
+  impl->SetArguments (a1, a2, a3, a4, a5, a6);
+}
+
+
+
+} // namespace ns3
+
+#endif /* TIMER_H */
--- a/src/simulator/wscript	Mon Oct 08 11:23:53 2007 +0100
+++ b/src/simulator/wscript	Mon Oct 08 11:24:16 2007 +0100
@@ -60,6 +60,8 @@
         'event-impl.cc',
         'simulator.cc',
         'time-default-value.cc',
+        'timer.cc',
+        'event-garbage-collector.cc',
         ]
 
     headers = bld.create_obj('ns3header')
@@ -73,6 +75,7 @@
         'scheduler-factory.h',
         'simulation-singleton.h',
         'time-default-value.h',
+        'timer.h'
         ]
 
     env = bld.env_of_name('default')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/mobility-generator.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,67 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 INRIA
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "ns3/ns2-mobility-file-topology.h"
+#include "ns3/object.h"
+#include "ns3/simulator.h"
+#include "ns3/mobility-model-notifier.h"
+#include <iostream>
+
+using namespace ns3;
+
+static void 
+CourseChange (Ptr<const MobilityModel> position)
+{
+  Position pos = position->Get ();
+  std::cout << Simulator::Now () << ", pos=" << position << ", x=" << pos.x << ", y=" << pos.y
+            << ", z=" << pos.z << std::endl;
+}
+
+int main (int argc, char *argv[])
+{
+  std::vector<Ptr<Object> > objects;
+  while (argc > 0)
+    {
+      if (strncmp (*argv, "--n=", strlen ("--n=")) == 0)
+	{
+	  uint32_t n = atoi (*argv + strlen ("--n="));
+	  for (uint32_t i = 0; i < n; i++)
+	    {
+	      Ptr<MobilityModelNotifier> notifier = Create<MobilityModelNotifier> ();
+	      notifier->RegisterListener (MakeCallback (&CourseChange));
+	      objects.push_back (notifier);
+	    }
+	} 
+      else if (strncmp (*argv, "--ns2-topology=", 
+			strlen ("--ns2-topology=")) == 0)
+	{
+	  const char *filename = *argv + strlen ("--ns2-topology=");
+	  Ns2MobilityFileTopology topology (filename);
+	  topology.Layout (objects.begin (), objects.end ());
+	}
+      argc--;
+      argv++;
+    }
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/mobility-visualizer-model.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,137 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include <vector>
+
+#include "ns3/ptr.h"
+#include "ns3/mobility-model.h"
+#include "ns3/mobility-model-notifier.h"
+#include "ns3/random-topology.h"
+#include "ns3/default-value.h"
+#include "ns3/command-line.h"
+#include "ns3/command-line.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/node.h"
+#include "ns3/node-list.h"
+#include "ns3/rectangle-default-value.h"
+
+#include "mobility-visualizer.h"
+
+using namespace ns3;
+
+static Time g_sampleInterval = Seconds (SAMPLE_INTERVAL);
+static uint32_t g_numNodes = 10;
+
+template <typename T>
+static const T* DefaultValueListGet (const std::string &name)
+{
+  for (DefaultValueList::Iterator iter = DefaultValueList::Begin ();
+       iter != DefaultValueList::End (); iter++)
+    {
+      const DefaultValueBase *value = *iter;
+      if (value->GetName () == name)
+        {
+          return dynamic_cast<const T*> (value);
+        }
+    }
+  return NULL;
+}
+
+
+
+static void 
+Sample ()
+{
+  
+  ViewUpdateData *data = new ViewUpdateData;
+  for (NodeList::Iterator nodeIter = NodeList::Begin (); nodeIter != NodeList::End (); nodeIter++)
+    {
+      Ptr<Node> node = *nodeIter;
+      Ptr<MobilityModel> mobility = node->QueryInterface<MobilityModel> (MobilityModel::iid);
+      Position pos = mobility->Get ();
+      Speed vel = mobility->GetSpeed ();
+
+      NodeUpdate update;
+      update.node = PeekPointer<Node> (node);
+      update.x = pos.x;
+      update.y = pos.y;
+      update.vx = vel.dx;
+      update.vy = vel.dy;
+      data->updateList.push_back (update);
+    }
+  data->time = Simulator::Now ().GetSeconds ();
+  view_update (data);
+  Simulator::Schedule (g_sampleInterval, Sample);
+}
+
+
+
+int model_init (int argc, char *argv[], double *x1, double *y1, double *x2, double *y2)
+{
+  DefaultValue::Bind ("RandomWalk2dMode", "Time");
+  DefaultValue::Bind ("RandomWalk2dTime", "5s");
+  DefaultValue::Bind ("RandomWalk2dSpeed", "Constant:20.0");
+  DefaultValue::Bind ("RandomDirection2dSpeed", "Uniform:10.0:20.0");
+  DefaultValue::Bind ("RandomWalk2dBounds", "0:400:0:300");
+  DefaultValue::Bind ("RandomDirection2dArea", "0:400:0:300");
+  DefaultValue::Bind ("RandomWaypointSpeed", "Uniform:10:30");
+
+//   DefaultValue::Bind ("RandomDiscPositionX", "100");
+//   DefaultValue::Bind ("RandomDiscPositionY", "50");
+//   DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30");
+
+  DefaultValue::Bind ("RandomTopologyPositionType", "RandomRectanglePosition");
+  DefaultValue::Bind ("RandomTopologyMobilityType", "RandomWalk2dMobilityModel");
+
+//   CommandLine::AddArgValue ("sample-interval","sample interval", g_sampleInterval);
+//   CommandLine::AddArgValue ("num-nodes","number of nodes", g_numNodes);
+
+  CommandLine::Parse (argc, argv);
+
+  RandomTopology topology;
+
+  for (uint32_t i = 0; i < g_numNodes; i++)
+    {
+      Ptr<Node> node = Create<Node> ();
+      node->AddInterface (Create<MobilityModelNotifier> ());
+    }
+
+  topology.Layout (NodeList::Begin (), NodeList::End ());
+
+  Simulator::Schedule (g_sampleInterval, Sample);
+
+  ClassId mobType = DefaultValueListGet<ClassIdDefaultValue> ("RandomTopologyMobilityType")->GetValue ();
+  if (mobType.GetName () == "RandomWalk2dMobilityModel")
+    {
+      Rectangle bounds = DefaultValueListGet<RectangleDefaultValue> ("RandomWalk2dBounds")->GetValue ();
+      *x1 = bounds.xMin;
+      *y1 = bounds.yMin;
+      *x2 = bounds.xMax;
+      *y2 = bounds.yMax;
+      std::cout << "RECT " << bounds.xMin << " " << bounds.xMax << " "
+                << bounds.yMin << " " << bounds.yMax << std::endl;
+    }
+  else if (mobType.GetName () == "RandomDirection2dMobilityModel")
+    {
+      Rectangle bounds = DefaultValueListGet<RectangleDefaultValue> ("RandomDirection2dArea")->GetValue ();
+      *x1 = bounds.xMin;
+      *y1 = bounds.yMin;
+      *x2 = bounds.xMax;
+      *y2 = bounds.yMax;
+      std::cout << "RECT " << bounds.xMin << " " << bounds.xMax << " "
+                << bounds.yMin << " " << bounds.yMax << std::endl;      
+    }
+  else if (mobType.GetName () == "RandomWaypointMobilityModel")
+    {
+      std::cerr << "bounds for RandomWaypointMobilityModel not implemented" << std::endl;
+      //ClassId posType = DefaultValueList::Get<ClassIdDefaultValue> ("RandomWaypointPosition")->GetValue ();
+      std::cout << "?" << std::endl; // too hard to represent an abstract/probabilistic model graphically
+    }
+  else
+    {
+      NS_FATAL_ERROR ("mobility type " << mobType.GetName () << " not supported");
+    }
+
+  std::cerr << g_sampleInterval << std::endl;
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/mobility-visualizer-view.cc	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,218 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+
+#include <map>
+
+#include <goocanvas.h>
+#include <glib/gthread.h>
+
+#include "mobility-visualizer.h"
+#include <map>
+#include "ns3/simulator.h"
+
+#define MAX_QUEUE_LENGTH 100
+#define MAX_EVENTS 20
+#define LOOKAHEAD_SECONDS 10
+
+GtkWidget *g_canvas;
+
+int model_init (int argc, char *argv[]);
+
+struct Node
+{
+  GooCanvasItem *m_item;
+  GooCanvasItem *m_vector;
+  void create ()
+  {
+    GooCanvasItem *root = goo_canvas_get_root_item (GOO_CANVAS (g_canvas));
+    m_item = goo_canvas_ellipse_new (root, 0, 0, 2.0, 2.0,
+                                     "line_width", 0.5,
+                                     "stroke_color", "black",
+                                     "fill_color", "red",
+                                     NULL);
+
+    m_vector = goo_canvas_polyline_new (root, FALSE, 0,
+                                        "line_width", 0.3,
+                                        "stroke_color", "black",
+                                        "end-arrow", TRUE,
+                                        "arrow-length", 10.0,
+                                        "arrow-width", 10.0,
+                                        NULL);
+    
+  }
+
+
+  void update (double x, double y, double vx, double vy)
+  {
+    g_object_set (m_item, "center_x", x, "center_y", y, NULL);
+    
+    if (vx == 0 && vy == 0)
+      {
+        GooCanvasPoints *points = goo_canvas_points_new (0);
+        g_object_set (m_vector, "points", points, NULL);
+        goo_canvas_points_unref (points);
+      }
+    else
+      {
+        GooCanvasPoints *points = goo_canvas_points_new (2);
+
+        points->coords[0] = x;
+        points->coords[1] = y;
+        points->coords[2] = x + vx;
+        points->coords[3] = y + vy;
+
+        g_object_set (m_vector, "points", points, NULL);
+        goo_canvas_points_unref (points);
+      }
+  }
+};
+
+std::map<void*, Node> g_nodes;
+
+GTimeVal initialTime = {-1, -1};
+gboolean firstTime = TRUE;
+double g_lookaheadTime = 0;
+GStaticMutex g_lookaheadTimeMux = G_STATIC_MUTEX_INIT;
+ViewUpdateData *g_nextData = NULL;
+
+
+GAsyncQueue *queue;
+
+#define TIME_SCALE 1
+
+double get_current_time ()
+{
+  GTimeVal currTime;
+  g_get_current_time (&currTime);
+  GTimeVal relativeTime;
+  relativeTime.tv_sec = currTime.tv_sec - initialTime.tv_sec + LOOKAHEAD_SECONDS;
+  relativeTime.tv_usec = currTime.tv_usec;
+  g_time_val_add (&relativeTime, -initialTime.tv_usec);
+  return (relativeTime.tv_sec + 1.0e-6*relativeTime.tv_usec)*TIME_SCALE;
+}
+
+// called from the simulation thread
+void view_update (ViewUpdateData *updateData)
+{
+  while ((g_static_mutex_lock (&g_lookaheadTimeMux), g_lookaheadTime) != 0 and updateData->time >= g_lookaheadTime)
+    {
+      g_static_mutex_unlock (&g_lookaheadTimeMux);
+      g_usleep ((gulong) 10e3);
+    }
+  g_static_mutex_unlock (&g_lookaheadTimeMux);
+  g_async_queue_push (queue, updateData);
+}
+
+void view_update_process (ViewUpdateData *updateData)
+{
+  for (std::vector<NodeUpdate>::const_iterator update
+         = updateData->updateList.begin ();
+       update != updateData->updateList.end ();
+       update++)
+    {
+      if (g_nodes.find (update->node) == g_nodes.end ())
+        {
+          g_nodes[update->node].create ();
+        }
+      g_nodes[update->node].update (update->x, update->y, update->vx, update->vy);
+    }
+  delete updateData;
+}
+
+gboolean view_update_consumer ()
+{
+  if (firstTime)
+    {
+      firstTime = FALSE;
+      g_get_current_time (&initialTime);
+    }
+
+  double now = get_current_time ();
+  g_static_mutex_lock (&g_lookaheadTimeMux);
+  g_lookaheadTime = now + LOOKAHEAD_SECONDS;
+  g_static_mutex_unlock (&g_lookaheadTimeMux);
+
+  if (!g_nextData)
+    g_nextData = (ViewUpdateData *) g_async_queue_try_pop (queue);
+
+  if (!g_nextData)
+    return TRUE;
+  
+  if (g_nextData->time > now)
+    return TRUE;
+
+  do
+    {
+      view_update_process (g_nextData);
+      g_nextData = (ViewUpdateData *) g_async_queue_try_pop (queue);
+    }
+  while (g_nextData && g_nextData->time <= now);
+
+  return TRUE;
+}
+
+void zoom_changed (GtkAdjustment *adj)
+{
+  goo_canvas_set_scale (GOO_CANVAS (g_canvas), gtk_adjustment_get_value (adj));
+}
+
+int main (int argc, char *argv[])
+{
+  g_thread_init (NULL);
+  gtk_init (&argc, &argv);
+  double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+
+  model_init (argc, argv, &x1, &y1, &x2, &y2);
+
+  GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_default_size (GTK_WINDOW (window), 640, 600);
+  gtk_widget_show (window);
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  GtkWidget *scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
+  gtk_widget_show (scrolled_win);
+
+  GtkWidget *vbox = gtk_vbox_new (FALSE, 4);
+  gtk_widget_show (vbox);
+  gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, 1, 1, 4);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+
+  GtkWidget *hbox = gtk_hbox_new (FALSE, 4);
+  gtk_widget_show (hbox);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, false, false, 4);
+
+  GtkObject *zoom = gtk_adjustment_new (3.0, 0.1, 10.0, 0.2, 1.0, 1.0);
+  gtk_box_pack_start(GTK_BOX (hbox),
+                     GTK_WIDGET (g_object_new (GTK_TYPE_SPIN_BUTTON, "adjustment", zoom,
+                                               "visible", true, "digits", 2, NULL)),
+                     false, false, 4);
+
+  g_canvas = goo_canvas_new ();
+  gtk_widget_set_size_request (GTK_WIDGET (g_canvas), 600, 450);
+  goo_canvas_set_bounds (GOO_CANVAS (g_canvas), -500, -500, 500, 500);
+  g_signal_connect (zoom, "value-changed", G_CALLBACK (zoom_changed), NULL);
+  gtk_adjustment_value_changed (GTK_ADJUSTMENT (zoom));
+  gtk_widget_show (g_canvas);
+  gtk_container_add (GTK_CONTAINER (scrolled_win), g_canvas);
+
+  goo_canvas_scroll_to (GOO_CANVAS (g_canvas), 0, 0);
+
+  // create the bounds rectangle
+  if (x1 != x2)
+    {
+      GooCanvasItem *item = 
+        goo_canvas_rect_new (goo_canvas_get_root_item (GOO_CANVAS (g_canvas)),
+                                                 x1, y1, x2-x1, y2-y1, NULL);
+        g_object_set (item, "line-width", 1.0, "stroke-color", "grey", NULL);
+    }
+
+  queue = g_async_queue_new ();
+
+  g_timeout_add ((guint) (SAMPLE_INTERVAL*1000), (GSourceFunc) view_update_consumer, NULL);
+
+  g_thread_create (GThreadFunc (ns3::Simulator::Run), NULL, FALSE, NULL);
+
+  gtk_main ();
+
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/utils/mobility-visualizer.h	Mon Oct 08 11:24:16 2007 +0100
@@ -0,0 +1,23 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#include <vector>
+
+int model_init (int argc, char *argv[], double *x1, double *y1, double *x2, double *y2);
+
+struct NodeUpdate
+{
+    void *node;
+    double x;
+    double y;
+    double vx;
+    double vy;
+};
+
+struct ViewUpdateData
+{
+  std::vector<NodeUpdate> updateList;
+  double time;
+};
+
+void view_update (ViewUpdateData *updateData);
+
+#define SAMPLE_INTERVAL (1.0/30)
--- a/utils/wscript	Mon Oct 08 11:23:53 2007 +0100
+++ b/utils/wscript	Mon Oct 08 11:24:16 2007 +0100
@@ -1,5 +1,13 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+import os.path
 
+def configure(conf):
+    check = conf.create_pkgconfig_configurator()
+    check.name = 'goocanvas gthread-2.0'
+    check.uselib = 'MOBILITY_VISUALIZER'
+    check.mandatory = False
+    conf.env['ENABLE_MOBILITY_VISUALIZER'] = check.run()
+    
 
 def build(bld):
     env = bld.env_of_name('default')
@@ -23,3 +31,12 @@
     obj = bld.create_ns3_program('print-trace-sources',
                                  ['internet-node', 'csma-cd', 'point-to-point'])
     obj.source = 'print-trace-sources.cc'
+
+    if env['ENABLE_MOBILITY_VISUALIZER']:
+        obj = bld.create_ns3_program('mobility-visualizer',
+                                     ['internet-node', 'mobility'])
+        obj.source = ['mobility-visualizer-model.cc', 'mobility-visualizer-view.cc']
+        obj.uselib = 'MOBILITY_VISUALIZER'
+        if os.path.basename(obj.env['CXX']).startswith("g++"):
+            obj.env.append_value('CXXFLAGS', '-fno-strict-aliasing')
+
--- a/wscript	Mon Oct 08 11:23:53 2007 +0100
+++ b/wscript	Mon Oct 08 11:24:16 2007 +0100
@@ -143,6 +143,7 @@
             variant_env.append_value("LINKFLAGS", "-Wl,--enable-runtime-pseudo-reloc")
 
     conf.sub_config('src')
+    conf.sub_config('utils')
 
 
 def create_ns3_program(bld, name, dependencies=('simulator',)):