merge with ns-3-dev
authorGustavo J. A. M. Carneiro <gjc@inescporto.pt>
Wed, 05 Sep 2007 18:35:39 +0100
changeset 1737 e72c130c3a59
parent 1728 190372a33951 (current diff)
parent 1312 8bc3f26344b9 (diff)
child 1738 6a3e37af9d24
merge with ns-3-dev
examples/csma-cd-one-subnet.cc
samples/main-packet.cc
src/common/chunk.cc
src/common/chunk.h
src/common/header.cc
src/common/trailer.cc
src/core/assert.cc
src/devices/csma-cd/backoff.cc
src/devices/csma-cd/backoff.h
src/devices/csma-cd/csma-cd-channel.cc
src/devices/csma-cd/csma-cd-channel.h
src/devices/csma-cd/csma-cd-ipv4-topology.cc
src/devices/csma-cd/csma-cd-ipv4-topology.h
src/devices/csma-cd/csma-cd-net-device.cc
src/devices/csma-cd/csma-cd-net-device.h
src/devices/csma-cd/csma-cd-topology.cc
src/devices/csma-cd/csma-cd-topology.h
src/devices/csma-cd/wscript
src/internet-node/arp-private.cc
src/internet-node/arp-private.h
src/internet-node/ipv4-l3-protocol.cc
src/internet-node/ipv4-private.cc
src/internet-node/ipv4-private.h
src/internet-node/l3-demux.cc
src/internet-node/l3-demux.h
src/internet-node/l3-protocol.cc
src/internet-node/l3-protocol.h
src/internet-node/wscript
src/node/ipv4-address.cc
src/node/ipv4-address.h
src/node/mac-address.cc
src/node/mac-address.h
src/simulator/wscript
utils/wscript
wscript
--- a/.hgtags	Mon Jul 30 14:48:56 2007 +0100
+++ b/.hgtags	Wed Sep 05 18:35:39 2007 +0100
@@ -3,3 +3,4 @@
 0dc81e76166c56aaae64da48b673b62155943aad packet-history-working
 38099dd26e9467b8f49f8632f22789858149a6e7 release ns-3.0.3
 5701e60bf01a8ac1308945e69001e0cc07948faf release ns-3.0.4
+08046b6aef37932507696a2f2f427b42d693781e release ns-3.0.5
--- a/AUTHORS	Mon Jul 30 14:48:56 2007 +0100
+++ b/AUTHORS	Wed Sep 05 18:35:39 2007 +0100
@@ -3,4 +3,5 @@
 Craig Dowell (craigdo@ee.washington.edu)
 Tom Henderson (tomhend@u.washington.edu)
 Mathieu Lacage (mathieu.lacage@sophia.inria.fr)
+Emmanuelle Laprise (emmmanuelle.laprise@bluekazoo.ca)
 George F. Riley (riley@ece.gatech.edu)
--- a/RELEASE_NOTES	Mon Jul 30 14:48:56 2007 +0100
+++ b/RELEASE_NOTES	Wed Sep 05 18:35:39 2007 +0100
@@ -3,12 +3,16 @@
 
 This file contains ns-3 release notes (most recent releases first).
 
-Release 3.0.5 (2007/08/XX)
+Release 3.0.5 (2007/08/15)
 ========================
 
-  - Add CSMA/CD model (Emmanuelle Laprise)
-  - Modularize ipv4 routing support (Gustavo Carneiro)
-  - Add mobility framework and basic mobility models
+  - Refactoring to support win32-based unix environments (Cygwin, mingw)
+  - "Packet socket" for allowing applications to access NetDevices directly
+  - Generalized, polymorphic Address class
+  - Add CSMA NetDevice model (from Emmanuelle Laprise)
+  - Modularize IPv4 routing support (from Gustavo Carneiro)
+  - Add mobility framework and basic mobility models 
+  - Global unicast centralized routing 
 
 Release 3.0.4 (2007/07/15)
 ========================
--- a/VERSION	Mon Jul 30 14:48:56 2007 +0100
+++ b/VERSION	Wed Sep 05 18:35:39 2007 +0100
@@ -1,1 +1,1 @@
-3.0.4
+3.0.5
--- a/doc/doxygen.conf	Mon Jul 30 14:48:56 2007 +0100
+++ b/doc/doxygen.conf	Wed Sep 05 18:35:39 2007 +0100
@@ -999,7 +999,7 @@
 # undefined via #undef or recursively expanded use the := operator 
 # instead of the = operator.
 
-PREDEFINED             = RUN_SELF_TESTS NS3_DEBUG_ENABLE
+PREDEFINED             = RUN_SELF_TESTS NS3_DEBUG_ENABLE NS3_ASSERT_ENABLE
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
 # this tag can be used to specify a list of macro names that should be expanded. 
--- a/doc/release_steps.txt	Mon Jul 30 14:48:56 2007 +0100
+++ b/doc/release_steps.txt	Wed Sep 05 18:35:39 2007 +0100
@@ -5,23 +5,20 @@
    - revise and check in RELEASE_NOTES
    - update and check in VERSION to the latest release number
 2. make a new "architecture.pdf" document and place it in the doc/ directory
-3. add current version of waf script from subversion:
-   - svn checkout http://waf.googlecode.com/svn/tags/ns3/ waf
-   - build waf script and put it into top of ns-3-dev
-4. cd ns-3-dev; ./waf configure; ./waf dist
-5. test tarball on release platforms (run-tests and simple-p2p)
-6. tag ns-3-dev with "release ns-3.0.X"
+3. cd ns-3-dev; ./waf configure; ./waf dist
+4. test tarball on release platforms (waf check and maybe some other scripts)
+5. tag ns-3-dev with "release ns-3.0.X"
   - hg tag "release ns-3.0.x"
   - hg push 
-7. clone the tagged ns-3-dev and place it on the repository
+6. clone the tagged ns-3-dev and place it on the repository
   - ssh code.nsnam.org; sudo; su code;
   - cp -r /home/code/repos/ns-3-dev /home/code/repos/ns-3.0.x
   - cd /home/code/repos/ns-3.0.x/.hg and edit the hgrc appropriately
-8. upload "ns-3.0.x.tar.bz2" to the releases/ directory on the server
-9. update web page
+7. upload "ns-3.0.x.tar.bz2" to the releases/ directory on the server
+8. update web page
    - add link to news.html
    - update download.html
    - update roadmap.html
    - build and update Doxygen directory on the server
    - update and upload software architecture document (PDF, HTML)
-10. announce to ns-developers, with summary of release notes
+9. announce to ns-developers, with summary of release notes
--- a/examples/csma-cd-one-subnet.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * 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
- */
-
-// Port of ns-2/tcl/ex/simple.tcl to ns-3
-//
-// Network topology
-//
-//       n0    n1   n2   n3
-//       |     |    |    |
-//     =====================
-//
-// - CBR/UDP flows from n0 to n1, and from n3 to n0
-// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
-//   (i.e., DataRate of 448,000 bps)
-// - DropTail queues 
-// - Tracing of queues and packet receptions to file "csma-cd-one-subnet.tr"
-
-#include <iostream>
-#include <fstream>
-#include <string>
-#include <cassert>
-
-#include "ns3/command-line.h"
-#include "ns3/default-value.h"
-#include "ns3/ptr.h"
-#include "ns3/random-variable.h"
-#include "ns3/debug.h"
-
-#include "ns3/simulator.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-
-#include "ns3/ascii-trace.h"
-#include "ns3/pcap-trace.h"
-#include "ns3/internet-node.h"
-#include "ns3/csma-cd-channel.h"
-#include "ns3/csma-cd-net-device.h"
-#include "ns3/csma-cd-topology.h"
-#include "ns3/csma-cd-ipv4-topology.h"
-#include "ns3/mac-address.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/socket.h"
-#include "ns3/ipv4-route.h"
-#include "ns3/onoff-application.h"
-
-#include "ns3/ascii-trace.h"
-
-#include "ns3/trace-context.h"
-#include "ns3/trace-root.h"
-
-
-using namespace ns3;
-
-
-int main (int argc, char *argv[])
-{
-
-  // Users may find it convenient to turn on explicit debugging
-  // for selected modules; the below lines suggest how to do this
-#if 0 
-  DebugComponentEnable("CsmaCdNetDevice");
-  DebugComponentEnable("Ipv4L3Protocol");
-  DebugComponentEnable("NetDevice");
-  DebugComponentEnable("Channel");
-  DebugComponentEnable("CsmaCdChannel");
-  DebugComponentEnable("PacketSocket");
-#endif
-
-  // Set up some default values for the simulation.  Use the Bind()
-  // technique to tell the system what subclass of Queue to use,
-  // and what the queue limit is
-
-  // The below Bind command tells the queue factory which class to
-  // instantiate, when the queue factory is invoked in the topology code
-  Bind ("Queue", "DropTailQueue");
-
-  // Allow the user to override any of the defaults and the above
-  // Bind()s at run-time, via command-line arguments
-  CommandLine::Parse (argc, argv);
-
-  // Here, we will explicitly create four nodes.  In more sophisticated
-  // topologies, we could configure a node factory.
-  Ptr<Node> n0 = Create<InternetNode> ();
-  Ptr<Node> n1 = Create<InternetNode> (); 
-  Ptr<Node> n2 = Create<InternetNode> (); 
-  Ptr<Node> n3 = Create<InternetNode> ();
-
-  // We create the channels first without any IP addressing information
-  Ptr<CsmaCdChannel> channel0 = 
-    CsmaCdTopology::CreateCsmaCdChannel(
-      DataRate(5000000), MilliSeconds(2));
-
-  uint32_t n0ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n0, channel0, 
-                                         MacAddress("10:54:23:54:23:50"));
-  uint32_t n1ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n1, channel0,
-                                         MacAddress("10:54:23:54:23:51"));
-  uint32_t n2ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n2, channel0,
-                                         MacAddress("10:54:23:54:23:52"));
-  uint32_t n3ifIndex = CsmaCdIpv4Topology::AddIpv4CsmaCdNode (n3, channel0,
-                                         MacAddress("10:54:23:54:23:53"));
-
-  // Later, we add IP addresses.  
-  CsmaCdIpv4Topology::AddIpv4Address (
-      n0, n0ifIndex, Ipv4Address("10.1.1.1"), Ipv4Mask("255.255.255.0"));
-
-  CsmaCdIpv4Topology::AddIpv4Address (
-      n1, n1ifIndex, Ipv4Address("10.1.1.2"), Ipv4Mask("255.255.255.0"));
-
-  CsmaCdIpv4Topology::AddIpv4Address (
-      n2, n2ifIndex, Ipv4Address("10.1.1.3"), Ipv4Mask("255.255.255.0"));
-  
-  CsmaCdIpv4Topology::AddIpv4Address (
-      n3, n3ifIndex, Ipv4Address("10.1.1.4"), Ipv4Mask("255.255.255.0"));
-
-  // Create the OnOff application to send UDP datagrams of size
-  // 210 bytes at a rate of 448 Kb/s
-  // from n0 to n1
-  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
-    n0, 
-    Ipv4Address("10.1.1.2"), 
-    80, 
-    "Udp",
-    ConstantVariable(1), 
-    ConstantVariable(0));
-  // Start the application
-  ooff->Start(Seconds(1.0));
-  ooff->Stop (Seconds(10.0));
-
-  // Create a similar flow from n3 to n0, starting at time 1.1 seconds
-  ooff = Create<OnOffApplication> (
-    n3, 
-    Ipv4Address("10.1.1.1"), 
-    80, 
-    "Udp",
-    ConstantVariable(1), 
-    ConstantVariable(0));
-  // Start the application
-  ooff->Start(Seconds(1.1));
-  ooff->Stop (Seconds(10.0));
- 
-  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
-  // Trace output will be sent to the csma-cd-one-subnet.tr file
-  AsciiTrace asciitrace ("csma-cd-one-subnet.tr");
-  asciitrace.TraceAllNetDeviceRx ();
-  asciitrace.TraceAllQueues ();
-
-  // Also configure some tcpdump traces; each interface will be traced
-  // The output files will be named 
-  // simple-point-to-point.pcap-<nodeId>-<interfaceId>
-  // and can be read by the "tcpdump -r" command (use "-tt" option to
-  // display timestamps correctly)
-  PcapTrace pcaptrace ("csma-cd-one-subnet.pcap");
-  pcaptrace.TraceAllIp ();
-
-  Simulator::Run ();
-    
-  Simulator::Destroy ();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-one-subnet.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,166 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+//       n0    n1   n2   n3
+//       |     |    |    |
+//     =====================
+//
+// - CBR/UDP flows from n0 to n1, and from n3 to n0
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+//   (i.e., DataRate of 448,000 bps)
+// - DropTail queues 
+// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/debug.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/eui48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/onoff-application.h"
+
+
+using namespace ns3;
+
+
+int main (int argc, char *argv[])
+{
+
+  // Users may find it convenient to turn on explicit debugging
+  // for selected modules; the below lines suggest how to do this
+#if 0 
+  DebugComponentEnable("CsmaNetDevice");
+  DebugComponentEnable("Ipv4L3Protocol");
+  DebugComponentEnable("NetDevice");
+  DebugComponentEnable("Channel");
+  DebugComponentEnable("CsmaChannel");
+  DebugComponentEnable("PacketSocket");
+#endif
+
+  // Set up some default values for the simulation.  Use the Bind()
+  // technique to tell the system what subclass of Queue to use,
+  // and what the queue limit is
+
+  // The below Bind command tells the queue factory which class to
+  // instantiate, when the queue factory is invoked in the topology code
+  DefaultValue::Bind ("Queue", "DropTailQueue");
+
+  // Allow the user to override any of the defaults and the above
+  // Bind()s at run-time, via command-line arguments
+  CommandLine::Parse (argc, argv);
+
+  // Here, we will explicitly create four nodes.  In more sophisticated
+  // topologies, we could configure a node factory.
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> (); 
+  Ptr<Node> n2 = Create<InternetNode> (); 
+  Ptr<Node> n3 = Create<InternetNode> ();
+
+  // We create the channels first without any IP addressing information
+  Ptr<CsmaChannel> channel0 = 
+    CsmaTopology::CreateCsmaChannel(
+      DataRate(5000000), MilliSeconds(2));
+
+  uint32_t n0ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n0, channel0, 
+                                         Eui48Address("10:54:23:54:23:50"));
+  uint32_t n1ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n1, channel0,
+                                         Eui48Address("10:54:23:54:23:51"));
+  uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channel0,
+                                         Eui48Address("10:54:23:54:23:52"));
+  uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n3, channel0,
+                                         Eui48Address("10:54:23:54:23:53"));
+
+  // Later, we add IP addresses.  
+  CsmaIpv4Topology::AddIpv4Address (
+      n0, n0ifIndex, Ipv4Address("10.1.1.1"), Ipv4Mask("255.255.255.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (
+      n1, n1ifIndex, Ipv4Address("10.1.1.2"), Ipv4Mask("255.255.255.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (
+      n2, n2ifIndex, Ipv4Address("10.1.1.3"), Ipv4Mask("255.255.255.0"));
+  
+  CsmaIpv4Topology::AddIpv4Address (
+      n3, n3ifIndex, Ipv4Address("10.1.1.4"), Ipv4Mask("255.255.255.0"));
+
+  // Create the OnOff application to send UDP datagrams of size
+  // 210 bytes at a rate of 448 Kb/s
+  // from n0 to n1
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress ("10.1.1.2", 80), 
+    "Udp",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+  // Start the application
+  ooff->Start(Seconds(1.0));
+  ooff->Stop (Seconds(10.0));
+
+  // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+  ooff = Create<OnOffApplication> (
+    n3, 
+    InetSocketAddress ("10.1.1.1", 80), 
+    "Udp",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+  // Start the application
+  ooff->Start(Seconds(1.1));
+  ooff->Stop (Seconds(10.0));
+ 
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+  // Trace output will be sent to the csma-one-subnet.tr file
+  AsciiTrace asciitrace ("csma-one-subnet.tr");
+  asciitrace.TraceAllNetDeviceRx ();
+  asciitrace.TraceAllQueues ();
+
+  // Also configure some tcpdump traces; each interface will be traced
+  // The output files will be named 
+  // simple-point-to-point.pcap-<nodeId>-<interfaceId>
+  // and can be read by the "tcpdump -r" command (use "-tt" option to
+  // display timestamps correctly)
+  PcapTrace pcaptrace ("csma-one-subnet.pcap");
+  pcaptrace.TraceAllIp ();
+
+  Simulator::Run ();
+    
+  Simulator::Destroy ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/csma-packet-socket.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+//       n0    n1   n2   n3
+//       |     |    |    |
+//     =====================
+//
+// - CBR/UDP flows from n0 to n1, and from n3 to n0
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+//   (i.e., DataRate of 448,000 bps)
+// - DropTail queues 
+// - Tracing of queues and packet receptions to file "csma-one-subnet.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/debug.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/eui48-address.h"
+#include "ns3/packet-socket-address.h"
+#include "ns3/socket.h"
+#include "ns3/onoff-application.h"
+#include "ns3/queue.h"
+
+using namespace ns3;
+
+static Ptr<CsmaNetDevice>
+CreateCsmaDevice (Ptr<Node> node, Ptr<CsmaChannel> channel)
+{
+  Ptr<CsmaNetDevice> device = Create<CsmaNetDevice> (node);
+  device->Attach (channel);
+  Ptr<Queue> queue = Queue::CreateDefault ();
+  device->AddQueue (queue);
+  return device;
+}
+
+
+int main (int argc, char *argv[])
+{
+  CommandLine::Parse (argc, argv);
+
+  // Here, we will explicitly create four nodes.  In more sophisticated
+  // topologies, we could configure a node factory.
+  Ptr<Node> n0 = Create<Node> ();
+  Ptr<Node> n1 = Create<Node> (); 
+  Ptr<Node> n2 = Create<Node> (); 
+  Ptr<Node> n3 = Create<Node> ();
+
+  // create the shared medium used by all csma devices.
+  Ptr<CsmaChannel> channel = Create<CsmaChannel> (DataRate(5000000), MilliSeconds(2));
+
+  // use a helper function to connect our nodes to the shared channel.
+  Ptr<NetDevice> n0If = CreateCsmaDevice (n0, channel);
+  Ptr<NetDevice> n1If = CreateCsmaDevice (n1, channel);
+  Ptr<NetDevice> n2If = CreateCsmaDevice (n2, channel);
+  Ptr<NetDevice> n3If = CreateCsmaDevice (n3, channel);
+
+
+  // create the address which identifies n1 from n0
+  PacketSocketAddress n0ToN1;
+  n0ToN1.SetSingleDevice (n0If->GetIfIndex ());      // set outgoing interface for outgoing packets
+  n0ToN1.SetPhysicalAddress (n1If->GetAddress ()); // set destination address for outgoing packets
+  n0ToN1.SetProtocol (2);            // set arbitrary protocol for outgoing packets
+
+  // create the address which identifies n0 from n3
+  PacketSocketAddress n3ToN0;
+  n3ToN0.SetSingleDevice (n3If->GetIfIndex ());
+  n3ToN0.SetPhysicalAddress (n0If->GetAddress ());
+  n3ToN0.SetProtocol (3);
+  
+  // Create the OnOff application to send raw datagrams of size
+  // 210 bytes at a rate of 448 Kb/s
+  // from n0 to n1
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    n0ToN1,
+    "Packet",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+  // Start the application
+  ooff->Start(Seconds(1.0));
+  ooff->Stop (Seconds(10.0));
+
+  // Create a similar flow from n3 to n0, starting at time 1.1 seconds
+  ooff = Create<OnOffApplication> (
+    n3, 
+    n3ToN0,
+    "Packet",
+    ConstantVariable(1), 
+    ConstantVariable(0));
+  // Start the application
+  ooff->Start(Seconds(1.1));
+  ooff->Stop (Seconds(10.0));
+ 
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+  // Trace output will be sent to the csma-packet-socket.tr file
+  AsciiTrace asciitrace ("csma-packet-socket.tr");
+  asciitrace.TraceAllNetDeviceRx ();
+  asciitrace.TraceAllQueues ();
+
+  Simulator::Run ();
+    
+  Simulator::Destroy ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/mixed-global-routing.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,199 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ *
+ */
+
+// This script exercises global routing code in a mixed point-to-point
+// and csma/cd environment
+//
+// Network topology
+//
+//  n0
+//     \ p-p
+//      \          (shared csma/cd)
+//       n2 -------------------------n3
+//      /            |        | 
+//     / p-p        n4        n5 ---------- n6
+//   n1                             p-p
+//
+// - CBR/UDP flows from n0 to n6
+// - Tracing of queues and packet receptions to file "mixed-global-routing.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/debug.h"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/csma-channel.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/csma-topology.h"
+#include "ns3/csma-ipv4-topology.h"
+#include "ns3/eui48-address.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/global-route-manager.h"
+
+using namespace ns3;
+
+int main (int argc, char *argv[])
+{
+
+  // Users may find it convenient to turn on explicit debugging
+  // for selected modules; the below lines suggest how to do this
+#if 0 
+  DebugComponentEnable ("Object");
+  DebugComponentEnable ("Queue");
+  DebugComponentEnable ("DropTailQueue");
+  DebugComponentEnable ("Channel");
+  DebugComponentEnable ("PointToPointChannel");
+  DebugComponentEnable ("PointToPointNetDevice");
+  DebugComponentEnable ("GlobalRouter");
+  DebugComponentEnable ("GlobalRouteManager");
+#endif
+
+  // Set up some default values for the simulation.  Use the Bind ()
+  // technique to tell the system what subclass of Queue to use,
+  // and what the queue limit is
+
+  // The below DefaultValue::Bind command tells the queue factory which 
+  // class to instantiate, when the queue factory is invoked in the 
+  // topology code
+  DefaultValue::Bind ("Queue", "DropTailQueue");
+
+  DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+  DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+  //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);   
+
+  // Allow the user to override any of the defaults and the above
+  // Bind ()s at run-time, via command-line arguments
+  CommandLine::Parse (argc, argv);
+
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> (); 
+  Ptr<Node> n2 = Create<InternetNode> (); 
+  Ptr<Node> n3 = Create<InternetNode> ();
+  Ptr<Node> n4 = Create<InternetNode> (); 
+  Ptr<Node> n5 = Create<InternetNode> (); 
+  Ptr<Node> n6 = Create<InternetNode> ();
+
+  // We create the channels first without any IP addressing information
+  Ptr<PointToPointChannel> channel0 = 
+    PointToPointTopology::AddPointToPointLink (
+      n0, n2, DataRate (5000000), MilliSeconds (2));
+
+  Ptr<PointToPointChannel> channel1 = 
+    PointToPointTopology::AddPointToPointLink (
+      n1, n2, DataRate (5000000), MilliSeconds (2));
+  
+  Ptr<PointToPointChannel> channel2 = 
+    PointToPointTopology::AddPointToPointLink (
+      n5, n6, DataRate (1500000), MilliSeconds (10));
+
+  // We create the channels first without any IP addressing information
+  Ptr<CsmaChannel> channelc0 = 
+    CsmaTopology::CreateCsmaChannel(
+      DataRate(5000000), MilliSeconds(2));
+
+  uint32_t n2ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n2, channelc0,
+                                         Eui48Address("10:54:23:54:23:50"));
+  uint32_t n3ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n3, channelc0,
+                                         Eui48Address("10:54:23:54:23:51"));
+  uint32_t n4ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n4, channelc0,
+                                         Eui48Address("10:54:23:54:23:52"));
+  uint32_t n5ifIndex = CsmaIpv4Topology::AddIpv4CsmaNode (n5, channelc0,
+                                         Eui48Address("10:54:23:54:23:53"));
+
+  // Later, we add IP addresses.  
+  PointToPointTopology::AddIpv4Addresses (
+      channel0, n0, Ipv4Address ("10.1.1.1"),
+      n2, Ipv4Address ("10.1.1.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel1, n1, Ipv4Address ("10.1.2.1"),
+      n2, Ipv4Address ("10.1.2.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel2, n5, Ipv4Address ("10.1.3.1"),
+      n6, Ipv4Address ("10.1.3.2"));
+
+  CsmaIpv4Topology::AddIpv4Address (
+      n2, n2ifIndex, Ipv4Address("10.250.1.1"), Ipv4Mask("255.255.255.0"));
+
+  CsmaIpv4Topology::AddIpv4Address (
+      n3, n3ifIndex, Ipv4Address("10.250.1.2"), Ipv4Mask("255.255.255.0"));
+  
+  CsmaIpv4Topology::AddIpv4Address (
+      n4, n4ifIndex, Ipv4Address("10.250.1.3"), Ipv4Mask("255.255.255.0"));
+  
+  CsmaIpv4Topology::AddIpv4Address (
+      n5, n5ifIndex, Ipv4Address("10.250.1.4"), Ipv4Mask("255.255.255.0"));
+
+  // Create router nodes, initialize routing database and set up the routing
+  // tables in the nodes.
+  GlobalRouteManager::PopulateRoutingTables ();
+
+  // Create the OnOff application to send UDP datagrams of size
+  // 210 bytes at a rate of 448 Kb/s
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress ("10.1.3.2", 80), 
+    "Udp",
+    ConstantVariable (1), 
+    ConstantVariable (0),
+    DataRate("300bps"),
+    50);
+  // Start the application
+  ooff->Start (Seconds (1.0));
+  ooff->Stop (Seconds (10.0));
+
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+  // Trace output will be sent to the simple-global-routing.tr file
+  AsciiTrace asciitrace ("mixed-global-routing.tr");
+  asciitrace.TraceAllQueues ();
+  asciitrace.TraceAllNetDeviceRx ();
+
+  // Also configure some tcpdump traces; each interface will be traced
+  // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
+  // and can be read by the "tcpdump -r" command (use "-tt" option to
+  // display timestamps correctly)
+  PcapTrace pcaptrace ("mixed-global-routing.pcap");
+  pcaptrace.TraceAllIp ();
+
+  Simulator::Run ();
+    
+  Simulator::Destroy ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/simple-global-routing.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,183 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ *
+ * ns-2 simple.tcl script (ported from ns-2)
+ * Originally authored by Steve McCanne, 12/19/1996
+ */
+
+// Port of ns-2/tcl/ex/simple.tcl to ns-3
+//
+// Network topology
+//
+//  n0
+//     \ 5 Mb/s, 2ms
+//      \          1.5Mb/s, 10ms
+//       n2 -------------------------n3
+//      /
+//     / 5 Mb/s, 2ms
+//   n1
+//
+// - all links are point-to-point links with indicated one-way BW/delay
+// - CBR/UDP flows from n0 to n3, and from n3 to n1
+// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec.
+// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec.
+//   (i.e., DataRate of 448,000 bps)
+// - DropTail queues 
+// - Tracing of queues and packet receptions to file "simple-global-routing.tr"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cassert>
+
+#include "ns3/debug.h"
+
+#include "ns3/command-line.h"
+#include "ns3/default-value.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+#include "ns3/ascii-trace.h"
+#include "ns3/pcap-trace.h"
+#include "ns3/internet-node.h"
+#include "ns3/point-to-point-channel.h"
+#include "ns3/point-to-point-net-device.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/point-to-point-topology.h"
+#include "ns3/onoff-application.h"
+#include "ns3/global-route-manager.h"
+
+using namespace ns3;
+
+int main (int argc, char *argv[])
+{
+
+  // Users may find it convenient to turn on explicit debugging
+  // for selected modules; the below lines suggest how to do this
+#if 0 
+  DebugComponentEnable ("Object");
+  DebugComponentEnable ("Queue");
+  DebugComponentEnable ("DropTailQueue");
+  DebugComponentEnable ("Channel");
+  DebugComponentEnable ("PointToPointChannel");
+  DebugComponentEnable ("PointToPointNetDevice");
+  DebugComponentEnable ("GlobalRouter");
+  DebugComponentEnable ("GlobalRouteMaager");
+#endif
+
+  // Set up some default values for the simulation.  Use the DefaultValue::Bind ()
+  // technique to tell the system what subclass of Queue to use,
+  // and what the queue limit is
+
+  // The below Bind command tells the queue factory which class to
+  // instantiate, when the queue factory is invoked in the topology code
+  DefaultValue::Bind ("Queue", "DropTailQueue");
+
+  DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+  DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
+
+  //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);   
+
+  // Allow the user to override any of the defaults and the above
+  // DefaultValue::Bind ()s at run-time, via command-line arguments
+  CommandLine::Parse (argc, argv);
+
+  // Here, we will explicitly create four nodes.  In more sophisticated
+  // topologies, we could configure a node factory.
+  Ptr<Node> n0 = Create<InternetNode> ();
+  Ptr<Node> n1 = Create<InternetNode> (); 
+  Ptr<Node> n2 = Create<InternetNode> (); 
+  Ptr<Node> n3 = Create<InternetNode> ();
+
+  // We create the channels first without any IP addressing information
+  Ptr<PointToPointChannel> channel0 = 
+    PointToPointTopology::AddPointToPointLink (
+      n0, n2, DataRate (5000000), MilliSeconds (2));
+
+  Ptr<PointToPointChannel> channel1 = 
+    PointToPointTopology::AddPointToPointLink (
+      n1, n2, DataRate (5000000), MilliSeconds (2));
+  
+  Ptr<PointToPointChannel> channel2 = 
+    PointToPointTopology::AddPointToPointLink (
+      n2, n3, DataRate (1500000), MilliSeconds (10));
+  
+  // Later, we add IP addresses.  
+  PointToPointTopology::AddIpv4Addresses (
+      channel0, n0, Ipv4Address ("10.1.1.1"),
+      n2, Ipv4Address ("10.1.1.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel1, n1, Ipv4Address ("10.1.2.1"),
+      n2, Ipv4Address ("10.1.2.2"));
+  
+  PointToPointTopology::AddIpv4Addresses (
+      channel2, n2, Ipv4Address ("10.1.3.1"),
+      n3, Ipv4Address ("10.1.3.2"));
+
+  // Create router nodes, initialize routing database and set up the routing
+  // tables in the nodes.
+  GlobalRouteManager::PopulateRoutingTables ();
+
+  // Create the OnOff application to send UDP datagrams of size
+  // 210 bytes at a rate of 448 Kb/s
+  Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
+    n0, 
+    InetSocketAddress ("10.1.3.2", 80), 
+    "Udp",
+    ConstantVariable (1), 
+    ConstantVariable (0));
+  // Start the application
+  ooff->Start (Seconds (1.0));
+  ooff->Stop (Seconds (10.0));
+
+  // Create a similar flow from n3 to n1, starting at time 1.1 seconds
+  ooff = Create<OnOffApplication> (
+    n3, 
+    InetSocketAddress ("10.1.2.1", 80),
+    "Udp",
+    ConstantVariable (1), 
+    ConstantVariable (0));
+  // Start the application
+  ooff->Start (Seconds (1.1));
+  ooff->Stop (Seconds (10.0));
+
+  // Configure tracing of all enqueue, dequeue, and NetDevice receive events
+  // Trace output will be sent to the simple-global-routing.tr file
+  AsciiTrace asciitrace ("simple-global-routing.tr");
+  asciitrace.TraceAllQueues ();
+  asciitrace.TraceAllNetDeviceRx ();
+
+  // Also configure some tcpdump traces; each interface will be traced
+  // The output files will be named simple-p2p.pcap-<nodeId>-<interfaceId>
+  // and can be read by the "tcpdump -r" command (use "-tt" option to
+  // display timestamps correctly)
+  PcapTrace pcaptrace ("simple-global-routing.pcap");
+  pcaptrace.TraceAllIp ();
+
+  Simulator::Run ();
+    
+  Simulator::Destroy ();
+
+  return 0;
+}
--- a/examples/simple-point-to-point.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/examples/simple-point-to-point.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -57,8 +57,8 @@
 #include "ns3/internet-node.h"
 #include "ns3/point-to-point-channel.h"
 #include "ns3/point-to-point-net-device.h"
-#include "ns3/mac-address.h"
 #include "ns3/ipv4-address.h"
+#include "ns3/inet-socket-address.h"
 #include "ns3/ipv4.h"
 #include "ns3/socket.h"
 #include "ns3/ipv4-route.h"
@@ -72,6 +72,7 @@
 
   // Users may find it convenient to turn on explicit debugging
   // for selected modules; the below lines suggest how to do this
+  // remember to add #include "ns3/debug.h" before enabling these
 #if 0 
   DebugComponentEnable("Object");
   DebugComponentEnable("Queue");
@@ -87,12 +88,12 @@
 
   // The below Bind command tells the queue factory which class to
   // instantiate, when the queue factory is invoked in the topology code
-  Bind ("Queue", "DropTailQueue");
+  DefaultValue::Bind ("Queue", "DropTailQueue");
 
-  Bind ("OnOffApplicationPacketSize", "210");
-  Bind ("OnOffApplicationDataRate", "448kb/s");
+  DefaultValue::Bind ("OnOffApplicationPacketSize", "210");
+  DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s");
 
-  //Bind ("DropTailQueue::m_maxPackets", 30);   
+  //DefaultValue::Bind ("DropTailQueue::m_maxPackets", 30);   
 
   // Allow the user to override any of the defaults and the above
   // Bind()s at run-time, via command-line arguments
@@ -144,8 +145,7 @@
   // 210 bytes at a rate of 448 Kb/s
   Ptr<OnOffApplication> ooff = Create<OnOffApplication> (
     n0, 
-    Ipv4Address("10.1.3.2"), 
-    80, 
+    InetSocketAddress ("10.1.3.2", 80), 
     "Udp",
     ConstantVariable(1), 
     ConstantVariable(0));
@@ -156,8 +156,7 @@
   // Create a similar flow from n3 to n1, starting at time 1.1 seconds
   ooff = Create<OnOffApplication> (
     n3, 
-    Ipv4Address("10.1.2.1"), 
-    80, 
+    InetSocketAddress ("10.1.2.1", 80), 
     "Udp",
     ConstantVariable(1), 
     ConstantVariable(0));
--- a/examples/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/examples/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -1,14 +1,23 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import Params
 
 def build(bld):
-    def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
-        obj = bld.create_obj('cpp', 'program')
-        obj.target = name
-        obj.uselib_local = ["ns3-%s" % dep for dep in deps]
-        obj.source = source
-        return obj
         
-    obj = create_ns_prog('simple-point-to-point', 'simple-point-to-point.cc', deps=['point-to-point', 'internet-node'])
-    obj = create_ns_prog('csma-cd-one-subnet', 'csma-cd-one-subnet.cc', deps=['csma-cd', 'internet-node'])
+    obj = bld.create_ns3_program('simple-global-routing',
+        ['point-to-point', 'internet-node', 'global-routing'])
+    obj.source = 'simple-global-routing.cc'
+
+    obj = bld.create_ns3_program('simple-point-to-point',
+        ['point-to-point', 'internet-node'])
+    obj.source = 'simple-point-to-point.cc'
 
+    obj = bld.create_ns3_program('csma-one-subnet',
+        ['csma', 'internet-node'])
+    obj.source = 'csma-one-subnet.cc'
+
+    obj = bld.create_ns3_program('csma-packet-socket',
+        ['csma', 'internet-node'])
+    obj.source = 'csma-packet-socket.cc'
+
+    obj = bld.create_ns3_program( 'mixed-global-routing',
+        ['point-to-point', 'internet-node', 'global-routing' , 'csma-cd'])
+    obj.source = 'mixed-global-routing.cc'
--- a/samples/main-default-value.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/main-default-value.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -73,7 +73,7 @@
   // global variable and value (string) to overwrite the default.
   // Here, the default value of 33 for testInt1 is overwritten with 57
   // 
-  Bind("testInt1", "57");
+  DefaultValue::Bind("testInt1", "57");
 
   TestClass* testclass = new TestClass ();
   NS_DEBUG_UNCOND("TestBool1 default value (" << testclass->m_testBool1 << ")");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-header.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,124 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+#include "ns3/packet.h"
+#include "ns3/header.h"
+#include <iostream>
+
+using namespace ns3;
+
+/* A sample Header implementation
+ */
+class MyHeader : public Header 
+{
+public:
+  static uint32_t GetUid (void);
+
+  MyHeader ();
+  virtual ~MyHeader ();
+
+  void SetData (uint16_t data);
+  uint16_t GetData (void) const;
+
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+  uint32_t GetSerializedSize (void) const;
+private:
+  uint16_t m_data;
+};
+
+MyHeader::MyHeader ()
+{
+  // we must provide a public default constructor, 
+  // implicit or explicit, but never private.
+}
+MyHeader::~MyHeader ()
+{}
+
+uint32_t
+MyHeader::GetUid (void)
+{
+  // This string is used by the internals of the packet
+  // code to keep track of the packet metadata.
+  // You need to make sure that this string is absolutely
+  // unique. The code will detect any duplicate string.
+  static uint32_t uid = AllocateUid<MyHeader> ("MyHeader.test.nsnam.org");
+  return uid;
+}
+
+std::string 
+MyHeader::GetName (void) const
+{
+  // This string is used to identify the type of 
+  // my header by the packet printing routines.
+  return "MYHEADER";
+}
+void 
+MyHeader::Print (std::ostream &os) const
+{
+  // This method is invoked by the packet printing
+  // routines to print the content of my header.
+  os << "data=" << m_data << std::endl;
+}
+uint32_t
+MyHeader::GetSerializedSize (void) const
+{
+  // we reserve 2 bytes for our header.
+  return 2;
+}
+void
+MyHeader::Serialize (Buffer::Iterator start) const
+{
+  // we can serialize two bytes at the start of the buffer.
+  // we write them in network byte order.
+  start.WriteHtonU16 (m_data);
+}
+uint32_t
+MyHeader::Deserialize (Buffer::Iterator start)
+{
+  // we can deserialize two bytes from the start of the buffer.
+  // we read them in network byte order and store them
+  // in host byte order.
+  m_data = start.ReadNtohU16 ();
+
+  // we return the number of bytes effectively read.
+  return 2;
+}
+
+void 
+MyHeader::SetData (uint16_t data)
+{
+  m_data = data;
+}
+uint16_t 
+MyHeader::GetData (void) const
+{
+  return m_data;
+}
+
+
+
+int main (int argc, char *argv[])
+{
+  // instantiate a header.
+  MyHeader sourceHeader;
+  sourceHeader.SetData (2);
+
+  // instantiate a packet
+  Packet p;
+  // and store my header into the packet.
+  p.AddHeader (sourceHeader);
+
+  // print the content of my packet on the standard output.
+  p.Print (std::cout);
+
+  // you can now remove the header from the packet:
+  MyHeader destinationHeader;
+  p.RemoveHeader (destinationHeader);
+
+  // and check that the destination and source
+  // headers contain the same values.
+  NS_ASSERT (sourceHeader.GetData () == destinationHeader.GetData ());
+
+  return 0;
+}
--- a/samples/main-packet-printer.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/main-packet-printer.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -90,15 +90,6 @@
   std::cout << std::endl;
 }
 
-// The below functions are used in place of default versions, in the
-// non-default case below.  For instance, DoPrintIpv4Header will print
-// out less IPv4 header information than the default print function
-void 
-DoPrintDefault (std::ostream &os,uint32_t packetUid, uint32_t size, 
-                std::string &name, struct PacketPrinter::FragmentInformation info)
-{
-  os << name <<" (size " << size << " trim_start " << info.start << " trim_end " << info.end << ")";
-}
 void
 DoPrintPayload (std::ostream & os,uint32_t packetUid,uint32_t size,
                 struct PacketPrinter::FragmentInformation info)
@@ -129,14 +120,10 @@
   // set a string separator automatically inserted
   // between each call to a printing function.
   printer.SetSeparator (" - ");
-  // set the default print function: invoked if no 
-  // specialized function has been provided for a header
-  // or trailer
-  printer.AddDefaultPrinter (MakeCallback (&DoPrintDefault));
   // set the payload print function
-  printer.AddPayloadPrinter (MakeCallback (&DoPrintPayload));
+  printer.SetPayloadPrinter (MakeCallback (&DoPrintPayload));
   // set the print function for the header type Ipv4Header.
-  printer.AddHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
+  printer.SetHeaderPrinter (MakeCallback (&DoPrintIpv4Header),
                             MakeCallback (&DoPrintIpv4HeaderFragment));
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/samples/main-packet-tag.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,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 "ns3/tag.h"
+#include "ns3/packet.h"
+#include <iostream>
+
+using namespace ns3;
+
+// define this class in a public header
+class MyTag : public Tag
+{
+public:
+  // we have to define a public constructor
+  MyTag ();
+  // we have to define a public copy constructor
+  MyTag (const MyTag &other);
+  // we have to define a public destructor
+  ~MyTag ();
+  // we have to define a public static GetUid method
+  static uint32_t GetUid (void);
+  // we have to define a public Print method
+  void Print (std::ostream &os) const;
+  // we have to define a public GetSerializedSize method
+  uint32_t GetSerializedSize (void) const;
+  // we have to define a public Serialize method
+  void Serialize (Buffer::Iterator i) const;
+  // we have to define a public Deserialize method
+  uint32_t Deserialize (Buffer::Iterator i);
+  
+  // these are our accessors to our tag structure
+  void SetSimpleValue (uint8_t value);
+  uint8_t GetSimpleValue (void) const;
+private:
+  uint8_t m_simpleValue;
+};
+
+MyTag::MyTag ()
+{}
+MyTag::MyTag (const MyTag &other)
+  : m_simpleValue (other.m_simpleValue)
+{}
+MyTag::~MyTag ()
+{}
+uint32_t 
+MyTag::GetUid (void)
+{
+  // we input a unique string to AllocateUid
+  // to avoid name collisions.
+  static uint32_t uid = AllocateUid<MyTag> ("MyTag.tests.nsnam.org");
+  return uid;
+}
+void 
+MyTag::Print (std::ostream &os) const
+{
+  // print the content of this tag for Packet::PrintTags
+  os << "MyTag=0x" << std::hex << (uint32_t)m_simpleValue << std::dec;
+}
+uint32_t 
+MyTag::GetSerializedSize (void) const
+{
+  // we do not want to deal with parallel simulations
+  // so we return 0.
+  return 0;
+}
+void 
+MyTag::Serialize (Buffer::Iterator i) const
+{
+  // we will never be invoked because we are not doing
+  // parallel simulations so, we assert.
+  NS_ASSERT (false);
+}
+uint32_t
+MyTag::Deserialize (Buffer::Iterator i)
+{
+  // we will never be invoked because we are not doing
+  // parallel simulations so, we assert.
+  NS_ASSERT (false);
+  // theoretically, return the number of bytes read
+  return 0;
+}
+
+
+void 
+MyTag::SetSimpleValue (uint8_t value)
+{
+  m_simpleValue = value;
+}
+uint8_t 
+MyTag::GetSimpleValue (void) const
+{
+  return m_simpleValue;
+}
+
+
+int main (int argc, char *argv[])
+{
+  // create a tag.
+  MyTag tag;
+  tag.SetSimpleValue (0x56);
+
+  // store the tag in a packet.
+  Packet p;
+  p.AddTag (tag);
+
+  // create a copy of the packet
+  Packet aCopy = p;
+
+  // read the tag from the packet copy
+  MyTag tagCopy;
+  p.PeekTag (tagCopy);
+
+  // the copy and the original are the same !
+  NS_ASSERT (tagCopy.GetSimpleValue () == tag.GetSimpleValue ());
+
+  aCopy.PrintTags (std::cout);
+  std::cout << std::endl;
+
+  return 0;
+}
--- a/samples/main-packet.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-#include "ns3/packet.h"
-#include "ns3/header.h"
-#include <iostream>
-
-using namespace ns3;
-
-/* A sample Header implementation
- */
-class MyHeader : public Header {
-public:
-  MyHeader ();
-  virtual ~MyHeader ();
-
-  void SetData (uint16_t data);
-  uint16_t GetData (void) const;
-private:
-  virtual std::string DoGetName (void) const;
-  virtual void PrintTo (std::ostream &os) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
-  virtual uint32_t GetSerializedSize (void) const;
-
-  uint16_t m_data;
-};
-
-MyHeader::MyHeader ()
-{}
-MyHeader::~MyHeader ()
-{}
-std::string 
-MyHeader::DoGetName (void) const
-{
-  return "MyHeader";
-}
-void 
-MyHeader::PrintTo (std::ostream &os) const
-{
-  os << "MyHeader data=" << m_data << std::endl;
-}
-uint32_t
-MyHeader::GetSerializedSize (void) const
-{
-  return 2;
-}
-void
-MyHeader::SerializeTo (Buffer::Iterator start) const
-{
-  // serialize in head of buffer
-  start.WriteHtonU16 (m_data);
-}
-uint32_t
-MyHeader::DeserializeFrom (Buffer::Iterator start)
-{
-  // deserialize from head of buffer
-  m_data = start.ReadNtohU16 ();
-  return GetSerializedSize ();
-}
-
-void 
-MyHeader::SetData (uint16_t data)
-{
-  m_data = data;
-}
-uint16_t 
-MyHeader::GetData (void) const
-{
-  return m_data;
-}
-
-/* A sample Tag implementation
- */
-struct MyTag {
-  uint16_t m_streamId;
-};
-
-static TagRegistration<struct MyTag> g_MyTagRegistration ("ns3::MyTag", 0);
-
-
-static void
-Receive (Packet p)
-{
-  MyHeader my;
-  p.RemoveHeader (my);
-  std::cout << "received data=" << my.GetData () << std::endl;
-  struct MyTag myTag;
-  p.PeekTag (myTag);
-}
-
-
-int main (int argc, char *argv[])
-{
-  Packet p;
-  MyHeader my;
-  my.SetData (2);
-  std::cout << "send data=2" << std::endl;
-  p.AddHeader (my);
-  struct MyTag myTag;
-  myTag.m_streamId = 5;
-  p.AddTag (myTag);
-  Receive (p);
-  return 0;
-}
--- a/samples/main-random-topology.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/main-random-topology.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -24,12 +24,12 @@
 
 int main (int argc, char *argv[])
 {
-  Bind ("RandomDiscPositionX", "100");
-  Bind ("RandomDiscPositionY", "50");
-  Bind ("RandomDiscPositionRho", "Uniform:0:30");
+  DefaultValue::Bind ("RandomDiscPositionX", "100");
+  DefaultValue::Bind ("RandomDiscPositionY", "50");
+  DefaultValue::Bind ("RandomDiscPositionRho", "Uniform:0:30");
 
-  Bind ("RandomTopologyPositionType", "RandomDiscPosition");
-  Bind ("RandomTopologyMobilityType", "StaticMobilityModel");
+  DefaultValue::Bind ("RandomTopologyPositionType", "RandomDiscPosition");
+  DefaultValue::Bind ("RandomTopologyMobilityType", "StaticMobilityModel");
 
   CommandLine::Parse (argc, argv);
 
--- a/samples/main-simple.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/main-simple.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -4,7 +4,9 @@
 #include "ns3/simulator.h"
 #include "ns3/socket-factory.h"
 #include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
 #include "ns3/nstime.h"
+#include "ns3/packet.h"
 
 using namespace ns3;
 
@@ -12,7 +14,7 @@
 GenerateTraffic (Ptr<Socket> socket, uint32_t size)
 {
   std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, tx bytes=" << size << std::endl;
-  socket->Send (0, size);
+  socket->Send (Packet (size));
   if (size > 0)
     {
       Simulator::Schedule (Seconds (0.5), &GenerateTraffic, socket, size - 50);
@@ -24,15 +26,15 @@
 }
 
 static void
-SocketPrinter (Ptr<Socket> socket, uint32_t size, const Ipv4Address &from, uint16_t fromPort)
+SocketPrinter (Ptr<Socket> socket, const Packet &packet, const Address &from)
 {
-  std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << size << std::endl;
+  std::cout << "at=" << Simulator::Now ().GetSeconds () << "s, rx bytes=" << packet.GetSize () << std::endl;
 }
 
 static void
 PrintTraffic (Ptr<Socket> socket)
 {
-  socket->RecvDummy (MakeCallback (&SocketPrinter));
+  socket->SetRecvCallback (MakeCallback (&SocketPrinter));
 }
 
 void
@@ -44,10 +46,12 @@
   Ptr<SocketFactory> socketFactory = a->QueryInterface<SocketFactory> (iid);
 
   Ptr<Socket> sink = socketFactory->CreateSocket ();
-  sink->Bind (80);
+  InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 80);
+  sink->Bind (local);
 
   Ptr<Socket> source = socketFactory->CreateSocket ();
-  source->Connect (Ipv4Address::GetLoopback (), 80);
+  InetSocketAddress remote = InetSocketAddress (Ipv4Address::GetLoopback (), 80);
+  source->Connect (remote);
 
   GenerateTraffic (source, 500);
   PrintTraffic (sink);
--- a/samples/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/samples/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -1,28 +1,43 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-import Params
 
 def build(bld):
-    def create_ns_prog(name, source, deps=['core', 'common', 'simulator']):
-        obj = bld.create_obj('cpp', 'program')
-        obj.target = name
-        obj.uselib_local = ["ns3-%s" % dep for dep in deps]
-        obj.source = source
-        return obj
-        
-    obj = create_ns_prog('main-debug', ['main-debug.cc', 'main-debug-other.cc'])
-    obj = create_ns_prog('main-callback', 'main-callback.cc')
-    obj = create_ns_prog('main-ptr', 'main-ptr.cc')
-    #obj = create_ns_prog('main-trace', 'main-trace.cc')
-    obj = create_ns_prog('main-simulator', 'main-simulator.cc')
-    obj = create_ns_prog('main-packet', 'main-packet.cc')
-    obj = create_ns_prog('main-test', 'main-test.cc')
-    obj = create_ns_prog('main-simple', 'main-simple.cc',
-                         deps=['node', 'internet-node', 'applications'])
-    #obj = create_ns_prog('main-simple-p2p', 'main-simple-p2p.cc', deps=['node', 'point-to-point'])
-    obj = create_ns_prog('main-default-value', 'main-default-value.cc',
-                         deps=['core', 'simulator', 'node', 'point-to-point'])
-    obj = create_ns_prog('main-grid-topology', 'main-grid-topology.cc',
-                         deps=['core', 'simulator', 'mobility', 'internet-node'])
-    obj = create_ns_prog('main-random-topology', 'main-random-topology.cc',
-                         deps=['core', 'simulator', 'mobility'])
+    obj = bld.create_ns3_program('main-debug')
+    obj.source = ['main-debug.cc', 'main-debug-other.cc']
+
+    obj = bld.create_ns3_program('main-callback')
+    obj.source = 'main-callback.cc'
+
+    obj = bld.create_ns3_program('main-ptr')
+    obj.source = 'main-ptr.cc'
+
+    obj = bld.create_ns3_program('main-simulator')
+    obj.source = 'main-simulator.cc'
+
+    obj = bld.create_ns3_program('main-packet-header', ['common', 'simulator'])
+    obj.source = 'main-packet-header.cc'
+
+    obj = bld.create_ns3_program('main-packet-tag', ['common', 'simulator'])
+    obj.source = 'main-packet-tag.cc'
 
+    obj = bld.create_ns3_program('main-packet-printer', ['common', 'simulator', 'internet-node'])
+    obj.source = 'main-packet-printer.cc'
+
+    obj = bld.create_ns3_program('main-test')
+    obj.source = 'main-test.cc'
+
+    obj = bld.create_ns3_program('main-simple',
+                                 ['node', 'internet-node', 'applications'])
+    obj.source = 'main-simple.cc'
+
+    obj = bld.create_ns3_program('main-default-value',
+                                 ['core', 'simulator', 'node', 'point-to-point'])
+    obj.source = 'main-default-value.cc'
+
+    obj = bld.create_ns3_program('main-grid-topology',
+                                 ['core', 'simulator', 'mobility', 'internet-node'])
+    obj.source = 'main-grid-topology.cc'
+
+    obj = bld.create_ns3_program('main-random-topology',
+                                 ['core', 'simulator', 'mobility'])
+    obj.source = 'main-random-topology.cc'
+
--- a/src/applications/onoff-application.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/applications/onoff-application.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -22,7 +22,7 @@
 // George F. Riley, Georgia Tech, Spring 2007
 // Adapted from ApplicationOnOff in GTNetS.
 
-#include "ns3/ipv4-address.h"
+#include "ns3/address.h"
 #include "ns3/node.h"
 #include "ns3/nstime.h"
 #include "ns3/data-rate.h"
@@ -31,6 +31,7 @@
 #include "ns3/simulator.h"
 #include "ns3/socket-factory.h"
 #include "ns3/default-value.h"
+#include "ns3/packet.h"
 #include "onoff-application.h"
 
 using namespace std;
@@ -47,22 +48,20 @@
 // Constructors
 
 OnOffApplication::OnOffApplication(Ptr<Node> n, 
-                                   const Ipv4Address  rip,
-                                   uint16_t rport,
+                                   const Address &remote,
                                    std::string iid,
                                    const  RandomVariable& ontime,
                                    const  RandomVariable& offtime)
   :  Application(n),
      m_cbrRate (g_defaultRate.GetValue ())
 {
-  Construct (n, rip, rport, iid,
+  Construct (n, remote, iid,
              ontime, offtime, 
              g_defaultSize.GetValue ());
 }
 
 OnOffApplication::OnOffApplication(Ptr<Node> n, 
-                                   const Ipv4Address  rip,
-                                   uint16_t rport,
+                                   const Address &remote,
                                    std::string iid,
                                    const  RandomVariable& ontime,
                                    const  RandomVariable& offtime,
@@ -71,22 +70,20 @@
   :  Application(n),
      m_cbrRate (rate)
 {
-  Construct (n, rip, rport, iid, 
+  Construct (n, remote, iid, 
              ontime, offtime, size);
 }
 
 void
 OnOffApplication::Construct (Ptr<Node> n, 
-                             const Ipv4Address  rip,
-                             uint16_t rport,
+                             const Address &remote,
                              std::string iid,
                              const  RandomVariable& onTime,
                              const  RandomVariable& offTime,
                              uint32_t size)
 {
   m_socket = 0;
-  m_peerIp = rip;
-  m_peerPort = rport;
+  m_peer = remote;
   m_connected = false;
   m_onTime = onTime.Copy ();
   m_offTime = offTime.Copy ();
@@ -144,7 +141,7 @@
       Ptr<SocketFactory> socketFactory = GetNode ()->QueryInterface<SocketFactory> (iid);
       m_socket = socketFactory->CreateSocket ();
       m_socket->Bind ();
-      m_socket->Connect (m_peerIp, m_peerPort);
+      m_socket->Connect (m_peer);
     }
   // Insure no pending event
   StopApplication();
@@ -209,7 +206,7 @@
 void OnOffApplication::SendPacket()
 {
   NS_ASSERT (m_sendEvent.IsExpired ());
-  m_socket->Send(0, m_pktSize);
+  m_socket->Send(Packet (m_pktSize));
   m_totBytes += m_pktSize;
   m_lastStartTime = Simulator::Now();
   m_residualBits = 0;
--- a/src/applications/onoff-application.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/applications/onoff-application.h	Wed Sep 05 18:35:39 2007 +0100
@@ -28,13 +28,13 @@
 #include "ns3/application.h"
 #include "ns3/event-id.h"
 #include "ns3/ptr.h"
+#include "ns3/data-rate.h"
 
 namespace ns3 {
 
-class Ipv4Address;
+class Address;
 class RandomVariable;
 class Socket;
-class DataRate;
 
 /**
  * \brief Generate traffic to a single destination according to an
@@ -52,23 +52,20 @@
 public:
   /**
    * \param n node associated to this application
-   * \param rip remote ip address
-   * \param rport remove port number
+   * \param remote remote ip address
    * \param iid
    * \param ontime on time random variable
    * \param offtime off time random variable
    */
   OnOffApplication(Ptr<Node> n,
-                   const Ipv4Address rip,
-                   uint16_t rport,
+                   const Address &remote,
                    std::string iid,
                    const RandomVariable& ontime,
                    const RandomVariable& offtime);
 
   /**
    * \param n node associated to this application
-   * \param rip remote ip address
-   * \param rport remove port number
+   * \param remote remote ip address
    * \param iid
    * \param ontime on time random variable
    * \param offtime off time random variable
@@ -76,8 +73,7 @@
    * \param size size of packets when sending data.
    */
   OnOffApplication(Ptr<Node> n,
-                   const Ipv4Address rip,
-                   uint16_t rport,
+                   const Address &remote,
                    std::string iid,
                    const RandomVariable& ontime,
                    const RandomVariable& offtime,
@@ -112,8 +108,7 @@
   virtual void StopApplication (void);     // Called at time specified by Stop
 
   void Construct (Ptr<Node> n,
-                  const Ipv4Address rip,
-                  uint16_t rport,
+                  const Address &remote,
                   std::string iid,
                   const RandomVariable& ontime,
                   const RandomVariable& offtime,
@@ -126,8 +121,7 @@
   void SendPacket();
 
   Ptr<Socket>     m_socket;       // Associated socket
-  Ipv4Address     m_peerIp;       // Peer IP address
-  uint16_t        m_peerPort;     // Peer port
+  Address         m_peer;         // Peer address
   bool            m_connected;    // True if connected
   RandomVariable* m_onTime;       // rng for On Time
   RandomVariable* m_offTime;      // rng for Off Time
--- a/src/applications/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/applications/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -1,10 +1,7 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
 def build(bld):
-    obj = bld.create_obj('cpp', 'shlib')
-    obj.name = 'ns3-applications'
-    obj.target = obj.name
-    obj.uselib_local = ['ns3-node']
+    obj = bld.create_ns3_module('applications', ['node'])
     obj.source = [
         'onoff-application.cc',
         ]
--- a/src/common/array-trace-resolver.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/array-trace-resolver.h	Wed Sep 05 18:35:39 2007 +0100
@@ -32,39 +32,11 @@
  * \brief a helper class to offer trace resolution for an array of objects.
  * \ingroup lowleveltracing
  */
-template <typename T>
+template <typename T, typename INDEX>
 class ArrayTraceResolver : public TraceResolver
 {
 public:
   /**
-   * \brief array index trace context
-   *
-   * During namespace parsing, ns3::ArrayTraceResolver will
-   * embed an instance of this class in the TraceContext 
-   * associated to every child object of the object stored
-   * at the index.
-   *
-   * The reason why this class exists is to ensure that we 
-   * need to ensure that we can store a unique type as context 
-   * into the TraceContext associated to this trace resolver.
-   */
-  class Index
-  {
-  public:
-    Index ();
-    Index (uint32_t index);
-    /**
-     * The Index is automatically convertible to the 
-     * uin32_t type such that it really behaves like a uint32_t
-     * array index for the user. 
-     *
-     * \returns the index itself
-     */
-    operator uint32_t ();
-  private:
-    uint32_t m_index;
-  };
-  /**
    * \param context trace context associated to this trace resolver
    * \param getSize callback which returns dynamically the size of underlying array
    * \param get callback which returns any element in the underlying array
@@ -81,51 +53,37 @@
    */
   ArrayTraceResolver (TraceContext const &context,
                       Callback<uint32_t> getSize, 
-                      Callback<T *, uint32_t> get);
+                      Callback<T, uint32_t> get);
 private:
   virtual TraceResolverList DoLookup (std::string id) const;
   Callback<uint32_t> m_getSize;
-  Callback<T *, uint32_t> m_get;
+  Callback<T, uint32_t> m_get;
 };
 }//namespace ns3
 
 namespace ns3 {
 
-template <typename T>
-ArrayTraceResolver<T>::Index::Index ()
-  : m_index ()
-{}
-template <typename T>
-ArrayTraceResolver<T>::Index::Index (uint32_t index)
-  : m_index (index)
-{}
-template <typename T>
-ArrayTraceResolver<T>::Index::operator uint32_t ()
-{
-  return m_index;
-}
-
-template <typename T>
-ArrayTraceResolver<T>::ArrayTraceResolver (TraceContext const &context,
-                                           Callback<uint32_t> getSize, 
-                                           Callback<T *, uint32_t> get)
+template <typename T, typename INDEX>
+ArrayTraceResolver<T,INDEX>::ArrayTraceResolver (TraceContext const &context,
+                                                 Callback<uint32_t> getSize, 
+                                                 Callback<T, uint32_t> get)
   : TraceResolver (context),
     m_getSize (getSize),
     m_get (get)
 {}
-template <typename T>
+template <typename T, typename INDEX>
 TraceResolver::TraceResolverList 
-ArrayTraceResolver<T>::DoLookup (std::string id) const
+ArrayTraceResolver<T,INDEX>::DoLookup (std::string id) const
 {
   TraceResolverList list;
   if (id == "*")
   {
     for (uint32_t i = 0; i < m_getSize (); i++)
     {
-	  TraceContext context = GetContext ();
-      typename ArrayTraceResolver<T>::Index index = typename ArrayTraceResolver<T>::Index (i);
-	  context.Add (index);
-	  list.push_back (m_get (i)->CreateTraceResolver (context));
+      TraceContext context = GetContext ();
+      INDEX index = i;
+      context.Add (index);
+      list.push_back (m_get (i)->CreateTraceResolver (context));
     }
   }
   return list;
--- a/src/common/buffer.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/buffer.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -410,8 +410,8 @@
   return tmp;
 }
 
-void
-Buffer::TransformIntoRealBuffer (void) const
+Buffer 
+Buffer::CreateFullCopy (void) const
 {
   if (m_zeroAreaSize != 0) 
     {
@@ -428,8 +428,16 @@
       Buffer::Iterator i = tmp.End ();
       i.Prev (dataEnd);
       i.Write (m_data->m_data+m_data->m_initialStart,dataEnd);
-      *const_cast<Buffer *> (this) = tmp;
+      return tmp;
     }
+  return *this;
+}
+
+void
+Buffer::TransformIntoRealBuffer (void) const
+{
+  Buffer tmp = CreateFullCopy ();
+  *const_cast<Buffer *> (this) = tmp;
 }
 
 
--- a/src/common/buffer.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/buffer.h	Wed Sep 05 18:35:39 2007 +0100
@@ -320,7 +320,7 @@
    */
   inline Buffer::Iterator End (void) const;
 
-  void TransformIntoRealBuffer (void) const;
+  Buffer CreateFullCopy (void) const;
 
   inline Buffer (Buffer const &o);
   inline Buffer &operator = (Buffer const &o);
@@ -343,6 +343,7 @@
   };
 
   inline uint8_t *GetStart (void) const;
+  void TransformIntoRealBuffer (void) const;
   static void Recycle (struct Buffer::BufferData *data);
   static struct Buffer::BufferData *Create (void);
   static struct Buffer::BufferData *Allocate (uint32_t size, uint32_t start);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/chunk-registry.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,117 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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 "chunk-registry.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+ChunkRegistry::InfoVector *
+ChunkRegistry::GetInfoVector (void)
+{
+  static InfoVector vec;
+  return &vec;
+}
+
+std::string 
+ChunkRegistry::GetUidStringFromUid (uint32_t uid)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.uidString;
+}
+uint32_t 
+ChunkRegistry::GetUidFromUidString (std::string uidString)
+{
+  uint32_t uid = 1;
+  InfoVector *vec = GetInfoVector ();
+  for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == uidString)
+	{
+	  return uid;
+	}
+      uid++;
+    }
+  NS_FATAL_ERROR ("Trying to access a non-registered Header or Trailer: \"" << uidString << "\". "<<
+		  "You could try calling NS_HEADER_ENSURE_REGISTER somewhere.");
+  return 0;
+}
+
+uint8_t *
+ChunkRegistry::GetStaticInstance (uint32_t uid)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.getStaticInstance ();
+}
+bool 
+ChunkRegistry::IsHeader (uint32_t uid)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.isHeader;
+}
+bool 
+ChunkRegistry::IsTrailer (uint32_t uid)
+{
+  return !IsHeader (uid);
+}
+uint32_t 
+ChunkRegistry::Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.deserialize (instance, i);
+}
+void 
+ChunkRegistry::Print (uint32_t uid, uint8_t *instance, std::ostream &os)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.print (instance, os);
+}
+std::string
+ChunkRegistry::GetName (uint32_t uid, uint8_t *instance)
+{ 
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  return info.getName (instance);
+}
+void 
+ChunkRegistry::InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
+				    uint32_t packetUid, uint32_t size, 
+				    Ptr<CallbackImplBase> callback)
+{
+  InfoVector *vec = GetInfoVector ();
+  NS_ASSERT (uid >= 1 && uid <= vec->size ());
+  Info info = (*vec)[uid - 1];
+  info.invokePrintCallback (instance, os, packetUid, size, callback);
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/chunk-registry.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,180 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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 CHUNK_REGISTRY_H
+#define CHUNK_REGISTRY_H
+
+#include <stdint.h>
+#include <ostream>
+#include "buffer.h"
+#include "ns3/ptr.h"
+#include "ns3/callback.h"
+
+namespace ns3 {
+
+/**
+ * \brief this registry keeps track of all different
+ * types of headers and trailers and assigns to each of them
+ * a unique integer.
+ * \internal
+ */
+class ChunkRegistry
+{
+public:
+  template <typename T>
+  static uint32_t RegisterHeader (std::string uuid);
+  template <typename T>
+  static uint32_t RegisterTrailer (std::string uuid);
+
+  static std::string GetUidStringFromUid (uint32_t uid);
+  static uint32_t GetUidFromUidString (std::string uidString);
+  static uint8_t *GetStaticInstance (uint32_t uid);
+  static uint32_t Deserialize (uint32_t uid, uint8_t *instance, Buffer::Iterator i);
+  static void Print (uint32_t uid, uint8_t *instance, std::ostream &os);
+  static std::string GetName (uint32_t uid, uint8_t *instance);
+  static bool IsHeader (uint32_t uid);
+  static bool IsTrailer (uint32_t uid);
+  static void InvokePrintCallback (uint32_t uid, uint8_t *instance, std::ostream &os,
+				   uint32_t packetUid, uint32_t size, 
+				   Ptr<CallbackImplBase> callback);
+private:
+  typedef uint8_t *(*GetStaticInstanceCb) (void);
+  typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
+  typedef void (*PrintCb) (uint8_t *,std::ostream &);
+  typedef std::string (*GetNameCb) (uint8_t *);
+  typedef void (*InvokePrintCallbackCb) (uint8_t *instance, std::ostream &os,
+					 uint32_t packetUid, uint32_t size, 
+					 Ptr<CallbackImplBase> callback);
+  struct Info {
+    std::string uidString;
+    bool isHeader;
+    GetStaticInstanceCb getStaticInstance;
+    DeserializeCb deserialize;
+    PrintCb print;
+    GetNameCb getName;
+    InvokePrintCallbackCb invokePrintCallback;
+  };
+  typedef std::vector<struct Info> InfoVector;
+  static InfoVector *GetInfoVector (void);
+  template <typename T>
+  static uint8_t *DoGetStaticInstance (void);
+  template <typename T>
+  static uint32_t DoDeserialize (uint8_t *instance, Buffer::Iterator i);
+  template <typename T>
+  static void DoPrint (uint8_t *instance, std::ostream &os);
+  template <typename T>
+  static std::string DoGetName (uint8_t *instance);
+  template <typename T>
+  static void DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
+				     uint32_t packetUid, uint32_t size, 
+				     Ptr<CallbackImplBase> callback);
+  template <typename T>
+  static uint32_t GetUid (bool isHeader, std::string uidString);
+
+};
+
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t 
+ChunkRegistry::RegisterHeader (std::string uuid)
+{
+  return GetUid<T> (true, uuid);
+}
+template <typename T>
+uint32_t 
+ChunkRegistry::RegisterTrailer (std::string uuid)
+{
+  return GetUid<T> (false, uuid);
+}
+
+template <typename T>
+uint32_t 
+ChunkRegistry::GetUid (bool isHeader, std::string uidString)
+{
+  InfoVector *vec = GetInfoVector ();
+  uint32_t uid = 1; 
+  for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == uidString)
+	{
+	  return uid;
+	}
+      uid++;
+    }
+  Info info;
+  info.getStaticInstance = &ChunkRegistry::DoGetStaticInstance<T>;
+  info.print = &ChunkRegistry::DoPrint<T>;
+  info.getName = &ChunkRegistry::DoGetName<T>;
+  info.deserialize = &ChunkRegistry::DoDeserialize<T>;
+  info.invokePrintCallback = &ChunkRegistry::DoInvokePrintCallback<T>;
+  info.uidString = uidString;
+  info.isHeader = isHeader;
+  vec->push_back (info);
+  return vec->size ();
+}
+
+template <typename T>
+uint8_t *
+ChunkRegistry::DoGetStaticInstance ()
+{
+  static T instance;
+  return reinterpret_cast<uint8_t *> (&instance);
+}
+template <typename T>
+uint32_t 
+ChunkRegistry::DoDeserialize (uint8_t *instance, Buffer::Iterator i)
+{
+  T *obj = reinterpret_cast<T *> (instance);
+  return obj->Deserialize (i);
+}
+template <typename T>
+void 
+ChunkRegistry::DoPrint (uint8_t *instance, std::ostream &os)
+{
+  T *obj = reinterpret_cast<T *> (instance);
+  obj->Print (os);
+}
+template <typename T>
+std::string
+ChunkRegistry::DoGetName (uint8_t *instance)
+{
+  T *obj = reinterpret_cast<T *> (instance);
+  return obj->GetName ();
+}
+template <typename T>
+void 
+ChunkRegistry::DoInvokePrintCallback (uint8_t *instance, std::ostream &os,
+				      uint32_t packetUid, uint32_t size, 
+				      Ptr<CallbackImplBase> callback)
+{
+  T *obj = reinterpret_cast<T *> (instance);
+  Callback<void,std::ostream&,uint32_t,uint32_t,const T*> cb;
+  cb.Assign (callback);
+  cb (os, packetUid, size, obj);
+}
+
+} // namespace ns3
+
+#endif /* CHUNK_H */
--- a/src/common/chunk.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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 "chunk.h"
-#include "ns3/assert.h"
-
-namespace ns3 {
-
-Chunk::Chunk ()
-{}
-
-Chunk::~Chunk ()
-{}
-
-std::string
-Chunk::GetName (void) const
-{
-  return DoGetName ();
-}
-void 
-Chunk::Print (std::ostream &os) const
-{
-  PrintTo (os);
-}
-uint32_t
-Chunk::GetSize (void) const
-{
-  return GetSerializedSize ();
-}
-void
-Chunk::Serialize (Buffer::Iterator start) const
-{
-  SerializeTo (start);
-}
-uint32_t
-Chunk::Deserialize (Buffer::Iterator start)
-{
-  uint32_t deserialized = DeserializeFrom (start);
-  return deserialized;
-}
-std::ostream& operator<< (std::ostream& os, Chunk const& chunk)
-{
-  chunk.Print (os);
-  return os;
-}
-
-}; // namespace ns3
--- a/src/common/chunk.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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 CHUNK_H
-#define CHUNK_H
-
-#include <stdint.h>
-#include <ostream>
-#include "buffer.h"
-
-namespace ns3 {
-
-class Chunk {
-public:
-  Chunk ();
-  virtual ~Chunk ();
-
-  std::string GetName (void) const;
-  void Print (std::ostream &os) const;
-  uint32_t GetSize (void) const;
-  void Serialize (Buffer::Iterator start) const;
-  uint32_t Deserialize (Buffer::Iterator start);
-private:
-  virtual std::string DoGetName (void) const = 0;
-  virtual void PrintTo (std::ostream &os) const = 0;
-  virtual uint32_t GetSerializedSize (void) const = 0;
-  virtual void SerializeTo (Buffer::Iterator i) const = 0;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator i) = 0;
-};
-
-std::ostream& operator<< (std::ostream& os, Chunk const& chunk);
-
-}; // namespace ns3
-
-#endif /* CHUNK_H */
--- a/src/common/composite-trace-resolver.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/composite-trace-resolver.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -30,6 +30,14 @@
 {}
 
 void 
+CompositeTraceResolver::Add (std::string name, 
+                             Callback<TraceResolver *,TraceContext const &> createResolver)
+{
+  TraceContext traceContext = GetContext ();
+  DoAdd (name, createResolver, traceContext);
+}
+
+void 
 CompositeTraceResolver::DoAdd (std::string name, 
 			       Callback<TraceResolver *,TraceContext const &> createResolver,
 			       TraceContext const &context)
@@ -107,20 +115,53 @@
 #ifdef RUN_SELF_TESTS
 
 #include "ns3/test.h"
+#include "trace-context-element.h"
 
 namespace ns3 {
 
+class TraceSourceTest : public TraceContextElement
+{
+public:
+  enum Sources {
+    DOUBLEA,
+    DOUBLEB,
+    SUBRESOLVER,
+  };
+  static uint16_t GetUid (void) 
+  {static uint16_t uid = AllocateUid<TraceSourceTest> ("TraceSourceTest"); return uid;}
+  void Print (std::ostream &os)
+  {os << "tracesource=";
+    if (m_sources == DOUBLEA) {os << "doubleA";}
+    else if (m_sources == DOUBLEB) {os << "doubleB";}
+    else if (m_sources == SUBRESOLVER) {os << "subresolver";}
+  }
+  TraceSourceTest () : m_sources (TraceSourceTest::DOUBLEA) {}
+  TraceSourceTest (enum Sources sources) :m_sources (sources) {}
+  bool IsDoubleA (void) {return m_sources == TraceSourceTest::DOUBLEA;}
+  bool IsDoubleB (void) {return m_sources == TraceSourceTest::DOUBLEB;}
+private:
+  enum TraceSourceTest::Sources m_sources;
+};
+
+class SubTraceSourceTest : public TraceContextElement
+{
+public:
+  enum Sources {
+    INT,
+  };
+  static uint16_t GetUid (void) 
+  {static uint16_t uid = AllocateUid<SubTraceSourceTest> ("SubTraceSourceTest"); return uid;}
+  void Print (std::ostream &os)
+  {os << "subtracesource=int";}
+  SubTraceSourceTest () : m_sources (SubTraceSourceTest::INT) {}
+  SubTraceSourceTest (enum Sources sources) : m_sources (sources) {}
+private:
+  enum Sources m_sources;
+};
+
 class CompositeTraceResolverTest : public Test
 {
 public:
-  enum TraceSources {
-    TEST_TRACE_DOUBLEA,
-    TEST_TRACE_DOUBLEB,
-    TEST_TRACE_SUBRESOLVER,
-  };
-  enum SubTraceSources {
-    TEST_SUBTRACE_INT,
-  };
   CompositeTraceResolverTest ();
   virtual ~CompositeTraceResolverTest ();
   virtual bool RunTests (void);
@@ -144,19 +185,19 @@
 void 
 CompositeTraceResolverTest::TraceDouble (TraceContext const &context, double v)
 {
-  enum CompositeTraceResolverTest::TraceSources source;
+  TraceSourceTest source;
   context.Get (source);
-  switch (source)
+  if (source.IsDoubleA ())
     {
-    case TEST_TRACE_DOUBLEA:
       m_gotDoubleA = true;
-      break;
-    case TEST_TRACE_DOUBLEB:
+    }
+  else if (source.IsDoubleB ())
+    {
       m_gotDoubleB = true;
-      break;
-    default:
+    }
+  else
+    {
       NS_FATAL_ERROR ("should not get any other trace source in this sink");
-      break;
     }
   
 }
@@ -171,7 +212,8 @@
 CompositeTraceResolverTest::CreateSubResolver (TraceContext const &context)
 {
   CompositeTraceResolver *subresolver = new CompositeTraceResolver (context);
-  subresolver->Add ("trace-int", m_traceInt, TEST_SUBTRACE_INT);
+  subresolver->Add ("trace-int", m_traceInt, 
+                    SubTraceSourceTest (SubTraceSourceTest::INT));
   return subresolver;
 }
 bool 
@@ -185,8 +227,10 @@
 
   CompositeTraceResolver resolver (context) ;
 
-  resolver.Add ("trace-double-a", traceDoubleA, TEST_TRACE_DOUBLEA);
-  resolver.Add ("trace-double-b", traceDoubleB, TEST_TRACE_DOUBLEB);
+  resolver.Add ("trace-double-a", traceDoubleA, 
+                TraceSourceTest (TraceSourceTest::DOUBLEA));
+  resolver.Add ("trace-double-b", traceDoubleB, 
+                TraceSourceTest (TraceSourceTest::DOUBLEB));
 
   resolver.Connect ("/*", MakeCallback (&CompositeTraceResolverTest::TraceDouble, this));
 
@@ -279,7 +323,7 @@
 
   resolver.Add ("subresolver", 
 		MakeCallback (&CompositeTraceResolverTest::CreateSubResolver, this),
-		TEST_TRACE_SUBRESOLVER);
+		TraceSourceTest (TraceSourceTest::SUBRESOLVER));
 
   resolver.Connect ("/subresolver/trace-int", 
 		    MakeCallback (&CompositeTraceResolverTest::TraceInt, this));
--- a/src/common/composite-trace-resolver.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/composite-trace-resolver.h	Wed Sep 05 18:35:39 2007 +0100
@@ -111,6 +111,18 @@
   void Add (std::string name, 
             Callback<TraceResolver *,TraceContext const &> createResolver,
             T const &context);
+
+  /**
+   * \param name name of child trace resolver
+   * \param createResolver a trace resolver constructor
+   *
+   * Add a child trace resolver to this resolver. This child
+   * trace resolver will match the name specified during
+   * namespace resolution. When this happens, the constructor
+   * will be invoked to create the child trace resolver.
+   */
+  void Add (std::string name, 
+            Callback<TraceResolver *,TraceContext const &> createResolver);
 private:
   template <typename SOURCE, typename CONTEXT>
   void DoAddTraceSource (std::string name,
@@ -205,7 +217,6 @@
   DoAdd (name, createResolver, traceContext);
 }
 
-
 }//namespace ns3
 
 #endif /* COMPOSITE_TRACE_RESOLVER_H */
--- a/src/common/header.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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 "header.h"
-
-namespace ns3 {
-
-Header::~Header ()
-{}
-
-}; // namespace ns3
--- a/src/common/header.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/header.h	Wed Sep 05 18:35:39 2007 +0100
@@ -22,7 +22,29 @@
 #ifndef HEADER_H
 #define HEADER_H
 
-#include "chunk.h"
+#include "chunk-registry.h"
+
+/**
+ * \relates ns3::Header
+ * \brief this macro should be instantiated exactly once for each
+ *        new type of Header
+ *
+ * This macro will ensure that your new Header type is registered
+ * within the packet header registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_HEADER_ENSURE_REGISTERED(x)         \
+static class thisisaveryverylongclassname ##x  \
+{                                              \
+ public:                                       \
+  thisisaveryverylongclassname ##x ()          \
+    { uint32_t uid; uid = x::GetUid ();}       \
+} g_thisisanotherveryveryverylongname ## x;
+
 
 namespace ns3 {
 
@@ -30,68 +52,64 @@
  * \brief Protocol header serialization and deserialization.
  *
  * Every Protocol header which needs to be inserted or removed
- * from a Packet instance must derive from this abstract base class
- * and implement the private pure virtual methods listed below:
- *   - ns3::Header::SerializeTo
- *   - ns3::Header::DeserializeFrom
- *   - ns3::Header::GetSerializedSize
- *   - ns3::Header::PrintTo
+ * from a Packet instance must derive from this base class and
+ * implement the following public methods:
+ *   - a default constructor: is used by the internal implementation
+ *     if the Packet class.
+ *   - a static method named GetUid: is used to uniquely identify
+ *     the type of each header. This method shall return a unique
+ *     integer allocated with Header::AllocateUid.
+ *   - a method named Serialize: is used by Packet::AddHeader to
+ *     store a header into the byte buffer of a packet.
+ *     The input iterator points to the start of the byte buffer in
+ *     which the header should write its data. The data written
+ *     is expected to match bit-for-bit the representation of this
+ *     header in a real network.
+ *   - a method named GetSerializedSize: is used by Packet::AddHeader
+ *     to store a header into the byte buffer of a packet. This method
+ *     should return the number of bytes which are needed to store
+ *     the full header data by Serialize.
+ *   - a method named Deserialize: is used by Packet::RemoveHeader to
+ *     re-create a header from the byte buffer of a packet. The input
+ *     iterator points to the start of the byte buffer from which
+ *     the header should read its data. The data read is expected to
+ *     match bit-for-bit the representation of this header in real
+ *     networks. This method shall return an integer which identifies
+ *     the number of bytes read.
+ *   - a method named Print: is used by Packet::Print to print the 
+ *     content of a header as ascii data to a c++ output stream.
+ *     Although the header is free to format its output as it
+ *     wishes, it is recommended to follow a few rules to integrate
+ *     with the packet pretty printer: start with flags, small field 
+ *     values located between a pair of parens. Values should be separated 
+ *     by whitespace. Follow the parens with the important fields, 
+ *     separated by whitespace.
+ *     i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
+ *   - a method named GetName: is used by Packet::Print to print
+ *     header fragments. This method should return a user-readable
+ *     single word as all capitalized letters.
+ *
+ * Sample code which shows how to create a new type of Header, and how to use it, 
+ * is shown in the sample file samples/main-packet-header.cc
  */
-class Header : public Chunk {
-public:
-  virtual ~Header ();
-private:
-  /**
-   * \returns a user-readable name to identify this type of header.
-   *
-   * The string returned is expected to be a single word with 
-   * all capital letters
-   */
-  virtual std::string DoGetName (void) const = 0;
-  /**
-   * \param os the std output stream in which this 
-   *       protocol header must print itself.
-   *
-   * Although the header is free to format its output as it
-   * wishes, it is recommended to follow a few rules to integrate
-   * with the packet pretty printer:
-   *   - start with flags, small field values located between a
-   *     pair of parens. Values should be separated by whitespace.
-   *   - follow the parens with the important fields, separated by
-   *     whitespace.
-   * i.e.:
-   * (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
-   */
-  virtual void PrintTo (std::ostream &os) const = 0;
-
-  /**
-   * \returns the size of the serialized Header.
-   *
-   * This method is used by Packet::AddHeader to reserve
-   * enough room in the packet byte buffer prior to calling
-   * Header::Serialize.
-   */
-  virtual uint32_t GetSerializedSize (void) const = 0;
-
-  /**
-   * \param start the buffer iterator in which the protocol header
-   *    must serialize itself. This iterator identifies 
-   *    the start of the buffer.
-   */
-  virtual void SerializeTo (Buffer::Iterator start) const = 0;
-  /**
-   * \param start the buffer iterator from which the protocol header must
-   *    deserialize itself. This iterator identifies 
-   *    the start of the buffer.
-   * \returns the number of bytes read from the buffer
-   *
-   * The value returned is used to trim the packet byte buffer of the 
-   * corresponding amount when this method is invoked from 
-   * Packet::RemoveHeader
-   */
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start) = 0;
+class Header 
+{
+protected:
+  template <typename T>
+  static uint32_t AllocateUid (std::string uuid);
 };
 
-}; // namespace ns3
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t 
+Header::AllocateUid (std::string uuid)
+{
+  return ChunkRegistry::RegisterHeader<T> (uuid);
+}
+
+} // namespace ns3
 
 #endif /* HEADER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/packet-metadata-test.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,683 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,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>
+ */
+#ifdef RUN_SELF_TESTS
+
+#include <stdarg.h>
+#include <iostream>
+#include <sstream>
+#include "ns3/test.h"
+#include "header.h"
+#include "trailer.h"
+#include "packet.h"
+#include "packet-metadata.h"
+#include "packet-printer.h"
+
+namespace ns3 {
+
+template <int N>
+class HistoryHeader : public Header
+{
+public:
+  static uint32_t GetUid (void);
+  HistoryHeader ();
+  bool IsOk (void) const;
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+private:
+  bool m_ok;
+};
+
+template <int N>
+uint32_t
+HistoryHeader<N>::GetUid (void)
+{
+  std::ostringstream oss;
+  oss << N << "HistoryHeader.ns3";
+  static uint32_t uid = AllocateUid<HistoryHeader<N> > (oss.str());
+  return uid;
+}
+
+template <int N>
+HistoryHeader<N>::HistoryHeader ()
+  : m_ok (false)
+{}
+
+template <int N>
+bool 
+HistoryHeader<N>::IsOk (void) const
+{
+  return m_ok;
+}
+
+template <int N>
+std::string 
+HistoryHeader<N>::GetName (void) const
+{
+  std::ostringstream oss;
+  oss << N;
+  return oss.str ();
+}
+
+template <int N>
+void 
+HistoryHeader<N>::Print (std::ostream &os) const
+{
+  NS_ASSERT (false);
+}
+template <int N>
+uint32_t 
+HistoryHeader<N>::GetSerializedSize (void) const
+{
+  return N;
+}
+template <int N>
+void 
+HistoryHeader<N>::Serialize (Buffer::Iterator start) const
+{
+  start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryHeader<N>::Deserialize (Buffer::Iterator start)
+{
+  m_ok = true;
+  for (int i = 0; i < N; i++)
+    {
+      if (start.ReadU8 () != N)
+        {
+          m_ok = false;
+        }
+    }
+  return N;
+}
+
+template <int N>
+class HistoryTrailer : public Trailer
+{
+public:
+  static uint32_t GetUid (void);
+  HistoryTrailer ();
+  bool IsOk (void) const;
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+private:
+  bool m_ok;
+};
+
+template <int N>
+uint32_t
+HistoryTrailer<N>::GetUid (void)
+{
+  std::ostringstream oss;
+  oss << N << "HistoryTrailer.ns3";
+  static uint32_t uid = AllocateUid<HistoryTrailer<N> > (oss.str ());
+  return uid;
+}
+
+
+template <int N>
+HistoryTrailer<N>::HistoryTrailer ()
+  : m_ok (false)
+{}
+
+template <int N>
+bool
+HistoryTrailer<N>::IsOk (void) const
+{
+  return m_ok;
+}
+
+template <int N>
+std::string 
+HistoryTrailer<N>::GetName (void) const
+{
+  std::ostringstream oss;
+  oss << N;
+  return oss.str ();
+}
+template <int N>
+void 
+HistoryTrailer<N>::Print (std::ostream &os) const
+{
+  NS_ASSERT (false);
+}
+template <int N>
+uint32_t 
+HistoryTrailer<N>::GetSerializedSize (void) const
+{
+  return N;
+}
+template <int N>
+void 
+HistoryTrailer<N>::Serialize (Buffer::Iterator start) const
+{
+  start.Prev (N);
+  start.WriteU8 (N, N);
+}
+template <int N>
+uint32_t
+HistoryTrailer<N>::Deserialize (Buffer::Iterator start)
+{
+  m_ok = true;
+  start.Prev (N);
+  for (int i = 0; i < N; i++)
+    {
+      if (start.ReadU8 () != N)
+        {
+          m_ok = false;
+        }
+    }
+  return N;
+}
+
+
+
+class PacketMetadataTest : public Test {
+public:
+  PacketMetadataTest ();
+  virtual ~PacketMetadataTest ();
+  bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...);
+  virtual bool RunTests (void);
+private:
+  template <int N>
+  void PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryHeader<N> *header);
+  template <int N>
+  void PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryTrailer<N> *trailer);
+  void PrintFragment (std::ostream &os,uint32_t packetUid,
+                      uint32_t size,std::string & name, 
+                      struct PacketPrinter::FragmentInformation info);
+  void PrintPayload (std::ostream &os,uint32_t packetUid,
+                     uint32_t size,
+                     struct PacketPrinter::FragmentInformation info);
+  template <int N>
+  void RegisterHeader (void);
+  template <int N>
+  void RegisterTrailer (void);
+  void CleanupPrints (void);
+  Packet DoAddHeader (Packet p);
+  bool Check (const char *file, int line, std::list<int> expected);
+
+
+  bool m_headerError;
+  bool m_trailerError;
+  std::list<int> m_prints;
+  PacketPrinter m_printer;
+};
+
+PacketMetadataTest::PacketMetadataTest ()
+  : Test ("PacketMetadata")
+{
+  m_printer.SetPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this));
+  m_printer.SetSeparator ("");
+}
+
+PacketMetadataTest::~PacketMetadataTest ()
+{}
+
+template <int N>
+void 
+PacketMetadataTest::RegisterHeader (void)
+{
+  static bool registered = false;
+  if (!registered)
+    {
+      m_printer.SetHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader<N>, this),
+                                  MakeCallback (&PacketMetadataTest::PrintFragment, this));
+      registered = true;
+    }
+}
+
+template <int N>
+void 
+PacketMetadataTest::RegisterTrailer (void)
+{
+  static bool registered = false;
+  if (!registered)
+    {
+      m_printer.SetTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer<N>, this),
+                                   MakeCallback (&PacketMetadataTest::PrintFragment, this));
+      registered = true;
+    }
+}
+
+
+template <int N>
+void 
+PacketMetadataTest::PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, 
+                                const HistoryHeader<N> *header)
+{
+  if (!header->IsOk ())
+    {
+      m_headerError = true;
+    }
+  m_prints.push_back (N);
+}
+
+template <int N>
+void 
+PacketMetadataTest::PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, 
+                                 const HistoryTrailer<N> *trailer)
+{
+  if (!trailer->IsOk ())
+    {
+      m_trailerError = true;
+    }
+  m_prints.push_back (N);
+}
+void 
+PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid,
+                                  uint32_t size,std::string & name, 
+                                  struct PacketPrinter::FragmentInformation info)
+{
+  m_prints.push_back (size - (info.end + info.start));
+}
+void 
+PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid,
+                                 uint32_t size,
+                                 struct PacketPrinter::FragmentInformation info)
+{
+  m_prints.push_back (size - (info.end + info.start));
+}
+
+
+void 
+PacketMetadataTest::CleanupPrints (void)
+{
+  m_prints.clear ();
+}
+
+bool
+PacketMetadataTest::Check (const char *file, int line, std::list<int> expected)
+{
+  if (m_headerError)
+    {
+      Failure () << "PacketMetadata header error. file=" << file 
+                << ", line=" << line << std::endl;
+      return false;
+    }
+  if (m_trailerError)
+    {
+      Failure () << "PacketMetadata trailer error. file=" << file 
+                << ", line=" << line << std::endl;
+      return false;
+    }
+  if (expected.size () != m_prints.size ())
+    {
+      goto error;
+    }
+  for (std::list<int>::iterator i = m_prints.begin (),
+         j = expected.begin (); 
+       i != m_prints.end (); i++, j++)
+    {
+      NS_ASSERT (j != expected.end ());
+      if (*j != *i)
+        {
+          goto error;
+        }
+    }
+  return true;
+ error:
+  Failure () << "PacketMetadata error. file="<< file 
+            << ", line=" << line << ", got:\"";
+  for (std::list<int>::iterator i = m_prints.begin (); 
+       i != m_prints.end (); i++)
+    {
+      Failure () << *i << ", ";
+    }
+  Failure () << "\", expected: \"";
+  for (std::list<int>::iterator j = expected.begin ();
+       j != expected.end (); j++)
+    {
+      Failure () << *j << ", ";
+    }
+  Failure () << "\"" << std::endl;
+  return false;
+}
+
+bool 
+PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...)
+{
+  m_headerError = false;
+  m_trailerError = false;
+  std::list<int> expected;
+  va_list ap;
+  va_start (ap, n);
+  for (uint32_t j = 0; j < n; j++)
+    {
+      int v = va_arg (ap, int);
+      expected.push_back (v);
+    }
+  va_end (ap);
+
+  m_printer.PrintForward ();
+  p.Print (Failure (), m_printer);
+  bool ok = Check (file, line, expected);
+  CleanupPrints ();
+  if (!ok)
+    {
+      return false;
+    }
+
+  m_printer.PrintBackward ();
+  p.Print (Failure (), m_printer);
+  expected.reverse ();
+  ok = Check (file, line, expected);
+  CleanupPrints ();
+  return ok;
+}
+
+#define ADD_HEADER(p, n)                        \
+  {                                             \
+    HistoryHeader<n> header;                    \
+    RegisterHeader<n> ();                       \
+    p.AddHeader (header);                       \
+  }
+#define ADD_TRAILER(p, n)                       \
+  {                                             \
+    HistoryTrailer<n> trailer;                  \
+    RegisterTrailer<n> ();                      \
+    p.AddTrailer (trailer);                     \
+  }
+#define REM_HEADER(p, n)                        \
+  {                                             \
+    HistoryHeader<n> header;                    \
+    RegisterHeader<n> ();                       \
+    p.RemoveHeader (header);                    \
+  }
+#define REM_TRAILER(p, n)                       \
+  {                                             \
+    HistoryTrailer<n> trailer;                  \
+    RegisterTrailer<n> ();                      \
+    p.RemoveTrailer (trailer);                  \
+  }
+#define CHECK_HISTORY(p, ...)                   \
+  {                                             \
+    if (!CheckHistory (p, __FILE__,             \
+                      __LINE__, __VA_ARGS__))   \
+      {                                         \
+        ok = false;                             \
+      }                                         \
+    Buffer buffer;                              \
+    buffer = p.Serialize ();                    \
+    Packet otherPacket;                         \
+    otherPacket.Deserialize  (buffer);          \
+    if (!CheckHistory (otherPacket, __FILE__,   \
+                      __LINE__, __VA_ARGS__))   \
+      {                                         \
+        ok = false;                             \
+      }                                         \
+  }
+
+
+Packet 
+PacketMetadataTest::DoAddHeader (Packet p)
+{
+  ADD_HEADER (p, 10);
+  return p;
+}
+
+bool
+PacketMetadataTest::RunTests (void)
+{
+  bool ok = true;
+
+  PacketMetadata::Enable ();
+
+  Packet p = Packet (0);
+  Packet p1 = Packet (0);
+
+  p = Packet (10);
+  ADD_TRAILER (p, 100);
+  CHECK_HISTORY (p, 2, 10, 100);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  CHECK_HISTORY (p, 4, 
+                 3, 2, 1, 10);
+  ADD_HEADER (p, 5);
+  CHECK_HISTORY (p, 5, 
+                 5, 3, 2, 1, 10);
+  ADD_HEADER (p, 6);
+  CHECK_HISTORY (p, 6, 
+                 6, 5, 3, 2, 1, 10);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  REM_HEADER (p, 3);
+  CHECK_HISTORY (p, 3, 
+                 2, 1, 10);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  REM_HEADER (p, 3);
+  REM_HEADER (p, 2);
+  CHECK_HISTORY (p, 2, 
+                 1, 10);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  REM_HEADER (p, 3);
+  REM_HEADER (p, 2);
+  REM_HEADER (p, 1);
+  CHECK_HISTORY (p, 1, 10);
+
+  p = Packet (10);
+  ADD_HEADER (p, 1);
+  ADD_HEADER (p, 2);
+  ADD_HEADER (p, 3);
+  p1 = p;
+  REM_HEADER (p1, 3);
+  REM_HEADER (p1, 2);
+  REM_HEADER (p1, 1);
+  CHECK_HISTORY (p1, 1, 10);
+  CHECK_HISTORY (p, 4, 
+                 3, 2, 1, 10);
+  ADD_HEADER (p1, 1);
+  ADD_HEADER (p1, 2);
+  CHECK_HISTORY (p1, 3, 
+                 2, 1, 10);
+  CHECK_HISTORY (p, 4, 
+                 3, 2, 1, 10);
+  ADD_HEADER (p, 3);
+  CHECK_HISTORY (p, 5, 
+                 3, 3, 2, 1, 10);
+  ADD_TRAILER (p, 4);
+  CHECK_HISTORY (p, 6, 
+                 3, 3, 2, 1, 10, 4);
+  ADD_TRAILER (p, 5);
+  CHECK_HISTORY (p, 7, 
+                 3, 3, 2, 1, 10, 4, 5);
+  REM_HEADER (p, 3);
+  CHECK_HISTORY (p, 6, 
+                 3, 2, 1, 10, 4, 5);
+  REM_TRAILER (p, 5);
+  CHECK_HISTORY (p, 5, 
+                 3, 2, 1, 10, 4);
+  p1 = p;
+  REM_TRAILER (p, 4);
+  CHECK_HISTORY (p, 4, 
+                 3, 2, 1, 10);
+  CHECK_HISTORY (p1, 5, 
+                 3, 2, 1, 10, 4);
+  p1.RemoveAtStart (3);
+  CHECK_HISTORY (p1, 4, 
+                 2, 1, 10, 4);
+  p1.RemoveAtStart (1);
+  CHECK_HISTORY (p1, 4, 
+                 1, 1, 10, 4);
+  p1.RemoveAtStart (1);
+  CHECK_HISTORY (p1, 3, 
+                 1, 10, 4);
+  p1.RemoveAtEnd (4);
+  CHECK_HISTORY (p1, 2, 
+                 1, 10);
+  p1.RemoveAtStart (1);
+  CHECK_HISTORY (p1, 1, 10);
+
+  p = Packet (10);
+  ADD_HEADER (p, 8);
+  ADD_TRAILER (p, 8);
+  ADD_TRAILER (p, 8);
+  p.RemoveAtStart (8+10+8);
+  CHECK_HISTORY (p, 1, 8);
+
+  p = Packet (10);
+  ADD_HEADER (p, 10);
+  ADD_HEADER (p, 8);
+  ADD_TRAILER (p, 6);
+  ADD_TRAILER (p, 7);
+  ADD_TRAILER (p, 9);
+  p.RemoveAtStart (5);
+  p.RemoveAtEnd (12);
+  CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4);
+
+  p = Packet (10);
+  ADD_HEADER (p, 10);
+  ADD_TRAILER (p, 6);
+  p.RemoveAtEnd (18);
+  ADD_TRAILER (p, 5);
+  ADD_HEADER (p, 3);
+  CHECK_HISTORY (p, 3, 3, 8, 5);
+  p.RemoveAtStart (12);
+  CHECK_HISTORY (p, 1, 4);
+  p.RemoveAtEnd (2);
+  CHECK_HISTORY (p, 1, 2);
+  ADD_HEADER (p, 10);
+  CHECK_HISTORY (p, 2, 10, 2);
+  p.RemoveAtEnd (5);
+  CHECK_HISTORY (p, 1, 7);
+
+  Packet p2 = Packet (0);
+  Packet p3 = Packet (0);
+
+  p = Packet (40);
+  ADD_HEADER (p, 5);
+  ADD_HEADER (p, 8);
+  CHECK_HISTORY (p, 3, 8, 5, 40);
+  p1 = p.CreateFragment (0, 5);
+  p2 = p.CreateFragment (5, 5);
+  p3 = p.CreateFragment (10, 43);
+  CHECK_HISTORY (p1, 1, 5);
+  CHECK_HISTORY (p2, 2, 3, 2);
+  CHECK_HISTORY (p3, 2, 3, 40);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p1, 2, 8, 2);
+  CHECK_HISTORY (p2, 2, 3, 2);
+  p1.AddAtEnd (p3);
+  CHECK_HISTORY (p1, 3, 8, 5, 40);
+  CHECK_HISTORY (p2, 2, 3, 2);
+  CHECK_HISTORY (p3, 2, 3, 40);
+  p1 = p.CreateFragment (0, 5);
+  CHECK_HISTORY (p1, 1, 5);
+
+  p3 = Packet (50);
+  ADD_HEADER (p3, 8);
+  CHECK_HISTORY (p3, 2, 8, 50);
+  CHECK_HISTORY (p1, 1, 5);
+  p1.AddAtEnd (p3);
+  CHECK_HISTORY (p1, 3, 5, 8, 50);
+  ADD_HEADER (p1, 5);
+  CHECK_HISTORY (p1, 4, 5, 5, 8, 50);
+  ADD_TRAILER (p1, 2);
+  CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2);
+  REM_HEADER (p1, 5);
+  CHECK_HISTORY (p1, 4, 5, 8, 50, 2);
+  p1.RemoveAtEnd (60);
+  CHECK_HISTORY (p1, 1, 5);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p1, 2, 8, 2);
+  CHECK_HISTORY (p2, 2, 3, 2);
+
+  p3 = Packet (40);
+  ADD_HEADER (p3, 5);
+  ADD_HEADER (p3, 5);
+  CHECK_HISTORY (p3, 3, 5, 5, 40);
+  p1 = p3.CreateFragment (0, 5);
+  p2 = p3.CreateFragment (5, 5);
+  CHECK_HISTORY (p1, 1, 5);
+  CHECK_HISTORY (p2, 1, 5);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p1, 2, 5, 5);
+
+  p = Packet (0);
+  CHECK_HISTORY (p, 0);
+
+  p3 = Packet (0);
+  ADD_HEADER (p3, 5);
+  ADD_HEADER (p3, 5);
+  CHECK_HISTORY (p3, 2, 5, 5);
+  p1 = p3.CreateFragment (0, 4);
+  p2 = p3.CreateFragment (9, 1);
+  CHECK_HISTORY (p1, 1, 4);
+  CHECK_HISTORY (p2, 1, 1);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p1, 2, 4, 1);
+
+
+  p = Packet (2000);
+  CHECK_HISTORY (p, 1, 2000);
+  
+  p = Packet ();
+  ADD_TRAILER (p, 10);
+  ADD_HEADER (p, 5);
+  p1 = p.CreateFragment (0, 8);
+  p2 = p.CreateFragment (8, 7);
+  p1.AddAtEnd (p2);
+  CHECK_HISTORY (p, 2, 5, 10);
+
+  p = Packet ();
+  ADD_TRAILER (p, 10);
+  REM_TRAILER (p, 10);
+  ADD_TRAILER (p, 10);
+  CHECK_HISTORY (p, 1, 10);
+
+  p = Packet ();
+  ADD_HEADER (p, 10);
+  REM_HEADER (p, 10);
+  ADD_HEADER (p, 10);
+  CHECK_HISTORY (p, 1, 10);
+
+  p = Packet ();
+  ADD_HEADER (p, 10);
+  p = DoAddHeader (p);
+  CHECK_HISTORY (p, 2, 10, 10);
+
+  return ok;
+}
+
+static PacketMetadataTest g_packetHistoryTest;
+
+}//namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- a/src/common/packet-metadata.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet-metadata.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -1,7 +1,6 @@
 /* -*- 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
@@ -24,8 +23,8 @@
 #include "ns3/fatal-error.h"
 #include "ns3/debug.h"
 #include "packet-metadata.h"
-#include "chunk.h"
 #include "buffer.h"
+#include "chunk-registry.h"
 
 NS_DEBUG_COMPONENT_DEFINE ("PacketMetadata");
 
@@ -965,19 +964,13 @@
   NS_ASSERT (leftToRemove == 0);
 }
 
-void 
-PacketMetadata::PrintDefault (std::ostream &os, Buffer buffer) const
-{
-  Print (os, buffer, PacketPrinter::GetDefault ());
-}
-
 uint32_t
 PacketMetadata::DoPrint (const struct PacketMetadata::SmallItem *item, 
                          const struct PacketMetadata::ExtraItem *extraItem,
                          Buffer data, uint32_t offset, const PacketPrinter &printer,
                          std::ostream &os) const
 {
-  uint32_t uid = item->typeUid & 0xfffffffe;
+  uint32_t uid = (item->typeUid & 0xfffffffe) >> 1;
   if (uid == 0)
     {
       // payload.
@@ -992,13 +985,13 @@
                                   extraItem->fragmentStart, 
                                   item->size - extraItem->fragmentEnd);
     }
-  else if (PacketPrinter::IsHeader (uid))
+  else if (ChunkRegistry::IsHeader (uid))
     {
       ns3::Buffer::Iterator j = data.Begin ();
       j.Next (offset);
       printer.PrintChunk (uid, j, os, extraItem->packetUid, item->size);
     }
-  else if (PacketPrinter::IsTrailer (uid))
+  else if (ChunkRegistry::IsTrailer (uid))
     {
       ns3::Buffer::Iterator j = data.End ();
       j.Prev (data.GetSize () - (offset + item->size));
@@ -1094,629 +1087,145 @@
     }
 }
 
-
-
-}; // namespace ns3
-
-#include <stdarg.h>
-#include <iostream>
-#include <sstream>
-#include "ns3/test.h"
-#include "header.h"
-#include "trailer.h"
-#include "packet.h"
-
-namespace ns3 {
-
-template <int N>
-class HistoryHeader : public Header
-{
-public:
-  HistoryHeader ();
-  bool IsOk (void) const;
-private:
-  virtual std::string DoGetName (void) const;
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
-  bool m_ok;
-};
-
-template <int N>
-HistoryHeader<N>::HistoryHeader ()
-  : m_ok (false)
-{}
-
-template <int N>
-bool 
-HistoryHeader<N>::IsOk (void) const
-{
-  return m_ok;
-}
-
-template <int N>
-std::string 
-HistoryHeader<N>::DoGetName (void) const
-{
-  std::ostringstream oss;
-  oss << N;
-  return oss.str ();
-}
-
-template <int N>
-void 
-HistoryHeader<N>::PrintTo (std::ostream &os) const
-{
-  NS_ASSERT (false);
-}
-template <int N>
 uint32_t 
-HistoryHeader<N>::GetSerializedSize (void) const
-{
-  return N;
-}
-template <int N>
-void 
-HistoryHeader<N>::SerializeTo (Buffer::Iterator start) const
-{
-  start.WriteU8 (N, N);
-}
-template <int N>
-uint32_t
-HistoryHeader<N>::DeserializeFrom (Buffer::Iterator start)
-{
-  m_ok = true;
-  for (int i = 0; i < N; i++)
-    {
-      if (start.ReadU8 () != N)
-        {
-          m_ok = false;
-        }
-    }
-  return N;
-}
-
-template <int N>
-class HistoryTrailer : public Trailer
-{
-public:
-  HistoryTrailer ();
-  bool IsOk (void) const;
-private:
-  virtual std::string DoGetName (void) const;
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
-  bool m_ok;
-};
-
-template <int N>
-HistoryTrailer<N>::HistoryTrailer ()
-  : m_ok (false)
-{}
-
-template <int N>
-bool
-HistoryTrailer<N>::IsOk (void) const
-{
-  return m_ok;
-}
-
-template <int N>
-std::string 
-HistoryTrailer<N>::DoGetName (void) const
-{
-  std::ostringstream oss;
-  oss << N;
-  return oss.str ();
-}
-template <int N>
-void 
-HistoryTrailer<N>::PrintTo (std::ostream &os) const
+PacketMetadata::GetSerializedSize (void) const
 {
-  NS_ASSERT (false);
-}
-template <int N>
-uint32_t 
-HistoryTrailer<N>::GetSerializedSize (void) const
-{
-  return N;
-}
-template <int N>
-void 
-HistoryTrailer<N>::SerializeTo (Buffer::Iterator start) const
-{
-  start.Prev (N);
-  start.WriteU8 (N, N);
-}
-template <int N>
-uint32_t
-HistoryTrailer<N>::DeserializeFrom (Buffer::Iterator start)
-{
-  m_ok = true;
-  start.Prev (N);
-  for (int i = 0; i < N; i++)
+  uint32_t totalSize = 0;
+  totalSize += 4;
+  if (!m_enable)
     {
-      if (start.ReadU8 () != N)
-        {
-          m_ok = false;
-        }
+      return totalSize;
     }
-  return N;
-}
-
-
-
-class PacketMetadataTest : public Test {
-public:
-  PacketMetadataTest ();
-  virtual ~PacketMetadataTest ();
-  bool CheckHistory (Packet p, const char *file, int line, uint32_t n, ...);
-  virtual bool RunTests (void);
-private:
-  template <int N>
-  void PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryHeader<N> *header);
-  template <int N>
-  void PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, const HistoryTrailer<N> *trailer);
-  void PrintFragment (std::ostream &os,uint32_t packetUid,
-                      uint32_t size,std::string & name, 
-                      struct PacketPrinter::FragmentInformation info);
-  void PrintDefault (std::ostream& os,uint32_t packetUid,
-                     uint32_t size,std::string& name,
-                     struct PacketPrinter::FragmentInformation info);
-  void PrintPayload (std::ostream &os,uint32_t packetUid,
-                     uint32_t size,
-                     struct PacketPrinter::FragmentInformation info);
-  template <int N>
-  void RegisterHeader (void);
-  template <int N>
-  void RegisterTrailer (void);
-  void CleanupPrints (void);
-  bool Check (const char *file, int line, std::list<int> expected);
-
-
-  bool m_headerError;
-  bool m_trailerError;
-  std::list<int> m_prints;
-  PacketPrinter m_printer;
-};
-
-PacketMetadataTest::PacketMetadataTest ()
-  : Test ("PacketMetadata")
-{
-  m_printer.AddPayloadPrinter (MakeCallback (&PacketMetadataTest::PrintPayload, this));
-  m_printer.AddDefaultPrinter (MakeCallback (&PacketMetadataTest::PrintDefault, this));
-}
-
-PacketMetadataTest::~PacketMetadataTest ()
-{}
-
-template <int N>
-void 
-PacketMetadataTest::RegisterHeader (void)
-{
-  static bool registered = false;
-  if (!registered)
+  struct PacketMetadata::SmallItem item;
+  struct PacketMetadata::ExtraItem extraItem;
+  uint32_t current = m_head;
+  while (current != 0xffff)
     {
-      m_printer.AddHeaderPrinter (MakeCallback (&PacketMetadataTest::PrintHeader<N>, this),
-                                  MakeCallback (&PacketMetadataTest::PrintFragment, this));
-      registered = true;
-    }
-}
-
-template <int N>
-void 
-PacketMetadataTest::RegisterTrailer (void)
-{
-  static bool registered = false;
-  if (!registered)
-    {
-      m_printer.AddTrailerPrinter (MakeCallback (&PacketMetadataTest::PrintTrailer<N>, this),
-                                   MakeCallback (&PacketMetadataTest::PrintFragment, this));
-      registered = true;
+      ReadItems (current, &item, &extraItem);
+      uint32_t uid = (item.typeUid & 0xfffffffe) >> 1;
+      if (uid == 0)
+        {
+          totalSize += 4;
+        }
+      else
+        {
+          totalSize += 4 + ChunkRegistry::GetUidStringFromUid (uid).size ();
+        }
+      totalSize += 1 + 4 + 2 + 4 + 4 + 4;
+      if (current == m_tail)
+        {
+          break;
+        }
+      NS_ASSERT (current != item.next);
+      current = item.next;
     }
-}
-
-
-template <int N>
-void 
-PacketMetadataTest::PrintHeader (std::ostream &os, uint32_t packetUid, uint32_t size, 
-                                const HistoryHeader<N> *header)
-{
-  if (!header->IsOk ())
-    {
-      m_headerError = true;
-    }
-  m_prints.push_back (N);
-}
-
-template <int N>
-void 
-PacketMetadataTest::PrintTrailer (std::ostream &os, uint32_t packetUid, uint32_t size, 
-                                 const HistoryTrailer<N> *trailer)
-{
-  if (!trailer->IsOk ())
-    {
-      m_trailerError = true;
-    }
-  m_prints.push_back (N);
+  return totalSize;
 }
 void 
-PacketMetadataTest::PrintFragment (std::ostream &os,uint32_t packetUid,
-                                  uint32_t size,std::string & name, 
-                                  struct PacketPrinter::FragmentInformation info)
+PacketMetadata::Serialize (Buffer::Iterator i, uint32_t size) const
 {
-  m_prints.push_back (size - (info.end + info.start));
+  uint32_t bytesWritten = 0;
+  i.WriteU32 (size);
+  bytesWritten += 4;
+  struct PacketMetadata::SmallItem item;
+  struct PacketMetadata::ExtraItem extraItem;
+  uint32_t current = m_head;
+  while (current != 0xffff)
+    {
+      ReadItems (current, &item, &extraItem);
+      NS_DEBUG ("bytesWritten=" << bytesWritten << ", typeUid="<<item.typeUid <<
+                ", size="<<item.size<<", chunkUid="<<item.chunkUid<<
+                ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<extraItem.fragmentEnd<<
+                ", packetUid="<<extraItem.packetUid);
+      uint32_t uid = (item.typeUid & 0xfffffffe) >> 1;
+      if (uid != 0)
+        {
+          std::string uidString = ChunkRegistry::GetUidStringFromUid (uid);
+          i.WriteU32 (uidString.size ());
+          bytesWritten += 4;
+          i.Write ((uint8_t *)uidString.c_str (), uidString.size ());
+          bytesWritten += uidString.size ();
+        }
+      else
+        {
+          i.WriteU32 (0);
+          bytesWritten += 4;
+        }
+      uint8_t isBig = item.typeUid & 0x1;
+      i.WriteU8 (isBig);
+      bytesWritten += 1;
+      i.WriteU32 (item.size);
+      bytesWritten += 4;
+      i.WriteU16 (item.chunkUid);
+      bytesWritten += 2;
+      i.WriteU32 (extraItem.fragmentStart);
+      bytesWritten += 4;
+      i.WriteU32 (extraItem.fragmentEnd);
+      bytesWritten += 4;
+      i.WriteU32 (extraItem.packetUid);
+      bytesWritten += 4;
+      if (current == m_tail)
+        {
+          break;
+        }
+      
+      NS_ASSERT (current != item.next);
+      current = item.next;
+    }
+  NS_ASSERT (bytesWritten == size);
 }
-void 
-PacketMetadataTest::PrintDefault (std::ostream& os,uint32_t packetUid,
-                     uint32_t size,std::string& name,
-                     struct PacketPrinter::FragmentInformation info)
+uint32_t 
+PacketMetadata::Deserialize (Buffer::Iterator i)
 {
-  NS_ASSERT (false);
-}
-void 
-PacketMetadataTest::PrintPayload (std::ostream &os,uint32_t packetUid,
-                                 uint32_t size,
-                                 struct PacketPrinter::FragmentInformation info)
-{
-  m_prints.push_back (size - (info.end + info.start));
+  struct PacketMetadata::SmallItem item;
+  struct PacketMetadata::ExtraItem extraItem;
+  uint32_t totalSize = i.ReadU32 ();
+  uint32_t size = totalSize;
+  size -= 4;
+  while (size > 0)
+    {
+      uint32_t uidStringSize = i.ReadU32 ();
+      size -= 4;
+      uint32_t uid;
+      if (uidStringSize == 0)
+        {
+          // uid zero for payload.
+          uid = 0;
+        }
+      else
+        {
+          std::string uidString;
+          for (uint32_t j = 0; j < uidStringSize; j++)
+            {
+              uidString.push_back (i.ReadU8 ());
+              size --;
+            }
+          uid = ChunkRegistry::GetUidFromUidString (uidString);
+        }
+      uint8_t isBig = i.ReadU8 ();
+      size --;
+      item.typeUid = (uid << 1) | isBig;
+      item.size = i.ReadU32 ();
+      size -= 4;
+      item.chunkUid = i.ReadU16 ();
+      size -= 2;
+      extraItem.fragmentStart = i.ReadU32 ();
+      size -= 4;
+      extraItem.fragmentEnd = i.ReadU32 ();
+      size -= 4;
+      extraItem.packetUid = i.ReadU32 ();
+      size -= 4;
+      NS_DEBUG ("size=" << size << ", typeUid="<<item.typeUid <<
+                ", size="<<item.size<<", chunkUid="<<item.chunkUid<<
+                ", fragmentStart="<<extraItem.fragmentStart<<", fragmentEnd="<<extraItem.fragmentEnd<<
+                ", packetUid="<<extraItem.packetUid);
+      uint32_t tmp = AddBig (0xffff, m_tail, &item, &extraItem);
+      UpdateTail (tmp);
+    }
+  NS_ASSERT (size == 0);
+  return totalSize;
 }
 
 
-void 
-PacketMetadataTest::CleanupPrints (void)
-{
-  m_prints.clear ();
-}
-
-bool
-PacketMetadataTest::Check (const char *file, int line, std::list<int> expected)
-{
-  if (m_headerError)
-    {
-      std::cout << "PacketMetadata header error. file=" << file 
-                << ", line=" << line << std::endl;
-      return false;
-    }
-  if (m_trailerError)
-    {
-      std::cout << "PacketMetadata trailer error. file=" << file 
-                << ", line=" << line << std::endl;
-      return false;
-    }
-  if (expected.size () != m_prints.size ())
-    {
-      goto error;
-    }
-  for (std::list<int>::iterator i = m_prints.begin (),
-         j = expected.begin (); 
-       i != m_prints.end (); i++, j++)
-    {
-      NS_ASSERT (j != expected.end ());
-      if (*j != *i)
-        {
-          goto error;
-        }
-    }
-  return true;
- error:
-  std::cout << "PacketMetadata error. file="<< file 
-            << ", line=" << line << ", got:\"";
-  for (std::list<int>::iterator i = m_prints.begin (); 
-       i != m_prints.end (); i++)
-    {
-      std::cout << *i << ", ";
-    }
-  std::cout << "\", expected: \"";
-  for (std::list<int>::iterator j = expected.begin ();
-       j != expected.end (); j++)
-    {
-      std::cout << *j << ", ";
-    }
-  std::cout << "\"" << std::endl;
-  return false;
-}
-
-bool 
-PacketMetadataTest::CheckHistory (Packet p, const char *file, int line, uint32_t n, ...)
-{
-  m_headerError = false;
-  m_trailerError = false;
-  std::list<int> expected;
-  va_list ap;
-  va_start (ap, n);
-  for (uint32_t j = 0; j < n; j++)
-    {
-      int v = va_arg (ap, int);
-      expected.push_back (v);
-    }
-  va_end (ap);
-
-  m_printer.PrintForward ();
-  p.Print (std::cerr, m_printer);
-  bool ok = Check (file, line, expected);
-  CleanupPrints ();
-  if (!ok)
-    {
-      return false;
-    }
-
-  m_printer.PrintBackward ();
-  p.Print (std::cerr, m_printer);
-  expected.reverse ();
-  ok = Check (file, line, expected);
-  CleanupPrints ();
-  return ok;
-}
-
-#define ADD_HEADER(p, n)                        \
-  {                                             \
-    HistoryHeader<n> header;                    \
-    RegisterHeader<n> ();                       \
-    p.AddHeader (header);                       \
-  }
-#define ADD_TRAILER(p, n)                       \
-  {                                             \
-    HistoryTrailer<n> trailer;                  \
-    RegisterTrailer<n> ();                      \
-    p.AddTrailer (trailer);                     \
-  }
-#define REM_HEADER(p, n)                        \
-  {                                             \
-    HistoryHeader<n> header;                    \
-    RegisterHeader<n> ();                       \
-    p.RemoveHeader (header);                    \
-  }
-#define REM_TRAILER(p, n)                       \
-  {                                             \
-    HistoryTrailer<n> trailer;                  \
-    RegisterTrailer<n> ();                      \
-    p.RemoveTrailer (trailer);                  \
-  }
-#define CHECK_HISTORY(p, ...)                   \
-  {                                             \
-    if (!CheckHistory (p, __FILE__,             \
-                      __LINE__, __VA_ARGS__))   \
-      {                                         \
-        ok = false;                             \
-      }                                         \
-  }
-
-bool
-PacketMetadataTest::RunTests (void)
-{
-  bool ok = true;
-
-  PacketMetadata::Enable ();
-
-  Packet p = Packet (0);
-  Packet p1 = Packet (0);
-
-  p = Packet (10);
-  ADD_TRAILER (p, 100);
-  CHECK_HISTORY (p, 2, 10, 100);
-
-  p = Packet (10);
-  ADD_HEADER (p, 1);
-  ADD_HEADER (p, 2);
-  ADD_HEADER (p, 3);
-  CHECK_HISTORY (p, 4, 
-                 3, 2, 1, 10);
-  ADD_HEADER (p, 5);
-  CHECK_HISTORY (p, 5, 
-                 5, 3, 2, 1, 10);
-  ADD_HEADER (p, 6);
-  CHECK_HISTORY (p, 6, 
-                 6, 5, 3, 2, 1, 10);
-
-  p = Packet (10);
-  ADD_HEADER (p, 1);
-  ADD_HEADER (p, 2);
-  ADD_HEADER (p, 3);
-  REM_HEADER (p, 3);
-  CHECK_HISTORY (p, 3, 
-                 2, 1, 10);
-
-  p = Packet (10);
-  ADD_HEADER (p, 1);
-  ADD_HEADER (p, 2);
-  ADD_HEADER (p, 3);
-  REM_HEADER (p, 3);
-  REM_HEADER (p, 2);
-  CHECK_HISTORY (p, 2, 
-                 1, 10);
-
-  p = Packet (10);
-  ADD_HEADER (p, 1);
-  ADD_HEADER (p, 2);
-  ADD_HEADER (p, 3);
-  REM_HEADER (p, 3);
-  REM_HEADER (p, 2);
-  REM_HEADER (p, 1);
-  CHECK_HISTORY (p, 1, 10);
+} // namespace ns3
 
-  p = Packet (10);
-  ADD_HEADER (p, 1);
-  ADD_HEADER (p, 2);
-  ADD_HEADER (p, 3);
-  p1 = p;
-  REM_HEADER (p1, 3);
-  REM_HEADER (p1, 2);
-  REM_HEADER (p1, 1);
-  CHECK_HISTORY (p1, 1, 10);
-  CHECK_HISTORY (p, 4, 
-                 3, 2, 1, 10);
-  ADD_HEADER (p1, 1);
-  ADD_HEADER (p1, 2);
-  CHECK_HISTORY (p1, 3, 
-                 2, 1, 10);
-  CHECK_HISTORY (p, 4, 
-                 3, 2, 1, 10);
-  ADD_HEADER (p, 3);
-  CHECK_HISTORY (p, 5, 
-                 3, 3, 2, 1, 10);
-  ADD_TRAILER (p, 4);
-  CHECK_HISTORY (p, 6, 
-                 3, 3, 2, 1, 10, 4);
-  ADD_TRAILER (p, 5);
-  CHECK_HISTORY (p, 7, 
-                 3, 3, 2, 1, 10, 4, 5);
-  REM_HEADER (p, 3);
-  CHECK_HISTORY (p, 6, 
-                 3, 2, 1, 10, 4, 5);
-  REM_TRAILER (p, 5);
-  CHECK_HISTORY (p, 5, 
-                 3, 2, 1, 10, 4);
-  p1 = p;
-  REM_TRAILER (p, 4);
-  CHECK_HISTORY (p, 4, 
-                 3, 2, 1, 10);
-  CHECK_HISTORY (p1, 5, 
-                 3, 2, 1, 10, 4);
-  p1.RemoveAtStart (3);
-  CHECK_HISTORY (p1, 4, 
-                 2, 1, 10, 4);
-  p1.RemoveAtStart (1);
-  CHECK_HISTORY (p1, 4, 
-                 1, 1, 10, 4);
-  p1.RemoveAtStart (1);
-  CHECK_HISTORY (p1, 3, 
-                 1, 10, 4);
-  p1.RemoveAtEnd (4);
-  CHECK_HISTORY (p1, 2, 
-                 1, 10);
-  p1.RemoveAtStart (1);
-  CHECK_HISTORY (p1, 1, 10);
-
-  p = Packet (10);
-  ADD_HEADER (p, 8);
-  ADD_TRAILER (p, 8);
-  ADD_TRAILER (p, 8);
-  p.RemoveAtStart (8+10+8);
-  CHECK_HISTORY (p, 1, 8);
-
-  p = Packet (10);
-  ADD_HEADER (p, 10);
-  ADD_HEADER (p, 8);
-  ADD_TRAILER (p, 6);
-  ADD_TRAILER (p, 7);
-  ADD_TRAILER (p, 9);
-  p.RemoveAtStart (5);
-  p.RemoveAtEnd (12);
-  CHECK_HISTORY (p, 5, 3, 10, 10, 6, 4);
-
-  p = Packet (10);
-  ADD_HEADER (p, 10);
-  ADD_TRAILER (p, 6);
-  p.RemoveAtEnd (18);
-  ADD_TRAILER (p, 5);
-  ADD_HEADER (p, 3);
-  CHECK_HISTORY (p, 3, 3, 8, 5);
-  p.RemoveAtStart (12);
-  CHECK_HISTORY (p, 1, 4);
-  p.RemoveAtEnd (2);
-  CHECK_HISTORY (p, 1, 2);
-  ADD_HEADER (p, 10);
-  CHECK_HISTORY (p, 2, 10, 2);
-  p.RemoveAtEnd (5);
-  CHECK_HISTORY (p, 1, 7);
-
-  Packet p2 = Packet (0);
-  Packet p3 = Packet (0);
-
-  p = Packet (40);
-  ADD_HEADER (p, 5);
-  ADD_HEADER (p, 8);
-  CHECK_HISTORY (p, 3, 8, 5, 40);
-  p1 = p.CreateFragment (0, 5);
-  p2 = p.CreateFragment (5, 5);
-  p3 = p.CreateFragment (10, 43);
-  CHECK_HISTORY (p1, 1, 5);
-  CHECK_HISTORY (p2, 2, 3, 2);
-  CHECK_HISTORY (p3, 2, 3, 40);
-  p1.AddAtEnd (p2);
-  CHECK_HISTORY (p1, 2, 8, 2);
-  CHECK_HISTORY (p2, 2, 3, 2);
-  p1.AddAtEnd (p3);
-  CHECK_HISTORY (p1, 3, 8, 5, 40);
-  CHECK_HISTORY (p2, 2, 3, 2);
-  CHECK_HISTORY (p3, 2, 3, 40);
-  p1 = p.CreateFragment (0, 5);
-  CHECK_HISTORY (p1, 1, 5);
-
-  p3 = Packet (50);
-  ADD_HEADER (p3, 8);
-  CHECK_HISTORY (p3, 2, 8, 50);
-  CHECK_HISTORY (p1, 1, 5);
-  p1.AddAtEnd (p3);
-  CHECK_HISTORY (p1, 3, 5, 8, 50);
-  ADD_HEADER (p1, 5);
-  CHECK_HISTORY (p1, 4, 5, 5, 8, 50);
-  ADD_TRAILER (p1, 2);
-  CHECK_HISTORY (p1, 5, 5, 5, 8, 50, 2);
-  REM_HEADER (p1, 5);
-  CHECK_HISTORY (p1, 4, 5, 8, 50, 2);
-  p1.RemoveAtEnd (60);
-  CHECK_HISTORY (p1, 1, 5);
-  p1.AddAtEnd (p2);
-  CHECK_HISTORY (p1, 2, 8, 2);
-  CHECK_HISTORY (p2, 2, 3, 2);
-
-  p3 = Packet (40);
-  ADD_HEADER (p3, 5);
-  ADD_HEADER (p3, 5);
-  CHECK_HISTORY (p3, 3, 5, 5, 40);
-  p1 = p3.CreateFragment (0, 5);
-  p2 = p3.CreateFragment (5, 5);
-  CHECK_HISTORY (p1, 1, 5);
-  CHECK_HISTORY (p2, 1, 5);
-  p1.AddAtEnd (p2);
-  CHECK_HISTORY (p1, 2, 5, 5);
-
-  p = Packet (0);
-  CHECK_HISTORY (p, 0);
-
-  p3 = Packet (0);
-  ADD_HEADER (p3, 5);
-  ADD_HEADER (p3, 5);
-  CHECK_HISTORY (p3, 2, 5, 5);
-  p1 = p3.CreateFragment (0, 4);
-  p2 = p3.CreateFragment (9, 1);
-  CHECK_HISTORY (p1, 1, 4);
-  CHECK_HISTORY (p2, 1, 1);
-  p1.AddAtEnd (p2);
-  CHECK_HISTORY (p1, 2, 4, 1);
-
-
-  p = Packet (2000);
-  CHECK_HISTORY (p, 1, 2000);
-  
-  p = Packet ();
-  ADD_TRAILER (p, 10);
-  ADD_HEADER (p, 5);
-  p1 = p.CreateFragment (0, 8);
-  p2 = p.CreateFragment (8, 7);
-  p1.AddAtEnd (p2);
-  CHECK_HISTORY (p, 2, 5, 10);
-
-  p = Packet ();
-  ADD_TRAILER (p, 10);
-  REM_TRAILER (p, 10);
-  ADD_TRAILER (p, 10);
-  CHECK_HISTORY (p, 1, 10);
-
-  p = Packet ();
-  ADD_HEADER (p, 10);
-  REM_HEADER (p, 10);
-  ADD_HEADER (p, 10);
-  CHECK_HISTORY (p, 1, 10);
-
-  return ok;
-}
-
-static PacketMetadataTest g_packetHistoryTest;
-
-}//namespace ns3
--- a/src/common/packet-metadata.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet-metadata.h	Wed Sep 05 18:35:39 2007 +0100
@@ -100,9 +100,12 @@
 
   uint32_t GetUid (void) const;
 
-  void PrintDefault (std::ostream &os, Buffer buffer) const;
   void Print (std::ostream &os, Buffer buffer, PacketPrinter const &printer) const;
 
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator i, uint32_t size) const;
+  uint32_t Deserialize (Buffer::Iterator i);
+
   static void PrintStats (void);
 
 private:
@@ -254,26 +257,26 @@
 void 
 PacketMetadata::AddHeader (T const &header, uint32_t size)
 {
-  DoAddHeader (PacketPrinter::GetHeaderUid<T> (), size);
+  DoAddHeader (T::GetUid () << 1, size);
 }
 
 template <typename T>
 void 
 PacketMetadata::RemoveHeader (T const &header, uint32_t size)
 {
-  DoRemoveHeader (PacketPrinter::GetHeaderUid<T> (), size);
+  DoRemoveHeader (T::GetUid () << 1, size);
 }
 template <typename T>
 void 
 PacketMetadata::AddTrailer (T const &trailer, uint32_t size)
 {
-  DoAddTrailer (PacketPrinter::GetTrailerUid<T> (), size);
+  DoAddTrailer (T::GetUid () << 1, size);
 }
 template <typename T>
 void 
 PacketMetadata::RemoveTrailer (T const &trailer, uint32_t size)
 {
-  DoRemoveTrailer (PacketPrinter::GetTrailerUid<T> (), size);
+  DoRemoveTrailer (T::GetUid () << 1, size);
 }
 
 
@@ -303,24 +306,23 @@
 PacketMetadata &
 PacketMetadata::operator = (PacketMetadata const& o)
 {
-  if (m_data == o.m_data) 
+  if (m_data != o.m_data) 
     {
-      // self assignment
-      return *this;
+      // not self assignment
+      NS_ASSERT (m_data != 0);
+      m_data->m_count--;
+      if (m_data->m_count == 0) 
+        {
+          PacketMetadata::Recycle (m_data);
+        }
+      m_data = o.m_data;
+      NS_ASSERT (m_data != 0);
+      m_data->m_count++;
     }
-  NS_ASSERT (m_data != 0);
-  m_data->m_count--;
-  if (m_data->m_count == 0) 
-    {
-      PacketMetadata::Recycle (m_data);
-    }
-  m_data = o.m_data;
   m_head = o.m_head;
   m_tail = o.m_tail;
   m_used = o.m_used;
   m_packetUid = o.m_packetUid;
-  NS_ASSERT (m_data != 0);
-  m_data->m_count++;
   return *this;
 }
 PacketMetadata::~PacketMetadata ()
--- a/src/common/packet-printer.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet-printer.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -20,12 +20,13 @@
  */
 
 #include "packet-printer.h"
+#include "chunk-registry.h"
 
 namespace ns3 {
 
 PacketPrinter::PacketPrinter ()
   : m_forward (true),
-    m_separator ("")
+    m_separator (" ")
 {}
 
 void 
@@ -44,44 +45,10 @@
   m_separator = separator;
 }
 void 
-PacketPrinter::AddPayloadPrinter (PayloadPrinter printer)
+PacketPrinter::SetPayloadPrinter (PayloadPrinter printer)
 {
   m_payloadPrinter = printer;
 }
-void 
-PacketPrinter::AddDefaultPrinter (DefaultPrinter printer)
-{
-  m_defaultPrinter = printer;
-}
-
-PacketPrinter::RegisteredChunks *
-PacketPrinter::GetRegisteredChunks (void)
-{
-  static RegisteredChunks registeredChunks;
-  return &registeredChunks;
-}
-
-PacketPrinter 
-PacketPrinter::GetDefault (void)
-{
-  return *(PacketPrinter::PeekDefault ());
-}
-PacketPrinter *
-PacketPrinter::PeekDefault (void)
-{
-  static PacketPrinter *tmp = PacketPrinter::CreateStaticDefault ();
-  return tmp;
-}
-PacketPrinter *
-PacketPrinter::CreateStaticDefault (void)
-{
-  static PacketPrinter tmp;
-  tmp.PrintForward ();
-  tmp.AddPayloadPrinter (MakeCallback (&PacketPrinter::DoDefaultPrintPayload));
-  tmp.SetSeparator (" ");
-  return &tmp;
-}
-
 
 void 
 PacketPrinter::PrintChunk (uint32_t chunkUid, 
@@ -90,26 +57,22 @@
                            uint32_t packetUid,
                            uint32_t size) const
 {
-  RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
-  NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
+  uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid);
+  ChunkRegistry::Deserialize (chunkUid, instance, start);
+
   for (PrinterList::const_iterator i = m_printerList.begin (); i != m_printerList.end (); i++)
     {
       if (i->m_chunkUid == chunkUid)
         {
-          DoPrintCallback cb = (*registeredChunks)[chunkUid/2-1].printCallback;
-          cb (i->m_printer, start, os, packetUid, size);
+          ChunkRegistry::InvokePrintCallback (chunkUid, instance, os, packetUid, size, i->m_printer);
           return;
         }
     }
-  DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
-  std::string name = cb ();
-  struct PacketPrinter::FragmentInformation info;
-  info.start = 0;
-  info.end = 0;
-  if (!m_defaultPrinter.IsNull ())
-    {
-      m_defaultPrinter (os, packetUid, size, name, info);
-    }
+  // if the over did not override this type of chunk,
+  // we print something by default.
+  std::string name = ChunkRegistry::GetName (chunkUid, instance);
+  os << name;
+  ChunkRegistry::Print (chunkUid, instance, os);
 }
 void 
 PacketPrinter::PrintChunkFragment (uint32_t chunkUid,
@@ -119,10 +82,8 @@
                                    uint32_t fragmentStart,
                                    uint32_t fragmentEnd) const
 {
-  RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
-  NS_ASSERT (chunkUid >= 1 && chunkUid/2 <= registeredChunks->size ());
-  DoGetNameCallback cb = (*registeredChunks)[chunkUid/2-1].getNameCallback;
-  std::string name = cb ();
+  uint8_t *instance = ChunkRegistry::GetStaticInstance (chunkUid);
+  std::string name = ChunkRegistry::GetName (chunkUid, instance);
   struct PacketPrinter::FragmentInformation info;
   info.start = fragmentStart;
   info.end = fragmentEnd;
@@ -130,14 +91,20 @@
     {
       if (i->m_chunkUid == chunkUid)
         {
+
           i->m_fragmentPrinter (os, packetUid, size, name, info);
           return;
         }
     }
-  if (!m_defaultPrinter.IsNull ())
-    {
-      m_defaultPrinter (os, packetUid, size, name, info);
-    }
+  // if the user did not override this type of chunk,
+  // we print something by default.
+  NS_ASSERT (info.start != 0 || info.end != 0);
+  os << name << " "
+     << "("
+     << "length " << size - (info.end + info.start) << " "
+     << "trim_start " << info.start << " "
+     << "trim_end " << info.end
+     << ")";
 }
 void 
 PacketPrinter::PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
@@ -149,15 +116,10 @@
   if (!m_payloadPrinter.IsNull ())
     {
       m_payloadPrinter (os, packetUid, size, info);
+      return;
     }
-}
-
-void 
-PacketPrinter::DoDefaultPrintPayload (std::ostream & os,
-                                      uint32_t packetUid,
-                                      uint32_t size,
-                                      struct PacketPrinter::FragmentInformation info)
-{
+  // if the user did not override the payload printer,
+  // we print something anyway.
   os << "DATA ("
      << "length " << size - (info.end + info.start);
   if (info.start != 0 || info.end != 0)
@@ -167,69 +129,7 @@
          << "trim_end " << info.end;
     }
   os << ")";
-}
 
-void 
-PacketPrinter::DoDefaultPrintDefault (std::ostream & os,
-                                      uint32_t packetUid,
-                                      uint32_t size,
-                                      std::string &name,
-                                      struct PacketPrinter::FragmentInformation info)
-{
-  NS_ASSERT_MSG (false, "This should never happen because we provide a printer for _all_ chunk types.");
-}
-
-void 
-PacketPrinter::DoDefaultPrintFragment (std::ostream & os,
-                                       uint32_t packetUid,
-                                       uint32_t size,
-                                       std::string &name,
-                                       struct PacketPrinter::FragmentInformation info)
-{
-  NS_ASSERT (info.start != 0 || info.end != 0);
-  os << name << " "
-     << "("
-     << "length " << size - (info.end + info.start) << " "
-     << "trim_start " << info.start << " "
-     << "trim_end " << info.end
-     << ")"
-    ;
 }
 
-void
-PacketPrinter::DoAddPrinter (uint32_t uid,
-                             Ptr<CallbackImplBase> printer,
-                             Callback<void,
-                             std::ostream &, 
-                             uint32_t, 
-                             uint32_t, 
-                             std::string &,
-                             struct PacketPrinter::FragmentInformation> fragmentPrinter)
-{
-  struct PacketPrinter::Printer p;
-  p.m_chunkUid = uid;
-  p.m_printer = printer;
-  p.m_fragmentPrinter = fragmentPrinter;
-  m_printerList.push_back (p);
-}
-
-bool 
-PacketPrinter::IsTrailer (uint32_t uid)
-{
-  RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
-  NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
-  bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
-  return !isHeader;
-}
-bool 
-PacketPrinter::IsHeader (uint32_t uid)
-{
-  RegisteredChunks *registeredChunks = PacketPrinter::GetRegisteredChunks ();
-  NS_ASSERT (uid >= 1 && uid/2 <= registeredChunks->size ());
-  bool isHeader = (*registeredChunks)[uid/2-1].isHeader;
-  return isHeader;
-}
-
-
-
 } // namespace ns3
--- a/src/common/packet-printer.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet-printer.h	Wed Sep 05 18:35:39 2007 +0100
@@ -26,14 +26,8 @@
 #include "buffer.h"
 #include <vector>
 
-namespace {
-  class ItemList;
-}
-
 namespace ns3 {
 
-class Chunk;
-
 /**
  * \brief hold a list of print callbacks for packet headers and trailers
  *
@@ -92,99 +86,38 @@
    * Print the content of the packet backward.
    */
   void PrintBackward (void);
+  /**
+   * \param separator the new separator
+   *
+   * The default separator is a single space character.
+   */
   void SetSeparator (std::string separator);
   /**
    * \param printer printer for payload
    */
-  void AddPayloadPrinter (PayloadPrinter printer);
+  void SetPayloadPrinter (PayloadPrinter printer);
   /**
    * \param printer printer for the specified chunk
    * \param fragmentPrinter printer for a fragment of the specified chunk
    *
-   * If the user has not specified a callback for a specific header present
-   * in a packet, the "default" callback is invoked. If no such callback
-   * was specified, nothing happens.
+   * If the user does not force a user-specific printing function through
+   * a call to SetHeaderPrinter, the default print output is generated.
    */
   template <typename T>
-  void AddHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+  void SetHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
                          ChunkFragmentPrinter fragmentPrinter);
   /**
    * \param printer printer for the specified chunk
    * \param fragmentPrinter printer for a fragment of the specified chunk
    *
-   * If the user has not specified a callback for a specific trailer present
-   * in a packet, the "default" callback is invoked. If no such callback
-   * was specified, nothing happens.
+   * If the user does not force a user-specific printing function through
+   * a call to SetTrailerPrinter, the default print output is generated.
    */
   template <typename T>
-  void AddTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
-                          ChunkFragmentPrinter fragmentPrinter);
-  /**
-   * \param printer printer for a chunk for which no callback was specified explicitely
-   */
-  void AddDefaultPrinter (DefaultPrinter printer);
-  
+  void SetTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+                          ChunkFragmentPrinter fragmentPrinter);  
 private:
   friend class PacketMetadata;
-  typedef void (*DoPrintCallback) (Ptr<CallbackImplBase>, Buffer::Iterator, std::ostream &,
-                                   uint32_t, uint32_t);
-  typedef std::string (*DoGetNameCallback) (void);
-  struct Printer
-  {
-    uint32_t m_chunkUid;
-    Ptr<CallbackImplBase> m_printer;
-    Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,struct PacketPrinter::FragmentInformation>
-      m_fragmentPrinter;
-  };
-  struct RegisteredChunk
-  {
-    DoPrintCallback printCallback;
-    DoGetNameCallback getNameCallback;
-    bool isHeader;
-  };
-  typedef std::vector<struct PacketPrinter::Printer> PrinterList;
-  typedef std::vector<struct RegisteredChunk> RegisteredChunks;
-
-
-  static PacketPrinter GetDefault (void);
-  static PacketPrinter *PeekDefault (void);
-  static PacketPrinter *CreateStaticDefault (void);
-  static void DoDefaultPrintPayload (std::ostream & os,
-                                     uint32_t packetUid,
-                                     uint32_t size,
-                                     struct PacketPrinter::FragmentInformation info);
-  static void DoDefaultPrintDefault (std::ostream & os,
-                                     uint32_t packetUid,
-                                     uint32_t size,
-                                     std::string &name,
-                                     struct PacketPrinter::FragmentInformation info);
-  template <typename T>
-  static void DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk);
-  static void DoDefaultPrintFragment (std::ostream & os,
-                                      uint32_t packetUid,
-                                      uint32_t size,
-                                      std::string &name,
-                                      struct PacketPrinter::FragmentInformation info);
-
-  template <typename T>
-  static void DoPrint (Ptr<CallbackImplBase> callbackPrinter,
-                       Buffer::Iterator i, 
-                       std::ostream &os, 
-                       uint32_t packetUid,
-                       uint32_t size);
-  template <typename T>
-  static std::string DoGetName (void);
-  template <typename T>
-  static uint32_t GetTrailerUid (void);
-  template <typename T>
-  static uint32_t GetHeaderUid (void);
-  template <typename T>
-  static uint32_t AllocateUid (bool isHeader);
-  static RegisteredChunks *GetRegisteredChunks (void);
-  static bool IsTrailer (uint32_t uid);
-  static bool IsHeader (uint32_t uid);
-
-
   void PrintChunk (uint32_t uid, 
 		   Buffer::Iterator i, 
 		   std::ostream &os, 
@@ -198,16 +131,15 @@
 			   uint32_t fragmentEnd) const;
   void PrintPayload (std::ostream &os, uint32_t packetUid, uint32_t size,
 		     uint32_t fragmentStart, uint32_t fragmentEnd) const;
-  void DoAddPrinter (uint32_t uid,
-                     Ptr<CallbackImplBase> printer,
-                     Callback<void,
-                       std::ostream &, 
-                       uint32_t, 
-                       uint32_t, 
-                       std::string &,
-                       struct PacketPrinter::FragmentInformation> fragmentPrinter);
-
-  static PacketPrinter m_defaultPacketPrinter;
+  struct Printer
+  {
+    uint32_t m_chunkUid;
+    Ptr<CallbackImplBase> m_printer;
+    Callback<void,std::ostream &,uint32_t,uint32_t,std::string &,
+             struct PacketPrinter::FragmentInformation> m_fragmentPrinter;
+  };
+  typedef std::vector<struct PacketPrinter::Printer> PrinterList;
+  
   PrinterList m_printerList;
   PayloadPrinter m_payloadPrinter;
   DefaultPrinter m_defaultPrinter;
@@ -221,97 +153,28 @@
 
 template <typename T>
 void 
-PacketPrinter::AddHeaderPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
-			   Callback<void,
-		            std::ostream &, 
-		            uint32_t, 
-                            uint32_t, 
-                            std::string &,
-		            struct PacketPrinter::FragmentInformation> fragmentPrinter)
+PacketPrinter::SetHeaderPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+                                 ChunkFragmentPrinter fragmentPrinter)
 {
-  static uint32_t uid = PacketPrinter::GetHeaderUid<T> ();
-  DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
+  Printer p;
+  p.m_chunkUid = T::GetUid ();
+  p.m_printer = printer.GetImpl ();
+  p.m_fragmentPrinter = fragmentPrinter;
+  m_printerList.push_back (p);
 }
 
 template <typename T>
 void 
-PacketPrinter::AddTrailerPrinter (Callback<void,std::ostream &, uint32_t, uint32_t, const T *> printer,
-			   Callback<void,
-		            std::ostream &, 
-		            uint32_t, 
-                            uint32_t, 
-                            std::string &,
-		            struct PacketPrinter::FragmentInformation> fragmentPrinter)
+PacketPrinter::SetTrailerPrinter (Callback<void,std::ostream &,uint32_t,uint32_t,const T *> printer,
+                                 ChunkFragmentPrinter fragmentPrinter)
 {
-  static uint32_t uid = PacketPrinter::GetTrailerUid<T> ();
-  DoAddPrinter (uid, printer.GetImpl (), fragmentPrinter);
-}
-
-template <typename T>
-void
-PacketPrinter::DoPrint (Ptr<CallbackImplBase> printerCallback,
-                        Buffer::Iterator i,
-                        std::ostream &os, 
-                        uint32_t packetUid,
-                        uint32_t size)
-{
-  T chunk = T ();
-  chunk.Deserialize (i);
-  Callback<void,std::ostream&,uint32_t,uint32_t,const T*> callback;
-  callback.Assign (printerCallback);
-  callback (os, packetUid, size, &chunk);
-}
-
-template <typename T>
-std::string
-PacketPrinter::DoGetName (void)
-{
-  T chunk = T ();
-  return chunk.GetName ();
+  Printer p;
+  p.m_chunkUid = T::GetUid ();
+  p.m_printer = printer.GetImpl ();
+  p.m_fragmentPrinter = fragmentPrinter;
+  m_printerList.push_back (p);
 }
 
-template <typename T>
-uint32_t 
-PacketPrinter::GetHeaderUid (void)
-{
-  static uint32_t uid = PacketPrinter::AllocateUid<T> (true);
-  return uid;
-}
-
-template <typename T>
-uint32_t 
-PacketPrinter::GetTrailerUid (void)
-{
-  static uint32_t uid = PacketPrinter::AllocateUid<T> (false);
-  return uid;
-}
-
-template <typename T>
-uint32_t
-PacketPrinter::AllocateUid (bool isHeader)
-{
-  RegisteredChunks *chunks = PacketPrinter::GetRegisteredChunks ();
-  RegisteredChunk chunk;
-  chunk.printCallback = &PacketPrinter::DoPrint<T>;
-  chunk.getNameCallback = &PacketPrinter::DoGetName<T>;
-  chunk.isHeader = isHeader;
-  chunks->push_back (chunk);
-  uint32_t uid = chunks->size () * 2;
-  PacketPrinter::PeekDefault ()->DoAddPrinter (uid, 
-                                               MakeCallback (&PacketPrinter::DoDefaultPrint<T>).GetImpl (),
-                                               MakeCallback (&PacketPrinter::DoDefaultPrintFragment));
-  return uid;
-}
-
-template <typename T>
-void 
-PacketPrinter::DoDefaultPrint (std::ostream &os, uint32_t packetUid, uint32_t size, const T *chunk)
-{
-  os << chunk->GetName () << " ";
-  chunk->Print (os);
-}
-
-
 
 } // namespace ns3
 
--- a/src/common/packet.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -74,14 +74,14 @@
 void 
 Packet::AddAtEnd (Packet packet)
 {
-  packet.m_buffer.TransformIntoRealBuffer ();
-  m_buffer.TransformIntoRealBuffer ();
+  Buffer src = packet.m_buffer.CreateFullCopy ();
+  Buffer dst = m_buffer.CreateFullCopy ();
 
-  Buffer src = packet.m_buffer;
-  m_buffer.AddAtEnd (src.GetSize ());
-  Buffer::Iterator destStart = m_buffer.End ();
+  dst.AddAtEnd (src.GetSize ());
+  Buffer::Iterator destStart = dst.End ();
   destStart.Prev (src.GetSize ());
   destStart.Write (src.Begin (), src.End ());
+  m_buffer = dst;
   /**
    * XXX: we might need to merge the tag list of the
    * other packet into the current packet.
@@ -126,9 +126,15 @@
 }
 
 void 
+Packet::PrintTags (std::ostream &os) const
+{
+  m_tags.Print (os, " ");
+}
+
+void 
 Packet::Print (std::ostream &os) const
 {
-  m_metadata.PrintDefault (os, m_buffer);
+  m_metadata.Print (os, m_buffer, PacketPrinter ());
 }
 
 void 
@@ -143,7 +149,58 @@
   PacketMetadata::Enable ();
 }
 
-}; // namespace ns3
+Buffer 
+Packet::Serialize (void) const
+{
+  Buffer buffer;
+  uint32_t reserve;
+
+  // write metadata
+  reserve = m_metadata.GetSerializedSize ();
+  buffer.AddAtStart (reserve);
+  m_metadata.Serialize (buffer.Begin (), reserve);
+
+  // write tags
+  reserve = m_tags.GetSerializedSize ();
+  buffer.AddAtStart (reserve);
+  m_tags.Serialize (buffer.Begin (), reserve);
+  
+  // aggregate byte buffer, metadata, and tags
+  Buffer tmp = m_buffer.CreateFullCopy ();
+  buffer.AddAtStart (tmp.GetSize ());
+  buffer.Begin ().Write (tmp.Begin (), tmp.End ());
+  
+  // write byte buffer size.
+  buffer.AddAtStart (4);
+  buffer.Begin ().WriteU32 (m_buffer.GetSize ());
+
+  return buffer;
+}
+void 
+Packet::Deserialize (Buffer buffer)
+{
+  Buffer buf = buffer;
+  // read size
+  uint32_t packetSize = buf.Begin ().ReadU32 ();
+  buf.RemoveAtStart (4);
+
+  // read buffer.
+  buf.RemoveAtEnd (buf.GetSize () - packetSize);
+  m_buffer = buf;
+
+  // read tags
+  buffer.RemoveAtStart (4 + packetSize);
+  uint32_t tagsDeserialized = m_tags.Deserialize (buffer.Begin ());
+  buffer.RemoveAtStart (tagsDeserialized);
+
+  // read metadata
+  uint32_t metadataDeserialized = 
+    m_metadata.Deserialize (buffer.Begin ());
+  buffer.RemoveAtStart (metadataDeserialized);
+}
+
+
+} // namespace ns3
 
 
 
--- a/src/common/packet.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/packet.h	Wed Sep 05 18:35:39 2007 +0100
@@ -27,6 +27,7 @@
 #include "trailer.h"
 #include "tags.h"
 #include "packet-metadata.h"
+#include "tag.h"
 #include "ns3/callback.h"
 #include "ns3/assert.h"
 
@@ -37,12 +38,15 @@
 /**
  * \brief network packets
  *
- * Each network packet contains a byte buffer and a list of tags.
+ * Each network packet contains a byte buffer, a list of tags, and
+ * metadata.
+ *
  * - The byte buffer stores the serialized content of the headers and trailers 
  * added to a packet. The serialized representation of these headers is expected
  * to match that of real network packets bit for bit (although nothing
  * forces you to do this) which means that the content of a packet buffer
  * is expected to be that of a real packet.
+ *
  * - The list of tags stores an arbitrarily large set of arbitrary 
  * user-provided data structures in the packet: only one instance of
  * each type of data structure is allowed in a list of tags. 
@@ -51,43 +55,22 @@
  * 16 bytes big. Trying to attach bigger data structures will trigger
  * crashes at runtime.
  *
- * Implementing a new type of Header for a new protocol is pretty easy
- * and is a matter of creating a subclass of the ns3::Header base class,
- * and implementing the 4 pure virtual methods defined in ns3::Header.
- * Sample code which shows how to create such a new Header, how to use
- * it, and how to manipulate tags is shown below:
- * \include samples/main-packet.cc
- *
- * The current implementation of the byte buffers and tag list is based
- * on COW (Copy On Write. An introduction to COW can be found in Scott 
- * Meyer's "More Effective C++", items 17 and 29). What this means is that
- * copying packets without modifying them is very cheap (in terms of cpu
- * and memory usage) and modifying them can be also very cheap. What is 
- * key for proper COW implementations is being
- * able to detect when a given modification of the state of a packet triggers
- * a full copy of the data prior to the modification: COW systems need
- * to detect when an operation is "dirty".
+ * - The metadata describes the type of the headers and trailers which
+ * were serialized in the byte buffer. The maintenance of metadata is
+ * optional and disabled by default. To enable it, you must call
+ * Packet::EnableMetadata and this will allow you to get non-empty
+ * output from Packet::Print and Packet::Print.
  *
- * Dirty operations:
- *   - ns3::Packet::RemoveTag
- *   - ns3::Packet::Add
- *   - both versions of ns3::Packet::AddAtEnd
+ * Implementing a new type of Header or Trailer for a new protocol is 
+ * pretty easy and is a matter of creating a subclass of the ns3::Header 
+ * or of the ns3::Trailer base class, and implementing the methods
+ * described in their respective API documentation.
  *
- * Non-dirty operations:
- *   - ns3::Packet::AddTag
- *   - ns3::Packet::RemoveAllTags
- *   - ns3::Packet::PeekTag
- *   - ns3::Packet::Peek
- *   - ns3::Packet::Remove
- *   - ns3::Packet::CreateFragment
- *   - ns3::Packet::RemoveAtStart
- *   - ns3::Packet::RemoveAtEnd
+ * Implementing a new type of Tag requires roughly the same amount of
+ * work and this work is described in the ns3::Tag API documentation.
  *
- * Dirty operations will always be slower than non-dirty operations,
- * sometimes by several orders of magnitude. However, even the
- * dirty operations have been optimized for common use-cases which
- * means that most of the time, these operations will not trigger
- * data copies and will thus be still very fast.
+ * The performance aspects of the Packet API are discussed in 
+ * \ref packetperf
  */
 class Packet {
 public:
@@ -132,7 +115,7 @@
   uint32_t GetSize (void) const;
   /**
    * Add header to this packet. This method invokes the
-   * ns3::Chunk::GetSerializedSize and ns3::Chunk::SerializeTo 
+   * GetSerializedSize and Serialize
    * methods to reserve space in the buffer and request the 
    * header to serialize itself in the packet buffer.
    *
@@ -142,7 +125,7 @@
   void AddHeader (T const &header);
   /**
    * Deserialize and remove the header from the internal buffer.
-   * This method invokes ns3::Chunk::DeserializeFrom.
+   * This method invokes Deserialize.
    *
    * \param header a reference to the header to remove from the internal buffer.
    * \returns the number of bytes removed from the packet.
@@ -151,7 +134,7 @@
   uint32_t RemoveHeader (T &header);
   /**
    * Add trailer to this packet. This method invokes the
-   * ns3::Chunk::GetSerializedSize and ns3::Trailer::serializeTo 
+   * GetSerializedSize and Serialize
    * methods to reserve space in the buffer and request the trailer 
    * to serialize itself in the packet buffer.
    *
@@ -161,7 +144,7 @@
   void AddTrailer (T const &trailer);
   /**
    * Remove a deserialized trailer from the internal buffer.
-   * This method invokes the ns3::Chunk::DeserializeFrom method.
+   * This method invokes the Deserialize method.
    *
    * \param trailer a reference to the trailer to remove from the internal buffer.
    * \returns the number of bytes removed from the end of the packet.
@@ -171,7 +154,8 @@
   /**
    * Attach a tag to this packet. The tag is fully copied
    * in a packet-specific internal buffer. This operation 
-   * is expected to be really fast.
+   * is expected to be really fast. The copy constructor of the
+   * tag is invoked to copy it into the tag buffer.
    *
    * \param tag a pointer to the tag to attach to this packet.
    */
@@ -198,6 +182,8 @@
   /**
    * Copy a tag stored internally to the input tag. If no instance
    * of this tag is present internally, the input tag is not modified.
+   * The copy constructor of the tag is invoked to copy it into the 
+   * input tag variable.
    *
    * \param tag a pointer to the tag to read from this packet
    * \returns true if an instance of this tag type is stored
@@ -211,6 +197,14 @@
    */
   void RemoveAllTags (void);
   /**
+   * \param os output stream in which the data should be printed.
+   *
+   * Iterate over the tags present in this packet, and
+   * invoke the Print method of each tag stored in the packet.
+   */
+  void PrintTags (std::ostream &os) const;
+
+  /**
    * Concatenate the input packet at the end of the current
    * packet. This does not alter the uid of either packet.
    *
@@ -294,6 +288,38 @@
    * errors will be detected and will abort the program.
    */
   static void EnableMetadata (void);
+
+  /**
+   * \returns a byte buffer
+   *
+   * This method creates a serialized representation of a Packet object
+   * ready to be transmitted over a network to another system. This
+   * serialized representation contains a copy of the packet byte buffer,
+   * the tag list, and the packet metadata (if there is one).
+   *
+   * This method will trigger calls to the Serialize and GetSerializedSize
+   * methods of each tag stored in this packet.
+   *
+   * This method will typically be used by parallel simulations where
+   * the simulated system is partitioned and each partition runs on
+   * a different CPU.
+   */
+  Buffer Serialize (void) const;
+  /**
+   * \param buffer a byte buffer
+   *
+   * This method reads a byte buffer as created by Packet::Serialize
+   * and restores the state of the Packet to what it was prior to
+   * calling Serialize.
+   *
+   * This method will trigger calls to the Deserialize method
+   * of each tag stored in this packet.
+   *
+   * This method will typically be used by parallel simulations where
+   * the simulated system is partitioned and each partition runs on
+   * a different CPU.
+   */
+  void Deserialize (Buffer buffer);
 private:
   Packet (Buffer buffer, Tags tags, PacketMetadata metadata);
   Buffer m_buffer;
@@ -302,7 +328,42 @@
   static uint32_t m_globalUid;
 };
 
-}; // namespace ns3
+/**
+ * \defgroup packetperf Packet Performance
+ * The current implementation of the byte buffers and tag list is based
+ * on COW (Copy On Write. An introduction to COW can be found in Scott 
+ * Meyer's "More Effective C++", items 17 and 29). What this means is that
+ * copying packets without modifying them is very cheap (in terms of cpu
+ * and memory usage) and modifying them can be also very cheap. What is 
+ * key for proper COW implementations is being
+ * able to detect when a given modification of the state of a packet triggers
+ * a full copy of the data prior to the modification: COW systems need
+ * to detect when an operation is "dirty".
+ *
+ * Dirty operations:
+ *   - ns3::Packet::RemoveTag
+ *   - ns3::Packet::AddHeader
+ *   - ns3::Packet::AddTrailer
+ *   - both versions of ns3::Packet::AddAtEnd
+ *
+ * Non-dirty operations:
+ *   - ns3::Packet::AddTag
+ *   - ns3::Packet::RemoveAllTags
+ *   - ns3::Packet::PeekTag
+ *   - ns3::Packet::RemoveHeader
+ *   - ns3::Packet::RemoveTrailer
+ *   - ns3::Packet::CreateFragment
+ *   - ns3::Packet::RemoveAtStart
+ *   - ns3::Packet::RemoveAtEnd
+ *
+ * Dirty operations will always be slower than non-dirty operations,
+ * sometimes by several orders of magnitude. However, even the
+ * dirty operations have been optimized for common use-cases which
+ * means that most of the time, these operations will not trigger
+ * data copies and will thus be still very fast.
+ */
+
+} // namespace ns3
 
 
 /**************************************************
@@ -316,9 +377,11 @@
 void
 Packet::AddHeader (T const &header)
 {
-  NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0, 
-                 "Must pass Header subclass to Packet::AddHeader");
-  uint32_t size = header.GetSize ();
+  const Header *testHeader;
+  // if the following assignment fails, it is because the 
+  // input to this function is not a subclass of the Header class
+  testHeader = &header;
+  uint32_t size = header.GetSerializedSize ();
   m_buffer.AddAtStart (size);
   header.Serialize (m_buffer.Begin ());
   m_metadata.AddHeader (header, size);
@@ -327,8 +390,10 @@
 uint32_t
 Packet::RemoveHeader (T &header)
 {
-  NS_ASSERT_MSG (dynamic_cast<Header const *> (&header) != 0, 
-                 "Must pass Header subclass to Packet::RemoveHeader");
+  Header *testHeader;
+  // if the following assignment fails, it is because the 
+  // input to this function is not a subclass of the Header class
+  testHeader = &header;
   uint32_t deserialized = header.Deserialize (m_buffer.Begin ());
   m_buffer.RemoveAtStart (deserialized);
   m_metadata.RemoveHeader (header, deserialized);
@@ -338,9 +403,11 @@
 void
 Packet::AddTrailer (T const &trailer)
 {
-  NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0, 
-                 "Must pass Trailer subclass to Packet::AddTrailer");
-  uint32_t size = trailer.GetSize ();
+  const Trailer *testTrailer;
+  // if the following assignment fails, it is because the 
+  // input to this function is not a subclass of the Trailer class
+  testTrailer = &trailer;
+  uint32_t size = trailer.GetSerializedSize ();
   m_buffer.AddAtEnd (size);
   Buffer::Iterator end = m_buffer.End ();
   trailer.Serialize (end);
@@ -350,8 +417,10 @@
 uint32_t
 Packet::RemoveTrailer (T &trailer)
 {
-  NS_ASSERT_MSG (dynamic_cast<Trailer const *> (&trailer) != 0, 
-                 "Must pass Trailer subclass to Packet::RemoveTrailer");
+  Trailer *testTrailer;
+  // if the following assignment fails, it is because the 
+  // input to this function is not a subclass of the Trailer class
+  testTrailer = &trailer;
   uint32_t deserialized = trailer.Deserialize (m_buffer.End ());
   m_buffer.RemoveAtEnd (deserialized);
   m_metadata.RemoveTrailer (trailer, deserialized);
@@ -362,18 +431,31 @@
 template <typename T>
 void Packet::AddTag (T const& tag)
 {
+  const Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   m_tags.Add (tag);
 }
 template <typename T>
 bool Packet::RemoveTag (T & tag)
 {
+  Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   return m_tags.Remove (tag);
 }
 template <typename T>
 bool Packet::PeekTag (T & tag) const
 {
+  Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   return m_tags.Peek (tag);
 }
-}; // namespace ns3
+
+} // namespace ns3
 
 #endif /* PACKET_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-registry.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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 "tag-registry.h"
+#include "ns3/fatal-error.h"
+
+namespace ns3 {
+
+TagRegistry::TagInfoVector *
+TagRegistry::GetInfo (void)
+{
+  static TagRegistry::TagInfoVector vector;
+  return &vector;
+}
+
+std::string
+TagRegistry::GetUidString (uint32_t uid)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  return info.uidString;
+}
+uint32_t 
+TagRegistry::GetUidFromUidString (std::string uidString)
+{
+  TagInfoVector *vec = GetInfo ();
+  uint32_t uid = 1;
+  for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == uidString)
+        {
+          return uid;
+        }
+      uid++;
+    }
+  NS_FATAL_ERROR ("We are trying to deserialize an un-registered type. This can't work.");
+  return 0;
+}
+
+void 
+TagRegistry::Destruct (uint32_t uid, uint8_t *data)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  info.destruct (data);
+}
+void 
+TagRegistry::Print (uint32_t uid, uint8_t *data, std::ostream &os)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  info.print (data, os);
+}
+uint32_t
+TagRegistry::GetSerializedSize (uint32_t uid, uint8_t *data)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  return info.getSerializedSize (data);
+}
+void 
+TagRegistry::Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  info.serialize (data, start);
+}
+uint32_t 
+TagRegistry::Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start)
+{
+  TagInfo info = (*GetInfo ())[uid - 1];
+  return info.deserialize (data, start);
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag-registry.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,149 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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 TAG_REGISTRY_H
+#define TAG_REGISTRY_H
+
+#include <string>
+#include <stdint.h>
+#include "buffer.h"
+
+namespace ns3 {
+
+/**
+ * \brief a registry of all existing tag types.
+ * \internal
+ *
+ * This class is used to give polymorphic access to the methods
+ * exported by a tag. It also is used to associate a single
+ * reliable uid to each unique type. 
+ */
+class TagRegistry
+{
+public:
+  template <typename T>
+  static uint32_t Register (std::string uidString);
+  static std::string GetUidString (uint32_t uid);
+  static uint32_t GetUidFromUidString (std::string uidString);
+  static void Destruct (uint32_t uid, uint8_t *data);
+  static void Print (uint32_t uid, uint8_t *data, std::ostream &os);
+  static uint32_t GetSerializedSize (uint32_t uid, uint8_t *data);
+  static void Serialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
+  static uint32_t Deserialize (uint32_t uid, uint8_t *data, Buffer::Iterator start);
+private:
+  typedef void (*DestructCb) (uint8_t *);
+  typedef void (*PrintCb) (uint8_t *, std::ostream &);
+  typedef uint32_t (*GetSerializedSizeCb) (uint8_t *);
+  typedef void (*SerializeCb) (uint8_t *, Buffer::Iterator);
+  typedef uint32_t (*DeserializeCb) (uint8_t *, Buffer::Iterator);
+  struct TagInfo
+  {
+    std::string uidString;
+    DestructCb destruct;
+    PrintCb print;
+    GetSerializedSizeCb getSerializedSize;
+    SerializeCb serialize;
+    DeserializeCb deserialize;
+  };
+  typedef std::vector<struct TagInfo> TagInfoVector;
+
+  template <typename T>
+  static void DoDestruct (uint8_t *data);
+  template <typename T>
+  static void DoPrint (uint8_t *data, std::ostream &os);
+  template <typename T>
+  static uint32_t DoGetSerializedSize (uint8_t *data);
+  template <typename T>
+  static void DoSerialize (uint8_t *data, Buffer::Iterator start);
+  template <typename T>
+  static uint32_t DoDeserialize (uint8_t *data, Buffer::Iterator start);
+
+  static TagInfoVector *GetInfo (void);
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+void 
+TagRegistry::DoDestruct (uint8_t *data)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  tag->~T ();  
+}
+template <typename T>
+void 
+TagRegistry::DoPrint (uint8_t *data, std::ostream &os)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  tag->Print (os);
+}
+template <typename T>
+uint32_t 
+TagRegistry::DoGetSerializedSize (uint8_t *data)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  return tag->GetSerializedSize ();
+}
+template <typename T>
+void 
+TagRegistry::DoSerialize (uint8_t *data, Buffer::Iterator start)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  tag->Serialize (start);
+}
+template <typename T>
+uint32_t 
+TagRegistry::DoDeserialize (uint8_t *data, Buffer::Iterator start)
+{
+  T *tag = reinterpret_cast<T *> (data);
+  return tag->Deserialize (start);
+}
+
+template <typename T>
+uint32_t 
+TagRegistry::Register (std::string uidString)
+{
+  TagInfoVector *vec = GetInfo ();
+  uint32_t j = 0;
+  for (TagInfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == uidString)
+        {
+          return j;
+        }
+      j++;
+    }
+  TagInfo info;
+  info.uidString = uidString;
+  info.destruct = &TagRegistry::DoDestruct<T>;
+  info.print = &TagRegistry::DoPrint<T>;
+  info.getSerializedSize = &TagRegistry::DoGetSerializedSize<T>;
+  info.serialize = &TagRegistry::DoSerialize<T>;
+  info.deserialize = &TagRegistry::DoDeserialize<T>;
+  vec->push_back (info);
+  uint32_t uid = vec->size ();
+  return uid;
+}
+
+} // namespace ns3
+
+#endif /* TAG_REGISTRY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/tag.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,126 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 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 TAG_H
+#define TAG_H
+
+#include <stdint.h>
+#include <string>
+
+/**
+ * \relates ns3::Tag
+ * \brief this macro should be instantiated exactly once for each
+ *        new type of Tag
+ *
+ * This macro will ensure that your new Tag type is registered
+ * within the tag registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_TAG_ENSURE_REGISTERED(x)	       \
+static class thisisaveryverylongclassname ##x  \
+{					       \
+ public:				       \
+  thisisaveryverylongclassname ##x ()          \
+    { uint32_t uid; uid = x::GetUid ();}       \
+} g_thisisanotherveryveryverylongname ## x;
+
+namespace ns3 {
+
+/**
+ * \brief a tag can be stored in a packet.
+ *
+ * A tag is a blob of 16 bytes of data which can be stored in
+ * a packet: a packet can contain an arbitrary number of tags
+ * and these tags are considered as "on-the-side" per-packet
+ * data structures which are not taken into account when calculating
+ * the size of the payload of a packet. They exist solely as 
+ * simulation-specific objects.
+ *
+ * Tags are typically used to:
+ *   - implement per-packet cross-layer communication
+ *   - implement packet coloring: you could store a "color" tag
+ *     in a packet to mark various types of packet for
+ *     simulation analysis
+ *
+ * To create a new type of tag, you must create a subclass
+ * of the Tag base class which defines:
+ *  - a public default constructor: needed for implementation
+ *    purposes of the Packet code.
+ *  - a public copy constructor: needed to copy a tag into
+ *    a packet tag buffer when the user invokes Packet::AddTag
+ *  - a public destructor: needed to destroy the copy of a tag
+ *    stored in a packet buffer when the user invokes Packet::RemoveTag
+ *    or when the packet is destroyed and the last reference to 
+ *    a tag instance disapears.
+ *  - a public static method named GetUid: needed to uniquely
+ *    the type of each tag instance.
+ *  - a public method named Print: needed to print the content
+ *    of a tag when the user calls Packet::PrintTags
+ *  - a public method named GetSerializedSize: needed to serialize
+ *    the content of a tag to a byte buffer when a packet must
+ *    be sent from one computing node to another in a parallel 
+ *    simulation. If this method returns 0, it means that the
+ *    tag does not need to be transfered from computing node to 
+ *     computing node
+ *  - a public method named Serialize: perform the serialization
+ *    to a byte buffer upon transfer to a new computing node in a 
+ *    parallel simulation.
+ *  - a public method named Deserialize: invert the serialization
+ *    from a byte buffer after being transfered to a new computing
+ *    node in a parallel simulation.
+ *
+ * A detailed example of what these methods should look like
+ * and how they should be implemented is described in samples/main-packet-tag.cc
+ */
+class Tag
+{
+protected:
+  /**
+   * \param name the unique name of the new type of tag
+   * \returns a newly-allocated uid
+   *
+   * This method should be used by subclasses to implement
+   * their static public GetUid method.
+   */
+  template <typename T>
+  static uint32_t AllocateUid (std::string name);
+};
+
+} // namespace ns3
+
+// implementation below.
+#include "tag-registry.h"
+
+namespace ns3 {
+
+template <typename T>
+uint32_t
+Tag::AllocateUid (std::string name)
+{
+  return TagRegistry::Register<T> (name);
+}
+
+} // namespace ns3
+
+#endif /* TAG_H */
--- a/src/common/tags.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/tags.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -20,84 +20,10 @@
  */
 #include "tags.h"
 #include <string.h>
+#include "ns3/fatal-error.h"
 
 namespace ns3 {
 
-TagRegistry *
-TagRegistry::GetInstance (void)
-{
-  static TagRegistry registry;
-  return &registry;
-}
-
-TagRegistry::TagRegistry ()
-  : m_sorted (false)
-{}
-
-
-void 
-TagRegistry::Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor)
-{
-  NS_ASSERT (!m_sorted);
-  struct TagInfoItem item;
-  item.uuid = uuid;
-  item.printer = prettyPrinter;
-  item.destructor = destructor;
-  m_registry.push_back (item);
-}
-bool 
-TagRegistry::CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b)
-{
-  return a.uuid < b.uuid;
-}
-uint32_t 
-TagRegistry::LookupUid (std::string uuid)
-{
-  if (!m_sorted) 
-    {
-      std::sort (m_registry.begin (), m_registry.end (), &TagRegistry::CompareItem);
-      m_sorted = true;
-    }
-  NS_ASSERT (m_sorted);
-  uint32_t uid = 1;
-  for (TagsDataCI i = m_registry.begin (); i != m_registry.end (); i++) 
-    {
-      if (i->uuid == uuid) 
-        {
-          return uid;
-        }
-      uid++;
-    }
-  // someone asked for a uid for an unregistered uuid.
-  NS_ASSERT (!"You tried to use unregistered tag: make sure you create an instance of type TagRegistration<YouTagType>.");
-  // quiet compiler
-  return 0;
-}
-void 
-TagRegistry::PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os)
-{
-  NS_ASSERT (uid > 0);
-  uint32_t index = uid - 1;
-  NS_ASSERT (m_registry.size () > index);
-  PrettyPrinter prettyPrinter = m_registry[index].printer;
-  if (prettyPrinter != 0) 
-    {
-      prettyPrinter (buf, os);
-    }
-}
-void 
-TagRegistry::Destruct (uint32_t uid, uint8_t buf[Tags::SIZE])
-{
-  NS_ASSERT (uid > 0);
-  uint32_t index = uid - 1;
-  NS_ASSERT (m_registry.size () > index);
-  Destructor destructor = m_registry[index].destructor;
-  NS_ASSERT (destructor != 0);
-  destructor (buf);
-}
-
-
-
 #ifdef USE_FREE_LIST
 
 struct Tags::TagData *Tags::gFree = 0;
@@ -193,13 +119,102 @@
 }
 
 void 
-Tags::PrettyPrint (std::ostream &os)
+Tags::Print (std::ostream &os, std::string separator) const
 {
   for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
     {
-      TagRegistry::GetInstance ()->PrettyPrint (cur->m_id, cur->m_data, os);
+      TagRegistry::Print (cur->m_id, cur->m_data, os);
+      if (cur->m_next != 0)
+        {
+          os << separator;
+        }
+    }
+}
+
+uint32_t
+Tags::GetSerializedSize (void) const
+{
+  uint32_t totalSize = 4; // reserve space for the size of the tag data.
+  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
+    {
+      uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
+      if (size != 0)
+        {
+          std::string uidString = TagRegistry::GetUidString (cur->m_id);
+          totalSize += 4; // for the size of the string itself.
+          totalSize += uidString.size ();
+          totalSize += size;
+        }
+    }
+  return totalSize;
+}
+
+void 
+Tags::Serialize (Buffer::Iterator i, uint32_t totalSize) const
+{
+  i.WriteU32 (totalSize);
+  for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
+    {
+      uint32_t size = TagRegistry::GetSerializedSize (cur->m_id, cur->m_data);
+      if (size != 0)
+        {
+          std::string uidString = TagRegistry::GetUidString (cur->m_id);
+          i.WriteU32 (uidString.size ());
+          uint8_t *buf = (uint8_t *)uidString.c_str ();
+          i.Write (buf, uidString.size ());
+          TagRegistry::Serialize (cur->m_id, cur->m_data, i);
+        }
     }
 }
+uint32_t
+Tags::Deserialize (Buffer::Iterator i)
+{
+  uint32_t totalSize = i.ReadU32 ();
+  uint32_t bytesRead = 4;
+  while (bytesRead < totalSize)
+    {
+      uint32_t uidStringSize = i.ReadU32 ();
+      bytesRead += 4;
+      std::string uidString;
+      uidString.reserve (uidStringSize);
+      for (uint32_t j = 0; j < uidStringSize; j++)
+        {
+          uint32_t c = i.ReadU8 ();
+          uidString.push_back (c);
+        }
+      bytesRead += uidStringSize;
+      uint32_t uid = TagRegistry::GetUidFromUidString (uidString);
+      struct TagData *newStart = AllocData ();
+      newStart->m_count = 1;
+      newStart->m_next = 0;
+      newStart->m_id = uid;
+      bytesRead += TagRegistry::Deserialize (uid, newStart->m_data, i);
+      newStart->m_next = m_next;
+      m_next = newStart;
+    }
+  NS_ASSERT (bytesRead == totalSize);
+  /**
+   * The process of serialization/deserialization 
+   * results in an inverted linked-list after
+   * deserialization so, we invert the linked-list
+   * in-place here.
+   * Note: the algorithm below is pretty classic
+   * but whenever I get to code it, it makes my
+   * brain hurt :)
+   */
+  struct TagData *prev = 0;
+  struct TagData *cur = m_next;
+  while (cur != 0)
+    {
+      struct TagData *next = cur->m_next;
+      cur->m_next = prev;
+      prev = cur;
+      cur = next;
+    }
+  m_next = prev;
+  return totalSize;
+}
+
 
 
 }; // namespace ns3
@@ -224,25 +239,67 @@
   virtual bool RunTests (void);
 };
 
-struct myTagA {
+class myTagA : public Tag
+{
+public:
+  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagA> ("myTagA.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {g_a = true;}
+  uint32_t GetSerializedSize (void) const {return 1;}
+  void Serialize (Buffer::Iterator i) const {i.WriteU8 (a);}
+  uint32_t Deserialize (Buffer::Iterator i) {a = i.ReadU8 (); return 1;}
+
   uint8_t a;
 };
-struct myTagB {
+class myTagB : public Tag
+{
+public:
+  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagB> ("myTagB.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {g_b = true;}
+  uint32_t GetSerializedSize (void) const {return 4;}
+  void Serialize (Buffer::Iterator i) const {i.WriteU32 (b);}
+  uint32_t Deserialize (Buffer::Iterator i) {b = i.ReadU32 (); return 4;}
+
   uint32_t b;
 };
-struct myTagC {
+class myTagC : public Tag
+{
+public:
+  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagC> ("myTagC.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {g_c = true;}
+  uint32_t GetSerializedSize (void) const {return Tags::SIZE;}
+  void Serialize (Buffer::Iterator i) const {i.Write (c, Tags::SIZE);}
+  uint32_t Deserialize (Buffer::Iterator i) {i.Read (c, Tags::SIZE); return Tags::SIZE;}
   uint8_t c [Tags::SIZE];
 };
-struct myInvalidTag {
+class myInvalidTag : public Tag
+{
+public:
+  static uint32_t GetUid (void) 
+  {static uint32_t uid = AllocateUid<myInvalidTag> ("myinvalidTag.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
   uint8_t invalid [Tags::SIZE+1];
 };
-struct myTagZ {
+class myTagZ  : public Tag
+{
+public:
+  static uint32_t GetUid (void) {static uint32_t uid = AllocateUid<myTagZ> ("myTagZ.test.nsnam.org"); return uid;}
+  void Print (std::ostream &os) const {g_z = true;}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
+
   uint8_t z;
 };
 
-class MySmartTag 
+class MySmartTag : public Tag
 {
 public:
+  static uint32_t GetUid (void) 
+  {static uint32_t uid = AllocateUid<MySmartTag> ("MySmartTag.test.nsnam.org"); return uid;}
   MySmartTag ()
   {
     //std::cout << "construct" << std::endl;
@@ -260,43 +317,12 @@
     //std::cout << "assign" << std::endl;
     return *this;
   }
-  static void PrettyPrinterCb (const MySmartTag *a, std::ostream &os)
-  {}
+  void Print (std::ostream &os) const {}
+  uint32_t GetSerializedSize (void) const {return 0;}
+  void Serialize (Buffer::Iterator i) const {}
+  uint32_t Deserialize (Buffer::Iterator i) {return 0;}
 };
 
-static void 
-myTagAPrettyPrinterCb (struct myTagA const*a, std::ostream &os)
-{
-  //os << "struct myTagA, a="<<(uint32_t)a->a<<std::endl;
-  g_a = true;
-}
-static void 
-myTagBPrettyPrinterCb (struct myTagB const*b, std::ostream &os)
-{
-  //os << "struct myTagB, b="<<b->b<<std::endl;
-  g_b = true;
-}
-static void 
-myTagCPrettyPrinterCb (struct myTagC const*c, std::ostream &os)
-{
-  //os << "struct myTagC, c="<<(uint32_t)c->c[0]<<std::endl;
-  g_c = true;
-}
-static void 
-myTagZPrettyPrinterCb (struct myTagZ const*z, std::ostream &os)
-{
-  //os << "struct myTagZ" << std::endl;
-  g_z = true;
-}
-
-
-static TagRegistration<struct myTagA> gMyTagARegistration ("A", &myTagAPrettyPrinterCb);
-static TagRegistration<struct myTagB> gMyTagBRegistration ("B", &myTagBPrettyPrinterCb);
-static TagRegistration<struct myTagC> gMyTagCRegistration ("C", &myTagCPrettyPrinterCb);
-static TagRegistration<struct myTagZ> g_myTagZRegistration ("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", 
-                                                            &myTagZPrettyPrinterCb);
-static TagRegistration<MySmartTag> g_myTagSmartRegistration ("SmartTag", &MySmartTag::PrettyPrinterCb);
-
 
 TagsTest::TagsTest ()
   : Test ("Tags")
@@ -311,7 +337,7 @@
 
   // build initial tag.
   Tags tags;
-  struct myTagA a;
+  myTagA a;
   a.a = 10;
   tags.Add (a);
   a.a = 0;
@@ -321,12 +347,12 @@
       ok = false;
     }
   g_a = false;
-  tags.PrettyPrint (std::cout);
+  tags.Print (std::cout, "");
   if (!g_a)
     {
       ok = false;
     }
-  struct myTagB b;
+  myTagB b;
   b.b = 0xff;
   tags.Add (b);
   b.b = 0;
@@ -337,7 +363,7 @@
     }
   g_b = false;
   g_a = false;
-  tags.PrettyPrint (std::cout);
+  tags.Print (std::cout, "");
   if (!g_a || !g_b)
     {
       ok = false;
@@ -346,26 +372,26 @@
   Tags other = tags;
   g_b = false;
   g_a = false;
-  other.PrettyPrint (std::cout);
+  other.Print (std::cout, "");
   if (!g_a || !g_b)
     {
       ok = false;
     }
   g_b = false;
   g_a = false;
-  tags.PrettyPrint (std::cout);
+  tags.Print (std::cout, "");
   if (!g_a || !g_b)
     {
       ok = false;
     }
-  struct myTagA oA;
+  myTagA oA;
   oA.a = 0;
   other.Peek (oA);
   if (oA.a != 10) 
     {
       ok = false;
     }
-  struct myTagB oB;
+  myTagB oB;
   oB.b = 1;
   other.Peek (oB);
   if (oB.b != 0xff) 
@@ -380,7 +406,7 @@
     }
   g_b = false;
   g_a = false;
-  other.PrettyPrint (std::cout);
+  other.Print (std::cout, "");
   if (g_a || !g_b)
     {
       ok = false;
@@ -401,7 +427,7 @@
 
   other = tags;
   Tags another = other;
-  struct myTagC c;
+  myTagC c;
   memset (c.c, 0x66, 16);
   another.Add (c);
   c.c[0] = 0;
@@ -421,12 +447,12 @@
   //struct myInvalidTag invalid;
   //tags.add (&invalid);
 
-  struct myTagZ tagZ;
+  myTagZ tagZ;
   Tags testLastTag;
   tagZ.z = 0;
   testLastTag.Add (tagZ);
   g_z = false;
-  testLastTag.PrettyPrint (std::cout);
+  testLastTag.Print (std::cout, "");
   if (!g_z)
     {
       ok = false;
@@ -440,6 +466,58 @@
     tmp.Remove (smartTag);
   }
 
+  {
+    Tags source;
+    myTagA aSource;
+    aSource.a = 0x66;
+    source.Add (aSource);
+    Buffer buffer;
+    uint32_t serialized = source.GetSerializedSize ();
+    buffer.AddAtStart (serialized);
+    source.Serialize (buffer.Begin (), serialized);
+    Tags dest;
+    dest.Deserialize (buffer.Begin ());
+    myTagA aDest;
+    aDest.a = 0x55;
+    dest.Peek (aDest);
+    if (aDest.a != 0x66)
+      {
+        ok = false;
+      }
+  }
+
+  {
+    Tags source;
+    myTagA aSource;
+    aSource.a = 0x66;
+    source.Add (aSource);
+    myTagZ zSource;
+    zSource.z = 0x77;
+    source.Add (zSource);
+
+    Buffer buffer;
+    uint32_t serialized = source.GetSerializedSize ();
+    buffer.AddAtStart (serialized);
+    source.Serialize (buffer.Begin (), serialized);
+    Tags dest;
+    dest.Deserialize (buffer.Begin ());
+
+    myTagA aDest;
+    aDest.a = 0x55;
+    dest.Peek (aDest);
+    if (aDest.a != 0x66)
+      {
+        ok = false;
+      }
+    myTagZ zDest;
+    zDest.z = 0x44;
+    dest.Peek (zDest);
+    if (zDest.z != 0x44)
+      {
+        ok = false;
+      }
+  }
+
   return ok;
 }
 
--- a/src/common/tags.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/tags.h	Wed Sep 05 18:35:39 2007 +0100
@@ -24,12 +24,10 @@
 #include <stdint.h>
 #include <ostream>
 #include <vector>
+#include "buffer.h"
 
 namespace ns3 {
 
-template <typename T>
-class TagPrettyPrinter;
-
 /**
  * \ingroup constants
  * \brief Tag maximum size
@@ -54,7 +52,10 @@
   template <typename T>
   bool Peek (T &tag) const;
 
-  void PrettyPrint (std::ostream &os);
+  void Print (std::ostream &os, std::string separator) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator i, uint32_t size) const;
+  uint32_t Deserialize (Buffer::Iterator i);
 
   inline void RemoveAll (void);
 
@@ -79,161 +80,39 @@
   struct TagData *m_next;
 };
 
-/**
- * \brief pretty print packet tags
- * 
- * This class is used to register a pretty-printer
- * callback function to print in a nice user-friendly
- * way the content of the target type. To register
- * such a type, all you need to do is instantiate
- * an instance of this type as a static variable.
- */
-template <typename T>
-class TagRegistration {
-public:
-  /**
-   * \param uuid a uuid generated with uuidgen
-   * \param fn a function which can pretty-print an instance
-   *        of type T in the output stream.
-   */
-  TagRegistration<T> (std::string uuid, void(*fn) (T const*, std::ostream &));
-private:
-  static void PrettyPrinterCb (uint8_t *buf, std::ostream &os);
-  static void DestructorCb (uint8_t *buf);
-  static void(*m_prettyPrinter) (T const*, std::ostream &);
-};
-
-}; // namespace ns3
+} // namespace ns3
 
 
 
 /**************************************************************
    An implementation of the templates defined above
  *************************************************************/
+#include "tag-registry.h"
+#include "tag.h"
 #include "ns3/assert.h"
 #include <string>
 
 namespace ns3 {
 
-class TagRegistry {
-public:
-  typedef void (*PrettyPrinter) (uint8_t [Tags::SIZE], std::ostream &);
-  typedef void (*Destructor) (uint8_t [Tags::SIZE]);
-  void Record (std::string uuid, PrettyPrinter prettyPrinter, Destructor destructor);
-  /**
-   * returns a numeric integer which uniquely identifies the input string.
-   * that integer cannot be zero which is a reserved value.
-   */
-  uint32_t LookupUid (std::string uuid);
-  void PrettyPrint (uint32_t uid, uint8_t buf[Tags::SIZE], std::ostream &os);
-  void Destruct (uint32_t uid, uint8_t buf[Tags::SIZE]);
-
-  static TagRegistry *GetInstance (void);
-private:
-  TagRegistry ();
-  struct TagInfoItem
-  {
-    std::string uuid;
-    PrettyPrinter printer;
-    Destructor destructor;
-  };
-  typedef std::vector<struct TagInfoItem> TagsData;
-  typedef std::vector<struct TagInfoItem>::const_iterator TagsDataCI;
-  static bool CompareItem (const struct TagInfoItem &a, const struct TagInfoItem &b);
-  bool m_sorted;
-  TagsData m_registry;
-};
-/**
- * The TypeUid class is used to create a mapping Type --> uid
- * Note that we use a static getUuid function which contains a
- * static std::string variable rather than a simpler static
- * member std::string variable to ensure the proper order
- * of initialization when these methods are invoked
- * from the constructor of another static variable.
- */
-template <typename T>
-class TypeUid {
-public:
-  static void Record (std::string uuid);
-  static const uint32_t GetUid (void);
-private:
-  static std::string *GetUuid (void);
-  T m_realType;
-};
-
-template <typename T>
-void TypeUid<T>::Record (std::string uuid)
-{
-  *(GetUuid ()) = uuid;
-}
-
-template <typename T>
-const uint32_t TypeUid<T>::GetUid (void)
-{
-  static const uint32_t uid = TagRegistry::GetInstance ()->
-    LookupUid (*(GetUuid ()));
-  return uid;
-}
-
-template <typename T>
-std::string *TypeUid<T>::GetUuid (void)
-{
-  static std::string uuid;
-  return &uuid;
-}
-
-
-
-/**
- * Implementation of the TagRegistration registration class.
- * It records a callback with the TagRegistry
- * This callback performs type conversion before forwarding
- * the call to the user-provided function.
- */
-template <typename T>
-TagRegistration<T>::TagRegistration (std::string uuid, void (*prettyPrinter) (T const*, std::ostream &))
-{
-  NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  m_prettyPrinter  = prettyPrinter;
-  TagRegistry::GetInstance ()->
-    Record (uuid, &TagRegistration<T>::PrettyPrinterCb, &TagRegistration<T>::DestructorCb);
-  TypeUid<T>::Record (uuid);
-}
-template <typename T>
-void 
-TagRegistration<T>::PrettyPrinterCb (uint8_t *buf, std::ostream &os)
-{
-  NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  T *tag = reinterpret_cast<T *> (buf);
-  (*m_prettyPrinter) (tag, os);
-}
-template <typename T>
-void
-TagRegistration<T>::DestructorCb (uint8_t *buf)
-{
-  T *tag = reinterpret_cast<T *> (buf);
-  tag->~T ();
-}
-template <typename T>
-void (*TagRegistration<T>::m_prettyPrinter) (T const*, std::ostream &) = 0;
-
-
-
-
 template <typename T>
 void 
 Tags::Add (T const&tag)
 {
+  const Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
+
   NS_ASSERT (sizeof (T) <= Tags::SIZE);
   // ensure this id was not yet added
   for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
     {
-      NS_ASSERT (cur->m_id != TypeUid<T>::GetUid ());
+      NS_ASSERT (cur->m_id != T::GetUid ());
     }
   struct TagData *newStart = AllocData ();
   newStart->m_count = 1;
   newStart->m_next = 0;
-  newStart->m_id = TypeUid<T>::GetUid ();
+  newStart->m_id = T::GetUid ();
   void *buf = &newStart->m_data;
   new (buf) T (tag);
   newStart->m_next = m_next;
@@ -244,18 +123,26 @@
 bool
 Tags::Remove (T &tag)
 {
+  Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   NS_ASSERT (sizeof (T) <= Tags::SIZE);
-  return Remove (TypeUid<T>::GetUid ());
+  return Remove (T::GetUid ());
 }
 
 template <typename T>
 bool
 Tags::Peek (T &tag) const
 {
+  Tag *parent;
+  // if the following assignment fails, it is because the
+  // input to this function is not a subclass of the Tag class.
+  parent = &tag;
   NS_ASSERT (sizeof (T) <= Tags::SIZE);
   for (struct TagData *cur = m_next; cur != 0; cur = cur->m_next) 
     {
-      if (cur->m_id == TypeUid<T>::GetUid ()) 
+      if (cur->m_id == T::GetUid ()) 
         {
           /* found tag */
           T *data = reinterpret_cast<T *> (&cur->m_data);
@@ -315,16 +202,14 @@
         }
       if (prev != 0) 
         {
-          TagRegistry::GetInstance ()->
-            Destruct (prev->m_id, prev->m_data);
+          TagRegistry::Destruct (prev->m_id, prev->m_data);
           FreeData (prev);
         }
       prev = cur;
     }
   if (prev != 0) 
     {
-      TagRegistry::GetInstance ()->
-        Destruct (prev->m_id, prev->m_data);
+      TagRegistry::Destruct (prev->m_id, prev->m_data);
       FreeData (prev);
     }
   m_next = 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/trace-context-element.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,34 @@
+#include "trace-context-element.h"
+
+namespace ns3 {
+
+uint32_t 
+ElementRegistry::GetSize (uint16_t uid)
+{
+  InfoVector *vec = GetInfoVector ();
+  struct Info info = (*vec)[uid - 1];
+  return info.size;
+}
+void 
+ElementRegistry::Print (uint16_t uid, uint8_t *instance, std::ostream &os)
+{
+  InfoVector *vec = GetInfoVector ();
+  struct Info info = (*vec)[uid - 1];
+  info.print (instance, os);
+}
+void 
+ElementRegistry::Destroy (uint16_t uid, uint8_t *instance)
+{
+  InfoVector *vec = GetInfoVector ();
+  struct Info info = (*vec)[uid - 1];
+  info.destroy (instance);
+}
+ElementRegistry::InfoVector *
+ElementRegistry::GetInfoVector (void)
+{
+  static InfoVector vector;
+  return &vector;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common/trace-context-element.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,189 @@
+#ifndef TRACE_CONTEXT_ELEMENT_H
+#define TRACE_CONTEXT_ELEMENT_H
+
+#include <string>
+#include <vector>
+
+#define NS_TRACE_CONTEXT_ELEMENT_ENSURE_REGISTERED(x)          \
+namespace {						       \
+static class thisisaveryverylongclassname ##x		       \
+  {							       \
+  public:						       \
+    thisisaveryverylongclassname ##x ()			       \
+      { uint32_t uid; uid = x::GetUid ();}		       \
+  } g_thisisanotherveryveryverylongname ##x ;		       \
+}
+
+namespace ns3 {
+
+/**
+ * \brief an item stored in a TraceContext
+ *
+ * To store trace context information in a TraceContext instance,
+ * users must subclass this base class and store subclass instances
+ * in a TraceContext with TraceContext::Add.
+ *
+ * Each subclass should define and implement:
+ *   - a public default constructor: it is used by the internals
+ *     of the implementation of TraceContext.
+ *   - a public destructor: it is also used by the internals of
+ *     the implementation of TraceContext.
+ *   - a public static method named GetUid which returns a 16 bit 
+ *     integer. The integer returned from this method should be
+ *     allocated with the protected AllocatedUid method.
+ *   - a public Print method: this method is used by the 
+ *     TraceContext::Print method to print the content of each
+ *     of the trace context element stored in the trace context.
+ *     This method takes a c++ output stream and argument and is
+ *     expected to write an ascii string describing its content
+ *     in this output stream.
+ *
+ * A typical subclass should look like this:
+ * \code
+ * class MyContext : public TraceContextElement
+ * {
+ * public:
+ *   // the _required_ public API
+ *   static uint16_t GetUid (void);
+ *   MyContext ();
+ *   ~MyContext ();
+ *   void Print (std::ostream &os) const;
+ *
+ *   // the user-specific API to manipulate the context.
+ *   void SetData (uint8_t data);
+ *   uint8_t GetData (void) const;
+ * private:
+ *   uint8_t m_myContextData;
+ * };
+ *
+ * uint16_t 
+ * MyContext::GetUid (void)
+ * {
+ *   static uint16_t uid = AllocateUid<MyContext> ("MyContext");
+ *   return uid;
+ * }
+ * MyContext::MyContext ()
+ * {}
+ * MyContext::~MyContext ()
+ * {}
+ * void 
+ * MyContext::Print (std::ostream &os) const
+ * {
+ *   os << "mycontext=" << (uint32_t) m_myContextData;
+ * }
+ * void 
+ * MyContext::SetData (uint8_t data)
+ * {
+ *   m_myContextData = data;
+ * }
+ * uint8_t 
+ * MyContext::GetData (void) const
+ * {
+ *   return m_myContextData;
+ * }
+ * \endcode
+ */
+class TraceContextElement
+{
+protected:
+  /**
+   * \param name a string which uniquely identifies the type
+   *        of the subclass which is calling this method.
+   * \returns a unique 32 bit integer associated to the
+   *          input string.
+   *
+   * Subclasses are expected to call this method from their
+   * public static GetUid method.
+   */
+  template <typename T>
+  static uint16_t AllocateUid (std::string name);
+};
+
+} // namespace ns3
+
+namespace ns3 {
+
+/**
+ * \brief a registry of TraceContextElement subclasses
+ * \internal
+ */
+class ElementRegistry
+{
+public:
+  template <typename T>
+  static uint16_t AllocateUid (std::string name);
+
+  static uint32_t GetSize (uint16_t uid);
+  static void Print (uint16_t uid, uint8_t *instance, std::ostream &os);
+  static void Destroy (uint16_t uid, uint8_t *instance);
+private:
+  typedef void (*PrintCb) (uint8_t *instance, std::ostream &os);
+  typedef void (*DestroyCb) (uint8_t *instance);
+  struct Info {
+    uint32_t size;
+    std::string uidString;
+    PrintCb print;
+    DestroyCb destroy;
+  };
+  typedef std::vector<struct Info> InfoVector;
+  static InfoVector *GetInfoVector (void);
+  template <typename T>
+  static void DoPrint (uint8_t *instance, std::ostream &os);
+  template <typename T>
+  static void DoDestroy (uint8_t *instance);  
+};
+
+template <typename T>
+void 
+ElementRegistry::DoPrint (uint8_t *instance, std::ostream &os)
+{
+  static T obj;
+  // make sure we are aligned.
+  memcpy ((void*)&obj, instance, sizeof (T));
+  obj.Print (os);
+}
+template <typename T>
+void 
+ElementRegistry::DoDestroy (uint8_t *instance)
+{
+  static T obj;
+  // make sure we are aligned.
+  memcpy ((void*)&obj, instance, sizeof (T));
+  obj.~T ();
+}
+
+template <typename T>
+uint16_t 
+ElementRegistry::AllocateUid (std::string name)
+{
+  InfoVector *vec = GetInfoVector ();
+  uint16_t uid = 1;
+  for (InfoVector::iterator i = vec->begin (); i != vec->end (); i++)
+    {
+      if (i->uidString == name)
+	{
+	  return uid;
+	}
+      uid++;
+    }
+  struct Info info;
+  info.size = sizeof (T);
+  info.uidString = name;
+  info.print = &ElementRegistry::DoPrint<T>;
+  info.destroy = &ElementRegistry::DoDestroy<T>;
+  vec->push_back (info);
+  return vec->size ();
+}
+
+
+
+template <typename T>
+uint16_t 
+TraceContextElement::AllocateUid (std::string name)
+{
+  return ElementRegistry::AllocateUid<T> (name);
+}
+
+} // namespace ns3
+
+#endif /* TRACE_CONTEXT_ELEMENT_H */
--- a/src/common/trace-context.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trace-context.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -19,12 +19,11 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "trace-context.h"
+#include "trace-context-element.h"
 #include "ns3/assert.h"
 
 namespace ns3 {
 
-std::vector<uint8_t> TraceContext::m_sizes;
-
 TraceContext::TraceContext ()
   : m_data (0)
 {}
@@ -68,12 +67,6 @@
     }
 }
 
-uint8_t 
-TraceContext::GetSize (uint8_t uid)
-{
-  return m_sizes[uid];
-}
-
 void 
 TraceContext::Add (TraceContext const &o)
 {
@@ -81,12 +74,12 @@
     {
       return;
     }
-  uint8_t currentUid;
+  uint16_t currentUid;
   uint16_t i = 0;
   while (i < o.m_data->size) 
     {
       currentUid = o.m_data->data[i];
-      uint8_t size = TraceContext::GetSize (currentUid);
+      uint8_t size = ElementRegistry::GetSize (currentUid);
       uint8_t *selfBuffer = CheckPresent (currentUid);
       uint8_t *otherBuffer = &(o.m_data->data[i+1]);
       if (selfBuffer != 0)
@@ -116,7 +109,7 @@
   uint16_t i = 0;
   do {
     currentUid = m_data->data[i];
-    uint8_t size = TraceContext::GetSize (currentUid);
+    uint8_t size = ElementRegistry::GetSize (currentUid);
     if (currentUid == uid)
       {
         return &m_data->data[i+1];
@@ -131,7 +124,7 @@
 TraceContext::DoAdd (uint8_t uid, uint8_t const *buffer)
 {
   NS_ASSERT (uid != 0);
-  uint8_t size = TraceContext::GetSize (uid);
+  uint8_t size = ElementRegistry::GetSize (uid);
   uint8_t *present = CheckPresent (uid);
   if (present != 0) {
     if (memcmp (present, buffer, size) == 0)
@@ -201,7 +194,7 @@
   uint16_t i = 0;
   do {
     currentUid = m_data->data[i];
-    uint8_t size = TraceContext::GetSize (currentUid);
+    uint8_t size = ElementRegistry::GetSize (currentUid);
     if (currentUid == uid)
       {
         memcpy (buffer, &m_data->data[i+1], size);
@@ -212,31 +205,48 @@
   return false;
 }
 
-uint8_t
-TraceContext::DoGetNextUid (void)
+void 
+TraceContext::Print (std::ostream &os) const
 {
-  static uint8_t uid = 0;
-  if (uid == 0)
+  if (m_data == 0)
     {
-      m_sizes.push_back (0);
+      return;
     }
-  uid++;
-  return uid;
+  uint8_t currentUid;
+  uint16_t i = 0;
+  do {
+    currentUid = m_data->data[i];
+    uint8_t size = ElementRegistry::GetSize (currentUid);
+    uint8_t *instance = &m_data->data[i+1];
+    ElementRegistry::Print (currentUid, instance, os);
+    i += 1 + size;
+    if (i < m_data->size && currentUid != 0)
+      {
+        os << " ";
+      }
+    else
+      {
+        break;
+      }
+  } while (true);
 }
 
-
 }//namespace ns3
 
 #include "ns3/test.h"
+#include <sstream>
 
 namespace ns3 {
 
 template <int N>
-class Ctx
+class Ctx : public TraceContextElement
 {
 public:
+  static uint16_t GetUid (void) {static uint16_t uid = AllocateUid<Ctx<N> > (GetName ()); return uid;}
+  static std::string GetName (void) {std::ostringstream oss; oss << "Ctx" << N; return oss.str ();}
   Ctx () : m_v (0) {}
   Ctx (int v) : m_v (v) {}
+  void Print (std::ostream &os) {os << N;}
   int Get (void) const { return N;}
 private:
   int m_v;
--- a/src/common/trace-context.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trace-context.h	Wed Sep 05 18:35:39 2007 +0100
@@ -24,6 +24,7 @@
 #include <stdint.h>
 #include <vector>
 #include "ns3/fatal-error.h"
+#include "trace-context-element.h"
 
 namespace ns3 {
 
@@ -77,25 +78,20 @@
    */
   template <typename T>
   void Get (T &context) const;
+
+  void Print (std::ostream &os) const;
 private:
   friend class TraceContextTest;
   // used exclusively for testing code.
   template <typename T>
   bool SafeGet (T &context) const;
   template <typename T>
-  bool SafeAdd (T &context);
+  bool SafeAdd (const T &context);
 
-  template <typename T>
-  static uint8_t GetUid (void);
-  template <typename T>
-  static uint8_t GetNextUid (void);
-  static uint8_t DoGetNextUid (void);
-  static uint8_t GetSize (uint8_t uid);
   uint8_t *CheckPresent (uint8_t uid) const;
   bool DoAdd (uint8_t uid, uint8_t const *buffer);
   bool DoGet (uint8_t uid, uint8_t *buffer) const;
 
-  static std::vector<uint8_t> m_sizes;
   struct Data {
     uint16_t count;
     uint16_t size;
@@ -111,8 +107,12 @@
 void 
 TraceContext::Add (T const &context)
 {
+  const TraceContextElement *parent;
+  // if the following assignment fails, it is because the input
+  // to this function is not a subclass of the TraceContextElement class.
+  parent = &context;
   uint8_t *data = (uint8_t *) &context;
-  bool ok = DoAdd (TraceContext::GetUid<T> (), data);
+  bool ok = DoAdd (T::GetUid (), data);
   if (!ok)
     {
       NS_FATAL_ERROR ("Trying to add twice the same type with different values is invalid.");
@@ -122,8 +122,12 @@
 void
 TraceContext::Get (T &context) const
 {
+  TraceContextElement *parent;
+  // if the following assignment fails, it is because the input
+  // to this function is not a subclass of the TraceContextElement class.
+  parent = &context;
   uint8_t *data = (uint8_t *) &context;
-  bool found = DoGet (TraceContext::GetUid<T> (), data);
+  bool found = DoGet (T::GetUid (), data);
   if (!found)
     {
       NS_FATAL_ERROR ("Type not stored in TraceContext");
@@ -133,35 +137,26 @@
 bool
 TraceContext::SafeGet (T &context) const
 {
+  TraceContextElement *parent;
+  // if the following assignment fails, it is because the input
+  // to this function is not a subclass of the TraceContextElement class.
+  parent = &context;
   uint8_t *data = (uint8_t *) &context;
-  bool found = DoGet (TraceContext::GetUid<T> (), data);
+  bool found = DoGet (T::GetUid (), data);
   return found;
 }
 template <typename T>
 bool
-TraceContext::SafeAdd (T &context)
+TraceContext::SafeAdd (const T &context)
 {
+  const TraceContextElement *parent;
+  // if the following assignment fails, it is because the input
+  // to this function is not a subclass of the TraceContextElement class.
+  parent = &context;
   uint8_t *data = (uint8_t *) &context;
-  bool ok = DoAdd (TraceContext::GetUid<T> (), data);
+  bool ok = DoAdd (T::GetUid (), data);
   return ok;
 }
-template <typename T>
-uint8_t
-TraceContext::GetUid (void)
-{
-  static uint8_t uid = GetNextUid<T> ();
-  return uid;
-}
-
-template <typename T>
-uint8_t
-TraceContext::GetNextUid (void)
-{
-  uint8_t uid = DoGetNextUid ();
-  m_sizes.push_back (sizeof (T));
-  return uid;
-}
-
 }//namespace ns3
 
 #endif /* TRACE_CONTEXT_H */
--- a/src/common/trace-root.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trace-root.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -41,7 +41,7 @@
                      Callback<TraceResolver *,TraceContext const &> createResolver)
 {
   CompositeTraceResolver *resolver = GetComposite ();
-  resolver->Add (name, createResolver, TraceRoot::NOTHING);
+  resolver->Add (name, createResolver);
 }
 
 CompositeTraceResolver *
--- a/src/common/trace-root.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trace-root.h	Wed Sep 05 18:35:39 2007 +0100
@@ -328,9 +328,6 @@
                         Callback<TraceResolver *,TraceContext const &> createResolver);
 private:
   static CompositeTraceResolver *GetComposite (void);
-  enum TraceType {
-    NOTHING,
-  };
 };
 
 }// namespace ns3
--- a/src/common/trailer.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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 "trailer.h"
-
-namespace ns3 {
-
-Trailer::~Trailer ()
-{}
-
-}; // namespace ns3
--- a/src/common/trailer.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/trailer.h	Wed Sep 05 18:35:39 2007 +0100
@@ -22,7 +22,28 @@
 #ifndef TRAILER_H
 #define TRAILER_H
 
-#include "chunk.h"
+#include "chunk-registry.h"
+
+/**
+ * \relates ns3::Trailer
+ * \brief this macro should be instantiated exactly once for each
+ *        new type of Trailer
+ *
+ * This macro will ensure that your new Trailer type is registered
+ * within the packet trailer registry. In most cases, this macro
+ * is not really needed but, for safety, please, use it all the
+ * time.
+ *
+ * Note: This macro is _absolutely_ needed if you try to run a
+ * distributed simulation.
+ */
+#define NS_TRAILER_ENSURE_REGISTERED(x)          \
+static class thisisaveryverylongclassname ##x    \
+{                                                \
+ public:                                         \
+  thisisaveryverylongclassname ##x ()            \
+    { uint32_t uid; uid = x::GetUid ();}         \
+} g_thisisanotherveryveryverylongname ##x;
 
 namespace ns3 {
 
@@ -30,98 +51,66 @@
  * \brief Protocol trailer serialization and deserialization.
  *
  * Every Protocol trailer which needs to be inserted or removed
- * from a Packet instance must derive from this abstract base class
- * and implement the private pure virtual methods listed below:
- *   - ns3::Trailer::SerializeTo
- *   - ns3::Trailer::DeserializeFrom
- *   - ns3::Trailer::GetSerializedSize
- *   - ns3::Trailer::PrintTo
+ * from a Packet instance must derive from this base class and
+ * implement the following public methods:
+ *   - a default constructor: is used by the internal implementation
+ *     if the Packet class.
+ *   - a static method named GetUid: is used to uniquely identify
+ *     the type of each trailer. This method shall return a unique
+ *     integer allocated with Trailer::AllocateUid.
+ *   - a method named Serialize: is used by Packet::AddTrailer to
+ *     store a trailer into the byte buffer of a packet.
+ *     The input iterator points to the end of the byte buffer in
+ *     which the trailer should write its data: the user is thus
+ *     required to call Buffer::Iterator::Prev prior to writing
+ *     any data in the buffer. The data written is expected to 
+ *     match bit-for-bit the representation of this trailer in a 
+ *     real network.
+ *   - a method named GetSerializedSize: is used by Packet::AddTrailer
+ *     to store a trailer into the byte buffer of a packet. This method
+ *     should return the number of bytes which are needed to store
+ *     the full trailer data by Serialize.
+ *   - a method named Deserialize: is used by Packet::RemoveTrailer to
+ *     re-create a trailer from the byte buffer of a packet. The input
+ *     iterator points to the end of the byte buffer from which
+ *     the trailer should read its data: the user is thus required to
+ *     call Buffer::Iterator::Prev prior to reading any data from the
+ *     buffer. The data read is expected to match bit-for-bit the 
+ *     representation of this trailer in real networks. This method 
+ *     shall return an integer which identifies the number of bytes read.
+ *   - a method named Print: is used by Packet::Print to print the 
+ *     content of a trailer as ascii data to a c++ output stream.
+ *     Although the trailer is free to format its output as it
+ *     wishes, it is recommended to follow a few rules to integrate
+ *     with the packet pretty printer: start with flags, small field 
+ *     values located between a pair of parens. Values should be separated 
+ *     by whitespace. Follow the parens with the important fields, 
+ *     separated by whitespace.
+ *     i.e.: (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
+ *   - a method named GetName: is used by Packet::Print to print
+ *     trailer fragments. This method should return a user-readable
+ *     single word as all capitalized letters.
  *
- * Note that the SerializeTo and DeserializeFrom methods behave
- * in a way which might seem surprising to users: the input iterator
- * really points to the end of the buffer to which and from which
- * the user is expected to write and read respectively. This means that
- * if the trailer has a fixed size and if the user wishes to read or
- * write that trailer from front to back, the user must rewind the 
- * iterator by hand to go to the start of the trailer. Typical code
- * looks like this:
- * \code
- * void CrcTrailer::SerializeTo (Buffer::Iterator end)
- * {
- *   end.Prev (4);
- *   end.WriteHtonU32 (m_crc);
- * }
- * \endcode
- *
- * Some users would have expected that the iterator would be rewinded 
- * to the "start" of the trailer before calling SerializeTo and DeserializeFrom.
- * However, this behavior was not implemented because it cannot be made to
- * work reliably for trailers which have a variable size. i.e., if the trailer 
- * contains options, the code which calls DeserializeFrom cannot rewind
- * to the start of the trailer because it does not know the real size of the 
- * trailer. Hence, to make this legitimate use-case work (variable-sized 
- * trailers), the input iterator to DeserializeFrom and SerializeTo points
- * to the end of the trailer, and not its start.
  */
-class Trailer : public Chunk {
-public:
-  virtual ~Trailer ();
-private:
-  /**
-   * \returns a user-readable name to identify this type of header.
-   *
-   * The string returned is expected to be a single word with 
-   * all capital letters
-   */
-  virtual std::string DoGetName (void) const = 0;
-  /**
-   * \param os the std output stream in which this 
-   *       protocol trailer must print itself.
-   *
-   * Although the header is free to format its output as it
-   * wishes, it is recommended to follow a few rules to integrate
-   * with the packet pretty printer:
-   *   - start with flags, small field values located between a
-   *     pair of parens. Values should be separated by whitespace.
-   *   - follow the parens with the important fields, separated by
-   *     whitespace.
-   * i.e.:
-   * (field1 val1 field2 val2 field3 val3) field4 val4 field5 val5
-   */
-  virtual void PrintTo (std::ostream &os) const = 0;
-
-  /**
-   * \returns the size of the serialized Trailer.
-   *
-   * This method is used by Packet::AddTrailer to reserve
-   * enough room in the packet byte buffer prior to calling
-   * Trailer::Serialize.
-   */
-  virtual uint32_t GetSerializedSize (void) const = 0;
-
-  /**
-   * \param end the buffer iterator in which the protocol trailer
-   *    must serialize itself. This iterator identifies 
-   *    the end of the buffer.
-   *
-   * This iterator must be typically moved with the Buffer::Iterator::Prev
-   * method before writing any byte in the buffer.
-   */
-  virtual void SerializeTo (Buffer::Iterator end) const = 0;
-  /**
-   * \param end the buffer iterator from which the protocol trailer must
-   *    deserialize itself. This iterator identifies 
-   *    the end of the buffer.
-   * \returns the number of bytes read from the buffer
-   *
-   * This iterator must be typically moved with the Buffer::Iterator::Prev
-   * method before reading any byte in the buffer. The value returned
-   * is used to trim the packet byte buffer of the corresponding
-   * amount when this method is invoked from Packet::RemoveTrailer
-   */
-  virtual uint32_t DeserializeFrom (Buffer::Iterator end) = 0;
+class Trailer 
+{
+protected:
+  template <typename T>
+  static uint32_t AllocateUid (std::string uidString);
 };
 
-}; // namespace ns3
+} // namespace ns3
+
+namespace ns3 {
+
+template <typename T>
+uint32_t 
+Trailer::AllocateUid (std::string uidString)
+{
+  return ChunkRegistry::RegisterTrailer<T> (uidString);
+}
+
+
+} // namespace ns3
 
 #endif /* TRAILER_H */
--- a/src/common/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/common/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -1,22 +1,20 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
 def build(bld):
-    common = bld.create_obj('cpp', 'shlib')
-    common.name = 'ns3-common'
-    common.target = common.name
-    common.uselib_local = ['ns3-core', 'ns3-simulator']
+    common = bld.create_ns3_module('common', ['core', 'simulator'])
     common.source = [
         'buffer.cc',
-        'chunk.cc',
-        'header.cc',
-        'trailer.cc',
+        'chunk-registry.cc',
         'packet-printer.cc',
         'packet-metadata.cc',
+        'packet-metadata-test.cc',
         'packet.cc',
         'tags.cc',
+        'tag-registry.cc',
         'pcap-writer.cc',
         'variable-tracer-test.cc',
         'trace-context.cc',
+        'trace-context-element.cc',
         'trace-resolver.cc',
         'callback-trace-source.cc',
         'empty-trace-resolver.cc',
@@ -28,10 +26,12 @@
     headers = bld.create_obj('ns3header')
     headers.source = [
         'buffer.h',
-        'chunk.h',
+        'chunk-registry.h',
         'header.h',
         'trailer.h',
         'tags.h',
+        'tag-registry.h',
+        'tag.h',
         'packet.h',
         'packet-printer.h',
         'packet-metadata.h',
@@ -41,6 +41,7 @@
         'pcap-writer.h',
         'callback-trace-source.h',
         'trace-context.h',
+        'trace-context-element.h',
         'trace-resolver.h',
         'empty-trace-resolver.h',
         'composite-trace-resolver.h',
--- a/src/core/assert.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2006 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 "assert.h"
-
-namespace ns3 {
-
-void
-AssertBreakpoint (void)
-{
-  int *a = 0;
-  /**
-   * we test here to allow a debugger to change the value of
-   * the variable 'a' to allow the debugger to avoid the 
-   * subsequent segfault.
-   */
-  if (a == 0)
-    {
-      *a = 0;
-    }
-}
-
-}//namespace ns3
--- a/src/core/assert.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/assert.h	Wed Sep 05 18:35:39 2007 +0100
@@ -21,6 +21,12 @@
 #ifndef ASSERT_H
 #define ASSERT_H
 
+#ifdef NS3_ASSERT_ENABLE
+
+#include <iostream>
+
+#include "breakpoint.h"
+
 /**
  * \defgroup assert Assert
  * \brief assert functions and macros
@@ -32,25 +38,6 @@
  * removed in optimized builds.
  */
 
-namespace ns3 {
-
-/**
- * \ingroup debugging
- *
- * When an NS_ASSERT cannot verify its condition, 
- * this function is called. This is where you should
- * be able to put a breakpoint with a debugger if
- * you want to catch assertions before the program 
- * halts.
- */
-void AssertBreakpoint (void);
-
-}//namespace ns3
-
-#ifdef NS3_ASSERT_ENABLE
-
-#include <iostream>
-
 /**
  * \ingroup assert
  * \param condition condition to verifiy.
@@ -65,10 +52,10 @@
     {                                                           \
       if (!(condition))                                         \
         {                                                       \
-          std::cout << "assert failed. file=" << __FILE__ <<    \
+          std::cerr << "assert failed. file=" << __FILE__ <<    \
             ", line=" << __LINE__ << ", cond=\""#condition <<   \
             "\"" << std::endl;                                  \
-          ns3::AssertBreakpoint ();                             \
+          NS_BREAKPOINT ();                                     \
         }                                                       \
     }                                                           \
   while (false)
@@ -88,8 +75,8 @@
     {                                           \
       if (!(condition))                         \
         {                                       \
-          std::cout << message << std::endl;    \
-          ns3::AssertBreakpoint ();             \
+          std::cerr << message << std::endl;    \
+          NS_BREAKPOINT ();                     \
         }                                       \
     }                                           \
   while (false)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/breakpoint.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,58 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA, 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: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ * Author: Gustavo Carneiro <gjc@inescporto.pt>
+ */
+
+#include "breakpoint.h"
+#include "ns3/core-config.h"
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+namespace ns3 {
+
+#if defined (HAVE_SIGNAL_H) && defined (SIGTRAP)
+
+void
+BreakpointFallback (void)
+{
+  raise (SIGTRAP);
+}
+
+#else
+
+void
+BreakpointFallback (void)
+{
+  int *a = 0;
+  /**
+   * we test here to allow a debugger to change the value of
+   * the variable 'a' to allow the debugger to avoid the 
+   * subsequent segfault.
+   */
+  if (a == 0)
+    {
+      *a = 0;
+    }
+}
+
+#endif // HAVE_SIGNAL_H
+
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/breakpoint.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INESC Porto, 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: Gustavo Carneiro <gjc@inescporto.pt>
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef BREAKPOINT_H
+#define BREAKPOINT_H
+
+namespace ns3 {
+
+/* Hacker macro to place breakpoints for selected machines.
+ * Actual use is strongly discouraged of course ;)
+ * Copied from GLib 2.12.9.
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GLib Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+/**
+ * \ingroup debugging
+ *
+ * Inserts a breakpoint instruction (or equivalent system call) into
+ * the code for selected machines.  When an NS_ASSERT cannot verify its condition, 
+ * this macro is used. Falls back to calling
+ * AssertBreakpoint() for architectures where breakpoint assembly
+ * instructions are not supported.
+ */
+#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) && defined (__GNUC__) && __GNUC__ >= 2
+#  define NS_BREAKPOINT() \
+   do{ __asm__ __volatile__ ("int $03"); }while(false)
+#elif defined (_MSC_VER) && defined (_M_IX86)
+#  define NS_BREAKPOINT() \
+   do{ __asm int 3h }while(false)
+#elif defined (__alpha__) && !defined(__osf__) && defined (__GNUC__) && __GNUC__ >= 2
+#  define NS_BREAKPOINT() \
+   do{ __asm__ __volatile__ ("bpt"); }while(false)
+#else	/* !__i386__ && !__alpha__ */
+#  define NS_BREAKPOINT()    ns3::BreakpointFallback ()
+#endif
+
+/**
+ * \brief fallback breakpoint function
+ *
+ * This function is used by the NS_BREAKPOINT() macro as a fallback
+ * for when breakpoint assembly instructions are not available.  It
+ * attempts to halt program execution either by a raising SIGTRAP, on
+ * unix systems, or by dereferencing a null pointer.
+ * 
+ * Normally you should not call this function directly.
+ */
+void BreakpointFallback (void);
+
+
+}//namespace ns3
+
+
+#endif /* BREAKPOINT_H */
--- a/src/core/callback.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/callback.h	Wed Sep 05 18:35:39 2007 +0100
@@ -358,7 +358,7 @@
 
 /**
  * \ingroup MakeCallback
- * \param mem_ptr class method member pointer
+ * \param memPtr class method member pointer
  * \param objPtr class instance
  * \return a wrapper Callback
  * Build Callbacks for class method members which takes no arguments
--- a/src/core/component-manager.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/component-manager.h	Wed Sep 05 18:35:39 2007 +0100
@@ -348,7 +348,7 @@
    * result.
    */
   template <typename T, typename T1, typename T2, typename T3, typename T4, typename T5>
-  static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5);
+  static Ptr<T> Create (ClassId classId, InterfaceId iid, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
 
 private:
   friend void RegisterCallback (ClassId classId, CallbackBase *callback, 
--- a/src/core/debug.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/debug.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -24,6 +24,7 @@
 #include "debug.h"
 #include "assert.h"
 #include "ns3/core-config.h"
+#include "fatal-error.h"
 
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
@@ -53,6 +54,7 @@
     {
       return;
     }
+  bool allFound = true;
   std::string env = envVar;
   std::string::size_type cur = 0;
   std::string::size_type next = 0;
@@ -88,7 +90,7 @@
         }
       if (!found)
         {
-          std::cout << "No debug component named=\"" << tmp << "\"" << std::endl;
+          allFound = false;
         }
       if (next == std::string::npos)
         {
@@ -100,6 +102,11 @@
           break;
         }
     }
+  if (allFound)
+    {
+      g_firstDebug = true;
+    }
+  
 #endif
 }
 
@@ -122,7 +129,6 @@
   if (g_firstDebug) 
     {
       DebugComponentEnableEnvVar ();
-      g_firstDebug = false;
     }
   return m_isEnabled;
 }
--- a/src/core/debug.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/debug.h	Wed Sep 05 18:35:39 2007 +0100
@@ -110,7 +110,7 @@
     {                                           \
       if (g_debug.IsEnabled ())			\
         {                                       \
-          std::cout << msg << std::endl;        \
+          std::cerr << msg << std::endl;        \
         }                                       \
     }                                           \
   while (false)
@@ -125,7 +125,7 @@
 #define NS_DEBUG_UNCOND(msg)         \
   do                                 \
     {                                \
-      std::cout << msg << std::endl; \
+      std::cerr << msg << std::endl; \
     }                                \
   while (false)
 
--- a/src/core/default-value.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/default-value.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -23,6 +23,52 @@
 
 namespace ns3 {
 
+namespace DefaultValue {
+
+enum BindStatus {
+  OK,
+  INVALID_VALUE,
+  NOT_FOUND
+};
+
+
+static 
+enum BindStatus
+BindSafe (std::string name, std::string value)
+{
+  for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
+       i != DefaultValueList::End (); i++)
+    {
+      DefaultValueBase *cur = *i;
+      if (cur->GetName () == name)
+	{
+	  if (!cur->ParseValue (value))
+	    {
+	      return INVALID_VALUE;
+	    }
+	  return OK;
+	}
+    }
+  return NOT_FOUND;
+}
+
+void
+Bind (std::string name, std::string value)
+{
+  switch (BindSafe (name, value)) {
+  case INVALID_VALUE:
+    NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
+    break;
+  case NOT_FOUND:
+    NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
+    break;
+  case OK:
+    break;
+  }
+}
+
+}
+
 DefaultValueBase::DefaultValueBase (const std::string &name,
 				    const std::string &help)
   : m_name (name),
@@ -112,48 +158,6 @@
   return &list;
 }
 
-enum BindStatus {
-  OK,
-  INVALID_VALUE,
-  NOT_FOUND
-};
-
-
-static 
-enum BindStatus
-BindSafe (std::string name, std::string value)
-{
-  for (DefaultValueList::Iterator i = DefaultValueList::Begin ();
-       i != DefaultValueList::End (); i++)
-    {
-      DefaultValueBase *cur = *i;
-      if (cur->GetName () == name)
-	{
-	  if (!cur->ParseValue (value))
-	    {
-	      return INVALID_VALUE;
-	    }
-	  return OK;
-	}
-    }
-  return NOT_FOUND;
-}
-
-void
-Bind (std::string name, std::string value)
-{
-  switch (BindSafe (name, value)) {
-  case INVALID_VALUE:
-    NS_FATAL_ERROR ("Invalid value: "<<name<<"="<<value);
-    break;
-  case NOT_FOUND:
-    NS_FATAL_ERROR ("No registered DefaultValue=\"" << name << "\"");
-    break;
-  case OK:
-    break;
-  }
-}
-
 BooleanDefaultValue::BooleanDefaultValue (std::string name,
 					  std::string help,
 					  bool defaultValue)
@@ -341,85 +345,40 @@
 bool 
 DefaultValueTest::RunTests (void)
 {
-  bool ok = true;
+  bool result = true;
 
   BooleanDefaultValue a ("bool-a", "help a", true);
-  if (!a.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-a", "false");
-  if (a.GetValue ())
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT (a.GetValue ());
+  DefaultValue::Bind ("bool-a", "false");
+  NS_TEST_ASSERT (!a.GetValue ());
   BooleanDefaultValue b ("bool-b", "help b", false);
-  Bind ("bool-b", "true");
-  if (!b.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-b", "0");
-  if (b.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-b", "1");
-  if (!b.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-b", "f");
-  if (b.GetValue ())
-    {
-      ok = false;
-    }
-  Bind ("bool-b", "t");
-  if (!b.GetValue ())
-    {
-      ok = false;
-    }
+  DefaultValue::Bind ("bool-b", "true");
+  NS_TEST_ASSERT (b.GetValue ());
+  DefaultValue::Bind ("bool-b", "0");
+  NS_TEST_ASSERT (!b.GetValue ());
+  DefaultValue::Bind ("bool-b", "1");
+  NS_TEST_ASSERT (b.GetValue ());
+  DefaultValue::Bind ("bool-b", "f");
+  NS_TEST_ASSERT (!b.GetValue ());
+  DefaultValue::Bind ("bool-b", "t");
+  NS_TEST_ASSERT (b.GetValue ());
 
-  Bind ("bool-b", "false");
-  if (b.GetValue ())
-    {
-      ok = false;
-    }
-  if (BindSafe ("bool-b", "tr") != INVALID_VALUE)
-    {
-      ok = false;
-    }
+  DefaultValue::Bind ("bool-b", "false");
+  NS_TEST_ASSERT (!b.GetValue ());
+  NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("bool-b", "tr"), DefaultValue::INVALID_VALUE)
 
-  NumericDefaultValue<int> i ("test-i", "help-i", -1);
-  if (i.GetValue () != -1)
-    {
-      ok = false;
-    }  
-  Bind ("test-i", "-2");
-  if (i.GetValue () != -2)
-    {
-      ok = false;
-    }
-  Bind ("test-i", "+2");
-  if (i.GetValue () != 2)
-    {
-      ok = false;
-    }
-  if (i.GetType () != "int32_t(-2147483648:2147483647)")
-    {
-      ok = false;
-    }
+  NumericDefaultValue<int32_t> i ("test-i", "help-i", -1);
+  NS_TEST_ASSERT_EQUAL (i.GetValue (), -1);
+  DefaultValue::Bind ("test-i", "-2");
+  NS_TEST_ASSERT_EQUAL (i.GetValue (), -2);
+  DefaultValue::Bind ("test-i", "+2");
+  NS_TEST_ASSERT_EQUAL (i.GetValue (), 2);
+  NS_TEST_ASSERT_EQUAL (i.GetType (), "int32_t(-2147483648:2147483647)");
   NumericDefaultValue<uint32_t> ui32 ("test-ui32", "help-ui32", 10);
-  if (ui32.GetType () != "uint32_t(0:4294967295)")
-    {
-      ok = false;
-    }
-  NumericDefaultValue<char> c ("test-c", "help-c", 10);
-  if (c.GetValue () != 10)
-    {
-      ok = false;
-    }
-  Bind ("test-c", "257");  
+  NS_TEST_ASSERT_EQUAL (ui32.GetType (), "uint32_t(0:4294967295)");
+  NumericDefaultValue<int8_t> c ("test-c", "help-c", 10);
+  NS_TEST_ASSERT_EQUAL (c.GetValue (), 10);
+  DefaultValue::Bind ("test-c", "257");  
   NumericDefaultValue<float> x ("test-x", "help-x", 10.0);
   NumericDefaultValue<double> y ("test-y", "help-y", 10.0);
 
@@ -429,19 +388,10 @@
 				   MY_ENUM_A, "A",
 				   MY_ENUM_B, "B",
 				   0, (void*)0);
-  if (e.GetValue () != MY_ENUM_C)
-    {
-      ok = false;
-    }
-  Bind ("test-e", "B");
-  if (e.GetValue () != MY_ENUM_B)
-    {
-      ok = false;
-    }
-  if (BindSafe ("test-e", "D") != INVALID_VALUE)
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_C);
+  DefaultValue::Bind ("test-e", "B");
+  NS_TEST_ASSERT_EQUAL (e.GetValue (), MY_ENUM_B);
+  NS_TEST_ASSERT_EQUAL (DefaultValue::BindSafe ("test-e", "D"), DefaultValue::INVALID_VALUE);
 
   class MyEnumSubclass : public EnumDefaultValue<enum MyEnum>
   {
@@ -456,15 +406,9 @@
       AddPossibleValue (MY_ENUM_D, "D");
     }
   } e1 ;
-  if (e1.GetValue () != MY_ENUM_B)
-    {
-      ok = false;
-    }
-  Bind ("test-e1", "D");
-  if (e1.GetValue () != MY_ENUM_D)
-    {
-      ok = false;
-    }
+  NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_B);
+  DefaultValue::Bind ("test-e1", "D");
+  NS_TEST_ASSERT_EQUAL (e1.GetValue (), MY_ENUM_D);
 
   DefaultValueList::Remove ("test-e1");
   DefaultValueList::Remove ("test-e");
@@ -474,7 +418,7 @@
   DefaultValueList::Remove ("test-c");
   DefaultValueList::Remove ("test-ui32");
   
-  return ok;
+  return result;
 }
 
 static DefaultValueTest g_default_value_tests;
--- a/src/core/default-value.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/default-value.h	Wed Sep 05 18:35:39 2007 +0100
@@ -31,6 +31,25 @@
 
 namespace ns3 {
 
+namespace DefaultValue
+{
+
+/**
+ * \ingroup config
+ * \param name name of variable to bind
+ * \param value value to bind to the specified variable
+ *
+ * If the variable name does not match any existing
+ * variable or if the value is not compatible with
+ * the variable type, this function will abort
+ * at runtime and print an error message detailing
+ * which variable or value triggered the problem.
+ */
+void Bind (std::string name, std::string value);
+
+}
+
+
 class DefaultValueBase
 {
 public:
@@ -84,19 +103,6 @@
 };
 
 /**
- * \ingroup config
- * \param name name of variable to bind
- * \param value value to bind to the specified variable
- *
- * If the variable name does not match any existing
- * variable or if the value is not compatible with
- * the variable type, this function will abort
- * at runtime and print an error message detailing
- * which variable or value triggered the problem.
- */
-void Bind (std::string name, std::string value);
-
-/**
  * \brief A Boolean variable for ns3::Bind
  * \ingroup config
  *
--- a/src/core/fatal-error.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/fatal-error.h	Wed Sep 05 18:35:39 2007 +0100
@@ -21,7 +21,7 @@
 #ifndef FATAL_ERROR_H
 #define FATAL_ERROR_H
 
-#include "assert.h"
+#include "breakpoint.h"
 #include <iostream>
 
 /**
@@ -32,15 +32,15 @@
  *
  * When this macro is hit at runtime, the user-specified 
  * error message is output and the program is halted by calling
- * the ns3::AssertBreakpoint function. This macro is enabled
+ * the NS_DEBUG_BREAKPOINT macro. This macro is enabled
  * unconditionally in all builds, including debug and optimized 
  * builds.
  */
 #define NS_FATAL_ERROR(msg)				\
   do                                                    \
     {                                                   \
-      std::cout << msg << std::endl;			\
-      ns3::AssertBreakpoint ();                         \
+      std::cerr << msg << std::endl;			\
+      NS_BREAKPOINT ();                                 \
     }                                                   \
   while (false)
 
--- a/src/core/ptr.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/ptr.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -28,9 +28,14 @@
 
 namespace ns3 {
 
+template <typename T>
+void Foo (void) {}
+
+
 class NoCount : public Object
 {
 public:
+  NoCount (void (*fn) (void));
   NoCount (Callback<void> cb);
   ~NoCount ();
   void Nothing (void) const;
@@ -292,12 +297,22 @@
     callback ();
   }
 
+
 #if 0
   // as expected, fails compilation.
   {
     Ptr<const Object> p = Create<NoCount> (cb);
     Callback<void> callback = MakeCallback (&NoCount::Nothing, p);
   }
+  // local types are not allowed as arguments to a template.
+  {
+    class B
+    {
+    public:
+      B () {}
+    };
+    Foo<B> ();
+  }
 #endif
   
 
--- a/src/core/ptr.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/ptr.h	Wed Sep 05 18:35:39 2007 +0100
@@ -65,7 +65,7 @@
   template <typename U>
   friend U *PeekPointer (const Ptr<U> &p);
 
-  void Acquire (void) const;
+  inline void Acquire (void) const;
 public:
   /**
    * Create an empty smart pointer
@@ -81,7 +81,16 @@
    * same, so that object is deleted if no more references to it
    * remain.
    */
-  Ptr (T *ptr);
+  Ptr (T *ptr);  
+  /**
+   * \param ptr raw pointer to manage
+   * \param ref if set to true, this method calls Ref, otherwise,
+   *        it does not call Ref.
+   *    
+   * Create a smart pointer which points to the object pointed to by
+   * the input raw pointer ptr.
+   */
+  Ptr (T *ptr, bool ref);
   Ptr (Ptr const&o);
   // allow conversions from T to T const.
   template <typename U>
@@ -379,6 +388,16 @@
 }
 
 template <typename T>
+Ptr<T>::Ptr (T *ptr, bool ref) 
+  : m_ptr (ptr)
+{
+  if (ref)
+    {
+      Acquire ();
+    }
+}
+
+template <typename T>
 Ptr<T>::Ptr (Ptr const&o) 
   : m_ptr (PeekPointer (o))
 {
--- a/src/core/random-variable.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/random-variable.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -108,8 +108,8 @@
 {
   if (RandomVariable::globalSeedSet)
     {
-      cout << "Random number generator already initialized!" << endl;
-      cout << "Call to RandomVariable::UseGlobalSeed() ignored" << endl;
+      cerr << "Random number generator already initialized!" << endl;
+      cerr << "Call to RandomVariable::UseGlobalSeed() ignored" << endl;
       return;
     }
   RandomVariable::globalSeed[0] = s0;
@@ -537,7 +537,7 @@
       ValueCDF& current = emp[i];
       if (current.value < prior.value || current.cdf < prior.cdf)
         { // Error
-          cout << "Empirical Dist error,"
+          cerr << "Empirical Dist error,"
                << " current value " << current.value
                << " prior value "   << prior.value
                << " current cdf "   << current.cdf
--- a/src/core/random-variable.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/random-variable.h	Wed Sep 05 18:35:39 2007 +0100
@@ -772,6 +772,7 @@
   /**
    * \param s Low end of the range
    * \param l High end of the range
+   * \param mean mean of the distribution
    * \return A triangularly distributed random number between s and l
    */
   static double GetSingleValue(double s, double l, double mean);
--- a/src/core/rng-stream.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/rng-stream.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -269,11 +269,11 @@
     }
     for (i = 3; i < 6; ++i) {
         if (seed[i] >= m2) {
-	  cout << "Seed[" << i << "] = " << seed[i] << endl; 
-            cerr << "*****************************************\n\n"
-                 << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set."
-                 << "\n\n*****************************************\n\n";
-            return (false);
+	  cerr << "Seed[" << i << "] = " << seed[i] << endl; 
+          cerr << "*****************************************\n\n"
+               << "ERROR: Seed[" << i << "] >= 4294944443, Seed is not set."
+               << "\n\n*****************************************\n\n";
+          return (false);
         }
     }
     if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) {
--- a/src/core/uid-manager.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/uid-manager.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -20,6 +20,7 @@
  */
 #include "uid-manager.h"
 #include "ns3/fatal-error.h"
+#include "ns3/assert.h"
 
 
 namespace ns3 {
--- a/src/core/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/core/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -15,18 +15,22 @@
     e.define = 'HAVE_GETENV'
     e.run()
 
+    e = conf.create_header_configurator()
+    e.mandatory = False
+    e.name = 'signal.h'
+    e.define = 'HAVE_SIGNAL_H'
+    e.run()
+
     conf.write_config_header('ns3/core-config.h')
 
 
 
 def build(bld):
-    core = bld.create_obj('cpp', 'shlib')
-    core.name = 'ns3-core'
-    core.target = core.name
+    core = bld.create_ns3_module('core')
     core.source = [
         'callback-test.cc',
         'debug.cc',
-        'assert.cc',
+        'breakpoint.cc',
         'ptr.cc',
         'object.cc',
         'test.cc',
@@ -58,6 +62,7 @@
         'object.h',
         'debug.h',
         'assert.h',
+        'breakpoint.h',
         'fatal-error.h',
         'test.h',
         'random-variable.h',
--- a/src/devices/csma-cd/backoff.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007, Emmanuelle Laprise
- * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
- */
-
-#include "backoff.h"
-
-namespace ns3 {
-
-Backoff::Backoff() 
-{
-  m_slotTime = MicroSeconds(1);
-  m_minSlots = 1;
-  m_maxSlots = 1000;
-  m_ceiling = 10;
-  m_maxRetries = 1000;
-
-  ResetBackoffTime();
-}
-
-Backoff::Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots,
-                 uint32_t ceiling, uint32_t maxRetries)
-{
-  m_slotTime = slotTime;
-  m_minSlots = minSlots;
-  m_maxSlots = maxSlots;
-  m_ceiling = ceiling;
-  m_maxRetries = maxRetries;
-}  
-
-Time
-Backoff::GetBackoffTime (void)
-{
-  Time backoff;
-  uint32_t ceiling;
-
-  if ((m_ceiling > 0) &&(m_numBackoffRetries > m_ceiling))
-    ceiling = m_ceiling;
-  else
-    ceiling = m_numBackoffRetries;
-
-  uint32_t minSlot = m_minSlots;
-  uint32_t maxSlot = (uint32_t)pow(2, ceiling) - 1;
-  if (maxSlot > m_maxSlots)
-    maxSlot = m_maxSlots;
-
-  uint32_t backoffSlots = 
-    (uint32_t)UniformVariable::GetSingleValue(minSlot, maxSlot);
-
-  backoff = Scalar(backoffSlots) * m_slotTime;
-  return (backoff);
-}
-
-void Backoff::ResetBackoffTime (void)
-{
-  m_numBackoffRetries = 0;
-}
-
-bool Backoff::MaxRetriesReached(void) {
-  return (m_numBackoffRetries >= m_maxRetries);
-}
-
-void Backoff::IncrNumRetries(void) {
-  m_numBackoffRetries++;
-}
-
-} // namespace ns3
--- a/src/devices/csma-cd/backoff.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- *
- * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
- * Derived from the p2p net device file
-Transmi */
-
-#ifndef BACKOFF_H
-#define BACKOFF_H
-
-#include <stdint.h>
-#include "ns3/nstime.h"
-#include "ns3/random-variable.h"
-
-namespace ns3 {
-
-  /**
-   * \brief The backoff class is used for calculating backoff times
-   * when many net devices can write to the same channel
-   *
-   */
-
-class Backoff {
-public:
-  uint32_t m_minSlots; // Minimum number of backoff slots (when
-                       // multiplied by m_slotTime, determines minimum
-                       // backoff time)
-  uint32_t m_maxSlots; // Maximim number of backoff slots (when
-                       // multiplied by m_slotTime, determines
-                       // maximum backoff time)
-  uint32_t m_ceiling;  // Caps the exponential function when the
-                       // number of retries reaches m_ceiling
-  uint32_t m_maxRetries; // Maximum number of transmission retries
-                         // before the packet is dropped.
-  Time     m_slotTime; // Length of one slot. A slot time, it usually
-                       // the packet transmission time, if the packet
-                       // size is fixed.
-
-  Backoff();
-  Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots, 
-          uint32_t ceiling, uint32_t maxRetries);
-
-  /**
-   * \return The amount of time that the net device should wait before
-   * trying to retransmit the packet
-   */
-  Time GetBackoffTime();
-  /**
-   * Indicates to the backoff object that the last packet was
-   * successfully transmitted and that the number of retries should be
-   * reset to 0.
-   */
-  void ResetBackoffTime();
-  /**
-   * \return True if the maximum number of retries has been reached
-   */
-  bool MaxRetriesReached();
-  /**
-   * Increments the number of retries by 1.
-   */
-  void IncrNumRetries();
-
-private:
-  uint32_t m_numBackoffRetries; // Number of times that the
-                                // transmitter has tried to
-                                // unsuccessfully transmit the current
-                                // packet
-};
-
-}; // namespace ns3
-
-#endif // BACKOFF_H
-
--- a/src/devices/csma-cd/csma-cd-channel.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,371 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
- */
-
-#include "csma-cd-channel.h"
-#include "csma-cd-net-device.h"
-#include "ns3/packet.h"
-#include "ns3/simulator.h"
-#include "ns3/debug.h"
-
-NS_DEBUG_COMPONENT_DEFINE ("CsmaCdChannel");
-
-namespace ns3 {
-
-CsmaCdDeviceRec::CsmaCdDeviceRec()
-{
-  active = false;
-}
-
-CsmaCdDeviceRec::CsmaCdDeviceRec(Ptr<CsmaCdNetDevice> device)
-{
-  devicePtr = device; 
-  active = true;
-}
-
-bool
-CsmaCdDeviceRec::IsActive() {
-  return active;
-}
-
-
-//
-// By default, you get a channel with the name "CsmaCd Channel" that 
-// has an "infitely" fast transmission speed and zero delay.
-CsmaCdChannel::CsmaCdChannel()
-: 
-  Channel ("CsmaCd Channel"), 
-  m_bps (DataRate(0xffffffff)),
-  m_delay (Seconds(0))
-{
-  NS_DEBUG("CsmaCdChannel::CsmaCdChannel ()");
-  Init();
-}
-
-CsmaCdChannel::CsmaCdChannel(
-  const DataRate& bps, 
-  const Time& delay)
-: 
-  Channel ("CsmaCd Channel"), 
-  m_bps (bps),
-  m_delay (delay)
-{
-  NS_DEBUG("CsmaCdChannel::CsmaCdChannel (" << Channel::GetName() 
-    << ", " << bps.GetBitRate() << ", " << delay << ")");
-  Init();
-}
-
-CsmaCdChannel::CsmaCdChannel(
-  const std::string& name,
-  const DataRate& bps, 
-  const Time& delay)
-: 
-  Channel (name),
-  m_bps (bps), 
-  m_delay (delay)
-{
-  NS_DEBUG("CsmaCdChannel::CsmaCdChannel (" << name << ", " << 
-           bps.GetBitRate() << ", " << delay << ")");
-  Init();
-}
-
-void CsmaCdChannel::Init() {
-  m_state = IDLE;
-  m_deviceList.clear();
-}
-
-int32_t
-CsmaCdChannel::Attach(Ptr<CsmaCdNetDevice> device)
-{
-  NS_DEBUG("CsmaCdChannel::Attach (" << device << ")");
-  NS_ASSERT(device != 0);
-
-  CsmaCdDeviceRec rec(device);
-  
-  m_deviceList.push_back(rec);
-  return (m_deviceList.size() - 1);
-}
-
-bool
-CsmaCdChannel::Reattach(Ptr<CsmaCdNetDevice> device)
-{
-  NS_DEBUG("CsmaCdChannel::Reattach (" << device << ")");
-  NS_ASSERT(device != 0);
-
-  std::vector<CsmaCdDeviceRec>::iterator it;
-  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
-    {
-      if (it->devicePtr == device) 
-        {
-          if (!it->active) 
-            {
-              it->active = true;
-              return true;
-            } 
-          else 
-            {
-              return false;
-            }
-        }
-    }
-  return false;
-}
-
-bool
-CsmaCdChannel::Reattach(uint32_t deviceId)
-{
-  NS_DEBUG("CsmaCdChannel::Reattach (" << deviceId << ")");
-  if (deviceId < m_deviceList.size())
-    {
-      return false;
-    }
-
-  if (m_deviceList[deviceId].active)
-    {
-      return false;
-    } 
-  else 
-    {
-      m_deviceList[deviceId].active = true;
-      return true;
-    }
-}
-
-bool
-CsmaCdChannel::Detach(uint32_t deviceId)
-{
-  NS_DEBUG("CsmaCdChannel::Detach (" << deviceId << ")");
-
-  if (deviceId < m_deviceList.size())
-    {
-      if (!m_deviceList[deviceId].active)
-        {
-          NS_DEBUG("CsmaCdChannel::Detach Device is already detached (" 
-                   << deviceId << ")");
-          return false;
-        }
-
-      m_deviceList[deviceId].active = false;
-      if ((m_state == TRANSMITTING) && (m_currentSrc == deviceId))
-        {
-          NS_DEBUG("CsmaCdChannel::Detach Device is currently"
-                   << "transmitting (" << deviceId << ")");
-          // Here we will need to place a warning in the packet
-        }
-
-      return true;
-    } 
-  else 
-    {
-      return false;
-    }
-}
-
-bool
-CsmaCdChannel::Detach(Ptr<CsmaCdNetDevice> device)
-{
-  NS_DEBUG("CsmaCdChannel::Detach (" << device << ")");
-  NS_ASSERT(device != 0);
-
-  std::vector<CsmaCdDeviceRec>::iterator it;
-  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
-    {
-      if ((it->devicePtr == device) && (it->active)) 
-        {
-          it->active = false;
-          return true;
-        }
-    }
-  return false;
-}
-
-bool
-CsmaCdChannel::TransmitStart(Packet& p, uint32_t srcId)
-{
-  NS_DEBUG ("CsmaCdChannel::TransmitStart (" << &p << ", " << srcId 
-            << ")");
-  NS_DEBUG ("CsmaCdChannel::TransmitStart (): UID is " << 
-            p.GetUid () << ")");
-
-  if (m_state != IDLE)
-    {
-      NS_DEBUG("CsmaCdChannel::TransmitStart (): state is not IDLE");
-      return false;
-    }
-
-  if (!IsActive(srcId))
-    {
-      NS_DEBUG("CsmaCdChannel::TransmitStart (): ERROR: Seclected "
-               << "source is not currently attached to network");
-      return false;
-    }
-
-  NS_DEBUG("CsmaCdChannel::TransmitStart (): switch to TRANSMITTING");
-  m_currentPkt = p;
-  m_currentSrc = srcId;
-  m_state = TRANSMITTING;
-  return true;
-}
-
-bool
-CsmaCdChannel::IsActive(uint32_t deviceId) 
-{
-    return (m_deviceList[deviceId].active);
-}
-
-bool
-CsmaCdChannel::TransmitEnd()
-{
-  NS_DEBUG("CsmaCdChannel::TransmitEnd (" << &m_currentPkt << ", " 
-           << m_currentSrc << ")");
-  NS_DEBUG("CsmaCdChannel::TransmitEnd (): UID is " << 
-            m_currentPkt.GetUid () << ")");
-
-  NS_ASSERT(m_state == TRANSMITTING);
-  m_state = PROPAGATING;
-
-  bool retVal = true;
-
-  if (!IsActive(m_currentSrc)) {
-    NS_DEBUG("CsmaCdChannel::TransmitEnd (): ERROR: Seclected source "
-             << "was detached before the end of the transmission");
-    retVal = false;
-  }
-
-  NS_DEBUG ("CsmaCdChannel::TransmitEnd (): Schedule event in " << 
-            m_delay.GetSeconds () << "sec");
-
-  Simulator::Schedule (m_delay,
-                       &CsmaCdChannel::PropagationCompleteEvent,
-                       this);
-  return retVal;
-}
-
-void
-CsmaCdChannel::PropagationCompleteEvent()
-{
-  NS_DEBUG("CsmaCdChannel::PropagationCompleteEvent (" 
-           << &m_currentPkt << ")");
-  NS_DEBUG ("CsmaCdChannel::PropagationCompleteEvent (): UID is " << 
-            m_currentPkt.GetUid () << ")");
-
-  NS_ASSERT(m_state == PROPAGATING);
-  m_state = IDLE;
-
-  NS_DEBUG ("CsmaCdChannel::PropagationCompleteEvent (): Receive");
-  
-  std::vector<CsmaCdDeviceRec>::iterator it;
-  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
-    {
-      if (it->IsActive())
-      {
-        it->devicePtr->Receive (m_currentPkt);
-      }
-    }
-}
-
-
-uint32_t 
-CsmaCdChannel::GetNumActDevices (void)
-{
-  int numActDevices = 0;
-  std::vector<CsmaCdDeviceRec>::iterator it;
-  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
-    {
-      if (it->active)
-        {
-          numActDevices++;
-        }
-    }
-  return numActDevices;
-}
-
-// This is not the number of active devices. This is the total number
-// of devices even if some were detached after.
-uint32_t 
-CsmaCdChannel::GetNDevices (void) const
-{
-  return (m_deviceList.size());
-}
-
-Ptr<NetDevice>
-CsmaCdChannel::GetDevice (uint32_t i) const
-{
-  Ptr< CsmaCdNetDevice > netDevice;
-
-  netDevice = m_deviceList[i].devicePtr;
-  return netDevice;
-}
-
-int32_t
-CsmaCdChannel::GetDeviceNum (Ptr<CsmaCdNetDevice> device)
-{
-  std::vector<CsmaCdDeviceRec>::iterator it;
-  int i = 0;
-  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
-    {
-      if (it->devicePtr == device)
-        {
-          if (it->active) 
-            {
-              return i;
-            } 
-          else 
-            {
-              return -2;
-            }
-        }
-      i++;
-    }
-  return -1;
-}
-
-bool 
-CsmaCdChannel::IsBusy (void)
-{
-  if (m_state == IDLE) 
-    {
-      return false;
-    } 
-  else 
-    {
-      return true;
-    }
-}
-
-DataRate
-CsmaCdChannel::GetDataRate (void)
-{
-  return m_bps;
-}
-
-Time
-CsmaCdChannel::GetDelay (void)
-{
-  return m_delay;
-}
-
-WireState
-CsmaCdChannel::GetState(void)
-{
-  return m_state;
-}
-
-} // namespace ns3
--- a/src/devices/csma-cd/csma-cd-channel.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,307 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- *
- * 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: Emmanuelle Laprise<emmanuelle.laprise@bluekazoo.ca>
- */
-
-#ifndef CSMA_CD_CHANNEL_H
-#define CSMA_CD_CHANNEL_H
-
-#include "ns3/channel.h"
-#include "ns3/ptr.h"
-#include "ns3/packet.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-
-namespace ns3 {
-
-class CsmaCdNetDevice;
-
-  /**
-   * \brief CsmaCdNetDevice Record 
-   *
-   * Stores the information related to each net device that is
-   * connected to the channel. 
-   */
-  class CsmaCdDeviceRec {
-  public:
-    Ptr< CsmaCdNetDevice > devicePtr; /// Pointer to the net device
-    bool                       active;    /// Is net device enabled to TX/RX
-
-    CsmaCdDeviceRec();
-    CsmaCdDeviceRec(Ptr< CsmaCdNetDevice > device);
-    /*
-     * \return If the net device pointed to by the devicePtr is active
-     * and ready to RX/TX.
-     */
-    bool IsActive();                   
-  };
-
-  /**
-   * Current state of the channel
-   */ 
-  enum WireState
-    {
-      IDLE,          /**< Channel is IDLE, no packet is being
-                        transmitted */
-      TRANSMITTING,  /**< Channel is BUSY, a packet is being written
-                        by a net device */
-      PROPAGATING    /**< Channel is BUSY, packet is propagating to
-                        all attached net devices */
-    };
-
-/**
- * \brief CsmaCd Channel.
- *
- * This class represents a simple Csma/Cd channel that can be used
- * when many nodes are connected to one wire. It uses a single busy
- * flag to indicate if the channel is currently in use. It does not
- * take into account the distances between stations or the speed of
- * light to determine collisions.
- *
- * Each net device must query the state of the channel and make sure
- * that it is IDLE before writing a packet to the channel.
- *
- * When the channel is instaniated, the constructor takes parameters
- * for a single speed, in bits per second, and a speed-of-light delay
- * time as a Time object.  When a net device is attached to a channel,
- * it is assigned a device ID, this is in order to facilitate the
- * check that makes sure that a net device that is trying to send a
- * packet to the channel is really connected to this channel
- *
- */
-class CsmaCdChannel : public Channel {
-public:
-  /**
-   * \brief Create a CsmaCdChannel
-   *
-   * By default, you get a channel with the name "CsmaCd Channel" that
-   * has an "infitely" fast transmission speed and zero delay.
-   */
-  CsmaCdChannel ();
-  
-  /**
-   * \brief Create a CsmaCdChannel
-   *
-   * \param bps The bitrate of the channel
-   * \param delay Transmission delay through the channel
-   */  
-  CsmaCdChannel (const DataRate& bps, const Time& delay);
-  
-  /**
-   * \brief Create a CsmaCdChannel
-   *
-   * \param name the name of the channel for identification purposes
-   * \param bps The bitrate of the channel
-   * \param delay Transmission delay through the channel
-   */
-  CsmaCdChannel (const std::string& name,
-                     const DataRate& bps, const Time& delay);
-
-  /**
-   * \brief Attach a given netdevice to this channel
-   *
-   * \param device Device pointer to the netdevice to attach to the channel
-   * \return The assigned device number
-   */
-  int32_t Attach (Ptr<CsmaCdNetDevice> device);
-  /**
-   * \brief Detach a given netdevice from this channel
-   *
-   * The net device is marked as inactive and it is not allowed to
-   * receive or transmit packets
-   *
-   * \param device Device pointer to the netdevice to detach from the channel
-   * \return True if the device is found and attached to the channel,
-   * false if the device is not currently connected to the channel or
-   * can't be found.
-   */
-  bool Detach (Ptr<CsmaCdNetDevice> device);
-  /**
-   * \brief Detach a given netdevice from this channel
-   *
-   * The net device is marked as inactive and it is not allowed to
-   * receive or transmit packets
-   *
-   * \param deviceId The deviceID assigned to the net device when it
-   * was connected to the channel
-   * \return True if the device is found and attached to the channel,
-   * false if the device is not currently connected to the channel or
-   * can't be found.
-   */
-  bool Detach (uint32_t deviceId);
-  /**
-   * \brief Reattach a previously detached net device to the channel
-   *
-   * The net device is marked as active. It is now allowed to receive
-   * or transmit packets. The net device must have been previously
-   * attached to the channel using the attach function.
-   *
-   * \param deviceId The device ID assigned to the net device when it
-   * was connected to the channel
-   * \return True if the device is found and is not attached to the
-   * channel, false if the device is currently connected to the
-   * channel or can't be found.
-   */
-  bool Reattach(uint32_t deviceId);
-  /**
-   * \brief Reattach a previously detached net device to the channel
-   *
-   * The net device is marked as active. It is now allowed to receive
-   * or transmit packets. The net device must have been previously
-   * attached to the channel using the attach function.
-   *
-   * \param device Device pointer to the netdevice to detach from the channel
-   * \return True if the device is found and is not attached to the
-   * channel, false if the device is currently connected to the
-   * channel or can't be found.
-   */
-  bool Reattach(Ptr<CsmaCdNetDevice> device);
-  /**
-   * \brief Start transmitting a packet over the channel
-   *
-   * If the srcId belongs to a net device that is connected to the
-   * channel, packet transmission begins, and the channel becomes busy
-   * until the packet has completely reached all destinations.
-   *
-   * \param p A reference to the packet that will be transmitted over
-   * the channel
-   * \param srcId The device Id of the net device that wants to
-   * transmit on the channel.
-   * \return True if the channel is not busy and the transmitting net
-   * device is currently active.
-   */
-  bool TransmitStart (Packet& p, uint32_t srcId);
-  /**
-   * \brief Indicates that the net device has finished transmitting
-   * the packet over the channel
-   *
-   * The channel will stay busy until the packet has completely
-   * propagated to all net devices attached to the channel. The
-   * TransmitEnd function schedules the PropagationCompleteEvent which
-   * will free the channel for further transmissions. Stores the
-   * packet p as the m_currentPkt, the packet being currently
-   * transmitting.
-   *
-   * \return Returns true unless the source was detached before it
-   * completed its transmission.
-   */
-  bool TransmitEnd ();
-  /**
-   * \brief Indicates that the channel has finished propagating the
-   * current packet. The channel is released and becomes free.
-   *
-   * Calls the receive function of every active net device that is
-   * attached to the channel.
-   */
-  void PropagationCompleteEvent();
-  /**
-   * \return Returns the device number assigned to a net device by the
-   * channel
-   *
-   * \param device Device pointer to the netdevice for which the device
-   * number is needed
-   */
-  int32_t GetDeviceNum (Ptr<CsmaCdNetDevice> device);
-  /**
-   * \return Returns the state of the channel (IDLE -- free,
-   * TRANSMITTING -- busy, PROPAGATING - busy )
-   */
-  WireState GetState();
-
-  /**
-   * \brief Indicates if the channel is busy. The channel will only
-   * accept new packets for transmission if it is not busy.
-   *
-   * \return Returns true if the channel is busy and false if it is
-   * free.
-   */
-  bool IsBusy();
-  
-  /**
-   * \brief Indicates if a net device is currently attached or
-   * detached from the channel.
-   *
-   * \param deviceId The ID that was assigned to the net device when
-   * it was attached to the channel.
-   * \return Returns true if the net device is attached to the
-   * channel, false otherwise.
-   */
-  bool IsActive(uint32_t deviceId);
-  /**
-   * \return Returns the number of net devices that are currently
-   * attached to the channel.
-   */
-  uint32_t GetNumActDevices (void);
-  /**
-   * \return Returns the total number of devices including devices
-   * that have been detached from the channel.
-   */
-  virtual uint32_t GetNDevices (void) const;
-  /**
-   * \param i The deviceId of the net device for which we want the
-   * pointer.
-   * \return Returns the pointer to the net device that is associated
-   * with deviceId i.
-   */
-  virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
-
-  virtual DataRate GetDataRate (void);
-  virtual Time GetDelay (void);
-
-private:
-  DataRate      m_bps;    /// Data rate of the channel
-  Time          m_delay;  /// Delay of the channel.
-
-  /**
-   * List of the net devices that have been or are currently connected
-   * to the channel.
-   *
-   * Devices are nor removed from this list, they are marked as
-   * inactive. Otherwise the assigned device IDs will not refer to the
-   * correct NetDevice. The DeviceIds are used so that it is possible
-   * to have a number to refer to an entry in the list so that the
-   * whole list does not have to be searched when making sure that a
-   * source is attached to a channel when it is transmitting data.
-   */
-  std::vector< CsmaCdDeviceRec >            m_deviceList;
-  /**
-   * Packet that is currently being transmitted on the channel (or last
-   * packet to have been transmitted on the channel if the channel is
-   * free.)
-   */
-  Packet                              m_currentPkt;
-  /**
-   * Device Id of the source that is currently transmitting on the
-   * channel. Or last source to have transmitted a packet on the
-   * channel, if the channel is currently not busy.
-   */
-  uint32_t                            m_currentSrc;
-  /**
-   * Current state of the channel
-   */
-  WireState          m_state;
-  /**
-   * Initializes the channel when it is constructed. Resets the
-   * deviceList and sets the channel state to IDLE.
-   */
-  void Init (void);
-};
-
-} // namespace ns3
-
-#endif /* CSMA_CD_CHANNEL_H */
--- a/src/devices/csma-cd/csma-cd-ipv4-topology.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2007 Emmanuelle Laprise
-//
-// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
-//
-
-#include <algorithm>
-#include "ns3/assert.h"
-#include "ns3/debug.h"
-#include "ns3/fatal-error.h"
-#include "ns3/nstime.h"
-#include "ns3/internet-node.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/queue.h"
-
-#include "csma-cd-channel.h"
-#include "csma-cd-net-device.h"
-#include "csma-cd-ipv4-topology.h"
-
-namespace ns3 {
-
-
-uint32_t
-CsmaCdIpv4Topology::AddIpv4CsmaCdNode(Ptr<Node> n1,
-                                      Ptr<CsmaCdChannel> ch,
-                                      MacAddress addr)
-{
-  Ptr<Queue> q = Queue::CreateDefault ();
-
-  // assume full-duplex
-  Ptr<CsmaCdNetDevice> nd0 = Create<CsmaCdNetDevice> (n1, addr, 
-                                                      ns3::CsmaCdNetDevice::IP_ARP,
-                                                      true, true);
-  nd0->AddQueue(q);
-  nd0->Attach (ch);
-  return nd0->GetIfIndex ();
-}
-
-
-void
-CsmaCdIpv4Topology::AddIpv4LlcCsmaCdNode(Ptr<Node> n1,
-                                         Ptr<CsmaCdChannel> ch,
-                                         MacAddress addr)
-{
-  Ptr<Queue> q = Queue::CreateDefault ();
-
-  Ptr<CsmaCdNetDevice> nd0 = Create<CsmaCdNetDevice> (n1, addr,
-                                                      ns3::CsmaCdNetDevice::LLC,
-                                                      true, false);
-  nd0->AddQueue(q);
-  nd0->Attach (ch);
-
-  Ptr<CsmaCdNetDevice> nd1 = Create<CsmaCdNetDevice> (n1, addr,
-                                                      ns3::CsmaCdNetDevice::LLC,
-                                                      false, true);
-  nd1->AddQueue(q);
-  nd1->Attach (ch);
-}
-
-void
-CsmaCdIpv4Topology::AddIpv4RawCsmaCdNode(Ptr<Node> n1,
-                                         Ptr<CsmaCdChannel> ch,
-                                         MacAddress addr)
-{
-  Ptr<Queue> q = Queue::CreateDefault ();
-
-  Ptr<CsmaCdNetDevice> nd0 = Create<CsmaCdNetDevice> (n1, addr,
-                                                      ns3::CsmaCdNetDevice::RAW,
-                                                      true, false);
-  nd0->AddQueue(q);
-  nd0->Attach (ch);
-
-  Ptr<CsmaCdNetDevice> nd1 = Create<CsmaCdNetDevice> (n1, addr,
-                                                      ns3::CsmaCdNetDevice::RAW,
-                                                      false, true);
-  nd1->AddQueue(q);
-  nd1->Attach (ch);
-}
-
-void
-CsmaCdIpv4Topology::AddIpv4Address(Ptr<Node> n1,
-                                       int ndNum,
-                                       const Ipv4Address& addr1,
-                                       const Ipv4Mask& netmask1)
-{
-
-  // Duplex link is assumed to be subnetted as a /30
-  // May run this unnumbered in the future?
-  Ipv4Mask netmask(netmask1);
-
-  Ptr<NetDevice> nd1 = n1->GetDevice(ndNum);
-
-  Ptr<Ipv4> ip1 = n1->QueryInterface<Ipv4> (Ipv4::iid);
-  uint32_t index1 = ip1->AddInterface (nd1);
-
-  ip1->SetAddress (index1, addr1);
-  ip1->SetNetworkMask (index1, netmask);
-  ip1->SetUp (index1);
-
-}
-
-void
-CsmaCdIpv4Topology::AddIpv4Routes (
-  Ptr<NetDevice> nd1, Ptr<NetDevice> nd2)
-{ 
-  // Assert that both are Ipv4 nodes
-  Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
-  Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
-  NS_ASSERT(ip1 != 0 && ip2 != 0);
-
-  // Get interface indexes for both nodes corresponding to the right channel
-  uint32_t index1 = 0;
-  bool found = false;
-  for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
-    {
-      if (ip1 ->GetNetDevice (i) == nd1)
-        {
-          index1 = i;
-          found = true;
-        }
-    }
-  NS_ASSERT(found);
-
-  uint32_t index2 = 0;
-  found = false;
-  for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
-    {
-      if (ip2 ->GetNetDevice (i) == nd2)
-        {
-          index2 = i;
-          found = true;
-        }
-    }
-  NS_ASSERT(found);
-
-  ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
-  ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2); 
-}
-
-} // namespace ns3
- 
--- a/src/devices/csma-cd/csma-cd-ipv4-topology.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2007 Emmanuelle Laprise
-//
-// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
-//
-
-#ifndef __CSMA_CD_IPV4_TOPOLOGY_H__
-#define __CSMA_CD_IPV4_TOPOLOGY_H__
-
-#include "ns3/ptr.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ipv4.h"
-#include "ns3/ipv4-route.h"
-#include "ns3/internet-node.h"
-#include "ns3/csma-cd-net-device.h"
-
-// The topology class consists of only static methods thar are used to
-// create the topology and data flows for an ns3 simulation
-
-namespace ns3 {
-
-class CsmaCdIpv4Channel;
-class Node;
-class IPAddr;
-class DataRate;
-class Queue;
-
-/**
- * \brief A helper class to create Topologies based on the
- * InternetNodes and CsmaCdChannels. Either the
- * SimpleCsmaCdNetDevice or the LLCCsmaCdNetDevice can be used
- * when constructing these topologies.
- */
-class CsmaCdIpv4Topology {
-public:
-
-  /**
-   * \param n1 Node to be attached to the Csma/Cd channel
-   * \param ch CsmaCdChannel to which node n1 should be attached
-   * \param addr Mac address of the node
-   *
-   * Add a Csma/Cd node to a Csma/Cd channel. This function adds
-   * a EthernetCsmaCdNetDevice to the nodes so that they can
-   * connect to a CsmaCdChannel. This means that Ethernet headers
-   * and trailers will be added to the packet before sending out on
-   * the net device.
-   * 
-   * \return ifIndex of the device
-   */
-  static uint32_t AddIpv4CsmaCdNode( Ptr<Node> n1,
-                                 Ptr<CsmaCdChannel> ch,
-                                 MacAddress addr);
-
-  /**
-   * \param n1 Node to be attached to the Csma/Cd channel
-   * \param ch CsmaCdChannel to which node n1 should be attached
-   * \param addr Mac address of the node
-   *
-   * Add a Csma/Cd node to a Csma/Cd channel. This function adds
-   * a RawCsmaCdNetDevice to the nodes so that they can connect
-   * to a CsmaCdChannel.
-   */
-  static void AddIpv4RawCsmaCdNode( Ptr<Node> n1,
-                                    Ptr<CsmaCdChannel> ch,
-                                    MacAddress addr);
-
-  /**
-   * \param n1 Node to be attached to the Csma/Cd channel
-   * \param ch CsmaCdChannel to which node n1 should be attached
-   * \param addr Mac address of the node
-   *
-   * Add a Csma/Cd node to a Csma/Cd channel. This function adds
-   * a LlcCsmaCdNetDevice to the nodes so that they can connect
-   * to a CsmaCdChannel.
-   */
-  static void AddIpv4LlcCsmaCdNode( Ptr<Node> n1,
-                                    Ptr<CsmaCdChannel> ch,
-                                    MacAddress addr);
-
-
-
-  /** 
-   * \param n1 Node
-   * \param ndNum NetDevice number with which to associate address
-   * \param addr1 Ipv4 Address for ndNum of n1
-   * \param network network mask for ndNum of node n1
-   * 
-   * Add an Ipv4Address to the Ipv4 interface associated with the
-   * ndNum CsmaCdIpv4NetDevices on the provided
-   * CsmaCdIpv4Channel
-   */
-  static void AddIpv4Address(Ptr<Node> n1, int ndNum, 
-                             const Ipv4Address& addr1,
-                             const Ipv4Mask& netmask1);
-
-  /**
-   * \param nd1 Node
-   * \param nd2 Node
-   * 
-   * Add an IPV4 host route between the two specified net devices
-   */
-  static void AddIpv4Routes (Ptr<NetDevice> nd1, Ptr<NetDevice> nd2);
-};
-
-} // namespace ns3
-
-#endif
-
--- a/src/devices/csma-cd/csma-cd-net-device.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,488 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
- */
-
-#include <iostream>
-#include <cassert>
-#include "ns3/debug.h"
-#include "ns3/queue.h"
-#include "ns3/simulator.h"
-#include "ns3/composite-trace-resolver.h"
-#include "csma-cd-net-device.h"
-#include "csma-cd-channel.h"
-#include "ns3/ethernet-header.h"
-#include "ns3/ethernet-trailer.h"
-#include "ns3/llc-snap-header.h"
-
-NS_DEBUG_COMPONENT_DEFINE ("CsmaCdNetDevice");
-
-namespace ns3 {
-
-CsmaCdNetDevice::CsmaCdNetDevice (Ptr<Node> node, MacAddress addr, 
-                                  CsmaCdEncapsulationMode encapMode) 
-  : NetDevice(node, addr), m_bps (DataRate (0xffffffff))
-{
-  NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")");
-  m_encapMode = encapMode;
-
-  Init(true, true);
-}
-
-CsmaCdNetDevice::CsmaCdNetDevice (Ptr<Node> node, MacAddress addr, 
-                                  CsmaCdEncapsulationMode encapMode,
-                                  bool sendEnable, bool receiveEnable) 
-  : NetDevice(node, addr), m_bps (DataRate (0xffffffff))
-{
-  NS_DEBUG ("CsmaCdNetDevice::CsmaCdNetDevice (" << node << ")");
-  m_encapMode = encapMode;
-
-  Init(sendEnable, receiveEnable);
-}
-
-CsmaCdNetDevice::~CsmaCdNetDevice()
-{
-  NS_DEBUG ("CsmaCdNetDevice::~CsmaCdNetDevice ()");
-  m_queue = 0;
-}
-
-void 
-CsmaCdNetDevice::DoDispose ()
-{
-  m_channel = 0;
-  NetDevice::DoDispose ();
-}
-
-//
-// Assignment operator for CsmaCdNetDevice.
-//
-// This uses the non-obvious trick of taking the source net device passed by
-// value instead of by reference.  This causes the copy constructor to be
-// invoked (where the real work is done -- see above).  All we have to do
-// here is to return the newly constructed net device.
-//
-/*
-CsmaCdNetDevice&
-CsmaCdNetDevice::operator= (const CsmaCdNetDevice nd)
-{
-  NS_DEBUG ("CsmaCdNetDevice::operator= (" << &nd << ")");
-  return *this;
-}
-*/
-
-void 
-CsmaCdNetDevice::Init(bool sendEnable, bool receiveEnable)
-{
-  m_txMachineState = READY;
-  m_tInterframeGap = Seconds(0);
-  m_channel = 0; 
-  m_queue = 0;
-
-  EnableBroadcast (MacAddress ("ff:ff:ff:ff:ff:ff"));
-  EnableMulticast();
-  EnablePointToPoint();
-
-  SetSendEnable (sendEnable);
-  SetReceiveEnable (receiveEnable);
-}
-
-void
-CsmaCdNetDevice::SetSendEnable (bool sendEnable)
-{
-  m_sendEnable = sendEnable;
-}
-
-void
-CsmaCdNetDevice::SetReceiveEnable (bool receiveEnable)
-{
-  m_receiveEnable = receiveEnable;
-}
-bool
-CsmaCdNetDevice::IsSendEnabled (void)
-{
-  return (m_sendEnable);
-}
-
-bool
-CsmaCdNetDevice::IsReceiveEnabled (void)
-{
-  return (m_receiveEnable);
-}
-
-void 
-CsmaCdNetDevice::SetDataRate (DataRate bps)
-{
-  m_bps = bps;
-}
-
-void 
-CsmaCdNetDevice::SetInterframeGap (Time t)
-{
-  m_tInterframeGap = t;
-}
-
-void 
-CsmaCdNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots, 
-                                      uint32_t maxSlots, uint32_t ceiling, 
-                                      uint32_t maxRetries)
-{
-  m_backoff.m_slotTime = slotTime;
-  m_backoff.m_minSlots = minSlots;
-  m_backoff.m_maxSlots = maxSlots;
-  m_backoff.m_ceiling = ceiling;
-  m_backoff.m_maxRetries = maxRetries;
-}
-void 
-CsmaCdNetDevice::AddHeader (Packet& p, const MacAddress& dest,
-                            uint16_t protocolNumber)
-{
-  if (m_encapMode == RAW)
-    {
-      return;
-    }
-  EthernetHeader header (false);
-  EthernetTrailer trailer;
-  header.SetSource(this->GetAddress());
-  header.SetDestination(dest);
-
-  uint16_t lengthType = 0;
-  switch (m_encapMode) 
-    {
-    case ETHERNET_V1:
-      lengthType = p.GetSize() + header.GetSize() + trailer.GetSize();
-      break;
-    case IP_ARP:
-      lengthType = protocolNumber;
-      break;
-    case LLC: {
-      LlcSnapHeader llc;
-      llc.SetType (protocolNumber);
-      p.AddHeader (llc);
-    } break;
-    case RAW:
-      NS_ASSERT (false);
-      break;
-    }
-  header.SetLengthType (lengthType);
-  p.AddHeader(header);
-  trailer.CalcFcs(p);
-  p.AddTrailer(trailer);
-}
-bool 
-CsmaCdNetDevice::ProcessHeader (Packet& p, uint16_t & param)
-{
-  if (m_encapMode == RAW)
-    {
-      return true;
-    }
-  EthernetHeader header (false);
-  EthernetTrailer trailer;
-      
-  p.RemoveTrailer(trailer);
-  trailer.CheckFcs(p);
-  p.RemoveHeader(header);
-
-  if ((header.GetDestination() != this->GetBroadcast()) &&
-      (header.GetDestination() != this->GetAddress()))
-    {
-      return false;
-    }
-
-  switch (m_encapMode)
-    {
-    case ETHERNET_V1:
-    case IP_ARP:
-      param = header.GetLengthType();
-      break;
-    case LLC: {
-      LlcSnapHeader llc;
-      p.RemoveHeader (llc);
-      param = llc.GetType ();
-    } break;
-    case RAW:
-      NS_ASSERT (false);
-      break;
-    }
-  return true;
-}
-
-bool
-CsmaCdNetDevice::DoNeedsArp (void) const
-{
-  if ((m_encapMode == IP_ARP) || (m_encapMode == LLC))
-    {
-      return true;
-    } 
-  else 
-    {
-      return false;
-    }
-}
-
-bool
-CsmaCdNetDevice::SendTo (Packet& p, const MacAddress& dest, uint16_t protocolNumber)
-{
-  NS_DEBUG ("CsmaCdNetDevice::SendTo (" << &p << ")");
-  NS_DEBUG ("CsmaCdNetDevice::SendTo (): UID is " << p.GetUid () << ")");
-
-  NS_ASSERT (IsLinkUp ());
-
-  // Only transmit if send side of net device is enabled
-  if (!IsSendEnabled())
-    return false;
-
-  AddHeader(p, dest, protocolNumber);
-
-  // Place the packet to be sent on the send queue
-  if (m_queue->Enqueue(p) == false )
-    {
-      return false;
-    }
-  // If the device is idle, we need to start a transmission. Otherwise,
-  // the transmission will be started when the current packet finished
-  // transmission (see TransmitCompleteEvent)
-  if (m_txMachineState == READY) 
-    {
-      // Store the next packet to be transmitted
-      if (m_queue->Dequeue (m_currentPkt))
-        {
-          TransmitStart();
-        }
-    }
-  return true;
-}
-
-void
-CsmaCdNetDevice::TransmitStart ()
-{
-  NS_DEBUG ("CsmaCdNetDevice::TransmitStart (" << &m_currentPkt << ")");
-  NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): UID is " 
-            << m_currentPkt.GetUid () << ")");
-//
-// This function is called to start the process of transmitting a packet.
-// We need to tell the channel that we've started wiggling the wire and
-// schedule an event that will be executed when it's time to tell the 
-// channel that we're done wiggling the wire.
-//
-  NS_ASSERT_MSG((m_txMachineState == READY) || (m_txMachineState == BACKOFF), 
-                "Must be READY to transmit. Tx state is: " 
-                << m_txMachineState);
-
-  // Only transmit if send side of net device is enabled
-  if (!IsSendEnabled())
-    return;
-
-  if (m_channel->GetState() != IDLE)
-    { // Channel busy, backoff and rechedule TransmitStart()
-      m_txMachineState = BACKOFF;
-      if (m_backoff.MaxRetriesReached())
-        { // Too many retries reached, abort transmission of packet
-          TransmitAbort();
-        } 
-      else 
-        {
-          m_backoff.IncrNumRetries();
-          Time backoffTime = m_backoff.GetBackoffTime();
-
-          NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): " 
-                    << "Channel busy, backing off for " 
-                    << backoffTime.GetSeconds () << "sec");
-
-          Simulator::Schedule (backoffTime, 
-                               &CsmaCdNetDevice::TransmitStart, 
-                               this);
-        }
-    } 
-  else 
-    {
-      // Channel is free, transmit packet
-      m_txMachineState = BUSY;
-      Time tEvent = Seconds (m_bps.CalculateTxTime(m_currentPkt.GetSize()));
-      
-      NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): " <<
-                "Schedule TransmitCompleteEvent in " << 
-                tEvent.GetSeconds () << "sec");
-      
-      Simulator::Schedule (tEvent, 
-                           &CsmaCdNetDevice::TransmitCompleteEvent, 
-                           this);
-      if (!m_channel->TransmitStart (m_currentPkt, m_deviceId))
-        {
-          NS_DEBUG ("CsmaCdNetDevice::TransmitStart (): " <<
-                    "Channel transmit start did not work at " << 
-                    tEvent.GetSeconds () << "sec");
-          m_txMachineState = READY;
-        } 
-      else 
-        {
-          // Transmission success, reset backoff time parameters.
-          m_backoff.ResetBackoffTime();
-        }
-    }
-}
-
-
-void
-CsmaCdNetDevice::TransmitAbort (void)
-{
-  NS_DEBUG ("CsmaCdNetDevice::TransmitAbort ()");
-
-  NS_DEBUG ("CsmaCdNetDevice::TransmitAbort (): Pkt UID is " <<
-            m_currentPkt.GetUid () << ")");
-
-  // Try to transmit a new packet
-  bool found;
-  found = m_queue->Dequeue (m_currentPkt);
-  NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
-  m_backoff.ResetBackoffTime();
-  m_txMachineState = READY;
-  TransmitStart ();
-}
-
-void
-CsmaCdNetDevice::TransmitCompleteEvent (void)
-{
-  NS_DEBUG ("CsmaCdNetDevice::TransmitCompleteEvent ()");
-//
-// This function is called to finish the  process of transmitting a packet.
-// We need to tell the channel that we've stopped wiggling the wire and
-// schedule an event that will be executed when it's time to re-enable
-// the transmitter after the interframe gap.
-//
-  NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
-  // Channel should be transmitting
-  NS_ASSERT(m_channel->GetState() == TRANSMITTING);
-  m_txMachineState = GAP;
-
-  NS_DEBUG ("CsmaCdNetDevice::TransmitCompleteEvent (): Pkt UID is " << 
-            m_currentPkt.GetUid () << ")");
-  m_channel->TransmitEnd (); 
-
-  NS_DEBUG (
-    "CsmaCdNetDevice::TransmitCompleteEvent (): " <<
-    "Schedule TransmitReadyEvent in "
-    << m_tInterframeGap.GetSeconds () << "sec");
-
-  Simulator::Schedule (m_tInterframeGap, 
-                       &CsmaCdNetDevice::TransmitReadyEvent, 
-                       this);
-}
-
-void
-CsmaCdNetDevice::TransmitReadyEvent (void)
-{
-  NS_DEBUG ("CsmaCdNetDevice::TransmitReadyEvent ()");
-//
-// This function is called to enable the transmitter after the interframe
-// gap has passed.  If there are pending transmissions, we use this opportunity
-// to start the next transmit.
-//
-  NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
-  m_txMachineState = READY;
-
-  // Get the next packet from the queue for transmitting
-  if (m_queue->IsEmpty())
-    {
-      return;
-    }
-  else
-    {
-      bool found;
-      found = m_queue->Dequeue (m_currentPkt);
-      NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
-      TransmitStart ();
-    }
-}
-
-TraceResolver *
-CsmaCdNetDevice::DoCreateTraceResolver (TraceContext const &context)
-{
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  resolver->Add ("queue", 
-                 MakeCallback (&Queue::CreateTraceResolver, 
-                               PeekPointer (m_queue)),
-                 CsmaCdNetDevice::QUEUE);
-  resolver->Add ("rx",
-                 m_rxTrace,
-                 CsmaCdNetDevice::RX);
-  return resolver;
-}
-
-bool
-CsmaCdNetDevice::Attach (Ptr<CsmaCdChannel> ch)
-{
-  NS_DEBUG ("CsmaCdNetDevice::Attach (" << &ch << ")");
-
-  m_channel = ch;
-
-  m_deviceId = m_channel->Attach(this);
-  m_bps = m_channel->GetDataRate ();
-  m_tInterframeGap = m_channel->GetDelay ();
-
-  /* 
-   * For now, this device is up whenever a channel is attached to it.
-   */
-  NotifyLinkUp ();
-  return true;
-}
-
-void
-CsmaCdNetDevice::AddQueue (Ptr<Queue> q)
-{
-  NS_DEBUG ("CsmaCdNetDevice::AddQueue (" << q << ")");
-
-  m_queue = q;
-}
-
-void
-CsmaCdNetDevice::Receive (Packet& p)
-{
-  NS_DEBUG ("CsmaCdNetDevice::Receive UID is (" << p.GetUid() << ")");
-
-  // Only receive if send side of net device is enabled
-  if (!IsReceiveEnabled())
-    return;
-
-  uint16_t param = 0;
-  Packet packet = p;
-
-  if (ProcessHeader(packet, param))
-    {
-      m_rxTrace (packet);
-      ForwardUp (packet, param);
-    } 
-  else 
-    {
-      m_dropTrace (packet);
-    }
-}
-
-Ptr<Queue>
-CsmaCdNetDevice::GetQueue(void) const 
-{ 
-    return m_queue;
-}
-
-Ptr<Channel>
-CsmaCdNetDevice::DoGetChannel(void) const 
-{ 
-    return m_channel;
-}
-
-} // namespace ns3
--- a/src/devices/csma-cd/csma-cd-net-device.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,409 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2007 Emmanuelle Laprise
- *
- * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
- * Derived from the p2p net device file
- */
-
-#ifndef CSMA_CD_NET_DEVICE_H
-#define CSMA_CD_NET_DEVICE_H
-
-#include <string.h>
-#include "ns3/node.h"
-#include "ns3/backoff.h"
-#include "ns3/mac-address.h"
-#include "ns3/net-device.h"
-#include "ns3/callback.h"
-#include "ns3/packet.h"
-#include "ns3/callback-trace-source.h"
-#include "ns3/nstime.h"
-#include "ns3/data-rate.h"
-#include "ns3/ptr.h"
-#include "ns3/random-variable.h"
-
-namespace ns3 {
-
-class Queue;
-class CsmaCdChannel;
-
-/**
- * \class CsmaCdNetDevice
- * \brief A Device for a CsmaCd Network Link.
- *
- * The Csma/Cd net device class is analogous to layer 1 and 2 of the
- * TCP stack. The NetDevice takes a raw packet of bytes and creates a
- * protocol specific packet from them. The Csma/Cd net device class
- * takes this packet and adds and processes the headers/trailers that
- * are associated with EthernetV1, EthernetV2, RAW or LLC
- * protocols. The EthernetV1 packet type adds and removes Ethernet
- * destination and source addresses. The LLC packet type adds and
- * removes LLC snap headers. The raw packet type does not add or
- * remove any headers.  Each Csma/Cd net device will receive all
- * packets written to the Csma/Cd link. The ProcessHeader function can
- * be used to filter out the packets such that higher level layers
- * only receive packets that are addressed to their associated net
- * devices
- *
- */
-class CsmaCdNetDevice : public NetDevice {
-public:
-  /**
-   * Enumeration of the types of traces supported in the class.
-   *
-   */
-  enum TraceType {
-    QUEUE, /**< Trace queue events on the attached queue */
-    RX,    /**< Trace packet reception events (from the channel) */
-    DROP    /**< Trace packet drop events (from the channel) */
-  };
-
-  /**
-   * Enumeration of the types of packets supported in the class.
-   *
-   */
-enum CsmaCdEncapsulationMode {
-  ETHERNET_V1, /**< Version one ethernet packet, length field */
-  IP_ARP,      /**< Ethernet packet encapsulates IP/ARP packet */
-  RAW,         /**< Packet that contains no headers */
-  LLC,         /**< LLC packet encapsulation */  
-};
-
-  /**
-   * Construct a CsmaCdNetDevice
-   *
-   * This is the constructor for the CsmaCdNetDevice.  It takes as a
-   * parameter the Node to which this device is connected.  Ownership of the
-   * Node pointer is not implied and the node must not be deleted.
-   *
-   * \param node the Node to which this device is connected.
-   * \param addr The source MAC address of the net device.
-   */
-  CsmaCdNetDevice (Ptr<Node> node, MacAddress addr, CsmaCdEncapsulationMode pktType);
-  CsmaCdNetDevice (Ptr<Node> node, MacAddress addr,
-                   CsmaCdEncapsulationMode pktType,
-                   bool sendEnable, bool receiveEnable);
-  /**
-   * Destroy a CsmaCdNetDevice
-   *
-   * This is the destructor for the CsmaCdNetDevice.
-   */
-  virtual ~CsmaCdNetDevice();
-  /**
-   * Set the Data Rate used for transmission of packets.  The data rate is
-   * set in the Attach () method from the corresponding field in the channel
-   * to which the device is attached.  It can be overridden using this method.
-   *
-   * @see Attach ()
-   * \param bps the data rate at which this object operates
-   */
-  void SetDataRate (DataRate bps);
-  /**
-   * Set the inteframe gap used to separate packets.  The interframe gap
-   * defines the minimum space required between packets sent by this device.
-   * It is usually set in the Attach () method based on the speed of light
-   * delay of the channel to which the device is attached.  It can be 
-   * overridden using this method if desired.
-   *
-   * @see Attach ()
-   * \param t the interframe gap time
-   */
-  void SetInterframeGap (Time t);
-  /**
-   * Set the backoff parameters used to determine the wait to retry
-   * transmitting a packet when the channel is busy.
-   *
-   * @see Attach ()
-   * \param slotTime Length of a packet slot (or average packet time)
-   * \param minSlots Minimum number of slots to wait
-   * \param maxSlots Maximum number of slots to wait
-   * \param maxRetries Maximum number of retries before packet is discard
-   * \param ceiling Cap on the exponential function when calculating max slots
-   */
-  void SetBackoffParams (Time slotTime, uint32_t minSlots, uint32_t maxSlots, 
-                        uint32_t maxRetries, uint32_t ceiling);
-  /**
-   * Attach the device to a channel.
-   *
-   * The function Attach is used to add a CsmaCdNetDevice to a
-   * CsmaCdChannel.
-   *
-   * @see SetDataRate ()
-   * @see SetInterframeGap ()
-   * \param ch a pointer to the channel to which this object is being attached.
-   */
-  bool Attach (Ptr<CsmaCdChannel> ch);
-  /**
-   * Attach a queue to the CsmaCdNetDevice.
-   *
-   * The CsmaCdNetDevice "owns" a queue.  This queue is created by the
-   * CsmaCdTopology object and implements a queueing method such as
-   * DropTail or RED.  The CsmaCdNetDevice assumes ownership of this
-   * queue and must delete it when the device is destroyed.
-   *
-   * @see CsmaCdTopology::AddCsmaCdLink ()
-   * @see Queue
-   * @see DropTailQueue
-   * \param queue a pointer to the queue for which object is assuming
-   *        ownership.
-   */
-  void AddQueue (Ptr<Queue> queue);
-  /**
-   * Receive a packet from a connected CsmaCdChannel.
-   *
-   * The CsmaCdNetDevice receives packets from its connected channel
-   * and forwards them up the protocol stack.  This is the public method
-   * used by the channel to indicate that the last bit of a packet has 
-   * arrived at the device.
-   *
-   * @see CsmaCdChannel
-   * \param p a reference to the received packet
-   */
-  void Receive (Packet& p);
-
-  bool IsSendEnabled (void);
-  bool IsReceiveEnabled (void);
-
-  void SetSendEnable (bool);
-  void SetReceiveEnable (bool);
-
-protected:
-  virtual bool DoNeedsArp (void) const;
-  virtual void DoDispose (void);
-  /**
-   * Get a copy of the attached Queue.
-   *
-   * This method is provided for any derived class that may need to get
-   * direct access to the underlying queue.
-   *
-   * \return a pointer to the queue.
-   */
-  Ptr<Queue> GetQueue (void) const; 
-  /**
-   * Get a copy of the attached Channel
-   *
-   * This method is provided for any derived class that may need to get
-   * direct access to the connected channel
-   *
-   * \return a pointer to the channel
-   */
-  virtual Ptr<Channel> DoGetChannel (void) const;
-  /**
-   * Adds the necessary headers and trailers to a packet of data in order to
-   * respect the packet type
-   *
-   * \param p Packet to which header should be added
-   * \param dest MAC destination address to which packet should be sent
-   * \param protocolNumber In some protocols, identifies the type of
-   * payload contained in this packet.
-   */
-  void AddHeader (Packet& p, const MacAddress& dest, 
-                  uint16_t protocolNumber);
-  /**
-   * Removes, from a packet of data, all headers and trailers that
-   * relate to the packet type
-   *
-   * \param p Packet whose headers need to be processed
-   * \param param An integer parameter that can be set by the function
-   * to return information gathered in the header
-   * \return Returns true if the packet should be forwarded up the
-   * protocol stack.
-   */
-  bool ProcessHeader (Packet& p, uint16_t & param);
-
-private:
-  // disable copy constructor and operator =
-  CsmaCdNetDevice &operator = (const CsmaCdNetDevice &o);
-  CsmaCdNetDevice (const CsmaCdNetDevice &o);
-  /**
-   * Initializes variablea when construction object.
-   */
-  void Init (bool sendEnable, bool receiveEnable);
-  /**
-   * Send a Packet on the Csma/Cd network
-   *
-   * This method does not use a destination address since all packets
-   * are broadcast to all NetDevices attached to the channel. Packet
-   * should contain all needed headers at this time.
-   *
-   * If the device is ready to transmit, the next packet is read off
-   * of the queue and stored locally until it has been transmitted.
-   *
-   * \param p a reference to the packet to send
-   * \param dest destination address
-   * \param protocolNumber -- this parameter is not used here
-   * \return true if success, false on failure
-   */
-  virtual bool SendTo (Packet& p, const MacAddress& dest, uint16_t protocolNumber);
-
-  /**
-   * Start Sending a Packet Down the Wire.
-   *
-   * The TransmitStart method is the method that is used internally in
-   * the CsmaCdNetDevice to begin the process of sending a packet
-   * out on the channel.  The corresponding method is called on the
-   * channel to let it know that the physical device this class
-   * represents has virually started sending signals, this causes the
-   * channel to become busy.  An event is scheduled for the time at
-   * which the bits have been completely transmitted. If the channel
-   * is busy, the method reschedules itself for a later time (within
-   * the backoff period)
-   *
-   * @see CsmaCdChannel::TransmitStart ()
-   * @see TransmitCompleteEvent ()
-   */
-  void TransmitStart ();
-  /**
-   * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
-   *
-   * The TransmitCompleteEvent method is used internally to finish the process
-   * of sending a packet out on the channel.  During execution of this method
-   * the TransmitEnd method is called on the channel to let it know that the
-   * physical device this class represents has virually finished sending 
-   * signals.  The channel uses this event to begin its speed of light delay
-   * timer after which it notifies the Net Device at the other end of the 
-   * link that the bits have arrived.  During this method, the net device 
-   * also schedules the TransmitReadyEvent at which time the transmitter 
-   * becomes ready to send the next packet.
-   *
-   * @see CsmaCdChannel::TransmitEnd ()
-   * @see TransmitReadyEvent ()
-   */
-  void TransmitCompleteEvent (void);
-  /**
-   * Cause the Transmitter to Become Ready to Send Another Packet.
-   *
-   * The TransmitReadyEvent method is used internally to re-enable the 
-   * transmit machine of the net device.  It is scheduled after a suitable
-   * interframe gap after the completion of the previous transmission.
-   * The queue is checked at this time, and if there is a packet waiting on
-   * the queue, the transmission process is begun.
-   *
-   * If a packet is in the queue, it is extracted for the queue as the
-   * next packet to be transmitted by the net device.
-   *
-   * @see TransmitStart ()
-   */
-  void TransmitReadyEvent (void);
-  /**
-   * Create a Trace Resolver for events in the net device.
-   * (NOT TESTED)
-   * @see class TraceResolver
-   */
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
-
-  /**
-   * Aborts the transmission of the current packet
-   *
-   * If the net device has tried to transmit a packet for more times
-   * than the maximum allowed number of retries (channel always busy)
-   * then the packet is dropped.
-   *
-   */
-  void TransmitAbort (void);
-
-  /** 
-   * Device ID returned by the attached functions. It is used by the
-   * mp-channel to identify each net device to make sure that only
-   * active net devices are writing to the channel
-   */
-  uint32_t m_deviceId; 
-
-  /**
-   * Enable net device to send packets. True by default
-   */
-  bool m_sendEnable;
-  /**
-   * Enable net device to receive packets. True by default
-   */
-  bool m_receiveEnable;
-  /**
-   * Enumeration of the states of the transmit machine of the net device.
-   */
-  enum TxMachineState
-    {
-      READY, /**< The transmitter is ready to begin transmission of a packet */
-      BUSY,  /**< The transmitter is busy transmitting a packet */
-      GAP,    /**< The transmitter is in the interframe gap time */
-      BACKOFF    /**< The transmitter is waiting for the channel to be free */
-    };
-  /**
-   * The state of the Net Device transmit state machine.
-   * @see TxMachineState
-   */
-  TxMachineState m_txMachineState;
-  
-  /**
-   * The type of packet that should be created by the AddHeader
-   * function and that should be processed by the ProcessHeader
-   * function.
-   */
-  CsmaCdEncapsulationMode m_encapMode;
-  /**
-   * The data rate that the Net Device uses to simulate packet transmission
-   * timing.
-   * @see class DataRate
-   */
-  DataRate m_bps;
-  /**
-   * The interframe gap that the Net Device uses to throttle packet
-   * transmission
-   * @see class Time
-   */
-  Time m_tInterframeGap;
-  /**
-   * Holds the backoff parameters and is used to calculate the next
-   * backoff time to use when the channel is busy and the net device
-   * is ready to transmit
-   */
-  Backoff m_backoff;
-  /**
-   * Next packet that will be transmitted (if transmitter is not
-   * currently transmitting) or packet that is currently being
-   * transmitted.
-   */
-  Packet m_currentPkt;
-  /**
-   * The CsmaCdChannel to which this CsmaCdNetDevice has been
-   * attached.
-   * @see class CsmaCdChannel
-   */
-  Ptr<CsmaCdChannel> m_channel;
-  /**
-   * The Queue which this CsmaCdNetDevice uses as a packet source.
-   * Management of this Queue has been delegated to the CsmaCdNetDevice
-   * and it has the responsibility for deletion.
-   * @see class Queue
-   * @see class DropTailQueue
-   */
-  Ptr<Queue> m_queue;
-  /**
-   * NOT TESTED
-   * The trace source for the packet reception events that the device can
-   * fire.
-   *
-   * @see class CallBackTraceSource
-   * @see class TraceResolver
-   */
-  CallbackTraceSource<Packet &> m_rxTrace;
-  CallbackTraceSource<Packet &> m_dropTrace;
-
-};
-
-}; // namespace ns3
-
-#endif // CSMA_CD_NET_DEVICE_H
-
--- a/src/devices/csma-cd/csma-cd-topology.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2007 Emmanuelle Laprise
-//
-// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
-//
-
-//
-// Topology helper for CsmaCd channels in ns3.
-
-#include "ns3/assert.h"
-#include "ns3/debug.h"
-#include "ns3/queue.h"
-
-#include "csma-cd-channel.h"
-#include "csma-cd-net-device.h"
-#include "csma-cd-topology.h"
-#include "ns3/socket-factory.h"
-
-namespace ns3 {
-
-Ptr<CsmaCdChannel>
-CsmaCdTopology::CreateCsmaCdChannel(
-  const DataRate& bps,
-  const Time& delay)
-{
-  Ptr<CsmaCdChannel> channel = Create<CsmaCdChannel> (bps, delay);
-
-  return channel;
-}
-
-#if 0
-Ptr<CsmaCdNetDevice>
-CsmaCdTopology::AddCsmaCdEthernetNode(
-  Ptr<Node> n1,
-  Ptr<CsmaCdChannel> ch,
-  MacAddress addr)
-{
-  Ptr<CsmaCdNetDevice> nd1 = Create<CsmaCdNetDevice> (n1, addr, 
-                                                      ns3::CsmaCdNetDevice::ETHERNET_V1);
-
-  Ptr<Queue> q = Queue::CreateDefault ();
-  nd1->AddQueue(q);
-  nd1->Attach (ch);
-  
-  return nd1;
-}
-
-Ptr<PacketSocket>
-CsmaCdTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app, 
-                                        Ptr<CsmaCdNetDevice> ndSrc,
-                                        Ptr<CsmaCdNetDevice> ndDest)
-{
-  Ptr<PacketSocket> socket = Create<PacketSocket> ();
-  socket->Bind(ndSrc);
-  socket->Connect(ndDest->GetAddress());
-  app->Connect(socket);
-
-  return socket;
-}
-
-Ptr<PacketSocket>
-CsmaCdTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app,
-                                        Ptr<CsmaCdNetDevice> ndSrc,
-                                        MacAddress macAddr)
-{
-  Ptr<PacketSocket> socket = Create<PacketSocket> ();
-  socket->Bind(ndSrc);
-  socket->Connect(macAddr);
-  app->Connect(socket);
-
-  return socket;
-}
-
-Ptr<Socket>
-CsmaCdTopology::CreatePacketSocket(Ptr<Node> n1, std::string iid_name)
-{
-  InterfaceId iid = InterfaceId::LookupByName (iid_name);
-
-  Ptr<SocketFactory> socketFactory =
-    n1->QueryInterface<SocketFactory> (iid);
-
-  Ptr<Socket> socket = socketFactory->CreateSocket ();
-
-  return socket;
-}
-#endif
-
-} // namespace ns3
- 
--- a/src/devices/csma-cd/csma-cd-topology.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2007 Emmanuelle Laprise
-//
-// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
-//
-// Topology helper for multipoint channels in ns3.
-// 
-#ifndef CSMA_CD_TOPOLOGY_H
-#define CSMA_CD_TOPOLOGY_H
-
-#include "ns3/ptr.h"
-#include "ns3/csma-cd-net-device.h"
-#if 0
-#include "ns3/packet-socket.h"
-#include "ns3/packet-socket-app.h"
-#endif
-#include "ns3/node.h"
-#include "ns3/mac-address.h"
-
-// The topology class consists of only static methods thar are used to
-// create the topology and data flows for an ns3 simulation
-
-namespace ns3 {
-
-class CsmaCdChannel;
-class Node;
-class DataRate;
-class Queue;
-
-/**
- * \brief A helper class to create CsmaCd Topologies 
- *
- * CsmaCd topologies are created based on the
- * ns3::CsmaCdNetDevice subclasses and ns3::CsmaCdChannel
- * objects.  This class uses the EthernetNetDevice and
- * PacketSocket classes in order to create logical connections between
- * net devices. The PacketSocket class generates the data and the
- * EthernetNetDevice class creates ethernet packets from the
- * data, filling in source and destination addresses. The
- * EthernetNetDevice class filters received data packets
- * according to its destination Mac addresses.
- */
-class CsmaCdTopology {
-public:
-  /** 
-   * \param dataRate Maximum transmission link rate 
-   * \param delay propagation delay between any two nodes 
-   * \return Pointer to the created CsmaCdChannel
-   * 
-   * Create a CsmaCdChannel. All nodes connected to a multipoint
-   * channels will receive all packets written to that channel
-   */
-  static Ptr<CsmaCdChannel> CreateCsmaCdChannel(
-    const DataRate& dataRate, const Time& delay);
-
-#if 0
-  /**
-   * \param n1 Node to be attached to the multipoint channel
-   * \param ch CsmaCdChannel to which node n1 should be attached 
-   * \param addr MacAddress that should be assigned to the
-   * EthernetNetDevice that will be added to the node.
-   *
-   * Add a multipoint node to a multipoint channel
-   */
-  static Ptr<CsmaCdNetDevice> AddCsmaCdEthernetNode(Ptr<Node> n1, 
-                                                    Ptr<CsmaCdChannel> ch,
-                                                    MacAddress addr);
-
-  /**
-   * \param app Application that will be sending data to the agent
-   * \param ndSrc Net Device that will be sending the packets onto the
-   * network
-   * \param ndDest Net Device to which ndSrc will be sending the packets
-   * \return A pointer to the PacketSocket
-   *
-   * Creates an PacketSocket and configure it to send packets between
-   * two net devices
-   */
-static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
-                                      Ptr<CsmaCdNetDevice> ndSrc,
-                                      Ptr<CsmaCdNetDevice> ndDest);
-
-  /**
-   * \param app Application that will be sending data to the agent
-   * \param ndSrc Net Device that will be sending the packets onto the
-   * network 
-   * \param macAddr Mac destination address for the packets send by
-   * the ndSrc net device \return a Pointer to the created
-   * PacketSocket
-   *
-   * Creates an PacketSocket and configure it to send packets from a
-   * net device to a destination MacAddress
-   */
-static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
-                                      Ptr<CsmaCdNetDevice> ndSrc,
-                                      MacAddress macAddr);
-
-  /**
-   * \param n1 Node from which socketfactory should be tested.
-   * \param iid_name Interface identifier ("Packet", in this case)
-   *
-   * This is a test function to make sure that a socket can be created
-   * by using the socketfactory interface provided in the
-   * netdevicenode.
-   */
-static  Ptr<Socket> CreatePacketSocket(Ptr<Node> n1, 
-                                       std::string iid_name);
-#endif
-
-};
-} // namespace ns3
-
-#endif
-
--- a/src/devices/csma-cd/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-
-def build(bld):
-    obj = bld.create_obj('cpp', 'shlib')
-    obj.name = 'ns3-csma-cd'
-    obj.target = obj.name
-    obj.uselib_local = ['ns3-node']
-    obj.source = [
-        'backoff.cc',
-        'csma-cd-net-device.cc',
-        'csma-cd-channel.cc',
-        'csma-cd-topology.cc',
-        'csma-cd-ipv4-topology.cc',
-        ]
-    headers = bld.create_obj('ns3header')
-    headers.source = [
-        'backoff.h',
-        'csma-cd-net-device.h',
-        'csma-cd-channel.h',
-        'csma-cd-topology.h',
-        'csma-cd-ipv4-topology.h',
-        ]
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/backoff.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,83 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007, Emmanuelle Laprise
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "backoff.h"
+
+namespace ns3 {
+
+Backoff::Backoff() 
+{
+  m_slotTime = MicroSeconds(1);
+  m_minSlots = 1;
+  m_maxSlots = 1000;
+  m_ceiling = 10;
+  m_maxRetries = 1000;
+
+  ResetBackoffTime();
+}
+
+Backoff::Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots,
+                 uint32_t ceiling, uint32_t maxRetries)
+{
+  m_slotTime = slotTime;
+  m_minSlots = minSlots;
+  m_maxSlots = maxSlots;
+  m_ceiling = ceiling;
+  m_maxRetries = maxRetries;
+}  
+
+Time
+Backoff::GetBackoffTime (void)
+{
+  Time backoff;
+  uint32_t ceiling;
+
+  if ((m_ceiling > 0) &&(m_numBackoffRetries > m_ceiling))
+    ceiling = m_ceiling;
+  else
+    ceiling = m_numBackoffRetries;
+
+  uint32_t minSlot = m_minSlots;
+  uint32_t maxSlot = (uint32_t)pow(2, ceiling) - 1;
+  if (maxSlot > m_maxSlots)
+    maxSlot = m_maxSlots;
+
+  uint32_t backoffSlots = 
+    (uint32_t)UniformVariable::GetSingleValue(minSlot, maxSlot);
+
+  backoff = Scalar(backoffSlots) * m_slotTime;
+  return (backoff);
+}
+
+void Backoff::ResetBackoffTime (void)
+{
+  m_numBackoffRetries = 0;
+}
+
+bool Backoff::MaxRetriesReached(void) {
+  return (m_numBackoffRetries >= m_maxRetries);
+}
+
+void Backoff::IncrNumRetries(void) {
+  m_numBackoffRetries++;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/backoff.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
+ * Derived from the p2p net device file
+Transmi */
+
+#ifndef BACKOFF_H
+#define BACKOFF_H
+
+#include <stdint.h>
+#include "ns3/nstime.h"
+#include "ns3/random-variable.h"
+
+namespace ns3 {
+
+  /**
+   * \brief The backoff class is used for calculating backoff times
+   * when many net devices can write to the same channel
+   *
+   */
+
+class Backoff {
+public:
+  uint32_t m_minSlots; // Minimum number of backoff slots (when
+                       // multiplied by m_slotTime, determines minimum
+                       // backoff time)
+  uint32_t m_maxSlots; // Maximim number of backoff slots (when
+                       // multiplied by m_slotTime, determines
+                       // maximum backoff time)
+  uint32_t m_ceiling;  // Caps the exponential function when the
+                       // number of retries reaches m_ceiling
+  uint32_t m_maxRetries; // Maximum number of transmission retries
+                         // before the packet is dropped.
+  Time     m_slotTime; // Length of one slot. A slot time, it usually
+                       // the packet transmission time, if the packet
+                       // size is fixed.
+
+  Backoff();
+  Backoff(Time slotTime, uint32_t minSlots, uint32_t maxSlots, 
+          uint32_t ceiling, uint32_t maxRetries);
+
+  /**
+   * \return The amount of time that the net device should wait before
+   * trying to retransmit the packet
+   */
+  Time GetBackoffTime();
+  /**
+   * Indicates to the backoff object that the last packet was
+   * successfully transmitted and that the number of retries should be
+   * reset to 0.
+   */
+  void ResetBackoffTime();
+  /**
+   * \return True if the maximum number of retries has been reached
+   */
+  bool MaxRetriesReached();
+  /**
+   * Increments the number of retries by 1.
+   */
+  void IncrNumRetries();
+
+private:
+  uint32_t m_numBackoffRetries; // Number of times that the
+                                // transmitter has tried to
+                                // unsuccessfully transmit the current
+                                // packet
+};
+
+}; // namespace ns3
+
+#endif // BACKOFF_H
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-channel.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,371 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "ns3/packet.h"
+#include "ns3/simulator.h"
+#include "ns3/debug.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("CsmaChannel");
+
+namespace ns3 {
+
+CsmaDeviceRec::CsmaDeviceRec()
+{
+  active = false;
+}
+
+CsmaDeviceRec::CsmaDeviceRec(Ptr<CsmaNetDevice> device)
+{
+  devicePtr = device; 
+  active = true;
+}
+
+bool
+CsmaDeviceRec::IsActive() {
+  return active;
+}
+
+
+//
+// By default, you get a channel with the name "Csma Channel" that 
+// has an "infitely" fast transmission speed and zero delay.
+CsmaChannel::CsmaChannel()
+: 
+  Channel ("Csma Channel"), 
+  m_bps (DataRate(0xffffffff)),
+  m_delay (Seconds(0))
+{
+  NS_DEBUG("CsmaChannel::CsmaChannel ()");
+  Init();
+}
+
+CsmaChannel::CsmaChannel(
+  const DataRate& bps, 
+  const Time& delay)
+: 
+  Channel ("Csma Channel"), 
+  m_bps (bps),
+  m_delay (delay)
+{
+  NS_DEBUG("CsmaChannel::CsmaChannel (" << Channel::GetName() 
+    << ", " << bps.GetBitRate() << ", " << delay << ")");
+  Init();
+}
+
+CsmaChannel::CsmaChannel(
+  const std::string& name,
+  const DataRate& bps, 
+  const Time& delay)
+: 
+  Channel (name),
+  m_bps (bps), 
+  m_delay (delay)
+{
+  NS_DEBUG("CsmaChannel::CsmaChannel (" << name << ", " << 
+           bps.GetBitRate() << ", " << delay << ")");
+  Init();
+}
+
+void CsmaChannel::Init() {
+  m_state = IDLE;
+  m_deviceList.clear();
+}
+
+int32_t
+CsmaChannel::Attach(Ptr<CsmaNetDevice> device)
+{
+  NS_DEBUG("CsmaChannel::Attach (" << device << ")");
+  NS_ASSERT(device != 0);
+
+  CsmaDeviceRec rec(device);
+  
+  m_deviceList.push_back(rec);
+  return (m_deviceList.size() - 1);
+}
+
+bool
+CsmaChannel::Reattach(Ptr<CsmaNetDevice> device)
+{
+  NS_DEBUG("CsmaChannel::Reattach (" << device << ")");
+  NS_ASSERT(device != 0);
+
+  std::vector<CsmaDeviceRec>::iterator it;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if (it->devicePtr == device) 
+        {
+          if (!it->active) 
+            {
+              it->active = true;
+              return true;
+            } 
+          else 
+            {
+              return false;
+            }
+        }
+    }
+  return false;
+}
+
+bool
+CsmaChannel::Reattach(uint32_t deviceId)
+{
+  NS_DEBUG("CsmaChannel::Reattach (" << deviceId << ")");
+  if (deviceId < m_deviceList.size())
+    {
+      return false;
+    }
+
+  if (m_deviceList[deviceId].active)
+    {
+      return false;
+    } 
+  else 
+    {
+      m_deviceList[deviceId].active = true;
+      return true;
+    }
+}
+
+bool
+CsmaChannel::Detach(uint32_t deviceId)
+{
+  NS_DEBUG("CsmaChannel::Detach (" << deviceId << ")");
+
+  if (deviceId < m_deviceList.size())
+    {
+      if (!m_deviceList[deviceId].active)
+        {
+          NS_DEBUG("CsmaChannel::Detach Device is already detached (" 
+                   << deviceId << ")");
+          return false;
+        }
+
+      m_deviceList[deviceId].active = false;
+      if ((m_state == TRANSMITTING) && (m_currentSrc == deviceId))
+        {
+          NS_DEBUG("CsmaChannel::Detach Device is currently"
+                   << "transmitting (" << deviceId << ")");
+          // Here we will need to place a warning in the packet
+        }
+
+      return true;
+    } 
+  else 
+    {
+      return false;
+    }
+}
+
+bool
+CsmaChannel::Detach(Ptr<CsmaNetDevice> device)
+{
+  NS_DEBUG("CsmaChannel::Detach (" << device << ")");
+  NS_ASSERT(device != 0);
+
+  std::vector<CsmaDeviceRec>::iterator it;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if ((it->devicePtr == device) && (it->active)) 
+        {
+          it->active = false;
+          return true;
+        }
+    }
+  return false;
+}
+
+bool
+CsmaChannel::TransmitStart(Packet& p, uint32_t srcId)
+{
+  NS_DEBUG ("CsmaChannel::TransmitStart (" << &p << ", " << srcId 
+            << ")");
+  NS_DEBUG ("CsmaChannel::TransmitStart (): UID is " << 
+            p.GetUid () << ")");
+
+  if (m_state != IDLE)
+    {
+      NS_DEBUG("CsmaChannel::TransmitStart (): state is not IDLE");
+      return false;
+    }
+
+  if (!IsActive(srcId))
+    {
+      NS_DEBUG("CsmaChannel::TransmitStart (): ERROR: Seclected "
+               << "source is not currently attached to network");
+      return false;
+    }
+
+  NS_DEBUG("CsmaChannel::TransmitStart (): switch to TRANSMITTING");
+  m_currentPkt = p;
+  m_currentSrc = srcId;
+  m_state = TRANSMITTING;
+  return true;
+}
+
+bool
+CsmaChannel::IsActive(uint32_t deviceId) 
+{
+    return (m_deviceList[deviceId].active);
+}
+
+bool
+CsmaChannel::TransmitEnd()
+{
+  NS_DEBUG("CsmaChannel::TransmitEnd (" << &m_currentPkt << ", " 
+           << m_currentSrc << ")");
+  NS_DEBUG("CsmaChannel::TransmitEnd (): UID is " << 
+            m_currentPkt.GetUid () << ")");
+
+  NS_ASSERT(m_state == TRANSMITTING);
+  m_state = PROPAGATING;
+
+  bool retVal = true;
+
+  if (!IsActive(m_currentSrc)) {
+    NS_DEBUG("CsmaChannel::TransmitEnd (): ERROR: Seclected source "
+             << "was detached before the end of the transmission");
+    retVal = false;
+  }
+
+  NS_DEBUG ("CsmaChannel::TransmitEnd (): Schedule event in " << 
+            m_delay.GetSeconds () << "sec");
+
+  Simulator::Schedule (m_delay,
+                       &CsmaChannel::PropagationCompleteEvent,
+                       this);
+  return retVal;
+}
+
+void
+CsmaChannel::PropagationCompleteEvent()
+{
+  NS_DEBUG("CsmaChannel::PropagationCompleteEvent (" 
+           << &m_currentPkt << ")");
+  NS_DEBUG ("CsmaChannel::PropagationCompleteEvent (): UID is " << 
+            m_currentPkt.GetUid () << ")");
+
+  NS_ASSERT(m_state == PROPAGATING);
+
+  NS_DEBUG ("CsmaChannel::PropagationCompleteEvent (): Receive");
+  
+  std::vector<CsmaDeviceRec>::iterator it;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if (it->IsActive())
+      {
+        it->devicePtr->Receive (m_currentPkt);
+      }
+    }
+  m_state = IDLE;
+}
+
+
+uint32_t 
+CsmaChannel::GetNumActDevices (void)
+{
+  int numActDevices = 0;
+  std::vector<CsmaDeviceRec>::iterator it;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if (it->active)
+        {
+          numActDevices++;
+        }
+    }
+  return numActDevices;
+}
+
+// This is not the number of active devices. This is the total number
+// of devices even if some were detached after.
+uint32_t 
+CsmaChannel::GetNDevices (void) const
+{
+  return (m_deviceList.size());
+}
+
+Ptr<NetDevice>
+CsmaChannel::GetDevice (uint32_t i) const
+{
+  Ptr< CsmaNetDevice > netDevice;
+
+  netDevice = m_deviceList[i].devicePtr;
+  return netDevice;
+}
+
+int32_t
+CsmaChannel::GetDeviceNum (Ptr<CsmaNetDevice> device)
+{
+  std::vector<CsmaDeviceRec>::iterator it;
+  int i = 0;
+  for (it = m_deviceList.begin(); it < m_deviceList.end(); it++) 
+    {
+      if (it->devicePtr == device)
+        {
+          if (it->active) 
+            {
+              return i;
+            } 
+          else 
+            {
+              return -2;
+            }
+        }
+      i++;
+    }
+  return -1;
+}
+
+bool 
+CsmaChannel::IsBusy (void)
+{
+  if (m_state == IDLE) 
+    {
+      return false;
+    } 
+  else 
+    {
+      return true;
+    }
+}
+
+DataRate
+CsmaChannel::GetDataRate (void)
+{
+  return m_bps;
+}
+
+Time
+CsmaChannel::GetDelay (void)
+{
+  return m_delay;
+}
+
+WireState
+CsmaChannel::GetState(void)
+{
+  return m_state;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-channel.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,307 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * 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: Emmanuelle Laprise<emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#ifndef CSMA_CHANNEL_H
+#define CSMA_CHANNEL_H
+
+#include "ns3/channel.h"
+#include "ns3/ptr.h"
+#include "ns3/packet.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+
+namespace ns3 {
+
+class CsmaNetDevice;
+
+  /**
+   * \brief CsmaNetDevice Record 
+   *
+   * Stores the information related to each net device that is
+   * connected to the channel. 
+   */
+  class CsmaDeviceRec {
+  public:
+    Ptr< CsmaNetDevice > devicePtr; /// Pointer to the net device
+    bool                       active;    /// Is net device enabled to TX/RX
+
+    CsmaDeviceRec();
+    CsmaDeviceRec(Ptr< CsmaNetDevice > device);
+    /*
+     * \return If the net device pointed to by the devicePtr is active
+     * and ready to RX/TX.
+     */
+    bool IsActive();                   
+  };
+
+  /**
+   * Current state of the channel
+   */ 
+  enum WireState
+    {
+      IDLE,          /**< Channel is IDLE, no packet is being
+                        transmitted */
+      TRANSMITTING,  /**< Channel is BUSY, a packet is being written
+                        by a net device */
+      PROPAGATING    /**< Channel is BUSY, packet is propagating to
+                        all attached net devices */
+    };
+
+/**
+ * \brief Csma Channel.
+ *
+ * This class represents a simple Csma channel that can be used
+ * when many nodes are connected to one wire. It uses a single busy
+ * flag to indicate if the channel is currently in use. It does not
+ * take into account the distances between stations or the speed of
+ * light to determine collisions.
+ *
+ * Each net device must query the state of the channel and make sure
+ * that it is IDLE before writing a packet to the channel.
+ *
+ * When the channel is instaniated, the constructor takes parameters
+ * for a single speed, in bits per second, and a speed-of-light delay
+ * time as a Time object.  When a net device is attached to a channel,
+ * it is assigned a device ID, this is in order to facilitate the
+ * check that makes sure that a net device that is trying to send a
+ * packet to the channel is really connected to this channel
+ *
+ */
+class CsmaChannel : public Channel {
+public:
+  /**
+   * \brief Create a CsmaChannel
+   *
+   * By default, you get a channel with the name "Csma Channel" that
+   * has an "infitely" fast transmission speed and zero delay.
+   */
+  CsmaChannel ();
+  
+  /**
+   * \brief Create a CsmaChannel
+   *
+   * \param bps The bitrate of the channel
+   * \param delay Transmission delay through the channel
+   */  
+  CsmaChannel (const DataRate& bps, const Time& delay);
+  
+  /**
+   * \brief Create a CsmaChannel
+   *
+   * \param name the name of the channel for identification purposes
+   * \param bps The bitrate of the channel
+   * \param delay Transmission delay through the channel
+   */
+  CsmaChannel (const std::string& name,
+                     const DataRate& bps, const Time& delay);
+
+  /**
+   * \brief Attach a given netdevice to this channel
+   *
+   * \param device Device pointer to the netdevice to attach to the channel
+   * \return The assigned device number
+   */
+  int32_t Attach (Ptr<CsmaNetDevice> device);
+  /**
+   * \brief Detach a given netdevice from this channel
+   *
+   * The net device is marked as inactive and it is not allowed to
+   * receive or transmit packets
+   *
+   * \param device Device pointer to the netdevice to detach from the channel
+   * \return True if the device is found and attached to the channel,
+   * false if the device is not currently connected to the channel or
+   * can't be found.
+   */
+  bool Detach (Ptr<CsmaNetDevice> device);
+  /**
+   * \brief Detach a given netdevice from this channel
+   *
+   * The net device is marked as inactive and it is not allowed to
+   * receive or transmit packets
+   *
+   * \param deviceId The deviceID assigned to the net device when it
+   * was connected to the channel
+   * \return True if the device is found and attached to the channel,
+   * false if the device is not currently connected to the channel or
+   * can't be found.
+   */
+  bool Detach (uint32_t deviceId);
+  /**
+   * \brief Reattach a previously detached net device to the channel
+   *
+   * The net device is marked as active. It is now allowed to receive
+   * or transmit packets. The net device must have been previously
+   * attached to the channel using the attach function.
+   *
+   * \param deviceId The device ID assigned to the net device when it
+   * was connected to the channel
+   * \return True if the device is found and is not attached to the
+   * channel, false if the device is currently connected to the
+   * channel or can't be found.
+   */
+  bool Reattach(uint32_t deviceId);
+  /**
+   * \brief Reattach a previously detached net device to the channel
+   *
+   * The net device is marked as active. It is now allowed to receive
+   * or transmit packets. The net device must have been previously
+   * attached to the channel using the attach function.
+   *
+   * \param device Device pointer to the netdevice to detach from the channel
+   * \return True if the device is found and is not attached to the
+   * channel, false if the device is currently connected to the
+   * channel or can't be found.
+   */
+  bool Reattach(Ptr<CsmaNetDevice> device);
+  /**
+   * \brief Start transmitting a packet over the channel
+   *
+   * If the srcId belongs to a net device that is connected to the
+   * channel, packet transmission begins, and the channel becomes busy
+   * until the packet has completely reached all destinations.
+   *
+   * \param p A reference to the packet that will be transmitted over
+   * the channel
+   * \param srcId The device Id of the net device that wants to
+   * transmit on the channel.
+   * \return True if the channel is not busy and the transmitting net
+   * device is currently active.
+   */
+  bool TransmitStart (Packet& p, uint32_t srcId);
+  /**
+   * \brief Indicates that the net device has finished transmitting
+   * the packet over the channel
+   *
+   * The channel will stay busy until the packet has completely
+   * propagated to all net devices attached to the channel. The
+   * TransmitEnd function schedules the PropagationCompleteEvent which
+   * will free the channel for further transmissions. Stores the
+   * packet p as the m_currentPkt, the packet being currently
+   * transmitting.
+   *
+   * \return Returns true unless the source was detached before it
+   * completed its transmission.
+   */
+  bool TransmitEnd ();
+  /**
+   * \brief Indicates that the channel has finished propagating the
+   * current packet. The channel is released and becomes free.
+   *
+   * Calls the receive function of every active net device that is
+   * attached to the channel.
+   */
+  void PropagationCompleteEvent();
+  /**
+   * \return Returns the device number assigned to a net device by the
+   * channel
+   *
+   * \param device Device pointer to the netdevice for which the device
+   * number is needed
+   */
+  int32_t GetDeviceNum (Ptr<CsmaNetDevice> device);
+  /**
+   * \return Returns the state of the channel (IDLE -- free,
+   * TRANSMITTING -- busy, PROPAGATING - busy )
+   */
+  WireState GetState();
+
+  /**
+   * \brief Indicates if the channel is busy. The channel will only
+   * accept new packets for transmission if it is not busy.
+   *
+   * \return Returns true if the channel is busy and false if it is
+   * free.
+   */
+  bool IsBusy();
+  
+  /**
+   * \brief Indicates if a net device is currently attached or
+   * detached from the channel.
+   *
+   * \param deviceId The ID that was assigned to the net device when
+   * it was attached to the channel.
+   * \return Returns true if the net device is attached to the
+   * channel, false otherwise.
+   */
+  bool IsActive(uint32_t deviceId);
+  /**
+   * \return Returns the number of net devices that are currently
+   * attached to the channel.
+   */
+  uint32_t GetNumActDevices (void);
+  /**
+   * \return Returns the total number of devices including devices
+   * that have been detached from the channel.
+   */
+  virtual uint32_t GetNDevices (void) const;
+  /**
+   * \param i The deviceId of the net device for which we want the
+   * pointer.
+   * \return Returns the pointer to the net device that is associated
+   * with deviceId i.
+   */
+  virtual Ptr<NetDevice> GetDevice (uint32_t i) const;
+
+  virtual DataRate GetDataRate (void);
+  virtual Time GetDelay (void);
+
+private:
+  DataRate      m_bps;    /// Data rate of the channel
+  Time          m_delay;  /// Delay of the channel.
+
+  /**
+   * List of the net devices that have been or are currently connected
+   * to the channel.
+   *
+   * Devices are nor removed from this list, they are marked as
+   * inactive. Otherwise the assigned device IDs will not refer to the
+   * correct NetDevice. The DeviceIds are used so that it is possible
+   * to have a number to refer to an entry in the list so that the
+   * whole list does not have to be searched when making sure that a
+   * source is attached to a channel when it is transmitting data.
+   */
+  std::vector< CsmaDeviceRec >            m_deviceList;
+  /**
+   * Packet that is currently being transmitted on the channel (or last
+   * packet to have been transmitted on the channel if the channel is
+   * free.)
+   */
+  Packet                              m_currentPkt;
+  /**
+   * Device Id of the source that is currently transmitting on the
+   * channel. Or last source to have transmitted a packet on the
+   * channel, if the channel is currently not busy.
+   */
+  uint32_t                            m_currentSrc;
+  /**
+   * Current state of the channel
+   */
+  WireState          m_state;
+  /**
+   * Initializes the channel when it is constructed. Resets the
+   * deviceList and sets the channel state to IDLE.
+   */
+  void Init (void);
+};
+
+} // namespace ns3
+
+#endif /* CSMA_CHANNEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-ipv4-topology.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,155 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+#include <algorithm>
+#include "ns3/assert.h"
+#include "ns3/debug.h"
+#include "ns3/fatal-error.h"
+#include "ns3/nstime.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/queue.h"
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "csma-ipv4-topology.h"
+
+namespace ns3 {
+
+uint32_t
+CsmaIpv4Topology::AddIpv4CsmaNode(Ptr<Node> n1,
+                                      Ptr<CsmaChannel> ch,
+                                      Eui48Address addr)
+{
+  Ptr<Queue> q = Queue::CreateDefault ();
+
+  // assume full-duplex
+  Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr, 
+                                                      ns3::CsmaNetDevice::IP_ARP,
+                                                      true, true);
+  nd0->AddQueue(q);
+  nd0->Attach (ch);
+  return nd0->GetIfIndex ();
+}
+
+
+void
+CsmaIpv4Topology::AddIpv4LlcCsmaNode(Ptr<Node> n1,
+                                         Ptr<CsmaChannel> ch,
+                                         Eui48Address addr)
+{
+  Ptr<Queue> q = Queue::CreateDefault ();
+
+  Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
+                                                      ns3::CsmaNetDevice::LLC,
+                                                      true, false);
+  nd0->AddQueue(q);
+  nd0->Attach (ch);
+
+  Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+                                                      ns3::CsmaNetDevice::LLC,
+                                                      false, true);
+  nd1->AddQueue(q);
+  nd1->Attach (ch);
+}
+
+void
+CsmaIpv4Topology::AddIpv4RawCsmaNode(Ptr<Node> n1,
+                                         Ptr<CsmaChannel> ch,
+                                         Eui48Address addr)
+{
+  Ptr<Queue> q = Queue::CreateDefault ();
+
+  Ptr<CsmaNetDevice> nd0 = Create<CsmaNetDevice> (n1, addr,
+                                                      ns3::CsmaNetDevice::RAW,
+                                                      true, false);
+  nd0->AddQueue(q);
+  nd0->Attach (ch);
+
+  Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr,
+                                                      ns3::CsmaNetDevice::RAW,
+                                                      false, true);
+  nd1->AddQueue(q);
+  nd1->Attach (ch);
+}
+
+void
+CsmaIpv4Topology::AddIpv4Address(Ptr<Node> n1,
+                                       int ndNum,
+                                       const Ipv4Address& addr1,
+                                       const Ipv4Mask& netmask1)
+{
+
+  // Duplex link is assumed to be subnetted as a /30
+  // May run this unnumbered in the future?
+  Ipv4Mask netmask(netmask1);
+
+  Ptr<NetDevice> nd1 = n1->GetDevice(ndNum);
+
+  Ptr<Ipv4> ip1 = n1->QueryInterface<Ipv4> (Ipv4::iid);
+  uint32_t index1 = ip1->AddInterface (nd1);
+
+  ip1->SetAddress (index1, addr1);
+  ip1->SetNetworkMask (index1, netmask);
+  ip1->SetUp (index1);
+
+}
+
+void
+CsmaIpv4Topology::AddIpv4Routes (
+  Ptr<NetDevice> nd1, Ptr<NetDevice> nd2)
+{ 
+  // Assert that both are Ipv4 nodes
+  Ptr<Ipv4> ip1 = nd1->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+  Ptr<Ipv4> ip2 = nd2->GetNode ()->QueryInterface<Ipv4> (Ipv4::iid);
+  NS_ASSERT(ip1 != 0 && ip2 != 0);
+
+  // Get interface indexes for both nodes corresponding to the right channel
+  uint32_t index1 = 0;
+  bool found = false;
+  for (uint32_t i = 0; i < ip1->GetNInterfaces (); i++)
+    {
+      if (ip1 ->GetNetDevice (i) == nd1)
+        {
+          index1 = i;
+          found = true;
+        }
+    }
+  NS_ASSERT(found);
+
+  uint32_t index2 = 0;
+  found = false;
+  for (uint32_t i = 0; i < ip2->GetNInterfaces (); i++)
+    {
+      if (ip2 ->GetNetDevice (i) == nd2)
+        {
+          index2 = i;
+          found = true;
+        }
+    }
+  NS_ASSERT(found);
+
+  ip1->AddHostRouteTo (ip2-> GetAddress (index2), index1);
+  ip2->AddHostRouteTo (ip1-> GetAddress (index1), index2); 
+}
+
+} // namespace ns3
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-ipv4-topology.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,122 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+#ifndef __CSMA_IPV4_TOPOLOGY_H__
+#define __CSMA_IPV4_TOPOLOGY_H__
+
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/ipv4.h"
+#include "ns3/ipv4-route.h"
+#include "ns3/internet-node.h"
+#include "ns3/csma-net-device.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class CsmaIpv4Channel;
+class Node;
+class IPAddr;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Topologies based on the
+ * InternetNodes and CsmaChannels. Either the
+ * SimpleCsmaNetDevice or the LLCCsmaNetDevice can be used
+ * when constructing these topologies.
+ */
+class CsmaIpv4Topology {
+public:
+
+  /**
+   * \param n1 Node to be attached to the Csma channel
+   * \param ch CsmaChannel to which node n1 should be attached
+   * \param addr Mac address of the node
+   *
+   * Add a Csma node to a Csma channel. This function adds
+   * a EthernetCsmaNetDevice to the nodes so that they can
+   * connect to a CsmaChannel. This means that Ethernet headers
+   * and trailers will be added to the packet before sending out on
+   * the net device.
+   * 
+   * \return ifIndex of the device
+   */
+  static uint32_t AddIpv4CsmaNode( Ptr<Node> n1,
+                                     Ptr<CsmaChannel> ch,
+                                     Eui48Address addr);
+
+  /**
+   * \param n1 Node to be attached to the Csma channel
+   * \param ch CsmaChannel to which node n1 should be attached
+   * \param addr Mac address of the node
+   *
+   * Add a Csma node to a Csma channel. This function adds
+   * a RawCsmaNetDevice to the nodes so that they can connect
+   * to a CsmaChannel.
+   */
+  static void AddIpv4RawCsmaNode( Ptr<Node> n1,
+                                    Ptr<CsmaChannel> ch,
+                                    Eui48Address addr);
+
+  /**
+   * \param n1 Node to be attached to the Csma channel
+   * \param ch CsmaChannel to which node n1 should be attached
+   * \param addr Mac address of the node
+   *
+   * Add a Csma node to a Csma channel. This function adds
+   * a LlcCsmaNetDevice to the nodes so that they can connect
+   * to a CsmaChannel.
+   */
+  static void AddIpv4LlcCsmaNode( Ptr<Node> n1,
+                                    Ptr<CsmaChannel> ch,
+                                    Eui48Address addr);
+
+
+
+  /** 
+   * \param n1 Node
+   * \param ndNum NetDevice number with which to associate address
+   * \param addr1 Ipv4 Address for ndNum of n1
+   * \param netmask1 network mask for ndNum of node n1
+   * 
+   * Add an Ipv4Address to the Ipv4 interface associated with the
+   * ndNum CsmaIpv4NetDevices on the provided
+   * CsmaIpv4Channel
+   */
+  static void AddIpv4Address(Ptr<Node> n1, int ndNum, 
+                             const Ipv4Address& addr1,
+                             const Ipv4Mask& netmask1);
+
+  /**
+   * \param nd1 Node
+   * \param nd2 Node
+   * 
+   * Add an IPV4 host route between the two specified net devices
+   */
+  static void AddIpv4Routes (Ptr<NetDevice> nd1, Ptr<NetDevice> nd2);
+};
+
+} // namespace ns3
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-net-device.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,574 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+
+#include <iostream>
+#include <cassert>
+#include "ns3/debug.h"
+#include "ns3/queue.h"
+#include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
+#include "csma-net-device.h"
+#include "csma-channel.h"
+#include "ns3/ethernet-header.h"
+#include "ns3/ethernet-trailer.h"
+#include "ns3/llc-snap-header.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("CsmaNetDevice");
+
+namespace ns3 {
+
+CsmaTraceType::CsmaTraceType (enum Type type)
+  : m_type (type)
+{}
+CsmaTraceType::CsmaTraceType ()
+  : m_type (RX)
+{}
+void 
+CsmaTraceType::Print (std::ostream &os) const
+{
+  switch (m_type) {
+  case RX:
+    os << "dev-rx";
+    break;
+  case DROP:
+    os << "dev-drop";
+    break;
+  }
+}
+uint16_t 
+CsmaTraceType::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<CsmaTraceType> ("CsmaTraceType");
+  return uid;
+}
+
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node)
+  : NetDevice (node, Eui48Address::Allocate ()),
+    m_bps (DataRate (0xffffffff))
+{
+  NS_DEBUG ("CsmaNetDevice::CsmaNetDevice (" << node << ")");
+  m_encapMode = IP_ARP;
+  Init(true, true);
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Eui48Address addr, 
+                                  CsmaEncapsulationMode encapMode) 
+  : NetDevice(node, addr), 
+    m_bps (DataRate (0xffffffff))
+{
+  NS_DEBUG ("CsmaNetDevice::CsmaNetDevice (" << node << ")");
+  m_encapMode = encapMode;
+
+  Init(true, true);
+}
+
+CsmaNetDevice::CsmaNetDevice (Ptr<Node> node, Eui48Address addr, 
+                                  CsmaEncapsulationMode encapMode,
+                                  bool sendEnable, bool receiveEnable) 
+  : NetDevice(node, addr), 
+    m_bps (DataRate (0xffffffff))
+{
+  NS_DEBUG ("CsmaNetDevice::CsmaNetDevice (" << node << ")");
+  m_encapMode = encapMode;
+
+  Init(sendEnable, receiveEnable);
+}
+
+CsmaNetDevice::~CsmaNetDevice()
+{
+  NS_DEBUG ("CsmaNetDevice::~CsmaNetDevice ()");
+  m_queue = 0;
+}
+
+void 
+CsmaNetDevice::DoDispose ()
+{
+  m_channel = 0;
+  NetDevice::DoDispose ();
+}
+
+//
+// Assignment operator for CsmaNetDevice.
+//
+// This uses the non-obvious trick of taking the source net device passed by
+// value instead of by reference.  This causes the copy constructor to be
+// invoked (where the real work is done -- see above).  All we have to do
+// here is to return the newly constructed net device.
+//
+/*
+CsmaNetDevice&
+CsmaNetDevice::operator= (const CsmaNetDevice nd)
+{
+  NS_DEBUG ("CsmaNetDevice::operator= (" << &nd << ")");
+  return *this;
+}
+*/
+
+void 
+CsmaNetDevice::Init(bool sendEnable, bool receiveEnable)
+{
+  m_txMachineState = READY;
+  m_tInterframeGap = Seconds(0);
+  m_channel = 0; 
+  m_queue = 0;
+
+  EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff"));
+  EnableMulticast();
+
+  SetSendEnable (sendEnable);
+  SetReceiveEnable (receiveEnable);
+}
+
+void
+CsmaNetDevice::SetSendEnable (bool sendEnable)
+{
+  m_sendEnable = sendEnable;
+}
+
+void
+CsmaNetDevice::SetReceiveEnable (bool receiveEnable)
+{
+  m_receiveEnable = receiveEnable;
+}
+bool
+CsmaNetDevice::IsSendEnabled (void)
+{
+  return (m_sendEnable);
+}
+
+bool
+CsmaNetDevice::IsReceiveEnabled (void)
+{
+  return (m_receiveEnable);
+}
+
+void 
+CsmaNetDevice::SetDataRate (DataRate bps)
+{
+  m_bps = bps;
+}
+
+void 
+CsmaNetDevice::SetInterframeGap (Time t)
+{
+  m_tInterframeGap = t;
+}
+
+void 
+CsmaNetDevice::SetBackoffParams (Time slotTime, uint32_t minSlots, 
+                                      uint32_t maxSlots, uint32_t ceiling, 
+                                      uint32_t maxRetries)
+{
+  m_backoff.m_slotTime = slotTime;
+  m_backoff.m_minSlots = minSlots;
+  m_backoff.m_maxSlots = maxSlots;
+  m_backoff.m_ceiling = ceiling;
+  m_backoff.m_maxRetries = maxRetries;
+}
+void 
+CsmaNetDevice::AddHeader (Packet& p, Eui48Address dest,
+                            uint16_t protocolNumber)
+{
+  if (m_encapMode == RAW)
+    {
+      return;
+    }
+  EthernetHeader header (false);
+  EthernetTrailer trailer;
+  Eui48Address source = Eui48Address::ConvertFrom (GetAddress ());
+  header.SetSource(source);
+  header.SetDestination(dest);
+
+  uint16_t lengthType = 0;
+  switch (m_encapMode) 
+    {
+    case ETHERNET_V1:
+      lengthType = p.GetSize() + header.GetSerializedSize() + trailer.GetSerializedSize();
+      break;
+    case IP_ARP:
+      lengthType = protocolNumber;
+      break;
+    case LLC: {
+      LlcSnapHeader llc;
+      llc.SetType (protocolNumber);
+      p.AddHeader (llc);
+    } break;
+    case RAW:
+      NS_ASSERT (false);
+      break;
+    }
+  header.SetLengthType (lengthType);
+  p.AddHeader(header);
+  trailer.CalcFcs(p);
+  p.AddTrailer(trailer);
+}
+bool 
+CsmaNetDevice::ProcessHeader (Packet& p, uint16_t & param)
+{
+  if (m_encapMode == RAW)
+    {
+      return true;
+    }
+  EthernetHeader header (false);
+  EthernetTrailer trailer;
+      
+  p.RemoveTrailer(trailer);
+  trailer.CheckFcs(p);
+  p.RemoveHeader(header);
+
+  if ((header.GetDestination() != GetBroadcast ()) &&
+      (header.GetDestination() != GetAddress ()))
+    {
+      return false;
+    }
+
+  switch (m_encapMode)
+    {
+    case ETHERNET_V1:
+    case IP_ARP:
+      param = header.GetLengthType();
+      break;
+    case LLC: {
+      LlcSnapHeader llc;
+      p.RemoveHeader (llc);
+      param = llc.GetType ();
+    } break;
+    case RAW:
+      NS_ASSERT (false);
+      break;
+    }
+  return true;
+}
+
+bool
+CsmaNetDevice::DoNeedsArp (void) const
+{
+  if ((m_encapMode == IP_ARP) || (m_encapMode == LLC))
+    {
+      return true;
+    } 
+  else 
+    {
+      return false;
+    }
+}
+
+bool
+CsmaNetDevice::SendTo (
+  const Packet& packet, 
+  const Address& dest, 
+  uint16_t protocolNumber)
+{
+  Packet p = packet;
+  NS_DEBUG ("CsmaNetDevice::SendTo (" << &p << ")");
+  NS_DEBUG ("CsmaNetDevice::SendTo (): UID is " << p.GetUid () << ")");
+
+  NS_ASSERT (IsLinkUp ());
+
+  // Only transmit if send side of net device is enabled
+  if (!IsSendEnabled())
+    return false;
+
+  Eui48Address destination = Eui48Address::ConvertFrom (dest);
+  AddHeader(p, destination, protocolNumber);
+
+  // Place the packet to be sent on the send queue
+  if (m_queue->Enqueue(p) == false )
+    {
+      return false;
+    }
+  // If the device is idle, we need to start a transmission. Otherwise,
+  // the transmission will be started when the current packet finished
+  // transmission (see TransmitCompleteEvent)
+  if (m_txMachineState == READY) 
+    {
+      // Store the next packet to be transmitted
+      if (m_queue->Dequeue (m_currentPkt))
+        {
+          TransmitStart();
+        }
+    }
+  return true;
+}
+
+void
+CsmaNetDevice::TransmitStart ()
+{
+  NS_DEBUG ("CsmaNetDevice::TransmitStart (" << &m_currentPkt << ")");
+  NS_DEBUG ("CsmaNetDevice::TransmitStart (): UID is " 
+            << m_currentPkt.GetUid () << ")");
+//
+// This function is called to start the process of transmitting a packet.
+// We need to tell the channel that we've started wiggling the wire and
+// schedule an event that will be executed when it's time to tell the 
+// channel that we're done wiggling the wire.
+//
+  NS_ASSERT_MSG((m_txMachineState == READY) || (m_txMachineState == BACKOFF), 
+                "Must be READY to transmit. Tx state is: " 
+                << m_txMachineState);
+
+  // Only transmit if send side of net device is enabled
+  if (!IsSendEnabled())
+    return;
+
+  if (m_channel->GetState() != IDLE)
+    { // Channel busy, backoff and rechedule TransmitStart()
+      m_txMachineState = BACKOFF;
+      if (m_backoff.MaxRetriesReached())
+        { // Too many retries reached, abort transmission of packet
+          TransmitAbort();
+        } 
+      else 
+        {
+          m_backoff.IncrNumRetries();
+          Time backoffTime = m_backoff.GetBackoffTime();
+
+          NS_DEBUG ("CsmaNetDevice::TransmitStart (): " 
+                    << "Channel busy, backing off for " 
+                    << backoffTime.GetSeconds () << "sec");
+
+          Simulator::Schedule (backoffTime, 
+                               &CsmaNetDevice::TransmitStart, 
+                               this);
+        }
+    } 
+  else 
+    {
+      // Channel is free, transmit packet
+      m_txMachineState = BUSY;
+      Time tEvent = Seconds (m_bps.CalculateTxTime(m_currentPkt.GetSize()));
+      
+      NS_DEBUG ("CsmaNetDevice::TransmitStart (): " <<
+                "Schedule TransmitCompleteEvent in " << 
+                tEvent.GetSeconds () << "sec");
+      
+      Simulator::Schedule (tEvent, 
+                           &CsmaNetDevice::TransmitCompleteEvent, 
+                           this);
+      if (!m_channel->TransmitStart (m_currentPkt, m_deviceId))
+        {
+          NS_DEBUG ("CsmaNetDevice::TransmitStart (): " <<
+                    "Channel transmit start did not work at " << 
+                    tEvent.GetSeconds () << "sec");
+          m_txMachineState = READY;
+        } 
+      else 
+        {
+          // Transmission success, reset backoff time parameters.
+          m_backoff.ResetBackoffTime();
+        }
+    }
+}
+
+
+void
+CsmaNetDevice::TransmitAbort (void)
+{
+  NS_DEBUG ("CsmaNetDevice::TransmitAbort ()");
+
+  NS_DEBUG ("CsmaNetDevice::TransmitAbort (): Pkt UID is " <<
+            m_currentPkt.GetUid () << ")");
+
+  // Try to transmit a new packet
+  bool found;
+  found = m_queue->Dequeue (m_currentPkt);
+  NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
+  m_backoff.ResetBackoffTime();
+  m_txMachineState = READY;
+  TransmitStart ();
+}
+
+void
+CsmaNetDevice::TransmitCompleteEvent (void)
+{
+  NS_DEBUG ("CsmaNetDevice::TransmitCompleteEvent ()");
+//
+// This function is called to finish the  process of transmitting a packet.
+// We need to tell the channel that we've stopped wiggling the wire and
+// schedule an event that will be executed when it's time to re-enable
+// the transmitter after the interframe gap.
+//
+  NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting");
+  // Channel should be transmitting
+  NS_ASSERT(m_channel->GetState() == TRANSMITTING);
+  m_txMachineState = GAP;
+
+  NS_DEBUG ("CsmaNetDevice::TransmitCompleteEvent (): Pkt UID is " << 
+            m_currentPkt.GetUid () << ")");
+  m_channel->TransmitEnd (); 
+
+  NS_DEBUG (
+    "CsmaNetDevice::TransmitCompleteEvent (): " <<
+    "Schedule TransmitReadyEvent in "
+    << m_tInterframeGap.GetSeconds () << "sec");
+
+  Simulator::Schedule (m_tInterframeGap, 
+                       &CsmaNetDevice::TransmitReadyEvent, 
+                       this);
+}
+
+void
+CsmaNetDevice::TransmitReadyEvent (void)
+{
+  NS_DEBUG ("CsmaNetDevice::TransmitReadyEvent ()");
+//
+// This function is called to enable the transmitter after the interframe
+// gap has passed.  If there are pending transmissions, we use this opportunity
+// to start the next transmit.
+//
+  NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap");
+  m_txMachineState = READY;
+
+  // Get the next packet from the queue for transmitting
+  if (m_queue->IsEmpty())
+    {
+      return;
+    }
+  else
+    {
+      bool found;
+      found = m_queue->Dequeue (m_currentPkt);
+      NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?");
+      TransmitStart ();
+    }
+}
+
+TraceResolver *
+CsmaNetDevice::DoCreateTraceResolver (TraceContext const &context)
+{
+  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
+  resolver->Add ("queue", 
+                 MakeCallback (&Queue::CreateTraceResolver, 
+                               PeekPointer (m_queue)));
+  resolver->Add ("rx",
+                 m_rxTrace,
+                 CsmaTraceType (CsmaTraceType::RX));
+  resolver->Add ("drop",
+                 m_dropTrace,
+                 CsmaTraceType (CsmaTraceType::DROP));
+   return resolver;
+}
+
+bool
+CsmaNetDevice::Attach (Ptr<CsmaChannel> ch)
+{
+  NS_DEBUG ("CsmaNetDevice::Attach (" << &ch << ")");
+
+  m_channel = ch;
+
+  m_deviceId = m_channel->Attach(this);
+  m_bps = m_channel->GetDataRate ();
+  m_tInterframeGap = m_channel->GetDelay ();
+
+  /* 
+   * For now, this device is up whenever a channel is attached to it.
+   */
+  NotifyLinkUp ();
+  return true;
+}
+
+void
+CsmaNetDevice::AddQueue (Ptr<Queue> q)
+{
+  NS_DEBUG ("CsmaNetDevice::AddQueue (" << q << ")");
+
+  m_queue = q;
+}
+
+void
+CsmaNetDevice::Receive (const Packet& packet)
+{
+  EthernetHeader header (false);
+  EthernetTrailer trailer;
+  Eui48Address broadcast;
+  Eui48Address destination;
+  Packet p = packet;
+
+  NS_DEBUG ("CsmaNetDevice::Receive UID is (" << p.GetUid() << ")");
+
+  // Only receive if send side of net device is enabled
+  if (!IsReceiveEnabled())
+    {
+      m_dropTrace (p);
+      return;
+    }
+
+  if (m_encapMode == RAW)
+    {
+      ForwardUp (packet, 0, GetBroadcast ());
+      m_dropTrace (p);
+      return;
+    }
+  p.RemoveTrailer(trailer);
+  trailer.CheckFcs(p);
+  p.RemoveHeader(header);
+
+  broadcast = Eui48Address::ConvertFrom (GetBroadcast ());
+  destination = Eui48Address::ConvertFrom (GetAddress ());
+  if ((header.GetDestination() != broadcast) &&
+      (header.GetDestination() != destination))
+    {
+      // not for us.
+      m_dropTrace (p);
+      return;
+    }
+
+  m_rxTrace (p);
+//
+// protocol must be initialized to avoid a compiler warning in the RAW
+// case that breaks the optimized build.
+//
+  uint16_t protocol = 0;
+
+  switch (m_encapMode)
+    {
+    case ETHERNET_V1:
+    case IP_ARP:
+      protocol = header.GetLengthType();
+      break;
+    case LLC: {
+      LlcSnapHeader llc;
+      p.RemoveHeader (llc);
+      protocol = llc.GetType ();
+    } break;
+    case RAW:
+      NS_ASSERT (false);
+      break;
+    }
+  
+  ForwardUp (p, protocol, header.GetSource ());
+  return;
+}
+
+Ptr<Queue>
+CsmaNetDevice::GetQueue(void) const 
+{ 
+    return m_queue;
+}
+
+Ptr<Channel>
+CsmaNetDevice::DoGetChannel(void) const 
+{ 
+    return m_channel;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-net-device.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,432 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ *
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca
+ * Derived from the p2p net device file
+ */
+
+#ifndef CSMA_NET_DEVICE_H
+#define CSMA_NET_DEVICE_H
+
+#include <string.h>
+#include "ns3/node.h"
+#include "ns3/backoff.h"
+#include "ns3/address.h"
+#include "ns3/net-device.h"
+#include "ns3/callback.h"
+#include "ns3/packet.h"
+#include "ns3/callback-trace-source.h"
+#include "ns3/nstime.h"
+#include "ns3/data-rate.h"
+#include "ns3/ptr.h"
+#include "ns3/random-variable.h"
+#include "ns3/eui48-address.h"
+
+namespace ns3 {
+
+class Queue;
+class CsmaChannel;
+
+class CsmaTraceType : public TraceContextElement
+{
+public:
+  enum Type {
+    RX, 
+    DROP
+  };
+  CsmaTraceType (enum Type type);
+  CsmaTraceType ();
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+private:
+  enum Type m_type;
+};
+
+/**
+ * \class CsmaNetDevice
+ * \brief A Device for a Csma Network Link.
+ *
+ * The Csma net device class is analogous to layer 1 and 2 of the
+ * TCP stack. The NetDevice takes a raw packet of bytes and creates a
+ * protocol specific packet from them. The Csma net device class
+ * takes this packet and adds and processes the headers/trailers that
+ * are associated with EthernetV1, EthernetV2, RAW or LLC
+ * protocols. The EthernetV1 packet type adds and removes Ethernet
+ * destination and source addresses. The LLC packet type adds and
+ * removes LLC snap headers. The raw packet type does not add or
+ * remove any headers.  Each Csma net device will receive all
+ * packets written to the Csma link. The ProcessHeader function can
+ * be used to filter out the packets such that higher level layers
+ * only receive packets that are addressed to their associated net
+ * devices
+ *
+ */
+class CsmaNetDevice : public NetDevice {
+public:
+
+  /**
+   * Enumeration of the types of packets supported in the class.
+   *
+   */
+enum CsmaEncapsulationMode {
+  ETHERNET_V1, /**< Version one ethernet packet, length field */
+  IP_ARP,      /**< Ethernet packet encapsulates IP/ARP packet */
+  RAW,         /**< Packet that contains no headers */
+  LLC,         /**< LLC packet encapsulation */  
+};
+
+  CsmaNetDevice (Ptr<Node> node);
+  /**
+   * Construct a CsmaNetDevice
+   *
+   * This is the constructor for the CsmaNetDevice.  It takes as a
+   * parameter the Node to which this device is connected.  Ownership of the
+   * Node pointer is not implied and the node must not be deleted.
+   *
+   * \param node the Node to which this device is connected.
+   * \param addr The source MAC address of the net device.
+   * \param pktType the type of encapsulation
+   */
+  CsmaNetDevice (Ptr<Node> node, Eui48Address addr, CsmaEncapsulationMode pktType);
+
+  /**
+   * Construct a CsmaNetDevice
+   *
+   * This is the constructor for the CsmaNetDevice.  It takes as a
+   * parameter the Node to which this device is connected.  Ownership of the
+   * Node pointer is not implied and the node must not be deleted.
+   *
+   * \param node the Node to which this device is connected.
+   * \param addr The source MAC address of the net device.
+   * \param pktType the type of encapsulation
+   * \param sendEnable whether this device is able to send
+   * \param receiveEnable whether this device is able to receive
+   */
+  CsmaNetDevice (Ptr<Node> node, Eui48Address addr,
+                   CsmaEncapsulationMode pktType,
+                   bool sendEnable, bool receiveEnable);
+  /**
+   * Destroy a CsmaNetDevice
+   *
+   * This is the destructor for the CsmaNetDevice.
+   */
+  virtual ~CsmaNetDevice();
+  /**
+   * Set the Data Rate used for transmission of packets.  The data rate is
+   * set in the Attach () method from the corresponding field in the channel
+   * to which the device is attached.  It can be overridden using this method.
+   *
+   * @see Attach ()
+   * \param bps the data rate at which this object operates
+   */
+  void SetDataRate (DataRate bps);
+  /**
+   * Set the inteframe gap used to separate packets.  The interframe gap
+   * defines the minimum space required between packets sent by this device.
+   * It is usually set in the Attach () method based on the speed of light
+   * delay of the channel to which the device is attached.  It can be 
+   * overridden using this method if desired.
+   *
+   * @see Attach ()
+   * \param t the interframe gap time
+   */
+  void SetInterframeGap (Time t);
+  /**
+   * Set the backoff parameters used to determine the wait to retry
+   * transmitting a packet when the channel is busy.
+   *
+   * @see Attach ()
+   * \param slotTime Length of a packet slot (or average packet time)
+   * \param minSlots Minimum number of slots to wait
+   * \param maxSlots Maximum number of slots to wait
+   * \param maxRetries Maximum number of retries before packet is discard
+   * \param ceiling Cap on the exponential function when calculating max slots
+   */
+  void SetBackoffParams (Time slotTime, uint32_t minSlots, uint32_t maxSlots, 
+                        uint32_t maxRetries, uint32_t ceiling);
+  /**
+   * Attach the device to a channel.
+   *
+   * The function Attach is used to add a CsmaNetDevice to a
+   * CsmaChannel.
+   *
+   * @see SetDataRate ()
+   * @see SetInterframeGap ()
+   * \param ch a pointer to the channel to which this object is being attached.
+   */
+  bool Attach (Ptr<CsmaChannel> ch);
+  /**
+   * Attach a queue to the CsmaNetDevice.
+   *
+   * The CsmaNetDevice "owns" a queue.  This queue is created by the
+   * CsmaTopology object and implements a queueing method such as
+   * DropTail or RED.  The CsmaNetDevice assumes ownership of this
+   * queue and must delete it when the device is destroyed.
+   *
+   * @see CsmaTopology::AddCsmaLink ()
+   * @see Queue
+   * @see DropTailQueue
+   * \param queue a pointer to the queue for which object is assuming
+   *        ownership.
+   */
+  void AddQueue (Ptr<Queue> queue);
+  /**
+   * Receive a packet from a connected CsmaChannel.
+   *
+   * The CsmaNetDevice receives packets from its connected channel
+   * and forwards them up the protocol stack.  This is the public method
+   * used by the channel to indicate that the last bit of a packet has 
+   * arrived at the device.
+   *
+   * @see CsmaChannel
+   * \param p a reference to the received packet
+   */
+  void Receive (const Packet& p);
+
+  bool IsSendEnabled (void);
+  bool IsReceiveEnabled (void);
+
+  void SetSendEnable (bool);
+  void SetReceiveEnable (bool);
+
+protected:
+  virtual bool DoNeedsArp (void) const;
+  virtual void DoDispose (void);
+  /**
+   * Get a copy of the attached Queue.
+   *
+   * This method is provided for any derived class that may need to get
+   * direct access to the underlying queue.
+   *
+   * \return a pointer to the queue.
+   */
+  Ptr<Queue> GetQueue (void) const; 
+  /**
+   * Get a copy of the attached Channel
+   *
+   * This method is provided for any derived class that may need to get
+   * direct access to the connected channel
+   *
+   * \return a pointer to the channel
+   */
+  virtual Ptr<Channel> DoGetChannel (void) const;
+  /**
+   * Adds the necessary headers and trailers to a packet of data in order to
+   * respect the packet type
+   *
+   * \param p Packet to which header should be added
+   * \param dest MAC destination address to which packet should be sent
+   * \param protocolNumber In some protocols, identifies the type of
+   * payload contained in this packet.
+   */
+  void AddHeader (Packet& p, Eui48Address dest, 
+                  uint16_t protocolNumber);
+  /**
+   * Removes, from a packet of data, all headers and trailers that
+   * relate to the packet type
+   *
+   * \param p Packet whose headers need to be processed
+   * \param param An integer parameter that can be set by the function
+   * to return information gathered in the header
+   * \return Returns true if the packet should be forwarded up the
+   * protocol stack.
+   */
+  bool ProcessHeader (Packet& p, uint16_t & param);
+
+private:
+  // disable copy constructor and operator =
+  CsmaNetDevice &operator = (const CsmaNetDevice &o);
+  CsmaNetDevice (const CsmaNetDevice &o);
+  /**
+   * Initializes variablea when construction object.
+   */
+  void Init (bool sendEnable, bool receiveEnable);
+  /**
+   * Send a Packet on the Csma network
+   *
+   * This method does not use a destination address since all packets
+   * are broadcast to all NetDevices attached to the channel. Packet
+   * should contain all needed headers at this time.
+   *
+   * If the device is ready to transmit, the next packet is read off
+   * of the queue and stored locally until it has been transmitted.
+   *
+   * \param p a reference to the packet to send
+   * \param dest destination address
+   * \param protocolNumber -- this parameter is not used here
+   * \return true if success, false on failure
+   */
+  virtual bool SendTo (const Packet& p, const Address& dest, uint16_t protocolNumber);
+
+  /**
+   * Start Sending a Packet Down the Wire.
+   *
+   * The TransmitStart method is the method that is used internally in
+   * the CsmaNetDevice to begin the process of sending a packet
+   * out on the channel.  The corresponding method is called on the
+   * channel to let it know that the physical device this class
+   * represents has virually started sending signals, this causes the
+   * channel to become busy.  An event is scheduled for the time at
+   * which the bits have been completely transmitted. If the channel
+   * is busy, the method reschedules itself for a later time (within
+   * the backoff period)
+   *
+   * @see CsmaChannel::TransmitStart ()
+   * @see TransmitCompleteEvent ()
+   */
+  void TransmitStart ();
+  /**
+   * Stop Sending a Packet Down the Wire and Begin the Interframe Gap.
+   *
+   * The TransmitCompleteEvent method is used internally to finish the process
+   * of sending a packet out on the channel.  During execution of this method
+   * the TransmitEnd method is called on the channel to let it know that the
+   * physical device this class represents has virually finished sending 
+   * signals.  The channel uses this event to begin its speed of light delay
+   * timer after which it notifies the Net Device at the other end of the 
+   * link that the bits have arrived.  During this method, the net device 
+   * also schedules the TransmitReadyEvent at which time the transmitter 
+   * becomes ready to send the next packet.
+   *
+   * @see CsmaChannel::TransmitEnd ()
+   * @see TransmitReadyEvent ()
+   */
+  void TransmitCompleteEvent (void);
+  /**
+   * Cause the Transmitter to Become Ready to Send Another Packet.
+   *
+   * The TransmitReadyEvent method is used internally to re-enable the 
+   * transmit machine of the net device.  It is scheduled after a suitable
+   * interframe gap after the completion of the previous transmission.
+   * The queue is checked at this time, and if there is a packet waiting on
+   * the queue, the transmission process is begun.
+   *
+   * If a packet is in the queue, it is extracted for the queue as the
+   * next packet to be transmitted by the net device.
+   *
+   * @see TransmitStart ()
+   */
+  void TransmitReadyEvent (void);
+  /**
+   * Create a Trace Resolver for events in the net device.
+   * (NOT TESTED)
+   * @see class TraceResolver
+   */
+  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
+
+  /**
+   * Aborts the transmission of the current packet
+   *
+   * If the net device has tried to transmit a packet for more times
+   * than the maximum allowed number of retries (channel always busy)
+   * then the packet is dropped.
+   *
+   */
+  void TransmitAbort (void);
+
+  /** 
+   * Device ID returned by the attached functions. It is used by the
+   * mp-channel to identify each net device to make sure that only
+   * active net devices are writing to the channel
+   */
+  uint32_t m_deviceId; 
+
+  /**
+   * Enable net device to send packets. True by default
+   */
+  bool m_sendEnable;
+  /**
+   * Enable net device to receive packets. True by default
+   */
+  bool m_receiveEnable;
+  /**
+   * Enumeration of the states of the transmit machine of the net device.
+   */
+  enum TxMachineState
+    {
+      READY, /**< The transmitter is ready to begin transmission of a packet */
+      BUSY,  /**< The transmitter is busy transmitting a packet */
+      GAP,    /**< The transmitter is in the interframe gap time */
+      BACKOFF    /**< The transmitter is waiting for the channel to be free */
+    };
+  /**
+   * The state of the Net Device transmit state machine.
+   * @see TxMachineState
+   */
+  TxMachineState m_txMachineState;
+  
+  /**
+   * The type of packet that should be created by the AddHeader
+   * function and that should be processed by the ProcessHeader
+   * function.
+   */
+  CsmaEncapsulationMode m_encapMode;
+  /**
+   * The data rate that the Net Device uses to simulate packet transmission
+   * timing.
+   * @see class DataRate
+   */
+  DataRate m_bps;
+  /**
+   * The interframe gap that the Net Device uses to throttle packet
+   * transmission
+   * @see class Time
+   */
+  Time m_tInterframeGap;
+  /**
+   * Holds the backoff parameters and is used to calculate the next
+   * backoff time to use when the channel is busy and the net device
+   * is ready to transmit
+   */
+  Backoff m_backoff;
+  /**
+   * Next packet that will be transmitted (if transmitter is not
+   * currently transmitting) or packet that is currently being
+   * transmitted.
+   */
+  Packet m_currentPkt;
+  /**
+   * The CsmaChannel to which this CsmaNetDevice has been
+   * attached.
+   * @see class CsmaChannel
+   */
+  Ptr<CsmaChannel> m_channel;
+  /**
+   * The Queue which this CsmaNetDevice uses as a packet source.
+   * Management of this Queue has been delegated to the CsmaNetDevice
+   * and it has the responsibility for deletion.
+   * @see class Queue
+   * @see class DropTailQueue
+   */
+  Ptr<Queue> m_queue;
+  /**
+   * NOT TESTED
+   * The trace source for the packet reception events that the device can
+   * fire.
+   *
+   * @see class CallBackTraceSource
+   * @see class TraceResolver
+   */
+  CallbackTraceSource<const Packet &> m_rxTrace;
+  CallbackTraceSource<const Packet &> m_dropTrace;
+
+};
+
+}; // namespace ns3
+
+#endif // CSMA_NET_DEVICE_H
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-topology.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+
+//
+// Topology helper for Csma channels in ns3.
+
+#include "ns3/assert.h"
+#include "ns3/debug.h"
+#include "ns3/queue.h"
+
+#include "csma-channel.h"
+#include "csma-net-device.h"
+#include "csma-topology.h"
+#include "ns3/socket-factory.h"
+
+namespace ns3 {
+
+Ptr<CsmaChannel>
+CsmaTopology::CreateCsmaChannel(
+  const DataRate& bps,
+  const Time& delay)
+{
+  Ptr<CsmaChannel> channel = Create<CsmaChannel> (bps, delay);
+
+  return channel;
+}
+
+#if 0
+Ptr<CsmaNetDevice>
+CsmaTopology::AddCsmaEthernetNode(
+  Ptr<Node> n1,
+  Ptr<CsmaChannel> ch,
+  MacAddress addr)
+{
+  Ptr<CsmaNetDevice> nd1 = Create<CsmaNetDevice> (n1, addr, 
+                                                      ns3::CsmaNetDevice::ETHERNET_V1);
+
+  Ptr<Queue> q = Queue::CreateDefault ();
+  nd1->AddQueue(q);
+  nd1->Attach (ch);
+  
+  return nd1;
+}
+
+Ptr<PacketSocket>
+CsmaTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app, 
+                                        Ptr<CsmaNetDevice> ndSrc,
+                                        Ptr<CsmaNetDevice> ndDest)
+{
+  Ptr<PacketSocket> socket = Create<PacketSocket> ();
+  socket->Bind(ndSrc);
+  socket->Connect(ndDest->GetAddress());
+  app->Connect(socket);
+
+  return socket;
+}
+
+Ptr<PacketSocket>
+CsmaTopology::ConnectPacketSocket(Ptr<PacketSocketApp> app,
+                                        Ptr<CsmaNetDevice> ndSrc,
+                                        MacAddress macAddr)
+{
+  Ptr<PacketSocket> socket = Create<PacketSocket> ();
+  socket->Bind(ndSrc);
+  socket->Connect(macAddr);
+  app->Connect(socket);
+
+  return socket;
+}
+
+Ptr<Socket>
+CsmaTopology::CreatePacketSocket(Ptr<Node> n1, std::string iid_name)
+{
+  InterfaceId iid = InterfaceId::LookupByName (iid_name);
+
+  Ptr<SocketFactory> socketFactory =
+    n1->QueryInterface<SocketFactory> (iid);
+
+  Ptr<Socket> socket = socketFactory->CreateSocket ();
+
+  return socket;
+}
+#endif
+
+} // namespace ns3
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/csma-topology.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,123 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+//
+// Copyright (c) 2007 Emmanuelle Laprise
+//
+// 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+//
+// Topology helper for multipoint channels in ns3.
+// 
+#ifndef CSMA_TOPOLOGY_H
+#define CSMA_TOPOLOGY_H
+
+#include "ns3/ptr.h"
+#include "ns3/csma-net-device.h"
+#include "ns3/node.h"
+
+// The topology class consists of only static methods thar are used to
+// create the topology and data flows for an ns3 simulation
+
+namespace ns3 {
+
+class CsmaChannel;
+class Node;
+class DataRate;
+class Queue;
+
+/**
+ * \brief A helper class to create Csma Topologies 
+ *
+ * Csma topologies are created based on the
+ * ns3::CsmaNetDevice subclasses and ns3::CsmaChannel
+ * objects.  This class uses the EthernetNetDevice and
+ * PacketSocket classes in order to create logical connections between
+ * net devices. The PacketSocket class generates the data and the
+ * EthernetNetDevice class creates ethernet packets from the
+ * data, filling in source and destination addresses. The
+ * EthernetNetDevice class filters received data packets
+ * according to its destination Mac addresses.
+ */
+class CsmaTopology {
+public:
+  /** 
+   * \param dataRate Maximum transmission link rate 
+   * \param delay propagation delay between any two nodes 
+   * \return Pointer to the created CsmaChannel
+   * 
+   * Create a CsmaChannel. All nodes connected to a multipoint
+   * channels will receive all packets written to that channel
+   */
+  static Ptr<CsmaChannel> CreateCsmaChannel(
+    const DataRate& dataRate, const Time& delay);
+
+#if 0
+  /**
+   * \param n1 Node to be attached to the multipoint channel
+   * \param ch CsmaChannel to which node n1 should be attached 
+   * \param addr MacAddress that should be assigned to the
+   * EthernetNetDevice that will be added to the node.
+   *
+   * Add a multipoint node to a multipoint channel
+   */
+  static Ptr<CsmaNetDevice> AddCsmaEthernetNode(Ptr<Node> n1, 
+                                                    Ptr<CsmaChannel> ch,
+                                                    MacAddress addr);
+
+  /**
+   * \param app Application that will be sending data to the agent
+   * \param ndSrc Net Device that will be sending the packets onto the
+   * network
+   * \param ndDest Net Device to which ndSrc will be sending the packets
+   * \return A pointer to the PacketSocket
+   *
+   * Creates an PacketSocket and configure it to send packets between
+   * two net devices
+   */
+static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
+                                      Ptr<CsmaNetDevice> ndSrc,
+                                      Ptr<CsmaNetDevice> ndDest);
+
+  /**
+   * \param app Application that will be sending data to the agent
+   * \param ndSrc Net Device that will be sending the packets onto the
+   * network 
+   * \param macAddr Mac destination address for the packets send by
+   * the ndSrc net device \return a Pointer to the created
+   * PacketSocket
+   *
+   * Creates an PacketSocket and configure it to send packets from a
+   * net device to a destination MacAddress
+   */
+static Ptr<PacketSocket> ConnectPacketSocket(Ptr<PacketSocketApp> app,
+                                      Ptr<CsmaNetDevice> ndSrc,
+                                      MacAddress macAddr);
+
+  /**
+   * \param n1 Node from which socketfactory should be tested.
+   * \param iid_name Interface identifier ("Packet", in this case)
+   *
+   * This is a test function to make sure that a socket can be created
+   * by using the socketfactory interface provided in the
+   * netdevicenode.
+   */
+static  Ptr<Socket> CreatePacketSocket(Ptr<Node> n1, 
+                                       std::string iid_name);
+#endif
+
+};
+} // namespace ns3
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/devices/csma/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,19 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    obj = bld.create_ns3_module('csma', ['node'])
+    obj.source = [
+        'backoff.cc',
+        'csma-net-device.cc',
+        'csma-channel.cc',
+        'csma-topology.cc',
+        'csma-ipv4-topology.cc',
+        ]
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'backoff.h',
+        'csma-net-device.h',
+        'csma-channel.h',
+        'csma-topology.h',
+        'csma-ipv4-topology.h',
+        ]
--- a/src/devices/point-to-point/point-to-point-net-device.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -26,9 +26,10 @@
 #include "ns3/queue.h"
 #include "ns3/simulator.h"
 #include "ns3/composite-trace-resolver.h"
+#include "ns3/eui48-address.h"
+#include "ns3/llc-snap-header.h"
 #include "point-to-point-net-device.h"
 #include "point-to-point-channel.h"
-#include "ns3/llc-snap-header.h"
 
 NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice");
 
@@ -39,10 +40,25 @@
            "The default data rate for point to point links",
            DataRate ("10Mb/s"));
 
-  PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node,
-                                                const DataRate& rate) 
+PointToPointTraceType::PointToPointTraceType ()
+{}
+void 
+PointToPointTraceType::Print (std::ostream &os) const
+{
+  os << "dev-rx";
+}
+uint16_t 
+PointToPointTraceType::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<PointToPointTraceType> ("PointToPointTraceType");
+  return uid;
+}
+
+
+PointToPointNetDevice::PointToPointNetDevice (Ptr<Node> node,
+                                              const DataRate& rate) 
 : 
-  NetDevice(node, MacAddress (6)), 
+  NetDevice(node, Eui48Address::Allocate ()), 
   m_txMachineState (READY),
   m_bps (rate),
   m_tInterframeGap (Seconds(0)),
@@ -55,7 +71,7 @@
   // BUGBUG FIXME
   //
   // You _must_ support broadcast to get any sort of packet from the ARP layer.
-  EnableBroadcast (MacAddress ("ff:ff:ff:ff:ff:ff"));
+  EnableBroadcast (Eui48Address ("ff:ff:ff:ff:ff:ff"));
   EnableMulticast();
   EnablePointToPoint();
 }
@@ -66,15 +82,16 @@
   m_queue = 0;
 }
 
-void PointToPointNetDevice::AddHeader(Packet& p, const MacAddress& dest,
-                                      uint16_t protocolNumber)
+void 
+PointToPointNetDevice::AddHeader(Packet& p, uint16_t protocolNumber)
 {
   LlcSnapHeader llc;
   llc.SetType (protocolNumber);
   p.AddHeader (llc);
 }
 
-bool PointToPointNetDevice::ProcessHeader(Packet& p, uint16_t& param)
+bool 
+PointToPointNetDevice::ProcessHeader(Packet& p, uint16_t& param)
 {
   LlcSnapHeader llc;
   p.RemoveHeader (llc);
@@ -100,9 +117,10 @@
   m_tInterframeGap = t;
 }
 
-bool PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest, 
+bool PointToPointNetDevice::SendTo (const Packet& packet, const Address& dest, 
                                     uint16_t protocolNumber)
 {
+  Packet p = packet;
   NS_DEBUG ("PointToPointNetDevice::SendTo (" << &p << ", " << &dest << ")");
   NS_DEBUG ("PointToPointNetDevice::SendTo (): UID is " << p.GetUid () << ")");
 
@@ -110,7 +128,7 @@
   // "go down" during the simulation?  Shouldn't we just wait for it
   // to come back up?
   NS_ASSERT (IsLinkUp ());
-  AddHeader(p, dest, protocolNumber);
+  AddHeader(p, protocolNumber);
 
 //
 // This class simulates a point to point device.  In the case of a serial
@@ -119,14 +137,14 @@
 //
 // If there's a transmission in progress, we enque the packet for later
 // trnsmission; otherwise we send it now.
-    if (m_txMachineState == READY) 
-      {
-        return TransmitStart (p);
-      }
-    else
-      {
-        return m_queue->Enqueue(p);
-      }
+  if (m_txMachineState == READY) 
+    {
+      return TransmitStart (p);
+    }
+  else
+    {
+      return m_queue->Enqueue(p);
+    }
 }
 
   bool
@@ -176,11 +194,10 @@
 {
   CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
   resolver->Add ("queue", 
-                 MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)),
-                 PointToPointNetDevice::QUEUE);
+                 MakeCallback (&Queue::CreateTraceResolver, PeekPointer (m_queue)));
   resolver->Add ("rx",
                  m_rxTrace,
-                 PointToPointNetDevice::RX);
+                 PointToPointTraceType ());
   return resolver;
 }
 
@@ -218,12 +235,12 @@
 void PointToPointNetDevice::Receive (Packet& p)
 {
   NS_DEBUG ("PointToPointNetDevice::Receive (" << &p << ")");
-  uint16_t param = 0;
+  uint16_t protocol = 0;
   Packet packet = p;
 
-  ProcessHeader(packet, param);
   m_rxTrace (packet);
-  ForwardUp (packet, param);
+  ProcessHeader(packet, protocol);
+  ForwardUp (packet, protocol, GetBroadcast ());
 }
 
 Ptr<Queue> PointToPointNetDevice::GetQueue(void) const 
--- a/src/devices/point-to-point/point-to-point-net-device.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/devices/point-to-point/point-to-point-net-device.h	Wed Sep 05 18:35:39 2007 +0100
@@ -22,7 +22,7 @@
 #define POINT_TO_POINT_NET_DEVICE_H
 
 #include <string.h>
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
 #include "ns3/node.h"
 #include "ns3/net-device.h"
 #include "ns3/callback.h"
@@ -38,6 +38,14 @@
 class Queue;
 class PointToPointChannel;
 
+class PointToPointTraceType : public TraceContextElement
+{
+public:
+  PointToPointTraceType ();
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+};
+
 /**
  * \class PointToPointNetDevice
  * \brief A Device for a Point to Point Network Link.
@@ -64,14 +72,6 @@
 class PointToPointNetDevice : public NetDevice {
 public:
   /**
-   * Enumeration of the types of traces supported in the class.
-   *
-   */
-  enum TraceType {
-    QUEUE, /**< Trace queue events on the attached queue */
-    RX,    /**< Trace packet reception events (from the channel) */
-  };
-  /**
    * Construct a PointToPointNetDevice
    *
    * This is the constructor for the PointToPointNetDevice.  It takes as a
@@ -175,7 +175,6 @@
   virtual Ptr<Channel> DoGetChannel(void) const;
   /**
    * Set a new default data rate
-   * @param Data rate to set for new default
    */
   static void SetDefaultRate(const DataRate&);
 
@@ -191,7 +190,7 @@
    * Adds the necessary headers and trailers to a packet of data in order to
    * respect the protocol implemented by the agent.
    */
-  void AddHeader(Packet& p, const MacAddress& dest, uint16_t protocolNumber);
+  void AddHeader(Packet& p, uint16_t protocolNumber);
   /**
    * Removes, from a packet of data, all headers and trailers that
    * relate to the protocol implemented by the agent
@@ -208,11 +207,11 @@
    *
    * @see NetDevice
    * @param p a reference to the packet to send
-   * @param dest a reference to the MacAddress of the destination device
+   * @param dest a reference to the Address of the destination device
    * @param protocolNumber Protocol Number used to find protocol touse
    * @returns true if success, false on failure
    */
-  virtual bool SendTo (Packet& p, const MacAddress& dest, 
+  virtual bool SendTo (const Packet& p, const Address& dest, 
                        uint16_t protocolNumber);
   /**
    * Start Sending a Packet Down the Wire.
@@ -291,7 +290,7 @@
    * @see class CallBackTraceSource
    * @see class TraceResolver
    */
-  CallbackTraceSource<Packet &> m_rxTrace;
+  CallbackTraceSource<const Packet &> m_rxTrace;
   /** 
    * Default data rate.  Used for all newly created p2p net devices
    */
--- a/src/devices/point-to-point/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/devices/point-to-point/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -2,10 +2,7 @@
 
 
 def build(bld):
-    module = bld.create_obj('cpp', 'shlib')
-    module.name = 'ns3-point-to-point'
-    module.target = module.name
-    module.uselib_local = ['ns3-node']
+    module = bld.create_ns3_module('point-to-point', ['node'])
     module.source = [
         'point-to-point-net-device.cc',
         'point-to-point-channel.cc',
--- a/src/internet-node/arp-cache.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-cache.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -148,7 +148,7 @@
   UpdateSeen ();
 }
 Packet 
-ArpCache::Entry::MarkAlive (MacAddress macAddress) 
+ArpCache::Entry::MarkAlive (Address macAddress) 
 {
   NS_ASSERT (m_state == WAIT_REPLY);
   //NS_ASSERT (m_waiting != 0);
@@ -182,7 +182,7 @@
   UpdateSeen ();
 }
 
-MacAddress
+Address
 ArpCache::Entry::GetMacAddress (void)
 {
   NS_ASSERT (m_state == ALIVE);
--- a/src/internet-node/arp-cache.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-cache.h	Wed Sep 05 18:35:39 2007 +0100
@@ -26,7 +26,7 @@
 #include "ns3/nstime.h"
 #include "ns3/net-device.h"
 #include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
 #include "ns3/ptr.h"
 #include "sgi-hashmap.h"
 
@@ -101,7 +101,7 @@
      * \param macAddress
      * \return 
      */
-    Packet MarkAlive (MacAddress macAddress);
+    Packet MarkAlive (Address macAddress);
     /**
      * \param waiting
      */
@@ -127,7 +127,7 @@
     /**
      * \return The MacAddress of this entry
      */
-    MacAddress GetMacAddress (void);
+    Address GetMacAddress (void);
     /**
      * \return True if this entry has timedout; false otherwise.
      */
@@ -143,7 +143,7 @@
     ArpCache *m_arp;
     ArpCacheEntryState_e m_state;
     Time m_lastSeen;
-    MacAddress m_macAddress;
+    Address m_macAddress;
     Packet m_waiting;
   };
 
--- a/src/internet-node/arp-header.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-header.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -25,13 +25,19 @@
 
 namespace ns3 {
 
-ArpHeader::~ArpHeader ()
-{}
+NS_HEADER_ENSURE_REGISTERED (ArpHeader);
+
+uint32_t
+ArpHeader::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<ArpHeader> ("ArpHeader.ns3");
+  return uid;
+}
 
 void 
-ArpHeader::SetRequest (MacAddress sourceHardwareAddress,
+ArpHeader::SetRequest (Address sourceHardwareAddress,
                        Ipv4Address sourceProtocolAddress,
-                       MacAddress destinationHardwareAddress,
+                       Address destinationHardwareAddress,
                        Ipv4Address destinationProtocolAddress)
 {
   m_type = ARP_TYPE_REQUEST;
@@ -41,9 +47,9 @@
   m_ipv4Dest = destinationProtocolAddress;
 }
 void 
-ArpHeader::SetReply (MacAddress sourceHardwareAddress,
+ArpHeader::SetReply (Address sourceHardwareAddress,
                      Ipv4Address sourceProtocolAddress,
-                     MacAddress destinationHardwareAddress,
+                     Address destinationHardwareAddress,
                      Ipv4Address destinationProtocolAddress)
 {
   m_type = ARP_TYPE_REPLY;
@@ -62,12 +68,12 @@
 {
   return (m_type == ARP_TYPE_REPLY)?true:false;
 }
-MacAddress 
+Address 
 ArpHeader::GetSourceHardwareAddress (void)
 {
   return m_macSource;
 }
-MacAddress 
+Address 
 ArpHeader::GetDestinationHardwareAddress (void)
 {
   return m_macDest;
@@ -84,13 +90,13 @@
 }
 
 std::string 
-ArpHeader::DoGetName (void) const
+ArpHeader::GetName (void) const
 {
   return "ARP";
 }
 
 void 
-ArpHeader::PrintTo (std::ostream &os) const
+ArpHeader::Print (std::ostream &os) const
 {
   if (IsRequest ()) 
     {
@@ -123,7 +129,7 @@
 }
 
 void
-ArpHeader::SerializeTo (Buffer::Iterator start) const
+ArpHeader::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   NS_ASSERT (m_macSource.GetLength () == m_macDest.GetLength ());
@@ -141,7 +147,7 @@
   WriteTo (i, m_ipv4Dest);
 }
 uint32_t
-ArpHeader::DeserializeFrom (Buffer::Iterator start)
+ArpHeader::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
   i.Next (2+2);
--- a/src/internet-node/arp-header.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-header.h	Wed Sep 05 18:35:39 2007 +0100
@@ -23,59 +23,47 @@
 #define ARP_HEADER_H
 
 #include "ns3/header.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
 #include "ns3/ipv4-address.h"
+#include <string>
 
 namespace ns3 {
 /**
  * \brief The packet header for an ARP packet
  */
-class ArpHeader : public Header {
- public:
-  virtual ~ArpHeader ();
+class ArpHeader : public Header 
+{
+public:
+  static uint32_t GetUid (void);
 
-  void SetRequest (MacAddress sourceHardwareAddress,
+  void SetRequest (Address sourceHardwareAddress,
                    Ipv4Address sourceProtocolAddress,
-                   MacAddress destinationHardwareAddress,
+                   Address destinationHardwareAddress,
                    Ipv4Address destinationProtocolAddress);
-  void SetReply (MacAddress sourceHardwareAddress,
+  void SetReply (Address sourceHardwareAddress,
                  Ipv4Address sourceProtocolAddress,
-                 MacAddress destinationHardwareAddress,
+                 Address destinationHardwareAddress,
                  Ipv4Address destinationProtocolAddress);
   bool IsRequest (void) const;
   bool IsReply (void) const;
-  MacAddress GetSourceHardwareAddress (void);
-  MacAddress GetDestinationHardwareAddress (void);
+  Address GetSourceHardwareAddress (void);
+  Address GetDestinationHardwareAddress (void);
   Ipv4Address GetSourceIpv4Address (void);
   Ipv4Address GetDestinationIpv4Address (void);
 
-private:
-  virtual std::string DoGetName (void) const;
-  /**
-   * \param os
-   */
-  virtual void PrintTo (std::ostream &os) const;
-  /**
-   * \return
-   */
-  virtual uint32_t GetSerializedSize (void) const;
-  /**
-   * \param start
-   */
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  /**
-   * \param start
-   * \return
-   */
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
 
   enum ArpType_e {
     ARP_TYPE_REQUEST = 1,
     ARP_TYPE_REPLY   = 2
   };
   uint16_t m_type;
-  MacAddress m_macSource;
-  MacAddress m_macDest;
+  Address m_macSource;
+  Address m_macDest;
   Ipv4Address m_ipv4Source;
   Ipv4Address m_ipv4Dest;
 };
--- a/src/internet-node/arp-ipv4-interface.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-ipv4-interface.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -25,10 +25,11 @@
 #include "ns3/composite-trace-resolver.h"
 #include "ns3/node.h"
 #include "ns3/net-device.h"
+#include "ns3/address.h"
 
 #include "arp-ipv4-interface.h"
-#include "arp-private.h"
 #include "ipv4-l3-protocol.h"
+#include "arp-l3-protocol.h"
 
 namespace ns3 {
 
@@ -46,8 +47,7 @@
   if (GetDevice () != 0)
     {
       resolver->Add ("netdevice",
-                     MakeCallback (&NetDevice::CreateTraceResolver, PeekPointer (GetDevice ())),
-                     ArpIpv4Interface::NETDEVICE);
+                     MakeCallback (&NetDevice::CreateTraceResolver, PeekPointer (GetDevice ())));
     }
   
   return resolver;
@@ -59,18 +59,17 @@
   NS_ASSERT (GetDevice () != 0);
   if (GetDevice ()->NeedsArp ())
     {
-      Ptr<ArpPrivate> arp = m_node->QueryInterface<ArpPrivate> (ArpPrivate::iid);
-      MacAddress hardwareDestination;
+      Ptr<ArpL3Protocol> arp = m_node->QueryInterface<ArpL3Protocol> (ArpL3Protocol::iid);
+      Address hardwareDestination;
       bool found;
 
       if (dest.IsBroadcast ())
         {
-           hardwareDestination = GetDevice ()->GetBroadcast ();
-           found = true;
+          hardwareDestination = GetDevice ()->GetBroadcast ();
+          found = true;
         }
       else
         {
-          Ptr<ArpPrivate> arp = m_node->QueryInterface<ArpPrivate> (ArpPrivate::iid);
           found = arp->Lookup (p, dest, GetDevice (), &hardwareDestination);
         }
 
--- a/src/internet-node/arp-ipv4-interface.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-ipv4-interface.h	Wed Sep 05 18:35:39 2007 +0100
@@ -39,10 +39,6 @@
 class ArpIpv4Interface : public Ipv4Interface
 {
  public:
-  enum TraceType {
-    NETDEVICE,
-    ARP,
-  };
   ArpIpv4Interface (Ptr<Node> node, Ptr<NetDevice> device);
   virtual ~ArpIpv4Interface ();
 
--- a/src/internet-node/arp-l3-protocol.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-l3-protocol.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -24,22 +24,24 @@
 #include "ns3/node.h"
 #include "ns3/net-device.h"
 
+#include "ipv4-l3-protocol.h"
 #include "arp-l3-protocol.h"
 #include "arp-header.h"
 #include "arp-cache.h"
 #include "ipv4-interface.h"
-#include "ipv4-private.h"
 
 NS_DEBUG_COMPONENT_DEFINE ("ArpL3Protocol");
 
 namespace ns3 {
 
+const InterfaceId ArpL3Protocol::iid = MakeInterfaceId ("ArpL3Protocol", Object::iid);
 const uint16_t ArpL3Protocol::PROT_NUMBER = 0x0806;
 
 ArpL3Protocol::ArpL3Protocol (Ptr<Node> node)
-  : L3Protocol (PROT_NUMBER, 0/* XXX: correct version number ? */ ),
-    m_node (node)
-{}
+  : m_node (node)
+{
+  SetInterfaceId (ArpL3Protocol::iid);
+}
 
 ArpL3Protocol::~ArpL3Protocol ()
 {}
@@ -53,7 +55,7 @@
     }
   m_cacheList.clear ();
   m_node = 0;
-  L3Protocol::DoDispose ();
+  Object::DoDispose ();
 }
 
 TraceResolver *
@@ -72,7 +74,7 @@
 	  return *i;
 	}
     }
-  Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
+  Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
   Ipv4Interface *interface = ipv4->FindInterfaceForDevice (device);
   ArpCache * cache = new ArpCache (device, interface);
   NS_ASSERT (device->IsBroadcast ());
@@ -82,10 +84,11 @@
 }
 
 void 
-ArpL3Protocol::Receive(Packet& packet, Ptr<NetDevice> device)
+ArpL3Protocol::Receive(Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
 {
   ArpCache *cache = FindCache (device);
   ArpHeader arp;
+  Packet packet = p;
   packet.RemoveHeader (arp);
   
   NS_DEBUG ("ARP: received "<< (arp.IsRequest ()? "request" : "reply") <<
@@ -104,7 +107,7 @@
     } 
   else if (arp.IsReply () &&
            arp.GetDestinationIpv4Address ().IsEqual (cache->GetInterface ()->GetAddress ()) &&
-           arp.GetDestinationHardwareAddress ().IsEqual (device->GetAddress ())) 
+           arp.GetDestinationHardwareAddress () == device->GetAddress ()) 
     {
       Ipv4Address from = arp.GetSourceIpv4Address ();
       ArpCache::Entry *entry = cache->Lookup (from);
@@ -115,7 +118,7 @@
               NS_DEBUG ("node="<<m_node->GetId ()<<", got reply from " << 
                         arp.GetSourceIpv4Address ()
                      << " for waiting entry -- flush");
-              MacAddress from_mac = arp.GetSourceHardwareAddress ();
+              Address from_mac = arp.GetSourceHardwareAddress ();
               Packet waiting = entry->MarkAlive (from_mac);
 	      cache->GetInterface ()->Send (waiting, arp.GetSourceIpv4Address ());
             } 
@@ -144,8 +147,8 @@
 }
 bool 
 ArpL3Protocol::Lookup (Packet &packet, Ipv4Address destination, 
-	     Ptr<NetDevice> device,
-	     MacAddress *hardwareDestination)
+                       Ptr<NetDevice> device,
+                       Address *hardwareDestination)
 {
   ArpCache *cache = FindCache (device);
   ArpCache::Entry *entry = cache->Lookup (destination);
@@ -231,7 +234,7 @@
 }
 
 void
-ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac)
+ArpL3Protocol::SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac)
 {
   ArpHeader arp;
   NS_DEBUG ("ARP: sending reply from node "<<m_node->GetId ()<<
--- a/src/internet-node/arp-l3-protocol.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/arp-l3-protocol.h	Wed Sep 05 18:35:39 2007 +0100
@@ -23,9 +23,8 @@
 
 #include <list>
 #include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ns3/address.h"
 #include "ns3/ptr.h"
-#include "l3-protocol.h"
 
 namespace ns3 {
 
@@ -38,22 +37,23 @@
 /**
  * \brief An implementation of the ARP protocol
  */
-class ArpL3Protocol : public L3Protocol
+class ArpL3Protocol : public Object
 {
 public:
+  static const InterfaceId iid;
   static const uint16_t PROT_NUMBER;
   /**
    * \brief Constructor
    * \param node The node which this ARP object is associated with
    */
   ArpL3Protocol (Ptr<Node> node);
-  ~ArpL3Protocol ();
+  virtual ~ArpL3Protocol ();
 
   virtual TraceResolver *CreateTraceResolver (TraceContext const &context);
   /**
    * \brief Recieve a packet
    */
-  virtual void Receive(Packet& p, Ptr<NetDevice> device);
+  void Receive(Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from);
   /**
    * \brief Perform an ARP lookup
    * \param p
@@ -64,14 +64,14 @@
    */
   bool Lookup (Packet &p, Ipv4Address destination, 
 	       Ptr<NetDevice> device,
-	       MacAddress *hardwareDestination);
+	       Address *hardwareDestination);
 protected:
   virtual void DoDispose (void);
 private:
   typedef std::list<ArpCache *> CacheList;
   ArpCache *FindCache (Ptr<NetDevice> device);
   void SendArpRequest (ArpCache const *cache, Ipv4Address to);
-  void SendArpReply (ArpCache const *cache, Ipv4Address toIp, MacAddress toMac);
+  void SendArpReply (ArpCache const *cache, Ipv4Address toIp, Address toMac);
   CacheList m_cacheList;
   Ptr<Node> m_node;
 };
--- a/src/internet-node/arp-private.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/* -*- 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 "arp-private.h"
-#include "arp-l3-protocol.h"
-#include "ns3/assert.h"
-#include "ns3/net-device.h"
-
-namespace ns3 {
-
-const InterfaceId ArpPrivate::iid = MakeInterfaceId ("ArpPrivate", Object::iid);
-
-ArpPrivate::ArpPrivate (Ptr<ArpL3Protocol> arp)
-  : m_arp (arp)
-{
-  SetInterfaceId (ArpPrivate::iid);
-}
-ArpPrivate::~ArpPrivate ()
-{
-  NS_ASSERT (m_arp == 0);
-}
-
-bool 
-ArpPrivate::Lookup (Packet &p, Ipv4Address destination, 
-		     Ptr<NetDevice> device,
-		     MacAddress *hardwareDestination)
-{
-  return m_arp->Lookup (p, destination, device, hardwareDestination);
-}
-
-void
-ArpPrivate::DoDispose (void)
-{
-  m_arp = 0;
-  Object::DoDispose ();
-}
-
-
-} // namespace ns3
--- a/src/internet-node/arp-private.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/* -*- 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 ARP_PRIVATE_H
-#define ARP_PRIVATE_H
-
-#include "ns3/object.h"
-#include "ns3/ipv4-address.h"
-
-namespace ns3 {
-
-class NetDevice;
-class MacAddress;
-class Packet;
-class ArpL3Protocol;
-
-class ArpPrivate : public Object
-{
-public:
-  static const InterfaceId iid;
-  ArpPrivate (Ptr<ArpL3Protocol> arp);
-  virtual ~ArpPrivate ();
-  bool Lookup (Packet &p, Ipv4Address destination, 
-	       Ptr<NetDevice> device,
-	       MacAddress *hardwareDestination);
-protected:
-  virtual void DoDispose (void);
-private:
-  Ptr<ArpL3Protocol> m_arp;
-};
-
-} // namespace ns3
-
-#endif /* ARP_PRIVATE_H */
--- a/src/internet-node/ascii-trace.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ascii-trace.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -24,14 +24,8 @@
 #include "ns3/trace-root.h"
 #include "ns3/simulator.h"
 #include "ns3/node.h"
+#include "ns3/packet.h"
 #include "ns3/queue.h"
-#include "ns3/node-list.h"
-#include "ns3/llc-snap-header.h"
-
-#include "ipv4-l3-protocol.h"
-#include "arp-header.h"
-#include "udp-header.h"
-#include "ipv4-header.h"
 
 namespace ns3 {
 
@@ -47,90 +41,62 @@
 AsciiTrace::TraceAllQueues (void)
 {
   Packet::EnableMetadata ();
-  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/queue/*",
-                      MakeCallback (&AsciiTrace::LogDevQueue, this));
+  TraceRoot::Connect ("/nodes/*/devices/*/queue/enqueue",
+                      MakeCallback (&AsciiTrace::LogDevQueueEnqueue, this));
+  TraceRoot::Connect ("/nodes/*/devices/*/queue/dequeue",
+                      MakeCallback (&AsciiTrace::LogDevQueueDequeue, this));
+  TraceRoot::Connect ("/nodes/*/devices/*/queue/drop",
+                      MakeCallback (&AsciiTrace::LogDevQueueDrop, this));
 }
 void
 AsciiTrace::TraceAllNetDeviceRx (void)
 {
   Packet::EnableMetadata ();
-  TraceRoot::Connect ("/nodes/*/ipv4/interfaces/*/netdevice/rx",
+  TraceRoot::Connect ("/nodes/*/devices/*/rx",
                       MakeCallback (&AsciiTrace::LogDevRx, this));
 }
 
-void
-AsciiTrace::PrintType (Packet const &packet)
+void 
+AsciiTrace::LogDevQueueEnqueue (TraceContext const &context, 
+  Packet const &packet)
 {
-  Packet p = packet;
-  LlcSnapHeader llc;
-  p.RemoveHeader (llc);
-  switch (llc.GetType ())
-    {
-    case 0x0800: {
-      Ipv4Header ipv4;
-      p.RemoveHeader (ipv4);
-      if (ipv4.GetProtocol () == 17)
-        {
-          UdpHeader udp;
-          p.RemoveHeader (udp);
-          m_os << "udp size=" << p.GetSize ();
-        }
-    } break;
-    case 0x0806: {
-      ArpHeader arp;
-      p.RemoveHeader (arp);
-      m_os << "arp ";
-      if (arp.IsRequest ())
-        {
-          m_os << "request";
-        }
-      else
-        {
-          m_os << "reply ";
-        }
-    } break;
-    }
-} 
+  m_os << "+ ";
+  m_os << Simulator::Now ().GetSeconds () << " ";
+  context.Print (m_os);
+  m_os << " pkt-uid=" << packet.GetUid () << " ";
+  packet.Print (m_os);
+  m_os << std::endl;
+}
 
 void 
-AsciiTrace::LogDevQueue (TraceContext const &context, Packet const &packet)
+AsciiTrace::LogDevQueueDequeue (TraceContext const &context, 
+  Packet const &packet)
 {
-  enum Queue::TraceType type;
-  context.Get (type);
-  switch (type) 
-    {
-    case Queue::ENQUEUE:
-      m_os << "+ ";
-      break;
-    case Queue::DEQUEUE:
-      m_os << "- ";
-      break;
-    case Queue::DROP:
-      m_os << "d ";
-      break;
-    }
+  m_os << "- ";
   m_os << Simulator::Now ().GetSeconds () << " ";
-  NodeList::NodeIndex nodeIndex;
-  context.Get (nodeIndex);
-  m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
-  Ipv4L3Protocol::InterfaceIndex interfaceIndex;
-  context.Get (interfaceIndex);
-  m_os << "interface=" << interfaceIndex << " ";
-  m_os << "pkt-uid=" << packet.GetUid () << " ";
+  context.Print (m_os);
+  m_os << " pkt-uid=" << packet.GetUid () << " ";
+  packet.Print (m_os);
+  m_os << std::endl;
+}
+
+void 
+AsciiTrace::LogDevQueueDrop (TraceContext const &context, 
+  Packet const &packet)
+{
+  m_os << "d ";
+  m_os << Simulator::Now ().GetSeconds () << " ";
+  context.Print (m_os);
+  m_os << " pkt-uid=" << packet.GetUid () << " ";
   packet.Print (m_os);
   m_os << std::endl;
 }
 void 
-AsciiTrace::LogDevRx (TraceContext const &context, Packet &p)
+AsciiTrace::LogDevRx (TraceContext const &context, const Packet &p)
 {
   m_os << "r " << Simulator::Now ().GetSeconds () << " ";
-  NodeList::NodeIndex nodeIndex;
-  context.Get (nodeIndex);
-  m_os << "node=" << NodeList::GetNode (nodeIndex)->GetId () << " ";
-  Ipv4L3Protocol::InterfaceIndex interfaceIndex;
-  context.Get (interfaceIndex);
-  m_os << "interface=" << interfaceIndex << " ";
-  m_os << "pkt-uid=" << p.GetUid () << " ";
+  context.Print (m_os);
+  m_os << " pkt-uid=" << p.GetUid () << " ";
   p.Print (m_os);
   m_os << std::endl;  
 }
--- a/src/internet-node/ascii-trace.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ascii-trace.h	Wed Sep 05 18:35:39 2007 +0100
@@ -37,9 +37,10 @@
   void TraceAllQueues (void);
   void TraceAllNetDeviceRx (void);
 private:
-  void PrintType (Packet const &p);
-  void LogDevQueue (TraceContext const &context, const Packet &p);
-  void LogDevRx (TraceContext const &context, Packet &p);
+  void LogDevQueueEnqueue (TraceContext const &context, const Packet &p);
+  void LogDevQueueDequeue (TraceContext const &context, const Packet &p);
+  void LogDevQueueDrop (TraceContext const &context, const Packet &p);
+  void LogDevRx (TraceContext const &context, const Packet &p);
   std::ofstream m_os;
 };
 
--- a/src/internet-node/internet-node.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/internet-node.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -23,21 +23,18 @@
 
 #include "ns3/composite-trace-resolver.h"
 #include "ns3/net-device.h"
+#include "ns3/callback.h"
 
-#include "l3-demux.h"
 #include "ipv4-l4-demux.h"
 #include "internet-node.h"
 #include "udp-l4-protocol.h"
 #include "ipv4-l3-protocol.h"
 #include "arp-l3-protocol.h"
 #include "udp-impl.h"
-#include "arp-private.h"
 #include "ipv4-impl.h"
-#include "ipv4-private.h"
 
 namespace ns3 {
 
-
 InternetNode::InternetNode()
 {
   Construct ();
@@ -56,39 +53,34 @@
 {
   Ptr<Ipv4L3Protocol> ipv4 = Create<Ipv4L3Protocol> (this);
   Ptr<ArpL3Protocol> arp = Create<ArpL3Protocol> (this);
-  Ptr<UdpL4Protocol> udp = Create<UdpL4Protocol> (this);
+  // XXX remove the PeekPointer below.
+  RegisterProtocolHandler (MakeCallback (&Ipv4L3Protocol::Receive, PeekPointer (ipv4)), 
+                           Ipv4L3Protocol::PROT_NUMBER, 0);
+  RegisterProtocolHandler (MakeCallback (&ArpL3Protocol::Receive, PeekPointer (arp)),
+                           ArpL3Protocol::PROT_NUMBER, 0);
 
-  Ptr<L3Demux> l3Demux = Create<L3Demux> (this);
+
   Ptr<Ipv4L4Demux> ipv4L4Demux = Create<Ipv4L4Demux> (this);
-
-  l3Demux->Insert (ipv4);
-  l3Demux->Insert (arp);
+  Ptr<UdpL4Protocol> udp = Create<UdpL4Protocol> (this);
   ipv4L4Demux->Insert (udp);
 
   Ptr<UdpImpl> udpImpl = Create<UdpImpl> (udp);
-  Ptr<ArpPrivate> arpPrivate = Create<ArpPrivate> (arp);
   Ptr<Ipv4Impl> ipv4Impl = Create<Ipv4Impl> (ipv4);
-  Ptr<Ipv4Private> ipv4Private = Create<Ipv4Private> (ipv4);
 
-  Object::AddInterface (ipv4Private);
+  Object::AddInterface (ipv4);
+  Object::AddInterface (arp);
   Object::AddInterface (ipv4Impl);
-  Object::AddInterface (arpPrivate);
   Object::AddInterface (udpImpl);
-  Object::AddInterface (l3Demux);
   Object::AddInterface (ipv4L4Demux);
 }
 
-
-TraceResolver *
-InternetNode::DoCreateTraceResolver (TraceContext const &context)
+void
+InternetNode::DoFillTraceResolver (CompositeTraceResolver &resolver)
 {
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  Ptr<Ipv4Private> ipv4 = QueryInterface<Ipv4Private> (Ipv4Private::iid);
-  resolver->Add ("ipv4",
-                 MakeCallback (&Ipv4Private::CreateTraceResolver, PeekPointer (ipv4)),
-                 InternetNode::IPV4);
-
-  return resolver;
+  Node::DoFillTraceResolver (resolver);
+  Ptr<Ipv4L3Protocol> ipv4 = QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+  resolver.Add ("ipv4",
+                MakeCallback (&Ipv4L3Protocol::CreateTraceResolver, PeekPointer (ipv4)));
 }
 
 void 
@@ -97,25 +89,4 @@
   Node::DoDispose ();
 }
 
-void 
-InternetNode::DoAddDevice (Ptr<NetDevice> device)
-{
-  device->SetReceiveCallback (MakeCallback (&InternetNode::ReceiveFromDevice, this));
-}
-
-bool
-InternetNode::ReceiveFromDevice (Ptr<NetDevice> device, const Packet &p, uint16_t protocolNumber) const
-{
-  Ptr<L3Demux> demux = QueryInterface<L3Demux> (L3Demux::iid);
-  Ptr<L3Protocol> target = demux->GetProtocol (protocolNumber);
-  if (target != 0) 
-    {
-      Packet packet = p;
-      target->Receive(packet, device);
-      return true;
-    }
-  return false;
-}
-
-
 }//namespace ns3
--- a/src/internet-node/internet-node.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/internet-node.h	Wed Sep 05 18:35:39 2007 +0100
@@ -36,9 +36,6 @@
 class InternetNode : public Node 
 {
 public:
-  enum TraceType {
-    IPV4,
-  };
   InternetNode();
   InternetNode(uint32_t systemId);
   virtual ~InternetNode ();
@@ -46,8 +43,7 @@
 protected:
   virtual void DoDispose(void);
 private:
-  virtual void DoAddDevice (Ptr<NetDevice> device);
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
+  virtual void DoFillTraceResolver (CompositeTraceResolver &resolver);
   bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &p, uint16_t protocolNumber) const;
   void Construct (void);
 };
--- a/src/internet-node/ipv4-header.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-header.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -28,8 +28,17 @@
 
 namespace ns3 {
 
+NS_HEADER_ENSURE_REGISTERED (Ipv4Header);
+
 bool Ipv4Header::m_calcChecksum = false;
 
+uint32_t
+Ipv4Header::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<Ipv4Header> ("Ipv4Header.ns3");
+  return uid;
+}
+
 Ipv4Header::Ipv4Header ()
   : m_payloadSize (0),
     m_identification (0),
@@ -40,8 +49,6 @@
     m_fragmentOffset (0),
     m_goodChecksum (true)
 {}
-Ipv4Header::~Ipv4Header ()
-{}
 
 void 
 Ipv4Header::EnableChecksums (void)
@@ -180,13 +187,13 @@
 }
 
 std::string 
-Ipv4Header::DoGetName (void) const
+Ipv4Header::GetName (void) const
 {
   return "IPV4";
 }
 
 void 
-Ipv4Header::PrintTo (std::ostream &os) const
+Ipv4Header::Print (std::ostream &os) const
 {
   // ipv4, right ?
   std::string flags;
@@ -229,7 +236,7 @@
 }
 
 void
-Ipv4Header::SerializeTo (Buffer::Iterator start) const
+Ipv4Header::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   
@@ -272,7 +279,7 @@
     }
 }
 uint32_t
-Ipv4Header::DeserializeFrom (Buffer::Iterator start)
+Ipv4Header::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
   uint8_t verIhl = i.ReadU8 ();
--- a/src/internet-node/ipv4-header.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-header.h	Wed Sep 05 18:35:39 2007 +0100
@@ -29,13 +29,14 @@
 /**
  * \brief Packet header for IPv4
  */
-class Ipv4Header : public Header {
+class Ipv4Header : public Header 
+{
 public:
+  static uint32_t GetUid (void);
   /**
    * \brief Construct a null IPv4 header
    */
   Ipv4Header ();
-  virtual ~Ipv4Header ();
   /**
    * \brief Enable checksum calculation for IP (XXX currently has no effect)
    */
@@ -139,12 +140,12 @@
    */
   bool IsChecksumOk (void) const;
 
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
 private:
-  virtual std::string DoGetName (void) const;
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
 
   enum FlagsE {
     DONT_FRAGMENT = (1<<0),
@@ -165,7 +166,7 @@
   bool m_goodChecksum;
 };
 
-}; // namespace ns3
+} // namespace ns3
 
 
 #endif /* IPV4_HEADER_H */
--- a/src/internet-node/ipv4-l3-protocol.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-l3-protocol.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -41,15 +41,86 @@
 
 namespace ns3 {
 
+const InterfaceId Ipv4L3Protocol::iid = MakeInterfaceId ("Ipv4L3Protocol", Object::iid);
 const uint16_t Ipv4L3Protocol::PROT_NUMBER = 0x0800;
 
+Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement ()
+  : m_type (TX)
+{}
+Ipv4L3ProtocolTraceContextElement::Ipv4L3ProtocolTraceContextElement (enum Type type)
+  : m_type (type)
+{}
+bool 
+Ipv4L3ProtocolTraceContextElement::IsTx (void) const
+{
+  return m_type == TX;
+}
+bool 
+Ipv4L3ProtocolTraceContextElement::IsRx (void) const
+{
+  return m_type == RX;
+}
+bool 
+Ipv4L3ProtocolTraceContextElement::IsDrop (void) const
+{
+  return m_type == DROP;
+}
+void 
+Ipv4L3ProtocolTraceContextElement::Print (std::ostream &os) const
+{
+  os << "ipv4=";
+  switch (m_type)
+    {
+    case TX:
+      os << "tx";
+      break;
+    case RX:
+      os << "rx";
+      break;
+    case DROP:
+      os << "drop";
+      break;
+    }
+}
+uint16_t 
+Ipv4L3ProtocolTraceContextElement::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<Ipv4L3ProtocolTraceContextElement> ("Ipv4L3ProtocolTraceContextElement");
+  return uid;
+}
+
+
+Ipv4l3ProtocolInterfaceIndex::Ipv4l3ProtocolInterfaceIndex ()
+  : m_index (0)
+{}
+Ipv4l3ProtocolInterfaceIndex::Ipv4l3ProtocolInterfaceIndex (uint32_t index)
+  : m_index (index)
+{}
+uint32_t 
+Ipv4l3ProtocolInterfaceIndex::Get (void) const
+{
+  return m_index;
+}
+void 
+Ipv4l3ProtocolInterfaceIndex::Print (std::ostream &os) const
+{
+  os << "ipv4-interface=" << m_index;
+}
+uint16_t 
+Ipv4l3ProtocolInterfaceIndex::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<Ipv4l3ProtocolInterfaceIndex> ("Ipv4l3ProtocolInterfaceIndex");
+  return uid;
+}
+
+
 Ipv4L3Protocol::Ipv4L3Protocol(Ptr<Node> node)
-  : L3Protocol (PROT_NUMBER, 4),
-    m_nInterfaces (0),
+  : m_nInterfaces (0),
     m_defaultTtl (64),
     m_identification (0),
     m_node (node)
 {
+  SetInterfaceId (Ipv4L3Protocol::iid);
   m_staticRouting = Create<Ipv4StaticRouting> ();
   AddRoutingProtocol (m_staticRouting, 0);
   SetupLoopback ();
@@ -66,9 +137,9 @@
     }
   m_interfaces.clear ();
   m_node = 0;
-  L3Protocol::DoDispose ();
   m_staticRouting->Dispose ();
   m_staticRouting = 0;
+  Object::DoDispose ();
 }
 
 void
@@ -86,20 +157,19 @@
 Ipv4L3Protocol::CreateTraceResolver (TraceContext const &context)
 {
   CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  resolver->Add ("tx", m_txTrace, Ipv4L3Protocol::TX);
-  resolver->Add ("rx", m_rxTrace, Ipv4L3Protocol::RX);
-  resolver->Add ("drop", m_dropTrace, Ipv4L3Protocol::DROP);
+  resolver->Add ("tx", m_txTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::TX));
+  resolver->Add ("rx", m_rxTrace, Ipv4L3ProtocolTraceContextElement(Ipv4L3ProtocolTraceContextElement::RX));
+  resolver->Add ("drop", m_dropTrace, Ipv4L3ProtocolTraceContextElement (Ipv4L3ProtocolTraceContextElement::DROP));
   resolver->Add ("interfaces", 
-                 MakeCallback (&Ipv4L3Protocol::InterfacesCreateTraceResolver, this), 
-                 Ipv4L3Protocol::INTERFACES);
+                 MakeCallback (&Ipv4L3Protocol::InterfacesCreateTraceResolver, this));
   return resolver;
 }
 
 TraceResolver *
 Ipv4L3Protocol::InterfacesCreateTraceResolver (TraceContext const &context) const
 {
-  ArrayTraceResolver<Ipv4Interface> *resolver = 
-    new ArrayTraceResolver<Ipv4Interface> 
+  ArrayTraceResolver<Ipv4Interface *, Ipv4l3ProtocolInterfaceIndex> *resolver = 
+    new ArrayTraceResolver<Ipv4Interface *,Ipv4l3ProtocolInterfaceIndex> 
     (context,
      MakeCallback (&Ipv4L3Protocol::GetNInterfaces, this),
      MakeCallback (&Ipv4L3Protocol::GetInterface, this));
@@ -240,18 +310,19 @@
 }  
 
 void 
-Ipv4L3Protocol::Receive(Packet& packet, Ptr<NetDevice> device)
+Ipv4L3Protocol::Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from)
 {
   uint32_t index = 0;
   for (Ipv4InterfaceList::const_iterator i = m_interfaces.begin (); i != m_interfaces.end (); i++)
     {
       if ((*i)->GetDevice () == device)
         {
-          m_rxTrace (packet, index);
+          m_rxTrace (p, index);
           break;
         }
       index++;
     }
+  Packet packet = p;
   Ipv4Header ipHeader;
   packet.RemoveHeader (ipHeader);
 
--- a/src/internet-node/ipv4-l3-protocol.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-l3-protocol.h	Wed Sep 05 18:35:39 2007 +0100
@@ -25,12 +25,11 @@
 #include <list>
 #include <stdint.h>
 #include "ns3/callback-trace-source.h"
-#include "ns3/array-trace-resolver.h"
+#include "ns3/trace-context-element.h"
 #include "ns3/ipv4-address.h"
-#include "ipv4-header.h"
 #include "ns3/ptr.h"
 #include "ns3/ipv4.h"
-#include "l3-protocol.h"
+#include "ipv4-header.h"
 #include "ipv4-static-routing.h"
 
 namespace ns3 {
@@ -45,19 +44,43 @@
 class TraceResolver;
 class TraceContext;
 
-
-class Ipv4L3Protocol : public L3Protocol 
+class Ipv4L3ProtocolTraceContextElement : public TraceContextElement
 {
 public:
-  static const uint16_t PROT_NUMBER;
-
-  enum TraceType {
+  enum Type {
     TX,
     RX,
     DROP,
-    INTERFACES,
   };
-  typedef ArrayTraceResolver<Ipv4Interface>::Index InterfaceIndex;
+  Ipv4L3ProtocolTraceContextElement ();
+  Ipv4L3ProtocolTraceContextElement (enum Type type);
+  bool IsTx (void) const;
+  bool IsRx (void) const;
+  bool IsDrop (void) const;
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+private:
+  enum Type m_type;
+};
+
+class Ipv4l3ProtocolInterfaceIndex : public TraceContextElement
+{
+public:
+  Ipv4l3ProtocolInterfaceIndex ();
+  Ipv4l3ProtocolInterfaceIndex (uint32_t index);
+  uint32_t Get (void) const;
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+private:
+  uint32_t m_index;
+};
+
+
+class Ipv4L3Protocol : public Object
+{
+public:
+  static const InterfaceId iid;
+  static const uint16_t PROT_NUMBER;
 
   Ipv4L3Protocol(Ptr<Node> node);
   virtual ~Ipv4L3Protocol ();
@@ -95,7 +118,7 @@
    *    - implement a per-NetDevice ARP cache
    *    - send back arp replies on the right device
    */
-  virtual void Receive(Packet& p, Ptr<NetDevice> device);
+  void Receive( Ptr<NetDevice> device, const Packet& p, uint16_t protocol, const Address &from);
 
   /**
    * \param packet packet to send
--- a/src/internet-node/ipv4-l4-demux.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-l4-demux.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -32,6 +32,30 @@
 
 const InterfaceId Ipv4L4Demux::iid = MakeInterfaceId ("Ipv4L4Demux", Object::iid);
 
+Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement ()
+  : m_protocolNumber (0)
+{}
+Ipv4L4ProtocolTraceContextElement::Ipv4L4ProtocolTraceContextElement (int protocolNumber)
+  : m_protocolNumber (protocolNumber)
+{}
+int 
+Ipv4L4ProtocolTraceContextElement::Get (void) const
+{
+  return m_protocolNumber;
+}
+void 
+Ipv4L4ProtocolTraceContextElement::Print (std::ostream &os) const
+{
+  os << "ipv4-protocol=0x" << std::hex << m_protocolNumber << std::dec;
+}
+uint16_t 
+Ipv4L4ProtocolTraceContextElement::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<Ipv4L4ProtocolTraceContextElement> ("Ipv4L4ProtocolTraceContextElement");
+  return uid;
+}
+
+
 Ipv4L4Demux::Ipv4L4Demux (Ptr<Node> node)
   : m_node (node)
 {
@@ -64,7 +88,7 @@
       std::string protValue;
       std::ostringstream oss (protValue);
       oss << (*i)->GetProtocolNumber ();
-      Ipv4L4ProtocolTraceType protocolNumber = (*i)->GetProtocolNumber ();
+      Ipv4L4ProtocolTraceContextElement protocolNumber = (*i)->GetProtocolNumber ();
       resolver->Add (protValue,
                      MakeCallback (&Ipv4L4Protocol::CreateTraceResolver, PeekPointer (protocol)),
                      protocolNumber);
--- a/src/internet-node/ipv4-l4-demux.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-l4-demux.h	Wed Sep 05 18:35:39 2007 +0100
@@ -28,6 +28,7 @@
 #include <list>
 #include "ns3/object.h"
 #include "ns3/ptr.h"
+#include "ns3/trace-context-element.h"
 
 namespace ns3 {
 
@@ -36,6 +37,18 @@
 class TraceResolver;
 class TraceContext;
 
+class Ipv4L4ProtocolTraceContextElement : public TraceContextElement
+{
+public:
+  Ipv4L4ProtocolTraceContextElement ();
+  Ipv4L4ProtocolTraceContextElement (int protocolNumber);
+  int Get (void) const;
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+private:
+  int m_protocolNumber;
+};
+
 /**
  * \brief L4 Ipv4 Demux
  */
@@ -43,7 +56,6 @@
 {
 public:
   static const InterfaceId iid;
-  typedef int Ipv4L4ProtocolTraceType;
   Ipv4L4Demux (Ptr<Node> node);
   virtual ~Ipv4L4Demux();
 
--- a/src/internet-node/ipv4-loopback-interface.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-loopback-interface.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -22,8 +22,9 @@
 #include "ns3/empty-trace-resolver.h"
 #include "ns3/net-device.h"
 #include "ns3/node.h"
+#include "ns3/eui48-address.h"
 #include "ipv4-loopback-interface.h"
-#include "ipv4-private.h"
+#include "ipv4-l3-protocol.h"
 
 namespace ns3 {
 
@@ -43,8 +44,8 @@
 void 
 Ipv4LoopbackInterface::SendTo (Packet packet, Ipv4Address dest)
 {
-  Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
-  ipv4->Receive (packet, GetDevice ());
+  Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
+  ipv4->Receive (GetDevice (), packet, Ipv4L3Protocol::PROT_NUMBER, Eui48Address ("ff:ff:ff:ff:ff:ff"));
 }
 
 }//namespace ns3
--- a/src/internet-node/ipv4-private.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* -*- 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 "ipv4-private.h"
-#include "ipv4-l3-protocol.h"
-#include "ns3/assert.h"
-#include "ns3/net-device.h"
-
-namespace ns3 {
-
-const InterfaceId Ipv4Private::iid = MakeInterfaceId ("Ipv4Private", Object::iid);
-
-Ipv4Private::Ipv4Private (Ptr<Ipv4L3Protocol> ipv4)
-  : m_ipv4 (ipv4)
-{
-  SetInterfaceId (Ipv4Private::iid);
-}
-Ipv4Private::~Ipv4Private ()
-{
-  NS_ASSERT (m_ipv4 == 0);
-}
-TraceResolver *
-Ipv4Private::CreateTraceResolver (TraceContext const &context)
-{
-  return m_ipv4->CreateTraceResolver (context);
-}
-void 
-Ipv4Private::Send (Packet const &packet, Ipv4Address source, 
-		    Ipv4Address destination, uint8_t protocol)
-{
-  m_ipv4->Send (packet, source, destination, protocol);
-}
-Ipv4Interface *
-Ipv4Private::FindInterfaceForDevice (Ptr<const NetDevice>device)
-{
-  return m_ipv4->FindInterfaceForDevice (device);
-}
-void 
-Ipv4Private::Receive(Packet& p, Ptr<NetDevice> device)
-{
-  m_ipv4->Receive (p, device);
-}
-void 
-Ipv4Private::DoDispose (void)
-{
-  m_ipv4 = 0;
-  Object::DoDispose ();
-}
-
-} // namespace ns3
--- a/src/internet-node/ipv4-private.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/* -*- 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 IPV4_PRIVATE_H
-#define IPV4_PRIVATE_H
-
-#include "ns3/object.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/ptr.h"
-#include <stdint.h>
-
-namespace ns3 {
-
-class Packet;
-class Ipv4L3Protocol;
-class TraceContext;
-class TraceResolver;
-class Ipv4Interface;
-class NetDevice;
-
-class Ipv4Private : public Object
-{
-public:
-  static const InterfaceId iid;
-  Ipv4Private (Ptr<Ipv4L3Protocol> ipv4);
-  virtual ~Ipv4Private ();
-
-  TraceResolver *CreateTraceResolver (TraceContext const &context);
-  void Send (Packet const &packet, Ipv4Address source, 
-	     Ipv4Address destination, uint8_t protocol);
-  Ipv4Interface *FindInterfaceForDevice (Ptr<const NetDevice>device);
-  void Receive(Packet& p, Ptr<NetDevice> device);
-protected:
-  virtual void DoDispose (void);
-private:
-  Ptr<Ipv4L3Protocol> m_ipv4;
-};
-
-} // namespace ns3
-
-#endif /* IPV4_PRIVATE_H */
--- a/src/internet-node/ipv4-static-routing.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/ipv4-static-routing.h	Wed Sep 05 18:35:39 2007 +0100
@@ -31,7 +31,6 @@
 #include "ipv4-header.h"
 #include "ns3/ptr.h"
 #include "ns3/ipv4.h"
-#include "l3-protocol.h"
 
 namespace ns3 {
 
--- a/src/internet-node/l3-demux.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-// Implement the L3Protocols capability for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-#include <sstream>
-#include <string>
-#include "ns3/composite-trace-resolver.h"
-#include "ns3/node.h"
-#include "l3-demux.h"
-#include "l3-protocol.h"
-
-namespace ns3 {
-
-const InterfaceId L3Demux::iid = MakeInterfaceId ("L3Demux", Object::iid);
-
-L3Demux::L3Demux (Ptr<Node> node)
-  : m_node (node)
-{
-  SetInterfaceId (L3Demux::iid);
-}
-
-L3Demux::~L3Demux()
-{}
-
-void
-L3Demux::DoDispose (void)
-{
-  for (L3Map_t::iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
-    {
-      i->second->Dispose ();
-      i->second = 0;
-    }
-  m_protocols.clear ();
-  m_node = 0;
-  Object::DoDispose ();
-}
-
-TraceResolver *
-L3Demux::CreateTraceResolver (TraceContext const &context) const
-{
-  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  for (L3Map_t::const_iterator i = m_protocols.begin(); i != m_protocols.end(); ++i)
-    {
-      std::string protValue;
-      std::ostringstream oss (protValue);
-      oss << i->second->GetProtocolNumber ();
-      ProtocolTraceType context = i->second->GetProtocolNumber ();
-      resolver->Add (protValue, 
-                     MakeCallback (&L3Protocol::CreateTraceResolver, PeekPointer (i->second)),
-                     context);
-    }
-  return resolver;
-}
-  
-void L3Demux::Insert(Ptr<L3Protocol> p)
-{
-  m_protocols.insert(L3Map_t::value_type(p->GetProtocolNumber (), p));
-}
-
-Ptr<L3Protocol>
-L3Demux::GetProtocol (int p)
-{ // Look up a protocol by protocol number
-  L3Map_t::iterator i = m_protocols.find(p);
-  if (i == m_protocols.end()) 
-    {
-      return 0;
-    }
-  return i->second; // Return the protocol
-}
-
-} //namespace ns3  
-  
--- a/src/internet-node/l3-demux.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-// Define the L3Protocols capability for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
-// This object manages the different layer 3 protocols for any ns3
-// node that has this capability.  
-
-#ifndef L3_DEMUX_H
-#define L3_DEMUX_H
-
-#include <map>
-#include "ns3/object.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class L3Protocol;
-class Node;
-class TraceResolver;
-class TraceContext;
-
-/**
- * \brief L3 Demux 
- */
-class L3Demux : public Object
-{
-public:
-  static const InterfaceId iid;
-  typedef int ProtocolTraceType;
-  L3Demux(Ptr<Node> node);
-  virtual ~L3Demux();
-
-  /**
-   * \param context the trace context to use to construct the
-   *        TraceResolver to return
-   * \returns a TraceResolver which can resolve all traces
-   *          performed in this object. The caller must
-   *          delete the returned object.
-   */
-  TraceResolver *CreateTraceResolver (TraceContext const &context) const;
-
-
-  /**
-   * \param protocol a template for the protocol to add to this L3 Demux.
-   *
-   * Invoke Copy on the input template to get a copy of the input
-   * protocol which can be used on the Node on which this L3 Demux 
-   * is running. The new L3Protocol is registered internally as
-   * a working L3 Protocol and returned from this method.
-   * The caller does not get ownership of the returned pointer.
-   */
-  void Insert(Ptr<L3Protocol> protocol);
-  /**
-   * \param protocolNumber number of protocol to lookup
-   *        in this L4 Demux
-   * \returns a matching L3 Protocol
-   *
-   * This method is typically called by lower layers
-   * to forward packets up the stack to the right protocol.
-   * It is also called from NodeImpl::GetIpv4 for example.
-   */
-  Ptr<L3Protocol> GetProtocol (int protocolNumber);
-protected:
-  virtual void DoDispose (void);
-private:
-  typedef std::map<int, Ptr<ns3::L3Protocol> > L3Map_t;
-
-  Ptr<Node> m_node;
-  L3Map_t m_protocols;
-};
-
-} //namespace ns3
-#endif
-
--- a/src/internet-node/l3-protocol.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-
-// NS3 - Layer 3 Protocol base class
-// George F. Riley, Georgia Tech, Spring 2007
-
-#include "l3-protocol.h"
-
-
-namespace ns3 {
-
-L3Protocol::L3Protocol(int protocolNumber, int version)
-    : m_protocolNumber (protocolNumber),
-      m_version (version)
-{}
-L3Protocol::~L3Protocol ()
-{}
-
-int 
-L3Protocol::GetProtocolNumber (void) const
-{
-  return m_protocolNumber;
-}
-int 
-L3Protocol::GetVersion() const
-{
-  return m_version;
-}
-
-void
-L3Protocol::DoDispose (void)
-{
-  Object::DoDispose ();
-}
-
-}//namespace ns3
--- a/src/internet-node/l3-protocol.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-
-// NS3 - Layer 3 Protocol base class
-// George F. Riley, Georgia Tech, Spring 2007
-
-#ifndef L3_PROTOCOL_H
-#define L3_PROTOCOL_H
-
-#include "ns3/object.h"
-#include "ns3/ptr.h"
-
-namespace ns3 {
-
-class Packet;
-class NetDevice;
-class TraceResolver;
-class TraceContext;
-
-/**
- * ::Send is always defined in subclasses.
- */
-class L3Protocol : public Object {
-public:
-  L3Protocol(int protocolNumber, int version);
-  virtual ~L3Protocol ();
-  /**
-   * \return The protocol number of this Layer 3 protocol
-   */  
-  int GetProtocolNumber (void) const;
-  /**
-   * \return The version number of this protocol
-   */
-  int GetVersion() const;
-
-  virtual TraceResolver *CreateTraceResolver (TraceContext const &context) = 0;
-  /**
-   * Lower layer calls this method after calling L3Demux::Lookup
-   * The ARP subclass needs to know from which NetDevice this
-   * packet is coming to:
-   *    - implement a per-NetDevice ARP cache
-   *    - send back arp replies on the right device
-   */
-  virtual void Receive(Packet& p, Ptr<NetDevice> device) = 0;
-
-protected:
-  virtual void DoDispose (void);
-private:
-  int m_protocolNumber;
-  int m_version;
-};
-
-} // Namespace ns3
-
-#endif
--- a/src/internet-node/pcap-trace.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/pcap-trace.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -82,10 +82,9 @@
 void 
 PcapTrace::LogIp (TraceContext const &context, Packet const &p, uint32_t interfaceIndex)
 {
-  NodeList::NodeIndex nodeIndex;
+  NodeListIndex nodeIndex;
   context.Get (nodeIndex);
-  uint32_t nodeId = NodeList::GetNode (nodeIndex)->GetId ();
-  PcapWriter *writer = GetStream (nodeId, interfaceIndex);
+  PcapWriter *writer = GetStream (nodeIndex.Get (), interfaceIndex);
   writer->WritePacket (p);
 }
 
--- a/src/internet-node/udp-header.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-header.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -24,8 +24,17 @@
 
 namespace ns3 {
 
+NS_HEADER_ENSURE_REGISTERED (UdpHeader);
+
 bool UdpHeader::m_calcChecksum = false;
 
+uint32_t
+UdpHeader::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<UdpHeader> ("UdpHeader.ns3");
+  return uid;
+}
+
 /* The magic values below are used only for debugging.
  * They can be used to easily detect memory corruption
  * problems so you can see the patterns in memory.
@@ -84,7 +93,7 @@
   destination.Serialize (buf+4);
   buf[8] = 0;
   buf[9] = protocol;
-  uint16_t udpLength = m_payloadSize + GetSize ();
+  uint16_t udpLength = m_payloadSize + GetSerializedSize ();
   buf[10] = udpLength >> 8;
   buf[11] = udpLength & 0xff;
 
@@ -92,16 +101,16 @@
 }
 
 std::string 
-UdpHeader::DoGetName (void) const
+UdpHeader::GetName (void) const
 {
   return "UDP";
 }
 
 void 
-UdpHeader::PrintTo (std::ostream &os) const
+UdpHeader::Print (std::ostream &os) const
 {
   os << "(" 
-     << "length: " << m_payloadSize + GetSize ()
+     << "length: " << m_payloadSize + GetSerializedSize ()
      << ") "
      << m_sourcePort << " > " << m_destinationPort
     ;
@@ -114,12 +123,12 @@
 }
 
 void
-UdpHeader::SerializeTo (Buffer::Iterator start) const
+UdpHeader::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   i.WriteHtonU16 (m_sourcePort);
   i.WriteHtonU16 (m_destinationPort);
-  i.WriteHtonU16 (m_payloadSize + GetSize ());
+  i.WriteHtonU16 (m_payloadSize + GetSerializedSize ());
   i.WriteU16 (0);
 
   if (m_calcChecksum) 
@@ -128,7 +137,7 @@
       //XXXX
       uint16_t checksum = Ipv4ChecksumCalculate (m_initialChecksum, 
                                                   buffer->PeekData (), 
-                                                  GetSize () + m_payloadSize);
+                                                  GetSerializedSize () + m_payloadSize);
       checksum = Ipv4ChecksumComplete (checksum);
       i = buffer->Begin ();
       i.Next (6);
@@ -137,12 +146,12 @@
     }
 }
 uint32_t
-UdpHeader::DeserializeFrom (Buffer::Iterator start)
+UdpHeader::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
   m_sourcePort = i.ReadNtohU16 ();
   m_destinationPort = i.ReadNtohU16 ();
-  m_payloadSize = i.ReadNtohU16 () - GetSize ();
+  m_payloadSize = i.ReadNtohU16 () - GetSerializedSize ();
   if (m_calcChecksum) 
     {
       // XXX verify checksum.
--- a/src/internet-node/udp-header.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-header.h	Wed Sep 05 18:35:39 2007 +0100
@@ -23,6 +23,7 @@
 #define UDP_HEADER_H
 
 #include <stdint.h>
+#include <string>
 #include "ns3/header.h"
 #include "ns3/ipv4-address.h"
 
@@ -30,15 +31,18 @@
 /**
  * \brief Packet header for UDP packets
  */
-class UdpHeader : public Header {
+class UdpHeader : public Header 
+{
 public:
+  static uint32_t GetUid (void);
+
   /**
    * \brief Constructor
    *
    * Creates a null header
    */
   UdpHeader ();
-  virtual ~UdpHeader ();
+  ~UdpHeader ();
 
   /**
    * \brief Enable checksum calculation for UDP (XXX currently has no effect)
@@ -80,13 +84,13 @@
                            Ipv4Address destination,
                            uint8_t protocol);
 
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
+
 private:
-  virtual std::string DoGetName (void) const;
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
-
   uint16_t m_sourcePort;
   uint16_t m_destinationPort;
   uint16_t m_payloadSize;
@@ -95,6 +99,6 @@
   static bool m_calcChecksum;
 };
 
-}; // namespace ns3
+} // namespace ns3
 
 #endif /* UDP_HEADER */
--- a/src/internet-node/udp-l4-protocol.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-l4-protocol.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -29,8 +29,6 @@
 #include "ipv4-end-point-demux.h"
 #include "ipv4-end-point.h"
 #include "ipv4-l3-protocol.h"
-#include "ipv4-private.h"
-#include "l3-demux.h"
 #include "udp-socket.h"
 
 namespace ns3 {
@@ -138,7 +136,7 @@
 
   packet.AddHeader (udpHeader);
 
-  Ptr<Ipv4Private> ipv4 = m_node->QueryInterface<Ipv4Private> (Ipv4Private::iid);
+  Ptr<Ipv4L3Protocol> ipv4 = m_node->QueryInterface<Ipv4L3Protocol> (Ipv4L3Protocol::iid);
   if (ipv4 != 0)
     {
       ipv4->Send (packet, saddr, daddr, PROT_NUMBER);
--- a/src/internet-node/udp-socket.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-socket.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -19,6 +19,7 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "ns3/node.h"
+#include "ns3/inet-socket-address.h"
 #include "udp-socket.h"
 #include "udp-l4-protocol.h"
 #include "ipv4-end-point.h"
@@ -56,6 +57,12 @@
   m_udp = 0;
 }
 
+enum Socket::SocketErrno
+UdpSocket::GetErrno (void) const
+{
+  return m_errno;
+}
+
 Ptr<Node>
 UdpSocket::GetNode (void) const
 {
@@ -72,12 +79,12 @@
 int
 UdpSocket::FinishBind (void)
 {
-  m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this));
-  m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this));
   if (m_endPoint == 0)
     {
       return -1;
     }
+  m_endPoint->SetRxCallback (MakeCallback (&UdpSocket::ForwardUp, this));
+  m_endPoint->SetDestroyCallback (MakeCallback (&UdpSocket::Destroy, this));
   return 0;
 }
 
@@ -88,29 +95,35 @@
   return FinishBind ();
 }
 int 
-UdpSocket::Bind (Ipv4Address address)
-{
-  m_endPoint = m_udp->Allocate (address);
-  return FinishBind ();
-}
-int 
-UdpSocket::Bind (uint16_t port)
+UdpSocket::Bind (const Address &address)
 {
-  m_endPoint = m_udp->Allocate (port);
-  return FinishBind ();
-}
-int 
-UdpSocket::Bind (Ipv4Address address, uint16_t port)
-{
-  m_endPoint = m_udp->Allocate (address, port);
+  if (!InetSocketAddress::IsMatchingType (address))
+    {
+      return ERROR_INVAL;
+    }
+  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+  Ipv4Address ipv4 = transport.GetIpv4 ();
+  uint16_t port = transport.GetPort ();
+  if (ipv4 == Ipv4Address::GetAny () && port == 0)
+    {
+      m_endPoint = m_udp->Allocate ();
+    }
+  else if (ipv4 == Ipv4Address::GetAny () && port != 0)
+    {
+      m_endPoint = m_udp->Allocate (port);
+    }
+  else if (ipv4 != Ipv4Address::GetAny () && port == 0)
+    {
+      m_endPoint = m_udp->Allocate (ipv4);
+    }
+  else if (ipv4 != Ipv4Address::GetAny () && port != 0)
+    {
+      m_endPoint = m_udp->Allocate (ipv4, port);
+    }
+
   return FinishBind ();
 }
 
-enum Socket::SocketErrno
-UdpSocket::GetErrno (void) const
-{
-  return m_errno;
-}
 int 
 UdpSocket::ShutdownSend (void)
 {
@@ -124,63 +137,43 @@
   return 0;
 }
 
-void 
-UdpSocket::DoClose(ns3::Callback<void, Ptr<Socket> > closeCompleted)
-{
-  // XXX: we should set the close state and check it in all API methods.
-  if (!closeCompleted.IsNull ())
-    {
-      closeCompleted (this);
-    }
-}
-void 
-UdpSocket::DoConnect(const Ipv4Address & address,
-                     uint16_t portNumber,
-                     ns3::Callback<void, Ptr<Socket> > connectionSucceeded,
-                     ns3::Callback<void, Ptr<Socket> > connectionFailed,
-                     ns3::Callback<void, Ptr<Socket> > halfClose)
+int
+UdpSocket::Close(void)
 {
-  m_defaultAddress = address;
-  m_defaultPort = portNumber;
-  if (!connectionSucceeded.IsNull ())
-    {
-      connectionSucceeded (this);
-    }
-  m_connected = true;
+  NotifyCloseCompleted ();
+  return 0;
 }
+
 int
-UdpSocket::DoAccept(ns3::Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
-                    ns3::Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
-                    ns3::Callback<void, Ptr<Socket> > closeRequested)
+UdpSocket::Connect(const Address & address)
 {
-  // calling accept on a udp socket is a programming error.
-  m_errno = ERROR_OPNOTSUPP;
-  return -1;
+  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+  m_defaultAddress = transport.GetIpv4 ();
+  m_defaultPort = transport.GetPort ();
+  NotifyConnectionSucceeded ();
+  m_connected = true;
+  return 0;
 }
 int 
-UdpSocket::DoSend (const uint8_t* buffer,
-                   uint32_t size,
-                   ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::Send (const Packet &p)
 {
   if (!m_connected)
     {
       m_errno = ERROR_NOTCONN;
       return -1;
     }
-  Packet p;
-  if (buffer == 0)
-    {
-      p = Packet (size);
-    }
-  else
-    {
-      p = Packet (buffer, size);
-    }
-  return DoSendPacketTo (p, m_defaultAddress, m_defaultPort, dataSent);
+  return DoSendTo (p, m_defaultAddress, m_defaultPort);
 }
 int
-UdpSocket::DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport,
-                           ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::DoSendTo (const Packet &p, const Address &address)
+{
+  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+  Ipv4Address ipv4 = transport.GetIpv4 ();
+  uint16_t port = transport.GetPort ();
+  return DoSendTo (p, ipv4, port);
+}
+int
+UdpSocket::DoSendTo (const Packet &p, Ipv4Address ipv4, uint16_t port)
 {
   if (m_endPoint == 0)
     {
@@ -196,64 +189,36 @@
       m_errno = ERROR_SHUTDOWN;
       return -1;
     }
-  m_udp->Send (p, m_endPoint->GetLocalAddress (), daddr,
-		   m_endPoint->GetLocalPort (), dport);
-  if (!dataSent.IsNull ())
-    {
-      dataSent (this, p.GetSize ());
-    }
+  m_udp->Send (p, m_endPoint->GetLocalAddress (), ipv4,
+		   m_endPoint->GetLocalPort (), port);
+  NotifyDataSent (p.GetSize ());
   return 0;
 }
 int 
-UdpSocket::DoSendTo(const Ipv4Address &address,
-                    uint16_t port,
-                    const uint8_t *buffer,
-                    uint32_t size,
-                    ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent)
+UdpSocket::SendTo(const Address &address, const Packet &p)
 {
   if (m_connected)
     {
       m_errno = ERROR_ISCONN;
       return -1;
     }
-  Packet p;
-  if (buffer == 0)
-    {
-      p = Packet (size);
-    }
-  else
-    {
-      p = Packet (buffer, size);
-    }
-  return DoSendPacketTo (p, address, port, dataSent);
-}
-void 
-UdpSocket::DoRecv(ns3::Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
-  m_rxCallback = callback;
-}
-void 
-UdpSocket::DoRecvDummy(ns3::Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> callback)
-{
-  m_dummyRxCallback = callback;
+  InetSocketAddress transport = InetSocketAddress::ConvertFrom (address);
+  Ipv4Address ipv4 = transport.GetIpv4 ();
+  uint16_t port = transport.GetPort ();
+  return DoSendTo (p, ipv4, port);
 }
 
 void 
-UdpSocket::ForwardUp (const Packet &packet, Ipv4Address saddr, uint16_t sport)
+UdpSocket::ForwardUp (const Packet &packet, Ipv4Address ipv4, uint16_t port)
 {
   if (m_shutdownRecv)
     {
       return;
     }
+  
+  Address address = InetSocketAddress (ipv4, port);
   Packet p = packet;
-  if (!m_dummyRxCallback.IsNull ())
-    {
-      m_dummyRxCallback (this, p.GetSize (), saddr, sport);
-    }
-  if (!m_rxCallback.IsNull ())
-    {
-      m_rxCallback (this, p.PeekData (), p.GetSize (), saddr, sport);
-    }
+  NotifyDataReceived (p, address);
 }
 
 }//namespace ns3
--- a/src/internet-node/udp-socket.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/udp-socket.h	Wed Sep 05 18:35:39 2007 +0100
@@ -25,6 +25,7 @@
 #include "ns3/callback.h"
 #include "ns3/socket.h"
 #include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
 
 namespace ns3 {
 
@@ -45,49 +46,32 @@
   virtual enum SocketErrno GetErrno (void) const;
   virtual Ptr<Node> GetNode (void) const;
   virtual int Bind (void);
-  virtual int Bind (Ipv4Address address);
-  virtual int Bind (uint16_t port); 
-  virtual int Bind (Ipv4Address address, uint16_t port);
+  virtual int Bind (const Address &address);
+  virtual int Close (void);
   virtual int ShutdownSend (void);
   virtual int ShutdownRecv (void);
+  virtual int Connect(const Address &address);
+  virtual int Send (const Packet &p);
+  virtual int SendTo(const Address &address,const Packet &p);
 
 private:
-  virtual void DoClose(ns3::Callback<void, Ptr<Socket> > closeCompleted);
-  virtual void DoConnect(const Ipv4Address & address,
-			 uint16_t portNumber,
-			 ns3::Callback<void, Ptr<Socket> > connectionSucceeded,
-			 ns3::Callback<void, Ptr<Socket> > connectionFailed,
-			 ns3::Callback<void, Ptr<Socket> > halfClose);
-  virtual int DoAccept(ns3::Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
-		       ns3::Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
-		       ns3::Callback<void, Ptr<Socket> > closeRequested);
-  virtual int DoSend (const uint8_t* buffer,
-                    uint32_t size,
-                    ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
-  virtual int DoSendTo(const Ipv4Address &address,
-                      uint16_t port,
-                      const uint8_t *buffer,
-                      uint32_t size,
-                      ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
-  virtual void DoRecv(ns3::Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t>);
-  virtual void DoRecvDummy(ns3::Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t>);
 
 private:
   friend class Udp;
   // invoked by Udp class
   int FinishBind (void);
-  void ForwardUp (const Packet &p, Ipv4Address saddr, uint16_t sport);
+  void ForwardUp (const Packet &p, Ipv4Address ipv4, uint16_t port);
   void Destroy (void);
-  int DoSendPacketTo (const Packet &p, Ipv4Address daddr, uint16_t dport,
-		      ns3::Callback<void, Ptr<Socket>, uint32_t> dataSent);
+  int DoSendTo (const Packet &p, const Address &daddr);
+  int DoSendTo (const Packet &p, Ipv4Address daddr, uint16_t dport);
 
   Ipv4EndPoint *m_endPoint;
   Ptr<Node> m_node;
   Ptr<UdpL4Protocol> m_udp;
   Ipv4Address m_defaultAddress;
   uint16_t m_defaultPort;
-  Callback<void,Ptr<Socket>,uint32_t,const Ipv4Address &,uint16_t> m_dummyRxCallback;
-  Callback<void,Ptr<Socket>,uint8_t const*,uint32_t,const Ipv4Address &,uint16_t> m_rxCallback;
+  Callback<void,Ptr<Socket>,uint32_t,const Address &> m_dummyRxCallback;
+  Callback<void,Ptr<Socket>,uint8_t const*,uint32_t,const Address &> m_rxCallback;
   enum SocketErrno m_errno;
   bool m_shutdownSend;
   bool m_shutdownRecv;
--- a/src/internet-node/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/internet-node/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -2,14 +2,9 @@
 
 
 def build(bld):
-    obj = bld.create_obj('cpp', 'shlib')
-    obj.name = 'ns3-internet-node'
-    obj.target = obj.name
-    obj.uselib_local = ['ns3-node', 'ns3-applications']
+    obj = bld.create_ns3_module('internet-node', ['node', 'applications'])
     obj.source = [
         'internet-node.cc',
-        'l3-demux.cc',
-        'l3-protocol.cc',
         'ipv4-l4-demux.cc',
         'ipv4-l4-protocol.cc',
         'ipv4-header.cc',
@@ -27,9 +22,7 @@
         'ipv4-loopback-interface.cc',
         'udp-socket.cc',
         'ipv4-end-point-demux.cc',
-        'arp-private.cc',
         'ipv4-impl.cc',
-        'ipv4-private.cc',
         'ascii-trace.cc',
         'pcap-trace.cc',
         'udp-impl.cc',
@@ -41,4 +34,5 @@
         'ascii-trace.h',
         'pcap-trace.h',
         'ipv4-header.h',
+        'udp-header.h',
         ]
--- a/src/mobility/mobility-model.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/mobility-model.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -52,9 +52,9 @@
 }
 
 double 
-MobilityModel::GetDistanceFrom (const MobilityModel &other) const
+MobilityModel::GetDistanceFrom (Ptr<const MobilityModel> other) const
 {
-  Position oPosition = other.DoGet ();
+  Position oPosition = other->DoGet ();
   Position position = DoGet ();
   return CalculateDistance (position, oPosition);
 }
--- a/src/mobility/mobility-model.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/mobility-model.h	Wed Sep 05 18:35:39 2007 +0100
@@ -57,7 +57,7 @@
    * \param position a reference to another mobility model
    * \returns the distance between the two objects. Unit is meters.
    */
-  double GetDistanceFrom (const MobilityModel &position) const;
+  double GetDistanceFrom (Ptr<const MobilityModel> position) const;
 protected:
   /**
    * Must be invoked by subclasses when the course of the
--- a/src/mobility/position.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/position.h	Wed Sep 05 18:35:39 2007 +0100
@@ -1,3 +1,4 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 #ifndef POSITION_H
 #define POSITION_H
 
--- a/src/mobility/random-position.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/random-position.h	Wed Sep 05 18:35:39 2007 +0100
@@ -1,3 +1,4 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 #ifndef RANDOM_POSITION_H
 #define RANDOM_POSITION_H
 
--- a/src/mobility/speed.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/speed.h	Wed Sep 05 18:35:39 2007 +0100
@@ -1,3 +1,4 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 #ifndef SPEED_H
 #define SPEED_H
 
--- a/src/mobility/static-speed-helper.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/static-speed-helper.h	Wed Sep 05 18:35:39 2007 +0100
@@ -1,3 +1,4 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
 #ifndef STATIC_SPEED_HELPER_H
 #define STATIC_SPEED_HELPER_H
 
--- a/src/mobility/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/mobility/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -1,10 +1,7 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
 def build(bld):
-    mobility = bld.create_obj('cpp', 'shlib')
-    mobility.name = 'ns3-mobility'
-    mobility.target = mobility.name
-    mobility.uselib_local = ['ns3-core', 'ns3-simulator']
+    mobility = bld.create_ns3_module('mobility', ['core', 'simulator'])
     mobility.source = [
         'grid-topology.cc',
         'hierarchical-mobility-model.cc',
--- a/src/node/address-utils.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/address-utils.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -26,24 +26,34 @@
 {
   i.WriteHtonU32 (ad.GetHostOrder ());
 }
-void WriteTo (Buffer::Iterator &i, MacAddress ad)
+void WriteTo (Buffer::Iterator &i, const Address &ad)
 {
-  uint8_t mac[MacAddress::MAX_LEN];
-  ad.Peek (mac);
+  uint8_t mac[Address::MAX_SIZE];
+  ad.CopyTo (mac);
   i.Write (mac, ad.GetLength ());
 }
+void WriteTo (Buffer::Iterator &i, Eui48Address ad)
+{
+  uint8_t mac[6];
+  ad.CopyTo (mac);
+  i.Write (mac, 6);
+}
 
 void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad)
 {
   ad.SetHostOrder (i.ReadNtohU32 ());
 }
-void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len)
+void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len)
 {
-  uint8_t mac[MacAddress::MAX_LEN];
+  uint8_t mac[Address::MAX_SIZE];
   i.Read (mac, len);
-  ad.Set (mac, len);
+  ad.CopyFrom (mac, len);
+}
+void ReadFrom (Buffer::Iterator &i, Eui48Address &ad)
+{
+  uint8_t mac[6];
+  i.Read (mac, 6);
+  ad.CopyFrom (mac);
 }
 
-
-
-}; // namespace ns3
+} // namespace ns3
--- a/src/node/address-utils.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/address-utils.h	Wed Sep 05 18:35:39 2007 +0100
@@ -22,16 +22,19 @@
 #define ADDRESS_UTILS_H
 
 #include "ns3/buffer.h"
-#include "ns3/ipv4-address.h"
-#include "ns3/mac-address.h"
+#include "ipv4-address.h"
+#include "address.h"
+#include "eui48-address.h"
 
 namespace ns3 {
 
 void WriteTo (Buffer::Iterator &i, Ipv4Address ad);
-void WriteTo (Buffer::Iterator &i, MacAddress ad);
+void WriteTo (Buffer::Iterator &i, const Address &ad);
+void WriteTo (Buffer::Iterator &i, Eui48Address ad);
 
 void ReadFrom (Buffer::Iterator &i, Ipv4Address &ad);
-void ReadFrom (Buffer::Iterator &i, MacAddress &ad, uint32_t len);
+void ReadFrom (Buffer::Iterator &i, Address &ad, uint32_t len);
+void ReadFrom (Buffer::Iterator &i, Eui48Address &ad);
 
 };
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,164 @@
+#include "ns3/assert.h"
+#include "address.h"
+#include <iostream>
+#include <iomanip>
+
+namespace ns3 {
+
+Address::Address ()
+  : m_type (0),
+    m_len (0)
+{
+  memset (m_data, 0, m_len);
+}
+
+Address::Address (uint8_t type, const uint8_t *buffer, uint8_t len)
+  : m_type (type),
+    m_len (len)
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  memset (m_data, 0, m_len);
+  memcpy (m_data, buffer, m_len);
+}
+Address::Address (const Address & address)
+  : m_type (address.m_type),
+    m_len (address.m_len)
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  memset (m_data, 0, m_len);
+  memcpy (m_data, address.m_data, m_len);
+}
+Address &
+Address::operator = (const Address &address)
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  m_type = address.m_type;
+  m_len = address.m_len;
+  NS_ASSERT (m_len <= MAX_SIZE);
+  memset (m_data, 0, m_len);
+  memcpy (m_data, address.m_data, m_len);
+  return *this;
+}
+
+bool
+Address::IsInvalid (void) const
+{
+  return m_len == 0 && m_type == 0;
+}
+
+uint8_t 
+Address::GetLength (void) const
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  return m_len;
+}
+uint32_t
+Address::CopyTo (uint8_t buffer[MAX_SIZE]) const
+{
+  NS_ASSERT (m_len <= MAX_SIZE);
+  memcpy (buffer, m_data, m_len);
+  return m_len;
+}
+uint32_t
+Address::CopyAllTo (uint8_t *buffer, uint8_t len) const
+{
+  NS_ASSERT (len >= m_len + 2);
+  buffer[0] = m_type;
+  buffer[1] = m_len;
+  memcpy (buffer + 2, m_data, m_len);
+  return m_len + 2;
+}
+
+uint32_t
+Address::CopyFrom (const uint8_t *buffer, uint8_t len)
+{
+  NS_ASSERT (len <= MAX_SIZE);
+  memcpy (m_data, buffer, len);
+  m_len = len;
+  return m_len;
+}
+uint32_t
+Address::CopyAllFrom (const uint8_t *buffer, uint8_t len)
+{
+  NS_ASSERT (len >= 2);
+  m_type = buffer[0];
+  m_len = buffer[1];
+  NS_ASSERT (len >= m_len + 2);
+  memcpy (m_data, buffer + 2, m_len);
+  return m_len + 2;
+}
+bool 
+Address::CheckCompatible (uint8_t type, uint8_t len) const
+{
+  NS_ASSERT (len <= MAX_SIZE);
+  return m_len == len && (m_type == type || m_type == 0);
+}
+bool 
+Address::IsMatchingType (uint8_t type) const
+{
+  return m_type == type;
+}
+
+uint8_t 
+Address::Register (void)
+{
+  static uint8_t type = 1;
+  type++;
+  return type;
+}
+
+bool operator == (const Address &a, const Address &b)
+{
+  NS_ASSERT (a.m_type == b.m_type || 
+	     a.m_type == 0 || 
+	     b.m_type == 0);
+  NS_ASSERT (a.GetLength() == b.GetLength());  
+  return memcmp (a.m_data, b.m_data, a.m_len) == 0;
+}
+bool operator != (const Address &a, const Address &b)
+{
+  return !(a == b);
+}
+bool operator < (const Address &a, const Address &b)
+{
+  NS_ASSERT (a.m_type == b.m_type  || 
+	     a.m_type == 0 || 
+	     b.m_type == 0);
+  NS_ASSERT (a.GetLength() == b.GetLength());
+  for (uint8_t i = 0; i < a.GetLength(); i++) 
+    {
+      if (a.m_data[i] < b.m_data[i]) 
+	{
+	  return true;
+	} 
+      else if (a.m_data[i] > b.m_data[i]) 
+	{
+	  return false;
+	}
+    }
+  return false;
+}
+
+std::ostream& operator<< (std::ostream& os, const Address & address)
+{
+  if (address.m_len == 0) 
+    {
+      os << "NULL-ADDRESS";
+      return os;
+    }
+  os.setf (std::ios::hex, std::ios::basefield);
+  os.fill('0');
+  for (uint8_t i=0; i < (address.m_len-1); i++) 
+    {
+      os << std::setw(2) << (uint32_t)address.m_data[i] << ":";
+    }
+  // Final byte not suffixed by ":"
+  os << std::setw(2) << (uint32_t)address.m_data[address.m_len-1];
+  os.setf (std::ios::dec, std::ios::basefield);
+  os.fill(' ');
+  return os;
+}
+
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/address.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,172 @@
+#ifndef ADDRESS_H
+#define ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+/**
+ * \brief a polymophic address class
+ *
+ * This class is very similar in design and spirit to the BSD sockaddr
+ * structure: they are both used to hold multiple types of addresses
+ * together with the type of the address.
+ *
+ * A new address class defined by a user needs to:
+ *   - allocate a type id with Address::Register
+ *   - provide a method to convert his new address to an Address 
+ *     instance. This method is typically a member method named ConvertTo:
+ *     Address MyAddress::ConvertTo (void) const;
+ *   - provide a method to convert an Address instance back to
+ *     an instance of his new address type. This method is typically
+ *     a static member method of his address class named ConvertFrom:
+ *     static MyAddress MyAddress::ConvertFrom (const Address &address);
+ *   - the ConvertFrom method is expected to check that the type of the
+ *     input Address instance is compatible with its own type.
+ *
+ * Typical code to create a new class type looks like:
+ * \code
+ * // this class represents addresses which are 2 bytes long.
+ * class MyAddress
+ * {
+ * public:
+ *   Address ConvertTo (void) const;
+ *   static MyAddress ConvertFrom (void);
+ * private:
+ *   static uint8_t GetType (void);
+ * };
+ *
+ * Address MyAddress::ConvertTo (void) const
+ * {
+ *   return Address (GetType (), m_buffer, 2);
+ * }
+ * MyAddress MyAddress::ConvertFrom (const Address &address)
+ * {
+ *   MyAddress ad;
+ *   NS_ASSERT (address.CheckCompatible (GetType (), 2));
+ *   address.CopyTo (ad.m_buffer, 2);
+ *   return ad;
+ * }
+ * uint8_t MyAddress::GetType (void)
+ * {
+ *   static uint8_t type = Address::Register ();
+ *   return type;
+ * }
+ * \endcode
+ */
+class Address 
+{
+public:
+  enum {
+    /**
+     * The maximum size of a byte buffer which
+     * can be stored in an Address instance.
+     */
+    MAX_SIZE = 30
+  };
+
+  /**
+   * Create an invalid address
+   */
+  Address ();
+  /**
+   * \param type the type of the Address to create
+   * \param buffer a pointer to a buffer of bytes which hold
+   *        a serialized representation of the address in network
+   *        byte order.
+   * \param len the length of the buffer.
+   * 
+   * Create an address from a type and a buffer. This constructor
+   * is typically invoked from the conversion functions of various
+   * address types when they have to convert themselves to an 
+   * Address instance.
+   */
+  Address (uint8_t type, const uint8_t *buffer, uint8_t len);
+  Address (const Address & address);
+  Address &operator = (const Address &address);
+
+  /**
+   * \returns true if this address is invalid, false otherwise.
+   *
+   * An address is invalid if and only if it was created
+   * through the default constructor and it was never
+   * re-initialized.
+   */
+  bool IsInvalid (void) const;
+  /**
+   * \returns the length of the underlying address.
+   */
+  uint8_t GetLength (void) const;
+  /**
+   * \param buffer buffer to copy the address bytes to.
+   * \returns the number of bytes copied.
+   */
+  uint32_t CopyTo (uint8_t buffer[MAX_SIZE]) const;
+  /**
+   * \param buffer buffer to copy the whole address data structure to
+   * \param len the size of the buffer
+   * \returns the number of bytes copied.
+   */
+  uint32_t CopyAllTo (uint8_t *buffer, uint8_t len) const;
+  /**
+   * \param buffer pointer to a buffer of bytes which contain
+   *        a serialized representation of the address in network
+   *        byte order.
+   * \param len length of buffer
+   * \returns the number of bytes copied.
+   *
+   * Copy the input buffer to the internal buffer of this address 
+   * instance.
+   */
+  uint32_t CopyFrom (const uint8_t *buffer, uint8_t len);
+  /**
+   * \param buffer pointer to a buffer of bytes which contain
+   *        a copy of all the members of this Address class.
+   * \param len the length of the buffer
+   * \returns the number of bytes copied.
+   */
+  uint32_t CopyAllFrom (const uint8_t *buffer, uint8_t len);
+  /**
+   * \param type a type id as returned by Address::Register
+   * \param len the length associated to this type id.
+   *
+   * \returns true if the type of the address stored internally
+   * is compatible with the requested type, false otherwise.
+   */
+  bool CheckCompatible (uint8_t type, uint8_t len) const;
+  /**
+   * \param type a type id as returned by Address::Register
+   * \returns true if the type of the address stored internally
+   * is compatible with the requested type, false otherwise.
+   *
+   * This method checks that the types are _exactly_ equal.
+   * This method is really used only by the PacketSocketAddress
+   * and there is little point in using it otherwise so, 
+   * you have been warned: DO NOT USE THIS METHOD.
+   */
+  bool IsMatchingType (uint8_t type) const;
+  /**
+   * Allocate a new type id for a new type of address.
+   * \returns a new type id.
+   */
+  static uint8_t Register (void);
+private:
+  friend bool operator == (const Address &a, const Address &b);
+  friend bool operator < (const Address &a, const Address &b);
+  friend std::ostream& operator<< (std::ostream& os, const Address & address);
+
+  uint8_t m_type;
+  uint8_t m_len;
+  uint8_t m_data[MAX_SIZE];
+};
+
+bool operator == (const Address &a, const Address &b);
+bool operator != (const Address &a, const Address &b);
+bool operator < (const Address &a, const Address &b);
+std::ostream& operator<< (std::ostream& os, const Address & address);
+
+} // namespace ns3
+
+
+#endif /* ADDRESS_H */
--- a/src/node/channel.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/channel.h	Wed Sep 05 18:35:39 2007 +0100
@@ -1,7 +1,5 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2007 University of Washington
- *
  * 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;
@@ -14,11 +12,8 @@
  * 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: Craig Dowell <craigdo@ee.washingon.edu>
- *
- *      Wed Feb 14 16:05:46 PST 2007 craigdo:  Created
  */
+
 #ifndef CHANNEL_H
 #define CHANNEL_H
 
@@ -41,6 +36,7 @@
 {
 public:
   static const InterfaceId iid;
+
   Channel ();
   Channel (std::string name);
 
@@ -62,8 +58,8 @@
   virtual Ptr<NetDevice> GetDevice (uint32_t i) const = 0;
 
 protected:
-  virtual ~Channel ();
-  std::string m_name;
+  virtual      ~Channel ();
+  std::string   m_name;
 
 private:
 };
--- a/src/node/ethernet-header.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ethernet-header.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -19,6 +19,8 @@
  * Author: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
  */
 
+#include <iomanip>
+#include <iostream>
 #include "ns3/assert.h"
 #include "ns3/debug.h"
 #include "ns3/header.h"
@@ -29,6 +31,15 @@
 
 namespace ns3 {
 
+NS_HEADER_ENSURE_REGISTERED (EthernetHeader);
+
+uint32_t
+EthernetHeader::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<EthernetHeader> ("EthernetHeader.ns3");
+  return uid;
+}
+
 EthernetHeader::EthernetHeader (bool hasPreamble)
   : m_enPreambleSfd (hasPreamble),
     m_lengthType (0)
@@ -39,9 +50,6 @@
     m_lengthType (0)
 {}
 
-EthernetHeader::~EthernetHeader ()
-{}
-
 void 
 EthernetHeader::SetLengthType (uint16_t lengthType)
 {
@@ -65,22 +73,22 @@
 }
 
 void 
-EthernetHeader::SetSource (MacAddress source)
+EthernetHeader::SetSource (Eui48Address source)
 {
   m_source = source;
 }
-MacAddress
+Eui48Address
 EthernetHeader::GetSource (void) const
 {
   return m_source;
 }
 
 void 
-EthernetHeader::SetDestination (MacAddress dst)
+EthernetHeader::SetDestination (Eui48Address dst)
 {
   m_destination = dst;
 }
-MacAddress
+Eui48Address
 EthernetHeader::GetDestination (void) const
 {
   return m_destination;
@@ -99,21 +107,21 @@
 }
 
 std::string
-EthernetHeader::DoGetName (void) const
+EthernetHeader::GetName (void) const
 {
   return "ETHERNET";
 }
 
 void 
-EthernetHeader::PrintTo (std::ostream &os) const
+EthernetHeader::Print (std::ostream &os) const
 {
   // ethernet, right ?
-  os << "(ethernet)";
   if (m_enPreambleSfd)
     {
       os << " preamble/sfd=" << m_preambleSfd << ",";
     }
-  os << " length/type=" << m_lengthType
+
+  os << " length/type=0x" << std::hex << m_lengthType << std::dec
      << ", source=" << m_source
      << ", destination=" << m_destination;
 }
@@ -123,13 +131,15 @@
   if (m_enPreambleSfd)
     {
       return PREAMBLE_SIZE + LENGTH_SIZE + 2*MAC_ADDR_SIZE;
-    } else {
+    } 
+  else 
+    {
       return LENGTH_SIZE + 2*MAC_ADDR_SIZE;
     }
 }
 
 void
-EthernetHeader::SerializeTo (Buffer::Iterator start) const
+EthernetHeader::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   
@@ -137,14 +147,12 @@
     {
       i.WriteU64(m_preambleSfd);
     }
-  NS_ASSERT (m_destination.GetLength () == MAC_ADDR_SIZE);
-  NS_ASSERT (m_source.GetLength () == MAC_ADDR_SIZE);
   WriteTo (i, m_destination);
   WriteTo (i, m_source);
   i.WriteU16 (m_lengthType);
 }
 uint32_t
-EthernetHeader::DeserializeFrom (Buffer::Iterator start)
+EthernetHeader::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
 
@@ -153,11 +161,11 @@
       m_enPreambleSfd = i.ReadU64 ();
     }
 
-  ReadFrom (i, m_destination, MAC_ADDR_SIZE);
-  ReadFrom (i, m_source, MAC_ADDR_SIZE);
+  ReadFrom (i, m_destination);
+  ReadFrom (i, m_source);
   m_lengthType = i.ReadU16 ();
 
   return GetSerializedSize ();
 }
 
-}; // namespace ns3
+} // namespace ns3
--- a/src/node/ethernet-header.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ethernet-header.h	Wed Sep 05 18:35:39 2007 +0100
@@ -23,7 +23,8 @@
 #define ETHERNET_HEADER_H
 
 #include "ns3/header.h"
-#include "ns3/mac-address.h"
+#include <string>
+#include "ns3/eui48-address.h"
 
 namespace ns3 {
 
@@ -45,11 +46,10 @@
  * the packet. Eventually the class will be improved to also support
  * VLAN tags in packet headers.
  */
-class EthernetHeader : public Header {
+class EthernetHeader : public Header 
+{
 public:
-  static const int PREAMBLE_SIZE = 8; /// size of the preamble_sfd header field
-  static const int LENGTH_SIZE = 2;   /// size of the length_type header field
-  static const int MAC_ADDR_SIZE = 6; /// size of src/dest addr header fields
+  static uint32_t GetUid (void);
 
   /**
    * \brief Construct a null ethernet header
@@ -62,7 +62,6 @@
    * By default, does not add or remove an ethernet preamble
    */
   EthernetHeader ();
-  virtual ~EthernetHeader ();
   /**
    * \param size The size of the payload in bytes
    */
@@ -70,11 +69,11 @@
   /**
    * \param source The source address of this packet
    */
-  void SetSource (MacAddress source);
+  void SetSource (Eui48Address source);
   /**
    * \param destination The destination address of this packet.
    */
-  void SetDestination (MacAddress destination);
+  void SetDestination (Eui48Address destination);
   /**
    * \param preambleSfd The value that the preambleSfd field should take
    */
@@ -90,11 +89,11 @@
   /**
    * \return The source address of this packet
    */
-  MacAddress GetSource (void) const;
+  Eui48Address GetSource (void) const;
   /**
    * \return The destination address of this packet
    */
-  MacAddress GetDestination (void) const;  
+  Eui48Address GetDestination (void) const;  
   /**
    * \return The value of the PreambleSfd field
    */
@@ -104,12 +103,15 @@
    */
   uint32_t GetHeaderSize() const;
 
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
 private:
-  virtual std::string DoGetName (void) const;
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
+  static const int PREAMBLE_SIZE = 8; /// size of the preamble_sfd header field
+  static const int LENGTH_SIZE = 2;   /// size of the length_type header field
+  static const int MAC_ADDR_SIZE = 6; /// size of src/dest addr header fields
 
   /**
    * If false, the preamble/sfd are not serialised/deserialised.
@@ -117,8 +119,8 @@
   bool m_enPreambleSfd;
   uint64_t m_preambleSfd;     /// Value of the Preamble/SFD fields
   uint16_t m_lengthType;      /// Length or type of the packet
-  MacAddress m_source;        /// Source address
-  MacAddress m_destination;   /// Destination address
+  Eui48Address m_source;        /// Source address
+  Eui48Address m_destination;   /// Destination address
 };
 
 }; // namespace ns3
--- a/src/node/ethernet-trailer.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ethernet-trailer.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -28,16 +28,22 @@
 
 namespace ns3 {
 
+NS_TRAILER_ENSURE_REGISTERED (EthernetTrailer);
+
 bool EthernetTrailer::m_calcFcs = false;
 
+uint32_t
+EthernetTrailer::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<EthernetTrailer> ("EthernetTrailer.ns3");
+  return uid;
+}
+
 EthernetTrailer::EthernetTrailer ()
 {
   Init();
 }
 
-EthernetTrailer::~EthernetTrailer ()
-{}
-
 void EthernetTrailer::Init()
 {
   m_fcs = 0;
@@ -85,13 +91,13 @@
   return GetSerializedSize();
 }
 std::string
-EthernetTrailer::DoGetName (void) const
+EthernetTrailer::GetName (void) const
 {
   return "ETHERNET";
 }
 
 void 
-EthernetTrailer::PrintTo (std::ostream &os) const
+EthernetTrailer::Print (std::ostream &os) const
 {
   os << " fcs=" << m_fcs;
 }
@@ -102,7 +108,7 @@
 }
 
 void
-EthernetTrailer::SerializeTo (Buffer::Iterator end) const
+EthernetTrailer::Serialize (Buffer::Iterator end) const
 {
   Buffer::Iterator i = end;
   i.Prev(GetSerializedSize());
@@ -110,7 +116,7 @@
   i.WriteU32 (m_fcs);
 }
 uint32_t
-EthernetTrailer::DeserializeFrom (Buffer::Iterator end)
+EthernetTrailer::Deserialize (Buffer::Iterator end)
 {
   Buffer::Iterator i = end;
   uint32_t size = GetSerializedSize();
--- a/src/node/ethernet-trailer.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ethernet-trailer.h	Wed Sep 05 18:35:39 2007 +0100
@@ -24,6 +24,7 @@
 
 #include "ns3/trailer.h"
 #include "ns3/packet.h"
+#include <string>
 
 namespace ns3 {
 /**
@@ -33,13 +34,16 @@
  * ethernet packet. The actual FCS functionality is not yet coded and
  * so this acts more as a placeholder.
  */
-class EthernetTrailer : public Trailer {
+class EthernetTrailer : public Trailer 
+{
 public:
+  static uint32_t GetUid (void);
+
   /**
    * \brief Construct a null ethernet trailer
    */
   EthernetTrailer ();
-  virtual ~EthernetTrailer ();
+
   /**
    * \brief Enable or disabled FCS checking and calculations
    * \param enable If true, enables FCS calculations.
@@ -77,12 +81,12 @@
    */ 
   uint32_t GetTrailerSize() const;
 
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator end) const;
+  uint32_t Deserialize (Buffer::Iterator end);
 private:
-  virtual std::string DoGetName (void) const;
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator end) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator end);
 
   /**
    * Initializes the trailer parameters during construction.
@@ -98,7 +102,7 @@
 
 };
 
-}; // namespace ns3
+} // namespace ns3
 
 
 #endif /* ETHERNET_TRAILER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/eui48-address.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,168 @@
+/* -*-  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 "eui48-address.h"
+#include "address.h"
+#include "ns3/assert.h"
+#include <iomanip>
+#include <iostream>
+
+namespace ns3 {
+
+#define ASCII_a (0x41)
+#define ASCII_z (0x5a)
+#define ASCII_A (0x61)
+#define ASCII_Z (0x7a)
+#define ASCII_COLON (0x3a)
+#define ASCII_ZERO (0x30)
+
+static char
+AsciiToLowCase (char c)
+{
+  if (c >= ASCII_a && c <= ASCII_z) {
+    return c;
+  } else if (c >= ASCII_A && c <= ASCII_Z) {
+    return c + (ASCII_a - ASCII_A);
+  } else {
+    return c;
+  }
+}
+
+
+Eui48Address::Eui48Address ()
+{
+  memset (m_address, 0, 6);
+}
+Eui48Address::Eui48Address (const char *str)
+{
+  int i = 0;
+  while (*str != 0 && i < 6) 
+    {
+      uint8_t byte = 0;
+      while (*str != ASCII_COLON && *str != 0) 
+	{
+	  byte <<= 4;
+	  char low = AsciiToLowCase (*str);
+	  if (low >= ASCII_a) 
+	    {
+	      byte |= low - ASCII_a + 10;
+	    } 
+	  else 
+	    {
+	      byte |= low - ASCII_ZERO;
+	    }
+	  str++;
+	}
+      m_address[i] = byte;
+      i++;
+      if (*str == 0) 
+	{
+	  break;
+	}
+      str++;
+    }
+  NS_ASSERT (i == 6);
+}
+void 
+Eui48Address::CopyFrom (const uint8_t buffer[6])
+{
+  memcpy (m_address, buffer, 6);
+}
+void 
+Eui48Address::CopyTo (uint8_t buffer[6]) const
+{
+  memcpy (buffer, m_address, 6);
+}
+
+bool 
+Eui48Address::IsMatchingType (const Address &address)
+{
+  return address.CheckCompatible (GetType (), 6);
+}
+Eui48Address::operator Address ()
+{
+  return ConvertTo ();
+}
+Address 
+Eui48Address::ConvertTo (void) const
+{
+  return Address (GetType (), m_address, 6);
+}
+Eui48Address 
+Eui48Address::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (address.CheckCompatible (GetType (), 6));
+  Eui48Address retval;
+  address.CopyTo (retval.m_address);
+  return retval;
+}
+Eui48Address 
+Eui48Address::Allocate (void)
+{
+  static uint64_t id = 0;
+  id++;
+  Eui48Address address;
+  address.m_address[0] = (id >> 40) & 0xff;
+  address.m_address[1] = (id >> 32) & 0xff;
+  address.m_address[2] = (id >> 24) & 0xff;
+  address.m_address[3] = (id >> 16) & 0xff;
+  address.m_address[4] = (id >> 8) & 0xff;
+  address.m_address[5] = (id >> 0) & 0xff;
+  return address;
+}
+uint8_t 
+Eui48Address::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
+
+bool operator == (const Eui48Address &a, const Eui48Address &b)
+{
+  uint8_t ada[6];
+  uint8_t adb[6];
+  a.CopyTo (ada);
+  b.CopyTo (adb);
+  return memcmp (ada, adb, 6) == 0;
+}
+bool operator != (const Eui48Address &a, const Eui48Address &b)
+{
+  return ! (a == b);
+}
+
+std::ostream& operator<< (std::ostream& os, const Eui48Address & address)
+{
+  uint8_t ad[6];
+  address.CopyTo (ad);
+
+  os.setf (std::ios::hex, std::ios::basefield);
+  os.fill('0');
+  for (uint8_t i=0; i < 5; i++) 
+    {
+      os << std::setw(2) << (uint32_t)ad[i] << ":";
+    }
+  // Final byte not suffixed by ":"
+  os << std::setw(2) << (uint32_t)ad[5];
+  os.setf (std::ios::dec, std::ios::basefield);
+  os.fill(' ');
+  return os;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/eui48-address.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,99 @@
+/* -*-  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>
+ */
+#ifndef EUI48_ADDRESS_H
+#define EUI48_ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+class Address;
+
+/**
+ * \brief an EUI-48 address
+ *
+ * This class can contain 48 bit IEEE addresses.
+ */
+class Eui48Address
+{
+public:
+  Eui48Address ();
+  /**
+   * \param str a string representing the new Eui48Address
+   *
+   * The format of the string is "xx:xx:xx:xx:xx:xx"
+   */
+  Eui48Address (const char *str);
+
+  /**
+   * \param buffer address in network order
+   *
+   * Copy the input address to our internal buffer.
+   */
+  void CopyFrom (const uint8_t buffer[6]);
+  /**
+   * \param buffer address in network order
+   *
+   * Copy the internal address to the input buffer.
+   */
+  void CopyTo (uint8_t buffer[6]) const;
+
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  operator Address ();
+  /**
+   * \param address a polymorphic address
+   * \returns a new Eui48Address from the polymorphic address
+   * 
+   * This function performs a type check and asserts if the
+   * type of the input address is not compatible with an
+   * Eui48Address.
+   */
+  static Eui48Address ConvertFrom (const Address &address);
+  /**
+   * \returns true if the address matches, false otherwise.
+   */
+  static bool IsMatchingType (const Address &address);
+  /**
+   * Allocate a new Eui48Address.
+   */
+  static Eui48Address Allocate (void);
+private:
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  Address ConvertTo (void) const;
+  static uint8_t GetType (void);
+  uint8_t m_address[6];
+};
+
+bool operator == (const Eui48Address &a, const Eui48Address &b);
+bool operator != (const Eui48Address &a, const Eui48Address &b);
+std::ostream& operator<< (std::ostream& os, const Eui48Address & address);
+
+} // namespace ns3
+
+#endif /* EUI48_ADDRESS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/eui64-address.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,171 @@
+/* -*-  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 "eui64-address.h"
+#include "address.h"
+#include "ns3/assert.h"
+#include <iomanip>
+#include <iostream>
+
+namespace ns3 {
+
+#define ASCII_a (0x41)
+#define ASCII_z (0x5a)
+#define ASCII_A (0x61)
+#define ASCII_Z (0x7a)
+#define ASCII_COLON (0x3a)
+#define ASCII_ZERO (0x30)
+
+static char
+AsciiToLowCase (char c)
+{
+  if (c >= ASCII_a && c <= ASCII_z) {
+    return c;
+  } else if (c >= ASCII_A && c <= ASCII_Z) {
+    return c + (ASCII_a - ASCII_A);
+  } else {
+    return c;
+  }
+}
+
+
+Eui64Address::Eui64Address ()
+{
+  memset (m_address, 0, 8);
+}
+Eui64Address::Eui64Address (const char *str)
+{
+  int i = 0;
+  while (*str != 0 && i < 8) 
+    {
+      uint8_t byte = 0;
+      while (*str != ASCII_COLON && *str != 0) 
+	{
+	  byte <<= 4;
+	  char low = AsciiToLowCase (*str);
+	  if (low >= ASCII_a) 
+	    {
+	      byte |= low - ASCII_a + 10;
+	    } 
+	  else 
+	    {
+	      byte |= low - ASCII_ZERO;
+	    }
+	  str++;
+	}
+      m_address[i] = byte;
+      i++;
+      if (*str == 0) 
+	{
+	  break;
+	}
+      str++;
+    }
+  NS_ASSERT (i == 6);
+}
+void 
+Eui64Address::CopyFrom (const uint8_t buffer[8])
+{
+  memcpy (m_address, buffer, 8);
+}
+void 
+Eui64Address::CopyTo (uint8_t buffer[8]) const
+{
+  memcpy (buffer, m_address, 8);
+}
+
+bool 
+Eui64Address::IsMatchingType (const Address &address)
+{
+  return address.CheckCompatible (GetType (), 8);
+}
+Eui64Address::operator Address ()
+{
+  return ConvertTo ();
+}
+Eui64Address 
+Eui64Address::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (address.CheckCompatible (GetType (), 8));
+  Eui64Address retval;
+  address.CopyTo (retval.m_address);
+  return retval;
+}
+Address
+Eui64Address::ConvertTo (void) const
+{
+  return Address (GetType (), m_address, 8);
+}
+
+Eui64Address 
+Eui64Address::Allocate (void)
+{
+  static uint64_t id = 0;
+  id++;
+  Eui64Address address;
+  address.m_address[0] = (id >> 56) & 0xff;
+  address.m_address[1] = (id >> 48) & 0xff;
+  address.m_address[2] = (id >> 40) & 0xff;
+  address.m_address[3] = (id >> 32) & 0xff;
+  address.m_address[4] = (id >> 24) & 0xff;
+  address.m_address[5] = (id >> 16) & 0xff;
+  address.m_address[6] = (id >> 8) & 0xff;
+  address.m_address[7] = (id >> 0) & 0xff;
+  return address;
+}
+uint8_t 
+Eui64Address::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
+
+bool operator == (const Eui64Address &a, const Eui64Address &b)
+{
+  uint8_t ada[8];
+  uint8_t adb[8];
+  a.CopyTo (ada);
+  b.CopyTo (adb);
+  return memcmp (ada, adb, 8) == 0;
+}
+bool operator != (const Eui64Address &a, const Eui64Address &b)
+{
+  return ! (a == b);
+}
+
+std::ostream& operator<< (std::ostream& os, const Eui64Address & address)
+{
+  uint8_t ad[8];
+  address.CopyTo (ad);
+
+  os.setf (std::ios::hex, std::ios::basefield);
+  os.fill('0');
+  for (uint8_t i=0; i < 7; i++) 
+    {
+      os << std::setw(2) << (uint32_t)ad[i] << ":";
+    }
+  // Final byte not suffixed by ":"
+  os << std::setw(2) << (uint32_t)ad[7];
+  os.setf (std::ios::dec, std::ios::basefield);
+  os.fill(' ');
+  return os;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/eui64-address.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,98 @@
+/* -*-  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>
+ */
+#ifndef EUI64_ADDRESS_H
+#define EUI64_ADDRESS_H
+
+#include <stdint.h>
+#include <ostream>
+
+namespace ns3 {
+
+class Address;
+
+/**
+ * \brief an EUI-64 address
+ *
+ * This class can contain 64 bit IEEE addresses.
+ */
+class Eui64Address
+{
+public:
+  Eui64Address ();
+  /**
+   * \param str a string representing the new Eui64Address
+   *
+   * The format of the string is "xx:xx:xx:xx:xx:xx"
+   */
+  Eui64Address (const char *str);
+
+  /**
+   * \param buffer address in network order
+   *
+   * Copy the input address to our internal buffer.
+   */
+  void CopyFrom (const uint8_t buffer[8]);
+  /**
+   * \param buffer address in network order
+   *
+   * Copy the internal address to the input buffer.
+   */
+  void CopyTo (uint8_t buffer[8]) const;
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  operator Address ();
+  /**
+   * \param address a polymorphic address
+   * \returns a new Eui64Address from the polymorphic address
+   * 
+   * This function performs a type check and asserts if the
+   * type of the input address is not compatible with an
+   * Eui64Address.
+   */
+  static Eui64Address ConvertFrom (const Address &address);
+  /**
+   * \returns true if the address matches, false otherwise.
+   */
+  static bool IsMatchingType (const Address &address);
+  /**
+   * Allocate a new Eui64Address.
+   */
+  static Eui64Address Allocate (void);
+private:
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  Address ConvertTo (void) const;
+  static uint8_t GetType (void);
+  uint8_t m_address[8];
+};
+
+bool operator == (const Eui64Address &a, const Eui64Address &b);
+bool operator != (const Eui64Address &a, const Eui64Address &b);
+std::ostream& operator<< (std::ostream& os, const Eui64Address & address);
+
+} // namespace ns3
+
+#endif /* EUI64_ADDRESS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/inet-socket-address.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,106 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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 "inet-socket-address.h"
+#include "ns3/assert.h"
+
+namespace ns3 {
+
+InetSocketAddress::InetSocketAddress (Ipv4Address ipv4, uint16_t port)
+  : m_ipv4 (ipv4),
+    m_port (port)
+{}
+InetSocketAddress::InetSocketAddress (Ipv4Address ipv4)
+  : m_ipv4 (ipv4),
+    m_port (0)
+{}
+InetSocketAddress::InetSocketAddress (const char *ipv4, uint16_t port)
+  : m_ipv4 (Ipv4Address (ipv4)),
+    m_port (port)
+{}
+InetSocketAddress::InetSocketAddress (const char * ipv4)
+  : m_ipv4 (Ipv4Address (ipv4)),
+    m_port (0)
+{}
+InetSocketAddress::InetSocketAddress (uint16_t port)
+  : m_ipv4 (Ipv4Address::GetAny ()),
+    m_port (port)
+{}
+uint16_t 
+InetSocketAddress::GetPort (void) const
+{
+  return m_port;
+}
+Ipv4Address 
+InetSocketAddress::GetIpv4 (void) const
+{
+  return m_ipv4;
+}
+
+void 
+InetSocketAddress::SetPort (uint16_t port)
+{
+  m_port = port;
+}
+void 
+InetSocketAddress::SetIpv4 (Ipv4Address address)
+{
+  m_ipv4 = address;
+}
+
+bool 
+InetSocketAddress::IsMatchingType (const Address &address)
+{
+  return address.CheckCompatible (GetType (), 6);
+}
+
+InetSocketAddress::operator Address () const
+{
+  return ConvertTo ();
+}
+
+Address 
+InetSocketAddress::ConvertTo (void) const
+{
+  uint8_t buf[6];
+  m_ipv4.Serialize (buf);
+  buf[4] = m_port & 0xff;
+  buf[5] = (m_port >> 8) & 0xff;
+  return Address (GetType (), buf, 6);
+}
+InetSocketAddress 
+InetSocketAddress::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (address.CheckCompatible (GetType (), 6));
+  uint8_t buf[6];
+  address.CopyTo (buf);
+  Ipv4Address ipv4 = Ipv4Address::Deserialize (buf);
+  uint16_t port = buf[4] | (buf[5] << 8);
+  return InetSocketAddress (ipv4, port);
+}
+uint8_t 
+InetSocketAddress::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/inet-socket-address.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,117 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2005 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 INET_SOCKET_ADDRESS_H
+#define INET_SOCKET_ADDRESS_H
+
+#include "address.h"
+#include "ipv4-address.h"
+#include <stdint.h>
+
+namespace ns3 {
+
+
+/**
+ * \brief an Inet address class
+ *
+ * This class is similar to inet_sockaddr in the BSD socket
+ * API. i.e., this class holds an Ipv4Address and a port number
+ * to form an ipv4 transport endpoint.
+ */
+class InetSocketAddress
+{
+public:
+  /**
+   * \param ipv4 the ipv4 address
+   * \param port the port number
+   */
+  InetSocketAddress (Ipv4Address ipv4, uint16_t port);
+  /**
+   * \param ipv4 the ipv4 address
+   *
+   * The port number is set to zero by default.
+   */
+  InetSocketAddress (Ipv4Address ipv4);
+  /**
+   * \param port the port number
+   *
+   * The ipv4 address is set to the "Any" address by default.
+   */
+  InetSocketAddress (uint16_t port);
+  /**
+   * \param ipv4 string which represents an ipv4 address
+   * \param port the port number
+   */
+  InetSocketAddress (const char *ipv4, uint16_t port);
+  /**
+   * \param ipv4 string which represents an ipv4 address
+   *
+   * The port number is set to zero.
+   */
+  InetSocketAddress (const char *ipv4);
+  /**
+   * \returns the port number
+   */
+  uint16_t GetPort (void) const;
+  /**
+   * \returns the ipv4 address
+   */
+  Ipv4Address GetIpv4 (void) const;
+
+  /**
+   * \param port the new port number.
+   */
+  void SetPort (uint16_t port);
+  /**
+   * \param address the new ipv4 address
+   */
+  void SetIpv4 (Ipv4Address address);
+
+  /**
+   * \returns true if the address matches, false otherwise.
+   */
+  static bool IsMatchingType (const Address &address);
+
+  /**
+   * \returns an Address instance which represents this
+   * InetSocketAddress instance.
+   */
+  operator Address () const;
+
+  /**
+   * \param address the Address instance to convert from.
+   *
+   * Returns an InetSocketAddress which corresponds to the input
+   * Address
+   */
+  static InetSocketAddress ConvertFrom (const Address &address);
+private:
+  Address ConvertTo (void) const;
+
+  static uint8_t GetType (void);
+  Ipv4Address m_ipv4;
+  uint16_t m_port;
+};
+
+} // namespace ns3
+
+
+#endif /* INET_SOCKET_ADDRESS_H */
--- a/src/node/ipv4-address.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ipv4-address.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -19,11 +19,11 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 #include "ns3/debug.h"
+#include "ipv4-address.h"
+#include "ns3/assert.h"
 
 NS_DEBUG_COMPONENT_DEFINE("Ipv4Address");
 
-#include "ipv4-address.h"
-
 
 namespace ns3 {
 
@@ -135,6 +135,17 @@
   m_address = AsciiToIpv4Host (address);
 }
 
+void
+Ipv4Address::Set (uint32_t address)
+{
+  m_address = address;
+}
+void
+Ipv4Address::Set (char const *address)
+{
+  m_address = AsciiToIpv4Host (address);
+}
+
 bool 
 Ipv4Address::IsEqual (Ipv4Address other) const
 {
@@ -160,8 +171,11 @@
 bool 
 Ipv4Address::IsMulticast (void) const
 {
-  // XXX
-  return false;
+//
+// Multicast addresses are defined as ranging from 224.0.0.0 through 
+// 239.255.255.255 (which is E0000000 through EFFFFFFF in hex).
+//
+  return (m_address >= 0xe0000000 && m_address <= 0xefffffff);
 }
 
 uint32_t
@@ -182,6 +196,20 @@
   buf[2] = (m_address >> 8) & 0xff;
   buf[3] = (m_address >> 0) & 0xff;
 }
+Ipv4Address 
+Ipv4Address::Deserialize (const uint8_t buf[4])
+{
+  Ipv4Address ipv4;
+  ipv4.m_address = 0;
+  ipv4.m_address |= buf[0];
+  ipv4.m_address <<= 8;
+  ipv4.m_address |= buf[1];
+  ipv4.m_address <<= 8;
+  ipv4.m_address |= buf[2];
+  ipv4.m_address <<= 8;
+  ipv4.m_address |= buf[3];
+  return ipv4;
+}
 
 void 
 Ipv4Address::Print (std::ostream &os) const
@@ -192,7 +220,39 @@
      << ((m_address >> 0) & 0xff);
 }
 
+bool 
+Ipv4Address::IsMatchingType (const Address &address)
+{
+  return address.CheckCompatible (GetType (), 4);
+}
+Ipv4Address::operator Address ()
+{
+  return ConvertTo ();
+}
 
+Address 
+Ipv4Address::ConvertTo (void) const
+{
+  uint8_t buf[4];
+  Serialize (buf);
+  return Address (GetType (), buf, 4);
+}
+
+Ipv4Address
+Ipv4Address::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (address.CheckCompatible (GetType (), 4));
+  uint8_t buf[4];
+  address.CopyTo (buf);
+  return Deserialize (buf);
+}
+
+uint8_t 
+Ipv4Address::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
 
 Ipv4Address 
 Ipv4Address::GetZero (void)
--- a/src/node/ipv4-address.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/ipv4-address.h	Wed Sep 05 18:35:39 2007 +0100
@@ -24,6 +24,7 @@
 
 #include <stdint.h>
 #include <ostream>
+#include "address.h"
 
 namespace ns3 {
 
@@ -52,6 +53,22 @@
   Ipv4Address (char const *address);
   
   /**
+   * input address is in host order.
+   * \param address The host order 32-bit address
+   */
+  void Set (uint32_t address);
+  /** 
+    * \brief Sets an Ipv4Address by parsing a the input C-string
+    *
+    * Input address is in format:
+    * hhh.xxx.xxx.lll
+    * where h is the high byte and l the
+    * low byte
+    * \param address C-string containing the address as described above
+    */
+  void Set (char const *address);
+
+  /**
    * \brief Comparison operation between two Ipv4Addresses
    * \param other address to which to compare this address
    * \return True if the addresses are equal. False otherwise.
@@ -70,11 +87,19 @@
   void SetHostOrder (uint32_t ip);
   /**
    * Serialize this address to a 4-byte buffer
+   *
    * \param buf output buffer to which this address gets overwritten with this
    * Ipv4Address
    */
   void Serialize (uint8_t buf[4]) const;
   /**
+   * \param buf buffer to read address from
+   * \returns an Ipv4Address
+   * 
+   * The input address is expected to be in network byte order format.
+   */
+  static Ipv4Address Deserialize (const uint8_t buf[4]);
+  /**
    * \brief Print this address to the given output stream
    *
    * The print format is in the typical "192.168.1.1"
@@ -91,15 +116,21 @@
    * (bitwise and) with a network mask, yielding an IPv4 network
    * address.
    *
-   * \param a network mask 
+   * \param mask a network mask 
    */
   Ipv4Address CombineMask (Ipv4Mask const &mask) const;
 
+  static bool IsMatchingType (const Address &address);
+  operator Address ();
+  static Ipv4Address ConvertFrom (const Address &address);
+
   static Ipv4Address GetZero (void);
   static Ipv4Address GetAny (void);
   static Ipv4Address GetBroadcast (void);
   static Ipv4Address GetLoopback (void);
 private:
+  Address ConvertTo (void) const;
+  static uint8_t GetType (void);
   uint32_t m_address;
 };
 
--- a/src/node/llc-snap-header.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/llc-snap-header.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -19,17 +19,24 @@
  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
  */
 
+#include "llc-snap-header.h"
 #include "ns3/assert.h"
-
-#include "llc-snap-header.h"
+#include <string>
 
 namespace ns3 {
 
+NS_HEADER_ENSURE_REGISTERED (LlcSnapHeader);
+
+uint32_t
+LlcSnapHeader::GetUid (void)
+{
+  static uint32_t uid = AllocateUid<LlcSnapHeader> ("LlcSnapHeader.ns3");
+  return uid;
+}
+
 LlcSnapHeader::LlcSnapHeader ()
 {}
 
-LlcSnapHeader::~LlcSnapHeader ()
-{}
 void 
 LlcSnapHeader::SetType (uint16_t type)
 {
@@ -48,13 +55,13 @@
 }
 
 std::string
-LlcSnapHeader::DoGetName (void) const
+LlcSnapHeader::GetName (void) const
 {
   return "LLCSNAP";
 }
 
 void 
-LlcSnapHeader::PrintTo (std::ostream &os) const
+LlcSnapHeader::Print (std::ostream &os) const
 {
   os << "(type 0x";
   os.setf (std::ios::hex, std::ios::basefield);
@@ -64,7 +71,7 @@
 }
 
 void
-LlcSnapHeader::SerializeTo (Buffer::Iterator start) const
+LlcSnapHeader::Serialize (Buffer::Iterator start) const
 {
   Buffer::Iterator i = start;
   uint8_t buf[] = {0xaa, 0xaa, 0x03, 0, 0, 0};
@@ -72,7 +79,7 @@
   i.WriteHtonU16 (m_etherType);
 }
 uint32_t
-LlcSnapHeader::DeserializeFrom (Buffer::Iterator start)
+LlcSnapHeader::Deserialize (Buffer::Iterator start)
 {
   Buffer::Iterator i = start;
   i.Next (5+1);
@@ -81,4 +88,4 @@
 }
 
 
-}; // namespace ns3
+} // namespace ns3
--- a/src/node/llc-snap-header.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/llc-snap-header.h	Wed Sep 05 18:35:39 2007 +0100
@@ -23,28 +23,30 @@
 #define LLC_SNAP_HEADER_H
 
 #include <stdint.h>
+#include <string>
 #include "ns3/header.h"
 
 namespace ns3 {
 
-class LlcSnapHeader : public Header {
- public:
+class LlcSnapHeader : public Header 
+{
+public:
+  static uint32_t GetUid (void);
+
   LlcSnapHeader ();
-  virtual ~LlcSnapHeader ();
-
 
   void SetType (uint16_t type);
   uint16_t GetType (void);
 
+  std::string GetName (void) const;
+  void Print (std::ostream &os) const;
+  uint32_t GetSerializedSize (void) const;
+  void Serialize (Buffer::Iterator start) const;
+  uint32_t Deserialize (Buffer::Iterator start);
 private:
-  virtual std::string DoGetName (void) const;
-  virtual void PrintTo (std::ostream &os) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void SerializeTo (Buffer::Iterator start) const;
-  virtual uint32_t DeserializeFrom (Buffer::Iterator start);
   uint16_t m_etherType;
 };
 
-}; // namespace ns3
+} // namespace ns3
 
 #endif /* LLC_SNAP_HEADER_H */
--- a/src/node/mac-address.cc	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,210 +0,0 @@
-/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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 <iostream>
-#include <iomanip>
-#include "ns3/assert.h"
-#include "mac-address.h"
-
-#define ASCII_a (0x41)
-#define ASCII_z (0x5a)
-#define ASCII_A (0x61)
-#define ASCII_Z (0x7a)
-#define ASCII_COLON (0x3a)
-#define ASCII_ZERO (0x30)
-
-namespace ns3 {
-
-// Static variables
-uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN];
-
-static char
-AsciiToLowCase (char c)
-{
-  if (c >= ASCII_a && c <= ASCII_z) {
-    return c;
-  } else if (c >= ASCII_A && c <= ASCII_Z) {
-    return c + (ASCII_a - ASCII_A);
-  } else {
-    return c;
-  }
-}
-
-
-MacAddress::MacAddress () : m_len(0)
-{
-  for (int i=0; i < MacAddress::MAX_LEN; i++) 
-    {
-      m_address[i] = 0;
-    }
-}
-
-MacAddress::MacAddress(uint8_t len) : m_len(len)
-{
-  NS_ASSERT (len <= MacAddress::MAX_LEN);
-  AdvanceAddress();
-  memcpy(m_address, g_nextAddress, len);
-}
-
-MacAddress::MacAddress (uint8_t const *address, uint8_t len)
-{
-  NS_ASSERT (len <= MacAddress::MAX_LEN);
-  for (int i=0; i < len; i++) 
-    {
-      m_address[i] = address[i];
-    }
-  for (int i=len; i < MacAddress::MAX_LEN; i++) 
-    {
-      m_address[i] = 0;
-    } 
-  m_len = len;
-}
-
-MacAddress::MacAddress (char const *str)
-{       
-  int i = 0;
-  while (*str != 0 && i < MacAddress::MAX_LEN) {
-    uint8_t byte = 0;
-    while (*str != ASCII_COLON && *str != 0) {
-      byte <<= 4;
-      char low = AsciiToLowCase (*str);
-      if (low >= ASCII_a) {
-        byte |= low - ASCII_a + 10;
-      } else {
-        byte |= low - ASCII_ZERO;
-      }
-      str++;
-    }
-    m_address[i] = byte;
-    i++;
-    if (*str == 0) {
-      break;
-    }
-    str++;
-  }
-  m_len = i;
-}
-
-MacAddress::~MacAddress ()
-{}
-
-bool 
-MacAddress::IsEqual (MacAddress other) const
-{
-    if (memcmp(other.m_address, m_address, m_len)) 
-      {
-        return false;
-      } 
-    else 
-      {
-        return true;
-      } 
-}
-
-void
-MacAddress::Print (std::ostream &os) const
-{
-    int i;
-    if (m_len == 0) 
-      {
-        os << "NULL-ADDRESS";
-        return;
-      }
-    os.setf (std::ios::hex, std::ios::basefield);
-    std::cout.fill('0');
-    for (i=0; i< (m_len-1); i++) 
-      {
-	os << std::setw(2) << (uint32_t)m_address[i] << ":";
-      }
-    // Final byte not suffixed by ":"
-    os << std::setw(2) << (uint32_t)m_address[i];
-    os.setf (std::ios::dec, std::ios::basefield);
-    std::cout.fill(' ');
-}
-
-uint8_t
-MacAddress::GetLength () const
-{
-    return m_len;
-}
-
-void
-MacAddress::Peek (uint8_t ad[MacAddress::MAX_LEN]) const
-{
-	memcpy (ad, m_address, MacAddress::MAX_LEN);
-}
-void
-MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len)
-{
-	memcpy (m_address, ad, MacAddress::MAX_LEN);
-        m_len = len;
-}
-
-// Static methods
-void MacAddress::AdvanceAddress()
-  {
-    // Advance to next address, little end first
-    for(size_t i = 0; i < MAX_LEN; ++i)
-      {
-        if (++g_nextAddress[i] != 0) break;
-      }
-  }
-
-// Non-member operators
-bool operator == (MacAddress const&a, MacAddress const&b)
-{
-	return a.IsEqual (b);
-}
-
-bool operator != (MacAddress const&a, MacAddress const&b)
-{
-	return !a.IsEqual (b);
-}
-
-bool operator < (MacAddress const&a, MacAddress const&b)
-{
-        uint8_t a_p[MacAddress::MAX_LEN];
-        uint8_t b_p[MacAddress::MAX_LEN];
-        a.Peek (a_p);
-        b.Peek (b_p);
-        NS_ASSERT (a.GetLength() == b.GetLength());
-        for (uint8_t i = 0; i < a.GetLength(); i++) 
-          {
-            if (a_p[i] < b_p[i]) 
-              {
-                return true;
-              } 
-            else if (a_p[i] > b_p[i]) 
-              {
-                return false;
-              }
-          }
-        return false;
-}
-
-std::ostream& operator<< (std::ostream& os, MacAddress const& address)
-{
-	address.Print (os);
-	return os;
-}
-
-
-}; // namespace ns3
--- a/src/node/mac-address.h	Mon Jul 30 14:48:56 2007 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/* -*-	Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2005 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 MAC_ADDRESS_H
-#define MAC_ADDRESS_H
-
-#include <stdint.h>
-#include <ostream>
-
-namespace ns3 {
-
-/**
- * \brief base class for Network Device addresses
- *
- * This class is a base class for different types of Network
- * Device addresses.  It generically stores an address of 
- * MAX_ADDR_LEN bytes, and provides methods to compare, print, and set
- * the address.
- */
-class MacAddress {
-public:
-  enum {
-    MAX_LEN = 32
-  };
-  /**
-   * \brief Construct a null MacAddress
-   *
-   * This MacAddress has length of zero, and is internally all zeros
-   */
-  MacAddress (void);
-  /**
-   * \brief Construct a MacAddress using the next available
-   * address.
-   * \see MacAddres::Next
-   * \param len length, in bytes, of the desired address
-   */
-  MacAddress(uint8_t len);
-  /**
-   * \brief Construct a MacAddress from a byte-array
-   *
-   * low byte should be first.
-   * \param address a byte array indicating the address
-   * \param len length, in bytes, of the address points to
-   */
-  MacAddress (uint8_t const *address, uint8_t len);
-  /**
-   * \brief Construct a MacAddress from a C-string
-   *
-   * The string should look like this:
-   * hh:xx:xx:xx:xx:ll
-   * where hh is the high byte and ll is
-   * the low byte.
-   * \param address the C-string representation of the address
-   */
-  MacAddress (char const *address);
-  ~MacAddress ();
-  
-  /**
-   * \brief Comparison operation between MacAddresses
-   * \param other The address against which to compare this one
-   * \return True if they are equal, false otherwise.
-   */   
-  bool IsEqual (MacAddress other) const;
-  /**
-   * \brief Print this MacAddress to a stream
-   *
-   * The format is colon seperated groups of two hexadecimal digits
-   * \param os The output stream desired
-   */ 
-  void Print (std::ostream &os) const;
-  
-  /**
-   * \return The length in bytes of this MacAddress
-   */
-  uint8_t GetLength() const;
-  /**
-   * \brief Copy routine to peek the contents of the MacAddress
-   *
-   * \param ad Output parameter which holds a copy of this MacAddress
-   */
-  void Peek (uint8_t ad[MAX_LEN]) const;
-  /**
-   * \brief Sets this MacAddress to a specific value
-   * \param ad byte buffer to set the MacAddress to
-   * \param len the length of the buffer
-   */
-  void Set (uint8_t const ad[MAX_LEN], uint8_t len);
-
-  // Static methods/members
-  /**
-   *
-   * Advance the global to the next available mac address.
-   */
-  static void AdvanceAddress();
-  static uint8_t g_nextAddress[MAX_LEN];
-
-private:
-  uint8_t m_address[MAX_LEN];
-  uint8_t m_len;
-};
-
-bool operator == (MacAddress const&a, MacAddress const&b);
-bool operator != (MacAddress const&a, MacAddress const&b);
-bool operator < (MacAddress const&a, MacAddress const&b);
-
-std::ostream& operator<< (std::ostream& os, MacAddress const& address);
-
-}; // namespace ns3
-
-#endif /* MAC_ADDRESS_H */
--- a/src/node/net-device.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/net-device.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -35,7 +35,7 @@
 
 const InterfaceId NetDevice::iid = MakeInterfaceId ("NetDevice", Object::iid);
 
-NetDevice::NetDevice(Ptr<Node> node, const MacAddress& addr) : 
+NetDevice::NetDevice(Ptr<Node> node, const Address& addr) : 
   m_node (node), 
   m_name(""), 
   m_ifIndex (0), 
@@ -53,7 +53,7 @@
 NetDevice::~NetDevice ()
 {}
 
-MacAddress 
+Address 
 NetDevice::GetAddress (void) const
 {
   return m_address;
@@ -113,7 +113,7 @@
 {
   return m_isBroadcast;
 }
-MacAddress const &
+Address const &
 NetDevice::GetBroadcast (void) const
 {
   NS_ASSERT (m_isBroadcast);
@@ -121,7 +121,7 @@
 }
 
 void
-NetDevice::EnableBroadcast (MacAddress broadcast)
+NetDevice::EnableBroadcast (Address broadcast)
 {
   m_isBroadcast = true;
   m_broadcast = broadcast;
@@ -171,7 +171,7 @@
 
 // Receive packet from above
 bool 
-NetDevice::Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber)
+NetDevice::Send(const Packet& p, const Address& dest, uint16_t protocolNumber)
 {
   if (m_isUp)
     {
@@ -197,18 +197,19 @@
 
 // Receive packets from below
 bool
-NetDevice::ForwardUp(Packet& p, uint32_t param)
+NetDevice::ForwardUp(const Packet& p, uint16_t param, const Address &from)
 {
   bool retval = false;
-  Packet packet = p;
 
-  NS_DEBUG ("NetDevice::ForwardUp: UID is " << packet.GetUid()
+  NS_DEBUG ("NetDevice::ForwardUp: UID is " << p.GetUid()
             << " device is: " << GetName());
   
   if (!m_receiveCallback.IsNull ())
     {
-      retval = m_receiveCallback (this, packet, param);
-    } else {
+      retval = m_receiveCallback (this, p, param, from);
+    } 
+  else 
+    {
       NS_DEBUG ("NetDevice::Receive call back is NULL");
     }
 
@@ -248,7 +249,7 @@
 }
 
 void 
-NetDevice::SetReceiveCallback (Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> cb)
+NetDevice::SetReceiveCallback (ReceiveCallback cb)
 {
   m_receiveCallback = cb;
 }
--- a/src/node/net-device.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/net-device.h	Wed Sep 05 18:35:39 2007 +0100
@@ -28,7 +28,7 @@
 #include "ns3/packet.h"
 #include "ns3/object.h"
 #include "ns3/ptr.h"
-#include "mac-address.h"
+#include "address.h"
 
 namespace ns3 {
 
@@ -79,9 +79,9 @@
   Ptr<Channel> GetChannel (void) const;
 
   /**
-   * \return the current MacAddress of this interface.
+   * \return the current Address of this interface.
    */
-  MacAddress GetAddress (void) const;
+  Address GetAddress (void) const;
   /**
    * \param mtu MTU value, in bytes, to set for the device
    * \return whether the MTU value was within legal bounds
@@ -137,7 +137,7 @@
    * Calling this method is invalid if IsBroadcast returns
    * not true.
    */
-  MacAddress const &GetBroadcast (void) const;
+  Address const &GetBroadcast (void) const;
   /**
    * \return value of m_isMulticast flag
    */
@@ -154,11 +154,11 @@
    *        is received.
    * 
    *  Called from higher layer to send packet into Network Device
-   *  to the specified destination MacAddress
+   *  to the specified destination Address
    * 
    * \return whether the Send operation succeeded 
    */
-  bool Send(Packet& p, const MacAddress& dest, uint16_t protocolNumber);
+  bool Send(const Packet& p, const Address& dest, uint16_t protocolNumber);
   /**
    * \returns the node base class which contains this network
    *          interface.
@@ -178,22 +178,35 @@
   bool NeedsArp (void) const;
 
   /**
+   * \param device a pointer to the net device which is calling this callback
+   * \param packet the packet received
+   * \param protocol the 16 bit protocol number associated with this packet.
+   *        This protocol number is expected to be the same protocol number
+   *        given to the Send method by the user on the sender side.
+   * \param address the address of the sender
+   * \returns true if the callback could handle the packet successfully, false
+   *          otherwise.
+   */
+  typedef Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t,const Address &> ReceiveCallback;
+
+  /**
    * \param cb callback to invoke whenever a packet has been received and must
    *        be forwarded to the higher layers.
+   *
    */
-  void SetReceiveCallback (Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> cb);
+  void SetReceiveCallback (ReceiveCallback cb);
 
  protected:
   /**
    * \param node base class node pointer of device's node 
    * \param addr MAC address of this device.
    */
-  NetDevice(Ptr<Node> node, const MacAddress& addr);
+  NetDevice(Ptr<Node> node, const Address& addr);
   /**
    * Enable broadcast support. This method should be
    * called by subclasses from their constructor
    */
-  void EnableBroadcast (MacAddress broadcast);
+  void EnableBroadcast (Address broadcast);
   /**
    * Set m_isBroadcast flag to false
    */
@@ -230,6 +243,7 @@
    * \param p packet sent from below up to Network Device
    * \param param Extra parameter extracted from header and needed by
    * some protocols
+   * \param address the address of the sender of this packet.
    * \returns true if the packet was forwarded successfully,
    *          false otherwise.
    *
@@ -237,7 +251,7 @@
    * forwards it to the higher layers by calling this method
    * which is responsible for passing it up to the Rx callback.
    */
-  bool ForwardUp (Packet& p, uint32_t param);
+  bool ForwardUp (const Packet& p, uint16_t param, const Address &address);
 
 
   /**
@@ -248,8 +262,6 @@
    */
   virtual void DoDispose (void);
 
-  Callback<bool,Ptr<NetDevice>,const Packet &,uint16_t> m_receiveCallback;
-
  private:
   /**
    * \param p packet to send
@@ -262,7 +274,7 @@
    * method.  When the link is Up, this method is invoked to ask 
    * subclasses to forward packets. Subclasses MUST override this method.
    */
-  virtual bool SendTo (Packet& p, const MacAddress &dest, uint16_t protocolNumber) = 0;
+  virtual bool SendTo (const Packet& p, const Address &dest, uint16_t protocolNumber) = 0;
   /**
    * \returns true if this NetDevice needs the higher-layers
    *          to perform ARP over it, false otherwise.
@@ -289,14 +301,15 @@
   Ptr<Node>     m_node;
   std::string   m_name;
   uint16_t      m_ifIndex;
-  MacAddress    m_address;
-  MacAddress    m_broadcast;
+  Address       m_address;
+  Address       m_broadcast;
   uint16_t      m_mtu;
   bool          m_isUp;
   bool          m_isBroadcast;
   bool          m_isMulticast;
   bool          m_isPointToPoint;
   Callback<void> m_linkChangeCallback;
+  ReceiveCallback m_receiveCallback;
 };
 
 }; // namespace ns3
--- a/src/node/node-list.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/node-list.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -40,6 +40,30 @@
 
 namespace ns3 {
 
+NodeListIndex::NodeListIndex ()
+  : m_index (0)
+{}
+NodeListIndex::NodeListIndex (uint32_t index)
+  : m_index (index)
+{}
+void 
+NodeListIndex::Print (std::ostream &os)
+{
+  os << "nodeid=" << m_index;
+}
+uint16_t 
+NodeListIndex::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<NodeListIndex> ("NodeListIndex");
+  return uid;
+}
+uint32_t 
+NodeListIndex::Get (void) const
+{
+  return m_index;
+}
+
+
 /**
  * The private node list used by the static-based API
  */
@@ -53,7 +77,6 @@
   NodeList::Iterator Begin (void);
   NodeList::Iterator End (void);
   TraceResolver *CreateTraceResolver (TraceContext const &context);
-  Node *PeekNode (uint32_t n);
   Ptr<Node> GetNode (uint32_t n);
   uint32_t GetNNodes (void);
 
@@ -99,11 +122,6 @@
 {
   return m_nodes.size ();
 }
-Node *
-NodeListPriv::PeekNode (uint32_t n)
-{
-  return PeekPointer (m_nodes[n]);
-}
 
 Ptr<Node>
 NodeListPriv::GetNode (uint32_t n)
@@ -115,11 +133,11 @@
 TraceResolver *
 NodeListPriv::CreateTraceResolver (TraceContext const &context)
 {
-  ArrayTraceResolver<Node> *resolver =
-    new ArrayTraceResolver<Node>
+  ArrayTraceResolver<Ptr<Node>, NodeListIndex> *resolver =
+    new ArrayTraceResolver<Ptr<Node>, NodeListIndex>
     (context, 
      MakeCallback (&NodeListPriv::GetNNodes, this),
-     MakeCallback (&NodeListPriv::PeekNode, this));
+     MakeCallback (&NodeListPriv::GetNode, this));
   return resolver;
 }
 
--- a/src/node/node-list.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/node-list.h	Wed Sep 05 18:35:39 2007 +0100
@@ -23,7 +23,7 @@
 #define NODE_LIST_H
 
 #include <vector>
-#include "ns3/array-trace-resolver.h"
+#include "ns3/trace-context-element.h"
 #include "ns3/ptr.h"
 
 namespace ns3 {
@@ -32,6 +32,19 @@
 class TraceResolver;
 class TraceContext;
 
+class NodeListIndex : public TraceContextElement
+{
+public:
+  NodeListIndex ();
+  NodeListIndex (uint32_t index);
+  void Print (std::ostream &os);
+  static uint16_t GetUid (void);
+  uint32_t Get (void) const;
+private:
+  uint32_t m_index;
+};
+
+
 /**
  * \brief the list of simulation nodes.
  *
@@ -40,7 +53,6 @@
 class NodeList
 {
 public:
-  typedef ArrayTraceResolver<Node>::Index NodeIndex;
   typedef std::vector< Ptr<Node> >::iterator Iterator;
 
   /**
--- a/src/node/node.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/node.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -1,51 +1,82 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-
-// Implement the basic Node object for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation, 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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
 #include "node.h"
 #include "node-list.h"
 #include "net-device.h"
 #include "application.h"
+#include "packet-socket-factory.h"
 #include "ns3/simulator.h"
+#include "ns3/composite-trace-resolver.h"
+#include "ns3/array-trace-resolver.h"
 
 namespace ns3{
 
 const InterfaceId Node::iid = MakeInterfaceId ("Node", Object::iid);
 
+NodeNetDeviceIndex::NodeNetDeviceIndex ()
+  : m_index (0)
+{}
+NodeNetDeviceIndex::NodeNetDeviceIndex (uint32_t index)
+  : m_index (index)
+{}
+uint32_t 
+NodeNetDeviceIndex::Get (void) const
+{
+  return m_index;
+}
+void 
+NodeNetDeviceIndex::Print (std::ostream &os) const
+{
+  os << "device=" << m_index;
+}
+uint16_t 
+NodeNetDeviceIndex::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<NodeNetDeviceIndex> ("NodeNetDeviceIndex");
+  return uid;
+}
+
+
+
 Node::Node()
   : m_id(0), 
     m_sid(0)
 {
-  SetInterfaceId (Node::iid);
-  m_id = NodeList::Add (this);
+  Construct ();
 }
 
 Node::Node(uint32_t sid)
   : m_id(0), 
     m_sid(sid)
 { 
+  Construct ();
+}
+
+void
+Node::Construct (void)
+{
   SetInterfaceId (Node::iid);
   m_id = NodeList::Add (this);
+  Ptr<PacketSocketFactory> socketFactory = Create<PacketSocketFactory> ();
+  AddInterface (socketFactory);
 }
   
 Node::~Node ()
@@ -54,7 +85,9 @@
 TraceResolver *
 Node::CreateTraceResolver (TraceContext const &context)
 {
-  return DoCreateTraceResolver (context);
+  CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
+  DoFillTraceResolver (*resolver);
+  return resolver;
 }
 
 uint32_t 
@@ -74,8 +107,9 @@
 {
   uint32_t index = m_devices.size ();
   m_devices.push_back (device);
-  DoAddDevice (device);
   device->SetIfIndex(index);
+  device->SetReceiveCallback (MakeCallback (&Node::ReceiveFromDevice, this));
+  NotifyDeviceAdded (device);
   return index;
 }
 Ptr<NetDevice>
@@ -107,8 +141,27 @@
   return m_applications.size ();
 }
 
+TraceResolver *
+Node::CreateDevicesTraceResolver (const TraceContext &context)
+{
+  ArrayTraceResolver<Ptr<NetDevice>,NodeNetDeviceIndex> *resolver = 
+    new ArrayTraceResolver<Ptr<NetDevice>,NodeNetDeviceIndex> 
+    (context,
+     MakeCallback (&Node::GetNDevices, this), 
+     MakeCallback (&Node::GetDevice, this));
+  
+  return resolver;
+}
 
-void Node::DoDispose()
+void
+Node::DoFillTraceResolver (CompositeTraceResolver &resolver)
+{
+  resolver.Add ("devices", 
+                MakeCallback (&Node::CreateDevicesTraceResolver, this));
+}
+
+void 
+Node::DoDispose()
 {
   for (std::vector<Ptr<NetDevice> >::iterator i = m_devices.begin ();
        i != m_devices.end (); i++)
@@ -129,4 +182,56 @@
   Object::DoDispose ();
 }
 
+void 
+Node::NotifyDeviceAdded (Ptr<NetDevice> device)
+{}
+
+void
+Node::RegisterProtocolHandler (ProtocolHandler handler, 
+                               uint16_t protocolType,
+                               Ptr<NetDevice> device)
+{
+  struct Node::ProtocolHandlerEntry entry;
+  entry.handler = handler;
+  entry.protocol = protocolType;
+  entry.device = device;
+  m_handlers.push_back (entry);
+}
+
+void
+Node::UnregisterProtocolHandler (ProtocolHandler handler)
+{
+  for (ProtocolHandlerList::iterator i = m_handlers.begin ();
+       i != m_handlers.end (); i++)
+    {
+      if (i->handler.IsEqual (handler))
+        {
+          m_handlers.erase (i);
+          break;
+        }
+    }
+}
+
+bool
+Node::ReceiveFromDevice (Ptr<NetDevice> device, const Packet &packet, 
+                         uint16_t protocol, const Address &from)
+{
+  bool found = false;
+  for (ProtocolHandlerList::iterator i = m_handlers.begin ();
+       i != m_handlers.end (); i++)
+    {
+      if (i->device == 0 ||
+          (i->device != 0 && i->device == device))
+        {
+          if (i->protocol == 0 || 
+              i->protocol == protocol)
+            {
+              i->handler (device, packet, protocol, from);
+              found = true;
+            }
+        }
+    }
+  return found;
+}
+
 }//namespace ns3
--- a/src/node/node.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/node.h	Wed Sep 05 18:35:39 2007 +0100
@@ -1,33 +1,31 @@
-// -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*-
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
-
-// Define the basic Node object for ns3.
-// George F. Riley, Georgia Tech, Fall 2006
-
-#ifndef I_NODE_H
-#define I_NODE_H
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation, 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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef NODE_H
+#define NODE_H
 
 #include <vector>
 
 #include "ns3/object.h"
+#include "ns3/callback.h"
+#include "ns3/trace-context-element.h"
 
 namespace ns3 {
 
@@ -35,6 +33,21 @@
 class TraceResolver;
 class NetDevice;
 class Application;
+class Packet;
+class Address;
+class CompositeTraceResolver;
+
+class NodeNetDeviceIndex : public TraceContextElement
+{
+public:
+  NodeNetDeviceIndex ();
+  NodeNetDeviceIndex (uint32_t index);
+  uint32_t Get (void) const;
+  void Print (std::ostream &os) const;
+  static uint16_t GetUid (void);
+private:
+  uint32_t m_index;
+};
 
 /**
  * \brief A network Node.
@@ -58,6 +71,17 @@
 public:
   static const InterfaceId iid;
 
+  /**
+   * Must be invoked by subclasses only.
+   */
+  Node();
+  /**
+   * \param systemId a unique integer used for parallel simulations.
+   *
+   * Must be invoked by subclasses only.
+   */
+  Node(uint32_t systemId);
+
   virtual ~Node();
 
   /**
@@ -93,11 +117,15 @@
    * Associate this device to this node.
    * This method is called automatically from NetDevice::NetDevice
    * so the user has little reason to call this method himself.
+   * The index returned is always non-zero.
    */
   uint32_t AddDevice (Ptr<NetDevice> device);
   /**
    * \param index the index of the requested NetDevice
    * \returns the requested NetDevice associated to this Node.
+   *
+   * The indexes used by the GetDevice method start at one and
+   * end at GetNDevices ()
    */
   Ptr<NetDevice> GetDevice (uint32_t index) const;
   /**
@@ -127,32 +155,52 @@
    */
   uint32_t GetNApplications (void) const;
 
-protected:
   /**
-   * Must be invoked by subclasses only.
+   * A protocol handler
    */
-  Node();
+  typedef Callback<void,Ptr<NetDevice>, const Packet &,uint16_t,const Address &> ProtocolHandler;
   /**
-   * \param systemId a unique integer used for parallel simulations.
+   * \param handler the handler to register
+   * \param protocolType the type of protocol this handler is 
+   *        interested in. This protocol type is a so-called
+   *        EtherType, as registered here:
+   *        http://standards.ieee.org/regauth/ethertype/eth.txt
+   *        the value zero is interpreted as matching all
+   *        protocols.
+   * \param device the device attached to this handler. If the
+   *        value is zero, the handler is attached to all
+   *        devices on this node.
+   */
+  void RegisterProtocolHandler (ProtocolHandler handler, 
+                                uint16_t protocolType,
+                                Ptr<NetDevice> device);
+  /**
+   * \param handler the handler to unregister
    *
-   * Must be invoked by subclasses only.
+   * After this call returns, the input handler will never
+   * be invoked anymore.
    */
-  Node(uint32_t systemId);
+  void UnregisterProtocolHandler (ProtocolHandler handler);
+
+protected:
   /**
    * The dispose method. Subclasses must override this method
    * and must chain up to it by calling Node::DoDispose at the
    * end of their own DoDispose method.
    */
   virtual void DoDispose (void);
+  /**
+   * \param resolver the resolver to store trace sources in.
+   *
+   * If a subclass wants to add new traces to a Node, it needs
+   * to override this method and record the new trace sources
+   * in the input resolver. Subclasses also _must_ chain up to
+   * their parent's DoFillTraceResolver method prior
+   * to recording they own trace sources.
+   */
+  virtual void DoFillTraceResolver (CompositeTraceResolver &resolver);
 private:
   /**
-   * \param context the trace context
-   * \returns a trace resolver to the user. The user must delete it.
-   *
-   * Subclasses must implement this method.
-   */
-  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context) = 0;
-  /**
    * \param device the device added to this Node.
    *
    * This method is invoked whenever a user calls Node::AddDevice.
@@ -160,14 +208,26 @@
    * at this point to setup the node's receive function for
    * the NetDevice packets.
    */
-  virtual void DoAddDevice (Ptr<NetDevice> device) = 0;
+  virtual void NotifyDeviceAdded (Ptr<NetDevice> device);
+
+  bool ReceiveFromDevice (Ptr<NetDevice> device, const Packet &packet, 
+                          uint16_t protocol, const Address &from);
+  void Construct (void);
+  TraceResolver *CreateDevicesTraceResolver (const TraceContext &context);
 
+  struct ProtocolHandlerEntry {
+    ProtocolHandler handler;
+    uint16_t protocol;
+    Ptr<NetDevice> device;
+  };
+  typedef std::vector<struct Node::ProtocolHandlerEntry> ProtocolHandlerList;
   uint32_t    m_id;         // Node id for this node
   uint32_t    m_sid;        // System id for this node
   std::vector<Ptr<NetDevice> > m_devices;
   std::vector<Ptr<Application> > m_applications;
+  ProtocolHandlerList m_handlers;
 };
 
 } //namespace ns3
 
-#endif /* I_NODE_H */
+#endif /* NODE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-address.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,134 @@
+/* -*-  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 "packet-socket-address.h"
+#include "net-device.h"
+
+namespace ns3 {
+
+PacketSocketAddress::PacketSocketAddress ()
+{}
+void 
+PacketSocketAddress::SetProtocol (uint16_t protocol)
+{
+  m_protocol = protocol;
+}
+void
+PacketSocketAddress::SetAllDevices (void)
+{
+  m_isSingleDevice = false;
+  m_device = 0;
+}
+void 
+PacketSocketAddress::SetSingleDevice (uint32_t index)
+{
+  m_isSingleDevice = true;
+  m_device = index;
+}
+void 
+PacketSocketAddress::SetPhysicalAddress (const Address address)
+{
+  m_address = address;
+}
+
+uint16_t 
+PacketSocketAddress::GetProtocol (void) const
+{
+  return m_protocol;
+}
+bool
+PacketSocketAddress::IsSingleDevice (void) const
+{
+  return m_isSingleDevice;
+}
+uint32_t
+PacketSocketAddress::GetSingleDevice (void) const
+{
+  return m_device;
+}
+Address 
+PacketSocketAddress::GetPhysicalAddress (void) const
+{
+  return m_address;
+}
+
+PacketSocketAddress::operator Address () const
+{
+  return ConvertTo ();
+}
+
+Address 
+PacketSocketAddress::ConvertTo (void) const
+{
+  Address address;
+  uint8_t buffer[Address::MAX_SIZE];
+  buffer[0] = m_protocol & 0xff;
+  buffer[1] = (m_protocol >> 8) & 0xff;
+  buffer[2] = (m_device >> 24) & 0xff;
+  buffer[3] = (m_device >> 16) & 0xff;
+  buffer[4] = (m_device >> 8) & 0xff;
+  buffer[5] = (m_device >> 0) & 0xff;
+  buffer[6] = m_isSingleDevice?1:0;
+  uint32_t copied = m_address.CopyAllTo (buffer + 7, Address::MAX_SIZE - 7);
+  return Address (GetType (), buffer, 7 + copied);
+}
+PacketSocketAddress 
+PacketSocketAddress::ConvertFrom (const Address &address)
+{
+  NS_ASSERT (IsMatchingType (address));
+  uint8_t buffer[Address::MAX_SIZE];
+  address.CopyTo (buffer);
+  uint16_t protocol = buffer[0] | (buffer[1] << 8);
+  uint32_t device = 0;
+  device |= buffer[2];
+  device <<= 8;
+  device |= buffer[3];
+  device <<= 8;
+  device |= buffer[4];
+  device <<= 8;
+  device |= buffer[5];
+  bool isSingleDevice = (buffer[6] == 1)?true:false;
+  Address physical;
+  physical.CopyAllFrom (buffer + 7, Address::MAX_SIZE - 7);
+  PacketSocketAddress ad;
+  ad.SetProtocol (protocol);
+  if (isSingleDevice)
+    {
+      ad.SetSingleDevice (device);
+    }
+  else
+    {
+      ad.SetAllDevices ();
+    }
+  ad.SetPhysicalAddress (physical);
+  return ad;
+}
+bool 
+PacketSocketAddress::IsMatchingType (const Address &address)
+{
+  return address.IsMatchingType (GetType ());
+}
+uint8_t 
+PacketSocketAddress::GetType (void)
+{
+  static uint8_t type = Address::Register ();
+  return type;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-address.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,77 @@
+/* -*-  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>
+ */
+#ifndef PACKET_SOCKET_ADDRESS_H
+#define PACKET_SOCKET_ADDRESS_H
+
+#include "ns3/ptr.h"
+#include "address.h"
+#include "eui48-address.h"
+#include "eui64-address.h"
+#include "net-device.h"
+
+namespace ns3 {
+
+class NetDevice;
+
+class PacketSocketAddress
+{
+ public:
+  PacketSocketAddress ();
+  void SetProtocol (uint16_t protocol);
+
+  void SetAllDevices (void);
+  void SetSingleDevice (uint32_t device);
+  void SetPhysicalAddress (const Address address);
+
+  uint16_t GetProtocol (void) const;
+  uint32_t GetSingleDevice (void) const;
+  bool IsSingleDevice (void) const;
+  Address GetPhysicalAddress (void) const;
+
+  /**
+   * \returns a new Address instance
+   *
+   * Convert an instance of this class to a polymorphic Address instance.
+   */
+  operator Address () const;
+  /**
+   * \param address a polymorphic address
+   *
+   * Convert a polymorphic address to an Eui48Address instance.
+   * The conversion performs a type check.
+   */
+  static PacketSocketAddress ConvertFrom (const Address &address);
+  /**
+   * \returns true if the address matches, false otherwise.
+   */
+  static bool IsMatchingType (const Address &address);
+ private:
+  static uint8_t GetType (void);
+  Address ConvertTo (void) const;
+  uint16_t m_protocol;
+  bool m_isSingleDevice;
+  uint32_t m_device;
+  Address m_address;
+};
+
+
+} // namespace ns3
+
+#endif /* PACKET_SOCKET_ADDRESS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#include "packet-socket-factory.h"
+#include "node.h"
+
+namespace ns3 {
+
+const InterfaceId PacketSocketFactory::iid = MakeInterfaceId ("Packet", 
+                                                              SocketFactory::iid);
+
+PacketSocketFactory::PacketSocketFactory ()
+{
+  SetInterfaceId (PacketSocketFactory::iid);
+}
+
+Ptr<Socket> PacketSocketFactory::CreateSocket (void)
+{
+  Ptr<Node> node = QueryInterface<Node> (Node::iid);
+  Ptr<PacketSocket> socket = Create<PacketSocket> (node);
+  return socket;
+} 
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket-factory.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,52 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise
+ * 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: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ */
+#ifndef PACKET_SOCKET_FACTORY_H
+#define PACKET_SOCKET_FACTORY_H
+
+#include "socket-factory.h"
+#include "packet-socket.h"
+
+namespace ns3 {
+
+class Socket;
+
+/**
+ * This can be used as an interface in a node in order for the node to
+ * generate PacketSockets that can connect to net devices.
+ */
+class PacketSocketFactory : public SocketFactory
+{
+public:
+  static const InterfaceId iid; /// Interface identifier
+
+  PacketSocketFactory ();
+
+  /**
+   * Creates a PacketSocket and returns a pointer to it.
+   *
+   * \return a pointer to the created socket
+   */
+  virtual Ptr<Socket> CreateSocket (void);
+};
+
+} // namespace ns3
+
+#endif /* PACKET_SOCKET_FACTORY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,285 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, 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
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+
+#include "packet-socket.h"
+#include "packet-socket-address.h"
+#include "ns3/debug.h"
+#include "ns3/node.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("PacketSocket");
+
+namespace ns3 {
+
+PacketSocket::PacketSocket (Ptr<Node> node)
+  : m_node (node)
+{
+  Init();
+}
+
+void 
+PacketSocket::Init()
+{
+  m_state = STATE_OPEN;
+  m_shutdownSend = false;
+  m_shutdownRecv = false;
+  m_errno = ERROR_NOTERROR;
+}
+
+PacketSocket::~PacketSocket ()
+{}
+
+void 
+PacketSocket::DoDispose (void)
+{
+  m_device = 0;
+}
+
+enum Socket::SocketErrno
+PacketSocket::GetErrno (void) const
+{
+  return m_errno;
+}
+
+Ptr<Node>
+PacketSocket::GetNode (void) const
+{
+  return m_node;
+}
+
+int
+PacketSocket::Bind (void)
+{
+  PacketSocketAddress address;
+  address.SetProtocol (0);
+  address.SetAllDevices ();
+  return DoBind (address);
+}
+int
+PacketSocket::Bind (const Address &address)
+{
+  if (!PacketSocketAddress::IsMatchingType (address))
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  PacketSocketAddress ad = PacketSocketAddress::ConvertFrom (address);
+  return DoBind (ad);
+}
+
+int
+PacketSocket::DoBind (const PacketSocketAddress &address)
+{
+  if (m_state == STATE_BOUND ||
+      m_state == STATE_CONNECTED)
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  Ptr<NetDevice> dev ;
+  if (address.IsSingleDevice ())
+    {
+      dev = 0;
+    }
+  else
+    {
+      m_node->GetDevice (address.GetSingleDevice ());
+    }
+  m_node->RegisterProtocolHandler (MakeCallback (&PacketSocket::ForwardUp, this),
+                                   address.GetProtocol (), dev);
+  m_state = STATE_BOUND;
+  m_protocol = address.GetProtocol ();
+  m_isSingleDevice = address.IsSingleDevice ();
+  m_device = address.GetSingleDevice ();
+  return 0;
+}
+
+int
+PacketSocket::ShutdownSend (void)
+{
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  m_shutdownSend = true;
+  return 0;
+}
+int
+PacketSocket::ShutdownRecv (void)
+{
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  m_shutdownRecv = false;
+  return 0;
+}
+int
+PacketSocket::Close(void)
+{
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  m_state = STATE_CLOSED;
+  NotifyCloseCompleted ();
+  return 0;
+}
+
+int
+PacketSocket::Connect(const Address &ad)
+{
+  PacketSocketAddress address;
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      goto error;
+    }
+  if (m_state == STATE_OPEN)
+    {
+      // connect should happen _after_ bind.
+      m_errno = ERROR_INVAL; // generic error condition.
+      goto error;
+    }
+  if (m_state == STATE_CONNECTED)
+    {
+      m_errno = ERROR_ISCONN;
+      goto error;
+    }
+  if (!PacketSocketAddress::IsMatchingType (ad))
+    {
+      m_errno = ERROR_AFNOSUPPORT;
+      goto error;
+    }
+  m_destAddr = ad;
+  m_state = STATE_CONNECTED;
+  NotifyConnectionSucceeded ();
+  return 0;
+ error:
+  NotifyConnectionFailed ();
+  return -1;
+}
+
+int
+PacketSocket::Send (const Packet &p)
+{
+  if (m_state == STATE_OPEN ||
+      m_state == STATE_BOUND)
+    {
+      m_errno = ERROR_NOTCONN;
+      return -1;
+    }
+  return SendTo (m_destAddr, p);
+}
+
+int
+PacketSocket::SendTo(const Address &address, const Packet &p)
+{
+  PacketSocketAddress ad;
+  if (m_state == STATE_CLOSED)
+    {
+      m_errno = ERROR_BADF;
+      return -1;
+    }
+  if (m_state == STATE_OPEN)
+    {
+      // XXX should return another error here.
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  if (m_shutdownSend)
+    {
+      m_errno = ERROR_SHUTDOWN;
+      return -1;
+    }
+  if (!PacketSocketAddress::IsMatchingType (address))
+    {
+      m_errno = ERROR_AFNOSUPPORT;
+      return -1;
+    }
+  ad = PacketSocketAddress::ConvertFrom (address);
+  
+  bool error = false;
+  Address dest = ad.GetPhysicalAddress ();
+  if (ad.IsSingleDevice ())
+    {
+      Ptr<NetDevice> device = m_node->GetDevice (ad.GetSingleDevice ());
+      if (!device->Send (p, dest, ad.GetProtocol ()))
+        {
+          error = true;
+        }
+    }
+  else
+    {
+      for (uint32_t i = 0; i < m_node->GetNDevices (); i++)
+        {
+          Ptr<NetDevice> device = m_node->GetDevice (i);
+          if (!device->Send (p, dest, ad.GetProtocol ()))
+            {
+              error = true;
+            }
+        }
+    }
+  if (!error)
+    {
+      NotifyDataSent (p.GetSize ());
+    }
+
+  if (error)
+    {
+      m_errno = ERROR_INVAL;
+      return -1;
+    }
+  else
+    {
+      return 0;
+    }
+}
+
+void 
+PacketSocket::ForwardUp (Ptr<NetDevice> device, const Packet &packet, 
+                         uint16_t protocol, const Address &from)
+{
+  if (m_shutdownRecv)
+    {
+      return;
+    }
+
+  Packet p = packet;
+
+  PacketSocketAddress address;
+  address.SetPhysicalAddress (from);
+  address.SetSingleDevice (device->GetIfIndex ());
+  address.SetProtocol (protocol);
+
+  NS_DEBUG ("PacketSocket::ForwardUp: UID is " << packet.GetUid()
+            << " PacketSocket " << this);
+  NotifyDataReceived (p, address);
+}
+
+}//namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/node/packet-socket.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,119 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2007 Emmanuelle Laprise, 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
+ *
+ * Authors: Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>,
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef PACKET_SOCKET_H
+#define PACKET_SOCKET_H
+
+#include <stdint.h>
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "ns3/socket.h"
+
+namespace ns3 {
+
+class Node;
+class Packet;
+class NetDevice;
+class PacketSocketAddress;
+
+/**
+ * \brief A PacketSocket is a link between an application and a net device.
+ *
+ * A PacketSocket can be used to connect an application to a net
+ * device. The application provides the buffers of data, the socket
+ * conserts them to a raw packet and the net device then adds the
+ * protocol specific headers and trailers. This socket type
+ * is very similar to the linux and BSD "packet" sockets.
+ *
+ * Here is a summary of the semantics of this class:
+ * - Bind: Bind uses only the protocol and device fields of the 
+ *       PacketSocketAddress. If none are provided, Bind uses 
+ *       zero for both, which means that the socket is bound
+ *       to all protocols on all devices on the node.
+ *
+ * - Connect: uses only the protocol, device and "physical address" 
+ *       field of the PacketSocketAddress. It is used to set the default
+ *       destination address for outgoing packets.
+ *
+ * - Send: send the input packet to the underlying NetDevices
+ *       with the default destination address. The socket must
+ *       be bound and connected.
+ *
+ * - SendTo: uses the protocol, device, and "physical address" 
+ *       fields of the PacketSocketAddress. The device value is 
+ *       used to specialize the packet transmission to a single 
+ *       device, the protocol value specifies the protocol of this
+ *       packet only and the "physical address" field is used to override the 
+ *       default destination address. The socket must be bound.
+ *
+ * - Recv: The address represents the address of the packer originator.
+ *       The fields "physical address", device, and protocol are filled.
+ *
+ * - Accept: not allowed
+ */
+class PacketSocket : public Socket
+{
+public:
+  PacketSocket (Ptr<Node> node);
+  virtual ~PacketSocket ();
+
+  virtual enum SocketErrno GetErrno (void) const;
+  virtual Ptr<Node> GetNode (void) const;
+  virtual int Bind (void);
+  virtual int Bind (const Address & address);
+  virtual int Close (void);
+  virtual int ShutdownSend (void);
+  virtual int ShutdownRecv (void);
+  virtual int Connect(const Address &address);
+  virtual int Send (const Packet &p);
+  virtual int SendTo(const Address &address,const Packet &p);
+
+
+private:
+
+private:
+  void Init (void);
+  void ForwardUp (Ptr<NetDevice> device, const Packet &packet, 
+                  uint16_t protocol, const Address &from);
+  int DoBind (const PacketSocketAddress &address);
+  virtual void DoDispose (void);
+
+  enum State {
+    STATE_OPEN,
+    STATE_BOUND,     // open and bound
+    STATE_CONNECTED, // open, bound and connected
+    STATE_CLOSED
+  };
+  Ptr<Node> m_node;
+  enum SocketErrno m_errno;
+  bool m_shutdownSend;
+  bool m_shutdownRecv;
+  enum State m_state;
+  uint16_t m_protocol;
+  bool m_isSingleDevice;
+  uint32_t m_device;
+  Address m_destAddr; /// Default destination address
+};
+
+}//namespace ns3
+
+#endif /* PACKET_SOCKET_H */
+
+
--- a/src/node/queue.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/queue.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -31,6 +31,52 @@
 static ClassIdDefaultValue g_classIdDefaultValue ("Queue", "Packet Queue",
                                                   Queue::iid, "DropTailQueue");
 
+
+uint16_t 
+QueueTraceType::GetUid (void)
+{
+  static uint16_t uid = AllocateUid<QueueTraceType> ("QueueTraceType");
+  return uid;
+}
+QueueTraceType::QueueTraceType ()
+  : m_type (QueueTraceType::ENQUEUE)
+{}
+QueueTraceType::QueueTraceType (enum Type type)
+  : m_type (type)
+{}
+bool 
+QueueTraceType::IsEnqueue (void) const
+{
+  return m_type == ENQUEUE;
+}
+bool 
+QueueTraceType::IsDequeue (void) const
+{
+  return m_type == DEQUEUE;
+}
+bool 
+QueueTraceType::IsDrop (void) const
+{
+  return m_type == DROP;
+}
+
+void 
+QueueTraceType::Print (std::ostream &os) const
+{
+  os << "queue-";
+  switch (m_type) {
+  case QueueTraceType::ENQUEUE:
+    os << "enqueue";
+    break;
+  case QueueTraceType::DEQUEUE:
+    os << "dequeue";
+    break;
+  case QueueTraceType::DROP:
+    os << "drop";
+    break;
+  }
+}
+
 Queue::Queue() : 
   m_nBytes(0), 
   m_nTotalReceivedBytes(0),
@@ -52,9 +98,9 @@
 Queue::CreateTraceResolver (TraceContext const &context)
 {
   CompositeTraceResolver *resolver = new CompositeTraceResolver (context);
-  resolver->Add ("enqueue", m_traceEnqueue, Queue::ENQUEUE);
-  resolver->Add ("dequeue", m_traceDequeue, Queue::DEQUEUE);
-  resolver->Add ("drop", m_traceDrop, Queue::DROP);
+  resolver->Add ("enqueue", m_traceEnqueue, QueueTraceType (QueueTraceType::ENQUEUE));
+  resolver->Add ("dequeue", m_traceDequeue, QueueTraceType (QueueTraceType::DEQUEUE));
+  resolver->Add ("drop", m_traceDrop, QueueTraceType (QueueTraceType::DROP));
   return resolver;
 }
 
--- a/src/node/queue.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/queue.h	Wed Sep 05 18:35:39 2007 +0100
@@ -31,11 +31,32 @@
 #include "ns3/object.h"
 #include "ns3/callback-trace-source.h"
 #include "ns3/trace-resolver.h"
+#include "ns3/trace-context-element.h"
 
 namespace ns3 {
 
 class StringEnumDefaultValue;
 
+class QueueTraceType : public TraceContextElement
+{
+public:
+  enum Type {
+    ENQUEUE,
+    DEQUEUE,
+    DROP
+  };
+  static uint16_t GetUid (void);
+  QueueTraceType ();
+  QueueTraceType (enum Type type);
+  bool IsEnqueue (void) const;
+  bool IsDequeue (void) const;
+  bool IsDrop (void) const;
+  void Print (std::ostream &os) const;
+private:
+  enum Type m_type;
+};
+
+
 /**
  * \brief Abstract base class for packet Queues
  * 
@@ -46,11 +67,6 @@
 public:
   static const InterfaceId iid;
 
-  enum TraceType {
-    ENQUEUE,
-    DEQUEUE,
-    DROP,
-  };
   Queue ();
   virtual ~Queue ();
 
--- a/src/node/socket.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/socket.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -1,4 +1,26 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation
+ *               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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
 #include "socket.h"
+#include "ns3/packet.h"
 
 namespace ns3 {
 
@@ -6,76 +28,117 @@
 {}
 
 void 
-Socket::Close(Callback<void, Ptr<Socket> > closeCompleted)
+Socket::SetCloseCallback (Callback<void,Ptr<Socket> > closeCompleted)
+{
+  m_closeCompleted = closeCompleted;
+}
+void 
+Socket::SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
+			    Callback<void, Ptr<Socket> > connectionFailed,
+			    Callback<void, Ptr<Socket> > halfClose)
 {
-  DoClose (closeCompleted);
+  m_connectionSucceeded = connectionSucceeded;
+  m_connectionFailed = connectionFailed;
+  m_halfClose = halfClose;
+}
+void 
+Socket::SetAcceptCallback (Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
+			   Callback<void, Ptr<Socket>, const Address&> newConnectionCreated,
+			   Callback<void, Ptr<Socket> > closeRequested)
+{
+  m_connectionRequest = connectionRequest;
+  m_newConnectionCreated = newConnectionCreated;
+  m_closeRequested = closeRequested;
+}
+void 
+Socket::SetSendCallback (Callback<void, Ptr<Socket>, uint32_t> dataSent)
+{
+  m_dataSent = dataSent;
+}
+void 
+Socket::SetRecvCallback (Callback<void, Ptr<Socket>, const Packet &,const Address&> receivedData)
+{
+  m_receivedData = receivedData;
 }
 
 void 
-Socket::Connect(const Ipv4Address & address,
-               uint16_t portNumber,
-               Callback<void, Ptr<Socket> > connectionSucceeded,
-               Callback<void, Ptr<Socket> > connectionFailed,
-               Callback<void, Ptr<Socket> > halfClose)
+Socket::NotifyCloseCompleted (void)
 {
-  DoConnect (address, portNumber, connectionSucceeded, connectionFailed, halfClose);
-}
-int
-Socket::Accept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
-	       Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
-	       Callback<void, Ptr<Socket> > closeRequested)
-{
-  return DoAccept (connectionRequest, newConnectionCreated, closeRequested);
+  if (!m_closeCompleted.IsNull ())
+    {
+      m_closeCompleted (this);
+    }
 }
-int 
-Socket::Send (const uint8_t* buffer,
-	      uint32_t size,
-	      Callback<void, Ptr<Socket>, uint32_t> dataSent)
+void 
+Socket::NotifyConnectionSucceeded (void)
 {
-  return DoSend (buffer, size, dataSent);
+  if (!m_connectionSucceeded.IsNull ())
+    {
+      m_connectionSucceeded (this);
+    }
 }
-int 
-Socket::SendTo(const Ipv4Address &address,
-	       uint16_t port,
-	       const uint8_t *buffer,
-	       uint32_t size,
-	       Callback<void, Ptr<Socket>, uint32_t> dataSent)
+void 
+Socket::NotifyConnectionFailed (void)
 {
-  return DoSendTo (address, port, buffer, size, dataSent);
+  if (!m_connectionFailed.IsNull ())
+    {
+      m_connectionFailed (this);
+    }
 }
 void 
-Socket::Recv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> callback)
+Socket::NotifyHalfClose (void)
+{
+  if (!m_halfClose.IsNull ())
+    {
+      m_halfClose (this);
+    }
+}
+bool 
+Socket::NotifyConnectionRequest (const Address &from)
 {
-  DoRecv (callback);
+  if (!m_connectionRequest.IsNull ())
+    {
+      return m_connectionRequest (this, from);
+    }
+  else
+    {
+      // refuse all incomming connections by default.
+      return false;
+    }
 }
 void 
-Socket::RecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> callback)
+Socket::NotifyNewConnectionCreated (Ptr<Socket> socket, const Address &from)
+{
+  if (!m_newConnectionCreated.IsNull ())
+    {
+      m_newConnectionCreated (socket, from);
+    }
+}
+void 
+Socket::NotifyCloseRequested (void)
 {
-  DoRecvDummy (callback);
+  if (!m_closeRequested.IsNull ())
+    {
+      m_closeRequested (this);
+    }
+}
+void 
+Socket::NotifyDataSent (uint32_t size)
+{
+  if (!m_dataSent.IsNull ())
+    {
+      m_dataSent (this, size);
+    }
+}
+void 
+Socket::NotifyDataReceived (const Packet &p, const Address &from)
+{
+  if (!m_receivedData.IsNull ())
+    {
+      m_receivedData (this, p, from);
+    }
 }
 
 
-bool 
-Socket::RefuseAllConnections (Ptr<Socket> socket, const Ipv4Address& address, uint16_t port)
-{
-  return false;
-}
-void 
-Socket::DummyCallbackVoidSocket (Ptr<Socket> socket)
-{}
-void
-Socket::DummyCallbackVoidSocketUi32 (Ptr<Socket> socket, uint32_t)
-{}
-void 
-Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr<Socket> socket, uint32_t, const Ipv4Address &, uint16_t)
-{}
-void 
-Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr<Socket> socket, const uint8_t *, uint32_t,
-							  const Ipv4Address &, uint16_t)
-{}
-void 
-Socket::DummyCallbackVoidSocketIpv4AddressUi16 (Ptr<Socket> socket, const Ipv4Address &, uint16_t)
-{}
-
 
 }//namespace ns3
--- a/src/node/socket.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/socket.h	Wed Sep 05 18:35:39 2007 +0100
@@ -1,42 +1,44 @@
-/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
-//
-// Copyright (c) 2006 Georgia Tech Research Corporation
-//
-// 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: George F. Riley<riley@ece.gatech.edu>
-//
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006 Georgia Tech Research Corporation
+ *               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
+ *
+ * Authors: George F. Riley<riley@ece.gatech.edu>
+ *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
 
 #ifndef __SOCKET_H__
 #define __SOCKET_H__
 
 #include "ns3/callback.h"
 #include "ns3/ptr.h"
-#include "ipv4-address.h"
 #include "ns3/object.h"
+#include "address.h"
 #include <stdint.h>
 
 namespace ns3 {
 
 class Node;
+class Packet;
 
 /**
  * \brief Define a Socket API based on the BSD Socket API.
  *
  * Contrary to the original BSD socket API, this API is asynchronous:
- * it does not contain blocking calls. This API also does not use
- * the dreaded BSD sockaddr_t type. Other than that, it tries to stick
+ * it does not contain blocking calls. Other than that, it tries to stick
  * to the BSD API to make it easier those who know the BSD API to use
  * this API.
  */
@@ -53,6 +55,9 @@
     ERROR_AGAIN,
     ERROR_SHUTDOWN,
     ERROR_OPNOTSUPP,
+    ERROR_AFNOSUPPORT,
+    ERROR_INVAL,
+    ERROR_BADF,
     SOCKET_ERRNO_LAST
   };
 
@@ -68,53 +73,77 @@
    */
   virtual Ptr<Node> GetNode (void) const = 0;
 
+  /**
+   * \param closeCompleted Callback invoked when the close operation is
+   *        completed.
+   */
+  void SetCloseCallback (Callback<void,Ptr<Socket> > closeCompleted);
+
+  /**
+   * \param connectionSucceeded this callback is invoked when the connection request
+   *        initiated by the user is successfully completed. The callback is passed
+   *        back a pointer to the same socket object.
+   * \param connectionFailed this callback is invoked when the connection request
+   *        initiated by the user is unsuccessfully completed. The callback is passed
+   *        back a pointer to the same socket object. 
+   * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the
+   *        other side closes the connection ? Or when I call Close ?
+   */
+  void SetConnectCallback (Callback<void, Ptr<Socket> > connectionSucceeded,
+                          Callback<void, Ptr<Socket> > connectionFailed,
+                          Callback<void, Ptr<Socket> > halfClose);
+  /**
+   * \brief Accept connection requests from remote hosts
+   * \param connectionRequest Callback for connection request from peer. 
+   *        This user callback is passed a pointer to this socket, the 
+   *        ip address and the port number of the connection originator. 
+   *        This callback must return true to accept the incoming connection,
+   *        false otherwise. If the connection is accepted, the 
+   *        "newConnectionCreated" callback will be invoked later to give access
+   *        to the user to the socket created to match this new connection. If the
+   *        user does not explicitely specify this callback, all incoming 
+   *        connections will be refused.
+   * \param newConnectionCreated Callback for new connection: when a new
+   *        is accepted, it is created and the corresponding socket is passed
+   *        back to the user through this callback. This user callback is passed
+   *        a pointer to the new socket, and the ip address and port number
+   *        of the connection originator.
+   * \param closeRequested Callback for connection close request from peer.
+   *        XXX: when is this callback invoked ?
+   */
+  void SetAcceptCallback (Callback<bool, Ptr<Socket>, const Address &> connectionRequest,
+                                 Callback<void, Ptr<Socket>, const Address&> newConnectionCreated,
+                                 Callback<void, Ptr<Socket> > closeRequested);
+  void SetSendCallback (Callback<void, Ptr<Socket>, uint32_t> dataSent);
+  /**
+   * \brief Receive data
+   * \param receivedData Invoked whenever new data is received.
+   *
+   */
+  void SetRecvCallback (Callback<void, Ptr<Socket>, const Packet &,const Address&> receivedData);
+
   /** 
-   * Allocate a free port number and
-   * bind this socket to this port number on all
-   * interfaces of this system.
+   * \param address the address to try to allocate
+   * \returns 0 on success, -1 on failure.
+   *
+   * Allocate a local endpoint for this socket.
+   */
+  virtual int Bind (const Address &address) = 0;
+
+  /** 
+   * Allocate a local endpoint for this socket.
    *
    * \returns 0 on success, -1 on failure.
    */
-  virtual int Bind (void) = 0;
-
-  /** 
-   * Allocate a free port number and
-   * bind this socket to this port number on the
-   * specified interface.
-   *
-   * \param address address of interface to bind to.
-   * \returns 0 on success, -1 on failure.
-   */
-  virtual int Bind (Ipv4Address address) = 0;
-
-  /**
-   * Bind this socket to this port number
-   * on all interfaces of this system.
-   *
-   * \param port port to bind to on all interfaces
-   * \returns 0 on success, -1 on failure.
-   */
-  virtual int Bind (uint16_t port) = 0; 
-
-  /**
-   * Bind this socket to this port number
-   * on the interface specified by address.
-   *
-   * \param address address of interface to bind to.
-   * \param port port to bind to on specified interface
-   * \returns 0 on success, -1 on failure.
-   */
-  virtual int Bind (Ipv4Address address, uint16_t port) = 0;
+  virtual int Bind () = 0;
 
   /** 
    * \brief Close a socket.
-   * \param closeCompleted Callback invoked when the close operation is
-   *        completed.
    *
    * After the Close call, the socket is no longer valid, and cannot
    * safely be used for subsequent operations.
    */
-  void Close(Callback<void, Ptr<Socket> > closeCompleted = MakeCallback (&Socket::DummyCallbackVoidSocket));
+  virtual int Close(void) = 0;
 
   /**
    * \returns zero on success, -1 on failure.
@@ -134,127 +163,47 @@
 
   /**
    * \brief Initiate a connection to a remote host
-   * \param address IP Address of remote.
-   * \param portNumber Port number of remote
-   * \param connectionSucceeded this callback is invoked when the connection request
-   *        initiated by the user is successfully completed. The callback is passed
-   *        back a pointer to the same socket object.
-   * \param connectionFailed this callback is invoked when the connection request
-   *        initiated by the user is unsuccessfully completed. The callback is passed
-   *        back a pointer to the same socket object. 
-   * \param halfClose XXX When exactly is this callback invoked ? If it invoked when the
-   *        other side closes the connection ? Or when I call Close ?
+   * \param address Address of remote.
    */
-  void Connect(const Ipv4Address & address,
-               uint16_t portNumber,
-               Callback<void, Ptr<Socket> > connectionSucceeded = MakeCallback(&Socket::DummyCallbackVoidSocket),
-               Callback<void, Ptr<Socket> > connectionFailed = MakeCallback(&Socket::DummyCallbackVoidSocket),
-               Callback<void, Ptr<Socket> > halfClose = MakeCallback(&Socket::DummyCallbackVoidSocket));
+  virtual int Connect(const Address &address) = 0;
     
   /**
-   * \brief Accept connection requests from remote hosts
-   * \param connectionRequest Callback for connection request from peer. 
-   *        This user callback is passed a pointer to this socket, the 
-   *        ip address and the port number of the connection originator. 
-   *        This callback must return true to accept the incoming connection,
-   *        false otherwise. If the connection is accepted, the 
-   *        "newConnectionCreated" callback will be invoked later to give access
-   *        to the user to the socket created to match this new connection. If the
-   *        user does not explicitely specify this callback, all incoming 
-   *        connections will be refused.
-   * \param newConnectionCreated Callback for new connection: when a new
-   *        is accepted, it is created and the corresponding socket is passed
-   *        back to the user through this callback. This user callback is passed
-   *        a pointer to the new socket, and the ip address and port number
-   *        of the connection originator.
-   * \param closeRequested Callback for connection close request from peer.
-   *        XXX: when is this callback invoked ?
-   */
-  int Accept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest = 
-             MakeCallback(&Socket::RefuseAllConnections),
-             Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated = 
-             MakeCallback (&Socket::DummyCallbackVoidSocketIpv4AddressUi16),
-             Callback<void, Ptr<Socket> > closeRequested = MakeCallback (&Socket::DummyCallbackVoidSocket));
-
-  /**
    * \brief Send data (or dummy data) to the remote host
-   * \param buffer Data to send (nil if dummy data).
-   * \param size Number of bytes to send.
-   * \param dataSent Data sent callback.
+   * \param p packet to send
    * \returns -1 in case of error or the number of bytes copied in the 
    *          internal buffer and accepted for transmission.
    */
-  int Send (const uint8_t* buffer,
-            uint32_t size,
-            Callback<void, Ptr<Socket>, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32));
+  virtual int Send (const Packet &p) = 0;
   
   /**
    * \brief Send data to a specified peer.
    * \param address IP Address of remote host
-   * \param port port number
-   * \param buffer Data to send (nil if dummy data).
-   * \param size Number of bytes to send.
-   * \param dataSent Data sent callback.
+   * \param p packet to send
    * \returns -1 in case of error or the number of bytes copied in the 
    *          internal buffer and accepted for transmission.
    */
-  int SendTo(const Ipv4Address &address,
-             uint16_t port,
-             const uint8_t *buffer,
-             uint32_t size,
-             Callback<void, Ptr<Socket>, uint32_t> dataSent = MakeCallback (&Socket::DummyCallbackVoidSocketUi32));
-  
-  /**
-   * \brief Receive data
-   * \param receivedData Invoked whenever new data is received.
-   *
-   * If you wish to transport only dummy packets, this method is not a very
-   * efficient way to receive these dummy packets: it will trigger a memory
-   * allocation to hold the dummy memory into a buffer which can be passed
-   * to the user. Instead, consider using the RecvDummy method.
-   */
-  void Recv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receivedData = 
-            MakeCallback (&Socket::DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16));
-  
-  /**
-   * \brief Receive data
-   * \param receivedData Invoked whenever new data is received.
-   *
-   * This method is included because it is vastly more efficient than the 
-   * Recv method when you use dummy payload.
-   */
-  void RecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t> receivedData =
-                 MakeCallback (&Socket::DummyCallbackVoidSocketUi32Ipv4AddressUi16));
+  virtual int SendTo(const Address &address,const Packet &p) = 0;
 
-private:
-  virtual void DoClose(Callback<void, Ptr<Socket> > closeCompleted) = 0;
-  virtual void DoConnect(const Ipv4Address & address,
-                         uint16_t portNumber,
-                         Callback<void, Ptr<Socket> > connectionSucceeded,
-                         Callback<void, Ptr<Socket> > connectionFailed,
-                         Callback<void, Ptr<Socket> > halfClose) = 0;
-  virtual int DoAccept(Callback<bool, Ptr<Socket>, const Ipv4Address&, uint16_t> connectionRequest,
-                       Callback<void, Ptr<Socket>, const Ipv4Address&, uint16_t> newConnectionCreated,
-                       Callback<void, Ptr<Socket> > closeRequested) = 0;
-  virtual int DoSend (const uint8_t* buffer,
-                    uint32_t size,
-                    Callback<void, Ptr<Socket>, uint32_t> dataSent) = 0;
-  virtual int DoSendTo(const Ipv4Address &address,
-                       uint16_t port,
-                       const uint8_t *buffer,
-                       uint32_t size,
-                       Callback<void, Ptr<Socket>, uint32_t> dataSent) = 0;
-  virtual void DoRecv(Callback<void, Ptr<Socket>, const uint8_t*, uint32_t,const Ipv4Address&, uint16_t> receive) = 0;
-  virtual void DoRecvDummy(Callback<void, Ptr<Socket>, uint32_t,const Ipv4Address&, uint16_t>) = 0;
+protected:
+  void NotifyCloseCompleted (void);
+  void NotifyConnectionSucceeded (void);
+  void NotifyConnectionFailed (void);
+  void NotifyHalfClose (void);
+  bool NotifyConnectionRequest (const Address &from);
+  void NotifyNewConnectionCreated (Ptr<Socket> socket, const Address &from);
+  void NotifyCloseRequested (void);
+  void NotifyDataSent (uint32_t size);
+  void NotifyDataReceived (const Packet &p, const Address &from);
 
-
-  static bool RefuseAllConnections (Ptr<Socket> socket, const Ipv4Address& address, uint16_t port);
-  static void DummyCallbackVoidSocket (Ptr<Socket> socket);
-  static void DummyCallbackVoidSocketUi32 (Ptr<Socket> socket, uint32_t);
-  static void DummyCallbackVoidSocketUi32Ipv4AddressUi16 (Ptr<Socket> socket, uint32_t, const Ipv4Address &, uint16_t);
-  static void DummyCallbackVoidSocketBufferUi32Ipv4AddressUi16 (Ptr<Socket> socket, const uint8_t *, uint32_t, 
-                                                                const Ipv4Address &, uint16_t);
-  static void DummyCallbackVoidSocketIpv4AddressUi16 (Ptr<Socket> socket, const Ipv4Address &, uint16_t);
+  Callback<void,Ptr<Socket> >    m_closeCompleted;
+  Callback<void, Ptr<Socket> >   m_connectionSucceeded;
+  Callback<void, Ptr<Socket> >   m_connectionFailed;
+  Callback<void, Ptr<Socket> >   m_halfClose;
+  Callback<void, Ptr<Socket> >   m_closeRequested;
+  Callback<bool, Ptr<Socket>, const Address &>   m_connectionRequest;
+  Callback<void, Ptr<Socket>, const Address&>    m_newConnectionCreated;
+  Callback<void, Ptr<Socket>, uint32_t>          m_dataSent;
+  Callback<void, Ptr<Socket>, const Packet &,const Address&> m_receivedData;
 };
 
 } //namespace ns3
--- a/src/node/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/node/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -1,16 +1,17 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
 def build(bld):
-    node = bld.create_obj('cpp', 'shlib')
-    node.name = 'ns3-node'
-    node.target = node.name
-    node.uselib_local = ['ns3-core', 'ns3-common', 'ns3-simulator']
+    node = bld.create_ns3_module('node', ['core', 'common', 'simulator'])
     node.source = [
+        'address.cc',
+        'eui48-address.cc',
+        'eui64-address.cc',
+        'inet-socket-address.cc',
+        'packet-socket-address.cc',
         'node.cc',
         'ipv4-address.cc',
         'net-device.cc',
-        'mac-address.cc',
-        'address-utils.cc',
+	'address-utils.cc',
         'llc-snap-header.cc',
         'ethernet-header.cc',
         'ethernet-trailer.cc',
@@ -21,6 +22,8 @@
         'node-list.cc',
         'socket.cc',
         'socket-factory.cc',
+        'packet-socket-factory.cc',
+        'packet-socket.cc',
         'udp.cc',
         'ipv4.cc',
         'application.cc',
@@ -28,11 +31,15 @@
 
     headers = bld.create_obj('ns3header')
     headers.source = [
+        'address.h',
+        'eui48-address.h',
+        'eui64-address.h',
+        'inet-socket-address.h',
+        'packet-socket-address.h',
         'node.h',
         'ipv4-address.h',
         'net-device.h',
-        'mac-address.h',
-        'address-utils.h',
+	'address-utils.h',
         'ipv4-route.h',
         'queue.h',
         'drop-tail-queue.h',
@@ -43,6 +50,7 @@
         'node-list.h',
         'socket.h',
         'socket-factory.h',
+        'packet-socket-factory.h',
         'udp.h',
         'ipv4.h',
         'application.h',
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/candidate-queue.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,150 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#include "ns3/debug.h"
+#include "ns3/assert.h"
+#include "candidate-queue.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("CandidateQueue");
+
+namespace ns3 {
+
+CandidateQueue::CandidateQueue()
+  : m_candidates ()
+{
+  NS_DEBUG("CandidateQueue::CandidateQueue ()");
+}
+
+CandidateQueue::~CandidateQueue()
+{
+  NS_DEBUG("CandidateQueue::~CandidateQueue ()");
+  Clear ();
+}
+
+  void
+CandidateQueue::Clear (void)
+{
+  NS_DEBUG("CandidateQueue::Clear ()");
+
+  while (!m_candidates.empty ())
+    {
+      SPFVertex *p = Pop ();
+      delete p;
+      p = 0;
+    }
+}
+
+  void
+CandidateQueue::Push (SPFVertex *vNew)
+{
+  NS_DEBUG("CandidateQueue::Push (" << vNew << ")");
+
+  CandidateList_t::iterator i = m_candidates.begin ();  
+
+  for (; i != m_candidates.end (); i++)
+    {
+      SPFVertex *v = *i;
+      if (vNew->GetDistanceFromRoot () < v->GetDistanceFromRoot ())
+        {
+          break;
+        }
+    }
+  m_candidates.insert(i, vNew);
+}
+
+  SPFVertex *
+CandidateQueue::Pop (void)
+{
+  NS_DEBUG("CandidateQueue::Pop ()");
+
+  if (m_candidates.empty ())
+    {
+      return 0;
+    }
+
+  SPFVertex *v = m_candidates.front ();
+  m_candidates.pop_front ();
+  return v;
+}
+
+  SPFVertex *
+CandidateQueue::Top (void) const
+{
+  NS_DEBUG("CandidateQueue::Top ()");
+
+  if (m_candidates.empty ())
+    {
+      return 0;
+    }
+
+  return m_candidates.front ();
+}
+
+  bool
+CandidateQueue::Empty (void) const
+{
+  NS_DEBUG("CandidateQueue::Empty ()");
+
+  return m_candidates.empty ();
+}
+
+  uint32_t
+CandidateQueue::Size (void) const
+{
+  NS_DEBUG("CandidateQueue::Size ()");
+
+  return m_candidates.size ();
+}
+
+  SPFVertex *
+CandidateQueue::Find (const Ipv4Address addr) const
+{
+  NS_DEBUG("CandidateQueue::Find ()");
+
+  CandidateList_t::const_iterator i = m_candidates.begin ();
+
+  for (; i != m_candidates.end (); i++)
+    {
+      SPFVertex *v = *i;
+      if (v->GetVertexId() == addr)
+        {
+          return v;
+        }
+    }
+
+  return 0;
+}
+
+  void
+CandidateQueue::Reorder (void)
+{
+  NS_DEBUG("CandidateQueue::Reorder ()");
+
+  std::list<SPFVertex*> temp;
+
+  while (!m_candidates.empty ()) {
+    SPFVertex *v = m_candidates.front ();
+    m_candidates.pop_front ();
+    temp.push_back(v);
+  }
+
+  while (!temp.empty ()) {
+    Push (temp.front ());
+    temp.pop_front ();
+  }
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/candidate-queue.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,181 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#ifndef CANDIDATE_QUEUE_H
+#define CANDIDATE_QUEUE_H
+
+#include <stdint.h>
+#include <list>
+#include "global-route-manager-impl.h"
+
+namespace ns3 {
+
+/**  
+ * \brief A Candidate Queue used in static routing.
+ *
+ * The CandidateQueue is used in the OSPF shortest path computations.  It
+ * is a priority queue used to store candidates for the shortest path to a
+ * given network.  
+ *
+ * The queue holds Shortest Path First Vertex pointers and orders them
+ * according to the lowest value of the field m_distanceFromRoot.  Remaining
+ * vertices are ordered according to increasing distance.  This implements a
+ * priority queue.
+ *
+ * Although a STL priority_queue almost does what we want, the requirement
+ * for a Find () operation, the dynamic nature of the data and the derived
+ * requirement for a Reorder () operation led us to implement this simple 
+ * enhanced priority queue.
+ */
+class CandidateQueue
+{
+public:
+/**
+ * @brief Create an empty SPF Candidate Queue.  
+ * @internal
+ *
+ * @see SPFVertex
+ */
+  CandidateQueue ();
+
+/**
+ * @internal Destroy an SPF Candidate Queue and release any resources held 
+ * by the contents.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+  virtual ~CandidateQueue ();
+
+/**
+ * @brief Empty the Candidate Queue and release all of the resources 
+ * associated with the Shortest Path First Vertex pointers in the queue.
+ * @internal
+ *
+ * @see SPFVertex
+ */
+  void Clear (void);
+
+/**
+ * @brief Push a Shortest Path First Vertex pointer onto the queue according
+ * to the priority scheme.
+ * @internal
+ * 
+ * On completion, the top of the queue will hold the Shortest Path First
+ * Vertex pointer that points to a vertex having lowest value of the field
+ * m_distanceFromRoot.  Remaining vertices are ordered according to 
+ * increasing distance.
+ *
+ * @see SPFVertex
+ * @param vNew The Shortest Path First Vertex to add to the queue.
+ */
+  void Push (SPFVertex *vNew);
+
+/**
+ * @brief Pop the Shortest Path First Vertex pointer at the top of the queue.
+ * @internal
+ *
+ * The caller is given the responsiblity for releasing the resources 
+ * associated with the vertex.
+ *
+ * @see SPFVertex
+ * @see Top ()
+ * @returns The Shortest Path First Vertex pointer at the top of the queue.
+ */
+  SPFVertex* Pop (void);
+
+/**
+ * @brief Return the Shortest Path First Vertex pointer at the top of the 
+ * queue.  
+ * @internal
+ *
+ * This method does not pop the SPFVertex* off of the queue, it simply 
+ * returns the pointer.
+ *
+ * @see SPFVertex
+ * @see Pop ()
+ * @returns The Shortest Path First Vertex pointer at the top of the queue.
+ */
+  SPFVertex* Top (void) const;
+
+/**
+ * @brief Test the Candidate Queue to determine if it is empty.
+ * @internal
+ *
+ * @returns True if the queue is empty, false otherwise.
+ */
+  bool Empty (void) const;
+
+/**
+ * @brief Return the number of Shortest Path First Vertex pointers presently
+ * stored in the Candidate Queue.
+ * @internal
+ *
+ * @see SPFVertex
+ * @returns The number of SPFVertex* pointers in the Candidate Queue.
+ */
+  uint32_t Size (void) const;
+
+/**
+ * @brief Searches the Candidate Queue for a Shortest Path First Vertex 
+ * pointer that points to a vertex having the given IP address.
+ * @internal
+ *
+ * @see SPFVertex
+ * @param addr The IP address to search for.
+ * @returns The SPFVertex* pointer corresponding to the given IP address.
+ */
+  SPFVertex* Find (const Ipv4Address addr) const;
+
+/**
+ * @brief Reorders the Candidate Queue according to the priority scheme.  
+ * @internal
+ * 
+ * On completion, the top of the queue will hold the Shortest Path First
+ * Vertex pointer that points to a vertex having lowest value of the field
+ * m_distanceFromRoot.  Remaining vertices are ordered according to 
+ * increasing distance.
+ *
+ * This method is provided in case the values of m_distanceFromRoot change
+ * during the routing calculations.
+ *
+ * @see SPFVertex
+ */
+  void Reorder (void);
+
+protected:
+  typedef std::list<SPFVertex*> CandidateList_t;
+  CandidateList_t m_candidates;
+
+private:
+/**
+ * Candidate Queue copy construction is disallowed (not implemented) to 
+ * prevent the compiler from slipping in incorrect versions that don't
+ * properly deal with deep copies.
+ */
+  CandidateQueue (CandidateQueue& sr);
+
+/**
+ * Candidate Queue assignment operator is disallowed (not implemented) to
+ * prevent the compiler from slipping in incorrect versions that don't
+ * properly deal with deep copies.
+ */
+  CandidateQueue& operator= (CandidateQueue& sr);
+};
+
+} // namespace ns3
+
+#endif /* CANDIDATE_QUEUE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager-impl.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,1711 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#include <utility>
+#include <vector>
+#include <queue>
+#include "ns3/assert.h"
+#include "ns3/fatal-error.h"
+#include "ns3/debug.h"
+#include "ns3/node-list.h"
+#include "ns3/ipv4.h"
+#include "global-router-interface.h"
+#include "global-route-manager-impl.h"
+#include "candidate-queue.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("GlobalRouteManager");
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// SPFVertex Implementation
+//
+// ---------------------------------------------------------------------------
+
+SPFVertex::SPFVertex () : 
+  m_vertexType (VertexUnknown), 
+  m_vertexId ("255.255.255.255"), 
+  m_lsa (0),
+  m_distanceFromRoot (SPF_INFINITY), 
+  m_rootOif (SPF_INFINITY),
+  m_nextHop ("0.0.0.0"),
+  m_parent (0),
+  m_children ()
+{
+}
+
+SPFVertex::SPFVertex (GlobalRoutingLSA* lsa) : 
+  m_vertexId (lsa->GetLinkStateId ()),
+  m_lsa (lsa),
+  m_distanceFromRoot (SPF_INFINITY), 
+  m_rootOif (SPF_INFINITY),
+  m_nextHop ("0.0.0.0"),
+  m_parent (0),
+  m_children ()
+{
+  if (lsa->GetLSType () == GlobalRoutingLSA::RouterLSA) 
+    {
+      NS_DEBUG ("SPFVertex:: setting m_vertexType to VertexRouter");
+      m_vertexType = SPFVertex::VertexRouter;
+    }
+  else if (lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA) 
+    { 
+      NS_DEBUG ("SPFVertex:: setting m_vertexType to VertexNetwork");
+      m_vertexType = SPFVertex::VertexNetwork;
+    }
+}
+
+SPFVertex::~SPFVertex ()
+{
+  for ( ListOfSPFVertex_t::iterator i = m_children.begin ();
+        i != m_children.end ();
+        i++)
+    {
+      SPFVertex *p = *i;
+      delete p;
+      p = 0;
+      *i = 0;
+    }
+  m_children.clear ();
+}
+
+  void 
+SPFVertex::SetVertexType (SPFVertex::VertexType type)
+{
+  m_vertexType = type;
+}
+
+  SPFVertex::VertexType 
+SPFVertex::GetVertexType (void) const
+{
+  return m_vertexType;
+}
+
+  void 
+SPFVertex::SetVertexId (Ipv4Address id)
+{
+  m_vertexId = id;
+}
+
+  Ipv4Address
+SPFVertex::GetVertexId (void) const
+{
+  return m_vertexId;
+}
+
+  void 
+SPFVertex::SetLSA (GlobalRoutingLSA* lsa)
+{
+  m_lsa = lsa;
+}
+
+  GlobalRoutingLSA* 
+SPFVertex::GetLSA (void) const
+{
+  return m_lsa;
+}
+
+  void 
+SPFVertex::SetDistanceFromRoot (uint32_t distance)
+{
+  m_distanceFromRoot = distance;
+}
+
+  uint32_t
+SPFVertex::GetDistanceFromRoot (void) const
+{
+  return m_distanceFromRoot;
+}
+
+  void 
+SPFVertex::SetOutgoingInterfaceId (uint32_t id)
+{
+  m_rootOif = id;
+}
+
+  uint32_t 
+SPFVertex::GetOutgoingInterfaceId (void) const
+{
+  return m_rootOif;
+}
+
+  void 
+SPFVertex::SetNextHop (Ipv4Address nextHop)
+{
+  m_nextHop = nextHop;
+}
+
+  Ipv4Address
+SPFVertex::GetNextHop (void) const
+{
+  return m_nextHop;
+}
+
+  void
+SPFVertex::SetParent (SPFVertex* parent)
+{
+  m_parent = parent;
+}
+
+  SPFVertex* 
+SPFVertex::GetParent (void) const
+{
+  return m_parent;
+}
+
+  uint32_t 
+SPFVertex::GetNChildren (void) const
+{
+  return m_children.size ();
+}
+
+  SPFVertex* 
+SPFVertex::GetChild (uint32_t n) const
+{
+  uint32_t j = 0;
+
+  for ( ListOfSPFVertex_t::const_iterator i = m_children.begin ();
+        i != m_children.end ();
+        i++, j++)
+    {
+      if (j == n)
+        {
+          return *i;
+        }
+    }
+  NS_ASSERT_MSG(false, "Index <n> out of range.");
+  return 0;
+}
+
+  uint32_t 
+SPFVertex::AddChild (SPFVertex* child)
+{
+  m_children.push_back (child);
+  return m_children.size ();
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManagerLSDB Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRouteManagerLSDB::GlobalRouteManagerLSDB ()
+:
+  m_database ()
+{
+  NS_DEBUG ("GlobalRouteManagerLSDB::GlobalRouteManagerLSDB ()");
+}
+
+GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ()
+{
+  NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ()");
+
+  LSDBMap_t::iterator i;
+  for (i= m_database.begin (); i!= m_database.end (); i++)
+    {
+      NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ():free LSA");
+      GlobalRoutingLSA* temp = i->second;
+      delete temp;
+    }
+  NS_DEBUG ("GlobalRouteManagerLSDB::~GlobalRouteManagerLSDB ():  clear map");
+  m_database.clear ();
+}
+
+  void
+GlobalRouteManagerLSDB::Initialize ()
+{
+  NS_DEBUG ("GlobalRouteManagerLSDB::Initialize ()");
+
+  LSDBMap_t::iterator i;
+  for (i= m_database.begin (); i!= m_database.end (); i++)
+    {
+      GlobalRoutingLSA* temp = i->second;
+      temp->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+    }
+}
+
+  void
+GlobalRouteManagerLSDB::Insert (Ipv4Address addr, GlobalRoutingLSA* lsa)
+{
+  NS_DEBUG ("GlobalRouteManagerLSDB::Insert ()");
+  m_database.insert (LSDBPair_t (addr, lsa));
+}
+
+  GlobalRoutingLSA*
+GlobalRouteManagerLSDB::GetLSA (Ipv4Address addr) const
+{
+  NS_DEBUG ("GlobalRouteManagerLSDB::GetLSA ()");
+//
+// Look up an LSA by its address.
+//
+  LSDBMap_t::const_iterator i;
+  for (i= m_database.begin (); i!= m_database.end (); i++)
+  {
+    if (i->first == addr)
+    {
+      return i->second;
+    }
+  }
+  return 0;
+}
+
+  GlobalRoutingLSA*
+GlobalRouteManagerLSDB::GetLSAByLinkData (Ipv4Address addr) const
+{
+  NS_DEBUG ("GlobalRouteManagerLSDB::GetLSAByLinkData ()");
+//
+// Look up an LSA by its address.
+//
+  LSDBMap_t::const_iterator i;
+  for (i= m_database.begin (); i!= m_database.end (); i++)
+    {
+      GlobalRoutingLSA* temp = i->second;
+// Iterate among temp's Link Records
+      for (uint32_t j = 0; j < temp->GetNLinkRecords (); j++)
+        {
+          GlobalRoutingLinkRecord *lr = temp->GetLinkRecord (j);
+          if ( lr->GetLinkType () == GlobalRoutingLinkRecord::TransitNetwork &&
+               lr->GetLinkData () == addr)
+            {
+              return temp;
+            }
+        }
+    }
+  return 0;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManagerImpl Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRouteManagerImpl::GlobalRouteManagerImpl () 
+: 
+  m_spfroot (0) 
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::GlobalRoutemanagerImpl ()");
+  m_lsdb = new GlobalRouteManagerLSDB ();
+}
+
+GlobalRouteManagerImpl::~GlobalRouteManagerImpl ()
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::~GlobalRouteManagerImpl ()");
+
+  if (m_lsdb)
+    {
+      delete m_lsdb;
+    }
+}
+
+  void
+GlobalRouteManagerImpl::DebugUseLsdb (GlobalRouteManagerLSDB* lsdb)
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::DebugUseLsdb ()");
+
+  if (m_lsdb)
+    {
+      delete m_lsdb;
+    }
+  m_lsdb = lsdb;
+}
+
+//
+// In order to build the routing database, we need at least one of the nodes
+// to participate as a router.  Eventually we expect to provide a mechanism
+// for selecting a subset of the nodes to participate; for now, we just make
+// all nodes routers.  We do this by walking the list of nodes in the system
+// and aggregating a Global Router Interface to each of the nodes.
+//
+  void
+GlobalRouteManagerImpl::SelectRouterNodes () 
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::SelectRouterNodes ()");
+
+  for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+      NS_DEBUG ("GlobalRouteManagerImpl::SelectRouterNodes (): "
+        "Adding GlobalRouter interface to node " <<
+                node->GetId ());
+
+      Ptr<GlobalRouter> globalRouter = Create<GlobalRouter> (node);
+      node->AddInterface (globalRouter);
+    }
+}
+
+//
+// In order to build the routing database, we need to walk the list of nodes
+// in the system and look for those that support the GlobalRouter interface.
+// These routers will export a number of Link State Advertisements (LSAs)
+// that describe the links and networks that are "adjacent" (i.e., that are
+// on the other side of a point-to-point link).  We take these LSAs and put
+// add them to the Link State DataBase (LSDB) from which the routes will 
+// ultimately be computed.
+//
+  void
+GlobalRouteManagerImpl::BuildGlobalRoutingDatabase () 
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::BuildGlobalRoutingDatabase()");
+//
+// Walk the list of nodes looking for the GlobalRouter Interface.
+//
+  for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//      
+// Ignore nodes that aren't participating in routing.
+//
+      if (!rtr)
+        {
+          continue;
+        }
+//
+// You must call DiscoverLSAs () before trying to use any routing info or to
+// update LSAs.  DiscoverLSAs () drives the process of discovering routes in
+// the GlobalRouter.  Afterward, you may use GetNumLSAs (), which is a very
+// computationally inexpensive call.  If you call GetNumLSAs () before calling 
+// DiscoverLSAs () will get zero as the number since no routes have been 
+// found.
+//
+      uint32_t numLSAs = rtr->DiscoverLSAs ();
+      NS_DEBUG ("Discover LSAs:  Found " << numLSAs << " LSAs");
+
+      for (uint32_t j = 0; j < numLSAs; ++j)
+        {
+          GlobalRoutingLSA* lsa = new GlobalRoutingLSA ();
+//
+// This is the call to actually fetch a Link State Advertisement from the 
+// router.
+//
+          rtr->GetLSA (j, *lsa);
+          NS_DEBUG (*lsa);
+//
+// Write the newly discovered link state advertisement to the database.
+//
+          m_lsdb->Insert (lsa->GetLinkStateId (), lsa); 
+        }
+    }
+}
+
+//
+// For each node that is a global router (which is determined by the presence
+// of an aggregated GlobalRouter interface), run the Dijkstra SPF calculation
+// on the database rooted at that router, and populate the node forwarding
+// tables.
+//
+// This function parallels RFC2328, Section 16.1.1, and quagga ospfd
+//
+// This calculation yields the set of intra-area routes associated
+// with an area (called hereafter Area A).  A router calculates the
+// shortest-path tree using itself as the root.  The formation
+// of the shortest path tree is done here in two stages.  In the
+// first stage, only links between routers and transit networks are
+// considered.  Using the Dijkstra algorithm, a tree is formed from
+// this subset of the link state database.  In the second stage,
+// leaves are added to the tree by considering the links to stub
+// networks.
+//
+// The area's link state database is represented as a directed graph.  
+// The graph's vertices are routers, transit networks and stub networks.  
+//
+// The first stage of the procedure (i.e., the Dijkstra algorithm)
+// can now be summarized as follows. At each iteration of the
+// algorithm, there is a list of candidate vertices.  Paths from
+// the root to these vertices have been found, but not necessarily
+// the shortest ones.  However, the paths to the candidate vertex
+// that is closest to the root are guaranteed to be shortest; this
+// vertex is added to the shortest-path tree, removed from the
+// candidate list, and its adjacent vertices are examined for
+// possible addition to/modification of the candidate list.  The
+// algorithm then iterates again.  It terminates when the candidate
+// list becomes empty. 
+//
+  void
+GlobalRouteManagerImpl::InitializeRoutes ()
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::InitializeRoutes ()");
+//
+// Walk the list of nodes in the system.
+//
+  for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+//
+// Look for the GlobalRouter interface that indicates that the node is
+// participating in routing.
+//
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// if the node has a global router interface, then run the global routing
+// algorithms.
+//
+      if (rtr && rtr->GetNumLSAs () )
+        {
+          SPFCalculate (rtr->GetRouterId ());
+        }
+    }
+}
+
+//
+// This method is derived from quagga ospf_spf_next ().  See RFC2328 Section 
+// 16.1 (2) for further details.
+//
+// We're passed a parameter <v> that is a vertex which is already in the SPF
+// tree.  A vertex represents a router node.  We also get a reference to the
+// SPF candidate queue, which is a priority queue containing the shortest paths
+// to the networks we know about.
+//
+// We examine the links in v's LSA and update the list of candidates with any
+// vertices not already on the list.  If a lower-cost path is found to a
+// vertex already on the candidate list, store the new (lower) cost.
+//
+  void
+GlobalRouteManagerImpl::SPFNext (SPFVertex* v, CandidateQueue& candidate)
+{
+  SPFVertex* w = 0;
+  GlobalRoutingLSA* w_lsa = 0;
+  GlobalRoutingLinkRecord *l = 0;
+  uint32_t distance = 0;
+  uint32_t numRecordsInVertex = 0;
+
+  NS_DEBUG ("GlobalRouteManagerImpl::SPFNext ()");
+
+// V points to a Router-LSA or Network-LSA
+// Loop over the links in router LSA or attached routers in Network LSA
+  if (v->GetVertexType () == SPFVertex::VertexRouter)
+    {
+      numRecordsInVertex = v->GetLSA ()->GetNLinkRecords (); 
+    }
+  if (v->GetVertexType () == SPFVertex::VertexNetwork)
+    {
+      numRecordsInVertex = v->GetLSA ()->GetNAttachedRouters (); 
+    }
+
+  for (uint32_t i = 0; i < numRecordsInVertex; i++)
+    {
+// Get w_lsa:  In case of V is Router-LSA
+      if (v->GetVertexType () == SPFVertex::VertexRouter) 
+        {
+          NS_DEBUG ("SPFNext: Examining " << v->GetVertexId () << "'s " <<
+            v->GetLSA ()->GetNLinkRecords () << " link records");
+//
+// (a) If this is a link to a stub network, examine the next link in V's LSA.
+// Links to stub networks will be considered in the second stage of the
+// shortest path calculation.
+//
+          l = v->GetLSA ()->GetLinkRecord (i);
+          if (l->GetLinkType () == GlobalRoutingLinkRecord::StubNetwork)
+            {
+              NS_DEBUG ("SPFNext: Found a Stub record to " << 
+                l->GetLinkId ());
+              continue;
+            }
+//
+// (b) Otherwise, W is a transit vertex (router or transit network).  Look up
+// the vertex W's LSA (router-LSA or network-LSA) in Area A's link state
+// database. 
+//
+          if (l->GetLinkType () == GlobalRoutingLinkRecord::PointToPoint)
+            {
+//
+// Lookup the link state advertisement of the new link -- we call it <w> in
+// the link state database.
+//
+              w_lsa = m_lsdb->GetLSA (l->GetLinkId ());
+              NS_ASSERT (w_lsa);
+              NS_DEBUG ("SPFNext:  Found a P2P record from " << 
+                v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+            }
+          else if (l->GetLinkType () == 
+            GlobalRoutingLinkRecord::TransitNetwork)
+            {
+              w_lsa = m_lsdb->GetLSA (l->GetLinkId ());
+              NS_ASSERT (w_lsa);
+              NS_DEBUG ("SPFNext:  Found a Transit record from " << 
+                v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+            }
+          else 
+            {
+              NS_ASSERT_MSG (0, "illegal Link Type");
+            }
+        }
+// Get w_lsa:  In case of V is Network-LSA
+      if (v->GetVertexType () == SPFVertex::VertexNetwork) 
+        {
+          w_lsa = m_lsdb->GetLSAByLinkData 
+            (v->GetLSA ()->GetAttachedRouter (i)); 
+          if (!w_lsa)
+            {
+              continue;
+            }
+          NS_DEBUG ("SPFNext:  Found a Network LSA from " << 
+            v->GetVertexId () << " to " << w_lsa->GetLinkStateId ());
+        }
+
+// Note:  w_lsa at this point may be either RouterLSA or NetworkLSA
+//
+// (c) If vertex W is already on the shortest-path tree, examine the next
+// link in the LSA.
+//
+// If the link is to a router that is already in the shortest path first tree
+// then we have it covered -- ignore it.
+//
+      if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_IN_SPFTREE) 
+        {
+          NS_DEBUG ("SPFNext: Skipping->  LSA "<< 
+            w_lsa->GetLinkStateId () << " already in SPF tree");
+          continue;
+        }
+//
+// (d) Calculate the link state cost D of the resulting path from the root to 
+// vertex W.  D is equal to the sum of the link state cost of the (already 
+// calculated) shortest path to vertex V and the advertised cost of the link
+// between vertices V and W.  
+//
+      if (v->GetLSA ()->GetLSType () == GlobalRoutingLSA::RouterLSA)
+        {
+          distance = v->GetDistanceFromRoot () + l->GetMetric ();
+        }
+      else
+        {
+          distance = v->GetDistanceFromRoot ();
+        }
+
+      NS_DEBUG ("SPFNext: Considering w_lsa " << w_lsa->GetLinkStateId ());
+
+// Is there already vertex w in candidate list?
+      if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED)
+        {
+
+// prepare vertex w
+          w = new SPFVertex (w_lsa);
+// Calculate nexthop to w
+// We need to figure out how to actually get to the new router represented
+// by <w>.  This will (among other things) find the next hop address to send
+// packets destined for this network to, and also find the outbound interface
+// used to forward the packets.
+//
+          if (SPFNexthopCalculation (v, w, l, distance))
+            {
+              w_lsa->SetStatus (GlobalRoutingLSA::LSA_SPF_CANDIDATE);
+//
+// Push this new vertex onto the priority queue (ordered by distance from the
+// root node).
+//
+              candidate.Push (w);
+              NS_DEBUG ("SPFNext:  Pushing " << 
+                w->GetVertexId () << ", parent vertexId: " << 
+                v->GetVertexId ());
+            }
+        }
+      else if (w_lsa->GetStatus () == GlobalRoutingLSA::LSA_SPF_CANDIDATE)
+        {
+//
+// We have already considered the link represented by <w>.  What wse have to
+// do now is to decide if this new router represents a route with a shorter
+// distance metric.
+//
+// So, locate the vertex in the candidate queue and take a look at the 
+// distance.
+          w = candidate.Find (w_lsa->GetLinkStateId ());
+          if (w->GetDistanceFromRoot () < distance)
+            {
+//
+// This is not a shorter path, so don't do anything.
+//
+              continue;
+            }
+          else if (w->GetDistanceFromRoot () == distance)
+            {
+//
+// This path is one with an equal cost.  Do nothing for now -- we're not doing
+// equal-cost multipath cases yet.
+//
+            }
+          else
+            {
+// 
+// this path represents a new, lower-cost path to <w> (the vertex we found in
+// the current link record of the link state advertisement of the current root
+// (vertex <v>)
+//
+// N.B. the nexthop_calculation is conditional, if it finds a valid nexthop
+// it will call spf_add_parents, which will flush the old parents
+//
+              if (SPFNexthopCalculation (v, w, l, distance))
+                {
+//
+// If we've changed the cost to get to the vertex represented by <w>, we 
+// must reorder the priority queue keyed to that cost.
+//
+                  candidate.Reorder ();
+                }
+            } // new lower cost path found   
+        } // end W is already on the candidate list
+    } // end loop over the links in V's LSA
+}
+
+//
+// This method is derived from quagga ospf_next_hop_calculation() 16.1.1.  
+//
+// Calculate nexthop from root through V (parent) to vertex W (destination)
+// with given distance from root->W.
+//
+// As appropriate, set w's parent, distance, and nexthop information
+//
+// For now, this is greatly simplified from the quagga code
+//                  
+  int
+GlobalRouteManagerImpl::SPFNexthopCalculation (
+  SPFVertex* v, 
+  SPFVertex* w,
+  GlobalRoutingLinkRecord* l,
+  uint32_t distance)
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::SPFNexthopCalculation ()");
+
+// If w is a NetworkVertex, l should be null
+/*
+  if (w->GetVertexType () == SPFVertex::VertexNetwork && l)
+    {
+        NS_ASSERT_MSG(0, "Error:  SPFNexthopCalculation parameter problem");
+    }
+*/
+
+//
+// The vertex m_spfroot is a distinguished vertex representing the node at
+// the root of the calculations.  That is, it is the node for which we are
+// calculating the routes.
+//
+// There are two distinct cases for calculating the next hop information.
+// First, if we're considering a hop from the root to an "adjacent" network
+// (one that is on the other side of a point-to-point link connected to the
+// root), then we need to store the information needed to forward down that
+// link.  The second case is if the network is not directly adjacent.  In that
+// case we need to use the forwarding information from the vertex on the path
+// to the destination that is directly adjacent [node 1] in both cases of the
+// diagram below.
+// 
+// (1) [root] -> [point-to-point] -> [node 1]
+// (2) [root] -> [point-to-point] -> [node 1] -> [point-to-point] -> [node 2]
+//
+// We call the propagation of next hop information down vertices of a path
+// "inheriting" the next hop information.
+//
+// The point-to-point link information is only useful in this calculation when
+// we are examining the root node. 
+//
+  if (v == m_spfroot)
+    {
+//
+// In this case <v> is the root node, which means it is the starting point
+// for the packets forwarded by that node.  This also means that the next hop
+// address of packets headed for some arbitrary off-network destination must
+// be the destination at the other end of one of the links off of the root
+// node if this root node is a router.  We then need to see if this node <w>
+// is a router.
+//
+      if (w->GetVertexType () == SPFVertex::VertexRouter) 
+        {
+//
+// In the case of point-to-point links, the link data field (m_linkData) of a
+// Global Router Link Record contains the local IP address.  If we look at the
+// link record describing the link from the perspecive of <w> (the remote
+// node from the viewpoint of <v>) back to the root node, we can discover the
+// IP address of the router to which <v> is adjacent.  This is a distinguished
+// address -- the next hop address to get from <v> to <w> and all networks 
+// accessed through that path.
+//
+// SPFGetNextLink () is a little odd.  used in this way it is just going to
+// return the link record describing the link from <w> to <v>.  Think of it as
+// SPFGetLink.
+//
+          NS_ASSERT(l);
+          GlobalRoutingLinkRecord *linkRemote = 0;
+          linkRemote = SPFGetNextLink (w, v, linkRemote);
+// 
+// At this point, <l> is the Global Router Link Record describing the point-
+// to point link from <v> to <w> from the perspective of <v>; and <linkRemote>
+// is the Global Router Link Record describing that same link from the 
+// perspective of <w> (back to <v>).  Now we can just copy the next hop 
+// address from the m_linkData member variable.
+// 
+// The next hop member variable we put in <w> has the sense "in order to get
+// from the root node to the host represented by vertex <w>, you have to send
+// the packet to the next hop address specified in w->m_nextHop.
+//
+          w->SetNextHop(linkRemote->GetLinkData ());
+// 
+// Now find the outgoing interface corresponding to the point to point link
+// from the perspective of <v> -- remember that <l> is the link "from"
+// <v> "to" <w>.
+//
+          w->SetOutgoingInterfaceId (
+            FindOutgoingInterfaceId (l->GetLinkData ()));
+
+          NS_DEBUG ("SPFNexthopCalculation: Next hop from " << 
+            v->GetVertexId () << " to " << w->GetVertexId () << 
+            " goes through next hop " << w->GetNextHop () <<
+            " via outgoing interface " << w->GetOutgoingInterfaceId ());
+        }  // end W is a router vertes
+      else 
+        {
+          NS_ASSERT (w->GetVertexType () == SPFVertex::VertexNetwork);
+// W is a directly connected network; no next hop is required
+          GlobalRoutingLSA* w_lsa = w->GetLSA ();
+          NS_ASSERT (w_lsa->GetLSType () == GlobalRoutingLSA::NetworkLSA);
+// Find outgoing interface ID for this network
+          w->SetOutgoingInterfaceId (
+            FindOutgoingInterfaceId (w_lsa->GetLinkStateId (), 
+            w_lsa->GetNetworkLSANetworkMask () ));
+          w->SetDistanceFromRoot (distance);
+          w->SetParent (v);
+          NS_DEBUG ("SPFNexthopCalculation: Next hop from " << 
+            v->GetVertexId () << " to network " << w->GetVertexId () << 
+            " via outgoing interface " << w->GetOutgoingInterfaceId ());
+          return 1;
+        }
+    } // end v is the root
+  else if (v->GetVertexType () == SPFVertex::VertexNetwork) 
+    {
+// See if any of v's parents are the root
+      if (v->GetParent () == m_spfroot)
+        {
+// 16.1.1 para 5. ...the parent vertex is a network that
+// directly connects the calculating router to the destination
+// router.  The list of next hops is then determined by
+// examining the destination's router-LSA...
+          NS_ASSERT (w->GetVertexType () == SPFVertex::VertexRouter);
+          GlobalRoutingLinkRecord *linkRemote = 0;
+          while ((linkRemote = SPFGetNextLink (w, v, linkRemote)))
+            {
+/* ...For each link in the router-LSA that points back to the
+ * parent network, the link's Link Data field provides the IP
+ * address of a next hop router.  The outgoing interface to
+ * use can then be derived from the next hop IP address (or 
+ * it can be inherited from the parent network).
+ */
+                w->SetNextHop(linkRemote->GetLinkData ());
+                w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+                NS_DEBUG ("SPFNexthopCalculation: Next hop from " << 
+                  v->GetVertexId () << " to " << w->GetVertexId () << 
+                  " goes through next hop " << w->GetNextHop () <<
+                  " via outgoing interface " << w->GetOutgoingInterfaceId ());
+            }
+        }
+      else 
+        {
+          w->SetNextHop (v->GetNextHop ());
+          w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+        }
+    }
+  else 
+    {
+//
+// If we're calculating the next hop information from a node (v) that is 
+// *not* the root, then we need to "inherit" the information needed to
+// forward the packet from the vertex closer to the root.  That is, we'll
+// still send packets to the next hop address of the router adjacent to the
+// root on the path toward <w>.
+//
+// Above, when we were considering the root node, we calculated the next hop
+// address and outgoing interface required to get off of the root network.  
+// At this point, we are further away from the root network along one of the
+// (shortest) paths.  So the next hop and outoing interface remain the same
+// (are inherited).
+//
+      w->SetNextHop (v->GetNextHop ());
+      w->SetOutgoingInterfaceId (v->GetOutgoingInterfaceId ());
+    }
+//
+// In all cases, we need valid values for the distance metric and a parent.
+//
+  w->SetDistanceFromRoot (distance);
+  w->SetParent (v);
+
+  return 1;
+}
+
+//
+// This method is derived from quagga ospf_get_next_link ()
+//
+// First search the Global Router Link Records of vertex <v> for one
+// representing a point-to point link to vertex <w>.
+//
+// What is done depends on prev_link.  Contrary to appearances, prev_link just
+// acts as a flag here.  If prev_link is NULL, we return the first Global
+// Router Link Record we find that describes a point-to-point link from <v> 
+// to <w>.  If prev_link is not NULL, we return a Global Router Link Record
+// representing a possible *second* link from <v> to <w>.
+//
+  GlobalRoutingLinkRecord* 
+GlobalRouteManagerImpl::SPFGetNextLink (
+  SPFVertex* v,
+  SPFVertex* w,
+  GlobalRoutingLinkRecord* prev_link) 
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::SPFGetNextLink ()");
+
+  bool skip = true;
+  bool found_prev_link = false;
+  GlobalRoutingLinkRecord* l;
+//
+// If prev_link is 0, we are really looking for the first link, not the next 
+// link.
+//
+  if (prev_link == 0)
+    {
+      skip = false;
+      found_prev_link = true;
+    }
+//  
+// Iterate through the Global Router Link Records advertised by the vertex
+// <v> looking for records representing the point-to-point links off of this
+// vertex.
+//
+  for (uint32_t i = 0; i < v->GetLSA ()->GetNLinkRecords (); ++i)
+    {
+      l = v->GetLSA ()->GetLinkRecord (i);
+//
+// The link ID of a link record representing a point-to-point link is set to
+// the router ID of the neighboring router -- the router to which the link
+// connects from the perspective of <v> in this case.  The vertex ID is also
+// set to the router ID (using the link state advertisement of a router node).
+// We're just checking to see if the link <l> is actually the link from <v> to
+// <w>.
+//
+      if (l->GetLinkId () == w->GetVertexId ()) 
+        {
+          if (!found_prev_link)
+            {
+              NS_DEBUG ("SPFGetNextLink: Skipping links before prev_link found");
+              found_prev_link = true;
+              continue;
+            }
+        
+          NS_DEBUG ("SPFGetNextLink: Found matching link l:  linkId = " <<
+          l->GetLinkId () << " linkData = " << l->GetLinkData ());
+//
+// If skip is false, don't (not too surprisingly) skip the link found -- it's 
+// the one we're interested in.  That's either because we didn't pass in a 
+// previous link, and we're interested in the first one, or because we've 
+// skipped a previous link and moved forward to the next (which is then the
+// one we want).
+//
+        if (skip == false) 
+          {
+            NS_DEBUG ("SPFGetNextLink: Returning the found link");
+            return l;
+          }
+        else
+          {
+//
+// Skip is true and we've found a link from <v> to <w>.  We want the next one.
+// Setting skip to false gets us the next point-to-point global router link
+// record in the LSA from <v>.
+//
+            NS_DEBUG ("SPFGetNextLink: Skipping the found link");
+            skip = false;
+            continue;
+          }
+      }
+    }
+  return 0;
+}
+  
+//
+// Used for unit tests.
+//
+  void
+GlobalRouteManagerImpl::DebugSPFCalculate (Ipv4Address root)
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::DebugSPFCalculate ()");
+  SPFCalculate (root);
+}
+
+// quagga ospf_spf_calculate
+  void
+GlobalRouteManagerImpl::SPFCalculate (Ipv4Address root)
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::SPFCalculate (): "
+    "root = " << root);
+
+  SPFVertex *v;
+//
+// Initialize the Link State Database.
+//
+  m_lsdb->Initialize ();
+//
+// The candidate queue is a priority queue of SPFVertex objects, with the top
+// of the queue being the closest vertex in terms of distance from the root
+// of the tree.  Initially, this queue is empty.
+//
+  CandidateQueue candidate;
+  NS_ASSERT(candidate.Size () == 0);
+//
+// Initialize the shortest-path tree to only contain the router doing the 
+// calculation.  Each router (and corresponding network) is a vertex in the
+// shortest path first (SPF) tree.
+//
+  v = new SPFVertex (m_lsdb->GetLSA (root));
+// 
+// This vertex is the root of the SPF tree and it is distance 0 from the root.
+// We also mark this vertex as being in the SPF tree.
+//
+  m_spfroot= v;
+  v->SetDistanceFromRoot (0);
+  v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
+
+  for (;;)
+    {
+//
+// The operations we need to do are given in the OSPF RFC which we reference
+// as we go along.
+//
+// RFC2328 16.1. (2). 
+//
+// We examine the Global Router Link Records in the Link State 
+// Advertisements of the current vertex.  If there are any point-to-point
+// links to unexplored adjacent vertices we add them to the tree and update
+// the distance and next hop information on how to get there.  We also add
+// the new vertices to the candidate queue (the priority queue ordered by
+// shortest path).  If the new vertices represent shorter paths, we use them
+// and update the path cost.
+//
+      SPFNext (v, candidate);
+//
+// RFC2328 16.1. (3). 
+//
+// If at this step the candidate list is empty, the shortest-path tree (of
+// transit vertices) has been completely built and this stage of the
+// procedure terminates. 
+//
+      if (candidate.Size () == 0)
+        {
+          break;
+        }
+//
+// Choose the vertex belonging to the candidate list that is closest to the
+// root, and add it to the shortest-path tree (removing it from the candidate
+// list in the process).
+//
+// Recall that in the previous step, we created SPFVertex structures for each
+// of the routers found in the Global Router Link Records and added tehm to 
+// the candidate list.
+//
+      v = candidate.Pop ();
+      NS_DEBUG ("SPFCalculate: Popped vertex " << v->GetVertexId ());
+//
+// Update the status field of the vertex to indicate that it is in the SPF
+// tree.
+//
+      v->GetLSA ()->SetStatus (GlobalRoutingLSA::LSA_SPF_IN_SPFTREE);
+//
+// The current vertex has a parent pointer.  By calling this rather oddly 
+// named method (blame quagga) we add the current vertex to the list of 
+// children of that parent vertex.  In the next hop calculation called during
+// SPFNext, the parent pointer was set but the vertex has been orphaned up
+// to now.
+//
+      SPFVertexAddParent (v);
+//
+// Note that when there is a choice of vertices closest to the root, network
+// vertices must be chosen before router vertices in order to necessarily
+// find all equal-cost paths. We don't do this at this moment, we should add
+// the treatment above codes. -- kunihiro. 
+//
+// RFC2328 16.1. (4). 
+//
+// This is the method that actually adds the routes.  It'll walk the list
+// of nodes in the system, looking for the node corresponding to the router
+// ID of the root of the tree -- that is the router we're building the routes
+// for.  It looks for the Ipv4 interface of that node and remembers it.  So
+// we are only actually adding routes to that one node at the root of the SPF 
+// tree.
+//
+// We're going to pop of a pointer to every vertex in the tree except the 
+// root in order of distance from the root.  For each of the vertices, we call
+// SPFIntraAddRouter ().  Down in SPFIntraAddRouter, we look at all of the 
+// point-to-point Global Router Link Records (the links to nodes adjacent to
+// the node represented by the vertex).  We add a route to the IP address 
+// specified by the m_linkData field of each of those link records.  This will
+// be the *local* IP address associated with the interface attached to the 
+// link.  We use the outbound interface and next hop information present in 
+// the vertex <v> which have possibly been inherited from the root.
+//
+// To summarize, we're going to look at the node represented by <v> and loop
+// through its point-to-point links, adding a *host* route to the local IP
+// address (at the <v> side) for each of those links.
+//
+      if (v->GetVertexType () == SPFVertex::VertexRouter)
+        {
+          SPFIntraAddRouter (v);
+        }
+      else if (v->GetVertexType () == SPFVertex::VertexNetwork)
+        {
+          SPFIntraAddTransit (v);
+        }
+      else
+        {
+          NS_ASSERT_MSG(0, "illegal SPFVertex type");
+        }
+//
+// RFC2328 16.1. (5). 
+//
+// Iterate the algorithm by returning to Step 2 until there are no more
+// candidate vertices.
+//
+    }
+//
+// Second stage of SPF calculation procedure's  
+// NOTYET:  ospf_spf_process_stubs (area, area->spf, new_table);
+//
+// We're all done setting the routing information for the node at the root of
+// the SPF tree.  Delete all of the vertices and corresponding resources.  Go
+// possibly do it again for the next router.
+//
+  delete m_spfroot;
+  m_spfroot = 0;
+}
+
+//
+// XXX This should probably be a method on Ipv4
+//
+// Return the interface index corresponding to a given IP address
+//
+  uint32_t
+GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a)
+{
+//
+// We have an IP address <a> and a vertex ID of the root of the SPF tree.  
+// The question is what interface index does this address correspond to.
+// The answer is a little complicated since we have to find a pointer to
+// the node corresponding to the vertex ID, find the Ipv4 interface on that
+// node in order to iterate the interfaces and find the one corresponding to
+// the address in question.
+//
+  Ipv4Address routerId = m_spfroot->GetVertexId ();
+//
+// Walk the list of nodes in the system looking for the one corresponding to
+// the node at the root of the SPF tree.  This is the node for which we are
+// building the routing table.
+//
+  NodeList::Iterator i = NodeList::Begin (); 
+  for (; i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// If the node doesn't have a GlobalRouter interface it can't be the one
+// we're interested in.
+//
+      if (rtr == 0)
+        {
+          continue;
+        }
+
+      if (rtr->GetRouterId () == routerId)
+        {
+//
+// This is the node we're building the routing table for.  We're going to need
+// the Ipv4 interface to look for the ipv4 interface index.  Since this node
+// is participating in routing IP version 4 packets, it certainly must have 
+// an Ipv4 interface.
+//
+          Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+          NS_ASSERT_MSG (ipv4, 
+            "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+            "QI for <Ipv4> interface failed");
+//
+// Look through the interfaces on this node for one that has the IP address
+// we're looking for.  If we find one, return the corresponding interface
+// index.
+//
+          for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
+            {
+              if (ipv4->GetAddress (i) == a)
+                {
+                  NS_DEBUG (
+                    "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+                    "Interface match for " << a);
+                  return i;
+                }
+            }
+        }
+    }
+//
+// Couldn't find it.
+//
+  return 0;
+}
+
+//
+// XXX This should probably be a method on Ipv4
+//
+// Return the interface index corresponding to a given IP address
+//
+  uint32_t
+GlobalRouteManagerImpl::FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask)
+{
+//
+// We have an IP address <a> and a vertex ID of the root of the SPF tree.  
+// The question is what interface index does this address correspond to.
+// The answer is a little complicated since we have to find a pointer to
+// the node corresponding to the vertex ID, find the Ipv4 interface on that
+// node in order to iterate the interfaces and find the one corresponding to
+// the address in question.
+//
+  Ipv4Address routerId = m_spfroot->GetVertexId ();
+//
+// Walk the list of nodes in the system looking for the one corresponding to
+// the node at the root of the SPF tree.  This is the node for which we are
+// building the routing table.
+//
+  NodeList::Iterator i = NodeList::Begin (); 
+  for (; i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+//
+// If the node doesn't have a GlobalRouter interface it can't be the one
+// we're interested in.
+//
+      if (rtr == 0)
+        {
+          continue;
+        }
+
+      if (rtr->GetRouterId () == routerId)
+        {
+//
+// This is the node we're building the routing table for.  We're going to need
+// the Ipv4 interface to look for the ipv4 interface index.  Since this node
+// is participating in routing IP version 4 packets, it certainly must have 
+// an Ipv4 interface.
+//
+          Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+          NS_ASSERT_MSG (ipv4, 
+            "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+            "QI for <Ipv4> interface failed");
+//
+// Look through the interfaces on this node for one that has the IP address
+// we're looking for.  If we find one, return the corresponding interface
+// index.
+//
+          for (uint32_t i = 0; i < ipv4->GetNInterfaces (); i++)
+            {
+              if (ipv4->GetAddress (i).CombineMask(amask) == 
+                  a.CombineMask(amask) )
+                {
+                  NS_DEBUG (
+                    "GlobalRouteManagerImpl::FindOutgoingInterfaceId (): "
+                    "Interface match for " << a);
+                  return i;
+                }
+            }
+        }
+    }
+//
+// Couldn't find it.
+//
+  return 0;
+}
+
+//
+// This method is derived from quagga ospf_intra_add_router ()
+//
+// This is where we are actually going to add the host routes to the routing
+// tables of the individual nodes.
+//
+// The vertex passed as a parameter has just been added to the SPF tree.
+// This vertex must have a valid m_root_oid, corresponding to the outgoing
+// interface on the root router of the tree that is the first hop on the path
+// to the vertex.  The vertex must also have a next hop address, corresponding
+// to the next hop on the path to the vertex.  The vertex has an m_lsa field
+// that has some number of link records.  For each point to point link record,
+// the m_linkData is the local IP address of the link.  This corresponds to
+// a destination IP address, reachable from the root, to which we add a host
+// route.
+//
+  void
+GlobalRouteManagerImpl::SPFIntraAddRouter (SPFVertex* v)
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter ()");
+
+  NS_ASSERT_MSG (m_spfroot, 
+    "GlobalRouteManagerImpl::SPFIntraAddRouter (): Root pointer not set");
+//
+// The root of the Shortest Path First tree is the router to which we are 
+// going to write the actual routing table entries.  The vertex corresponding
+// to this router has a vertex ID which is the router ID of that node.  We're
+// going to use this ID to discover which node it is that we're actually going
+// to update.
+//
+  Ipv4Address routerId = m_spfroot->GetVertexId ();
+
+  NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+    "Vertex ID = " << routerId);
+//
+// We need to walk the list of nodes looking for the one that has the router
+// ID corresponding to the root vertex.  This is the one we're going to write
+// the routing information to.
+//
+  NodeList::Iterator i = NodeList::Begin (); 
+  for (; i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+//
+// The router ID is accessible through the GlobalRouter interface, so we need
+// to QI for that interface.  If there's no GlobalRouter interface, the node
+// in question cannot be the router we want, so we continue.
+// 
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+
+      if (rtr == 0)
+        {
+          NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+            "No GlobalRouter interface on node " << node->GetId ());
+          continue;
+        }
+//
+// If the router ID of the current node is equal to the router ID of the 
+// root of the SPF tree, then this node is the one for which we need to 
+// write the routing tables.
+//
+      NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+        "Considering router " << rtr->GetRouterId ());
+
+      if (rtr->GetRouterId () == routerId)
+        {
+          NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+            "setting routes for node " << node->GetId ());
+//
+// Routing information is updated using the Ipv4 interface.  We need to QI
+// for that interface.  If the node is acting as an IP version 4 router, it
+// should absolutely have an Ipv4 interface.
+//
+          Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+          NS_ASSERT_MSG (ipv4, 
+            "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+            "QI for <Ipv4> interface failed");
+//
+// Get the Global Router Link State Advertisement from the vertex we're
+// adding the routes to.  The LSA will have a number of attached Global Router
+// Link Records corresponding to links off of that vertex / node.  We're going
+// to be interested in the records corresponding to point-to-point links.
+//
+          GlobalRoutingLSA *lsa = v->GetLSA ();
+          NS_ASSERT_MSG (lsa, 
+            "GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+            "Expected valid LSA in SPFVertex* v");
+
+          uint32_t nLinkRecords = lsa->GetNLinkRecords ();
+//
+// Iterate through the link records on the vertex to which we're going to add
+// routes.  To make sure we're being clear, we're going to add routing table
+// entries to the tables on the node corresping to the root of the SPF tree.
+// These entries will have routes to the IP addresses we find from looking at
+// the local side of the point-to-point links found on the node described by
+// the vertex <v>.
+//
+          for (uint32_t j = 0; j < nLinkRecords; j += 2)
+            {
+//
+// We are only concerned about point-to-point links
+//
+              GlobalRoutingLinkRecord *lr = lsa->GetLinkRecord (j);
+              if (lr->GetLinkType () != GlobalRoutingLinkRecord::PointToPoint)
+                {
+                  continue;
+                }
+
+              NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddRouter (): "
+                " Node " << node->GetId () <<
+                " add route to " << lr->GetLinkData () <<
+                " using next hop " << v->GetNextHop () <<
+                " via interface " << v->GetOutgoingInterfaceId ());
+//
+// Here's why we did all of that work.  We're going to add a host route to the
+// host address found in the m_linkData field of the point-to-point link
+// record.  In the case of a point-to-point link, this is the local IP address
+// of the node connected to the link.  Each of these point-to-point links
+// will correspond to a local interface that has an IP address to which
+// the node at the root of the SPF tree can send packets.  The vertex <v> 
+// (corresponding to the node that has these links and interfaces) has 
+// an m_nextHop address precalculated for us that is the address to which the
+// root node should send packets to be forwarded to these IP addresses.
+// Similarly, the vertex <v> has an m_rootOif (outbound interface index) to
+// which the packets should be send for forwarding.
+//
+              ipv4->AddHostRouteTo (lr->GetLinkData (), v->GetNextHop (),
+                v->GetOutgoingInterfaceId ());
+            }
+//
+// Done adding the routes for the selected node.
+//
+          return;
+        }
+    }
+}
+  void
+GlobalRouteManagerImpl::SPFIntraAddTransit (SPFVertex* v)
+{
+  NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit ()");
+
+  NS_ASSERT_MSG (m_spfroot, 
+    "GlobalRouteManagerImpl::SPFIntraAddTransit (): Root pointer not set");
+//
+// The root of the Shortest Path First tree is the router to which we are 
+// going to write the actual routing table entries.  The vertex corresponding
+// to this router has a vertex ID which is the router ID of that node.  We're
+// going to use this ID to discover which node it is that we're actually going
+// to update.
+//
+  Ipv4Address routerId = m_spfroot->GetVertexId ();
+
+  NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+    "Vertex ID = " << routerId);
+//
+// We need to walk the list of nodes looking for the one that has the router
+// ID corresponding to the root vertex.  This is the one we're going to write
+// the routing information to.
+//
+  NodeList::Iterator i = NodeList::Begin (); 
+  for (; i != NodeList::End (); i++)
+    {
+      Ptr<Node> node = *i;
+//
+// The router ID is accessible through the GlobalRouter interface, so we need
+// to QI for that interface.  If there's no GlobalRouter interface, the node
+// in question cannot be the router we want, so we continue.
+// 
+      Ptr<GlobalRouter> rtr = 
+        node->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+
+      if (rtr == 0)
+        {
+          NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+            "No GlobalRouter interface on node " << node->GetId ());
+          continue;
+        }
+//
+// If the router ID of the current node is equal to the router ID of the 
+// root of the SPF tree, then this node is the one for which we need to 
+// write the routing tables.
+//
+      NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+        "Considering router " << rtr->GetRouterId ());
+
+      if (rtr->GetRouterId () == routerId)
+        {
+          NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+            "setting routes for node " << node->GetId ());
+//
+// Routing information is updated using the Ipv4 interface.  We need to QI
+// for that interface.  If the node is acting as an IP version 4 router, it
+// should absolutely have an Ipv4 interface.
+//
+          Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+          NS_ASSERT_MSG (ipv4, 
+            "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+            "QI for <Ipv4> interface failed");
+//
+// Get the Global Router Link State Advertisement from the vertex we're
+// adding the routes to.  The LSA will have a number of attached Global Router
+// Link Records corresponding to links off of that vertex / node.  We're going
+// to be interested in the records corresponding to point-to-point links.
+//
+          GlobalRoutingLSA *lsa = v->GetLSA ();
+          NS_ASSERT_MSG (lsa, 
+            "GlobalRouteManagerImpl::SPFIntraAddTransit (): "
+            "Expected valid LSA in SPFVertex* v");
+          Ipv4Mask tempmask = lsa->GetNetworkLSANetworkMask ();
+          Ipv4Address tempip = lsa->GetLinkStateId ();
+          tempip = tempip.CombineMask (tempmask);
+          ipv4->AddNetworkRouteTo (tempip, tempmask, v->GetNextHop (),
+            v->GetOutgoingInterfaceId ());
+          NS_DEBUG ("GlobalRouteManagerImpl::SPFIntraAddNetwork (): "
+            " Node " << node->GetId () <<
+            " add network route to " << tempip <<
+            " using next hop " << v->GetNextHop () <<
+            " via interface " << v->GetOutgoingInterfaceId ());
+        }
+    } 
+}
+
+// Derived from quagga ospf_vertex_add_parents ()
+//
+// This is a somewhat oddly named method (blame quagga).  Although you might
+// expect it to add a parent *to* something, it actually adds a vertex
+// to the list of children *in* each of its parents. 
+//
+// Given a pointer to a vertex, it links back to the vertex's parent that it
+// already has set and adds itself to that vertex's list of children.
+//
+// For now, only one parent (not doing equal-cost multipath)
+//
+  void
+GlobalRouteManagerImpl::SPFVertexAddParent (SPFVertex* v)
+{
+  v->GetParent ()->AddChild (v);
+}
+
+} // namespace ns3
+
+#ifdef RUN_SELF_TESTS
+
+// ---------------------------------------------------------------------------
+//
+// Unit Tests
+//
+// ---------------------------------------------------------------------------
+
+#include "ns3/test.h"
+#include "ns3/simulator.h"
+
+namespace ns3 {
+
+class GlobalRouterTestNode : public Node
+{
+public:
+  GlobalRouterTestNode ();
+
+private:
+  virtual void DoAddDevice (Ptr<NetDevice> device) const {};
+  virtual TraceResolver *DoCreateTraceResolver (TraceContext const &context);
+};
+
+GlobalRouterTestNode::GlobalRouterTestNode ()
+{
+//  Ptr<Ipv4L3Protocol> ipv4 = Create<Ipv4L3Protocol> (this);
+}
+
+  TraceResolver*
+GlobalRouterTestNode::DoCreateTraceResolver (TraceContext const &context)
+{
+  return 0;
+}
+
+class GlobalRouteManagerImplTest : public Test {
+public:
+  GlobalRouteManagerImplTest ();
+  virtual ~GlobalRouteManagerImplTest ();
+  virtual bool RunTests (void);
+};
+
+GlobalRouteManagerImplTest::GlobalRouteManagerImplTest ()
+  : Test ("GlobalRouteManagerImpl")
+{
+}
+
+GlobalRouteManagerImplTest::~GlobalRouteManagerImplTest ()
+{}
+
+  bool
+GlobalRouteManagerImplTest::RunTests (void)
+{
+  bool ok = true;
+
+  CandidateQueue candidate;
+
+  for (int i = 0; i < 100; ++i)
+    {
+      SPFVertex *v = new SPFVertex;
+      v->SetDistanceFromRoot (rand () % 100);
+      candidate.Push (v);
+    }
+
+  uint32_t lastDistance = 0;
+
+  for (int i = 0; i < 100; ++i)
+    {
+      SPFVertex *v = candidate.Pop ();
+      if (v->GetDistanceFromRoot () < lastDistance)
+        {
+          ok = false;
+        }
+      lastDistance = v->GetDistanceFromRoot ();
+      delete v;
+      v = 0;
+    }
+
+  // Build fake link state database; four routers (0-3), 3 point-to-point
+  // links
+  //
+  //   n0
+  //      \ link 0
+  //       \          link 2
+  //        n2 -------------------------n3
+  //       /
+  //      / link 1
+  //    n1
+  //
+  //  link0:  10.1.1.1/30, 10.1.1.2/30
+  //  link1:  10.1.2.1/30, 10.1.2.2/30
+  //  link2:  10.1.3.1/30, 10.1.3.2/30
+  //
+  // Router 0
+  GlobalRoutingLinkRecord* lr0 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint, 
+    "0.0.0.2",  // router ID 0.0.0.2
+    "10.1.1.1", // local ID
+    1);         // metric
+
+  GlobalRoutingLinkRecord* lr1 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.1.1",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLSA* lsa0 = new GlobalRoutingLSA ();
+  lsa0->SetLSType (GlobalRoutingLSA::RouterLSA);
+  lsa0->SetLinkStateId ("0.0.0.0");
+  lsa0->SetAdvertisingRouter ("0.0.0.0");
+  lsa0->AddLinkRecord (lr0);
+  lsa0->AddLinkRecord (lr1);
+
+  // Router 1
+  GlobalRoutingLinkRecord* lr2 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.2",
+    "10.1.2.1",
+    1);
+
+  GlobalRoutingLinkRecord* lr3 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.2.1",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLSA* lsa1 = new GlobalRoutingLSA ();
+  lsa1->SetLSType (GlobalRoutingLSA::RouterLSA);
+  lsa1->SetLinkStateId ("0.0.0.1");
+  lsa1->SetAdvertisingRouter ("0.0.0.1");
+  lsa1->AddLinkRecord (lr2);
+  lsa1->AddLinkRecord (lr3);
+  
+  // Router 2 
+  GlobalRoutingLinkRecord* lr4 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.0",
+    "10.1.1.2",
+    1);
+
+  GlobalRoutingLinkRecord* lr5 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.1.2",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLinkRecord* lr6 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.1",
+    "10.1.2.2",
+    1);
+
+  GlobalRoutingLinkRecord* lr7 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.2.2",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLinkRecord* lr8 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.3",
+    "10.1.3.2",
+    1);
+
+  GlobalRoutingLinkRecord* lr9 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.3.2",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLSA* lsa2 = new GlobalRoutingLSA ();
+  lsa2->SetLSType (GlobalRoutingLSA::RouterLSA);
+  lsa2->SetLinkStateId ("0.0.0.2");
+  lsa2->SetAdvertisingRouter ("0.0.0.2");
+  lsa2->AddLinkRecord (lr4);
+  lsa2->AddLinkRecord (lr5);
+  lsa2->AddLinkRecord (lr6);
+  lsa2->AddLinkRecord (lr7);
+  lsa2->AddLinkRecord (lr8);
+  lsa2->AddLinkRecord (lr9);
+
+  // Router 3
+  GlobalRoutingLinkRecord* lr10 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::PointToPoint,
+    "0.0.0.2",
+    "10.1.2.1",
+    1);
+
+  GlobalRoutingLinkRecord* lr11 = new GlobalRoutingLinkRecord (
+    GlobalRoutingLinkRecord::StubNetwork,
+    "10.1.2.1",
+    "255.255.255.252",
+    1);
+
+  GlobalRoutingLSA* lsa3 = new GlobalRoutingLSA ();
+  lsa3->SetLSType (GlobalRoutingLSA::RouterLSA);
+  lsa3->SetLinkStateId ("0.0.0.3");
+  lsa3->SetAdvertisingRouter ("0.0.0.3");
+  lsa3->AddLinkRecord (lr10);
+  lsa3->AddLinkRecord (lr11);
+
+  // Test the database 
+  GlobalRouteManagerLSDB* srmlsdb = new GlobalRouteManagerLSDB ();
+  srmlsdb->Insert (lsa0->GetLinkStateId (), lsa0);
+  srmlsdb->Insert (lsa1->GetLinkStateId (), lsa1);
+  srmlsdb->Insert (lsa2->GetLinkStateId (), lsa2);
+  srmlsdb->Insert (lsa3->GetLinkStateId (), lsa3);
+  NS_ASSERT (lsa2 == srmlsdb->GetLSA (lsa2->GetLinkStateId ()));
+
+  // next, calculate routes based on the manually created LSDB
+  GlobalRouteManagerImpl* srm = new GlobalRouteManagerImpl ();
+  srm->DebugUseLsdb (srmlsdb);  // manually add in an LSDB
+  // Note-- this will succeed without any nodes in the topology
+  // because the NodeList is empty
+  srm->DebugSPFCalculate (lsa0->GetLinkStateId ());  // node n0
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  // This delete clears the srm, which deletes the LSDB, which clears 
+  // all of the LSAs, which each destroys the attached LinkRecords.
+  delete srm;
+
+  return ok;
+}
+
+// Instantiate this class for the unit tests
+// XXX here we should do some verification of the routes built
+static GlobalRouteManagerImplTest g_globalRouteManagerTest;
+
+} // namespace ns3
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager-impl.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,763 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#ifndef GLOBAL_ROUTE_MANAGER_IMPL_H
+#define GLOBAL_ROUTE_MANAGER_IMPL_H
+
+#include <stdint.h>
+#include <list>
+#include <queue>
+#include <map>
+#include "ns3/object.h"
+#include "ns3/ptr.h"
+#include "ns3/ipv4-address.h"
+#include "global-router-interface.h"
+
+namespace ns3 {
+
+const uint32_t SPF_INFINITY = 0xffffffff;
+
+class CandidateQueue;
+
+/**
+ * @brief Vertex used in shortest path first (SPF) computations. See RFC 2328,
+ * Section 16.
+ *
+ * Each router in the simulation is associated with an SPFVertex object.  When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes.  Each of these 
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is the SPFVertex representing the router that is having
+ * its routing tables set.  The SPFVertex objects representing other routers
+ * or networks in the simulation are arranged in the SPF tree.  It is this 
+ * tree that represents the Shortest Paths to the other networks.
+ *
+ * Each SPFVertex has a pointer to the Global Router Link State Advertisement
+ * (LSA) that its underlying router has exported.  Within these LSAs are
+ * Global Router Link Records that describe the point to point links from the
+ * underlying router to other nodes (represented by other SPFVertex objects)
+ * in the simulation topology.  The combination of the arrangement of the 
+ * SPFVertex objects in the SPF tree, along with the details of the link
+ * records that connect them provide the information required to construct the
+ * required routes.
+ */
+class SPFVertex
+{
+public:
+/**
+ * @brief Enumeration of the possible types of SPFVertex objects.
+ * @internal
+ *
+ * Currently we use VertexRouter to identify objects that represent a router 
+ * in the simulation topology, and VertexNetwork to identify objects that 
+ * represent a network.
+ */
+  enum VertexType {
+    VertexUnknown = 0,  /**< Uninitialized Link Record */
+    VertexRouter,       /**< Vertex representing a router in the topology */
+    VertexNetwork       /**< Vertex representing a network in the topology */
+  };
+
+/**
+ * @brief Construct an empty ("uninitialized") SPFVertex (Shortest Path First 
+ * Vertex).
+ * @internal
+ *
+ * The Vertex Type is set to VertexUnknown, the Vertex ID is set to 
+ * 255.255.255.255, and the distance from root is set to infinity 
+ * (UINT32_MAX).  The referenced Link State Advertisement (LSA) is set to 
+ * null as is the parent SPFVertex.  The outgoing interface index is set to
+ * infinity, the next hop address is set to 0.0.0.0 and the list of children
+ * of the SPFVertex is initialized to empty.
+ *
+ * @see VertexType
+ */
+  SPFVertex();
+
+/**
+ * @brief Construct an initialized SPFVertex (Shortest Path First Vertex).
+ * @internal
+ *
+ * The Vertex Type is initialized to VertexRouter and the Vertex ID is found
+ * from the Link State ID of the Link State Advertisement (LSA) passed as a
+ * parameter.  The Link State ID is set to the Router ID of the advertising
+ * router.  The referenced LSA (m_lsa) is set to the given LSA.  Other than 
+ * these members, initialization is as in the default constructor.
+ * of the SPFVertex is initialized to empty.
+ *
+ * @see SPFVertex::SPFVertex ()
+ * @see VertexType
+ * @see GlobalRoutingLSA
+ * @param lsa The Link State Advertisement used for finding initial values.
+ */
+  SPFVertex(GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Destroy an SPFVertex (Shortest Path First Vertex).
+ * @internal
+ *
+ * The children vertices of the SPFVertex are recursively deleted.
+ *
+ * @see SPFVertex::SPFVertex ()
+ */
+  ~SPFVertex();
+
+/**
+ * @brief Get the Vertex Type field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex Type describes the kind of simulation object a given SPFVertex
+ * represents.
+ *
+ * @see VertexType
+ * @returns The VertexType of the current SPFVertex object.
+ */
+  VertexType GetVertexType (void) const;
+
+/**
+ * @brief Set the Vertex Type field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex Type describes the kind of simulation object a given SPFVertex
+ * represents.
+ *
+ * @see VertexType
+ * @param type The new VertexType for the current SPFVertex object.
+ */
+  void SetVertexType (VertexType type);
+
+/**
+ * @brief Get the Vertex ID field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex ID uniquely identifies the simulation object a given SPFVertex
+ * represents.  Typically, this is the Router ID for SPFVertex objects 
+ * representing routers, and comes from the Link State Advertisement of a 
+ * router aggregated to a node in the simulation.  These IDs are allocated
+ * automatically by the routing environment and look like IP addresses 
+ * beginning at 0.0.0.0 and monotonically increasing as new routers are
+ * instantiated.
+ *
+ * @returns The Ipv4Address Vertex ID of the current SPFVertex object.
+ */
+  Ipv4Address GetVertexId (void) const;
+
+/**
+ * @brief Set the Vertex ID field of a SPFVertex object.
+ * @internal
+ *
+ * The Vertex ID uniquely identifies the simulation object a given SPFVertex
+ * represents.  Typically, this is the Router ID for SPFVertex objects 
+ * representing routers, and comes from the Link State Advertisement of a 
+ * router aggregated to a node in the simulation.  These IDs are allocated
+ * automatically by the routing environment and look like IP addresses 
+ * beginning at 0.0.0.0 and monotonically increase as new routers are
+ * instantiated.  This method is an explicit override of the automatically
+ * generated value.
+ *
+ * @param id The new Ipv4Address Vertex ID for the current SPFVertex object.
+ */
+  void SetVertexId (Ipv4Address id);
+
+/**
+ * @brief Get the Global Router Link State Advertisement returned by the 
+ * Global Router represented by this SPFVertex during the route discovery 
+ * process.
+ * @internal
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::DiscoverLSAs ()
+ * @returns A pointer to the GlobalRoutingLSA found by the router represented
+ * by this SPFVertex object.
+ */
+  GlobalRoutingLSA* GetLSA (void) const;
+
+/**
+ * @brief Set the Global Router Link State Advertisement returned by the 
+ * Global Router represented by this SPFVertex during the route discovery 
+ * process.
+ * @internal
+ *
+ * @see SPFVertex::GetLSA ()
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::DiscoverLSAs ()
+ * @warning Ownership of the LSA is transferred to the "this" SPFVertex.  You
+ * must not delete the LSA after calling this method.
+ * @param lsa A pointer to the GlobalRoutingLSA.
+ */
+  void SetLSA (GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Get the distance from the root vertex to "this" SPFVertex object.
+ * @internal
+ *
+ * Each router in the simulation is associated with an SPFVertex object.  When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes.  Each of these 
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex to which
+ * a route is being calculated from the root.  The distance from the root that
+ * we're asking for is the number of hops from the root vertex to the vertex
+ * in question.
+ *
+ * The distance is calculated during route discovery and is stored in a
+ * member variable.  This method simply fetches that value.
+ *
+ * @returns The distance, in hops, from the root SPFVertex to "this" SPFVertex.
+ */
+  uint32_t GetDistanceFromRoot (void) const;
+
+/**
+ * @brief Set the distance from the root vertex to "this" SPFVertex object.
+ * @internal
+ *
+ * Each router in the simulation is associated with an SPFVertex object.  When
+ * calculating routes, each of these routers is, in turn, chosen as the "root"
+ * of the calculation and routes to all of the other routers are eventually
+ * saved in the routing tables of each of the chosen nodes.  Each of these 
+ * routers in the calculation has an associated SPFVertex.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex to which
+ * a route is being calculated from the root.  The distance from the root that
+ * we're asking for is the number of hops from the root vertex to the vertex
+ * in question.
+ *
+ * @param distance The distance, in hops, from the root SPFVertex to "this"
+ * SPFVertex.
+ */
+  void SetDistanceFromRoot (uint32_t distance);
+
+/**
+ * @brief Get the interface ID that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from 
+ * the root.  The outgoing interface that we're asking for is the interface
+ * index on the root node that should be used to start packets along the
+ * path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the interface ID is determined by
+ * examining the Global Router Link Records of the Link State Advertisement
+ * generated by the root node's GlobalRouter.  These interfaces are used to 
+ * forward packets off of the root's network down those links.  As other 
+ * vertices are discovered which are further away from the root, they will 
+ * be accessible down one of the paths begun by a Global Router Link Record.
+ * 
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to the interface of that
+ * first hop.  This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices.  We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, the root node is asking, "which of my local interfaces
+ * should I use to get a packet to the network or host represented by 'this'
+ * SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @returns The interface index to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+  uint32_t GetOutgoingInterfaceId (void) const;
+
+/**
+ * @brief Set the interface ID that should be used to begin forwarding packets
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from 
+ * the root.  The outgoing interface that we're asking for is the interface
+ * index on the root node that should be used to start packets along the
+ * path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the interface ID is determined by
+ * examining the Global Router Link Records of the Link State Advertisement
+ * generated by the root node's GlobalRouter.  These interfaces are used to 
+ * forward packets off of the root's network down those links.  As other 
+ * vertices are discovered which are further away from the root, they will 
+ * be accessible down one of the paths begun by a Global Router Link Record.
+ * 
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to the interface of that
+ * first hop.  This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices.  We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, we are letting the root node know which of its local
+ * interfaces it should use to get a packet to the network or host represented
+ * by "this" SPFVertex.
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @param id The interface index to use when forwarding packets to the host or
+ * network represented by "this" SPFVertex.
+ */
+  void SetOutgoingInterfaceId (uint32_t id);
+
+/**
+ * @brief Get the IP address that should be used to begin forwarding packets 
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from 
+ * the root.  The IP address that we're asking for is the address on the 
+ * remote side of a link off of the root node that should be used as the
+ * destination for packets along the path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the IP address used when forwarding
+ * packets is determined by examining the Global Router Link Records of the
+ * Link State Advertisement generated by the root node's GlobalRouter.  This
+ * address is used to forward packets off of the root's network down those
+ * links.  As other vertices / nodes are discovered which are further away
+ * from the root, they will be accessible down one of the paths via a link
+ * described by one of these Global Router Link Records.
+ * 
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to a first hop router down
+ * an interface.  This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices.  We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method, the root node is asking, "which router should I send a
+ * packet to in order to get that packet to the network or host represented 
+ * by 'this' SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @returns The IP address to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+  Ipv4Address GetNextHop (void) const;
+
+/**
+ * @brief Set the IP address that should be used to begin forwarding packets 
+ * from the root SPFVertex to "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set.  The "this" SPFVertex is the vertex that
+ * represents the host or network to which a route is being calculated from 
+ * the root.  The IP address that we're asking for is the address on the 
+ * remote side of a link off of the root node that should be used as the
+ * destination for packets along the path to "this" vertex.
+ *
+ * When initializing the root SPFVertex, the IP address used when forwarding
+ * packets is determined by examining the Global Router Link Records of the
+ * Link State Advertisement generated by the root node's GlobalRouter.  This
+ * address is used to forward packets off of the root's network down those
+ * links.  As other vertices / nodes are discovered which are further away
+ * from the root, they will be accessible down one of the paths via a link
+ * described by one of these Global Router Link Records.
+ * 
+ * To forward packets to these hosts or networks, the root node must begin
+ * the forwarding process by sending the packets to a first hop router down
+ * an interface.  This means that the first hop address and interface ID must
+ * be the same for all downstream SPFVertices.  We call this "inheriting"
+ * the interface and next hop.
+ *
+ * In this method we are telling the root node which router it should send
+ * should I send a packet to in order to get that packet to the network or
+ * host represented by 'this' SPFVertex."
+ *
+ * @see GlobalRouter
+ * @see GlobalRoutingLSA
+ * @see GlobalRoutingLinkRecord
+ * @param nextHop The IP address to use when forwarding packets to the host
+ * or network represented by "this" SPFVertex.
+ */
+  void SetNextHop (Ipv4Address nextHop);
+
+/**
+ * @brief Get a pointer to the SPFVector that is the parent of "this" 
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.
+ *
+ * This method returns a pointer to the parent node of "this" SPFVertex
+ * (both of which reside in that SPF tree).
+ *
+ * @returns A pointer to the SPFVertex that is the parent of "this" SPFVertex
+ * in the SPF tree.
+ */
+  SPFVertex* GetParent (void) const;
+
+/**
+ * @brief Set the pointer to the SPFVector that is the parent of "this" 
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.
+ *
+ * This method sets the parent pointer of "this" SPFVertex (both of which
+ * reside in that SPF tree).
+ *
+ * @param parent A pointer to the SPFVertex that is the parent of "this" 
+ * SPFVertex* in the SPF tree.
+ */
+  void SetParent (SPFVertex* parent);
+
+/**
+ * @brief Get the number of children of "this" SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.  Each vertex
+ * in the SPF tree can have a number of children that represent host or 
+ * network routes available via that vertex.
+ *
+ * This method returns the number of children of "this" SPFVertex (which 
+ * reside in the SPF tree).
+ *
+ * @returns The number of children of "this" SPFVertex (which reside in the
+ * SPF tree).
+ */
+  uint32_t GetNChildren (void) const;
+
+/**
+ * @brief Get a borrowed SPFVertex pointer to the specified child of "this" 
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.  Each vertex
+ * in the SPF tree can have a number of children that represent host or 
+ * network routes available via that vertex.
+ *
+ * This method the number of children of "this" SPFVertex (which reside in
+ * the SPF tree.
+ *
+ * @see SPFVertex::GetNChildren
+ * @param n The index (from 0 to the number of children minus 1) of the 
+ * child SPFVertex to return.
+ * @warning The pointer returned by GetChild () is a borrowed pointer.  You
+ * do not have any ownership of the underlying object and must not delete
+ * that object.
+ * @returns A pointer to the specified child SPFVertex (which resides in the
+ * SPF tree).
+ */
+  SPFVertex* GetChild (uint32_t n) const;
+
+/**
+ * @brief Get a borrowed SPFVertex pointer to the specified child of "this" 
+ * SPFVertex.
+ * @internal
+ *
+ * Each router node in the simulation is associated with an SPFVertex object.
+ * When calculating routes, each of these routers is, in turn, chosen as the 
+ * "root" of the calculation and routes to all of the other routers are
+ * eventually saved in the routing tables of each of the chosen nodes.
+ *
+ * The "Root" vertex is then the SPFVertex representing the router that is
+ * having its routing tables set and is the root of the SPF tree.  Each vertex
+ * in the SPF tree can have a number of children that represent host or 
+ * network routes available via that vertex.
+ *
+ * This method the number of children of "this" SPFVertex (which reside in
+ * the SPF tree.
+ *
+ * @see SPFVertex::GetNChildren
+ * @warning Ownership of the pointer added to the children of "this" 
+ * SPFVertex is transferred to the "this" SPFVertex.  You must not delete the
+ * (now) child SPFVertex after calling this method.
+ * @param child A pointer to the SPFVertex (which resides in the SPF tree) to
+ * be added to the list of children of "this" SPFVertex.
+ * @returns The number of children of "this" SPFVertex after the addition of
+ * the new child.
+ */
+  uint32_t AddChild (SPFVertex* child);
+
+private:
+  VertexType m_vertexType;
+  Ipv4Address m_vertexId;
+  GlobalRoutingLSA* m_lsa;
+  uint32_t m_distanceFromRoot;
+  uint32_t m_rootOif;
+  Ipv4Address m_nextHop;
+  SPFVertex* m_parent;
+  typedef std::list<SPFVertex*> ListOfSPFVertex_t;
+  ListOfSPFVertex_t m_children;
+
+/**
+ * @brief The SPFVertex copy construction is disallowed.  There's no need for
+ * it and a compiler provided shallow copy would be wrong.
+ */
+  SPFVertex (SPFVertex& v);
+
+/**
+ * @brief The SPFVertex copy assignment operator is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+  SPFVertex& operator= (SPFVertex& v);
+};
+
+/**
+ * @brief The Link State DataBase (LSDB) of the Global Route Manager.
+ *
+ * Each node in the simulation participating in global routing has a
+ * GlobalRouter interface.  The primary job of this interface is to export
+ * Global Router Link State Advertisements (LSAs).  These advertisements in
+ * turn contain a number of Global Router Link Records that describe the 
+ * point to point links from the underlying node to other nodes (that will 
+ * also export their own LSAs.
+ *
+ * This class implements a searchable database of LSAs gathered from every
+ * router in the simulation.
+ */
+class GlobalRouteManagerLSDB
+{
+public:
+/**
+ * @brief Construct an empty Global Router Manager Link State Database.
+ * @internal
+ *
+ * The database map composing the Link State Database is initialized in
+ * this constructor.
+ */
+  GlobalRouteManagerLSDB ();
+
+/**
+ * @brief Destroy an empty Global Router Manager Link State Database.
+ * @internal
+ *
+ * The database map is walked and all of the Link State Advertisements stored
+ * in the database are freed; then the database map itself is clear ()ed to
+ * release any remaining resources.
+ */
+  ~GlobalRouteManagerLSDB ();
+
+/**
+ * @brief Insert an IP address / Link State Advertisement pair into the Link
+ * State Database.
+ * @internal
+ *
+ * The IPV4 address and the GlobalRoutingLSA given as parameters are converted
+ * to an STL pair and are inserted into the database map.
+ *
+ * @see GlobalRoutingLSA
+ * @see Ipv4Address
+ * @param addr The IP address associated with the LSA.  Typically the Router 
+ * ID.
+ * @param lsa A pointer to the Link State Advertisement for the router.
+ */
+  void Insert(Ipv4Address addr, GlobalRoutingLSA* lsa);
+
+/**
+ * @brief Look up the Link State Advertisement associated with the given
+ * link state ID (address).
+ * @internal
+ *
+ * The database map is searched for the given IPV4 address and corresponding
+ * GlobalRoutingLSA is returned.
+ *
+ * @see GlobalRoutingLSA
+ * @see Ipv4Address
+ * @param addr The IP address associated with the LSA.  Typically the Router 
+ * ID.
+ * @returns A pointer to the Link State Advertisement for the router specified
+ * by the IP address addr.
+ */
+  GlobalRoutingLSA* GetLSA (Ipv4Address addr) const;
+/**
+ * @brief Look up the Link State Advertisement associated with the given
+ * link state ID (address).  This is a variation of the GetLSA call
+ * to allow the LSA to be found by matching addr with the LinkData field
+ * of the TransitNetwork link record.
+ * @internal
+ *
+ * @see GetLSA
+ * @param addr The IP address associated with the LSA.  Typically the Router 
+ * @returns A pointer to the Link State Advertisement for the router specified
+ * by the IP address addr.
+ * ID.
+ */
+  GlobalRoutingLSA* GetLSAByLinkData (Ipv4Address addr) const;
+
+/**
+ * @brief Set all LSA flags to an initialized state, for SPF computation
+ * @internal
+ *
+ * This function walks the database and resets the status flags of all of the
+ * contained Link State Advertisements to LSA_SPF_NOT_EXPLORED.  This is done
+ * prior to each SPF calculation to reset the state of the SPFVertex structures
+ * that will reference the LSAs during the calculation.
+ *
+ * @see GlobalRoutingLSA
+ * @see SPFVertex
+ */
+  void Initialize ();
+
+private:
+  typedef std::map<Ipv4Address, GlobalRoutingLSA*> LSDBMap_t;
+  typedef std::pair<Ipv4Address, GlobalRoutingLSA*> LSDBPair_t;
+
+  LSDBMap_t m_database;
+/**
+ * @brief GlobalRouteManagerLSDB copy construction is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+  GlobalRouteManagerLSDB (GlobalRouteManagerLSDB& lsdb);
+
+/**
+ * @brief The SPFVertex copy assignment operator is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+  GlobalRouteManagerLSDB& operator= (GlobalRouteManagerLSDB& lsdb);
+};
+
+/**
+ * @brief A global router implementation.
+ *
+ * This singleton object can query interface each node in the system
+ * for a GlobalRouter interface.  For those nodes, it fetches one or
+ * more Link State Advertisements and stores them in a local database.
+ * Then, it can compute shortest paths on a per-node basis to all routers, 
+ * and finally configure each of the node's forwarding tables.
+ *
+ * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd.
+ */
+class GlobalRouteManagerImpl
+{
+public:
+  GlobalRouteManagerImpl ();
+  virtual ~GlobalRouteManagerImpl ();
+/**
+ * @brief Select which nodes in the system are to be router nodes and 
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+  virtual void SelectRouterNodes ();
+
+/**
+ * @brief Build the routing database by gathering Link State Advertisements
+ * from each node exporting a GlobalRouter interface.
+ * @internal
+ */
+  virtual void BuildGlobalRoutingDatabase ();
+
+/**
+ * @brief Compute routes using a Dijkstra SPF computation and populate
+ * per-node forwarding tables
+ * @internal
+ */
+  virtual void InitializeRoutes ();
+
+/**
+ * @brief Debugging routine; allow client code to supply a pre-built LSDB
+ * @internal
+ */
+  void DebugUseLsdb (GlobalRouteManagerLSDB*);
+
+/**
+ * @brief Debugging routine; call the core SPF from the unit tests
+ * @internal
+ */
+  void DebugSPFCalculate (Ipv4Address root);
+
+private:
+/**
+ * @brief GlobalRouteManagerImpl copy construction is disallowed.
+ * There's no  need for it and a compiler provided shallow copy would be 
+ * wrong.
+ */
+  GlobalRouteManagerImpl (GlobalRouteManagerImpl& srmi);
+
+/**
+ * @brief Global Route Manager Implementation assignment operator is
+ * disallowed.  There's no  need for it and a compiler provided shallow copy
+ * would be hopelessly wrong.
+ */
+  GlobalRouteManagerImpl& operator= (GlobalRouteManagerImpl& srmi);
+
+  SPFVertex* m_spfroot;
+  GlobalRouteManagerLSDB* m_lsdb;
+  void SPFCalculate (Ipv4Address root);
+  void SPFNext (SPFVertex*, CandidateQueue&);
+  int SPFNexthopCalculation (SPFVertex* v, SPFVertex* w, 
+    GlobalRoutingLinkRecord* l, uint32_t distance);
+  void SPFVertexAddParent (SPFVertex* v);
+  GlobalRoutingLinkRecord* SPFGetNextLink (SPFVertex* v, SPFVertex* w, 
+    GlobalRoutingLinkRecord* prev_link);
+  void SPFIntraAddRouter (SPFVertex* v);
+  void SPFIntraAddTransit (SPFVertex* v);
+  uint32_t FindOutgoingInterfaceId (Ipv4Address a);
+  uint32_t FindOutgoingInterfaceId (Ipv4Address a, Ipv4Mask amask);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTE_MANAGER_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,68 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#include "ns3/assert.h"
+#include "ns3/debug.h"
+#include "ns3/simulation-singleton.h"
+#include "global-route-manager.h"
+#include "global-route-manager-impl.h"
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouteManager Implementation
+//
+// ---------------------------------------------------------------------------
+
+  void
+GlobalRouteManager::PopulateRoutingTables () 
+{
+  SelectRouterNodes ();
+  BuildGlobalRoutingDatabase ();
+  InitializeRoutes ();
+}
+
+  void
+GlobalRouteManager::SelectRouterNodes () 
+{
+  SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+    SelectRouterNodes ();
+}
+
+  void
+GlobalRouteManager::BuildGlobalRoutingDatabase () 
+{
+  SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+    BuildGlobalRoutingDatabase ();
+}
+
+  void
+GlobalRouteManager::InitializeRoutes ()
+{
+  SimulationSingleton<GlobalRouteManagerImpl>::Get ()->
+    InitializeRoutes ();
+}
+
+  uint32_t
+GlobalRouteManager::AllocateRouterId ()
+{
+  static uint32_t routerId = 0;
+  return routerId++;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-route-manager.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,93 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#ifndef GLOBAL_ROUTE_MANAGER_H
+#define GLOBAL_ROUTE_MANAGER_H
+
+namespace ns3 {
+
+/**
+ * @brief A global global router
+ *
+ * This singleton object can query interface each node in the system
+ * for a GlobalRouter interface.  For those nodes, it fetches one or
+ * more Link State Advertisements and stores them in a local database.
+ * Then, it can compute shortest paths on a per-node basis to all routers, 
+ * and finally configure each of the node's forwarding tables.
+ *
+ * The design is guided by OSPFv2 RFC 2328 section 16.1.1 and quagga ospfd.
+ */
+class GlobalRouteManager
+{
+public:
+/**
+ * @brief Build a routing database and initialize the routing tables of
+ * the nodes in the simulation.
+ *
+ * All this function does is call  BuildGlobalRoutingDatabase () and
+ * InitializeRoutes ().
+ *
+ * @see BuildGlobalRoutingDatabase ();
+ * @see InitializeRoutes ();
+ */
+  static void PopulateRoutingTables ();
+
+/**
+ * @brief Allocate a 32-bit router ID from monotonically increasing counter.
+ */
+  static uint32_t AllocateRouterId ();
+
+private:
+/**
+ * @brief Select which nodes in the system are to be router nodes and 
+ * aggregate the appropriate interfaces onto those nodes.
+ * @internal
+ *
+ */
+  static void SelectRouterNodes ();
+
+/**
+ * @brief Build the routing database by gathering Link State Advertisements
+ * from each node exporting a GlobalRouter interface.
+ * @internal
+ *
+ */
+  static void BuildGlobalRoutingDatabase ();
+
+/**
+ * @brief Compute routes using a Dijkstra SPF computation and populate
+ * per-node forwarding tables
+ * @internal
+ */
+  static void InitializeRoutes ();
+
+/**
+ * @brief Global Route Manager copy construction is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ *
+ */
+  GlobalRouteManager (GlobalRouteManager& srm);
+
+/**
+ * @brief Global Router copy assignment operator is disallowed.  There's no 
+ * need for it and a compiler provided shallow copy would be wrong.
+ */
+  GlobalRouteManager& operator= (GlobalRouteManager& srm);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTE_MANAGER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-router-interface.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,821 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#include "ns3/debug.h"
+#include "ns3/assert.h"
+#include "ns3/channel.h"
+#include "ns3/net-device.h"
+#include "ns3/internet-node.h"
+#include "ns3/ipv4.h"
+#include "global-router-interface.h"
+
+NS_DEBUG_COMPONENT_DEFINE ("GlobalRouter");
+
+namespace ns3 {
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRoutingLinkRecord Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRoutingLinkRecord::GlobalRoutingLinkRecord ()
+:
+  m_linkId ("0.0.0.0"),
+  m_linkData ("0.0.0.0"),
+  m_linkType (Unknown),
+  m_metric (0)
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::GlobalRoutingLinkRecord ()");
+}
+
+GlobalRoutingLinkRecord::GlobalRoutingLinkRecord (
+  LinkType    linkType, 
+  Ipv4Address linkId, 
+  Ipv4Address linkData, 
+  uint32_t    metric)
+:
+  m_linkId (linkId),
+  m_linkData (linkData),
+  m_linkType (linkType),
+  m_metric (metric)
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::GlobalRoutingLinkRecord (" <<
+    linkType << ", " << linkId << ", " << linkData << ", " << metric << ")");
+}
+
+GlobalRoutingLinkRecord::~GlobalRoutingLinkRecord ()
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::~GlobalRoutingLinkRecord ()");
+}
+
+  Ipv4Address
+GlobalRoutingLinkRecord::GetLinkId (void) const
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::GetLinkId ()");
+  return m_linkId;
+}
+
+  void
+GlobalRoutingLinkRecord::SetLinkId (Ipv4Address addr)
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::SetLinkId ()");
+  m_linkId = addr;
+}
+
+  Ipv4Address
+GlobalRoutingLinkRecord::GetLinkData (void) const
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::GetLinkData ()");
+  return m_linkData;
+}
+
+  void
+GlobalRoutingLinkRecord::SetLinkData (Ipv4Address addr)
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::SetLinkData ()");
+  m_linkData = addr;
+}
+
+  GlobalRoutingLinkRecord::LinkType
+GlobalRoutingLinkRecord::GetLinkType (void) const
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::GetLinkType ()");
+  return m_linkType;
+}
+
+  void
+GlobalRoutingLinkRecord::SetLinkType (
+  GlobalRoutingLinkRecord::LinkType linkType)
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::SetLinkType ()");
+  m_linkType = linkType;
+}
+
+  uint32_t
+GlobalRoutingLinkRecord::GetMetric (void) const
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::GetMetric ()");
+  return m_metric;
+}
+
+  void
+GlobalRoutingLinkRecord::SetMetric (uint32_t metric)
+{
+  NS_DEBUG("GlobalRoutingLinkRecord::SetMetric ()");
+  m_metric = metric;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRoutingLSA Implementation
+//
+// ---------------------------------------------------------------------------
+
+GlobalRoutingLSA::GlobalRoutingLSA()
+  : 
+  m_lsType (GlobalRoutingLSA::Unknown),
+  m_linkStateId("0.0.0.0"),
+  m_advertisingRtr("0.0.0.0"),
+  m_linkRecords(),
+  m_networkLSANetworkMask("0.0.0.0"),
+  m_attachedRouters(),
+  m_status(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED)
+{
+  NS_DEBUG("GlobalRoutingLSA::GlobalRoutingLSA ()");
+}
+
+GlobalRoutingLSA::GlobalRoutingLSA (
+  GlobalRoutingLSA::SPFStatus status,
+  Ipv4Address linkStateId, 
+  Ipv4Address advertisingRtr)
+:
+  m_lsType (GlobalRoutingLSA::Unknown),
+  m_linkStateId(linkStateId),
+  m_advertisingRtr(advertisingRtr),
+  m_linkRecords(),
+  m_networkLSANetworkMask("0.0.0.0"),
+  m_attachedRouters(),
+  m_status(status)
+{
+  NS_DEBUG("GlobalRoutingLSA::GlobalRoutingLSA (" << status << ", " <<
+    linkStateId << ", " << advertisingRtr << ")");
+}
+
+GlobalRoutingLSA::GlobalRoutingLSA (GlobalRoutingLSA& lsa)
+  : m_lsType(lsa.m_lsType), m_linkStateId(lsa.m_linkStateId), 
+    m_advertisingRtr(lsa.m_advertisingRtr), 
+    m_networkLSANetworkMask(lsa.m_networkLSANetworkMask), 
+    m_status(lsa.m_status)
+{
+  NS_ASSERT_MSG(IsEmpty(), 
+    "GlobalRoutingLSA::GlobalRoutingLSA (): Non-empty LSA in constructor");
+  CopyLinkRecords (lsa);
+}
+
+  GlobalRoutingLSA&
+GlobalRoutingLSA::operator= (const GlobalRoutingLSA& lsa)
+{
+  m_lsType = lsa.m_lsType;
+  m_linkStateId = lsa.m_linkStateId;
+  m_advertisingRtr = lsa.m_advertisingRtr;
+  m_networkLSANetworkMask = lsa.m_networkLSANetworkMask, 
+  m_status = lsa.m_status;
+
+  ClearLinkRecords ();
+  CopyLinkRecords (lsa);
+  return *this;
+}
+
+  void
+GlobalRoutingLSA::CopyLinkRecords (const GlobalRoutingLSA& lsa)
+{
+  for (ListOfLinkRecords_t::const_iterator i = lsa.m_linkRecords.begin ();
+       i != lsa.m_linkRecords.end (); 
+       i++)
+    {
+      GlobalRoutingLinkRecord *pSrc = *i;
+      GlobalRoutingLinkRecord *pDst = new GlobalRoutingLinkRecord;
+
+      pDst->SetLinkType (pSrc->GetLinkType ());
+      pDst->SetLinkId (pSrc->GetLinkId ());
+      pDst->SetLinkData (pSrc->GetLinkData ());
+
+      m_linkRecords.push_back(pDst);
+      pDst = 0;
+    }
+
+   m_attachedRouters = lsa.m_attachedRouters;
+}
+
+GlobalRoutingLSA::~GlobalRoutingLSA()
+{
+  NS_DEBUG("GlobalRoutingLSA::~GlobalRoutingLSA ()");
+  ClearLinkRecords ();
+}
+
+  void
+GlobalRoutingLSA::ClearLinkRecords(void)
+{
+  for ( ListOfLinkRecords_t::iterator i = m_linkRecords.begin ();
+        i != m_linkRecords.end (); 
+        i++)
+    {
+      NS_DEBUG("GlobalRoutingLSA::ClearLinkRecords ():  free link record");
+
+      GlobalRoutingLinkRecord *p = *i;
+      delete p;
+      p = 0;
+
+      *i = 0;
+    }
+  NS_DEBUG("GlobalRoutingLSA::ClearLinkRecords():  clear list");
+  m_linkRecords.clear();
+}
+
+  uint32_t
+GlobalRoutingLSA::AddLinkRecord (GlobalRoutingLinkRecord* lr)
+{
+  m_linkRecords.push_back (lr);
+  return m_linkRecords.size ();
+}
+
+  uint32_t
+GlobalRoutingLSA::GetNLinkRecords (void) const
+{
+  return m_linkRecords.size ();
+}
+
+  GlobalRoutingLinkRecord *
+GlobalRoutingLSA::GetLinkRecord (uint32_t n) const
+{
+  uint32_t j = 0;
+  for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin ();
+        i != m_linkRecords.end (); 
+        i++, j++)
+    {
+      if (j == n) 
+        {
+          return *i;
+        }
+    }
+  NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetLinkRecord (): invalid index");
+  return 0;
+}
+
+  bool
+GlobalRoutingLSA::IsEmpty (void) const
+{
+  return m_linkRecords.size () == 0;
+}
+
+  GlobalRoutingLSA::LSType
+GlobalRoutingLSA::GetLSType (void) const
+{
+  return m_lsType;
+}
+
+  void 
+GlobalRoutingLSA::SetLSType (GlobalRoutingLSA::LSType typ) 
+{
+  m_lsType = typ;
+}
+
+  Ipv4Address
+GlobalRoutingLSA::GetLinkStateId (void) const
+{
+  return m_linkStateId;
+}
+
+  void
+GlobalRoutingLSA::SetLinkStateId (Ipv4Address addr)
+{
+  m_linkStateId = addr;
+}
+
+  Ipv4Address
+GlobalRoutingLSA::GetAdvertisingRouter (void) const
+{
+  return m_advertisingRtr;
+}
+
+  void
+GlobalRoutingLSA::SetAdvertisingRouter (Ipv4Address addr)
+{
+  m_advertisingRtr = addr;
+}
+
+  void 
+GlobalRoutingLSA::SetNetworkLSANetworkMask (Ipv4Mask mask)
+{
+  m_networkLSANetworkMask = mask;
+}
+
+  Ipv4Mask 
+GlobalRoutingLSA::GetNetworkLSANetworkMask (void) const
+{
+  return m_networkLSANetworkMask;
+}
+
+  GlobalRoutingLSA::SPFStatus
+GlobalRoutingLSA::GetStatus (void) const
+{
+  return m_status;
+}
+
+  uint32_t 
+GlobalRoutingLSA::AddAttachedRouter (Ipv4Address addr)
+{
+  m_attachedRouters.push_back (addr);
+  return m_attachedRouters.size ();
+}
+
+  uint32_t 
+GlobalRoutingLSA::GetNAttachedRouters (void) const
+{
+  return m_attachedRouters.size (); 
+}
+
+  Ipv4Address 
+GlobalRoutingLSA::GetAttachedRouter (uint32_t n) const
+{
+  uint32_t j = 0;
+  for ( ListOfAttachedRouters_t::const_iterator i = m_attachedRouters.begin ();
+        i != m_attachedRouters.end (); 
+        i++, j++)
+    {
+      if (j == n) 
+        {
+          return *i;
+        }
+    }
+  NS_ASSERT_MSG(false, "GlobalRoutingLSA::GetAttachedRouter (): invalid index");
+  return Ipv4Address("0.0.0.0");
+}
+
+  void
+GlobalRoutingLSA::SetStatus (GlobalRoutingLSA::SPFStatus status)
+{
+  m_status = status;
+}
+
+  void 
+GlobalRoutingLSA::Print (std::ostream &os) const
+{
+  os << "m_lsType = " << m_lsType << std::endl <<
+        "m_linkStateId = " << m_linkStateId << std::endl <<
+        "m_advertisingRtr = " << m_advertisingRtr << std::endl;
+
+  if (m_lsType == GlobalRoutingLSA::RouterLSA) 
+    {
+      for ( ListOfLinkRecords_t::const_iterator i = m_linkRecords.begin ();
+            i != m_linkRecords.end (); 
+            i++)
+        {
+          GlobalRoutingLinkRecord *p = *i;
+          os << "----------" << std::endl;
+          os << "m_linkId = " << p->GetLinkId () << std::endl;
+          os << "m_linkData = " << p->GetLinkData () << std::endl;
+        }
+    }
+  else if (m_lsType == GlobalRoutingLSA::NetworkLSA) 
+    {
+      os << "----------" << std::endl;
+      os << "m_networkLSANetworkMask = " << m_networkLSANetworkMask 
+         << std::endl;
+      for ( ListOfAttachedRouters_t::const_iterator i = 
+            m_attachedRouters.begin ();
+            i != m_attachedRouters.end (); 
+            i++)
+        {
+          Ipv4Address p = *i;
+          os << "attachedRouter = " << p << std::endl;
+        }
+    }
+  else 
+    {
+      NS_ASSERT_MSG(0, "Illegal LSA LSType: " << m_lsType);
+    }
+}
+
+std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa)
+{
+  lsa.Print (os);
+  return os;
+}
+
+// ---------------------------------------------------------------------------
+//
+// GlobalRouter Implementation
+//
+// ---------------------------------------------------------------------------
+
+const InterfaceId GlobalRouter::iid = 
+  MakeInterfaceId ("GlobalRouter", Object::iid);
+
+GlobalRouter::GlobalRouter (Ptr<Node> node)
+  : m_node(node), m_LSAs()
+{
+  NS_DEBUG("GlobalRouter::GlobalRouter ()");
+  SetInterfaceId (GlobalRouter::iid);
+  m_routerId.Set(GlobalRouteManager::AllocateRouterId ());
+}
+
+GlobalRouter::~GlobalRouter ()
+{
+  NS_DEBUG("GlobalRouter::~GlobalRouter ()");
+  ClearLSAs();
+}
+
+void
+GlobalRouter::DoDispose ()
+{
+  m_node = 0;
+  Object::DoDispose ();
+}
+
+  void
+GlobalRouter::ClearLSAs ()
+{
+  NS_DEBUG("GlobalRouter::ClearLSAs ()");
+
+  for ( ListOfLSAs_t::iterator i = m_LSAs.begin ();
+        i != m_LSAs.end (); 
+        i++)
+    {
+      NS_DEBUG("GlobalRouter::ClearLSAs ():  free LSA");
+
+      GlobalRoutingLSA *p = *i;
+      delete p;
+      p = 0;
+
+      *i = 0;
+    }
+  NS_DEBUG("GlobalRouter::ClearLSAs ():  clear list");
+  m_LSAs.clear();
+}
+
+  Ipv4Address
+GlobalRouter::GetRouterId (void) const
+{
+  return m_routerId;
+}
+
+//
+// Go out and discover any adjacent routers and build the Link State 
+// Advertisements that reflect them and their associated networks.
+// 
+  uint32_t 
+GlobalRouter::DiscoverLSAs (void)
+{
+  NS_DEBUG("GlobalRouter::DiscoverLSAs () for node " << m_node->GetId () );
+  NS_ASSERT_MSG(m_node, 
+    "GlobalRouter::DiscoverLSAs (): <Node> interface not set");
+
+  ClearLSAs ();
+
+// While building the router-LSA, keep a list of those NetDevices for
+// which I am the designated router and need to later build a NetworkLSA
+  std::list<Ptr<NetDevice> > listOfDRInterfaces;
+
+//
+// We're aggregated to a node.  We need to ask the node for a pointer to its
+// Ipv4 interface.  This is where the information regarding the attached 
+// interfaces lives.
+//
+  Ptr<Ipv4> ipv4Local = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+  NS_ASSERT_MSG(ipv4Local, 
+    "GlobalRouter::DiscoverLSAs (): QI for <Ipv4> interface failed");
+//
+// Each node originates a Router-LSA
+//
+  GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
+  pLSA->SetLSType (GlobalRoutingLSA::RouterLSA);
+  pLSA->SetLinkStateId (m_routerId);
+  pLSA->SetAdvertisingRouter (m_routerId);
+  pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+//
+// We need to ask the node for the number of net devices attached. This isn't
+// necessarily equal to the number of links to adjacent nodes (other routers)
+// as the number of devices may include those for stub networks (e.g., 
+// ethernets, etc.).  
+//
+  uint32_t numDevices = m_node->GetNDevices();
+  NS_DEBUG("GlobalRouter::DiscoverLSAs (): numDevices = " << numDevices);
+  for (uint32_t i = 0; i < numDevices; ++i)
+    {
+      Ptr<NetDevice> ndLocal = m_node->GetDevice(i);
+
+      if (ndLocal->IsBroadcast () && !ndLocal->IsPointToPoint () )
+        {
+          NS_DEBUG("GlobalRouter::DiscoverLSAs (): broadcast link");
+          GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+//
+// We need to determine whether we are on a transit or stub network
+// If we find at least one more router on this channel, we are a transit
+//
+//
+// Now, we have to find the Ipv4 interface whose netdevice is the one we 
+// just found.  This is still the IP on the local side of the channel.  There 
+// is a function to do this used down in the guts of the stack, but it's not 
+// exported so we had to whip up an equivalent.
+//
+          uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+          Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+          Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+          NS_DEBUG("Working with local address " << addrLocal);
+//
+// Now, we're going to walk over to the remote net device on the other end of 
+// the point-to-point channel we now know we have.  This is where our adjacent 
+// router (to use OSPF lingo) is running.  
+//
+          Ptr<Channel> ch = ndLocal->GetChannel();
+          uint32_t nDevices = ch->GetNDevices();
+          if (nDevices == 1)
+            {
+              // This is a stub broadcast interface
+              NS_DEBUG("GlobalRouter::DiscoverLSAs (): Router-LSA stub broadcast link");
+              // XXX in future, need to consider if >1 includes other routers
+              plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+              // Link ID is IP network number of attached network
+              plr->SetLinkId (addrLocal.CombineMask(maskLocal));
+              // Link Data is network mask; convert to Ipv4Address
+              Ipv4Address maskLocalAddr;
+              maskLocalAddr.Set(maskLocal.GetHostOrder ());
+              plr->SetLinkData (maskLocalAddr);
+              // Cost is interface's configured output cost (NOTYET)
+              plr->SetMetric (1);
+              pLSA->AddLinkRecord(plr);
+              plr = 0;
+              continue;
+            }
+          else
+            {
+              NS_DEBUG("GlobalRouter::DiscoverLSAs (): Router-LSA Broadcast link");
+              // multiple routers on a broadcast interface
+              // lowest IP address is designated router
+              plr->SetLinkType (GlobalRoutingLinkRecord::TransitNetwork);
+              // Link ID is IP interface address of designated router
+              Ipv4Address desigRtr = 
+                FindDesignatedRouterForLink (m_node, ndLocal);
+              if (desigRtr == addrLocal) 
+                {
+                  listOfDRInterfaces.push_back (ndLocal);
+                  NS_DEBUG("GlobalRouter::DiscoverLSAs (): " << 
+                    m_node->GetId () << " is a DR");
+                }
+              plr->SetLinkId (desigRtr);
+              // Link Data is router's own IP address
+              plr->SetLinkData (addrLocal);
+              // Cost is interface's configured output cost (NOTYET)
+              plr->SetMetric (1);
+              pLSA->AddLinkRecord (plr);
+              plr = 0;
+              continue;
+            }
+        }
+      else if (ndLocal->IsPointToPoint () )
+        {
+          NS_DEBUG("GlobalRouter::DiscoverLSAs (): Router-LSA Point-to-point device");
+//
+// Now, we have to find the Ipv4 interface whose netdevice is the one we 
+// just found.  This is still the IP on the local side of the channel.  There 
+// is a function to do this used down in the guts of the stack, but it's not 
+// exported so we had to whip up an equivalent.
+//
+          uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+//
+// Now that we have the Ipv4 interface index, we can get the address and mask
+// we need.
+//
+          Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+          Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+          NS_DEBUG("Working with local address " << addrLocal);
+//
+// Now, we're going to walk over to the remote net device on the other end of 
+// the point-to-point channel we now know we have.  This is where our adjacent 
+// router (to use OSPF lingo) is running.  
+//
+          Ptr<Channel> ch = ndLocal->GetChannel();
+          Ptr<NetDevice> ndRemote = GetAdjacent(ndLocal, ch);
+//
+// The adjacent net device is aggregated to a node.  We need to ask that net 
+// device for its node, then ask that node for its Ipv4 interface.
+//
+          Ptr<Node> nodeRemote = ndRemote->GetNode();
+          Ptr<Ipv4> ipv4Remote = nodeRemote->QueryInterface<Ipv4> (Ipv4::iid);
+          NS_ASSERT_MSG(ipv4Remote, 
+            "GlobalRouter::DiscoverLSAs (): QI for remote <Ipv4> failed");
+//
+// Per the OSPF spec, we're going to need the remote router ID, so we might as
+// well get it now.
+//
+          Ptr<GlobalRouter> srRemote = 
+            nodeRemote->QueryInterface<GlobalRouter> (GlobalRouter::iid);
+          NS_ASSERT_MSG(srRemote, 
+            "GlobalRouter::DiscoverLSAs():QI for remote <GlobalRouter> failed");
+          Ipv4Address rtrIdRemote = srRemote->GetRouterId();
+          NS_DEBUG("Working with remote router " << rtrIdRemote);
+//
+// Now, just like we did above, we need to get the IP interface index for the 
+// net device on the other end of the point-to-point channel.
+//
+          uint32_t ifIndexRemote = FindIfIndexForDevice(nodeRemote, ndRemote);
+//
+// Now that we have the Ipv4 interface, we can get the (remote) address and
+// mask we need.
+//
+          Ipv4Address addrRemote = ipv4Remote->GetAddress(ifIndexRemote);
+          Ipv4Mask maskRemote = ipv4Remote->GetNetworkMask(ifIndexRemote);
+          NS_DEBUG("Working with remote address " << addrRemote);
+//
+// Now we can fill out the link records for this link.  There are always two
+// link records; the first is a point-to-point record describing the link and
+// the second is a stub network record with the network number.
+//
+          GlobalRoutingLinkRecord *plr = new GlobalRoutingLinkRecord;
+          plr->SetLinkType (GlobalRoutingLinkRecord::PointToPoint);
+          plr->SetLinkId (rtrIdRemote);
+          plr->SetLinkData (addrLocal);
+          pLSA->AddLinkRecord (plr);
+          plr = 0;
+
+          plr = new GlobalRoutingLinkRecord;
+          plr->SetLinkType (GlobalRoutingLinkRecord::StubNetwork);
+          plr->SetLinkId (addrRemote);
+          plr->SetLinkData (Ipv4Address(maskRemote.GetHostOrder()));  // Frown
+          pLSA->AddLinkRecord (plr);
+          plr = 0;
+        }
+      else
+        {
+          NS_ASSERT_MSG(0, "GlobalRouter::DiscoverLSAs (): unknown link type");
+        }
+
+    }
+//
+// The LSA goes on a list of LSAs in case we want to begin exporting other
+// kinds of advertisements (than Router LSAs).
+  m_LSAs.push_back (pLSA);
+  NS_DEBUG(*pLSA);
+
+
+// Now, determine whether we need to build a NetworkLSA
+  if (listOfDRInterfaces.size () > 0)
+    {
+      for (std::list<Ptr<NetDevice> >::iterator i = listOfDRInterfaces.begin ();
+        i != listOfDRInterfaces.end (); i++)
+        {
+// Build one NetworkLSA for each interface that is a DR
+          Ptr<NetDevice> ndLocal = *i;
+          uint32_t ifIndexLocal = FindIfIndexForDevice(m_node, ndLocal);
+          Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+          Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+
+          GlobalRoutingLSA *pLSA = new GlobalRoutingLSA;
+          pLSA->SetLSType (GlobalRoutingLSA::NetworkLSA);
+          pLSA->SetLinkStateId (addrLocal);
+          pLSA->SetAdvertisingRouter (m_routerId);
+          pLSA->SetNetworkLSANetworkMask (maskLocal);
+          pLSA->SetStatus (GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED);
+// Build list of AttachedRouters
+          Ptr<Channel> ch = ndLocal->GetChannel();
+          uint32_t nDevices = ch->GetNDevices();
+          NS_ASSERT (nDevices);
+          for (uint32_t i = 0; i < nDevices; i++)
+            {
+              Ptr<NetDevice> tempNd = ch->GetDevice (i);
+              NS_ASSERT (tempNd);
+              Ptr<Node> tempNode = tempNd->GetNode ();
+              uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
+              Ptr<Ipv4> tempIpv4 = tempNode->QueryInterface<Ipv4> (Ipv4::iid);
+              NS_ASSERT (tempIpv4);
+              Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
+              pLSA->AddAttachedRouter (tempAddr);
+            }
+          m_LSAs.push_back (pLSA);
+          NS_DEBUG(*pLSA);
+        }
+    }
+
+  return m_LSAs.size ();
+}
+
+  Ipv4Address
+GlobalRouter::FindDesignatedRouterForLink (Ptr<Node> node, 
+  Ptr<NetDevice> ndLocal) const
+{
+  uint32_t ifIndexLocal = FindIfIndexForDevice(node, ndLocal);
+  Ptr<Ipv4> ipv4Local = m_node->QueryInterface<Ipv4> (Ipv4::iid);
+  NS_ASSERT (ipv4Local);
+  Ipv4Address addrLocal = ipv4Local->GetAddress(ifIndexLocal);
+  Ipv4Mask maskLocal = ipv4Local->GetNetworkMask(ifIndexLocal);
+
+  Ptr<Channel> ch = ndLocal->GetChannel();
+  uint32_t nDevices = ch->GetNDevices();
+  NS_ASSERT (nDevices);
+  Ipv4Address lowest = addrLocal;
+  // iterate all NetDevices and return the lowest numbered IP address 
+  for (uint32_t i = 0; i < nDevices; i++)
+    {
+      Ptr<NetDevice> tempNd = ch->GetDevice (i);
+      NS_ASSERT (tempNd);
+      Ptr<Node> tempNode = tempNd->GetNode ();
+      uint32_t tempIfIndex = FindIfIndexForDevice (tempNode, tempNd);
+      Ptr<Ipv4> tempIpv4 = tempNode->QueryInterface<Ipv4> (Ipv4::iid);
+      NS_ASSERT (tempIpv4);
+      Ipv4Address tempAddr = tempIpv4->GetAddress(tempIfIndex);
+      if (tempAddr < addrLocal)
+        {
+          addrLocal = tempAddr;
+        }
+    }
+  return addrLocal;
+}
+
+  uint32_t 
+GlobalRouter::GetNumLSAs (void) const
+{
+  NS_DEBUG("GlobalRouter::GetNumLSAs ()");
+  return m_LSAs.size ();
+}
+
+//
+// Get the nth link state advertisement from this router.
+//
+  bool
+GlobalRouter::GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const
+{
+  NS_ASSERT_MSG(lsa.IsEmpty(), "GlobalRouter::GetLSA (): Must pass empty LSA");
+//
+// All of the work was done in GetNumLSAs.  All we have to do here is to
+// walk the list of link state advertisements created there and return the 
+// one the client is interested in.
+//
+  ListOfLSAs_t::const_iterator i = m_LSAs.begin ();
+  uint32_t j = 0;
+
+  for (; i != m_LSAs.end (); i++, j++)
+    {
+      if (j == n)
+        {
+          GlobalRoutingLSA *p = *i;
+          lsa = *p;
+          return true;
+        }
+    }
+
+  return false;
+}
+
+//
+// Link through the given channel and find the net device that's on the
+// other end.  This only makes sense with a point-to-point channel.
+//
+  Ptr<NetDevice>
+GlobalRouter::GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const
+{
+
+  NS_ASSERT_MSG(ch->GetNDevices() == 2, 
+    "GlobalRouter::GetAdjacent (): Channel with other than two devices");
+//
+// This is a point to point channel with two endpoints.  Get both of them.
+//
+  Ptr<NetDevice> nd1 = ch->GetDevice(0);
+  Ptr<NetDevice> nd2 = ch->GetDevice(1);
+//
+// One of the endpoints is going to be "us" -- that is the net device attached
+// to the node on which we're running -- i.e., "nd".  The other endpoint (the
+// one to which we are connected via the channel) is the adjacent router.
+//
+  if (nd1 == nd)
+    {
+      return nd2;
+    }
+  else if (nd2 == nd)
+    {
+      return nd1;
+    }
+  else
+    {
+      NS_ASSERT_MSG(false,
+        "GlobalRouter::GetAdjacent (): Wrong or confused channel?");
+      return 0;
+    }
+}
+
+//
+// Given a node and a net device, find the IPV4 interface index that 
+// corresponds to that net device.
+//
+  uint32_t
+GlobalRouter::FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const
+{
+  Ptr<Ipv4> ipv4 = node->QueryInterface<Ipv4> (Ipv4::iid);
+  NS_ASSERT_MSG(ipv4, "QI for <Ipv4> interface failed");
+  for (uint32_t i = 0; i < ipv4->GetNInterfaces(); ++i )
+    {
+      if (ipv4->GetNetDevice(i) == nd) 
+        {
+          return i;
+        }
+    }
+
+  NS_ASSERT_MSG(0, "Cannot find interface for device");
+  return 0;
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/global-router-interface.h	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,667 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+#ifndef GLOBAL_ROUTER_INTERFACE_H
+#define GLOBAL_ROUTER_INTERFACE_H
+
+#include <stdint.h>
+#include <list>
+#include "ns3/object.h"
+#include "ns3/ptr.h"
+#include "ns3/node.h"
+#include "ns3/channel.h"
+#include "ns3/ipv4-address.h"
+#include "ns3/global-route-manager.h"
+
+namespace ns3 {
+
+/**
+ * @brief A single link record for a link state advertisement.
+ *
+ * The GlobalRoutingLinkRecord is modeled after the OSPF link record field of
+ * a Link State Advertisement.  Right now we will only see two types of link
+ * records corresponding to a stub network and a point-to-point link (channel).
+ */
+class GlobalRoutingLinkRecord
+{
+public:
+/**
+ * @enum LinkType
+ * @brief Enumeration of the possible types of Global Routing Link Records.
+ *
+ * These values are defined in the OSPF spec.  We currently only use 
+ * PointToPoint and StubNetwork types.
+ */
+  enum LinkType {
+    Unknown = 0,        /**< Uninitialized Link Record */
+    PointToPoint,       /**< Record representing a point to point channel */
+    TransitNetwork,     /**< Unused -- for future OSPF compatibility  */
+    StubNetwork,        /**< Record represents a leaf node network */
+    VirtualLink         /**< Unused -- for future OSPF compatibility  */
+  };
+
+/**
+ * @brief Construct an empty ("uninitialized") Global Routing Link Record.
+ *
+ * The Link ID and Link Data Ipv4 addresses are set to "0.0.0.0";
+ * The Link Type is set to Unknown;
+ * The metric is set to 0.
+ */
+  GlobalRoutingLinkRecord ();
+
+/**
+ * Construct an initialized Global Routing Link Record.
+ *
+ * @param linkType The type of link record to construct.
+ * @param linkId The link ID for the record.
+ * @param linkData The link data field for the record.
+ * @param metric The metric field for the record.
+ * @see LinkType
+ * @see SetLinkId
+ * @see SetLinkData
+ */
+  GlobalRoutingLinkRecord (
+    LinkType    linkType, 
+    Ipv4Address linkId, 
+    Ipv4Address linkData, 
+    uint32_t    metric);
+
+/**
+ * @brief Destroy a Global Routing Link Record.
+ *
+ * Currently does nothing.  Here as a placeholder only.
+ */
+  ~GlobalRoutingLinkRecord ();
+
+/**
+ * Get the Link ID field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link ID will be the Router ID
+ * of the neighboring router.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link ID will be the adjacent
+ * neighbor's IP address
+ *
+ * @returns The Ipv4Address corresponding to the Link ID field of the record.
+ */
+  Ipv4Address GetLinkId(void) const;
+
+/**
+ * @brief Set the Link ID field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link ID must be the Router ID
+ * of the neighboring router.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link ID must be the adjacent
+ * neighbor's IP address
+ *
+ * @param addr An Ipv4Address to store in the Link ID field of the record.
+ */
+  void SetLinkId(Ipv4Address addr);
+
+/**
+ * @brief Get the Link Data field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link Data will be the IP
+ * address of the node of the local side of the link.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link Data will be the
+ * network mask
+ *
+ * @returns The Ipv4Address corresponding to the Link Data field of the record.
+ */
+  Ipv4Address GetLinkData(void) const;
+
+/**
+ * @brief Set the Link Data field of the Global Routing Link Record.
+ *
+ * For an OSPF type 1 link (PointToPoint) the Link Data must be the IP
+ * address of the node of the local side of the link.
+ *
+ * For an OSPF type 3 link (StubNetwork), the Link Data must be set to the
+ * network mask
+ *
+ * @param addr An Ipv4Address to store in the Link Data field of the record.
+ */
+  void SetLinkData(Ipv4Address addr);
+
+/**
+ * @brief Get the Link Type field of the Global Routing Link Record.
+ *
+ * The Link Type describes the kind of link a given record represents.  The
+ * values are defined by OSPF.
+ *
+ * @see LinkType
+ * @returns The LinkType of the current Global Routing Link Record.
+ */
+  LinkType GetLinkType(void) const;
+
+/**
+ * @brief Set the Link Type field of the Global Routing Link Record.
+ *
+ * The Link Type describes the kind of link a given record represents.  The
+ * values are defined by OSPF.
+ *
+ * @see LinkType
+ * @param linkType The new LinkType for the current Global Routing Link Record.
+ */
+  void SetLinkType(LinkType linkType);
+
+/**
+ * @brief Get the Metric Data field of the Global Routing Link Record.
+ *
+ * The metric is an abstract cost associated with forwarding a packet across
+ * a link.  A sum of metrics must have a well-defined meaning.  That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of
+ * two hops relate to the cost of sending a packet); rather you should use
+ * something like delay.
+ *
+ * @returns The metric field of the Global Routing Link Record.
+ */
+  uint32_t GetMetric(void) const;
+
+/**
+ * @brief Set the Metric Data field of the Global Routing Link Record.
+ *
+ * The metric is an abstract cost associated with forwarding a packet across
+ * a link.  A sum of metrics must have a well-defined meaning.  That is, you
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth of
+ * two hops relate to the cost of sending a packet); rather you should use
+ * something like delay.
+ *
+ * @param metric The new metric for the current Global Routing Link Record.
+ */
+  void SetMetric(uint32_t metric);
+
+private:
+/**
+ * m_linkId and m_linkData are defined by OSPF to have different meanings 
+ * depending on the type of link a given link records represents.  They work
+ * together.
+ *
+ * For Type 1 link (PointToPoint), set m_linkId to Router ID of 
+ * neighboring router.
+ *
+ * For Type 3 link (Stub), set m_linkId to neighbor's IP address
+ */
+  Ipv4Address m_linkId;         
+
+/**
+ * m_linkId and m_linkData are defined by OSPF to have different meanings 
+ * depending on the type of link a given link records represents.  They work
+ * together.
+ *
+ * For Type 1 link (PointToPoint), set m_linkData to local IP address  
+ *
+ * For Type 3 link (Stub), set m_linkData to mask
+ */
+  Ipv4Address m_linkData;    // for links to RouterLSA, 
+
+/**
+ * The type of the Global Routing Link Record.  Defined in the OSPF spec.  
+ * We currently only use PointToPoint and StubNetwork types.
+ */
+  LinkType m_linkType;
+
+/**
+ * The metric for a given link.
+ *
+ * A metric is abstract cost associated with forwarding a packet across a 
+ * link.  A sum of metrics must have a well-defined meaning.  That is, you 
+ * shouldn't use bandwidth as a metric (how does the sum of the bandwidth 
+ * of two hops relate to the cost of sending a packet); rather you should
+ * use something like delay.
+ */
+  uint32_t m_metric;  
+};
+
+/**  
+ * @brief a Link State Advertisement (LSA) for a router, used in global 
+ * routing.
+ * 
+ * Roughly equivalent to a global incarnation of the OSPF link state header
+ * combined with a list of Link Records.  Since it's global, there's
+ * no need for age or sequence number.  See RFC 2328, Appendix A.
+ */
+class GlobalRoutingLSA
+{
+public:
+/**
+ * @enum LSType
+ * @brief corresponds to LS type field of RFC 2328 OSPF LSA header
+ */
+  enum LSType {
+    Unknown = 0,        /**< Uninitialized Type */
+    RouterLSA,
+    NetworkLSA,
+    SummaryLSA,
+    SummaryLSA_ASBR,
+    ASExternalLSAs
+  };
+/**
+ * @enum SPFStatus
+ * @brief Enumeration of the possible values of the status flag in the Routing 
+ * Link State Advertisements.
+ */
+  enum SPFStatus {
+    LSA_SPF_NOT_EXPLORED = 0,	/**< New vertex not yet considered */
+    LSA_SPF_CANDIDATE,		/**< Vertex is in the SPF candidate queue */
+    LSA_SPF_IN_SPFTREE		/**< Vertex is in the SPF tree */
+  };
+/**
+ * @brief Create a blank Global Routing Link State Advertisement.  
+ *
+ * On completion Ipv4Address variables initialized to 0.0.0.0 and the 
+ * list of Link State Records is empty.
+ */
+  GlobalRoutingLSA();
+
+/**
+ * @brief Create an initialized Global Routing Link State Advertisement.  
+ *
+ * On completion the list of Link State Records is empty.
+ *
+ * @param status The status to of the new LSA.
+ * @param linkStateId The Ipv4Address for the link state ID field.
+ * @param advertisingRtr The Ipv4Address for the advertising router field.
+ */
+  GlobalRoutingLSA(SPFStatus status, Ipv4Address linkStateId, 
+    Ipv4Address advertisingRtr);
+
+/**
+ * @brief Copy constructor for a Global Routing Link State Advertisement.
+ *
+ * Takes a piece of memory and constructs a semantically identical copy of
+ * the given LSA.
+ *
+ * @param lsa The existing LSA to be used as the source.
+ */
+  GlobalRoutingLSA (GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Destroy an existing Global Routing Link State Advertisement.
+ *
+ * Any Global Routing Link Records present in the list are freed.
+ */
+  ~GlobalRoutingLSA();
+
+/**
+ * @brief Assignment operator for a Global Routing Link State Advertisement.
+ *
+ * Takes an existing Global Routing Link State Advertisement and overwrites
+ * it to make a semantically identical copy of a given prototype LSA.
+ *
+ * If there are any Global Routing Link Records present in the existing 
+ * LSA, they are freed before the assignment happens.
+ *
+ * @param lsa The existing LSA to be used as the source.
+ * @returns Reference to the overwritten LSA.
+ */
+  GlobalRoutingLSA& operator= (const GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Copy any Global Routing Link Records in a given Global Routing Link
+ * State Advertisement to the current LSA.  
+ * 
+ * Existing Link Records are not deleted -- this is a concatenation of Link 
+ * Records.
+ *
+ * @see ClearLinkRecords ()
+ * @param lsa The LSA to copy the Link Records from.
+ */
+  void CopyLinkRecords (const GlobalRoutingLSA& lsa);
+
+/**
+ * @brief Add a given Global Routing Link Record to the LSA.
+ *
+ * @param lr The Global Routing Link Record to be added.
+ * @returns The number of link records in the list.
+ */
+  uint32_t AddLinkRecord (GlobalRoutingLinkRecord* lr);
+
+/**
+ * @brief Return the number of Global Routing Link Records in the LSA.
+ *
+ * @returns The number of link records in the list.
+ */
+  uint32_t GetNLinkRecords (void) const;
+
+/**
+ * @brief Return a pointer to the specified Global Routing Link Record.
+ *
+ * @param n The LSA number desired.
+ * @returns The number of link records in the list.
+ */
+  GlobalRoutingLinkRecord* GetLinkRecord (uint32_t n) const;
+
+/**
+ * @brief Release all of the Global Routing Link Records present in the Global
+ * Routing Link State Advertisement and make the list of link records empty.
+ */
+  void ClearLinkRecords(void);
+
+/**
+ * @brief Check to see if the list of Global Routing Link Records present in the
+ * Global Routing Link State Advertisement is empty.
+ *
+ * @returns True if the list is empty, false otherwise.
+ */
+  bool IsEmpty(void) const;
+
+/**
+ * @brief Print the contents of the Global Routing Link State Advertisement and
+ * any Global Routing Link Records present in the list.  Quite verbose.
+ */
+  void Print (std::ostream &os) const;
+
+/**
+ * @brief Return the LSType field of the LSA 
+ */
+  LSType GetLSType (void) const;
+/**
+ * @brief Set the LS type field of the LSA
+ */
+  void SetLSType (LSType typ);
+
+/**
+ * @brief Get the Link State ID as defined by the OSPF spec.  We always set it
+ * to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ * @returns The Ipv4Address stored as the link state ID.
+ */
+  Ipv4Address GetLinkStateId (void) const;
+
+/**
+ * @brief Set the Link State ID is defined by the OSPF spec.  We always set it
+ * to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+  void SetLinkStateId (Ipv4Address addr);
+
+/**
+ * @brief Get the Advertising Router as defined by the OSPF spec.  We always
+ * set it to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ * @returns The Ipv4Address stored as the advetising router.
+ */
+  Ipv4Address GetAdvertisingRouter (void) const;
+
+/**
+ * @brief Set the Advertising Router as defined by the OSPF spec.  We always
+ * set it to the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+  void SetAdvertisingRouter (Ipv4Address  rtr);
+
+/**
+ * @brief For a Network LSA, set the Network Mask field that precedes
+ * the list of attached routers.
+ */
+  void SetNetworkLSANetworkMask (Ipv4Mask mask);
+
+/**
+ * @brief For a Network LSA, get the Network Mask field that precedes
+ * the list of attached routers.
+ * 
+ * @returns the NetworkLSANetworkMask 
+ */
+  Ipv4Mask GetNetworkLSANetworkMask (void) const;
+
+/**
+ * @brief Add an attached router to the list in the NetworkLSA
+ *
+ * @param addr The Ipv4Address of the interface on the network link
+ * @returns The number of addresses in the list.
+ */
+  uint32_t AddAttachedRouter (Ipv4Address addr);
+
+/**
+ * @brief Return the number of attached routers listed in the NetworkLSA
+ *
+ * @returns The number of attached routers.
+ */
+  uint32_t GetNAttachedRouters (void) const;
+
+/**
+ * @brief Return an Ipv4Address corresponding to the specified attached router
+ *
+ * @param n The attached router number desired (number in the list).
+ * @returns The Ipv4Address of the requested router
+ */
+  Ipv4Address GetAttachedRouter (uint32_t n) const;
+
+/**
+ * @brief Get the SPF status of the advertisement.
+ *
+ * @see SPFStatus
+ * @returns The SPFStatus of the LSA.
+ */
+  SPFStatus GetStatus (void) const;
+
+/**
+ * @brief Set the SPF status of the advertisement
+ *
+ * @see SPFStatus
+ */
+  void SetStatus (SPFStatus status);
+
+private:
+/**
+ * The type of the LSA.  Each LSA type has a separate advertisement
+ * format.
+ */
+  LSType m_lsType;
+/**
+ * The Link State ID is defined by the OSPF spec.  We always set it to the
+ * router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+  Ipv4Address  m_linkStateId;
+
+/**
+ * The Advertising Router is defined by the OSPF spec.  We always set it to 
+ * the router ID of the router making the advertisement.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @see GlobalRouting::GetRouterId ()
+ */
+  Ipv4Address  m_advertisingRtr;
+
+/**
+ * A convenience typedef to avoid too much writers cramp.
+ */
+  typedef std::list<GlobalRoutingLinkRecord*> ListOfLinkRecords_t;
+
+/**
+ * Each Link State Advertisement contains a number of Link Records that
+ * describe the kinds of links that are attached to a given node.  We 
+ * consider PointToPoint and StubNetwork links.
+ *
+ * m_linkRecords is an STL list container to hold the Link Records that have
+ * been discovered and prepared for the advertisement.
+ *
+ * @see GlobalRouting::DiscoverLSAs ()
+ */
+  ListOfLinkRecords_t m_linkRecords;
+
+/**
+ * Each Network LSA contains the network mask of the attached network
+ */
+  Ipv4Mask m_networkLSANetworkMask;
+
+/**
+ * A convenience typedef to avoid too much writers cramp.
+ */
+  typedef std::list<Ipv4Address> ListOfAttachedRouters_t;
+
+/**
+ * Each Network LSA contains a list of attached routers
+ *
+ * m_attachedRouters is an STL list container to hold the addresses that have
+ * been discovered and prepared for the advertisement.
+ *
+ * @see GlobalRouting::DiscoverLSAs ()
+ */
+  ListOfAttachedRouters_t m_attachedRouters;
+
+/**
+ * This is a tristate flag used internally in the SPF computation to mark
+ * if an SPFVertex (a data structure representing a vertex in the SPF tree
+ * -- a router) is new, is a candidate for a shortest path, or is in its
+ * proper position in the tree.
+ */
+  SPFStatus m_status;
+};
+
+std::ostream& operator<< (std::ostream& os, GlobalRoutingLSA& lsa);
+
+/**
+ * @brief An interface aggregated to a node to provide global routing info
+ *
+ * An interface aggregated to a node that provides global routing information
+ * to a global route manager.  The presence of the interface indicates that
+ * the node is a router.  The interface is the mechanism by which the router
+ * advertises its connections to neighboring routers.  We're basically 
+ * allowing the route manager to query for link state advertisements.
+ */
+class GlobalRouter : public Object
+{
+public:
+/**
+ * @brief The Interface ID of the Global Router interface.
+ *
+ * @see Object::QueryInterface ()
+ */
+  static const InterfaceId iid;
+
+/**
+ * @brief Create a Global Router class and aggregate its interface onto the 
+ * Node provided.
+ *
+ * @param node The existing Node onto which this router will be aggregated.
+ */
+  GlobalRouter (Ptr<Node> node);
+
+/**
+ * @brief Get the Router ID associated with this Global Router.
+ *
+ * The Router IDs are allocated in the RoutingEnvironment -- one per Router, 
+ * starting at 0.0.0.1 and incrementing with each instantiation of a router.
+ *
+ * @see RoutingEnvironment::AllocateRouterId ()
+ * @returns The Router ID associated with the Global Router.
+ */
+  Ipv4Address GetRouterId (void) const;
+
+/**
+ * @brief Walk the connected channels, discover the adjacent routers and build
+ * the associated number of Global Routing Link State Advertisements that 
+ * this router can export.
+ *
+ * This is a fairly expensive operation in that every time it is called
+ * the current list of LSAs is built by walking connected point-to-point
+ * channels and peeking into adjacent IPV4 stacks to get address information.
+ * This is done to allow for limited dymanics of the Global Routing 
+ * environment.  By that we mean that you can discover new link state 
+ * advertisements after a network topology change by calling DiscoverLSAs 
+ * and then by reading those advertisements.
+ *
+ * @see GlobalRoutingLSA
+ * @see GlobalRouter::GetLSA ()
+ * @returns The number of Global Routing Link State Advertisements.
+ */
+  uint32_t DiscoverLSAs (void);
+
+/**
+ * @brief Get the Number of Global Routing Link State Advertisements that this
+ * router can export.
+ *
+ * To get meaningful information you must have previously called DiscoverLSAs.
+ * After you know how many LSAs are present in the router, you may call 
+ * GetLSA () to retrieve the actual advertisement.
+ *
+ * @see GlobalRouterLSA
+ * @see GlobalRouting::DiscoverLSAs ()
+ * @see GlobalRouting::GetLSA ()
+ * @returns The number of Global Routing Link State Advertisements.
+ */
+  uint32_t GetNumLSAs (void) const;
+
+/**
+ * @brief Get a Global Routing Link State Advertisements that this router has 
+ * said that it can export.
+ *
+ * This is a fairly inexpensive expensive operation in that the hard work
+ * was done in GetNumLSAs.  We just copy the indicated Global Routing Link
+ * State Advertisement into the requested GlobalRoutingLSA object.
+ *
+ * You must call GlobalRouter::GetNumLSAs before calling this method in 
+ * order to discover the adjacent routers and build the advertisements.
+ * GetNumLSAs will return the number of LSAs this router advertises.  
+ * The parameter n (requested LSA number) must be in the range 0 to 
+ * GetNumLSAs() - 1.
+ *
+ * @see GlobalRoutingLSA
+ * @see GlobalRouting::GetNumLSAs ()
+ * @param n The index number of the LSA you want to read.
+ * @param lsa The GlobalRoutingLSA class to receive the LSA information.
+ * @returns The number of Global Router Link State Advertisements.
+ */
+  bool GetLSA (uint32_t n, GlobalRoutingLSA &lsa) const;
+
+private:
+  virtual ~GlobalRouter ();
+  void ClearLSAs (void);
+
+  Ptr<NetDevice> GetAdjacent(Ptr<NetDevice> nd, Ptr<Channel> ch) const;
+  uint32_t FindIfIndexForDevice(Ptr<Node> node, Ptr<NetDevice> nd) const;
+  Ipv4Address FindDesignatedRouterForLink (Ptr<Node> node,   
+    Ptr<NetDevice> ndLocal) const;
+
+  Ptr<Node>     m_node;
+
+  typedef std::list<GlobalRoutingLSA*> ListOfLSAs_t;
+  ListOfLSAs_t m_LSAs;
+
+  Ipv4Address m_routerId;
+
+  // inherited from Object
+  virtual void DoDispose (void);
+
+/**
+ * @brief Global Router copy construction is disallowed.
+ */
+  GlobalRouter (GlobalRouter& sr);
+
+/**
+ * @brief Global Router assignment operator is disallowed.
+ */
+  GlobalRouter& operator= (GlobalRouter& sr);
+};
+
+} // namespace ns3
+
+#endif /* GLOBAL_ROUTER_INTERFACE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/routing/global-routing/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,17 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def build(bld):
+    module = bld.create_ns3_module('global-routing', ['node'])
+    module.source = [
+        'global-router-interface.cc',
+        'global-route-manager.cc',
+        'global-route-manager-impl.cc',
+        'candidate-queue.cc',
+        ]
+    headers = bld.create_obj('ns3header')
+    headers.source = [
+        'global-router-interface.h',
+        'global-route-manager.h',
+        'candidate-queue.h',
+        ]
+
--- a/src/simulator/event-id.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/event-id.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -30,7 +30,7 @@
     m_uid (0)
 {}
   
-EventId::EventId (EventImpl *impl, uint64_t ts, uint32_t uid)
+EventId::EventId (const Ptr<EventImpl> &impl, uint64_t ts, uint32_t uid)
   : m_eventImpl (impl),
     m_ts (ts),
     m_uid (uid)
@@ -38,11 +38,7 @@
 void 
 EventId::Cancel (void)
 {
-  if (!IsExpired ())
-    {
-      m_eventImpl->Cancel ();
-      m_eventImpl = 0;
-    }
+  Simulator::Cancel (*this);
 }
 bool 
 EventId::IsExpired (void) const
@@ -55,9 +51,9 @@
   return !IsExpired ();
 }
 EventImpl *
-EventId::GetEventImpl (void) const
+EventId::PeekEventImpl (void) const
 {
-  return m_eventImpl;
+  return PeekPointer (m_eventImpl);
 }
 uint64_t 
 EventId::GetTs (void) const
--- a/src/simulator/event-id.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/event-id.h	Wed Sep 05 18:35:39 2007 +0100
@@ -22,6 +22,8 @@
 #define EVENT_ID_H
 
 #include <stdint.h>
+#include "ns3/ptr.h"
+#include "event-impl.h"
 
 namespace ns3 {
 
@@ -33,7 +35,7 @@
 class EventId {
 public:
   EventId ();
-  EventId (EventImpl *impl, uint64_t ts, uint32_t uid);
+  EventId (const Ptr<EventImpl> &impl, uint64_t ts, uint32_t uid);
   /**
    * This method is syntactic sugar for the ns3::Simulator::cancel
    * method.
@@ -51,12 +53,12 @@
    * they are supposed to be invoked only by
    * subclasses of the Scheduler base class.
    */
-  EventImpl *GetEventImpl (void) const;
+  EventImpl *PeekEventImpl (void) const;
   uint64_t GetTs (void) const;
   uint32_t GetUid (void) const;
 private:
   friend bool operator == (const EventId &a, const EventId &b);
-  EventImpl *m_eventImpl;
+  Ptr<EventImpl> m_eventImpl;
   uint64_t m_ts;
   uint32_t m_uid;
 };
--- a/src/simulator/event-impl.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/event-impl.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -29,7 +29,8 @@
 {}
 
 EventImpl::EventImpl ()
-  : m_cancel (false)
+  : m_cancel (false),
+    m_count (1)
 {}
 void 
 EventImpl::Invoke (void)
--- a/src/simulator/event-impl.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/event-impl.h	Wed Sep 05 18:35:39 2007 +0100
@@ -28,6 +28,8 @@
 class EventImpl {
 public:
   EventImpl ();
+  inline void Ref (void) const;
+  inline void Unref (void) const;
   virtual ~EventImpl () = 0;
   void Invoke (void);
   void Cancel (void);
@@ -37,8 +39,28 @@
 private:
   friend class Event;
   bool m_cancel;
+  mutable uint32_t m_count;
 };
 
 }; // namespace ns3
 
+namespace ns3 {
+
+void
+EventImpl::Ref (void) const
+{
+  m_count++;
+}
+void
+EventImpl::Unref (void) const
+{
+  m_count--;
+  if (m_count == 0)
+    {
+      delete this;
+    }
+}
+
+} // namespace ns3
+
 #endif /* EVENT_IMPL_H */
--- a/src/simulator/high-precision-128.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/high-precision-128.h	Wed Sep 05 18:35:39 2007 +0100
@@ -222,7 +222,9 @@
       HP128INC (m_nslowcmps);
       return SlowCompare (o);
     }
-
+  // The below statement is unreachable but necessary for optimized
+  // builds with gcc-4.0.x due to a compiler bug.
+  return 0;  
 }
 HighPrecision 
 HighPrecision::Zero (void)
--- a/src/simulator/scheduler-heap.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-heap.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -170,7 +170,7 @@
 }
 
 bool
-SchedulerHeap::RealIsEmpty (void) const
+SchedulerHeap::IsEmpty (void) const
 {
   return (m_heap.size () == 1)?true:false;
 }
@@ -223,9 +223,11 @@
 
 
 void
-SchedulerHeap::RealInsert (EventId id)
+SchedulerHeap::Insert (const EventId &id)
 {
-  EventImpl *event = id.GetEventImpl ();
+  // acquire single ref
+  EventImpl *event = id.PeekEventImpl ();
+  event->Ref ();
   Scheduler::EventKey key;
   key.m_ts = id.GetTs ();
   key.m_uid = id.GetUid ();
@@ -234,29 +236,34 @@
 }
 
 EventId
-SchedulerHeap::RealPeekNext (void) const
+SchedulerHeap::PeekNext (void) const
 {
   std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[Root ()];
   return EventId (next.first, next.second.m_ts, next.second.m_uid);
 }
-void     
-SchedulerHeap::RealRemoveNext (void)
+EventId
+SchedulerHeap::RemoveNext (void)
 {
+  std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[Root ()];
   Exch (Root (), Last ());
   m_heap.pop_back ();
   TopDown (Root ());
+  return EventId (Ptr<EventImpl> (next.first, false), next.second.m_ts, next.second.m_uid);
 }
 
 
 bool
-SchedulerHeap::RealRemove (EventId id)
+SchedulerHeap::Remove (const EventId &id)
 {
   uint32_t uid = id.GetUid ();
   for (uint32_t i = 1; i < m_heap.size (); i++)
     {
       if (uid == m_heap[i].second.m_uid)
         {
-          NS_ASSERT (m_heap[i].first == id.GetEventImpl ());
+          NS_ASSERT (m_heap[i].first == id.PeekEventImpl ());
+          std::pair<EventImpl *,Scheduler::EventKey> next = m_heap[i];
+          // release single ref
+          next.first->Unref ();
           Exch (i, Last ());
           m_heap.pop_back ();
           TopDown (i);
--- a/src/simulator/scheduler-heap.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-heap.h	Wed Sep 05 18:35:39 2007 +0100
@@ -35,13 +35,13 @@
   SchedulerHeap ();
   virtual ~SchedulerHeap ();
 
+  virtual void Insert (const EventId &id);
+  virtual bool IsEmpty (void) const;
+  virtual EventId PeekNext (void) const;
+  virtual EventId RemoveNext (void);
+  virtual bool Remove (const EventId &ev);
+
 private:
-  virtual void RealInsert (EventId id);
-  virtual bool RealIsEmpty (void) const;
-  virtual EventId RealPeekNext (void) const;
-  virtual void RealRemoveNext (void);
-  virtual bool RealRemove (EventId ev);
-
   typedef std::vector<std::pair<EventImpl *, Scheduler::EventKey> > BinaryHeap;
 
   inline uint32_t Parent (uint32_t id) const;
--- a/src/simulator/scheduler-list.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-list.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -67,10 +67,12 @@
 }
 
 void
-SchedulerList::RealInsert (EventId id)
+SchedulerList::Insert (const EventId &id)
 {
   Scheduler::EventKey key;
-  EventImpl *event = id.GetEventImpl ();
+  // acquire refcount on EventImpl
+  EventImpl *event = id.PeekEventImpl ();
+  event->Ref ();
   key.m_ts = id.GetTs ();
   key.m_uid = id.GetUid ();
   for (EventsI i = m_events.begin (); i != m_events.end (); i++) 
@@ -84,31 +86,35 @@
   m_events.push_back (std::make_pair (event, key));
 }
 bool 
-SchedulerList::RealIsEmpty (void) const
+SchedulerList::IsEmpty (void) const
 {
   return m_events.empty ();
 }
 EventId
-SchedulerList::RealPeekNext (void) const
+SchedulerList::PeekNext (void) const
 {
   std::pair<EventImpl *, EventKey> next = m_events.front ();
   return EventId (next.first, next.second.m_ts, next.second.m_uid);
 }
 
-void
-SchedulerList::RealRemoveNext (void)
+EventId
+SchedulerList::RemoveNext (void)
 {
+  std::pair<EventImpl *, EventKey> next = m_events.front ();
   m_events.pop_front ();
+  return EventId (Ptr<EventImpl> (next.first,false), next.second.m_ts, next.second.m_uid);
 }
 
 bool
-SchedulerList::RealRemove (EventId id)
+SchedulerList::Remove (const EventId &id)
 {
   for (EventsI i = m_events.begin (); i != m_events.end (); i++) 
     {
       if (i->second.m_uid == id.GetUid ())
         {
-          NS_ASSERT (id.GetEventImpl () == i->first);
+          NS_ASSERT (id.PeekEventImpl () == i->first);
+          // release single acquire ref.
+          i->first->Unref ();
           m_events.erase (i);
           return true;
         }
--- a/src/simulator/scheduler-list.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-list.h	Wed Sep 05 18:35:39 2007 +0100
@@ -37,13 +37,13 @@
   SchedulerList ();
   virtual ~SchedulerList ();
 
+  virtual void Insert (const EventId &id);
+  virtual bool IsEmpty (void) const;
+  virtual EventId PeekNext (void) const;
+  virtual EventId RemoveNext (void);
+  virtual bool Remove (const EventId &ev);
+
  private:
-  virtual void RealInsert (EventId id);
-  virtual bool RealIsEmpty (void) const;
-  virtual EventId RealPeekNext (void) const;
-  virtual void RealRemoveNext (void);
-  virtual bool RealRemove (EventId ev);
-
   inline bool IsLower (Scheduler::EventKey const*a, Scheduler::EventKey const*b) const;
 
   typedef std::list<std::pair<EventImpl*, EventKey> > Events;
--- a/src/simulator/scheduler-map.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-map.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -88,9 +88,11 @@
 
 
 void
-SchedulerMap::RealInsert (EventId id)
+SchedulerMap::Insert (const EventId &id)
 {
-  EventImpl *event = id.GetEventImpl ();
+  // acquire a single ref
+  EventImpl *event = id.PeekEventImpl ();
+  event->Ref ();
   Scheduler::EventKey key;
   key.m_ts = id.GetTs ();
   key.m_uid = id.GetUid ();
@@ -100,33 +102,38 @@
 }
 
 bool
-SchedulerMap::RealIsEmpty (void) const
+SchedulerMap::IsEmpty (void) const
 {
   return m_list.empty ();
 }
 
 EventId
-SchedulerMap::RealPeekNext (void) const
+SchedulerMap::PeekNext (void) const
 {
   EventMapCI i = m_list.begin ();
   NS_ASSERT (i != m_list.end ());
   
   return EventId (i->second, i->first.m_ts, i->first.m_uid);
 }
-void
-SchedulerMap::RealRemoveNext (void)
+EventId
+SchedulerMap::RemoveNext (void)
 {
-  m_list.erase (m_list.begin ());
+  EventMapI i = m_list.begin ();
+  std::pair<Scheduler::EventKey, EventImpl*> next = *i;
+  m_list.erase (i);
+  return EventId (Ptr<EventImpl> (next.second, false), next.first.m_ts, next.first.m_uid);
 }
 
 bool
-SchedulerMap::RealRemove (EventId id)
+SchedulerMap::Remove (const EventId &id)
 {
   Scheduler::EventKey key;
   key.m_ts = id.GetTs ();
   key.m_uid = id.GetUid ();
   EventMapI i = m_list.find (key);
-  NS_ASSERT (i->second == id.GetEventImpl ());
+  NS_ASSERT (i->second == id.PeekEventImpl ());
+  // release single ref.
+  i->second->Unref ();
   m_list.erase (i);
   return true;
 }
--- a/src/simulator/scheduler-map.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler-map.h	Wed Sep 05 18:35:39 2007 +0100
@@ -36,12 +36,12 @@
   SchedulerMap ();
   virtual ~SchedulerMap ();
 
+  virtual void Insert (const EventId &id);
+  virtual bool IsEmpty (void) const;
+  virtual EventId PeekNext (void) const;
+  virtual EventId RemoveNext (void);
+  virtual bool Remove (const EventId &ev);
 private:
-  virtual void RealInsert (EventId id);
-  virtual bool RealIsEmpty (void) const;
-  virtual EventId RealPeekNext (void) const;
-  virtual void RealRemoveNext (void);
-  virtual bool RealRemove (EventId ev);
 
   class EventKeyCompare {
   public:
--- a/src/simulator/scheduler.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -27,33 +27,4 @@
 Scheduler::~Scheduler () 
 {}
 
-void
-Scheduler::Insert (EventId id)
-{
-  return RealInsert (id);
-}
-bool 
-Scheduler::IsEmpty (void) const
-{
-  return RealIsEmpty ();
-}
-EventId
-Scheduler::PeekNext (void) const
-{
-  NS_ASSERT (!RealIsEmpty ());
-  return RealPeekNext ();
-}
-void 
-Scheduler::RemoveNext (void)
-{
-  NS_ASSERT (!RealIsEmpty ());
-  return RealRemoveNext ();
-}
-bool
-Scheduler::Remove (EventId id)
-{
-  NS_ASSERT (!RealIsEmpty ());
-  return RealRemove (id);
-}
-
 }; // namespace ns3
--- a/src/simulator/scheduler.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/scheduler.h	Wed Sep 05 18:35:39 2007 +0100
@@ -27,21 +27,18 @@
 
 namespace ns3 {
 
-class EventImpl;
-
 /**
  * \brief Maintain the event list
  *
  * This base class specifies the interface used to maintain the 
  * event list. If you want to provide a new event list scheduler, 
  * you need to create a subclass of this base class and implement 
- * all the private pure virtual methods defined here. Namely:
- *   - ns3::Scheduler::realInsert
- *   - ns3::Scheduler::realIsEmpty
- *   - ns3::Scheduler::realPeekNext
- *   - ns3::Scheduler::realPeekNextKey
- *   - ns3::Scheduler::realRemoveNext
- *   - ns3::Scheduler::realRemove
+ * all the pure virtual methods defined here. Namely:
+ *   - ns3::Scheduler::Insert
+ *   - ns3::Scheduler::IsEmpty
+ *   - ns3::Scheduler::PeekNext
+ *   - ns3::Scheduler::RemoveNext
+ *   - ns3::Scheduler::Remove
  *
  * If you need to provide a new event list scheduler without
  * editing the main simulator class, you need to also implement
@@ -60,46 +57,36 @@
 
   virtual ~Scheduler () = 0;
 
-  void Insert (EventId id);
-  bool IsEmpty (void) const;
-  EventId PeekNext (void) const;
-  void RemoveNext (void);
-  bool Remove (EventId);
-
-private:
   /**
-   * \param event event to store in the event list
-   * \param key timecode associated to this new event
-   * \returns an event id which identifies the event inserted
+   * \param id event to store in the event list
    *
    * This method takes ownership of the event pointer.
    */
-  virtual void RealInsert (EventId id) = 0;
+  virtual void Insert (const EventId &id) = 0;
   /**
    * \returns true if the event list is empty and false otherwise.
    */
-  virtual bool RealIsEmpty (void) const = 0;
+  virtual bool IsEmpty (void) const = 0;
   /**
    * \returns a pointer to the next earliest event. The caller
    *      takes ownership of the returned pointer.
    *
    * This method cannot be invoked if the list is empty.
    */
-  virtual EventId RealPeekNext (void) const = 0;
+  virtual EventId PeekNext (void) const = 0;
   /**
    * This method cannot be invoked if the list is empty.
    * Remove the next earliest event from the event list.
    */
-  virtual void RealRemoveNext (void) = 0;
+  virtual EventId RemoveNext (void) = 0;
   /**
    * \param id the id of the event to remove
-   * \param key the timecode of the event removed
-   * \returns a pointer to the event removed. The caller
-   *      takes ownership of the returned pointer.
+   * \returns true if the id was found and removed 
+   *          successfully, false otherwise.
    *
    * This methods cannot be invoked if the list is empty.
    */
-  virtual bool RealRemove (EventId id) = 0;
+  virtual bool Remove (const EventId &id) = 0;
 };
 
 }; // namespace ns3
--- a/src/simulator/simulator.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/simulator.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -23,6 +23,7 @@
 #include "scheduler.h"
 #include "event-impl.h"
 
+#include "ns3/ptr.h"
 #include "ns3/assert.h"
 #include "ns3/default-value.h"
 
@@ -61,12 +62,12 @@
   Time Next (void) const;
   void Stop (void);
   void StopAt (Time const &time);
-  EventId Schedule (Time const &time, EventImpl *event);
-  EventId ScheduleNow (EventImpl *event);
-  EventId ScheduleDestroy (EventImpl *event);
-  void Remove (EventId ev);
-  void Cancel (EventId &ev);
-  bool IsExpired (EventId ev);
+  EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
+  EventId ScheduleNow (const Ptr<EventImpl> &event);
+  EventId ScheduleDestroy (const Ptr<EventImpl> &event);
+  void Remove (const EventId &ev);
+  void Cancel (const EventId &ev);
+  bool IsExpired (const EventId &ev);
   void Run (void);
   Time Now (void) const;
 
@@ -114,13 +115,12 @@
 {
   while (!m_destroyEvents.empty ()) 
     {
-      EventImpl *ev = m_destroyEvents.front ().GetEventImpl ();
+      Ptr<EventImpl> ev = m_destroyEvents.front ().PeekEventImpl ();
       m_destroyEvents.pop_front ();
       TRACE ("handle destroy " << ev);
       if (!ev->IsCancelled ())
         {
           ev->Invoke ();
-          delete ev;
         }
     }
   delete m_events;
@@ -138,8 +138,7 @@
 void
 SimulatorPrivate::ProcessOneEvent (void)
 {
-  EventId next = m_events->PeekNext ();
-  m_events->RemoveNext ();
+  EventId next = m_events->RemoveNext ();
 
   NS_ASSERT (next.GetTs () >= m_currentTs);
   --m_unscheduledEvents;
@@ -151,9 +150,8 @@
     {
       m_log << "e "<<next.GetUid () << " " << next.GetTs () << std::endl;
     }
-  EventImpl *event = next.GetEventImpl ();
+  EventImpl *event = next.PeekEventImpl ();
   event->Invoke ();
-  delete event;
 }
 
 bool 
@@ -204,7 +202,7 @@
   m_stopAt = at.GetTimeStep ();
 }
 EventId
-SimulatorPrivate::Schedule (Time const &time, EventImpl *event)
+SimulatorPrivate::Schedule (Time const &time, const Ptr<EventImpl> &event)
 {
   NS_ASSERT (time.IsPositive ());
   NS_ASSERT (time >= TimeStep (m_currentTs));
@@ -221,7 +219,7 @@
   return id;
 }
 EventId
-SimulatorPrivate::ScheduleNow (EventImpl *event)
+SimulatorPrivate::ScheduleNow (const Ptr<EventImpl> &event)
 {
   EventId id (event, m_currentTs, m_uid);
   if (m_logEnable) 
@@ -235,7 +233,7 @@
   return id;
 }
 EventId
-SimulatorPrivate::ScheduleDestroy (EventImpl *event)
+SimulatorPrivate::ScheduleDestroy (const Ptr<EventImpl> &event)
 {
   EventId id (event, m_currentTs, 2);
   m_destroyEvents.push_back (id);
@@ -255,7 +253,7 @@
 }
 
 void
-SimulatorPrivate::Remove (EventId ev)
+SimulatorPrivate::Remove (const EventId &ev)
 {
   if (ev.GetUid () == 2)
     {
@@ -275,7 +273,7 @@
       return;
     }
   m_events->Remove (ev);
-  delete ev.GetEventImpl ();
+  Cancel (ev);
 
   if (m_logEnable) 
     {
@@ -286,13 +284,16 @@
 }
 
 void
-SimulatorPrivate::Cancel (EventId &id)
+SimulatorPrivate::Cancel (const EventId &id)
 {
-  id.Cancel ();
+  if (!IsExpired (id))
+    {
+      id.PeekEventImpl ()->Cancel ();
+    }
 }
 
 bool
-SimulatorPrivate::IsExpired (const EventId ev)
+SimulatorPrivate::IsExpired (const EventId &ev)
 {
   if (ev.GetUid () == 2)
     {
@@ -306,11 +307,11 @@
          }
       return true;
     }
-  if (ev.GetEventImpl () == 0 ||
+  if (ev.PeekEventImpl () == 0 ||
       ev.GetTs () < m_currentTs ||
       (ev.GetTs () == m_currentTs &&
        ev.GetUid () <= m_currentUid) ||
-      ev.GetEventImpl ()->IsCancelled ()) 
+      ev.PeekEventImpl ()->IsCancelled ()) 
     {
       return true;
     }
@@ -336,20 +337,20 @@
 
 void Simulator::SetLinkedList (void)
 {
-  Bind ("Scheduler", "List");
+  DefaultValue::Bind ("Scheduler", "List");
 }
 void Simulator::SetBinaryHeap (void)
 {
-  Bind ("Scheduler", "BinaryHeap");
+  DefaultValue::Bind ("Scheduler", "BinaryHeap");
 }
 void Simulator::SetStdMap (void)
 {
-  Bind ("Scheduler", "Map");
+  DefaultValue::Bind ("Scheduler", "Map");
 }
 void 
 Simulator::SetExternal (const std::string &external)
 {
-  Bind ("Scheduler", external);
+  DefaultValue::Bind ("Scheduler", external);
 }
 void Simulator::EnableLogTo (char const *filename)
 {
@@ -411,39 +412,39 @@
   return GetPriv ()->Now ();
 }
 
-EventImpl *
+Ptr<EventImpl>
 Simulator::MakeEvent (void (*f) (void))
 {
     // zero arg version
   class EventFunctionImpl0 : public EventImpl {
   public:
-  	typedef void (*F)(void);
+    typedef void (*F)(void);
       
-  	EventFunctionImpl0 (F function) 
-  		: m_function (function)
-  	{}
-  	virtual ~EventFunctionImpl0 () {}
+    EventFunctionImpl0 (F function) 
+      : m_function (function)
+    {}
+    virtual ~EventFunctionImpl0 () {}
   protected:
-  	virtual void Notify (void) { 
-  		(*m_function) (); 
-      }
+    virtual void Notify (void) { 
+      (*m_function) (); 
+    }
   private:
   	F m_function;
   } *ev = new EventFunctionImpl0 (f);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 EventId
-Simulator::Schedule (Time const &time, EventImpl *ev)
+Simulator::Schedule (Time const &time, const Ptr<EventImpl> &ev)
 {
   return GetPriv ()->Schedule (Now () + time, ev);
 }
 EventId
-Simulator::ScheduleNow (EventImpl *ev)
+Simulator::ScheduleNow (const Ptr<EventImpl> &ev)
 {
   return GetPriv ()->ScheduleNow (ev);
 }
 EventId
-Simulator::ScheduleDestroy (EventImpl *ev)
+Simulator::ScheduleDestroy (const Ptr<EventImpl> &ev)
 {
   return GetPriv ()->ScheduleDestroy (ev);
 }  
@@ -465,18 +466,18 @@
 
 
 void
-Simulator::Remove (EventId ev)
+Simulator::Remove (const EventId &ev)
 {
   return GetPriv ()->Remove (ev);
 }
 
 void
-Simulator::Cancel (EventId &ev)
+Simulator::Cancel (const EventId &ev)
 {
   return GetPriv ()->Cancel (ev);
 }
 bool 
-Simulator::IsExpired (EventId id)
+Simulator::IsExpired (const EventId &id)
 {
   return GetPriv ()->IsExpired (id);
 }
@@ -538,13 +539,14 @@
 public:
   SimulatorTests ();
   // only here for testing of Ptr<>
-  void Ref (void);
-  void Unref (void);
+  void Ref (void) const;
+  void Unref (void) const;
   virtual ~SimulatorTests ();
   virtual bool RunTests (void);
 private:
   uint64_t NowUs ();
   bool RunOneTest (void);
+  void RunTestsConst (void) const;
   void A (int a);
   void B (int b);
   void C (int c);
@@ -565,6 +567,24 @@
   void cbaz3 (const int &, const int &, const int &);
   void cbaz4 (const int &, const int &, const int &, const int &);
   void cbaz5 (const int &, const int &, const int &, const int &, const int &);
+
+  void bar0c (void) const;
+  void bar1c (int) const;
+  void bar2c (int, int) const;
+  void bar3c (int, int, int) const;
+  void bar4c (int, int, int, int) const;
+  void bar5c (int, int, int, int, int) const;
+  void baz1c (int &) const;
+  void baz2c (int &, int &) const;
+  void baz3c (int &, int &, int &) const;
+  void baz4c (int &, int &, int &, int &) const;
+  void baz5c (int &, int &, int &, int &, int &) const;
+  void cbaz1c (const int &) const;
+  void cbaz2c (const int &, const int &) const;
+  void cbaz3c (const int &, const int &, const int &) const;
+  void cbaz4c (const int &, const int &, const int &, const int &) const;
+  void cbaz5c (const int &, const int &, const int &, const int &, const int &) const;
+
   void destroy (void);
   
   bool m_b;
@@ -582,10 +602,10 @@
 SimulatorTests::~SimulatorTests ()
 {}
 void 
-SimulatorTests::Ref (void)
+SimulatorTests::Ref (void) const
 {}
 void 
-SimulatorTests::Unref (void)
+SimulatorTests::Unref (void) const
 {}
 uint64_t
 SimulatorTests::NowUs (void)
@@ -688,6 +708,57 @@
 SimulatorTests::cbaz5 (const int &, const int &, const int &, const int &, const int &)
 {}
 
+void 
+SimulatorTests::bar0c (void) const
+{}
+void 
+SimulatorTests::bar1c (int) const
+{}
+void 
+SimulatorTests::bar2c (int, int) const
+{}
+void 
+SimulatorTests::bar3c (int, int, int) const
+{}
+void 
+SimulatorTests::bar4c (int, int, int, int) const
+{}
+void 
+SimulatorTests::bar5c (int, int, int, int, int) const
+{}
+
+void
+SimulatorTests::baz1c (int &) const
+{}
+void
+SimulatorTests::baz2c (int &, int &) const
+{}
+void
+SimulatorTests::baz3c (int &, int &, int &) const
+{}
+void 
+SimulatorTests::baz4c (int &, int &, int &, int &) const
+{}
+void 
+SimulatorTests::baz5c (int &, int &, int &, int &, int &) const
+{}
+
+void
+SimulatorTests::cbaz1c (const int &) const
+{}
+void
+SimulatorTests::cbaz2c (const int &, const int &) const
+{}
+void
+SimulatorTests::cbaz3c (const int &, const int &, const int &) const
+{}
+void 
+SimulatorTests::cbaz4c (const int &, const int &, const int &, const int &) const
+{}
+void 
+SimulatorTests::cbaz5c (const int &, const int &, const int &, const int &, const int &) const
+{}
+
 bool
 SimulatorTests::RunOneTest (void)
 {
@@ -722,6 +793,80 @@
     }
   return ok;
 }
+void
+SimulatorTests::RunTestsConst (void) const
+{
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, this);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, this, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, this, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, this, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, this, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz1c, this, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz2c, this, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz3c, this, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar0c, this);
+  Simulator::ScheduleNow (&SimulatorTests::bar1c, this, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar2c, this, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar3c, this, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz1c, this, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz2c, this, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz3c, this, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+  Simulator::ScheduleNow (&SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar0c, this);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar1c, this, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar2c, this, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar3c, this, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz1c, this, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz2c, this, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz3c, this, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::cbaz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar0c, Ptr<const SimulatorTests> (this));
+  Simulator::ScheduleDestroy (&SimulatorTests::bar1c, Ptr<const SimulatorTests> (this), 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar2c, Ptr<const SimulatorTests> (this), 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar3c, Ptr<const SimulatorTests> (this), 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar4c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::bar5c, Ptr<const SimulatorTests> (this), 0, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz1c, this, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz2c, this, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz3c, this, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz4c, this, 0, 0, 0, 0);
+  Simulator::Schedule (Seconds (0.0), &SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz1c, this, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz2c, this, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz3c, this, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleNow (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz1c, this, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz2c, this, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz3c, this, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz4c, this, 0, 0, 0, 0);
+  Simulator::ScheduleDestroy (&SimulatorTests::baz5c, this, 0, 0, 0, 0, 0);
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+}
+
 bool 
 SimulatorTests::RunTests (void)
 {
@@ -869,6 +1014,8 @@
   Simulator::ScheduleDestroy (&SimulatorTests::baz5, this, 0, 0, 0, 0, 0);
 #endif
 
+  RunTestsConst ();
+
   EventId nowId = Simulator::ScheduleNow (&foo0);
   m_destroyId = Simulator::ScheduleDestroy (&SimulatorTests::destroy, this);
   if (m_destroyId.IsExpired ())
@@ -884,6 +1031,22 @@
       ok = false;
     }
 
+  EventId anId = Simulator::ScheduleNow (&foo0);
+  EventId anotherId = anId;
+  if (anId.IsExpired () || anotherId.IsExpired ())
+    {
+      ok = false;
+    }
+  Simulator::Remove (anId);
+  if (!anId.IsExpired () || !anotherId.IsExpired ())
+    {
+      ok = false;
+    }
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+  
+
   return ok;
 }
 
--- a/src/simulator/simulator.h	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/simulator.h	Wed Sep 05 18:35:39 2007 +0100
@@ -163,8 +163,8 @@
    * @param obj the object on which to invoke the member method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj);
+  template <typename MEM, typename OBJ>
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -172,8 +172,8 @@
    * @param a1 the first argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, typename U1, typename T1>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1), OBJ obj, T1 a1);
+  template <typename MEM, typename OBJ, typename T1>
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -182,8 +182,8 @@
    * @param a2 the second argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, typename U1, typename U2, typename T1, typename T2>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2);
+  template <typename MEM, typename OBJ, typename T1, typename T2>
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -193,10 +193,9 @@
    * @param a3 the third argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3);
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -207,10 +206,9 @@
    * @param a4 the fourth argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3, typename U4,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3, typename T4>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
   /**
    * @param time the relative expiration time of the event.
    * @param mem_ptr member method pointer to invoke
@@ -222,10 +220,9 @@
    * @param a5 the fifth argument to pass to the invoked method
    * @returns an id for the scheduled event.
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3, typename U4, typename U5,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventId Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, 
+  static EventId Schedule (Time const &time, MEM mem_ptr, OBJ obj, 
                            T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
   /**
    * @param time the relative expiration time of the event.
@@ -295,27 +292,25 @@
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    */
-  template <typename T, typename OBJ>
-  static EventId ScheduleNow (void (T::*mem_ptr) (void), OBJ obj);
+  template <typename MEM, typename OBJ>
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    * @param a1 the first argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, 
-            typename U1,  
+  template <typename MEM, typename OBJ, 
             typename T1>
-  static EventId ScheduleNow (void (T::*mem_ptr) (U1), OBJ obj, T1 a1);
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    * @param a1 the first argument to pass to the invoked method
    * @param a2 the second argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2>
-  static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2);
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -323,10 +318,9 @@
    * @param a2 the second argument to pass to the invoked method
    * @param a3 the third argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3>
-  static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3);
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -335,11 +329,10 @@
    * @param a3 the third argument to pass to the invoked method
    * @param a4 the fourth argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3, typename U4,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3, typename T4>
-  static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, 
-                           T1 a1, T2 a2, T3 a3, T4 a4);
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, 
+                              T1 a1, T2 a2, T3 a3, T4 a4);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -349,11 +342,10 @@
    * @param a4 the fourth argument to pass to the invoked method
    * @param a5 the fifth argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3, typename U4, typename U5,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventId ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, 
-                           T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  static EventId ScheduleNow (MEM mem_ptr, OBJ obj, 
+                              T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
   /**
    * @param f the function to invoke
    */
@@ -414,27 +406,25 @@
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    */
-  template <typename T, typename OBJ>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj);
+  template <typename MEM, typename OBJ>
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    * @param a1 the first argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, 
-            typename U1,
+  template <typename MEM, typename OBJ, 
             typename T1>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (U1), OBJ obj, T1 a1);
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
    * @param a1 the first argument to pass to the invoked method
    * @param a2 the second argument to pass to the invoked method
    */
-  template <typename T, typename OBJ,
-            typename U1, typename U2,
+  template <typename MEM, typename OBJ,
             typename T1, typename T2>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2);
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -442,10 +432,9 @@
    * @param a2 the second argument to pass to the invoked method
    * @param a3 the third argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3);
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -454,11 +443,10 @@
    * @param a3 the third argument to pass to the invoked method
    * @param a4 the fourth argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3, typename U4,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3, typename T4>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, 
-                               T1 a1, T2 a2, T3 a3, T4 a4);
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, 
+                                  T1 a1, T2 a2, T3 a3, T4 a4);
   /**
    * @param mem_ptr member method pointer to invoke
    * @param obj the object on which to invoke the member method
@@ -468,11 +456,10 @@
    * @param a4 the fourth argument to pass to the invoked method
    * @param a5 the fifth argument to pass to the invoked method
    */
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3, typename U4, typename U5,
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventId ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, 
-                               T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  static EventId ScheduleDestroy (MEM mem_ptr, OBJ obj, 
+                                  T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
   /**
    * @param f the function to invoke
    */
@@ -534,7 +521,7 @@
    *
    * @param id the event to remove from the list of scheduled events.
    */
-  static void Remove (EventId id);
+  static void Remove (const EventId &id);
   /**
    * Set the cancel bit on this event: the event's associated function
    * will not be invoked when it expires. 
@@ -547,7 +534,7 @@
    * 
    * @param id the event to cancel
    */
-  static void Cancel (EventId &id);
+  static void Cancel (const EventId &id);
   /**
    * This method has O(1) complexity.
    * Note that it is not possible to test for the expiration of
@@ -560,7 +547,7 @@
    * @param id the event to test for expiration
    * @returns true if the event has expired, false otherwise.
    */
-  static bool IsExpired (const EventId id);
+  static bool IsExpired (const EventId &id);
   /**
    * Return the "current simulation time".
    */
@@ -569,50 +556,45 @@
   Simulator ();
   ~Simulator ();
 
-  template <typename T, typename OBJ>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (void), OBJ obj);
-  template <typename T, typename OBJ, 
-            typename U1,
+  template <typename MEM, typename OBJ>
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj);
+  template <typename MEM, typename OBJ, 
             typename T1>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1);
-  template <typename T, typename OBJ, 
-            typename U1, typename U2,
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1);
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2);
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3,
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2);
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3);
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3, typename U4,
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3);
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3, typename T4>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
-  template <typename T, typename OBJ, 
-            typename U1, typename U2, typename U3, typename U4, typename U5,
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4);
+  template <typename MEM, typename OBJ, 
             typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventImpl *MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, 
-                               T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
-  static EventImpl *MakeEvent (void (*f) (void));
+  static Ptr<EventImpl> MakeEvent (MEM mem_ptr, OBJ obj, 
+                                   T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  static Ptr<EventImpl> MakeEvent (void (*f) (void));
   template <typename U1, 
             typename T1>
-  static EventImpl *MakeEvent (void (*f) (U1), T1 a1);
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1), T1 a1);
   template <typename U1, typename U2, 
             typename T1, typename T2>
-  static EventImpl *MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2);
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2);
   template <typename U1, typename U2, typename U3,
             typename T1, typename T2, typename T3>
-  static EventImpl *MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3);
   template <typename U1, typename U2, typename U3, typename U4,
             typename T1, typename T2, typename T3, typename T4>
-  static EventImpl *MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4);
   template <typename U1, typename U2, typename U3, typename U4, typename U5,
             typename T1, typename T2, typename T3, typename T4, typename T5>
-  static EventImpl *MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
+  static Ptr<EventImpl> MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5);
 
   static SimulatorPrivate *GetPriv (void);
-  static EventId Schedule (Time const &time, EventImpl *event);
-  static EventId ScheduleDestroy (EventImpl *event);
-  static EventId ScheduleNow (EventImpl *event);
+  static EventId Schedule (Time const &time, const Ptr<EventImpl> &event);
+  static EventId ScheduleDestroy (const Ptr<EventImpl> &event);
+  static EventId ScheduleNow (const Ptr<EventImpl> &event);
   static SimulatorPrivate *m_priv;
 };
 
@@ -649,14 +631,13 @@
   }
 };
 
-template <typename T, typename OBJ>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (void), OBJ obj) 
+template <typename MEM, typename OBJ>
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj) 
 {
   // zero argument version
   class EventMemberImpl0 : public EventImpl {
   public:
-    typedef void (T::*F)(void);
-    EventMemberImpl0 (OBJ obj, F function) 
+    EventMemberImpl0 (OBJ obj, MEM function) 
       : m_obj (obj), 
         m_function (function)
     {}
@@ -666,22 +647,20 @@
       (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (); 
     }
     OBJ m_obj;
-    F m_function;
-  } *ev = new EventMemberImpl0 (obj, mem_ptr);
-  return ev;
+    MEM m_function;
+  } * ev = new EventMemberImpl0 (obj, mem_ptr);
+  return Ptr<EventImpl> (ev, false);
 }
 
 
-template <typename T, typename OBJ, 
-          typename U1,
+template <typename MEM, typename OBJ, 
           typename T1>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1), OBJ obj, T1 a1)
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1)
 {
   // one argument version
   class EventMemberImpl1 : public EventImpl {
   public:
-    typedef void (T::*F)(U1);
-    EventMemberImpl1 (OBJ obj, F function, T1 a1) 
+    EventMemberImpl1 (OBJ obj, MEM function, T1 a1) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1)
@@ -693,23 +672,20 @@
       (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1);
     }
     OBJ m_obj;
-    F m_function;
+    MEM m_function;
     typename TypeTraits<T1>::ReferencedType m_a1;
   } *ev = new EventMemberImpl1 (obj, mem_ptr, a1);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2) 
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) 
 {
   // two argument version
   class EventMemberImpl2 : public EventImpl {
   public:
-    typedef void (T::*F)(U1, U2);
-      
-    EventMemberImpl2 (OBJ obj, F function, T1 a1, T2 a2) 
+    EventMemberImpl2 (OBJ obj, MEM function, T1 a1, T2 a2) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1),
@@ -722,24 +698,21 @@
       (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2);
     }
     OBJ m_obj;
-    F m_function;
+    MEM m_function;
     typename TypeTraits<T1>::ReferencedType m_a1;
     typename TypeTraits<T2>::ReferencedType m_a2;
   } *ev = new EventMemberImpl2 (obj, mem_ptr, a1, a2);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) 
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
 {
   // three argument version
   class EventMemberImpl3 : public EventImpl {
   public:
-    typedef void (T::*F)(U1,U2,U3);
-      
-    EventMemberImpl3 (OBJ obj, F function, T1 a1, T2 a2, T3 a3) 
+    EventMemberImpl3 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1),
@@ -753,25 +726,22 @@
       (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3);
     }
     OBJ m_obj;
-    F m_function;
+    MEM m_function;
     typename TypeTraits<T1>::ReferencedType m_a1;
     typename TypeTraits<T2>::ReferencedType m_a2;
     typename TypeTraits<T3>::ReferencedType m_a3;
   } *ev = new EventMemberImpl3 (obj, mem_ptr, a1, a2, a3);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3, typename U4,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3, typename T4>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   // four argument version
   class EventMemberImpl4 : public EventImpl {
   public:
-    typedef void (T::*F)(U1, U2, U3, U4);
-          
-    EventMemberImpl4 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4) 
+    EventMemberImpl4 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1),
@@ -786,27 +756,24 @@
       (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4);
     }
     OBJ m_obj;
-    F m_function;
+    MEM m_function;
     typename TypeTraits<T1>::ReferencedType m_a1;
     typename TypeTraits<T2>::ReferencedType m_a2;
     typename TypeTraits<T3>::ReferencedType m_a3;
     typename TypeTraits<T4>::ReferencedType m_a4;
   } *ev = new EventMemberImpl4 (obj, mem_ptr, a1, a2, a3, a4);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3, typename U4, typename U5,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3, typename T4, typename T5>
-EventImpl *Simulator::MakeEvent (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, 
-                                 T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+Ptr<EventImpl> Simulator::MakeEvent (MEM mem_ptr, OBJ obj, 
+                                     T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   // five argument version
   class EventMemberImpl5 : public EventImpl {
   public:
-    typedef void (T::*F)(U1, U2, U3, U4, U5);
-      
-    EventMemberImpl5 (OBJ obj, F function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+    EventMemberImpl5 (OBJ obj, MEM function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
       : m_obj (obj), 
         m_function (function),
         m_a1 (a1),
@@ -822,18 +789,18 @@
       (EventMemberImplObjTraits<OBJ>::GetReference (m_obj).*m_function) (m_a1, m_a2, m_a3, m_a4, m_a5);
     }
     OBJ m_obj;
-    F m_function;
+    MEM m_function;
     typename TypeTraits<T1>::ReferencedType m_a1;
     typename TypeTraits<T2>::ReferencedType m_a2;
     typename TypeTraits<T3>::ReferencedType m_a3;
     typename TypeTraits<T4>::ReferencedType m_a4;
     typename TypeTraits<T5>::ReferencedType m_a5;
   } *ev = new EventMemberImpl5 (obj, mem_ptr, a1, a2, a3, a4, a5);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
 template <typename U1, typename T1>
-EventImpl *Simulator::MakeEvent (void (*f) (U1), T1 a1) 
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1), T1 a1) 
 {
   // one arg version
   class EventFunctionImpl1 : public EventImpl {
@@ -852,12 +819,12 @@
     }
     F m_function;
     typename TypeTraits<T1>::ReferencedType m_a1;
-  } *ev = new EventFunctionImpl1(f, a1);
-  return ev;
+  } *ev = new EventFunctionImpl1 (f, a1);
+  return Ptr<EventImpl> (ev, false);
 }
 
 template <typename U1, typename U2, typename T1, typename T2>
-EventImpl *Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2) 
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2), T1 a1, T2 a2) 
 {
   // two arg version
   class EventFunctionImpl2 : public EventImpl {
@@ -879,12 +846,12 @@
     typename TypeTraits<T1>::ReferencedType m_a1;
     typename TypeTraits<T2>::ReferencedType m_a2;
   } *ev = new EventFunctionImpl2 (f, a1, a2);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
 template <typename U1, typename U2, typename U3,
           typename T1, typename T2, typename T3>
-EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3), T1 a1, T2 a2, T3 a3)
 {
   // three arg version
   class EventFunctionImpl3 : public EventImpl {
@@ -908,12 +875,12 @@
     typename TypeTraits<T2>::ReferencedType m_a2;
     typename TypeTraits<T3>::ReferencedType m_a3;
   } *ev = new EventFunctionImpl3 (f, a1, a2, a3);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
 template <typename U1, typename U2, typename U3, typename U4,
           typename T1, typename T2, typename T3, typename T4>
-EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) 
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3,U4), T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   // four arg version
   class EventFunctionImpl4 : public EventImpl {
@@ -939,12 +906,12 @@
     typename TypeTraits<T3>::ReferencedType m_a3;
     typename TypeTraits<T4>::ReferencedType m_a4;
   } *ev = new EventFunctionImpl4 (f, a1, a2, a3, a4);
-  return ev;
+  return Ptr<EventImpl> (ev, false);
 }
 
 template <typename U1, typename U2, typename U3, typename U4, typename U5,
           typename T1, typename T2, typename T3, typename T4, typename T5>
-EventImpl *Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+Ptr<EventImpl> Simulator::MakeEvent (void (*f) (U1,U2,U3,U4,U5), T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   // five arg version
   class EventFunctionImpl5 : public EventImpl {
@@ -972,53 +939,48 @@
     typename TypeTraits<T4>::ReferencedType m_a4;
     typename TypeTraits<T5>::ReferencedType m_a5;
   } *ev = new EventFunctionImpl5 (f, a1, a2, a3, a4, a5);
-  return ev; 
+  return Ptr<EventImpl> (ev, false);
 }
 
-template <typename T, typename OBJ>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (void), OBJ obj) 
+template <typename MEM, typename OBJ>
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj));
 }
 
 
-template <typename T, typename OBJ,
-          typename U1,
+template <typename MEM, typename OBJ,
           typename T1>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1), OBJ obj, T1 a1) 
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2)
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2)
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2));
 }
 
-template <typename T, typename OBJ,
-          typename U1, typename U2, typename U3,
+template <typename MEM, typename OBJ,
           typename T1, typename T2, typename T3>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) 
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3, typename U4,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3, typename T4>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3, typename U4, typename U5,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3, typename T4, typename T5>
-EventId Simulator::Schedule (Time const &time, void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, 
-  						 T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
+EventId Simulator::Schedule (Time const &time, MEM mem_ptr, OBJ obj, 
+                             T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   return Schedule (time, MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
 }
@@ -1060,55 +1022,50 @@
 
 
 
-template <typename T, typename OBJ>
+template <typename MEM, typename OBJ>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (void), OBJ obj) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj));
 }
 
 
-template <typename T, typename OBJ, 
-          typename U1,
+template <typename MEM, typename OBJ, 
           typename T1>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1), OBJ obj, T1 a1) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3, typename U4,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3, typename T4>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3, typename U4, typename U5,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3, typename T4, typename T5>
 EventId
-Simulator::ScheduleNow (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, 
+Simulator::ScheduleNow (MEM mem_ptr, OBJ obj, 
                         T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   return ScheduleNow (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
@@ -1156,55 +1113,50 @@
 
 
 
-template <typename T, typename OBJ>
+template <typename MEM, typename OBJ>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (void), OBJ obj) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj));
 }
 
 
-template <typename T, typename OBJ, 
-          typename U1,
+template <typename MEM, typename OBJ, 
           typename T1>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1), OBJ obj, T1 a1) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2), OBJ obj, T1 a1, T2 a2) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3), OBJ obj, T1 a1, T2 a2, T3 a3) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3));
 }
 
-template <typename T, typename OBJ,
-          typename U1, typename U2, typename U3, typename U4,
+template <typename MEM, typename OBJ,
           typename T1, typename T2, typename T3, typename T4>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4), OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, T1 a1, T2 a2, T3 a3, T4 a4) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4));
 }
 
-template <typename T, typename OBJ, 
-          typename U1, typename U2, typename U3, typename U4, typename U5,
+template <typename MEM, typename OBJ, 
           typename T1, typename T2, typename T3, typename T4, typename T5>
 EventId
-Simulator::ScheduleDestroy (void (T::*mem_ptr) (U1,U2,U3,U4,U5), OBJ obj, 
+Simulator::ScheduleDestroy (MEM mem_ptr, OBJ obj, 
                             T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) 
 {
   return ScheduleDestroy (MakeEvent (mem_ptr, obj, a1, a2, a3, a4, a5));
--- a/src/simulator/time.cc	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/time.cc	Wed Sep 05 18:35:39 2007 +0100
@@ -414,12 +414,12 @@
 
   TimeStepPrecision::Set (TimeStepPrecision::NS);
 
-  Bind ("TimeStepPrecision", "S");
-  Bind ("TimeStepPrecision", "MS");
-  Bind ("TimeStepPrecision", "US");
-  Bind ("TimeStepPrecision", "NS");
-  Bind ("TimeStepPrecision", "PS");
-  Bind ("TimeStepPrecision", "FS");
+  DefaultValue::Bind ("TimeStepPrecision", "S");
+  DefaultValue::Bind ("TimeStepPrecision", "MS");
+  DefaultValue::Bind ("TimeStepPrecision", "US");
+  DefaultValue::Bind ("TimeStepPrecision", "NS");
+  DefaultValue::Bind ("TimeStepPrecision", "PS");
+  DefaultValue::Bind ("TimeStepPrecision", "FS");
 
   return ok;
 }
--- a/src/simulator/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/simulator/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -47,11 +47,7 @@
 
 
 def build(bld):
-    sim = bld.create_obj('cpp', 'shlib')
-    sim.name = 'ns3-simulator'
-    sim.target = sim.name
-    sim.uselib_local = ['ns3-core']
-
+    sim = bld.create_ns3_module('simulator', ['core'])
     sim.source = [
         'high-precision.cc',
         'time.cc',
--- a/src/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/src/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -2,6 +2,7 @@
 
 import os, os.path
 import shutil
+import types
 
 import Action
 import Common
@@ -16,12 +17,12 @@
     'node',
     'internet-node',
     'devices/point-to-point',
-    'devices/csma-cd',
+    'devices/csma',
     'applications',
+    'routing/global-routing',
     'mobility',
     )
 
-
 def set_options(opt):
     opt.sub_options('simulator')
 
@@ -38,23 +39,30 @@
     conf.sub_config('simulator')
 
     blddir = os.path.abspath(os.path.join(conf.m_blddir, conf.env.variant()))
-    for module in all_modules:
-        module_path = os.path.join(blddir, 'src', module)
-        conf.env.append_value('NS3_MODULE_PATH', module_path)
-        if Params.g_options.enable_rpath:
-            conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (module_path,))
+    conf.env['NS3_MODULE_PATH'] = [os.path.join(blddir)]
+    if Params.g_options.enable_rpath:
+        conf.env.append_value('RPATH', '-Wl,-rpath=%s' % (os.path.join(blddir),))
 
     ## Used to link the 'run-tests' program with all of ns-3 code
     conf.env['NS3_MODULES'] = ['ns3-' + module.split('/')[-1] for module in all_modules]
 
-
+def create_ns3_module(bld, name, dependencies=()):
+    module = bld.create_obj('cpp', 'objects')
+    module.name = 'ns3-' + name
+    module.target = module.name
+    module.add_objects = ['ns3-' + dep for dep in dependencies]
+    module.env.append_value('CXXFLAGS', module.env['shlib_CXXFLAGS'])
+    return module
+    
 
 def build(bld):
     Object.register('ns3header', Ns3Header)
     Action.Action('ns3header', func=_ns3_headers_inst, color='BLUE')
+    bld.create_ns3_module = types.MethodType(create_ns3_module, bld)
     
     bld.add_subdirs(list(all_modules))
 
+
 class Ns3Header(Object.genobj):
     """A set of NS-3 header files"""
     def __init__(self, env=None):
--- a/utils/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/utils/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -4,23 +4,15 @@
 def build(bld):
     env = bld.env_of_name('default')
 
-    def create_ns_prog(name, source):
-        obj = bld.create_obj('cpp', 'program')
-        obj.target = name
-        obj.source = source
-        return obj
-
-    unit_tests = create_ns_prog('run-tests', 'run-tests.cc')
+    unit_tests = bld.create_ns3_program('run-tests')
     unit_tests.install_var  = 0 # do not install
     unit_tests.unit_test    = 1 # runs on 'waf check'
+    unit_tests.source = 'run-tests.cc'
     ## link unit test program with all ns3 modules
-    unit_tests.uselib_local = env['NS3_MODULES']
+    unit_tests.uselib_local = 'ns3'
     
-    obj = create_ns_prog('bench-simulator', 'bench-simulator.cc')
-    obj.uselib_local = "ns3-core ns3-common ns3-simulator"
+    obj = bld.create_ns3_program('bench-simulator', ['simulator'])
+    obj.source = 'bench-simulator.cc'
 
-    obj = create_ns_prog('replay-simulation', 'replay-simulation.cc')
-    obj.uselib_local = "ns3-core ns3-common ns3-simulator"
-
-    obj = create_ns_prog('bench-event-collector', 'bench-event-collector.cc')
-    obj.uselib_local = "ns3-simulator"
+    obj = bld.create_ns3_program('replay-simulation', ['simulator'])
+    obj.source = 'replay-simulation.cc'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/waf	Wed Sep 05 18:35:39 2007 +0100
@@ -0,0 +1,338 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Thomas Nagy, 2005 (ita)
+
+import os, sys
+if 'PSYCOWAF' in os.environ:
+	try:
+		import psyco
+		psyco.full()
+	except:
+		pass
+
+VERSION="1.1.1"
+REVISION="1420549696"
+INSTALL=sys.platform=='win32' and 'c:/temp' or '/usr/local'
+cwd = os.getcwd()
+
+def decodeAscii85(s):
+	out=[]
+	app=out.append
+	s=''.join(s.split()).replace('z','!!!!!')
+	p1,p2=divmod(len(s), 5)
+	stop=5*p1
+	p3,p4=s[0:stop],s[stop:]
+	for i in range(p1):
+		off=i*5
+		a=ord(p3[off])-33
+		b=ord(p3[off+1])-33
+		c=ord(p3[off+2])-33
+		d=ord(p3[off+3])-33
+		e=ord(p3[off+4])-33
+		num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e
+		x,p=divmod(num,256)
+		x,o=divmod(x,256)
+		m,n=divmod(x,256)
+		app(chr(m)+chr(n)+chr(o)+chr(p))
+	if p2:
+		while len(p4)<5: p4=p4+'!'
+		a=ord(p4[0])-33
+		b=ord(p4[1])-33
+		c=ord(p4[2])-33
+		d=ord(p4[3])-33
+		e=ord(p4[4])-33
+		num=(52200625L*a)+(614125*b)+(7225*c)+(85*d)+e
+		x,p=divmod(num,256)
+		x,o=divmod(x,256)
+		m,n=divmod(x, 256)
+		if p2==2: app(chr(m))
+		elif p2==3: app(chr(m)+chr(n))
+		elif p2==4: app(chr(m)+chr(n)+chr(o))
+	return ''.join(out)
+
+# wafdir is needed to parse the command-line arguments or print the version number
+wafdir=None # SPECIAL LINE
+
+def uncompress_wafdir(newdir):
+	file = open(sys.argv[0], 'rb')
+	while 1:
+		line = file.readline()
+		if not line:
+			print "This is a stripped-down waf, there is no wafadmin directory available"
+			print "Please set WAFDIR to a directory containing a directory named wafadmin"
+			print "Or use the full waf version available freely at http://freehackers.org/~tnagy/bksys.html"
+			print "\033[91mNo wafadmin: cannot execute anything (error)\033[0m"
+			sys.exit(1)
+		line=line.rstrip()
+		if line=='# ===>BEGIN WOOF<===':
+			cnt = file.readline()
+			if not cnt:
+				print "Corrupted waf (1)"
+				sys.exit(1)
+
+			line = file.readline().rstrip()
+			if line!='# ===>END WOOF<===':
+				print "Corrupted waf (2)"
+				sys.exit(1)
+			break
+	if not cnt:
+		print "Corrupted waf (3)"
+		sys.exit(1)
+
+	cnt = decodeAscii85(cnt[1:])
+
+	# create wafadmin
+	import shutil
+	try: shutil.rmtree(newdir)
+	except OSError: pass
+	try: os.makedirs(newdir)
+	except OSError:
+		print "Could uncompress waf-local into %s"%newdir
+		print "Please install waf system-wide or move waf in a writeable directory"
+		sys.exit(1)
+
+	os.chdir(newdir)
+	file = open('wafadmin.tar.bz2', 'wb')
+	file.write(cnt)
+	file.close()
+
+	# now we have the tar file to open
+	import tarfile
+	tar = tarfile.open('wafadmin.tar.bz2')
+	for tarinfo in tar:
+		tar.extract(tarinfo)
+	tar.close()
+
+	# cleanup the tarfile and chdir to the previous directory
+	os.chmod('wafadmin', 0755)
+	os.chmod('wafadmin'+os.sep+'Tools', 0755)
+	os.unlink('wafadmin.tar.bz2')
+	os.chdir(cwd)
+
+	global wafdir
+	wafdir = newdir
+
+def try_wafdir(dir):
+	global wafdir
+	if wafdir: return
+	try:
+		os.stat(os.path.join(dir, 'wafadmin'))
+		wafdir = os.path.abspath(dir)
+	except OSError:
+		pass
+
+def find_wafadmin():
+	global wafdir
+	name = sys.argv[0]
+
+	# wafadmin may be in $WAFDIR (developers)
+	if 'WAFDIR' in os.environ:
+		try_wafdir(os.environ['WAFDIR'])
+		if wafdir: return
+
+	# waf-light is a special beast
+	if name[-5:] == 'light':
+		try_wafdir(os.path.dirname(os.path.abspath(name)))
+		if wafdir: return
+		print "\033[91mwaf-light in use, wafadmin not found -> export WAFDIR=/folder\033[0m"
+		sys.exit(1)
+
+	if not wafdir:
+		dir = "/lib/waf-%s-%s/" % (VERSION, REVISION)
+		for i in [INSTALL, '/usr', '/usr/local', '/opt']:
+			try_wafdir(i+dir)
+			if wafdir: return
+
+	# remove $HOME/.waf-version if asked to
+	if wafdir:
+		if "--nocache" in sys.argv:
+			import shutil
+			print "removing the local wafdir", wafdir
+			try: shutil.rmtree(wafdir)
+			except OSError: pass
+		try: os.stat(wafdir)
+		except OSError: wafdir=None
+
+	if wafdir: return
+
+	# look in the directory containing waf
+	if sys.platform == 'win32': s='waf-%s-%s'
+	else: s='.waf-%s-%s'
+	dir = os.path.join(os.path.dirname(os.path.abspath(name)), s % (VERSION, REVISION))
+	try_wafdir(dir)
+	if wafdir: return
+
+	# not found, uncompress
+	wafdir = dir
+	uncompress_wafdir(dir)
+
+# run the test
+find_wafadmin()
+if "-vv" in sys.argv: print "wafdir is ", wafdir
+
+# Update sys.path and import our modules
+wafadmindir = os.path.join(wafdir, 'wafadmin')
+tooldir = os.path.join(wafadmindir, 'Tools')
+sys.path = [wafadmindir, tooldir] + sys.path
+
+import Options, Params, Utils
+from Params import fatal, warning
+
+# Set the directory containing the tools
+Params.g_tooldir = [tooldir]
+Params.g_cwd_launch = cwd
+
+if Params.g_version != VERSION:
+	fatal('version mismatch waf %s <-> wafadmin %s (wafdir %s)' % (VERSION, Params.g_version, wafdir))
+
+# some command-line options can be processed immediately
+if '--version' in sys.argv:
+	opt_obj = Options.Handler()
+	opt_obj.parse_args()
+	sys.exit(0)
+
+# now find the wscript file
+msg1 = 'Waf: *** Nothing to do! Please run waf from a directory containing a file named "wscript"'
+
+# Some people want to configure their projects gcc-style:
+# mkdir build && cd build && ../waf configure && ../waf
+# check that this is really what is wanted
+build_dir_override = None
+candidate = None
+
+lst = os.listdir(cwd)
+xml = 0
+#check if a wscript or a wscript_xml file is in current directory
+if (not 'wscript' in lst) and (not 'wscript_xml' in lst):
+	if 'configure' in sys.argv:
+		#set the build directory with the current directory
+		build_dir_override = cwd
+	if 'wscript_build' in lst:
+		#try to find the wscript root
+		candidate = cwd
+else:
+	#wscript or wscript_xml is in current directory, use this directory as candidate
+	candidate = cwd
+
+try:
+	#check the following dirs for wscript or wscript_xml
+	search_for_candidate = True
+	if not candidate:
+		#check first the calldir if there is wscript or wscript_xml
+		#for example: /usr/src/configure the calldir would be /usr/src
+		calldir = os.path.abspath(os.path.dirname(sys.argv[0]))
+		lst_calldir = os.listdir(calldir)
+		if 'wscript'       in lst_calldir:
+			candidate = calldir
+			search_for_candidate = False
+		if 'wscript_xml'   in lst_calldir:
+			candidate = calldir
+			xml = 1
+			search_for_candidate = False
+	if "--make-waf" in sys.argv and candidate:
+		search_for_candidate = False
+
+	#check all directories above current dir for wscript or wscript_xml if still not found
+	while search_for_candidate:
+		if len(cwd) <= 3:
+			break # stop at / or c:
+		dirlst = os.listdir(cwd)
+		if 'wscript' in dirlst:
+			candidate = cwd
+			xml = 0
+		if 'wscript_xml' in dirlst:
+			candidate = cwd
+			xml = 1
+			break
+		if 'configure' in sys.argv and candidate:
+			break
+		if Params.g_lockfile in dirlst:
+			break
+		cwd = cwd[:cwd.rfind(os.sep)] # climb up
+except:
+	fatal(msg1)
+
+if not candidate:
+	# check if the user only wanted to display the help
+	if '-h' in sys.argv or '--help' in sys.argv:
+		warning('No wscript file found: the help message may be incomplete')
+		opt_obj = Options.Handler()
+		opt_obj.parse_args()
+		sys.exit(0)
+	else:
+		fatal(msg1)
+
+# We have found wscript, but there is no guarantee that it is valid
+os.chdir(candidate)
+
+# xml -> jump to the parser
+if xml:
+	from XMLScripting import compile
+	compile(candidate+os.sep+'wscript_xml')
+else:
+	# define the main module containing the functions init, shutdown, ..
+	Utils.set_main_module(os.path.join(candidate, 'wscript'))
+
+if build_dir_override:
+	try:
+		# test if user has set the blddir in wscript.
+		blddir = Utils.g_module.blddir
+		msg = 'Overriding build directory %s with %s' % (blddir, build_dir_override)
+		Params.niceprint(msg, 'WARNING', 'waf')
+	except:
+		pass
+	Utils.g_module.blddir = build_dir_override
+
+# fetch the custom command-line options recursively and in a procedural way
+opt_obj = Options.Handler()
+opt_obj.sub_options('') # will look in wscript
+opt_obj.parse_args()
+
+# use the parser results
+if Params.g_commands['dist']:
+	# try to use the user-defined dist function first, fallback to the waf scheme
+	try:
+		Utils.g_module.dist()
+		sys.exit(0)
+	except AttributeError:
+		pass
+	try: appname = Utils.g_module.APPNAME
+	except: appname = 'noname'
+
+	try:
+		get_version = Utils.g_module.get_version
+	except AttributeError:
+		try:
+			version = Utils.g_module.VERSION
+		except AttributeError:
+			version = '1.0'
+	else:
+		version = get_version()
+
+	from Scripting import Dist
+	Dist(appname, version)
+	sys.exit(0)
+elif Params.g_commands['distclean']:
+	# try to use the user-defined distclean first, fallback to the waf scheme
+	try:
+		Utils.g_module.distclean()
+		sys.exit(0)
+	except AttributeError:
+		pass
+	from Scripting import DistClean
+	DistClean()
+	sys.exit(0)
+
+try: Utils.g_module.init()
+except AttributeError: pass
+
+import Scripting
+try: Scripting.Main()
+except KeyboardInterrupt: Params.fatal('build interrupted')
+#import hotshot
+#prof=hotshot.Profile("/tmp/proftest.txt")
+#prof.runcall(Scripting.Main)
+#prof.close()
+# ===>BEGIN WOOF<===
+#6<\%_0gSqh;d#""QRi4MNW9%Ys8;Tjs8W-!s8W-!s8W*A!!!?/+s:iT#QPE@+:JNalM^0u7E&7,zzU5BWbz!oq"M1#9$/UR'Q@h2E0$HX4Xf:2NWkAtYU?>A0Z5XLk)fl$_aFmsXWhU_,Lb16eF=;LtY_;4@7:GM-3XH_G<FH]L6)A#/tII6?F=n!f<;Dmo*/EZ8k06d=rcDllJO.=Kk,'Vu-N>C2j>#5d`0]WUYfGLm@uTQ\8/5QGJZ:^!al1hiXX4Z1]3!!bahTQJ6W5j?(>6<:;j),Tb;_rq(S"]4Tp^n;;I($KLb"*XME*kPRs*a8a2mA3[.1[C%gSaknoQEB!KJ-V"e78sKLqQ7f<[g/oQpRq#,Vr%IVd/!*kI"26_!32kCX@/ja$DLgq@fQK/-iaSS!!!!";/3L+=0I&?f7!+ek.8]W)APb35bL",pV+k_pMdk@?Ld<Y]670LFZJF2mr[DB?KZ6.4blath7_MfLYfaNgfMf\^@#1iBpE`'[U9nS"GEe>FY3?)DUUjT#DH7:>M`,<SnH%`#(?(umV$WHA_1emlV*c(Y+AeLXkm@X]tPQVS*bPYeRe1Ac1U,NqYGWCql]g;mpCFs]XG!/n$gVSDI-Z:jmG:??2)%ll,r\jH+LV)o71Ie]=$)heun>MT5>M/qVQ)JWr&9p34.AoCg76^f"/EJ?[LOSc!G2QpN!kMlQ5PB>Qe9%Xo[YKlb;dNP`]gkf@ssK;9s,dbO;"NT3MhD^$AIlhY2:7flm,"G4"[>Y<&9$D@`gThd^jnZ_MkF;8&MfhT_KQmgJI5!mpgHlFYZOZqC'b^!'!4K5Y]WkSeBG<@%rN>Lj:QF;+aoG>u01g@k+Y`YU:#VlpC;Vn7Acp27T:*mH>2S\UodkG^QSWW;eD-_iLEpYGS9D;0"0)e=XTS%GZeH+R"qG6Vro=)?^%<8/(-0o!<.!:A;%gu=t9pWoEpgV1/+h`#2J>>)ZQbs<_*Sb@9_n8e[!qoO3!";6&f\`o3cnr@F4mWY5$95Q*D:)19M*#1*/qjW`(cF0ohH"Sbcj?;r*gO8fKJ^K*SY2=G/[tW[F]b3d#aR,7p%`R)?hV@.e\_[;n;U_NV[bIcYT6Hej%op:XeGJR,RIVId78h^iJ?PM]q?Dl)pH7hk*r!DC]u.OU?Z#Pf^%]/-]_@H?DVG!CXk<*KmsE[D2n-r&Z1j9lpNOa;T\4qGD4TF@T(]d&k69`8a5+JD-#2Z4^"r*:3\V7INr!(i71t/D!e`=D!/W),8%`Cj]6isn]cM<u]s)edCt<#nC4!Y-%ZToRcVE6;_X"87j0a'b^"sJ#mV>^NFjX2S"V3l^mpg\RYT3@:>!Dht^,jl`_Y8=.c(64<o7=Rc%W+A649^H-]Beo'oOT\RFdWr%>"dKXeQn`/[l`pC0`([UDk<"N=94JdUXD?tIB\s`!.]Sb+:)W`d$OrL)?aTBR8Mp5ksK.e7R<"V!!!.T+p``HN<'#R!hZ;9rDPPH]i3T2RSQjX;ot`-%0K</JB.]j!!5JTJHJ.?dg3n5d*SAJ7[c1t1t9Y2RP=t/9Za9A4W9rk6R,*p)J$e-4[BB'&I;)L+dC*KIYjufUX:ps'Z`L-4fW4oO9pLn$mPt,-CC/+!&6;9;F1tg9`QN/QkLg+9f*R_<;_EAW:D=44Z905<:rC/:J_-YB\IuM!!!.jLk5a11)^/nWVTCaOm4dMWVU0nr@2X+Rjl$I!!!!.!!!!@;ucM4qZ.IO6soj1TF)7(ckJ3ijs&)FEtN5EWf!dL8YBIBNs#_"[$Zr=9?#ud3rGOl]6C@/;mOQie"[q5C0Zs*^!rN_?LmLG?MDe@%YTARr@(WV5NpRud166n<=Y`Vr.6Agoe"WT2TP"0d'E*qpEaQTk-%`FP](F)B(0G2[Mh&@QUPe3=&N@h``onhCNYu30!oHB@M7_B5O4.O-nccRK*7!]_9XW8,,dqq%g`J;J4&H!ne='J-j?E?)A&_`'I[!"ndl4%O),t,91_\&Lp8)\<'85#0VJ0*I3Ha5E%)QU&)R`)-p]$f&YL99&:d+r;@3:]9M`dg,4jp1PT`NO*T5>>!$%8JQ,isPJ`I(_*2iqB_BAV?,)f%m'T+R?Tj/]O&cNVHHmAUBFJ)M[a@.lm9LU2t3gM1h8cL-RdLdWh<<GTVe.Dcq'ho,^8CGH'"V=N3&;4"\5n$[@6561`,#AFc6k(9`'2:8[;&%GI77fmH8J'-D784J\;*`N&bXb9P'nO1p"&ME?<=G!X1^,&mS4um9;%Y3E'LbEP,qtT]$jBQ10ml_?=]o2@R@tsrQ9knH-qY[%.Zf5rWX4t0RUTuE$<jEd<iUh1A;LMJLdk!O6A:7?+d**\$7%&K$AO6_7\V)9VFDt&KN]^sWFcK8,%QO@MHGZY#bi2.VFcMo@Us2KU/CujL6<`m#sqg-TVe/(+Fo3DMI;UGMBiO$@ORt-.O$9M#cK-i-<a"CRRSE_6BWLLR$N9"@&@CeL5;d[$4>NV%3lH^70+kPbWurM"Ubm[_%@s3!@.eH,m6RM"VVRa^dO;B$l)I@,sagc'i`+J`=Pu]:dHonP`-:j;\9^#6Ua?t6:1ke6pUhb`(<<^&Oa^J6U=+,&JA%GKG$]V;$96["9hK+PT^Tk'ZEL0:t%,Bd"KV2727LS9T9TK<#$[p6ps?V1pg.SYZ4)U'N!1G,r66gKMtRd&i?DG_[I6t<E')l5Y/^hbXiN\7'd$<;*tpn`CrZ3!>@aV8J*f0;^;oNPXJ,8$OmeH`.LTS$PQFW'*S[TPS$lG1GVNq92)0U5tOCB&/<M[71h*a8MqrjaWuu\&Houa0f)dj<7&u\,Z'RjdRck9:b4:T86$'l0iJcS1CHIS&440':f,@m7$0&/5m9Og&r]Zs:f&E:ZkT=S0h=PtOGq@_'GXUK5seL9&/@i(1)/(=/Hl;D'TiJ"$q*BM<"V\76kfq28CC*cd_doc,f!C`#)t#s1pI]%"JGrQ/3uTrWBsNP"YD5r9aX^V,=G(f"Am'''L3@p+U#%a<<1JZ&4&(i1dNt"'29oQ,YCp."9_+Y0[rc.;aj+Y'SR\A;ai2O<D?I:6NKSH"]2!`"J[(B`(_LV&BrB*&qVtS+@smI%89/_;%-"6Te`i@6Oc<,=Wo,ZTn9:r81?k<$AOCH$<h2#Pc5iPUnWu".0?6?-43@9RSlbXRJ(,b6pr*SVZ]C!5uS38C`3>S(*oi7$%aW>)(HP\#`'glVCAL=Lo*WZL`g5_!\.rR$5S/DTI(jJR3Dqe8j]CgTS??rPaW^cP(K?nq*K'M784CL1BLQ5'L9T09b`^(9%>XAN=,k69/6Z&#f+U15nGda*A@dR3T,"&fGR\_J>alb5_=\9TdlM*#RDb'Qt`9#,bc-=Q4aHM#RQb>A-N@?)G-f7M1UuV!Z<jN&Hrm]">`n*%5B:c1C410"Xt]*`"Fb'OAmr4&P5fPN>4-=1/ftp:st:g'bF3`9%-*].7l!cK#7Wn1lWma5SOIN.tp8U!(\m["%a4>4cCp)`'I5)+\PN[,qpVh:_=Br#n2do8u!l`&OeDg70Oo&_$lM@0bh!Jb;,.hKeP8=,SJIWb"DfW<Cml]YmC_2'Z=]Z:dl*i3J>f`6V'l_!>8(&YfTiV6j45Y#gB+Q6Hl+@!DQCq+B(iu[$7C3:f,)!1DEeU8PE)0;)1g5d8`an:t&E:9LCTIb(Tsh;cQ7";af![<'jKI`6cq16NES)/4hBd&d9]mZk5"AZOp2;";*CeYYtfAV(E!A;O%BI"N7QB6kGP.'b]"-;_T@\&O?Cb`!e%.'NHA(&-RYT<Da&k8OTm-;c$"Q!mi)_!<aqW1djbA.7lm$&QLC#_Sn4W`DfbF)^^GO$'qGsMP6\FQlqY#M&)5*:hZPYB`t4;#RG0S,&(X--AX*_"pp*Z$>BR-JLDjpK*FW;8kKekTV@R9-A"Q.+:;M<TS[*MW)TLGBnRCdU*`3[U7*M\R$iPhP(;o0d`0,$(<)TF8O63-PZ1LV_J*9YKTdt3/.j.d%+;Ls>XUhRJYZPnOX2E=9M6!19#/p[&@0Nt<00BY`.V)`_6=-:W>[+\@:C(J-kqMo-n6*$JV#'q6:=-W'SZ`U.7?e$U4SgX-N<Ej9LMhg5s[h)9gHo*aZr`=0I8G)b>SQW&HY?H,r#uf.8rYZ0b6m5Q!t)d;Q-<t+s:QpBVH,SO6\bFKRjh75mX_a'G@2b+L4=%PQVPV"Um^c"@,:E;%Q.$eO9Wu&s/AF7+0;a0G)Hl#nk]"d%q"J/49Vp/L;W1#ssjZ8e=m@P^Da1@dYsL8t0gs1^E4Tc]ljf\U+7!=L]tPBd`fXLmG]mJSHen&b$HgqChY;,&eD1ao$@pa#I+N/5hk&`_r82L/>t>s-j*d<Z1]K$0P9H4[oQiD#_%6:Z\d;,<0V4;[esVV8mPLJ%k.)7KL8`=r;!<"RBk548G4'BgV8eT-RaESY`%IM1=O&D]/#^V"BZO.)a-8*Okk5`TDE^Mb4s,-t[4O)YmA!ZtZ"E>Ws,EdI]%Cr(m4d>e0kLPcTrcnGMfkMIt2d@80uNa&N5E/mY[Y2cPmY^KAApchTGs,*%kFc2X$UU,l\(FVC$6&p?t[,3<q((%g#7-S.$TpqoL,ltnaGN6d7dYWS)Y;()Vu$*ssOOI!l"k*96o="g(Z8tpB!7=iS?jY4V^fAW]f+q,MAOZcC6DMh*j"q3G$As8X[(7)he;'M$h:$N7E(QSa%IM9DbUV8)PF,:aQN0o'.].N$M#2<Yccg-%kL-\:MB^H]_gG<nE(E5h[Ej#8ZIKJjtU/\*@ltOPn2TG]BTVsg\bS3R6^*a'1Ht+<oIYg569c'3]5()IQM)QXs\5,YqVidU8]D(=o_4n\?MD+rQEQ#mfQk>r=>mbD$@qt)SQh<X7B;QA6]FZ=r,O$>RbC8\U2["2n>ia:T<6)6H\9_%A<;W*o6.j_H>H$U++PXZ<W^!dXWN$6Z8pY@hdspBR9-+&rqLISGbU*HrF^K(9ks:'<ppf`E7Va.$PG<4UE@[pk2WuFneD8VV5CGopfIq/tDG;X==M:g^EC#c)LP(Tr*jj4?lI_N)&s7JLK2=Q"UC:!HhS0n.:W)JqHi'VVk;Q%-$EiBO@tJrn!0eSuIQ9=,+m+]VH-SB_l$B&<_bE_Sleug'<noD]RY[Y/9K?lYlL^YFP]KP9)@kJ+:os&`omN_8=sT]'FW0"OEr3F>*lD;&Gm4dQPuVA;ap3,k@Fh8'`led1@no?to3''K0\[i@#_)("eY9d).6dmEWFZUA-n&]8pH/)rP:S^McNds_PS9gslAVP%@r!r4/Nj>T.<D7foBn*i=J?ha?0a9^ZIP;;b,@HZpA8-n@Jl+"Jor/8GG5j7Tn*RYVVS>T$;d6DZL#122"e$EZh\m)[1PrHDp?=E7-lps8;>TGnJ[Wn,hQC"7;Fup<LE&IbmDsV&O=@[A%J?i6nOu`lFEuQqFn5P)8gK";pq^o'gcW"M3UN_D-*d1\L(QRX?Yji'D=EG7:DimU4kL:$N3"q-;uZE'^VQ^&78MYPiV<if%;D\g3Yro/n"GMYG,PJ=C8)A7I:';TY`1s-ENn%2I/U)61-@YIJBPsk;`aFThSpja![sm_IL25)>4f-9;m:c=^iS-g^"nA+4TN9k]B>+;h:mbT1Dern<)TjE2tMkMN6FSFp?FUX<N$8bGcW3KMZ)0#rZZnL!h26,Z0?/PsUKZU7@5b#&rsd>P,Oi'blRY;Pr*FG9N_5#c7X7K3!a.10c:$q<IN15rr]?V_Nd9Z1cSe#Jj[]'5%t5-9<P,#]oRa61+!<[n\t/%Fe8#+Z)X1S_p].Za1o[<lG:m-M7_*/de!=ZVpb(KdB5,R%Ye?[P2::`/#aoBd-dO0RjQP/p+@L^)DSRD[cL6O+L!gT'O1#PAeB+Vbki%4!prUoVm_@VF:sfTWt#TLNLoNmA%?&iDm:5`.a%.Dc5"<$'mhI1([_#9SR^L-ntXX`!W'2!@1eddJ1?09?r4*@nqsm[-+P`7@d+8Ct1^&*V"G&ZAUNjnE[b<9#=[R03a)#OW:2c,n*=dA^/>H]4`TcKcY3^\$a>W@apXq5K)]/Yq>h\7Lcos_R&ES?Gu)UG&1P,Pua+r$;-EOWWCDcB]V;!@/-eF?MjK;^@2(k8R5U0JsbsjdqQrm7.E4UBap7PipE&\MlAk`TpX!=M.]U3*;WX`KW.PI*RBs_$l.D?2Ru*<W1@fe@q;&h,jXOU&a#hb-E(!6)WiQCKsoB&nLNm+kMjKG(WQF2Y]@Z!Ct0f6:s]a+9r-M8k<A9Xng*q]_"&o@^Gg#\:B)<)Q'W&")kj;CoJ#_nB&gap:<HaK(!!\`2p&Y^j0@k$Z,)oHoEtHOEUtF?=-KYrZSX.%U(5Q\[i-U[*AJpjpaeG?B!i,h%eu]0Z@`3^MK8eW/1h93CM6iYpL;pa+sX`F]cGg1(@DpCF_?qK3H/@#c?#_C/6J6*=F'_OX1VL>?Zut73*Z!R=$uq+;^g4Fq.flXjcb_C:NBJJ%O"SWZ_2ra:ZCOX26]pEG(UZ-jAmC%I,@3?I]0+8b:IQ8"VPinq+oFEB&:W#a8J!CAeQq.E0J+]jQ'/NlIe9P_Iobr9@rP3][1+mXd\ro%lE=(,Ge,sBi7KpOJUhV)cI5K<*@R`fDI&KlISf?'g&F([mdHjS8-6f#OOLIQ1q,N0sDWW_e5Ia[AW?ajb$>n$bl?0V"Ves4qEp?WQ-M^e&4_hG+W<B?cL%He+ZF1qIe>qg>)">&%pVrZ7,mR=\\N=i@;:.c271V*-KB911'qp"b%\S9Xla^b*F4bBTARI2CUDD&;\62U/Gs;om+GIc=b%.T%/p8B-p2Io5P[=U*^Nd6`98;Eq[qY@p/b11o$L;j;j.7i=dq_i"[pB?)5Rg=*4GbpIbc?>J\An0g<*'jucP.`T<;?SHRI]9d]n8rS@!9]B8rUiHI+*2h-SJh`:Ja1L+RKLc"'5ZtDM>WKoEX-f2r<qG3gLgM6jrPZ_j#&#IoieSu*7CPTa7>unUHIr;Mj>``QkAa6>:2qhp_/ku-*6`e);E7SsqA?F6,(*>B+H[a\LOrjEoPATdEcsp0!n+&H>0_d&<+k]^(#_`NnenMEr"7^.Zm]s6=Yi_,qrDa?12SG!4-AGc[0^r$\+/u!E[tLpfM5QElOD`7CZT_0EU+gER`6n8*X\Z+D.a:)?<S"gGd)5hnfg'h3cP(=n\C+*rYYmF?5pq6M=eO]Q6d=)B&]CqP1ujHRon_^`C8CrH_rKc)^7u@]_De?]0L<->@Q&oG+Cs[$1s(n<7s3E[D-Ej$^@ROB8LE;6%ghsB\l*geF/IsQZ5MhAEoY1l:H@7WXPt:l_[T/CLMcRG3dU?i=!N_MNY[u#D0Itrd#of4S<pj79I:748L1ae[PXrg%1K2eU3CKM3](njc6ZYj'9ht@@_1kE=1JVT,*SG5pJQrp["fe$p*JF:[:"c-C(:[rc^_<-oq%Vd`]]A2T7t\WoB1CYrja&ZE+5PqQ/B0:l,rX6'>!PC,l.Aj,:%9J%Qu3Xb7Nd,fj?a<.`M&E_a9_C)?^J;j2toZs7psO,.0iFY9I3:4h,9A54MOu&#.;*:)%E%F"69,E4NgNf7e;!/J3!Cp"YXrQ;tEkj^b;_bB_7=G\SC$Oj510U8<-)\ii&L]?6NKZ;,+iM5J$>.6=/#M.l'Y\ojV][<.jQk=$XiiTaAoBs]/LdD8>i,djHX]^GVqdnKMN*=6BE22P"PUm6;`^kmIsP(p+XP!k(k+1aoh.*^Y3DWo+ICLYXfYG8nJ,i:Ur*MWM)#d\3EkuJqdm9rjk:HNM`\5DKV-d"6PM:2$N>G`bg,ipeO'M#cgWTG)e.he[;rD0;ZG'%B;(lK68?nmVno-"Mc&(=\.@N(iu;4Y"C0Hi@f$q;0%$5eL#7Nr+I3N?g.,(qY0&EE?GDP[4^G3Mr1ZkB!Jmf^%TFR'=jhr2=ae&D6+UD*"cUpK/Tm0*4Kd%(L?r@=>,bIaWpEYjB+N+9&PPVHKkcNLKQ''Fq_-;V3_&St\$>%)@>B`%cV%/=VWo=9OFa'jd=31[5`gRLNMP.FCab0#'p*%3M,^tCge$<dhDj0&Q4E_emQ/IFgl&Gt/ZIpGTBr0/23=._[D6u]3nIDB$b[;=+>9`6)=MPim4Yn'm@f#:YSXa(3qYmgeFBO`Q)(*Uj94uf6h,]F`U\F,](F]g^%:W>f:)BA&omm"e2opoIR,pj.7#T:jmpo&c6#6PJTjdd_]l;AcSPfHU`+GPA)RX!*5nqa2)=`uL]FaAuD^)ej4QpW_g-s$9j6DJ`mHfWJ:NCWgAiV[@b-OZf3N]I]#dn7"VU*ge8)=ubX4'.l8Dh>)5?g3CgcWak-+N4ut0\'5F\n[n;=rLCt.Bj:Q)R3r"pqFsL[jpSPM]qC@:oF;Nh:G%VfO^T$;[lQlI6CZijeOj^*hDFCHm-QAKP,0O]Vcb=@shiAjH];;VLN22Ylf)$N>"c&8Ia&/OFPe"^X8,$H-[lKq>&'qHQi?.G"isQHmEVWNj)63HS_"emH1^V!Ff0O3U'G#LIold=)nh+.+e%7;Z#D`"G`o(oG"Y&mX%_er#o?.>]Ps)&j`t]OPSco>!4W%Y4O0%e:pRE?s73D(-N;+;E`j*'i\>MG'nVYOj]$1B@/`G6:CdV'##ch6=t:Q6ZpLDiI'l75)VD*JtA7dgt#iPH+nAdOm747O+''ffiRQr?,G5/>te>m``6`hS)8\k'Ih/_<%>-]ic*+,D&U?&r=XUr+eHCT.t\%'jf]C>Oac1P([3_Q2,`f3"ON<&OQLP%l92em?nS^8kH@TaHn))0Iu5o^Qfj?^]19/>d]n04?dl&+\3[@k,YN)?4HRORrtSU`Qh"7UDNg;)WWJ2%,k@3P?hcXY.0NNl/1t9P1BIQLbaY.AXWC=[dLN<Yh=jT?'$#ZMbhYQ[6?kY.qXU+rD!;G#DoBS^8]@$Ea<mH?`bR[B!]n<AircU\8h?7bkb_!&I*ca[,-enT#a)e^-plM+E/Nm^Dk9mkq/G=+o<h;[3hed/5-C-@]6($<<N,jDd.c'NO6X9!n((*&cc,LXcnLm9^#O2,39jd;<),1E8:#\3aOY[jh`PSc"+N@/LTQfWVL3"mc>AH4%qttMUTr(XG7WLPhtch"0i"D)SWp#t3:(u0(X`'aW#'(3/Wg[A28ilg9@(=o1Fbg+,)U2!rAl;UI,WG%IiO9S_b8rAM\O.^(WUD^kZF1K4OIkAO*B7Hpq.\9Tq5F;jc0fmJbf^BK+VW=*$5:16sF)PTuq9#CXfnt-6$R<a.R)b'GQE2W29uo+'*=r;CFSYh8hJa%TTN:fa7caL!fmF-!8J5H7OM$:lPnu"`.=B1d=]I!ZN/o[(hRq1R$6/FSY@=N5ka0odl7@+SF_.$uK4%%9Eul^rRO)Su;=%\JN\MNP,gtN@$&LA>LNi)St`i646-sJD`eX&W/bdVC0p5]:<M#$R--mmShO,Ii6D\CHs1gXM6slMpb:0ASVV_+2u%I0m];pO6iedNFOm-i>-hRG>ja'][NK#FP#7f-%^[X^4(JKWO9_<7J2m$k!-W',Z=8INZ2ViiiJ\nL9*M!l7mT,["#r(9@[=:\[QEPh0et1MrT26]*6G#Ai7P=h':M\.beY@#SK]5Gs&>]dTe5G.VA7<kDeO_^#-FXXA^B+7%mK8D]0W1m7M(NN4m!378^s(WTa)04rubVo?d#nf/eWRJ"b)eIVYjp<@`-LV!)NnF)e$*&HoN$@V#9bfd]^c,SM_jq]&pCfpW&;2,Ia;lRd;Kf"4gJA0MJFZ@n=%9H(j5CU:8AiW>$\iZ[u>30uKJgbAOV*Y3oBUI7;K)h^B>6krqe>N.cX&^[_'7pVnCZ?EP,97k;9NKMq;imN[iJk8@rYgDjW?"Vo&WFt_,k^aUeSeOmtgGrR'TZYre:2Se.MNZ_IGNV!iK[&[_)13fpP.&c6SO,&$c!k<&4BFNUMre7X3-b>[TY"t$_T^Qd1"Y*L1S#)ejVH;mX@OV4+QTuG>KP97g]J&,+^lHJA%MM,E])g#1lm%`,?gi\A*t#XMW:>D=7Ql-af%)(FRXUY2FGttFNQ^CQSPehEEja97>,oAG!j[+-4O#koI?ZG`*\^(7@G99n>;82RpJ8QUrqN>Vkdqfd<V#SWj(JPPs:n41Xjf>nJjNK&k[!QgefJcohejJU9jE88;1#QDE:>JX(M[D]'6))KV`O&,5YPgV%*@^RH1,bngg]6egQhZPIqp^8+3"rN3)/B4&%VZ:L'@6rVPlt>Is^!l:J17Ng63b+]Ymj_d3q7/4?+;Y2o96jq0)@3,%JDUu-*+N+@[i>o,n;B\FIQXJSXcKbI<B<Tt6Y.&pn8)U@oC[+nEGSW9579g8Pb*U1]hEiITOP4)@AEKcbq()87V4_k?:E^IF6/;UXBB`)st10_I9mc8P?#f.pDK6olc8XbL;MBbi&]k&q9_(ieK,[<0HW0/q?`D[NAW]Jh_Cf8N3FehlPqdRj+);Y[mSDDX6';`kT0mOr/iLhj_Pi)[Y&Q2p5-U.r[Pdmb;.%5WkU*R7OX-tGp.:\X"'t-+jP,l?t;>q*ie,%T,D3TqcBD&8?Q-6AS:%[`:iFs=`mYW2tV@#[Zjo+lN]?^,i>]LPNKB!3;]+A\>I%+r0,+GN-W=IJ"[-9TQ^XDZ/j^tcF6q/`h?V0G\Eo^.Er%7(_Q<rb07trkk[.'[Tcao>tk=E2[CNS%b7VX-8S&J$V7J(-Jk]K\Yhqh0OPKb"eF1R^6SMh03S%6O3M?I*V=WCE"as&8(HT)X,X%-l0h+:1QZeL0nXe]d*2/OFNCCSO'Tfln1pua`,QJ4K7WZdsH*rf#qr#-3,%lDQ;6:m[19`DM8ceic+h`/TIKjIsJU;Oo6"Yp#@B?AK9JWGV(+*8Su1p\Lc,Bs!2[@o%l$7/Oga4QGb:We]tX1QGsP%5b$/EZ$T2G:%o+-U'IWqs`EAqo^m:X$fd0N1:B=K^3*qU8J\SP0!cb[4<-N&#@HP]2Ad/6&OL_iCb`[7(#:.C$+U&Z]WPpXE0>ReV#:9Hp24R'00t@"T,7fp?D$VN>7bNN+b2+m&KBs3%kB`J%&h>Y!uf2RHZ<.HG.l&rJsPq7rPa?O87$rL758Pcto+d2mttZE:HPH.^>QT)/D6h`_a2b?ZG6g^NAgkM&LOfem1eapThZTasqu<gBbd>#,p.PsQd#7&rL.Q8F?l-1=?EQbbC<&V5U'\YB#OOt=PVgKC%3,uJ2?i#:gpM.sWu8G]7DBB=W_g[+-@DsZ?JXKSt,VDM9uOFKNG4hj_Uk)qm/)?(^1^O@-2gZ)3m=ms:NK9=2NSZXBACE;cFaUM9c>,XPX*N"t1opE!>-j]EQj4ebbU7m;U_b7.AFg*HQk<$Mm!OV;C":=`mW&BBoGCD3*7TG;fTJGM%6luj3@U-/arFEJU%2;K9(4P[,R7Y_+,#^]H\>V:(i^)68+GADr9jJLi`[eK\N9Y/..D^p(cjs"^)cY+i6.JR4]%>i;j486-H-Rm=S._@RofVTTR(j0\468Z3)_Bk8cJsLcMKb8%\Sg?S9K.gMg@o]D7?a=J%OR>5i\$76F1F,f]sb2h/&>-*P9H5,S_:%r(><:N"o7hVjU_(#>]5D5!JJ5s$5r+%I;fH,h8.Wu]0tU$S.no2[_e=b]\]M^;/QNA`0kajBS3=)*Cu;FPEI1E/h[K%e#=F_":?Z7`mdik+V+%J=n5o8)a-+G?#3q,JSU7PJNodk.3LhTe^03eM^bM8<BnKK(oj6_j;\&]YWY0^4:*Hi\e/#CVSGiB%/Pg"9[+899(593jl>Iq?'q6li0g!q^B?LiESl+XN1K'lIQ!sOdWq9Oe`TEpe_LI8DK$'_#^u#5>T6F5$uVFU)to&B'+J1MbK0KsWsmG4_5l[oe\\[i05js0MV)J%P",rddSe['+>Acn3pMZ10i6LS1o1pX1t";5b53PFfeNf$Jf\$snpbU@Fgq\uXj[>,G$o6e9^!<"GdAE)c%0oE",>RY:V2^4,kLAGVfD<(WR"S.0\OHAgl4+\)Oe3.9-$+i#Dr9fUZ(%cR?(KE]d8BAP7?URE,j8lE.l2?S.\)^MZC0W)6-m@LYppGau?8TBE8fiJh,YG7!G^R-8R-YbSNVF(Ijh-1!o]7F1%VDO%DRhrQ!\8=-L&lSUCBqj62*.I!NdYO'sMkL9\G(`-r\qRq;sV^fS%HNC"(W\gFCe,Im4N*Stu:;\jqu9G$tog<SFP]oGSX>b>^hgI*HP5P=hl7X/T1Tqe*8\5tq7A-_*X>tUI\r`P#cNUrQD-W9__O6VrFlJlaCE1eZ[c[T:r0qp.I_]n!WPoDPn.@g]%;oFY7#Y!B`WH<kY9bTql*Rm\Wm8n1mbrHb@CkPu8`5L1.;@Fcq5s:8EeP!u`W24-g8"][`q<,j_H59o<;ms*0SadYt1_pNSC1R\CnU[D_Y<hm@C;p%rIXh/4mItq(0<FjQgrm7$W%'EdirOISV"$>h6!@pQH5)3>qr@N-$*l6=A>t<m7,MC!6YlrbD6fI??hb.%8,OAh]]7!2NZZ7G$"(\R,f366qA`c]J'3F7^hG\3]84*9/W=eP]k0<8BrBm'?dn?lkV1$JS10aJ-mY[aMO8'dI=u7A0aLs?4noj^hbGM_LlYZq(rXCXWiC`J1/n,*4TWS.E8W#\R[=@oL2]MSJe"LX-M+E\/^GkLUbj.LLDb.pTHZ:r%f`3U<kpkubCHO[H#N/AqKA(gkKAF;oH/7's&Z>GRt\[J`t\QQ7,D,7a$(JC!f;pF(gN_M)-]*mWVgjH`P-uk+S?$+TKUlVlLXXr%EJLNo#\/2FE%s4VCq"nlqMCMTCco)3;^R<c)'%(VadQ\"??,'oP)IGiVKWnWd@f2&ihu@O+RbRGJh)lY2HtAK'?'uIUW",@-G*841ILRDh/""aW8GdoJ$CVVn(0ubY"!TfZjmXMk=8P[l6Ha@;ofs]?2F#Jq[AP:l$1D2[UF2'4);eF)9?@29516VbkT,;,oP/W[uX>01TJ-5jb$YL\B"%7C4,2N;af;fuU(\EKO\aM_$?0Qne_<jFYMY$R]_cD$(>WFsCWip`!7%Lpk7RG'<:][*P6Z+TZfl@50W9d.Eb.Bct/KpkPNiKS-UeTdXTK,nKoZkFOnnB^B/]M)Jj\T<7i(5[rSd5Za%r(4a=C5X@Zq<2+Zb8jf%d5e'6(R=p\R7j:WoH?;!4P?W<:+)qcG#+@@R,__pPk1I01beu(?'r3[jMfKhpkZ]P`1dKLpR2HNQ4Q(;NS63/r9aU9t=J;A%+-14,CG_foPc8Q,Y/8#^.t$-`C6;RiKC"1G+?P^9g.3d1Kk#u",o9g3S8F,[7VJT`8=6#M5bDEW9]H72kh'`:/W<5.*Cc;k&i'P-<e>QZH4:E]/AS8V."WQGfu"LFj\h)Lh,Q1(a>"3S]NL5480+deOHZL.-QXGM%OJ#KmFq4\;qTl$Uf@i<2>8hUXVapGq4XaaD7c@9E6$pS.m#gU)97>>&F]+<.;Y;5l>4BRR:.&R$8ha.rHt-SMVs9)p7K70X=W^Fj-*qn)Q224_X6HDO*;X*?Bg!can<pi?":5;dgE+V@^-Y<\V8ti:-/:IL(<r*D&T6-S$pUgmrF!.T6t9peVm^M)MK@OHBPHjZnR"h/)tpT,n&k+Y8N;V_C_/Q-!%!OT$dhb%,@-s5+e+c;uJUeo:$5W=60NuMS*9&L*htjY)lednKB"HWCZ`Da6stXeKu>s-A4n2kmimZeG#+KQbrSk7R%.NU1g)>Wjs8Ji\eJt2^d+oTs&+VF*$'1@s6lmC3'Ip8V7V23N6W>jE0bXN[QbK:_,0K%-&NR9ao9AR&b[)OnOK)U<b"46VM7<LPgn&n6P@9oX!4Z"q."173>PCLJ:i43mjsL1YQPe$,kMjOJfEh?hfHH>&0?8(dg%NGc'YWkMjR=gfs97VK)AJa!.>MSGQgZ;p]I4G4]d+T&/b&LrmB,(HI\LQi1:+*Vsf6H,oZI8TU$hjWg1kZ6l>$3h()lY'SUGhp/)D5_l_":J+8,L&<+YQ)-PY4*c9uZ;:371=8MZT\JlKSZE:XE,n)`VoK$D^ol(Qa2;6_StCbg?On-:a6jLt=1K=E5JST8%th3+S)O8+mqd1g+8,-slt%mPRN&*b3k/%J2u5D0m$I&4)4gl#FMA-Rm+Qn:`/LEO8X02fi6b.Ul$os\9j/RHTbAJFoMHu59#3n6HWkg,<9O(3)6`A0oSbSN1D2rO92JUcCe6*M"@Q*Z9iOYL'+mK,5nHRb&A;Lo+)eKu_?$<lTmsAEFJ,FP.3UJGo3]p2]0[3"dZIHo#XHm-;,pIj<>:'"rbXkmYMjF17cIM*+U4cWETObfNso?k5rYOaF<6_a@bsDX,i$*4E+b3)Gqnue'&lc?P)5[)XTkGZ1]c!#VFY_oBok2C-ECa(Hm39tCW"qQr;+D[d(@qd5GoT(Q=NY5!^1e>1-lc!6u6hn8sk7_fD-Moq`>;FX7K=&6!.GrIme0[_LRdCHp$llo@PkcG7t7GLT7+tSc503pX>>[oT;*g)Sj#D&YHNY%boC!K2F<$=*ac@HT7D^i]i/;SP5E"$BtW>dS*3!'*E6NEfd=2@Mo/oQkb`5$*f?IX3r^'#YlPc4CVL9_EL2Y;'LjmdP>F*d7L=;-SHs?r?B4<V,@eEf=%Vb:DI*;*YgM@n9D0"?t\qIB!!7hYSWTeR8;KGouX!nYMi`aKWbGhNGZpQG_9&:!s8Z'';OXJZeKK&7M[sf&.TCd6-cW.<2SCAmbWo5Z.k-7XEDD'9;8p\Xn^=c="hmN)/uR.E@K/;,G*B&nDhjdBr'3j^-Q(NdRQIX4kC'4c[I_/Da2:E@I;6%oedB<#$a/rK2cd4,CqI*?3K!J,oCfJ2QZ39jLA6KI3fb'D9dC"ZN!*RBj.Q,N'pH/Vs%I^j4qIIdBU\OK$,'3NYU8J($n:ALhK0*M$0@=Mc*jo`KsfX"3Qo4j]KfV934gtni.L'n&AMl7p3tk`0!YeY"=dg]^!#[_-@<"ke<9b&[6&d&%9p#R9d4@--rEDDGG)*^"iUje*j0"GA^*69Z'-Z;iY_7(e_WiUI%:bJ#AF6d!nZ1Ah,A[jYBtq["V7N7^HVVpm`kQME^hG$Qo4mUdt/9P8Y)?L=,C_/$4BG27Id8"FXVWYpKZmdV@)tcGHa%?u0Ds2>&h=VL!fZc,_WE[;7%.:r02MV#'s>G*]Y,`iC]_7>::%2g8,?55o\^cC*gm=l6?]An*F?78^a+[(O:Jpm+gdFWlGk#2Nas/!@_[6D!"(n.`2`Uq?J"1)F$d2)8Q-ok(sF1?+cKE*;Q(23Wa<G8nVqK@UCL>1Z??jl6B#a0gbk'>u%`7jZOG!S$`jK5Lh$i)Skk1*gqS.4%"@T>ik1><V`++\:OB\NHX(_fn+f27+hQOUfOMBcN!e*aQ_ESOt`OGj!6`1T^<m.CPs:X9Ng?kXTnBl:JNA/hYgI98/gq;RMHa[s**VF&C#O];$QgNhb=Q_4e"C@[o0T)S$XPS$BD5[j#t$\s^L$)VmG#3Pmb$l_u=1TrPZnR:k<?h4<oqS#"8?iotQ+Nn;.D?MXMo)3rL[T#@D;62[;hNa6pj7&H2<AeRjc[;J^F<P6knnA,Pc%(0d52keKq+uC8`%0`Q!TpE:-8;pVkJApQ`#Zf5DXBN/&puW,t)uB2BQDgQ9[!]M-aHXa)<Je\]0&.Qi!N>*=Q\e$F!`K-+b0E)pAo8FUVcA^`"raY\O[)rj2&$N<]0<qP,Wil\mD5Ctp$Ske22.Oo;Mu3&'qEfjnBY1I2nXJKj[U=/*dZHq'cZhH*="`:"Fu"sk.#51nrl)$l;N!cRf4An'NeH[XKFX^jqPgIjOfZsD;d(&air=;@.<hN(S0#b,!-;@Pe)0^d,LI:kmG.l%q'3lTZm!'qltA<Au!*>F<5J,N8TQTrTaKiQJSt6g=^,+M;,`GEC&U*BZ]V%<-`\?1J+%3:Jf^N[G^Ct]JauD)E1]biG$mdIDeCWd'WS5Q?&/M3sk-tT/cJDi+k/e4(`Qk4NWA1,dgN\7JUVCPjhXmMe*i!&De:C#qgd+pXP;b0O5,L+!TC\dn9Lg)FOrak3q6doFHnuVqC:5`!AaXF%%KDJ6*ul;jS2\md/?!STCn*N=#CL\QOiOC7I'%Z]X@+_*sc.W(uEGIQ]>ICSj2e":<;L`EPg%(,NloR7Z]H3GW?j#3RRRP%QI^N#>,YXR+,AHR1]LrIJYZL2]D/aC29>S0qGn>&1:32-s`gQecjF,)fGpYpVGgWTQ&tcDji:Mo8P[-$*7FSg`#;aLntt?)j?N9@>.p3aUHI^BJq<nRt@"P8fK?EfjdI00l53,YGqR-hh1QD15Sr<q'h#j:(CkGo?lTID+A,TTbfO$>9Qs&n.!:fr^Z;Pr7W>*-H@d7RJY,/G:DeRdho3VZTn'm`LTU#IUA9FA0%/`niq)9LCZjoX>0DdM6dta`eYo-#^G?$65IZ*Jrn6?3Ap.RTDZeI=E?91&Qp$[A65g&/I.<a7]-8cS\Ren,?8XCIq9hRB`?Dr8$\r\$1`*EE1&3SZsl%H_j>eXPifFL2.GmomV*!^tBD>WJdVf!e:)'Li6C`T8#H[`P(AC/gd"c#B<XJ%Vn_'ESJ):I[UF90lR"l[Cd[qigWt9'596YN-H&$CHP0Cf(jcQl\o<3M9U_P!^r5tG-_cbCCXnMCX=#RNJ'Tu[CNEW.7uic?YlC;JXW%HSj#A6O$i+!gd`DfZut.q#E*qa,4M&@Z(^GW5p/u,8MCiOZl#/C;Apkm+1I+ElpCs?i2s4c.h%#EWX9#f.%4HUK>XR0*(We_cr)ShVR%uEh!5O0Hj=-*[kS_"(.\/mGB<b1HFE,!-pAo,aq7$15X=m$K&d$pd4^O8kD5PqEQ9coEob\J$DG`+crf<qD8"GpRgrVSW;o/.7Y2IB=Z(q!dLFUnIjLY!fk#!BqX)0mUu-dJ5D!]$*MK(8<aTK`n6=L3LZdQu+Ee1"C8PQ>I6c12kd0Ql:%8L\i_tYK57ma6iM(fCDG1N+6YNbOm%]-!`aFC3nO.RrK\(.'r6Z9[gNB:YDj7DDpcYm5%$9\kA3+h'k@X[CoB:8(Gp?;i'K32bc!%Ktf``gd3bG]S9stE/YtENOYHQ))fsf@fAb5PnA[tEG^=B$_l&^_`-paf([W7DCQ4lV2Os%7k!Y\m2:dH22r-)ZH",H'sC7f7b5G=hU"NXR2!]Bgq?.]ADpkB@M,tgFnG^rt*]\@[G_I.b/G8K-*.W&,>..HJg+S4r@E_GD=VkcK%M;6VmAd0m*8.c'"h\WkScM5#O-<iV_H/P?cfQ;4DnT^Mq(d_,R+,YP4`e5SkSc5$kjhoA$djpZ'd4t#<,*L\pD=FV0Wa=H,\[8ZPkSu5of_Ogc4-)I3onRC+kOY"<F02J'Rod]d10[CC<pF;*M^<ZZChr^q'.Zn5.6OrR0;PH\Xgc6AY(]5:):@mI]EWV[_;f/SmI<#7.IXUrVN7i.5oO8P&=o6Wlr6[,ABi"fj8,nNgVUnBN&MDK7e^l`/pf)=;3r-ERo@X,7nM*MD0nItaSDIeYl#85e7LZ2bbjXtVj8-uNX0?;BbL=*m+d-pKc*!d26mr>ES85mSUp>KLb+;6QmhNerAH#T#.\Ig[DA[kCFmN$c\7[)(+3;M1i#E+e.AY6fF=YM)#Q13;d>)_lg`Z$o.RS%ZHd>-CFnHWM@C\\4fo&\T.]Qo,`Xt`%C=7Q56l$gVrQ"*E,@H`>Mo:p_Hn(QIX-4,<l<R:W[QecEcMS5B8\dZm''$h?a&:XY8g3sSMKAn%L2F`C5eGDaLf8N:kT0:<dcN%@.,K7b9@]Hf!36eDr#2JiD7'\*ZqTUGO=XdQ4S3N7Zm)1/gVjVWoB/sVnJ,GDeKV=G%NnY$&E4'K.lpT:^bM%PJ"@<+U2hTS\9%0b&F64_q^Mj:VA&M6TCKGcA87E29_qu>/d(3;mp4n'ldmDNUbA(?q+oj71?9pTPH@Fl$R:*Oa_>]i'0s%H@7&W%kh1(dL`4JbJWb<no%\?M0-_;F+/*.=D3I:B/;%qCT_^04%;s?Iqhs74Neg\Y>[e7k\ja=ad21F&&H3K'$2nd`i;G3cf4Y8CfG;C#^*bIQ'YR;/`Y$bA@WX.Q4E8eeN9tDb3bE^:@g!,6eUUS7fL@8f+-)mXm[b8AGj2DM8n@-mDlAoH-cdhc_UJV:ig9M@2%qsO]YSAX:<a)2[W1,ES8!3^V6#\)[%C.Z=-,*W]?q1[S;%V(dkj";^P$dX2saHE0b)Cha&3ARq-QrV>m[qeQ%`#L/"t-!i4ksZQFBI&](2W?5FjsM?r(h@`E1<7X<--\[`QbPI(G!3"?5WZd#Rob_FFc7h1ZE2)]MTgdu4mB15l!qiU4c[4(%qB9$9)i_;aWb^q2pZKXQC[[kcA0bngD1.F$k&RN4PATb8tKV6R^C/^c?T0ZXlX6=]"oKQ)RirrP[EgAQfkgV+G"f3'%B/#or9t8/NYE;/jaZ$Np?DF6SCb+T].S,/9ouM,T\"'afDhYB-&&aofplep8TOa]u`r)a8$]>og`rm#bM,Tp/=#+Bu.MX<cKQ&<c&<b"02F;JHs/M,r.,TI:nY&sG,(Gb.aAggC;K)-<d3@@TLoC-rI1JtT8"]!j#W>Z([4a.6Qo6s;8Ws1DYH/A\mW,@scs7<$RRss]S8skg@e[=^[S#uYN?0:EC1fi(.(A8a%:<oXBSgU:m.N<\R9q%h,Rn?H:,ldQQIfsF/ZZdr]FD9Uph8ODd?*BH#%t&)$*t%n+XG'_?uQs6"&bU![4,n8aaRlm'"nb^I5c3[I%'tTBf8n`PbR=Kbo+F,&QDSUkW%Smq.Z0XUa)oIoA8iJ+.1jZB_+a2h/VK)AHDu0I5kkY)NF6h>W'X6Lt6[cKU^Ur^^J^VRstld?c5J#?;,.cY9fs&f]CULa[lfcl.fgjBO-sD2Ui^6%WXm[#>F8>/7'XOjCW.F9:^c3Z`GqTpPc[7KT&8mqQ<L^WTb5"fO>:)iq:XlY/<oTi=,7$;JC]n>hh.[Y"sa,bEXNUMhpIS^SqslQZ307-Yd!Ydah$t9PVderp%SHZ=^ei'-tK'K,ltj^7=Hn9XF*:TgiOhHFpi788*D?AWZAA_^;@@D%^=.7`bt"9hrAGWfE^mW7>"^%[]8_H<KDl*$.So2DPOZ0f(o/k@WR%<.PZiLNV]F`\QSM'0T5ra?_B["fg\g-0OVTfNQtI9)_b\;?CPa%5K:oE-0DcH2BJ,'4!rd]C<mdNZ";?KZq)9>%!?t'd-)=Y`jF(E:kU&lO^URaq89em@QANFUlnDQDqpLpi=TV)9R(W@T9nd.#q<KdB7=1Kh]^X#dEe:8X1[_ngA<J\X_!]\6#ESN(/^<]h(@(6CLCX,eo4@-o9DoHD8ja2iCE&%&8&W9CpTD>0uF)G[A(P`0NM3H@r%a-p'V)p,M4ph9&e)cD-elb=l]"6!jHONpkl6T?[eEegg#eH':/<9)>PR%)Y$=lQc>,^deJO`Hr[^'b*U3op]ouQ#'OV[S;nkVK94YZWM$u!2P8X*SEt8Xd@UpP<`:Z7jBIOjm^jpF.fboW^uEG(c;N7l]&7CC*,Iq<k^9ck`AYIn75]h(s3-t3G"3h`ChF?<_\.6CeS6VH%]ggp2Ya7M+0*LR6f5b:pDA;,TH/Onf7=m3S-C^VX:,jUKR/"[5+_I`_!+/1rZdTqE#X43=/=+L^jHNh_RlCUA7kEc8>KmB,geP.8J+c>kTZ>6AK&;m1]fXaG=hU0:3JkWuPG7)d5^TG%HC>`%hZf.\)@`]krAGVBom(/DHaI71=L/Wq,Ve9OXj+)mCJ?,gG$u0/QhK]]IZ+]q2sq*,stAh2_BCI+]]lH>qVdbA<u%-[9AIf/^:?<#5im>^pr&Mqkiid+^U9;pY,>V58Jme*p)JAX<#$1"$QV(d34*FU7ma<j!#VKdjHMMNE-T(-`/Pd:WkQl.MLgNI):N&>!k[p=kJt@+.Z%Nuo96[CoUg*[b:I;]"cJ??C?MVU[E5luV#oOSrJ=<9'P4IWAo<Niq*>AHRbn^f4$E[ikZWkgH29a\&'@`==#B0a;egIM8(4be'>\7g\lI$5Ic/iS,UVGLgePmCEd4r\X6G>;^ZKGs%SlRuVr4Mn_>ZlEaW1pWW;AY)l9"Zt9.Hh83bSdYGc(4W@;dhY]d^P>ug+12IP4Q'[j"^)cQc30leUrp#?0G,EaO9\&NC76OS"jeVkL2r<;bD="u*].`4hS+5Ntc_m(UD5d82JPH)amkr^rNTm*UB+>X^QYg^XiXbU8lR:`1SFN26`0RO5Via4d].rnXSLW_];!sMR3gUQWCj9$Iq53+S(Qf/ic5F\(4^&a0B-6kQNYI<MbHRc_(k#;aLLlT<a'7"KRtagfCEaJ[3@.E+.69TcTXN0Af?7FuIAn`"-05]SA.?Yc*rWEm3]>T8ENK7#B>!>Sgf)Chl'g^?3qqV&dVFsTY"5+k712GaG/1.[SVMmiLcYrA.F=1ejU]jbOU.@VC5uJ+Ec*?lY?3;!E=opG5s4bL.eQuh2T]!eoI5cH\pCu7_oG>j6Cl"7C).8Y5&_Ep5NnALc"LUAJXSd&e%/;61/WE=j#T(cC5]r#-)Vr?AR&h-Vs.C.&Q:Q:.Z\jug!`XM-:oJGTqKi6T8`$bc@5(=9oYS02\*@OU:YG`4ref=Vi^+/>koQp'7n8o&!l<RX].kj3[9"]..3I)Mu.'sR"'+6A+JW,pNB\u2mMTt2TJj.PB#Qsqfk!2bSfrZS.pjq);TqA\XMhX'0:E-&lZ!qe@+*jC:MW.d/'KKq/nahR+T37]&1,aJMkc/+U*ILDCa7<*X'<DiK9+Q_a^HCqlKJLg%"a*NYd'&MZG9CioD6hod:?(LcO7eq6]nng/6=4X$F)Tn0FMa.=:rk:<#$HnI26OJ8)s:R@ncrV[Y4QRZtm]aNM/5@;bRp+3MJkS`FuR,ha20Bo)lN5I[EHmJ%5fo4DUm,+jp]B/Vg:S[J,hlIDpEQfgL)&$&j&XoD2\DIaFVNuW:hf"VC:Fm6cLH5pKp^/G2r*69?0;I!bGV6OWTN)\0qVb(d>U@e>4Oj,oPR(Qoa%L8;*9jEh&V(ghbp97diCl,2?Q7;4_MNV:04CR[FOrGb>l-UqkKtts>1c[aC)LO&RG@Xs^?B)KKUue$#h1"deL'P?+lYN-@UQl;>7GGA<,B*;);LR\N*1'd@3jh?fUF0fk(Y6Uk`qU%!QJ#1f[OcM39WOCO-?1?Np`VrODJ>EUI*d%,,21oFdmh?Ch/96]ig_1u_mQ\nCh1[u.`V3d]Yl<[ggQ&cL@R*[>EdIXBskiVOrE&+hpXQVQ&,k6Zq)i*E]$NRT,D>J>?.N<L4lRjjcf)SL5.!%CR@<k<Q32U-68Zoe8+TJ\8"^3'Dh])OX?ti$$],''jK2:i@=.Sl:uJc@*Fh<NASnlPtGB.),88:8AggGoUASgCLp04b>i:#kVH=<Zg!a=NV]c,`HS$3jXt]0%V5BNmruq0RRmt,CC-HXVDO%ECJ-e6[jc2sQBZe9>0$9d;-(BPHAn?#h%L4K9HI.5jYs=Fn9rc+o9u@%8g1"q,!4]2Arg1"W$/$8gdZ-.hF(gTotS5*+fc<<1UuLX8rADh8!/d8Uo?4oIbbts/hBps`QEt?c0`IZ0@]+0d@W)R2kt#XI8(VYo/sZnViH"c>Y-b^KW?t#KQc21k;d>lBY:sI]EG8`ohDV&qX.pd+/96iQaG#.nEp-n[SunsGN`"W_<?3]8<Z#`8=JR30%8*:j#A/>"o3%6AI!A$UiY+#0:[Af_<DAfl(mA5r`n.sgM"[!im45i=\3_6%q[+.1Z>p>Z(Cg6-6@$%83[Y#d3?1<fp:-W]e_<.jI+O+QE!,p(u2=D/'ha9"_VML(o:Dgk.a/f,EY;o/KK%(5$(8/4;:Fa41Ec\D\)$V.#5J4Dou%9_rZJ?e="u7lCt?l-IXp-F\EX9<4:pYlWdLM4'Sa&UU(iig;3PXh2ZdIh:Z0aLLj9>g1OS'jcZJ$dh'sY)e#SX+(L&*bO+2PBuQ=!G]IML"eD4Kb3_e\ZVXPnRhc1J#7OZ$+L#:W'bQ5hr>[HC>(oq@TqeNWIAbGsWBI_&ULlic4)h'F,@*+>j[REVF/)K_,W:&C1Rbn0lA4[n^h0<82aOb%d&At)G^5RTK2*Cr47ghUc`[fI9rn]>5C,#k@qhBf7TMK[3UD^fEH]"P;KjjMathq<15/U]5/toJ>r/G2M3G<+g\XctYGaM`LII$g_JFbB,t#nuV=Vk_cr1D^NOY^KBsOtN(Wk)04&EK7cR3HcpGd;48ss5e/h*[5A7@:;b$=+CB\c>'Yr^/el>+^PgpPSSI]>=2,X2I;mAS&T#;0qZgC/2]4uK$#rS#PLT+:3D,$#9C?%u<g1\5e<7i_*7@M\p$kgM]<Es*drN,bGKiLA?9Ai;W:K`b5X5-sE-PV4s0lL0U%%_9<`@K@M_ZVW8b7A)5*bo%Q?ht0i!Ed/6JX+SsYUE)=:SoqgiXKYGi06@t;i46Am1-ZafZeo*X^MdPm*\*mGqM(EkJrQ::E).0jm=p'R&,A<bWD8=(>f(CTRd2p@<'tPM^5H6piIs<QC__"(N`7-38`=F@jpB5k7^<'8d@I&_0W6WRH.Ao01&PqEoZJkF7\=OWoj_N@)l+egVZd@qR-dkmJiAgT?F^2Eg#a/4*$lYYP#-!D\i"nNc$sa\;W'lb#WmmY_jj;(-uA$oI#h^0V=KN?V:=GkOdhd:A\d+@cA[AXje*%r>q0i>B%K^C,A6JXPiU"=B+m"p]d'>bLc!$1<-78.7bf,;`.m;C@RB0/`6L<OZt=+7i&(jY!q&E:V"C4t*l9cH<n$g4@!6C<&rhe>K5r5/eoP:pdKslE-CIH[L@/r1.P@7$7>XY!FdD2Ok8*Kl9f$"%,QsO)4JW'NRgG"Q>'1d/0-6XOJYJkb7('(h,fZsC3*cg16F[BO;hM1![RgeX_t,`m=AD^]Lf9_l0;lJ^S`ohGhkH-7%[[lDPAuDA#ZT8d,t_i"L5UiqIlnDa=>,g\N'VkhG-Bu!'Hn;I8&3&K&OD^(IT.V'6af1X#6jOK@%SGqJJQUCrR9oCo=Is?i2/C!SG'!S<k8iQ:q/q@c#jHK]S@K/,oI:Yq-'pmP,t<rFQE]**SO_;_bU=@c*/FaK9io,I&W-=45O1L=00][31Q"plq<%saI\tuGemM(4?J@'/%h^`])1Kb5*N$@B>#'+eW[#]b_Zr%CK`&rdbAJL[V7qmYh?Vt!=>orEa\<tP&Q'.dojo@5:\\cdYO^2i6S;uFVq>#k5EIG975[Z-UaP"]?p,U5)N<=VNEpjLIR+N1JhCLioCc.A1;-oFYrNCA$g#(0m#n0:-%W#lSk>erj;ih2%@kk'HSpS28JPl9o\Ur`CO\hP<eor$,f1+,0T@r7>%^V5[\.$hQ:G'TjcFEL-LuP",<1`ptjGEjd-g%=6WYY/mJn>c@4S\b37!$fC0_XK%nK#>Z35!:B$]#mHXUpGOaftY_rc<p3R1N6p,h=N<)knkVQ69\0-EBNW.(]Q?.$_NJ(g]%l+i<9o>oB_#"6D=BZPP!D"14Hrq!b;;3.o%b]h%WCsX7_dC1GqX>:Od!__gc^RLJ-!?r+)gp?N,T^2N)/%ZjK:L^sB.l[nrL6da0,CR/kAKlL+V\On>fO4FS[>H>Tho2>'q^\j1mP_[_XEbP7c;rV0q1lS#m5_iFf`t2?5dr4pJ34WK/*4K=RO1o/ogJ,WOD!4848qC<6/qp*FNqYEH&m.oM\'\>i<n$mCp=N;@#tMVOSCJS)lo!=-?NHR9&cEd"_O;E8C)_Hg-iD]0;J21XDr(X&CVU$#EW,<n^VJ<.T)4/agVYDfsurVKnH8C\H4%O:UB:(H]qeC2^c=kfuN5<D7XDCA5!g6o9[0r2k7L3h);fP7K+q8kn+=q+<VaWYT!.kCr6Bf<[BLhCr:Y?u[D\QRCEBbLPb:a)dNQJ#,t1^ba;jZTI89?DM6G8K>Vs%aHVoDE7ELmk(Us\=860HT<#"Ol<jNi#'k0S^IR+QHd<(:VS42Dire2[R0/X2(RJ_66g4%B"XasWk"J"W],T:rg!b+4Uh*;qEiFuj(cRRQEK\BL\@\&aZ]gmV6c/*d(H^"59am#lkr8tARdcd>%W.fGII65.dNA8U<YVVbLgU`Q-/T-knc+H-r4.:C#GPegO4'$Sl(I3cl%gGHmLqUXc1TC[BlG`6+4?C99b%@?:"l6-]\`,Zg`9BZp!D(k%.[rQ(;QS^rWmhF%.je+8$jODPrdV@R"MkHaZ@VSb%#H8mHM88X0.`]P#sn3hfp'*VRt"e<R>qb=UNh0'8In#=sDcXMdB=YZ\l6,'>3h^1!Eq9J4GgEncUPVp@Qm'?JV$gidZ_c60sE;eK8DV#YYh`mU,<,>9:@0.#AN9k8hI@2&S&,je0X6>aII*4la'X_mB.(E=:A'.G`!5Y*!*a3:!o21ngq<d@A]RB1Wh`"pbj<6OeLHJjtW\N"9iEK2WY$2i7[D0^K/.l,"0D"N<I*XmM_PY,SZ&\7_A3aoHGBQtfGj?V;&k-l>6%;?P'Vb#%NoN!9TGt"tXjY$EN.+P&Cp^Q&X?+<)4'Zl"uT*H4.+!2+==8BW9-@mo!)%W(10?D^A`<Ls4>'=+YF^uDQ%MBaa7B<gR2uDefk%Os'-pf\XrD.%amd[Q=SkWMKcT4nB7_V\HPA.8h]$8N=8heok)\ke@C%3`R;YWd+LYH;\Q_+/ZZZj3.S5,[,<T9]Tdn)gCOJGPXggSLm4sDp)+;]]6ojoTu)c;Yr*E/^Y#,C*a`[]/Q/cuGn"u(rl.AiR=2U>p"V%=n^2gK12&DeXLT9_o[SL/;]f.Da4+#'7&<Vu<^2H_5nNZ8rbAV="b(,YZk=(TsB'$*%5?"=p15_R:SS1UT:KnQm.$4RGH;^I3/&_dn+HE,Wn&P,bb1ONlEJV\'Y3NOcg9+"o5,d=%DO&43%@fhd3Ubn7_JMcL670T#t_GgeuVUZiDRXr>dBDN3A(XEn@QRL;kBfQ4/=#G)7b=.GkXs2LV/]&[)VNYolesf);=tkN-938O@TJK5\B':WsD*\Fm3@[^IUs1b>kl_<jNJ?^25r_F_A>^'E6&0VX]l=H8m+,3T-SgV]93)OB^:Ctm[mqc$;eEP.eiZ9G=j[2F4E):"S]14#(:*iHn\fJrT'WdfPW'/b#6I^^"AORt/5>T\fPZ0;4_:^!.:FiZrUHj.`,=,\+gP_<U_u)_bWF&m\1%4a;9L?/h>?iXq!%SK6"?NN=u,>Il\X"]RIA7s6Ap&,r_0n6dTW72+48*IFZceH<mHZj3Qn2V;JbdudE,0e'Xd4<XJL5/02dTd##tiS3A<-Fc;(.%/[LI&pW%F`jg_lUF$j[ST\"t(3!s;7`3'Z,^$E9e/jI7j^*]f+cS6?cRW(>Ef,D*j4Cpl\HSsLB+A`3"[m^ZGn%OFI\$8<`c.XeM'ZQ!h"8)A3?t,7kG,U9tCB\q?jUD?$WQsh"a.^JsZ,E?<gEp,:[Sk1'XR-Ul<(XTJ]1'$1_&J&F8nQW&1Hoc*di,)(jdpPM-)ED0iA)+LHc\>p%hihs9INO0m,BYD5,La44W`JKdsl;uWF%6,%50LnU.V&rJ1K1F*hFb*bH#@A^-"N8+3?Id/-T-*MSFP*5+Q85_1Dm>S+"nn\L87b_f>+C0M!B?>4e?QYcg+5fQinriFb.dETXVI,$35XDES6[IeoT-fHm#.W&N=059gojM!51C%=2*gp`FK"_*dima804qTj!']eO"s4`&^7Q"Ga>ZiVd\[1o,8sgNdGIR;U>dh`"_$*Z7GY?_HQga^q?i)u!Q>l7b[#M!phcUQ*APQ3N_58Er_o>ucJ1mYpPZBsPgFelc`L0c?0f1/-<Ek-bg``1W-+I7A6-@M6-tk>G8b`GNHQY)QRm'ea'$f`OUm:9<$>W)Zg"QIM1s>.t*t@W#5:X@UV,S[3W9b9p3.GqJG-b8TO*lT3C6<6Mt%Q0GA,hY%:V&odf+Wd3/?&sg#NP%n)uC$TK7'TMlgHEA$D(&$$D0M$UB/K[Y)hLMERCh/L1QNBIIq)N_>H((TP1Kr'@f3JK@EQtScK2a'XXWlPE\3_c6ZE<SLRhI"<E./Ur[+Q!`'YR/N\?gptAVuN&=K&Wfh5<tE9^R8)>pe8oQ<&n#32L(;H:?@H7qmY-2;si?F?Qt2L0@"?:))@CRW(FQA7CcD2J.-V;OF=K\^&\C85m4q[Tja#Z7DtC.QpXU6+1"a=)D3o".CX.<#\o,VBP>!1q6^tB$iGLpm9(mRN]S,W/ci*7p@dt/c)%'pRM$K_0RV\01K*6d:T;80:!R]k,a"SC#/4JMijMc32iARj2L[h^#Q;"AW`8Miu]SV%:\AcrAU.bKr`Kse@sI2D!*mKkt=W`7<uPLdoC#@f[4EVHtf]2r#OlRGCmq8)a;mD`[p^>#:h^.:BCro.\]ir^IXW5#A;3ji!QdCQ0uP)&lXUMc#Z*4,'uNhA;a9[&8:St;O*gN=klq\qr=LCJZAm3V'GH0\)5/+fmC1cPHn3JiK^,jjiL`L)k?&B"b\79[n>ae'HF,TEQBn_5phT\0)O"mHJ$VAk1?u'(4&)Oo$TkLM,#g^-a%ARk!=>XF5c<;g_aR)/<&LrZ;9tKFiq:1mVt)YZ<f,TM6XmkS/O]/PI<L'3$*1dE)#Aj91u[oHRC[H(iiJr4VW?W*_1&Z-AXM`/qgsP*T+5=Te0TQk5-E8VL./s,=2mo%3qW\F>I-8_A@\h%2'UQgkVm@0nX>5"7trS-q>?_!Y",!URjBAWnc6,10X4N2sWT%HT:.,SKKeliqN&1VV'G'0'SkeLOTa`@tn:A0C?r4lnZ_811muKl#ZKeh2"O0R>m/Z,8-$%.%.2ReW<qtM"fb'+YlVG5";jLV7%;Bg;0YE7XNp)U,lhO=*rL?Vt54PhKcC(GRHZb9>VL!%n+)&M^!#JD%1S]-7YJrB@E@g3+tKL9N%]h7IS.7P>R^_GTMp?%*>c2j?^blPifb3=t7l\U:a?pEI'eVO;`p@FsJCgde$<;!M\"AW:-GFU"blFQ)ra-og<?Zo&3*%ofY(dqas?UTH0@#6Ximgc6cn.28W7\Yg*NZn@`b68p.MkrR5dH,2V;7bF-NOXC`Gmhrp^*oerK@70\/1g@Ej^g@9H[31jt&.5B;2<mZ0;S&>SUUug*OY+nF,kr>06D^('d4L\L+rqhf%]/@6Bb837oLE+CS@apX@-D%5KB0"\RrWHG?[Ce(d7VpuFMr3TbMc'9F6qcF==V;f>B6?g;108:<G?I]d^15,rcQ/c3kG8Hqg@M]:XQ1YT-LuF#%%,jWg$'^J3OpC\1g#q;Z@<L*?5L9&k"nY1o(jY;MiMFa9MN`X7X0&OX)a?^/ZSdSI0j=F[RJ=(I(_t;kf?&P../I7)$Hj3hj0X4B*Se>9[>:Hc;L`m&Y>kPBr.R4:a2qH."=Uf:@(X&?d&#Q3fc1!*LpcQ4c)8UoU#^=2AcSLrHl1cqVo6pn@e*p@@8/<qG6PLE]Yg'Ue<gM]c>>";Wo!dr28J_DW3AC^4Xh<I/H$Z/,+?KoC)%(A`ph%i1SZM_<ohm?CXf_#bl=NhNH'PW-!%UEn*4*2oPONk&3B4Y\A!][*#6B;"U*iY#&%,e]GUI5C<:([@\hGF^G;<,MrGt``>d`4Ir5X<>1<'[,:.Boi-12aSFk!n=G(MKG.6c=O7SWDVV5_hV>/q,iUT&SP%\RPdZu$%j<fnr]D-L^D-7,q6\jf=sH"PhGSi.j"mJ9J(X:8V]5A#4R,g=]q`I%/^EW]"d(bh2_n3(9hAN/oFR4n.0>rDWe$YC`.?n[):6FPqJ^hDRtu\M\Ea\Qrh[aX[QR'PP;rK%#n[*11=Jf*h.a"Wh2Ga*jtijd:4=W(OK-tD8N&u3=YSS%VTc.!c>tW*'M0S+:R5Oe;1(;dQ+s/?oC'SXd2g!DRksSsTQ4Ki(5bqcB)\Z9%K5HPcW;2.UJ9LsT?)2T2Y"_1qd2b9+_;.+s0BOI]X5'*4L:]q:3U[MM8U8@8c<HS?n!9<(+%IZLXW$^,]O!n3L;N"/u$'I-rDiiPS\<=CHUYb2E"2G+Yb1C$LKS#,SN;(E;4A^B"ZI@X7e^6_W?RAYMDDb\o$BTr\sjLJRA8K,?Ibde4reQG+TIu*`3Hah_fRBpH0\Bjm+qYfCSY0He1AAg@uTBrK+<C(9-e_-(&CF(Q3;>oHn'Z[,U614!u`,4Y))#Iatf""n/>S3WG?DVo>7bdpL;Ug@)KQFD2U>JD'^I%mJr5#)%>!r6RCa`bRcnH,u:6"C1t"\%r)5ED=8JBnS1tH9LHBK8L&mIQIlPGW,*-R++q=!]uhAqCp-&o!/_0\FDKUe4=G&^?:;-*R/50VR1J"-e.F<=O#Cc3uTPsXiS-rm.;kMD;s-,LB=;ERj)[IN$&bp;l[?(b&!@Xdp`6X<S8-5bq\!sg6/AkQ'UdXCBg:Z,.mfK0rK8'$bOklQGTe2ehFWu(e-)E\AAphD"$e#j>fE-bD1Flh[`?qe*GPT\.1-Raq>^7gj+O6Sf&,,U.&&2:ZgAWEOs^o7K9'n7D2<2;P>m`>M3_N<]`L_!tAM=qGJn,-uIFq`oqd"$Q41p..O*(=Qh5k.S='n`AC]]"B'^VeesRIAM>AYPSG/`Ck?(#+]M;+WkRT52.jIdfJLU:[O7m52e&UL[hV:0&7mAR[`C-W<LikB]=H6V9^(q&gfF]mmIB+KVDW)'LR9H(f_#Y$%(dB^AQ>Hl'@oqhfsMqYItnZ#rK0C(L1l[3E`/"7Bh\m*Ba(A#^uH.66X=)-Z5E06(aIeP;;2XkfDd8@bRhsG?1Ds5%Z8WuSi!D864'-+d\^_]UqOd2fn`9iJtA(HKTpemKRHXXSU-(4jIHD"nodoA(r9Db@_>V0"is@`PmTd?MIO8B2\@F!*_YHo_ItW>T&a*YA3l,MEp>MUDV@_<(tjlL3]C08.o`r2Y,LRp[.L?<@mqV.`$U3(Y6\(V/rriCV%#6Hf6R5`BK[RS[PR45H:<Gt>Glhc)0f+Ggj%>%$=[hP2VU^s\[0Zeiu/bZ9n:?aR#p/tL&ktpHYEp5X9+"7D-?m#@<TJoLrT$&f9p2]4"^NePl_C=N(^uEf^sJ(p3d>b0hY\,rMQo\j#0Sr5[lR((<[YA5l.M6]@mNRXRRG7YGb8k%ABp$&[3,!Qs=U+WLDQB;_q6I"Ai(>&Id1pfpKP4=9c'/W[5_52Orlh0smW@14R'"OWsHAG*,*_4@h^XcCXY(O6M##$]=(2S_H1ZMlkMhcLnD!(c(IVYX\+HSXSMn->%OQB"](c3&5=_@cCfEQ.FsW'e5(`*/%!$+iJ3Z._Lsp+dMZ:c9d`B!VhVY!&[--+F/FCD>G4[j&-R"JZRSmhT*:c@N5^ck9s!d8)-cA\MLQ9MF_Ru\7Ta[K-.0d5)J*',bR8`$a@rdJ2i1Q7i1a$a1UJI3`."k"ja4Ci)\eF_,@>T?f9fd;#+([1,KNsJ#m>i6P)&C&&d/8c3Ftq?MXBk8\A)GprNK!0BMLqjubLVP,o,()CbUIm,2(C]p*;+[!IZp',utdY>`]'Y[A=c./g4[n?gjM4#1]I!tL&.E_:6,FB(9gf8fDcWZSQB'X-NqhI#*(._MJNBDU`g*IkP&fD<(fY5d1Uk/k6JDT(iq]L.5:<8U%A8I%M9"<YW'r>[U'UOjF0_"kW\HdFe.+rQpT,,K#@;Es<uq06B!)n\ERY7VO1*HNi+[0sC7?\\).rP(7p/G7iV4qs1Slg!=rU"rg\WRukg'MA[\H5N66Yr17cAIgoRe93KY\2NI*h#)Gon^%/;Er?]40?HQP7e5M02q-Ws^1Zoch_%.\s'5$m?_;rMKXKLF.1X@B&hrSESmU7KBMXG?T8e=dF&?E47.uX/d0q,[6%soh1JZX]qL?Q#W7HUYr2A*'K?5!;J8$f&C==?_&B$NFN(l.^^:IaK(/B9r.J>TXJ<;5T3]ss[:NQ[OI2#[.fZ[dg[[+(O/j0,oh;S5qO4fZNHh5itEGnY%B]8:TJj(Kpq>B+b0?NY\?fT5Wk1rG/Ms3HUXPiD-#JZ5NcSRj5#Cg.%ar6ZFIh,qqpii<tf7jKsrS,U73nO>e#P!8J@RLhN!@]>nAR-FXI_D;F$;uNfn!Ur[k8FarrWlt1TJ1fSL[Y23E-TF85p/No7BqB&s*Ltu$lVpG5\,N4@hB"[dZf^p!>#hl6Bots.7FC@'JMgNIl_R^@45$G_C3qH+!c>bDE>3+dR-)*(b$bo5gcE\(_==i1%6*78Zp9("Q<EoSE0tQ2Z(6Oc_J::T]]W&O]qbh1B%#E+.r=tbLPe;8U11!rZ%i^o_&5*mU%aHf#<BilCZDQ'e[hfp>sFZTm2]<lhp4t`:U\FO40WsbrbR$TB=t(fa5h4&9HgN/JHH)rd535nGM-UG#Ri-)66/XJ&<d'&F#WdqKs[ek>Uo>>Gdr;GhnGRI]"&FVfitb@"%qbhdgO"qL#o5"bZb^5B!-OVTYcp1pm8uBCYTV2Ys9GRK&SX55skt?hRY]/+[8i$fh.Lg%<L[SuVR0rh"Y.PNVE3Q?kLA?b:VC7"'Ddk*,b_A(jZ?qP>F_1:=4>gJTN+?aofag@sXs1XF7ke)JBt]sMVVX[Cse]Q*B1ei1%>k]H":^J-ihfKM5qp'4oRJ'4*iBRUQN&o=<4_f$$/[Vs+Ih:5#^QOhc15B4TnI/f>k`dSmZq0l>9I=-34V[f0oSmQ^/r[WDANIGg:J"Pj"2%4s]rgEd6O5DTPHK_Ik^UNoas#*BD/b8(*`cJ`=i\*BA1:<`14KY5tM-KOrdCtq?'Ddc"pFs@SbI+F:c/%W`1kS\?AqpCi3dJr@1Os"H)/G"#%YbjhfIse2^TVucCO`M]e)AltIG;:\jRm>$ja$Ys=29G*O+XnB[)&=4=;8CQ,,0g#^I6q`Hsg4oi5P%_U]Df_U3&Z:$f#ef60N84S,/BZUZUS;r?[Z5+mt`q5DH?'[7E*cmHMhS`a9OprEiX0e]FTQn+]'J*CWbU6.&TEBt:^TQZ2[Vm$YA.pG)TD:TEpIGM?K%o;C*`H#duumG%*El$`Q'c@%fNdp*tbiHNjMTrM)p0_"[]8DX)#H?/qQ)r^>mSJf^\h[DA:[=/R1U,AM;:%?lR5hrp#DEMFV`K(N`HG^Qgq@AAGH@\B;_h6.>T$]oYAu<.h?_cA*8(H\p^5na*`RUZqX7p9h@lmK$juTdDp36NX;pY;9h>7,:@ma$fkPgS(EB[`e]1JTgS9pn#E?n=)NuH=ZnA>Yb_Ju%m0oYSuSIP2ACY<k,ir+&PUCVX?>+Z#0>>k=lFtrj+1<-c^iVN-p")8]A"[d-HbBtL,L3\.kEo$='<'CIt*JSO9_HS(OR6;K'Bl#H>;WQ]kd*86%[9?<$4mga2UK@?jnb[_(`;3%1G\VKt[CGRNh@e;Oh^\;:LLXK3^Oqh5rlt\Qnt07Xc+S;IOjH2iFtrZ$;=*+`5n1"ue*3lUp)f5UcAT;__5bc:Ia's..@OunA:ordh&[Y&A,-#[nE^"7mEG3pp=%Xl>(CVWl=7fG)(ojrn#re;mnZcQ^P%$%4jiBQS-`c0_7P$-N@hj,r.bQ`/fMQ!LUn>9&#9"cL>tj[h/mP4e+]K0IgrB(IrBl/X6'*HVNRI`cW?-jqRe%>>'#%>B)569esGH;%LJK7ng)'(K:-@2\O;qWqY8`LSFtVIbGP5nl@5/3CC\c<s&dX17O;.5"?;iA*[F;(J^u)$s+`_Q_1:1_(aT+qcZ,9u.1K8o+Wu<T,\,&qNm\+gFppVWd(JBA&,:U[jl*Le$'*CK@pZLK(@H1Um4;%(GiMt&k,YDikoDH7G)3mjaga5dXrH;m;c9-KW>ol**_u)5K"jn*5%="9[r\IZVFD/Kl1=U4=+blL^)`5iW\.gN36u8a*lOjMN/8]W&3rP18%C?sL*NG&@'M>AA0&4(^SgZu?cZ`c#P%X3g)nG.hO^/8DrI:UT"jnLHdAV]G^h[8olg6s;&]IV&4H5er?mB2s!3)pV5o[@r'+5S0"rFT\'OQG^Ba)rlg$NE,P<%+(\:%eY<;87I5l7r>5:TgjM@?)@K.n>ns$kXCVEo:\XnQrbl>d9HN%^@*+^@Q@,1DrY3iT!Z`1XtlM:=l5Bf#,Qks3)=odPr*Mt'RZf:[sk.8an[1seYkNC%C'@2u-^Kj$,`?KDqR#*:sZ;[+bpJ#2+rf!AUn+L*/FQ^,&YB*ni?["-35"G,;1&EgiH[Ha'*lh:Y>$4&(*;r(H]'%PqhsC$K8c8;ZO0@624O:72h`nI=3BtK4e!op@gYMMJfBJ:@Y'8GC%YL[W+M@$KcVM:aH*d!U>k-pIL(Ib6a>f\f$=5-E"7Q.\N41DW@blSB`EkU^*^1VidLj.J`2IKj#Rm4m7)m;tRg[PnJ2Du?l`hr-3UD!6%aT?<?dQBa)"T9:4U."@3^MOA\uM^/kMX>A34/QBbNSB`U8gslFL_[WJb#uSjE05#,BBg;^*!:OC125iFI;m@ps`JW15+Z."poAP17"(/!sh7>To)Z5AUfrDc4nYoW^LRd!A,#\)g@fkFW8VN*:4t:4cK)/R)P&Z/Z>mg.Z29Va.=8pXQ^CYjMU;q]Rd?-j]f4KhG,<>P^88F-!,r^@khTgLp83BUD+:g7H$q6JP>N`6j);q%`@WL\;`j!'d-s:_*OsFg-0u5pKl72P2?K,SQk(NC]&[1ICH,No>1A=B'K/nIp5f^[;_2lqEC#;blf6ogtY8+=k"Ug&$472K,oRG+.VY=)K7F%=UDD5U\!aHrt\tdhkneV/0P;[\)2c85','2\FgBq$(7B52K$#%SRq%Kooea_7V<hh(9q>$S`Qq5Y_op1^;6aoN.mDhC[S/T.[obi.CaX`X`q6-Y9@]Nn]O=8rDj`PLFi,D>dnWaO0X0ud-\Jq`O5TQ0C/*$d?ej#^V8DPcc5r(^TGH=qaS`]Bb>mTg7of&%-Rt,9ahj[k;[A,kVEdF2kQ/RK;LRN&SstP]M"HRaNrCb<XT(D!uU8:Q\kt4SXKm2@7:rqBj*q0=@=m8[K`j%a'f2%<6Ehi'I"Au.*^SVa>2pO9RuS%!=b+lE8Po[1,-ODc.7]?,;Kd\0%)k[?!K@/0IKLa^eL9/6o;q1\JHY'^eA$;c3LQ3;I7Sle=0"hL2!;Gi9]2PcofJp/V&,P3<Y,cHV,Z`*o1MbFM<]8k0S]SoJ>"2Re+i#pX&,CcS7>;hhuP]GhC)YYGna&5,S1df[p"GB%,MIM"rogYPPs`T=6R8c5j71Rd3bQlD/QNYK[=FGLC/;n`j+S<F;%PQT[D"jIZrYGsUQ<?[m!McEkP5Djs=IhEJ@nejP!HeN/OE29J]:\bpTmEW0[?oKC?=h%0!ELt7J`As7Z<A(I%7iuQYDC=T:5?$U@4k1'DAo2`@!/P#@KL\'D5L1g+Tb:KmJ<f9ACXB(m9*Tr9lnCg*lS9/0<9)#jcK/-rf38tq'#SJ3=f7E7X8J86<W3DBgR":X;lp\`Yaq.,FHAiDF7>Qe3Ja(dVN_(@V?,k9LitsELSrO,P4%V9a)DL[^_;o@jf8Ohm22[ANC-jEff8S`q#D#'3df5B`%j@,.*-pT&5tsaFHT(P3M24=h*rIiCHBSJ+EKg.<kCZe'4C@sF1t1M&eVt,O[PQibK>$\$ROd@)5,#p.3+#SA>)"+/cNJQd:j=,X(lPhqlsZfbPEUqF*%4@#<Wd)nZoI8/-Vjj/)&Qc&A.'S@X(a0raGLlq#oUQiIMJPK5tQ&C+Zu^GY8*>f>\]k_fu^#``XYNhBHm,AV]4)EWefZPd>V%f)oLO.naI\aK<)J4/OYjdo?Q^&ULOL,6FW6aHTdSPB?Bc+UHd"anC[D\BAi\K(p&/a/R$j(B@4'9>lGIoAGLI.9uY021&#[f]bB<;%O]5]&Ui$ur)4sF+2$cQ;6;_`B'`EA%SCuHroH^c!nPAW\X-@XE`[)3oB?u5obX5P[a'-41/#n,):Ccs+@!<'eXSk!HY:HQK4e[lj7'<oYRnRS"?*.ZA;.)_DV\,]UTBFjOt=+Cg9q9WRM&C_MH"I*mAAT]W.N`a0gnk.VAPgB$[sZqajE[iA%4d\_dk0gCm_IK=D.%-^9ug[IUUVVJdJ-H71s"\ag9p/Icm\6m`,fQXUs]#@+`IHPg2]Id-([9eg!5ckqh+6jVO.cJI!fs&mGK=%%%8[[G`r4+u]kH/#S'0?eNNJVFj/#-XL7naX@B-.gFFQ[]LL&$uJTC@S@nhkCV((RsV!J7Mg5e,\j^Jkpe7#%.%i;&Af,,eJdAl:<"9/>Zp;pH<O1GYg+R0YZP\3gmPq\i2Na'd<?5]W8"El<H5M-V.n8@gL],];8a6ZL9?Kpo52VZF`L76BUBi!/b$Y7o_2?3&gDt&W-NTklA_:cjH[t("m:SYdg^e(<I8T42c6ii8NZ!7@n`Z"G%jZb]t!>se21IelucGiB+1YVfuEG_XX5o:7V_Btj!q8Q]ja"R)r58q\a@e`s,?if(*1]@inaL5Zqb1u&KfkA1LB7Ykh\2`p\u_eGI*1)U(0l;FWV5JBgIPj7in61_K/27r^$*`U74Y(E/m)GVJkQHdHaB6Wjo[D,d6lfN6DVdnmO!6i9r7>cbABtCS!MmrdAu9Na?ZP9kZD2?;6O73E'f2iML4t46nE??#Nmm3WucmcPdNH@^i-N>.N;.,n6p5d;:X2DZ5fUNEP!u[q5lD*^bo;::Pshh6-PF\X\D9CQlSm,Y_?5OduY2,au!@;pAXPr;45kSpBCeI,7Z.Tm,;D<_uMZilq(J_i2fLB2qA[X\'YV)X"7D?'=FbNSAdGI(VqDf,PZR>Vi7)Ra!g7<4sqiL2,;M;kJt;K/^WShQhc8X9s&;*HZGIg[S:XCFN*@='W1U=aO]/.u_c6D-#;9qE?uBLFmZ*61Sek>1'91G@tQ7f[0^=#%rg^Jq2/UPpQcf,U6!9l\Hc=.?:-]Gt1VE?`pl=B3eEZRkt\/NL"0[%Q\%=g-^1N3or!?ouJG+1un#&Cnth0[5%Z%*^:fq:HlHN@jXhR8,ac&'%b?W?68509j;WUo[[sOV&O$BictCfYiH-Xn3-L39r:NU[o4IgUo+HT$DPn9.k.#+RJr+%KZ-P0\89&H$e2HI-uA-6K3AK:j"n=AnY9fi6]e>7AA7:-9(];3qmbL8\6]Y;lH1dYR:1hh3&a?sUWN7K9k+U2YP!ikruq((SajP92-0Wj;Ej`$CsA)Z#95U4Um&rgKDT5mMnh1oeiVT77tWNGO.D+/"AmDHRhp6^GHF'=:nqA>l-%fb/gM4uJU5S9Ys-.L4VM.eUO2Jo?HT(SpUoOt:MS-5$f(pnVBJu10XZJ+_$Di<rpf<NnEl")$W'IAE_hb%NhK1;\TXBj[[!1I2e5%.AVm/f[L*p^@&R^]7,K*k20>3Kr+N?FJAS9S\gAQe.Fj9AaHU6d:Lqdi=^s7jZWKC`,J5mh!gSMbmA;aE4H9lt8K^2K7j@;G#IgX!\eS:*cES#&`f&qIUT7bD`plK>FOUQ9'"dG`4ZLU5Pm4*#RHLFS=@I8a;b\c*-mOCZ#YcHE0rC/?OYg<>4%'tU&b]DP:iap[XYSf#I$pGIJqiC3.:b%lc[ZZ8US`]<i7^i=,)n#bZm]o)"q@i/PbUoe1hGWKIVj.8>J^ukkV`:*B["TEa%"WSHNo(Rl?`te-#7i_2+*eHcP+L>BTb0XOsNYA_eIKE@k6EQLLrhTX?#t,B(S$JZXo^F/5>(,jJ;4+8Y;!FQOk_F^7;A2i^VR](V3)IU^=;2+6Hm5!k0:6`Dd)U$l"^:QDZ^a`po"JA(e!t2Tl`K>&fj!ELWCSL<]mGdkn8&W=J:9<UcT>O:NL0Kh41u4QdbbL<hdL6r?plL1bradUATb`UM-aQV-LXO9ukZH_5.*.u-9tl#E85_&&&7.)lpVVkcO+3,hh57gg`pUdf=pJVD9V=`e#loNGVK"%G*=%6um4S"&=_3(l[J>7baos&H;._]ija=t_VE:/@7[:/QhKo:+!HY"^jf.HXE:W+S5H.U+)uMQ7*[Y[\ET,)S!7g=?'M`ELJ"<2_:ldaGA(-^en`m`hq*+0JcuN*?cA>*Wdd5sVi5efT7q(mLqIRB#fBH.DWbj+cZY:?J,924.p8=.;2%G3>d8/?_H&71?EibfbsCRonC>2MLlI&XL_Sk><jQ<r@='=:Cbn>Z,=J^%2nTj(ASj\'B2+W(a;;'O=A2S:W7-PuUblMa4ccq<.4e]30$m2W`-:aON(NEQ;;'4e*eOnh'TYhD*uSgVYD;2GWY82>]Nghc;7)`2/`SB88!QYX$o%_.+7h`h@pqlH]r>nQM#`YKt%?D#991PF#_TCg;cFFSXoQ1tr$-%]KZi?H#=(iG'jT>4Qtqf7>uiW63&[Xc1?%^VV\\S[bWJ4R]F#"I,qD6X].%dVI$?$btFo[qK[JWPr1S,ClhM%jVRBejXm9ej$(1P-[9Kk%\n]A_QH5BD9DGi>4(O8p<ZT2YuU]L%Pt<g&rVr>/qc,<3#sWoB:[kW*L.(/4MuTb%*W2Z\l*>\LLA%e#oM*MmuDQ*[cJ8*)Z39H16@SjPs-1%2Ia))\'[/:?o8q=Nh#)4<a3D-B57WSaWuCO$37gWq<]8Uc6]CDO-%5Xt[_:qQFbC</.i*:(hoZ'q'lsQrdkc86)%$gkuK-e'$=aeDuJG#99qn5E-jfEAu/4GjM'LEs-P.Laat'hb-jF6HXf$*N%-;k1\l\Y;h2'RL,EFkn!.@PYcIL1R1Nc6QV0]:fdOh$Vn8/@#!K?(%^:KU0.iB9Fj^)lcs)n:sI]df_"JPmsc0ls6[W>W9#f$7XQ]B''8c6,Kl:^@3ahq)B#hGe2:BS]m<@'h(@g,OA/rW7jWH1p2H8o]F)i\St%NRU6=CJl+ScB7#IIWkBU+]%R3B'G&rWQSM(YBQ]dCIor;7FWe;RB0;T^QB4PUXKQG8rW7cqVc)oC6C-@'42GePQ[?c"](=]0]b:)O?;2!YgE?4jqf&RNK1YrUS@PbG\c:)F!>1h#Pm9<Q6ZrS[e;NPBp':%YcaB#]*.mC<'@.fc6XW%4\LBLHjp/F#mm7j+(Da]5@n%h=<c,WQ7+B\,NEq2!8MsJe0+58djOkO?FVJi*=F/dp;,AYNX1-%baAZ(S]6#Jd*XRmo6\t+[6:79G?C_]XFmqf1G<@O(P`Z`f.CTU<&)Wd^G3-NIhDl\)60$+E.';#Rj9t-R:<bm"u8nh3q;%n^p<'[PR1?Ul/-V0==BK])Oc6oFu1T$<`nhmNTM@pXU1VE$0c]LqB\Ud=dBZQD__R\,ZV2alq<U+4nF/\D'CNI0a:1DJhg*GB#2LblZ<s6!kY9VFT/a^LnV!5dEp>_fXX!I5Y3,Y%)hd!MA[,IJn>:pHBQM792Dmi"$::jM:\!3$b'6V4_QQqcgR^LXu=glKdn$J?@:TA!4cU@Dh.8P@@>.X2]=-:Zj,*d#'rp*-&Mt)X'>tF9Q0f?&Wkp0-g]*P@>:>1kj'D@h3-R?U2D]HkUq\"I=@U$q"[:iK2&t#&s@aGdT#tArYJPip6Tap'M)nhJu5LV1uL.uP'\[HVO=Cm]2$Uc/9hq>"Zoh=X-oG1&1lCA$'nMTV#kfng]jd@1>T!H+8=+eqGG3HLB?;&bF-8X[!)L'B<aX/rgosXu)0&Ch7qUd-qqINE-e'VoVrDbR,kSb8$6EcVupXuXPE&qV_[,jY,BgOnG\Z&K9=l5fh\Ve?UpEbp0L@%+6prQ._b+^OR<1G+V_e3U5:GXf1Bh<[#4l64Q=>p!>_([n_A;3YG9N\3b\&*8`h4darq()AnH&Q=dAu+.0&_`djh6R4!j^SC2j3nK*nPu@ZrbK6SG)E-5HVh(AE]i73rKDP/Y$=+XNn,229T9DQUi>1;ogJ\jfgOM1[cSb%S=`33+VPEI8.dhi\ND^]X3to?aSV`H)Bj+Nc<'uom1jLf[&Be<jg=-]ei>2X4;r;GR\6[Jp%cn+dQBMF\EKo!/VgV[9V]L2]5`#Q3NtkP\<5'81eg<dmupW]PfU<`&2$VJ?g+XQ_j_IODNE"@o]=6.[&k,BT0%4W0;ZtmH^/Q(c(J#GrX[FQh+o[KLEj?38Q_u1^*]VWL[n`_Yhcfg`C/>;ooDd\=^nd;n<;5.`RgAhEABXjho\^%Q$&E30:jUR72;&,bak6m6g:`8W\%oQl64QDAt*mG\h9Par0P=Q(TaT@\9^rq)J+8m`_L:5l<rd>#hNW[hD2P>KmW?qUp-g:8#m.o*9#C9B:1N>q7J6/H<PR-ns<[%@niLde!;18j#?"#g$/1uP=ZTDBfO>E-&J'#iFHZ)i^fq%B[IJtF09^hTW.N!dBYK$V4J^9amWp_B.>^78qNY>himBfmI]i0T.LG@AERW=Js"?BA@L&85rNGj?sYt+aINo/(:&>e76RrO\9+5)[[3913n=$T/KM$Zr&^fUPAYomHYojD3S;Ku`7NBa%D1D4\_k!rGZK_A56T@pO%p);.8CpG06+Vdp9VCQ;jq$@eGA`olPATmBtepmN?Lh`P>4m\hr?dBPAU)=fZ*3JpZ.B7W>GmcL7Sht$,_IMqeInMgQT(/D)At87@%jr9pJD"r,<['h660HL0!%[WCA6)d]qt&.MdVl@jG,_81hgC@<Zj[@c]RQAa?/WqOA'_%CG4`H1S][UKOY2'J4@c`_a(0L7P5rk-tLOb>%/s<RJqYc/3g'^(PXQq/>5i%!_C(O"A1^=-TQ71q7[2.d7]+Ra?)mXCF:tB<JC1@LTehVR,buH5PIT>>B7"hH6[2RJ6=8e.^^S*m6k@e";@qY6&"%n@>(3pdg@?(jT[lpSGK!/J7Q/Eu2ls[kUZC_]0GeefigbY!o27HZG_^-EEJh;/t^\_A:8Zf>]>=CM[c[;0//%22?MFW;a>I_k.$&8#ql'28Nk4g)\A[ka#q&s,.=bhB;.N9Q?,)WJ)ZEqtKQSagVS_Il],%\I@[ah8ZWZ=nL2A>UA3t=5AhL*`Va[hOh^7..,OUPFK&7be+2#N?cVr*WOI3V_)hErLXrcV*1-/N`.UnP&C8`WD:i=7nu9Z@bc>.?Q@a9>g0UD0?B[(XDl`[LZca8[dei7e].Rc*_!9s=ba4)8j'KASpf)N=[b*Ao=_3S^0%hlL(7O#`NI^?k^OXW7A#asSL6iRaBtX-*^0ONRr6RB_k"Pu_Zk;2Tc[_K6PH7#RHs;#<7e2COa>qIiP0tKfAl#ll,dRpX\*FLNo=k#Np]HV92j\JHrnre=DCj1,0Q9?S^(-7jV!Q!]Vdn<WhjHGORgg>ZUh@<q%gAc,.!KBQ`h6jpq!3FK$c0\3@cFdmgSKlD(qd+4C3!t:f3l'HHm2\JnYsb.f7SK4ZQ"RKWcr,E3Y8@j4Zr"8D5@.pH9BcmmXPL28UK5Ym@D0Nqu@Kl!1c?Xd3*iYG;W!ZZ#S[]fKt:Rs]"Xg=":q%37`%^F#KSmq\O7%@R]j!q1<gV:X\8*9M/-e@UGEg$3XH\":.eJkM+Y_<&qccTEpA9pd>M,F6VH]ME,s[-t&<7u&<q(S0r,.`k"(?U5"Z/?$3SN^70Uek%;MM6]F01Gj@!\OnW',MJ31l>56>mb]L.i!+>b4jNl7(.`I>SYNnfY&(`^FiX%4:=BP+!`Hsa&KnlLLsAn>h_3'`.@a7<@(V/t["=3s7ick%h\R*.jCn4"`Z/F;9Z^a4;VgLgpj+r:G0#tsbm*qXUK.s#*[]KF-Ts8Cd+>5aYAY]_\MP)pD"@:%d7]]D,i8asQ?AZf6TRBOM6tS`HbrXi7Dk=)-2sFsTt*A,)"?//c1/gQX'J;6f/)+X\"]M-5+b%SRMq0,+3H"s4Fp/g@eR[bZg%"q?UUD/D!"(Nq,J:9$_9$$]8!b7,D6<]k3Y"E:rSHTh-u$nBqJi=k-%R):'Nh@S9PqAd)e;tT5,aeH;^JGQsndIKG!Ijn;^Hh2`b8V;8hn/ZlF<P(`V"1r)NAfYnt]rfM68Fn)$U\I8D+9CXT_3,VfoV9l_BiJ4^EC\R$7"b!O]`YnKL<j"k4=h8/@S:,dc#Y+*(7^E4k/T/sj#o!e<r*St<XlrV*J[1(MY.[r'GEM!51VY@b)]0?Z^3^1t2:Sc(\GJAUS_#hq]`<q;.SC3ojDZ+,/.\8>NDo[Oqj#nZ$9-+qWpiO/mh;a'Ai7LD?f"1+JA2:TYM,mP0,@&>1R%6gsq.u^))'^O[,j[Q@GDn`m>?h-Ak7<#d3phb=;\Y9a_PHB\I=$u?9b/:-r]E>jG@dl;Rm)-[Q"T:noX+i9Z%93gR/UO07u"^k=4r^lcMZ'fPGcXlSNdTOA+5KL"ZI+*1m;oqS7CcnQCm,nC^K43KT3D;>+9fN1HO?PR4B2I%.(g4d>F^__q)q]#_o>$C`/&B7*'r-Zlki6F&H&!$`@GA5aGFij.Sk7UddcdrNroGD2es@X[MAe=)^(7G9%>MYE)2*L[L7gbV:Tc"VX91rdL^NTSJ!B:-h)DASLQB:5D)C6Q]*Kn0[rRMRu)>=(_/=PC5+69qqnT%4VV4L+fjD++L<*PiX9-#o+2*m8Y/o[HMjb&(jF"'D^^H,sdD3(cs_sI#PRPnXV>dj\S/^F-G,!RXIgG>&+b<5.$OTn7*i`V]!6k\!1RRY7.-$GD?<aCb@+TYO,GEk>:(n[m,iFYV908ZVd0aH?J=]Bbj*:bPA[A=#"n"%"bIHUX\75b$e!P]ZYu]LaX(SM(K@W1(;k[&pJJ*>O2$5aR,'FI_Z.ub]+>%/)!K<M(6tl(h+u=7O6"kSCP6V]jgedX^K94n+o+(&.u?<JDI<%"%4UV!L>OOeN1&F+L_i_%s.M]p\FR=-;K7[S#<[MO:Hg70HoM"^U1Kqh4BD2>k1Z#PQn:\Z"+@*4tB>pUgP8K`#B1G1a[bYONEodK>r<uOE3]lpuOBYLB@nFTgc4(6!UGQl0b53G'o$]3<&e8@P=2[nKlA$\<l%?n&b<3VlVqNU/ZNrY?6j*4)m0Ce(RVF.W2.NVRSa)c&gHV:;;''Q:1Y;"O3C*m`B]h3>,MQ]dI/>*INfMfOs3?efX/C#nhs`Y0eoHT@No\3;Vd^e4Bqrr0ta<VOc"00L[nO9:aGfKpgZUe3Nh$4FOuNrGQi>OS!$8E[=YM4HRUHAp8staQe='D0CZcj8RBTelMHLdMU@K9fb&"O6B_\-W%Y$0QBODod2!Y@]X)sjQ;n1AhRmuZ,EIY>=EUPm[4U3a-Nto#oaBBT4YAZ8:DNLTdr9/:1f`J9X:bU9bAAA.*f0RnZ?P10opArYFIJI0:I+`]Ok>ZrJiYl5Fu?9\\!RX.IIIO`ok8lNpi<<9G'JD.W2<+K.tZ:;RV[E,[=EHS_o>#RSu4p1Ld/=gk<dp4u\rKqY3p9'Z%VP].03N@/FeDpM5@a[ni[9N6?@-2`d0C9"2IRFQoXSjD=Z?Nuk[e^8iA^="#A!:k<"u&0sGh7ls>U4eCtP]/*KgQCiF@f>gW<f#:QD6hJ`W'_HDX'P6FTK<pT#7!9f0U1-UP+b`DI2c#];EWJ<?.W<mYPsYQ=5,Wsn(mt&@E\@Yr7P`u^Ar?E/rl]CR%\/,1PBSq>Vb6!O>ZG46@;Q;_,cdZfApEKqhn<jDmeF[Y.F:KlbnE"#6OMU"ri>3UdkYjJ@'`d?T'JBF%ZK%8U8l=fN*)aI2:.lbIY<%5i>ef\I3Y#0RH<\m8]hM)N]l1.[te-W$r7C+.Qoj+iC@0%o]t`hb#5@2$m]"jS%E]IAlSFD$+9n]_`rdC9KQc>5it?Z4&sMu_+o]E7a6$2R!AOU`]%Yr=5@'UDsR,VO>aL'NQZ)_A.g1U,H4M),]g:iHdYo5_.Cp?+gmm5c`T(R^&ae37EB>A`S"Y?Y`XV6obcUo-uH2.,1M"rnlhX5=q`b=&"@c_#OcWJ#0+69>&bC',b.fR-;Rn]@WY@+p&X4:OWg*.:Hona)A)OK9:c&B;Vp"ak:D'SE=(#RfQljgK?._Mn,8Yc7\XAIbtg+Z$cL8DL4..:A80%\+npAs?DY<+;Ud@ECS82Ua6HbH3+lCtjpi^M6&<McdIDQpaKM5+j4NqOL+fqQa>0fKZaRasW&n`WU/fokP*_6UnGJI1;8h-*lBa[le'<.jhLiB["*<Dl@nDg1Zms`e-CU^6m5oF-ba])$#h%.4V.N2G$[q[4@&b+Mb\O=W)tZ1N2OT\!"uFe/)SL2j;N!scT+dOgE$e/T8HIWo+cDVEb@A/EZ"(MmUlN)*aZFJt\3,eMdYd`=)/j90DEMlmjPOJWE4RFhB4IP*9NJ_`Bm18r9mDG7\#paI#Yhc1T]W-153!gI*86Lq(Cahgc+3oJU5=fP(/#Ed(gL=fL=Ak)"0P"6D.I:D8C,YGbm68DYB.5Yl@R3G-uFq^IIiT:laX?B&5+fC)0:ZEP2-O_M?74mBkP%VFr`IN398ZJ7lsJm94!8e[?^#jCuk:Mc^rZ%\p_P@B<^oMHUgXRnJeQ`b2m_VEpZ7L3RU<uFO*q.,[X:sj%&WUEHZ/,l-D!,NQ++N5<g]#Td/A576U4/4,.F"a7'\uDiG5"PX0@R7KhQ2?@MYDBm&=LP;16Y@ndE8?@!XaTlreJWEs,rp\5gjhru_93S#u8JX>hQ@GVZ40OH%3)Q!bjd!Y3s?ob/sc(>pW-meV1r(_JsTg1j2+gO!]9GmR"nD*;sLbq"0P/M4EgDin$VT84ZNA8q5h4iS:Fc,&k=SaM#I7LY&>SV2N6]Tc4N@(u^HPd$5J2r"]r7jZ'OU/k\bHpd3al"Y$5AL^YA;Vp7pRs"3:K;uCdM<5md"hHrW70ha$qS-W5j[;lZ#CU&<F`#!es3Or27rguee8<Z=(LGjMr^Zl9]%h;oFGg6eFmfmCUOG7`NZLm/hZ`d<F]BK!6p/R^p6ua*1O>,fe(d-d[UX3'(qSU28$:[EM4Fi&FX2\o`9I#_F<%_3YY]&,N!c6IoP?q$N"i^@$s9a7$nRi^)/EX),u[PAU,q1-Bti[_1+"6e*@H@c(%BDjFK1D]Q=GOCf[)9DQ((erJuueL-&gm8e3ghpm0M\8S4-e,kmoW.ca11\,,]bn%I5@LMR3>ZKIQ5FWSTT&%^!V=W'm!\]phZrVMJMNdf:n+j2a0CgFnHJAG%nmH=/Xs+B)'Dt;J(8[^SE\e-??]g^K>[Jg6k4@jG27Oc\e]s86Ir4b#The9f]_IJPUcao7ANP-o@9A.q'asf(Dh\*'Leh/MA36!MnhkD*#j@u?'M[q'ccm=KMaqg-/T,(,ZJ0AK5`BEOj67sAk_n-`OoU6j2$O7h0H5IV%*Uc8`["t,\3?S=-#7gl2jEq&\1-a2CXY:[CYXo^KDRf0jq#5OOqTbd:UW.I2",#,&$\OBl0FC><e&sk\ibnqgEd'4^_am\W/HpKS.B^G8RA_.mJmd$b@/nZ:f7k`E;Mu6@l`FF=3RC[HBfI#->JUSkO<\V@Gk#l5*O1WbiSBZ];2or@)Q7%R]b5>$in<65>FV,_%Z.$#jf),i$f.qkPX5q:lp$C_5E[.8Z#mGt*)Jo_ht5Uo^mm1"jDpU=XEst6q%;9;(umH"rV\]O+-XlAjFGQU$?MD%jqJZ;<5g@['J@5Y%O6QM:WGq5b9)H1VNU4kom#8a,,J8:pTiVrfme%mcNmh7d*E!2Rb;(&ed<-MDBJ8qloM@G[7P"24N-$=WTC@BULt%M%efC)`,:%%m5g]"om/O`%p0CVd!>ah7"l'Z0;Kab&J/&9Q]d:N_2ha##2.nh4Y_mtRLNrS:RQfQ%9sa#p.NPBB];/<WP0g$l65R'%mV+)WAl2n!CYqO@0*?f]LO-bB<Y/p-PPn=/1/CmJEoN''L5K%ENg9=i(RBIO2nNNL[MMm8!Dm^dR4e(+VR.-,TmlE.3s[(5^GTj?&`7X6OemTfh:F2Id)7eTN^NmJWtFOLb,d&3^a.e_lGk;<D?Dh"cG9j"WP!5m*E#4Xdb5rBsbEF-H0k\ZAIq:67S/_isI'\7Xd;kr`.+Mp%PoCl4P>N(LMs@hY(\DTZCp!Z:20a?7%=(Z]]>o(a0,1m=@VpLgY9(PYPF,(i`>&qOp(k1VaFTf]q'tibXf"JR^iYV+UtXlj$b)[WI7e@8L`"B`XWp$&X#t$l!)3q57\r&n)#h9mgt!oZ;Yc/sOdaL[g9>^'m/3(WGPF'U2aa)t_.3b]@[R:!\G.ABc92Su63EE]H!2ap9dY'Z//X:]X!aJ\)lQ(bIi^)n>.=[%c@iJ]b@X%3Q0m]WlY"Q"O]>19eYISB@=3<'ub__.Zh*'GQ/?gL%VmIh"OM'>W35e(LrE\DVBU_MI1gBLqfKM"!47,ouj0T*c@n#B$RAThfKW[\V5IBs:mrmPsPNTqE[k+sl-UCZk1(*pV?]kMt]HTaTA=46U,jd*S/5d>ftn*KR6nM'u^ilnl//@PUSN8DjhE@]K,6X;`\J7'ol(cj;.qioG$DfI!MKV?u`M1E#=Wl3qeO(.BB8p";9hK[E^.=@WdJE1&>35([6>Dl%t%j36YC0BgDFSG\10l?aT54nON.D`$9qfKe\Sft%M09\A>"f'88jb,ZEL"IOfG%5a;C*^Fgh8mdJaFEE*DM0q-4$O/FBT]6c1:G]U$Z0-G[nkQ=KZGAt<TrmPOFf_;U&rncR%2W3*@?q5!@O&H)7ccXj;$dC[H3jk>3_RPLF)qPj%AF]=fX-^f+/&j!E?ZS<_HYB"WX#Q*.rTiB-[^_E".@Lf->"R_fFf%OTu!N\q4;Sh0Oai%MP+dmkVg^Di0hnlL,EQSJ_D:9A!p4.E_jO]d"YpenM%ljblDfpT-S$"O!-1r8rRKVA.dO>pcA)<GY%M\I&4qPM1!4M(T`0NQu3]0O(K(IWB?8(1;GT0<=[^q'M#Z(NChg]4X^\)8)1M'AA4)dS\p(=%5^edL(4FDq4&n'^bu:]F1NAZ%88J<k,oVFe?9C;Rf6"U6e8^9k??/D\b#@)U7#&rr`%pEQ<Rq;OW,$m.F*<!dSe7o?_(&^IW3CS+aBbK@"]Rc))q<ZS\*W$h'p8MV'3FC%,hMLe<$\VG-MW[V3UScPLo#3HR$jm@uR)#ZU6T<IGGJJCC$6"gfp6?pjo)'fDR<2blIf^RE4/4l=Q@0Qb(DQ3N_,fPhl9Q,nVD?G<j8s0-go.bl+*2]Ri5_K>eiU9`ndSTOV!$BaGJT8i6tONd=GY?:.p+8XMh@HSMLJnXN"%nA#d,o\iVafFufkZbu2_f4U!-[.EL)ERAN2E_#-r]`#>3ehR.>m_@j4\V<RC4:_ko,m_CE$()K=kiX$NfYeV5lkgR[nErE"<B/[#L3#A<0IN;]M':"j*DT(mb[*@eh(M-j5$>fb%)h`6NY"'PTs3aeJ69.2cY<o2@5ERh`>s%/Z*58ce04NS'S8`!Ij]4:F]@>!:r&/F_`[ERV0a:pR^8_]3M\YU"/3nW8\"Tg3Xulb#5K5P%%1d`/)oY%A89pI4>KG70/#BS*cS)E4JY$F7*o@s!9Odp$B0R.cc=ng,ic[&%h7]RGB&dtG,h>f+I2#(AA4g)TMhP%)EBPXSECELYMSWpr$ermI1/'aNQZUK8DCsNPfL%7@85IM&;PT<Paf?B%kIS4cXi76qJcgD'*k6GN(#*tHdZ+CF;=_5r"Jq4(grh1=@`[9b>@6mF\O[Tm^)BUOHY/9@[Z`+]U.c3fa$*Q1Q8t(TU6Uuq005Q,kW9dV^f7B;f.pbU1f('B%\l8<gd(#Gt@^*"5''VU5HA(N5f4aj%;BbYOQ#umbT#]FBgPP1ul`)KX`:pndpt4-G!Nu2GZ.d]3WT7+ks8o(b`D:2@6:*#[V8R(mTi^@ckTP/Gji:8`;uKTugY^YNrmK7HCCk6eY1l_ub?@T@?DFh[%*cbtnOb1-Eeg0m^_C,B:\\i4*Nh]YCi>e[Om7ir6%u?Dc=bX0[7H`5lu=A?0371lVu\C=F(i=aYU:[t3eWPV]a,=T[X:Q6UZqh#\54Pc01q+YQ@5q7ggNZi+Oeqq(iIk.:N`Y"9KuQS0bY=&Z6V[O(h4rnLKc3+(?Pe+U*tJ*7JU&#p=N5U-&Q?FX#6s"4F]Vqe</`P!OK1kU<F>RBP)N]9FLG$"%cQn/1b'mF>;@[da!FYFm0S2-0Fb"+:i#Up^,IUk/ZWrcqt\=rj[,%GJX-f&ep[_qfQcLr'&o;!t6fNg`g+=,TkKI$M1*I6H1?=`[gG0O]A2Lt"Ts!50JVtRq>CJKLRV\O.2_k:1IFFSU[#,ita?aP-H]oATj/#qJ,cW1_%RI>:ckno>4ZH$R?MZO%*(8AC4KD1.VM&bI!X_3M/22bMKWO"SsC/49g1`sQj76>g;>h=Sr;aWCCZW&FQ4fSFihr+D`o`%Fe/1g?2ch/-CkY1W80UkqPMq/K\OlrGiG$gL)<k8'RffJZ7#:PCJWO:)Us#P`2FZcL+(!)JbMukhto^@k/:(23=&_o$Wj:q"t]PEF_m+;-j6ViJigY'V'/t+.b)JDQ%HQhj_=><!H%32XHW:e"b-'n1),aY77[a`.Q[K(ubbI<O_CJBZR_<jDXWJk*m>a>(q]2B\!'RR'+-bqkm'uRtlVX"oCP*%_0<<SUT3%7>9h00]EVDK1Be]XFpH+i%9k8P=7F7=YbK]Iot+Bgi)]d'3j,GF^/]SEV*=rN05^/`:4i[APT/MaRMFujJ/de?HXk+OTg#/fIS&db8/!]<3C<'MJdKdYkr`6mu=PcHiPm%jURresdBgI`LlK@-ao27<ebCBq9GdII!QJL7n8o`q]WDMe1qfPC'O'>khrPNfH-ike(J^VX^XQmqQIO4gCP]e*sL<NMYH;nT#S#BS$<HeOc3H]pJ7+qYVc7.4>Kiim!(j65I>X1-Tlb#$ts0/dG8LJjHP=b7]+g_drQ1Y7sCN+(Y!].8fS$eZ$18\d_*gGR$OB0\(QjQ3uHN*M+g+"/<-8<Qr!6=Uc(T-#]Bo@rb-8#9&gRI>?F'uAFi!bM'-OInWnJ_k`4k;2uuc[N=0"7]2a_6lR\Vac]%8ZB[LkJ;FAp1*CR!Dqf?SL.&i1aJ4>XKK!tZ^0%/5G'bco;-97j7T'PlAlBdgp):i'sVi.b)?kq2*2:\MQ8\+3j/0Y;Wal\bU2cLK!T\LTM^nYkc8GQU2RO)qG;jl"KhtiqLNm9Y^2ZXPA"DZSd5n_:9Hb4^8uNkYkWG&>S*)Wfhp^j%LNS3U6/Yk<;nV965T:/lhi4-AB.ZpR&WXM&8<*\FnT#fG&?\q@@Qfh9?LN;lP9WU<@=U<UV(`MhICB=Z^NZRVAEJ_P2c5S>T1"s8sb<Kb"_D1b1n<-B'eTMT"st8>O3\ac-=LVa_((?'MW82MGe?$IAi`monPD*!WTA<VgP64kfTlZ`_8)2>V%CHL2@Yp5\W8@r:u_.E:ol^7%Cfa-/_d'=!NupM9PVr=2,KffITR6'MSsY[j#!G's/]arq0pWlB0[Nq<*.Lf!E&6]X]Jm[7Nh5];jWKS\@9n@(>NT;BsLF9<'LsjQ].sb#M(@G>t-e<M+7aqLg0%;9@EN(%A0K\OPRK[&r""/W&=ImdJoff3Ik3\^+RM0,/,l2Jgi1QLaZF5rBUAh?'XWAiSr<j/rurkt;.*.%8)rUNL0!j1i%3F/ekc)A'KijuhhOTD[<?3k]7W;a'@g-![s#rpX`5c]O'4Sisg[EFX[o7q;"YYGUah`I""8QF5+]jiFWp+d8M:/45H38dV@DK^;:K4fUq#HfZU7V2Z<oD]3#i[@OU>nWdge@8*<2_0gOb].iSaH+_eH\"eq)odXqF^?&hZHiu#r$J,5$CQ0`Xqg:=^aH67-R5jZ+bS"&%h*P!:1&3D36&9tIBE&!L>YL>EVigm58>r=.SFYVA^Ki0SSA;F3OA%]`A)V?Ma\8gspC:=^PYJf4Xs/NN73*[^bY@lD_8b%oU5M-@b=S$!$kUt?O(snMgnlVpI(nS7l\!!=@Z2.Z;P?'db_[9Q=EcR5g8^L0qjaeS$_=qc'PC0_1Br)F='/GoWhV[0;L73*)N<IPit$&f?'/"1T<@>qV3J$M_U\\+cgLP[S@bB_CT9d^@TlO/I[7_9?Dt[`k@r@OXNBk7iF9A-<0_#)]<Z5fiLQ-D9"c452oOg#h'WqP6Ae*@cU,"4(nTjZ;AEc"hqLcbE?&<3LNcm_l1:Ke-Ur;hgKk4c2L<%$h"\go\X@]LTVB'G($=/pWh'b]:HVmIeBSfpWr&uTHdC)eGA@?)@cr+[M[LWkgr"6Q]j#97[2YQ>W=dS)3KMP3i)OVa_Da8rk%-Lo[aW)@$/EFT\X1C_;rDi91#1\f<L=h9lb7Ml$'GFS^%CW<VUKqMNUKo@JI9&]A>IL=@TGRW]c6Le9seO;"Hq#4_s`5qiu\AXMCmdN\%LeH^d)S5b='sg0Q>.?b-o_F*&2E'#ZDaAA!Ut+Vd6<:"g>/;"eYVuerr$eP5T!6\%ci)9&H3LQHcG.UXl2m/9M=q]DZ#7GZ/MW(M77s'mP;`9<YSpFJjQ\*So2tZl*eX\)homd+(euOfE"$$M^\\&2dH\O(?3!L[$*[<2dL>L27tDjrOV*6T0i@4,><\_(-6&bi0YPSfA)4(pmTOCknksYP#I@NQkH7X.5Uckcqn#V&5dFr#*^*-B!oN"1b)hMI\%O4!(kpK:2&=GPHK(ba8T)Rs-=/il)#CUaULr^O*:FnZ,bRPbC]M3j7-R?:AhfSr6-bR3Hiu%+A&e#$lFsmkXEq6l"XOf*!+KAHEZ!603Z"ldF'0hkd#V\oQ4t\PgfK*fNI%XE_d-*@dq6OQafdAWZok8qs)fRsFDOP&kC%3uKD66232h00Jsq'68QS#*.XHKmr)Hl\OPDPk]*QnHYpM.KJ!d_u`=MeZVbN?D3?2#*j*Q/+XOKqj/oKVtX.0qQbIROMfp1^+J/f.qIbt=aNB3]2\.G"oX0iAe=pX+!GW#P,NuRf/IC)S39J6*R,l&&m?76>pB1Yf<2NB6o"6oo50UZFWrs.LDibl2HSTY9N&9DVsj(('4)F4D<[C^N^]Vm)<l^X2sKb_`=(Qp,jUtHKF8]U(6m6AL8l-p`!RmKP_adq;(qVBLN(6GOYM&q'mJKT5fJi&1#_3qgTfer0Yb&DA_LdY#G44ofI[oSN#-D@=YtuaOuBPSn*'=rOs4PLUYLN+BCIlEBU2,QR5"2+!r6l%9@JbX4R<`FODi)1B1>%$a!gcA`>WVgM(o6(.%9Vof6\8bh)5a[0UO/3&FT]87L(cnafD1::j1/14%15bE41*@VZ_dW=pYqh^ILD_5oJQ&Ln1C!MV%aK1qIHd^>fc(XBm-0H,r*IW3XuU+!LS#B:PWka@p;$9XN;Z;$Bd(JtuNb*AQ]&(Yu'oXR`P5l=s)TP$F;EE_2m!YbRaeaaI%\=4Po6pN%aa1;2\11P/=30,MBqaj-rED]AGs4QV.k5nNG*a<RatW-AV8qB_IXdG,g9Q;2GqLmY,_cc*ItR?Q<nV[bVVXjO'g-(@5[cp2)op.JQ!CGrGh."'LmGqto(HVdu53:P[)fU@A33UK"^cc:*RR@1KZkJqt-)q<(B,T(:c@GEGLJBX%>A&as2fbrHuimb6B/FB@<)U!6mIm<RScftFAZ.ng@G's8'8&OicS3G9#r.au\PV]%QMmI`KA@mG7lL!?b8G(s?r#%,-2T'7&]_9[Mr9b!apC$6X'5+rt\Yb1%0lXC>E*0RQ";int76Yr_eg-,g;WI->7A+f"EaMN06W^P+U,G4elFEF"iXtGMg`R/A+<?rSPf`lr\q^1[]2k'7UJ2U"!:oC39AYJ-0`f'HPl11l6Cb,#b&LqTpHDNFr-pVp3VKLeC@5M[C37ZqnUn3u[tnL;#Thm7OT8ke,#+LW.Acka!%]k06Y-4&_9XB#OEr#Y1^,B=#?`=Ws)pW9T#o+/+crLM+p[eeLVF<.$1T2;GcJ1cqXN#(iShAO,1TD8#)T4&eZuLor_d9B.o+J(l8GnPQ'r?g#\+PsWiLi[:A#B]l\hir?3A\iWtYgkPK9^-7EOe^R>DY7,YVB<_*Q6Y-NZNqTn2;/MJXO)lspN[&=ESU,>uW3Uq]J*rG^E.&rI=QK.S!MN>ji<X\JE)=G[Yf[ZWV'D%=/>K*ITmBkYN.Jb8(Fo@+h+ia+Em!hD_=lNN^c.\IC`7[n7loak)s:bt7LcAXJ+U9pF56&O<?Mn1Nt_$8P(@"YdjE-96Lp*hsXq2_B/5lc0iY-]3Jh3^F/$bRD!N=8ABK%38F0d,u)T_R:LYOMiiP:%:]$uJ$Pfp6<-Q=QB&_\#9$+$goA]fR1*3:IE8;uWYH&OWXNh#[;sA0K5VOmSBU!Qd+t_1@#t"0#,\>8N5H*UkOf3T34?f8#'CfE3-o7p`%C"bkmUK?GrX/9nrQcnrZs6rCigiDSa4mF%6?Se0UP#B6,f!AmZ.bepc@8I\Jip'dB(E]c3)fckF832+(,J[E>t<1plDYrSI$!MGO*ct8(PHR1OHl@aJ:Y;km!o9:&]4qO7G-kj%s^5Znii&q4AjO/fc?BUj/(ML64W9#3b88Zh?RRrVN?/D778O.+uD#e<['#-dVBiOa*rM35Ak9(h)AQ*PY*gqgM+S:o[YE"`HBa9_e)e-0)aHoe[Ca5lI468DcHQX,hi?`i#UBc&*Fc;U/NFU*9#tLe8aKI%\?0,ANhK_Eln8F`*.*3o0i>"hXBGX(F3!%"S#.s@IAWq3]-tM-JK]I>X3tDD[4DCRPDC#ulLB&#dN"Z5d!%;#B$Z^fom)6L`GBBHY#]fW*k<4Yk_@M=dHtD5^jsDJhqq3(DBCg4#D?A]p=AS[?YNL,c[\IkDi-s,IrRA,;V/t"Z"FWRI0l8$aZd%=3A6h70hP4bScA`kbosXTWQt*eE0]iP:Kul1X:.'_%IkjeUC7%R7;7YJQHGZ@HB9unc_2ucc-"0\KoDO-Ll0a#8bM=\LrH\&F9eDF4lS\A6Hi.*8o&Z?R"Yr@0ZD>oo]*R.8`9j+4OmtK>pMm6AZOO[*BVjUY14nU)6o3rNcAlMYZ)o_6CB44l"A'+(aRbVHE:#knmIbrbbX_9d&:\YL3_f1tgTf@*D6nWI'ZnlJL_G#(\5"4bRlmRDib:M69Y\nYVT!CTaoVeYT_TIJg7u-Bg(FsOj!mG.g8OB'WG6RD\6+?+rEikgmQQ*pcK,\jOj*(3_B_^oP-.e2;U<bsPM.H5hBSYJFBGSbG0\Qr^RDc/g3PpJ-^L5t1fYZh1jueZT_@CKGI0,_)sc_k7hrXGS$\Pc)rSnrOLAbWoj^+CSX*,A)'!WqUK<lW6si@Y[:^TFLH$Ma;6X<Nm;J/,QT5AfT_i^JN7tM%;;AD]0lgDbMa<dW+E2#^S=+jH`:IIK9Iqj/DO]EA7;Sr=/jF,4f!RfH]`\A=hT?IEOn7As"=;FYO_2Pii,Cb<_q4fM-KAD#n!C"F'%,B[r'Rn%lnr.>p9Ed9AkTP=QbJn*NEjuU_9\b'59PG'l9?-`*)#Pe@:3I#6_HsI8c6ET;$[%I9o+$>\op6b#(pfGrL*bS_$E7`Sr3mG5D0R*D.?%e^r(Y7kLcE)A99V<ci4l6`h3tt"*?(.&,=UW(N@WGV8/)DSUo'4^]:u#*=fjTo*d?07dA#+RCFuP]9HIkdNV$E0#L;/E<oJL3fbA*\Km=t.p9l@?fqi("+-u&'BeiL84("q'HX'$@2C+&KC,c=PADon"[X[6ec1R`jU>`HOrsc)Ooo7^`_W4P+M8X:\H9OMI)Zgkh^<.7"nX8H:B#434P4'qmL$Z/a.E"`il$#BKI4Vk*::_O=_Nn$FR#&?$V=H)RfGTp=NZ^KO'f'5W%0f(Q"h"1qtot\n`2M\D;+F[9H<jKjYNmD6t'(DNJJ:>Z><'G6_p)48OMKO*"8=!Nb(hLVDKD[6Kk]3m19(MM3EIFJKcWTC]Xp51kbug?]4,&$>B%b!43el"n`rZ)9nIkBuY?2:>eaF2*251P<YtN*YZX]4&=B9)%#(5;M5W*/Dt]l+FL'=k#(*]i.[<rhi!)-89-1^UqBAdm5-FU2A;#8(\79c!dY?OJ4&Q3IhMnD+pa@Kj80<KL($4^%6R:IfDO5dngEi[53#@4jAYoC%L9qP+s0:l:/^7#T/X?oG(Q(d3Q6*(nin&UOER^j;5O-(_i"H-mc_dM'@bHTL`#hB6@'_>pF(9AGt/7<a@FkSjXnB+ntXt(IU>hTn/c0bTT,mo*O>b(Hk2n4c?Ij[^^`_k"9H"t2c+cF6pJP8.B:%%.[d<PZ)G3do1?O"'gq6bp1cB%ac,Qg:s"SL_:Zj)Nn-?nD:A"%&)-<^6g8eAb\0ne<OO*dBrW",q?9-b2@:UeH:V_&WKb9;0N#Td[?+X0_?7,#[D%gkd*SdKG2NOknV/Cp_$4^Zd$$dc+Q*ck-=u.%p8"k'.`Vm1F</bf$*7BOGTM#[$ue55_mcM'%PtQK,sh=]:%n%$6q%#"QlFb1YaU?eUf^FeKA!!kZp\.,[6K?LVQG$DEBC1Cj,seR_d!5k3(Yo8')jL-5LER17iR^1U0r_&,=>';?:\K,b4JC<Kau\P&eR\q*j<JEHB&1$#OVVg?A;r\@UVa(Zt9h]cJ?>-3OJnnE8JYq[Y"WTO=+WcBOQnk01Oq1WHKtPp=?2<I1SV6),kg`:K(m,Bir2g/k1F4[B;C'S^UiR=M_TT7Fr'@aTt(KbKqBm__\XkA`4&udO.u#b3gftZR1h\gt%uP:f:,&<f]o@F*L\;?1JG_YfbZ\NLY]H%WnjCPn2f'i6\NBbAH?CdlFlR/1>3bk\R.BCD9ZS@$I:3bcBcmc"NDG-q4r!`>o@*@GKDBLhO5g04(GUjj;^BQW#n)/]8ot$2PVJ)YC74e*8KNQd,3-bSgn#R(Ia`)*l)q?e[FL&J3>$"=-C",_SN0!<F?A6<BWs]G"Y3'ReqK<O$CN%&UUK[1p7dF^1PjI@/[9U$3(Kd_i.UqSu!/:,)R9&erqU&FsrL;$_7_9Qe(7%-m_s(cBeA?8Z%Hr1?XV@^`X7/ps"0h,[d,m&J.^Oe+#49t(?NjU>%Sb-'I1OG$VR"l)q-Ogp5rlA?smB3hS-BliQck?DqsN-%(VC7-ocTrsaj2U2!Y%`j)"epJEKA!MU^-p/1?I9XE/jnJ0[Ic^[tA+HVsXH?%.20^n]];$nsF-l"M/1s:[#se0KGDGaj\d.n4&pd&tG:3\Sj&O(N[=f-OLN$W9_@Qbagc.#(RH,FuQbh`([e?C21C^^%HiA"@>/qlQmV$27_$@f0"df>WJOf#k:1h:diqEV09aq;4VJ`X3NH-oV%QaK'Ls`3E/crC:3_q$r&IC`*1,$b!^gQAT8%7@POR8/%)Gp;?ii;?%@9<OfVDbsf=MXr-BL#['gn=88cI]=.^/D:4^o^!)L@`jRarIA/HTe/mG$>f1Ts_Ch:uX9f+QaMo%>=nXq4u/!e;YR,dK.[%4pMD0Ie!1)0Ji5R,"Q4mbh(]m#P[lrW:KlT(\'Si8&t?R.Op%SB-38ThtjDI6e=K6$-UB!%iH&^fQDZ7gh^kcLT@[C606g&FVeA&h6MTl*M&(g\Xs:-lMQ$VTflqY]^R%"E0)t+nPdulCie"fliQHs)D=pBFJDC-#G`.)]dWBX^1[b=mDGm5$G#B#kLEkta2H5]#]pJ-RFXMBiXA,g2YU8-e\mbicoAMD%VUaH&YH>r\b:I+VSk__hXd\$Cbc8<1#^NV!nRE:8bANqU$!X;pq\'0&sJ0,8k\?F38LNiWV%TnJmo\Dp+aXX8ht+Y]_P,)')<:$*=4Wjl5I8u<TOVacOcXr[-2[oga1O09GO(E"<umC(uT.dD9p+t:l8\OEDWtf'-tC2dhac3#a99ak%oV;,^a!F*(bl\"WrfBW3h<+m^a$@N<+2gTuJ0N\n@[_"oBOM$8G"%Zk-,WG6s4>F+2FF>!1Is%rtQIr"URPe<[3Y!U^$bQX`/Q9iH^R'GHlSC-IjGUm=\E0H&QE@k*tpVLVM(bW%@oJ[T!Se1Oamc&dp0*-qDl[/F^P@h`9s"amoUC$^mYZSPIn!fUnZ'$MGKd=JB2eetE3pL/K+$;Ym*4cOi8Me;,;7m8Z#pDR-ZHZf_1]Z!(/,bVpl>$Zno+?&#6@QWr8+UPYH4.M(-?o/*4E'/1>PtJpnE"iQG;/Yp)mN2fnF#7U>_`E+nkU;MsdVK*sZ<Stg3+/_9cX4e$jmpth%Y2kZ]/d'&)AG1M'+(3uZ^=p;eoKFY&$-&(L:s*=Irj`$D/_U)qeVF;@LOB!;lWfN#\mV\BR3qgZ9\Fhq5Ym#I+V>#F=-<:1`Qa/dWr5?U`K=sO$A3ZXNuVhVj70Vs*?r+@Sre%"f*O[q$<^N^h?!/ZOMB:gk`n;&0,s<AR$,(cXe>tLOGu0[rN(,DnS0CoXiT]f`s2r;HX%0Y^a.?K]4!W]Pdh3ODs1r6q&C)`NeI<Qei_mJFHJ]6[Oq?6'r[nAf4^k*ku^,1!D):dBDEFKH)Z-@/Gs0^*dT7n=9I&9Uq>n)EL8mqF8QHoaDUfTriH^O6kgMpBDb*"-YYl3<)7(WI^qnoaX=MX*=+?3!)(LcfbCnbjk*_HG=E*bkoWg."*XFq@G2CJk>CH9\mAT:BR$Xn+P)]ZLm76mRR5WoQYMD/$f+e>sBe6rZ5:d:I>ASDL@/%_4(-'[Uf!?hb6?2C@k@<9cgF<d8mMe$aPR5'b[sEI`!l<&#f?8:C;lj'IMY0QHLI=ek#H7U=c\=!k+!;gc(qZY3L+q#HZp,$tM7`ZP)eB_$<>ahdO.rr@;6GRc=gD"7h\47ZL]*9Ed-pOY[djDp!Ka,-g+#^U3\_qLbLCr2<H;>W=3k"F-F=W6[=%[\X`^>"bl]A*`[,'Kr($e7\\Dg1f3hmOJl=i=E^0)4;kJojT&=NrunkG`Xb-`b'P=!WG&N#)%j5dG^?B@:FZC17tm,U"k=tC\U9-FN"0t0K.GdGbb.Sq@CNm.JV4!I&h^*Li-?kqju,Z\!U_1rGrOtnSo.rkDdT?SDHP2fV+[B<,b4kf,;NH0l"";5+_j`.'LtFj/.F1\Cn_;%?Z90m$SR4nP&NHN^L&.G[7^-0n!BVDpOHtbe1"m/2KtP$m@mLaF;Jrrh%VaG1)?TnHp@.E5OD)!L6mVK)N#:k(Z2*0Qf,C[)i<9os>2EOE*VM%o>-V3#j.eK*@r7YRP%CJ?`7M6bT:JFCF:U8E*?"h\e>8?p/0+/KBR'aNZ`O&+A;.gU?*N4<:$l[(m^!9gl[0B4AX)jbjDM>"M'_IlN5Kl@<nHRECH48I9qN?jMK#F<(uN#nZ0+2!/?rs"B^]^/<8<83@APer7obLIN4:YZPkhq#`JJDSEZf3Y4.ZLV#/@#oG-,58\h/2u+I\bfAa"4_GF7R;OZu$n?9>5f'-pUU3#[r1?:"!;BNg5g/-B<r$]0^Rq],ZJPbR!#rffmpXj\$Bm=SLt;`=(eaTiNOlg^"C]Yk'bi&eqkO?+%2&`$a/IG6e/'7,1LAUSP'BGLPjicJ$F\f-Rco+e)Y_AY'o@&dRn+@:(G<Joh7Gbjp8<_q-gX)+7298$Y@lbc%[qg\&B@"r;!U-m9OG^pO^)a>8sj(dL;43%LsEct>!H@>c73:FS3WaS4nenolX>][RJ.C.*L7Y-iW?Cn`K:#k2`gJ#4[0pIN;a^Nm.I!*g[H7sV".i?]E-7]5s1@"UWs.o!Wk^@"`=7s(,gol@dlL86IKYnc<i@1QHA\_<=UAIN&gcQ@RJ)(cMIptGsZ.Zp-]nW7VlSbEm68e8Gk74p&T2HXM=t+#8mOml5Ua?1O5F?\E"VJc%]m?Qjhl>I67D'q&_`T1<((pou#MkJsQ\&AdaoW/K]C]nA8,AOsBlL.AV%adG6Bo73,_fUqK_N8M[p#&bh,2-B\e3o_Y[!S685`nPM[eo<^/'I9L3VF@.d>GlDOBMOUfe@=ZA7fS,4'BFZ@:]Fa##9Ej*U6^HP&&E?$cMB'H;%S?E0(+Q=3@koS-5J6pp=>'ogVj2\%=!dVY<WP&(dVF=l.KakFH9:i$%C3p.",%V'?a9fEB'b%7=bO<6ReU9!%$aKXI\4RI&AJ@3Y)rIJ(%Y5PIKr)6*MT/eO&5jM$0^]aEt%#5O@23br=.3G1c@-W(78\>aCI4c00jS#5aH446gp6]]Leb#[C=oPlhlD[,<:H906g_i&@;Pf/I$l9OA'>J2Ud9uRe*$Df)@W?I#@/d8dn-:bUa^G_pudNG9<teU`Xo_onY@(QZFXaK/=R:qq[`bMg!['<%W/b8;SS\C*R+$+WMD4(p@(b[/`)$aaQHmg%G;kSVU`0I16Xo.E#q^HgC3g/<\QR."l[h#q"")kjJE6ThZ(iBAJ>O#]l-rO]dh&NJU$D+!D/uX[r;Q"$oIf@;&Ki+A*sqWWY4_;de>^4>@B1QW!2Ob'5'7M0:#s`s*\.^Z!!X->O+*Mu:W_(gqQ^-H7`E!J+HY+MVt2A01FhqrZ)[Jbr%[,n2r0!eOmX^i-]f]XS\_KIZJ33bcL"Z5Nf:?_Pp6.+$QTCOb57qFfO+`cR!e>ur`'8m\[^VAXMF1X<0.89eR9db-#<">H/?LjmuE&;djt81k.UQ.o+p9`Fbk!D#JT9fA)-NHF&,P7:5&.;`'b'l\1r]1B49^V"XU4iU"XOD)XlNfkZHPADC:j=*KH?V+Qj<s+KEn%B/85b<piOrm\#HOu)=&J?:N@YBP/Q6iCX:n!82U*:;-TIHOCM53_1A;1PK@E9F,.Dp35m0>EfFZ$.7a&\:hBK_K(q]LBm;F_CXVLB+1+B#MW."l519@U+0j,#jh_Rd'##IuJ([N7q5i,7n2GI$?aMn0C-ohTA%:c7QJN9-mjD#V^T>V%(O&jh\G((%6EOF67Oj/pqGV3Y_%P>IBN&<d@n&FjED7Q4l:JMSS%%(3TF+u1*-;"R*ce21Z/d1PYAru+5,Wu0s,@]#At7Un.!@j3BW'Pdn$1HZfo+P7+"h@A><65^TnRHWF&&W%[(2b4,ER<p(CclF,i2ZmCOBJ^4Jr&pKMqp5-EZn-RfNs?ukTAlai#Q1BIh#`A+rtO47?MAPX*hLCX%iO13g%s7TSe?`/=J'_bX3cb],fE*u:lOEPjOH][ob:Cc1`)/ufh4ZgbBu9GIT\3YfC;8/bDr0rT@H*i$DMK`+ke&icL=QFDFjrTfNqmo)scpQO&5L,qsCpfXVR_^\f^IVE;<c7\S"%]Afo]0f%7H6,lQ%+2k=Y`\L4@gEAJE9(8J@b@lq-aAP>LCI[eF$hT8TphsRu+a?*8^pmeM`]ZFS5h79DORZr._aY?sq^E@uR-JVqOI>m!POEC0G_nrZiQ@7lg[LO^N'[$S_TVADfnSe0]rh"+`e(F\aI!#GAB6m7XmpXBT%4fsQO,p68O=E\n:I'd%,ttk&0L'omBr5h+pc5Um%+YPbD@NAWPKAd-S1i2KBYA"]LF@sP)?uBs(&>NLCch(RQ@$:RiQXXb=[dntI?[M1O4fZ[31I2lBVD$2dI_T=%qa`AjS"q1dAjWd`g^8SRQL:,Da$/>n<**8?lbdupn&,\I.E/(6q>jbXfl?=NL:X1Cu@dR9Wjg'62LIVbQE-a6SSY27046T8I\%tf^@,.RPK+\]ZdrW%^sgDB6MJ=\t/d&`B7bpesP0l2"_E*HjTtZ,qkX9:*hatn5Pbp+9D*?]0A6k+]]*V_5?K0[DrjnNtH4iB&72OX^V]nhE#-I2pH&pn]$qr1$o>I?ajg7;cq,@C>@lohO1Oe6c,OKc_oFFkE:iHUYa%L6cB0hMkJ-kP2JqY4'Z[q'qe\]JkPnZM]Gl8MO%/C8Z's,IHAk%me,D;cn>;Og7J%QTZbGE,W1M#B;Wh+Qk`>?4&Ik6j(a$7=]%<:#;KpaXI^I0[>)ar`JoXr5uUdn8,+490=UUpp4)'<e1U'X(Y@I#*JDXcJ$5>`dJLKU?H)N/8WP\aW@hcLh=Y$]B7:&"He>3%W;4$TJ?!0Xh)k<gbf.MJDQi-dOMh:UTr$&J8r./ak1,_Z_0dhr00pgH.+MZcT0B``\-"P^l!G'sJ`r(j+iPl3q@l>+dJ.I+f]13QSh2$7%@EOh0^]gI4+-Rt4AS<ILa5$<$[C-GY*D/mp7X'gUc2[&e?LmbhE#YjZfa\0X.ER7rbl(j.X=,X64eDA+4N%+J9EZS2!B8p&b^W*1.&]Qj*P\md;,S7APsqpd*m1WE_,SMrppVp8L,?9oI0\ll%$E_n1>KCL`(U1)F]]F1ZeN63?7XU6i>-/cj^09&OU7UA1hA`k\Q3MjE/a6ibK!U'6kO/a?rMQ#/dd#bC_".1H2^>7$*NrLAKTLhI"n6WS*.K@dnT04,UV!`uNH8U+fu2W.`j$1kE(neYWJ"pM^%Yb=CurDlcGK%FgJ[ltP<hgc,!4$TC;noq7s!EeY\C9&#hqFCjk#R5DUS_=Cp3mW0$]%eI2(!_+;ZcZ-&L\8_U=JqoXf:c\3M(]B$sc@KAADA-^r,1?P`bq=R_EM_QVC][:JN[GFSTF_VT_lh.cf<TQK9g,m]A?K=;6mjVuoGJ0D1n<Z,prVGX1nG"g>Be52SA_@2@+\^P\I8/^P2u2[!7Lu!g9MoHKWod8$r&!B!A!I&*u3Jq48]o5]&[QV)K2Ld6EF<U20sU0G(uY,4`kShk500::<plsZo1iCR,V%M8mO>PUXD<D^l1^:dh?;g8/6k#mN69G(MOV[OV4:*62p5%q*RMA7=M<7+>fid80e<PZB>iRX?cjf#Xjd'.g3WG0G=L`c%O(IHt?8B%1Ss@!uunqK2!o<6Jl:)o:neln:%@D+R4B,7=6^(CUFfB#r)uuecA$'0fT+"Ng`,GmBm'3*?M@I,O?$0?-N\,cq#&VO<('K9L^k$)RGUC8:R72cm6U&rA*n,dAqJJ.FPR'%BO(@L,99pYT">s6d/*^_`Kd_EAqll.+`;l)@"%%b_FnioYeUV<"1Cp/VJuc^r2ULoOMVTS$e(nTC2RN2`Y2rBl\4>WbJCr*KXo$!0(A*^E.[I(a]@+\8s]iC(tmN&X8$5e8eK_#WupO:g$j+)f>k^Yui]'+`V*RbPoQ8!e=r-^Mt5ZZKKd1/$pTh8u`mqCKf(QO&WfPE%N-IJ:hMe?O%l$7O8>$o\A'0G6`DGVirMl5sQ.p6*VdP<&P5aLeH`_J=9mK\::G^3\h]ei!W%CnI6<eVIK_\Hc[[MD$6X#p#X6>c2l;5?s(lEa<g,(Ll=p.4o_eFCT9=*jesFQCR>CgEYC%-1K5#2Ldj]J8:hsp%U(Zmi7X%+RW>ZFlGUbSL#PMIF0SWgmUlY!K(b]]V_khWhcK?k1l)]"KTRsVacf8n<&cMK-`[!<`G<[H-4jrnKA5hgYP:56Zq0EUC@'SVU[ZJ\%mPfZT3&S"^,%H\4]nS#GL5gprJ<Z8Z'$6(if5o)kO2("Gs%"NgX6T]g&]e6J^ljj!8O,U3KW]n'?+3VA8E<bLTt5A*@'iF,JSB^IGXr&U>i2P=$oR=^c3afb9(#5p^_pTLsl\rUIk:HUV[u\1hLQAf4eZ2P'BaK4.mE1MU3=-83,b'26\4;`,k2n/1D_2RbE7%:?I2]^'!7H6TmQD#<7b%m83tPQ#IRP_"@`q'kIW"-d3pAHA<#$*?1GP>E--I]/,^=&6ZUK:Kna*V@'bAD'6]>nVD1>AIbEE`%n>h*ba'5fL?u_'2`613et=epYlpBlC$'#BQqA*G6qug(aKE!bDQsciYaiT"2%29,b@MU;_gn$@%*gY.]1Eb0B3pA-Z2[!"*[G&LiuA#anr[Cf&2gG!j6?00h`Qk1jZTpPY*-BXO1QjB:K,._JNuQ-r7("&Gj#a*g7V+L;biR(cQ$N\b;STR-S8%HpbU':D>iCRNhhV_YJP:isgdd,I$oN9Iphb(P)#'p0aL)8&hipEY\*Wi?O5!-hmVh'%"Q+F!/E46-[ee<&$_4(?rQ-3RS^W4%4P.F&bbqj[sY_&HgQ&p+/6l('`4J>l4>Z6U%3.ZsL.VZMnIAe0;bb)20!*Ye6chWc"]#,,!Si6".*h77'U`d:38g:C"6iTL"c:!YH!ZGoJ@:J4O.kD<,@<h"hg#Yn&e6g2jq3;205u!^%Lo07A'jkTLH&[#"LJ@#^N%ipn.gmlOkflo43+G9ULH5U/:A3&'3dl;IsR\oF19RnG0g0"<3>7hj4J6#oL^64l,33"N#AbICK9CPULO*(lI\'5o:Ze#pp-`CoXthjPAPj<KFoI:>)F.+)1(6\4/@GfN_,_bUNJG;,?2q$%c?KS4hg)J7RGL77K(Tu];VqCs*j1;3s'GZDBPUp.eQ,W[pCZY?^:I".@3_(&M0`:ukdHiSL8C1@oe3tu"!g9m%iUE[2o&V.-Z%?JE,Wj=fJ]Ja_4\uTl^qn:qL?=kRS8MKKhH1r6s)fs=X7nh4g^moW?4@WJI2FnZ=?ujb78WlCB\]9P`c[p1%JEMN>2!l>Uj6#i`mQ-<K&4D`es$49<R5_X'8%@q'll2./kHD?I?$8i)OX$![HM1&HTj*pqiHc68hCr<4frjhNl:^2^_'D#\D@6XI0s(]6NLj&Qim*qM]6,fF'+Yl9HH8X5GYH>7`WdG(rLVN%"&$h9:l%\91E9n7d>)FsMdmNk0JfJ:3Ti^)&]*Wa8:hn36%H4B`^uscr-P^n31DVD;3[I@048`;%K^kc,micnlQ#j$Tug*[Hl*]]b>'dUjQP\ml4`b<!T39.G`\.mF\HPN8/X2o&HI2ISh[*H%Ud,7=f;eFW82DDX2q=qfn5S5AP+9h,VT^Wdf"ST=t8tLcFHjad(W==VEpjc"WeiC&04<ul$j:PFHZZ'ZKj&gfnr<6`4fIK3A'iDF\$."BX?34)U7TDEXQTCTOeUTP"*g4]&l$,i>i`.0;88r-'P7cTO\W8qF".e()BZ?WY0iiD%BoC#M1Sbg-jHU&N:gCV@E<Aar199\Onrgaus^Um=W?g+30/ghu4^B-I4"D?+<L#Yh,la,`Yt.m#lTBCJF.?NIEH"1"`$gb[EUoir;Se'XBGD=GPNj$qF<4:g%*oT"1/K[!a:$5[44c+:<Mj"nfXH^VX9=ZOktjf&g>q#1BR+@\qg8/`q$^6n\;FH3siP6]rCZct&^BqBH:8%r.l&3\s+r;<_:tD&,WiUqY.jM>3)cN1ll<E:Tc<!f1>kX9ekf[`>tTKM5*]JiD=),8eB_#Q(+nm$rZ9i,^N*0.N(4'S+,"8*"EH@<6aI?[3#/0O"1$WSFal[-fFMZ(s2Ej/N^gKjk[K`)R\VU`[PTO)]kMFq8JC[6K5-TU8:rmkXqm-iek!&P6S$(/)8W70*r3OAIb9fk@Wo&>hO^pd<p>YYpH80gnn1_r,E?]C-/&"sEN$6%>NJHDaaHp;$N)]Mquk(m%#Mnc@eU0!kl>BEWV^Y2[mh.;]ECJ2e+^i1Jh%aF9'c;8apZG!W&Y&UcRCB!sgPJ3>>(RgF?QnR7/[SL\+krg<k#Iuj6foD=.q*K:tjV0#Cn%ZY3'lVR;Z^JX;AiW/pt#=7^0lG8Ym]qi6)e2Y%VT(D_02E'[%hZk+K0iAe6Mt!`B>=0Qe1;NROL/V$B$;HarDTdL_b:E#!-*$$pe&:jE<LhQ6lVn_CPrnClajJ66\nD1_&8Ll)+ObGL[s2%l('@-Z&?dW8+W*:5kp3\V&[4*@_.or$IAc.]:6J3S6(s9na=CY3,(s[$\K(E1LPCUi+']Q4>^g%UR(5TZAb!QN!2RgDDgam]P-mhiHgr&:\:RE$GgA4VPSuB5?Pg@$+pa:,Jnfe74b.@,UM,r'r<_,RhBX/[gM4o*H[ROE#Ok9PZKu(O4-L*h"OKhd,'UE19"Y\erU8X>e_5A#!<7:1<J(1]H)'%D7G2(WZ,nIA:kf<$?o5/+MkdMm9dalC!T1]nqajbE;Mkf26:-PZ'dutK6k>aqblZoJ@3ngV'GSn4:nS#H6Bk(V8cYSs#RMqHMARTG'kp&[@R?2j$A\\>#"XjhKBeO#R"56H!W=N4#R@'4T[-jE+"0Sta8mUO4Sen;LB]o<!I8d$%C?6\aV+L'&Lq3+no+%L1sS%ZVbj%G[T"J1AMSk,>Z#3f._uSH*SnP'i=!7&CiD]#N1)#sQTfSJ&1.t^HVsNWB:2YClaSK=U*<c**%"XY(kq<fLnIM.a;s4Jm_CSVnUh,rHZ%N`.Ei/E".fdA&qg;'Lc[&;4*Ul*;Zs0gOL#4U-6&VMY^F$r\n!:cK8:e+;aL>:GF39=7!g$fd3/:^U:`X?aMZ@9SAn3NjM>3(UZDb"P9BAlN"KHN6;aCd2%9PV_<U/Bp'^O1)Nf=\$%DKY52PneY*G;a)2cc'Hu%,8SB[i0#aCbY[%>iW3sM:eHl(Mr6"^4q0t$IA+@D_g`sDt2NMCkM`M3a4_V;4t9k`b*BIW0=#e-p"ilF&RJVgag`po%%-%(.GK0W0"_EXY*/6p"!)F;M1Sd;3`.%CqBp35Ka3sY"Ggd$Ou&>9(h"ULbtM$rB7L?P5=jEpp1l1I3S\pQlJ!TCVQ9_T5rC"^A!l9KG0"'3:i?O&;QP_S=R%k%JO*09ltaaOXdH]5H[\"`!aQ`ml]@.U\/E*QI\VjQ#/0pF)9YNulA,t)?V=j7#9"XP)2L+eaGYbS8Wd)$bu;'8-tS;&GJ:@D43pE+@'r"qM)!VL0#UO@Y'iug@"m\B<7pmI$#@@4S2*7Xc)[+,Ho]I?&LRK^P5$=I5.5JfTJ-5h[Y3D^8VXcapccVbA1E'_T:+0>D`;go,4E`=qY[:Fa!$k5c7LV#8M8L>UC3"TUXJNNE<jLYEen*Dk*TBJSUP7`eaieWBmK;'Y$$R?Dj&-fHUbCTC#VXga*LS4YUcj^>A+qt()Q,lLYBMotHJe3cLJ.`tK8nONTL-R$j!`]Fs+9Whh<'rs]*gBDf"@/d`"XOUMWCk];Nu`rHLWW>Ue.W'7qpm]R-;X,UO6p=5&,P)YhYRSPN;;gk8^Zq1qQKf0F%o?8&.oSE1e:L14=mcX,!g\[1Y+8K@BsLj8[(]Q#Q'YpM@/j(T(hk^k-.#EL#1ifSj4!tUDAe\\0.N2p#_(d7#;Z`)`6XiQI]D*$RKbki"R>hLu%mdIU'GLMFkOP'-4=28"Hu`BO..!0-<:<1gFkL9HK-P>DOFNPhdI%,ZNJG/dsNrDKM'B_9l\'OemYeJ4TD7r='&fM$T4f"T_.<`2Q!udN\]=+3UHV4F2\_P6.XWZ%(a!m^Lr"Rh@R1nD.*Hd\aCF%?a#u_?C#g!JV0Q-<uEoJkOkqKD#15#<;=?9SG[p7*p5kHd9<[7Wm\>:R^Nki-Pg15D*=L=J);p:E].h=Jo^+'`dVto6<InQsb3!p=_1fINiE/%\I3p^<#l0,%/q3lIj3pUVi5lg`U$O=,EqBogo$O66s]oI?VCjg9;PtFU!JrbZ"<\:VK3[q.;kro&]GNPj;`oDC>`biBjrg=[LPH/J?b6=AoC^755p_%j&$t5%\a.[B3"o$.,+E86Q865hA>T@T?;i-7/jFOM[FsOj6)-k`GG+eafHT.PUKdREc50mRS"FRV`C7rPN%8EQI\JlmG,1r^1-DErJR8JM(Z/S?6aA-DT)qIlk]^8ZhAdYU<kD;)hCIN[M(7IGPr_`\G1]*`lg.+HrMOiY;?S$iT,mnh;HV!J/#f#*DY4_2e>qZ[?A0+T_t+E=D"qb8ILUqu*PD6IRe"fS0fBmskU]Xqmj2aRC(2rbk:ll?Jo,Q<dh,Il.'l"FnA.9#QsJ#r*i*6AYe0%u]<BPZ^19_?Z%QZLNa"K43"SBKl^@g.)@)eZY&apB!hW-alAf/)d7e>JdA/.Vg(`(J<shp%QNqHst,jS>%D9bZ5lS!66/u"S@`#*A)n7*.1u]eF0b`MeA7G#Z^Vl#'PX+JF!Ink-uZ[UWgDaai5+)UV&.Za_I\Urg.sZ1p:ZD&#,u`&)RJsQUkf=5\Mkjd-?0>','SC5UZ>6f)B$TDj/T[j7"Gl@0FA=6\e/D!u,r$C#e0Cp&rk@eF?72L8ZU<SgBJWe8ObsgXF"PJ%t_eFM@8n&qC[mi=_J$+HSbV]SdCC+P><WKT7&^YlUZ\QDadF/-U-Q"a7lg2FrnXc@Q>KeNfc.Qt7g6'9ahED=goLf8pQ/c81MK4(fo559]kS<d'(K,kI-<EdsJi;r-``o^ugQG<65dB6kkkbCdIt]EYAFXsQan13>(V3*l%2MhN[54e-or67W%?dqmrb+^mD$:2(X4pX\'jjG&<2LZ%?c!H^L6Qk*(lAlXf?W"bUUi4*l1YoUsp@HN0S71>28G?3[8[?@3m%hiTJO%W!eH[F[]<-9DLh$h@jX8Zgnog`rk@^X.s1uF1@>JF,7$sq7rJXZ?nA/b<ujeD^J=BngDN%sVB;f_:HoR"p$<h-gDb&ka'C*Tef,]mT-3oL-G8$/n>T4JnlId@G"biEWL[d\VJLsY.UOpW,([>kq_&I)*2.;+%JW'8l6Mi7Q^mE#GYNg*@U(bDSb*2fq%%!ju0H]Mc#_L-Ohm$olqhs9Yn+<BSV=JZ<8oK-6[ojGTSaFVd/A.2^VXN>9(Mm6;JC0A5F7aG&\lu;`t-Q)8u$.6tkGVbaVd%V3mC$R5#Yd,>eqR7+LL#d\`hF4^[a+u_M``;Qb<8;WmF!I4%@1*^ZOZ[*OmTp>#fU!'mW&L;dp;$$g#(SO^iLsh&oF0FM6i0LZFj>WB"\'0*=(.5,gge1r@CJ@&"4fuFk<:8HVj/#bJZT!oDIS&X6QL$@NW-Y<Ksg-1#J!cmmgBYsC;&;qHD;tPg/WdC2s%qU<m\8R1'0a&Vem<n(MPdda4>num[Zgu_;&m>KgNX&La;,%/VV^sI2_3ug)RnU"/>!Un6WGcPt(?L@;?e*\*Cst;28J;k8Q^VciF?I@LX1_Ot,$,?9I(hi7!qF'b#)*BJqa6gi.]j!rW*ca(r.B)WaFg`hPk1gVbBdd#$D-/jTdl*%5gMdJ\ko$]\KAi=6LF:<2-Qe5bKks((IrGRlXhok,[M6ZY5u*5Tian02I';H4H.O=m"0:!k(hU5'T/F)tMP^kGLG<Z@sJ*s=_t/jhi&:h'$W+uR0oeD(A\"Gd99!;FtaOpWZpD=9n.<Ci+%IP'bi(OG3)40#M0TIMffk#sQC+b1Pe6eBed*Q2@J"-B+]?%KFMQ<%G309P,Pjm?RmpH*5[K-Z6kLr=$4"?kM.*Ri?bfEAD_QDYB";cHZ*MPD(q-BQV/OCJJG:'rEj%Mg=B&:X%k(eg#(@l\Qr62@.RO98rCY&Sso6t44B.jP@O=W?&t;2$A\-A-sI$8.tkl6"agjU&=\b/'1eJAR0Ib!O,4a'P'pH-DrUj$%0H(B?hnmt&N$mOX5X=aF(0WTH4Q!&?VS0\BCld@p4]I%`g%+qTSJON,qYQNne"8=&T$/G#[44:Qt+&YrHEKLr%'i(3jaY%_C(.&EU3*#Y0O3!d`W:'6W2?NEXu5;8ApReK<ONs11?'-Vnd*8"Ph['Ik3(bhPVM.Xbg00t7MS*Ekl/E)OEb;DmH#)3X,6<S,!9Nf]0jH+6J56r/MM4Uf+EDD_4::_!_ciN5^(<s)e<?jVuRa9V]+H8.S_cG$fKA4F-jQR("a219cE1\<H@m0Q*=.kLOjlkWa83+sZ$$l_s92q8_#+Ce\cm"(u+Y6;f#rk.5_+9YO""jnLob^sKJb'Kh[7ITh*V#Wf;AnM$mU"c!&GU$IUW2CQ<U)3Aa1/kjJbdgV5J:#g8m%h<1*O1(j-YTR`R"gF),`h=%KdDe'VUg!Jf'fB%no&SWr-DDqpM?l.prd34qPM<K8p@3Fm+kK3^XYl7r(JNG8($NLiLkA^-""u]A?il>XM(%7&))D9=T))E:B`0ZOu::R-rX^.7tcB7n7ZUaU;ZT(ammBa7`@IScF?<ra&V['oGG-:b#P5rR2\IL+qCpCm6K#D+WUW3[)d(=r7arT:p*u+MmQ>:?.s2SoG3-'?Ks6(*Bm.TEe5JQ,ddkZB'`Sd-L:oR&#a7H'b6Em,gha5SksqmjZR1,R-,7TP%4aI2bSk'MX`_`[LZSRtg_sRmRu(/^^)P@tW79)j^-)qrSNqVl1++r.Wn(YCh@\C^hoPfOne@RZ%QfNWBOp+piI'DP<MS;VrSB6gD@Z^?(QS6e"Y!5B.2_qoA!)N5$^L:Cu2b7T)_Sh@>PZ8-LC[5q"Yi4-*8eoUsTM.(IQq=u9,6"=.^Z^5gIO)>?W-E1*,9h.=MVRqN!Z@XXo!8=bS?9S(05QtR[9)l7"IC6BiU-q^4n7R>:N#;eu3[ZX0!IY5*B>87[1>[ZJH.eUB9JY:gU*DkFSk3FA-(4*QM&G.CFopQa]`Cc`C6cFeS$6DD7ME'6T)sW^J(6o2J'jtkoduHhj(Mr#3gd7l'jI#H/.TGc%Jc@XV`RN7eFb74V"QKc!m(hpJrnRb482:C:1sLM#R:,JPE3f-*Id+655Wd9\p@amPbn5p.K8f^F95hcP75u2*>%(nJs.CjA`uZutD8J+qmRf^T96B(Wf(Z7BX+aeT09bY-BZE-RL;k47DM<o]bQT\!5ne#o,1O9Le/0p7.g@i`b6Zq!.oolR/gEfR;CuX<\fEYSF8L:Xcs#UaL.olKS,BeLXVHi*HK!Om;CWYR@jrcN^c7u<]bk11&R8eL1[0uM>$J8q&iL!*ra*\9'D@1K5#U6;9thW1"O#d>BS_KrW08[2M!A8'k"1^C#NW6<Hpd'<N1$hs597WdNV+9D*,1)BP]I!KMG#@l\:b]'DDloaVgWl+l(b#1(g*$$/Ti]_LMkb;UmU=]0g=V06kjn`\mi."_(d5PWR,c$D<meX[KViX+NkZYi`F5>'im%'fJJ#gG^-aKHQmQD[5WejTY1*Va1:NXd%4"):X;^S'C]5NN*&8%3sJsP`e]`@l]7IP?_0CID=1O7^J+Lp(r*7Y`j']u\uAS]-k_mSc(%>Zo**Pugqh-8MA/_Fp<*XG#ggS':]r&B;Ad_8IT)5969g82?2[Q3jn?`npH>%(Hp[bQY-Wlo&4RElfb5#9$M"39.@Fc"<%`rPQP'$TcIK?D!+Qm:.6cqELZG7i.T4gOUN.*L^8Y]23d2@LeiU/f7QlUlJdm1H>T[SB)%#<7204tQ[0lAa_3u:iXRWm'.>$SNVno78,GM_pA2pQ?/Pu4'jJ'#Y>7a4A,E\`lE+V!u-?7Y=f&VGUGK)/t[A7,KbOo7*NPs7\cukLGW[aTs8o:P$3FK1(2q&L85/F8[E+Pamm*/_+NC'oZkU`D"*MS6Sqq!)J,8QUR]7*NVX7POVL6(,mN$i7Z9;5EJ'5bXb@6=c@!dPCl0\.#*>Rb9O@:B<c-WI>C#R1JNaXop-3eI3o.l'@XRR@.]_^RDBBdt[-+G&-F"njPL30F`-Qt%1j$m`c[H)E<&aMSI_13(`dhr<g?n6m1;@Z2/R^SE_7"1K7R+3=9X&'2aeoO5LPjG0UEJ"TJZ'f?XUrupp]q*L1#7R7,%^rR!:%4[8V(QX,jV)*,n+Hq9C&r+"'ZsV1q#L";%4<P]LVW&okQ[sQM&+tG?\13$^9I^3kG]nJ):@'*8&gW<.E\^ap!Q@FS:(:AV.VrKLU)H=n;bEa6KLOUj.5GTOrUoi6TqlCaAdsP4)GSNg&_E&'E*/,GNW'A[4;HM7%5%:71C1n_AMm3u//h1UipduMi7]?\S#a@[6a8Om-'oYa6FaIma875EiGuSZIO,*N3`SZJkq72(G7G2PkA^>4WrA/W7-[&n:n\jr6`5Du9=!f^/$>/6.7TC`*+4krWG([t],IW"BU"025fGR/W,WqMOarmT.TM=7=sY;SJte>NBppB6TW0-8d2IfJ.B/1+,mHKa?SS4($gHKsPQ`U+<CG=?$QGHN+[#S#Bn2"k7!j7bL)WB>KC5AH+DVf0RA14U/=[P;'AabM7PK'02C,r1/bm0K3J&/+>GFcO_\.D.,T&[H@QfCW\N!Z$D[s<eB'TYKqJI2Yfl4d)$#_O\cB0I6f8;234:bh7*04g/c\.BUR"JocjD5r`m<)Y>3V;qFpp2VMOD&>@4^41$^f"PC89bl9p6*K%BD$15$3,,+D'lW0'NbjU_6]eRn9tC(1W[AI$=Y6^R_6)^1lX'f5YS/Pnc927$7Ue)R]3En%g78oBSrNNM'bh<Un;M',U-.+ECE5_YqSmC<=K'V^=T1Wp"V3V8JCr?Ou'%U75Y05qgk7ADbrBRNkoSqm*b)W9u9GU@#U>+DX+2D33!rAJAhh'6/shXhZ9"5/Nud@#$o"X+IAJSmoq\9$GaN<+*q^.EM#Z!?X4R5^`g5ic&3/9DWrCnMF6htQHt;6ZfUp'H%9HmXu''DKefZ*Q]!@,8f@^4EY:-S?%Yr2rkGe6-)V7o?f67YJpKN!W)Qr,pT:5s<0CsLOHO_s8*<@n&q#W0c0qB$(?Df\I<EnVDn04UT\alKa,S(_p+%oIG$a=N=$]e7]*(`$WMU"kBgV8QD$&9=8<d:LrFA=ib"X.\FH[Y&U*,+u*AaQ2#Xk6b2kQt]][JiJb=Tt0C#pln><\:>]_a^[6Zh#=IaY@#%TUXlhhJ;HESt<fOGf+\bo2LJiN)!pG^!+f^.,]o&tu7&S9(AZ8$JbNk5=b4Sn;1ag<m/.)^.rc@Ek5'41ibcFDH,.+EYptNkYq3i#'h+$^QIZE4Su]aai.T%!Wo3%j4Y9,lq0ZeY5u;f89%T.!8*YAeQV0i8,TdOd6gq!Kq[GnakPuQP8(J3fFnI1e4+f%s>-sL*f\pi!5bQ5=49R%K64HlAS2VSl<+CC`/b9FXd>kX/.].FQqX'*ZT@%^!#+QfEo7D9BiMEK4oZdSlsDe^KsPSd9dHj8R#7*rHY87h$kZQ2W:0,&;[]NUhL"+2,/ma6O"G(Of`3M]%8II=@9XG!4s)/jRQX>+?jK?09a2#EG237)%DUmj/ZTu0A8Z!+Z1Xr/VOU4+;b+9Ju9WA;J@7tBOjh^,7$hr#?dHR@*L$o]>1?-B?ur1RrJI<.)6Hb@/gejT*+i6Yj2f,k`=-`Q1c:Ho!@V2S!\2qqHj3&<4R2#C`8b9"gG\H="\Ut9e/oN7>%l<`3HCcB[\CBroU51"1geJmJ[:[E_`dD1$;O,&Q$X27l^<,Dh]c9@J-8aBc0UKg'R%2<g;[tM?6,.jGQp\"Vtcu4V2B[OK.l&(f;Y^+X/?Q;(Ls'f(?jd(;%eggV6>)4_Yr.Xs]iGbn2dPii\e4,8qsZ]r81M.4[a<I-BSK3@8sFOlqVXEL]/?kH:#f_RZdC4Cr*QO4EB'OI6d>=b`h7$SsSa2gR9,,]G#S<BW'U*D)*.0]dtL,h\KJo]hJuMd/q*cKaA+\9'2PeT>.>\5da,ERI^EA#n/6X6*;oREtG<;6FRW^e_;::QI:WnG#g5OerabA=So-OWq?^+U76W7<5So(G?=;95X2W)5Rr`@4(.mR$sMJ5$^5GZ%0]eipoFJ4?Hk/?3lpQ4<og#0Fn(;1smPaC)VsL`/#7_5nQLE^E.\X1UF_QL-V\a=fbVVi+>`UfjaXU6MT2n+,!rJcPa9>%:>s3GB=[$&'*P*dcEikP<#sC:5I,g178^"6'6J>L@f)&6pdRsN?oi_Z\'eKSJ\I+XJ6YK^CXmSR$b(PM_%3_4p#@3Me3SSiEjH,hIPY!X_qrYmG1K('+?X:0YiE8!J:Sm^m'rQ7?T'.]kWkekWQUt`_S;E+Km\H^cQr'pY*q6G#V;rCPbGnT,c97]Pe9a6iPq].Tn!k9!F(Sg7(([L#.*8=VHd,V\aAMN?H;YoM2k_dctqaK]DU&n&p%>BhpZnaeU`Ae!s;,J`2/S/tWX+*Q>jqTr"I7LUu*/$tgn$_gm^;'DB@RiI`E)X[ADL0r2!o9bJ$=kA`.,#9Fk$XV-Age/+IkLpWTW,"!H/%@r5i1H]rDR#E)qkCn&,dF1*=@'J/:GQM_Uh`4m3`K$D'o]gK_ok<198B-\Ok6F8T\W]?W8^EuK,W.[.&L;ZpW$(JR*Ha5fno7T6/;2F/Kf!]r`DM`H95^0<1J%NYgu.bmoGkr!Z"[(hp[KH>;(V0>4QWE`@g'&X<7W@@d2>[,*>G1rO-M]rK1?O1I<ab!Ws$h+N",kG.2;]b3[qf%k6cS(]6irQ/!I%p38]Yi=f/XFH5/<JD"bS+Dd()NpU*Gl0XK'2MM>k'V76WU\hPpZGIu!"IGL'=2jc6-%@sT[P26/K6<cO,X#M@IEuU*_k>g9EWu3JU.B-TQ'mCQi4\0n<f*iO9]AJ/O$s&2(GU6F-:(cn?_\)"r^u)UnNd\sSXGF2f9H'APY-(\>G+oCJS?aLff-7I$enqc$5k+$\2H^gUV]&kCpX2g+7%NqbSi:gN1QN<L>S.S=>654O7gqDQA1NK=NZ`.^V$%39X/[VB@l!4WoH%OCXaIWH_Lc9Ui<0-h1i29n@uV>13Lgll,Dr;1`[,9)3Z<,R?.h5Q2lLksKbJg/?u>Z=V4;*T$^NH#"uM=@^>e=a,kbiM<@UuVl5*Nb5E%^=F`r(N_:EOaq<Zfce/kY6a\L"K:P,\0RPdRB07i-m0kmYaL`j9T18\UF]r4R`HC(kj0\+(`HPMBt+V=C"[*iA8A=tD&.\fOX;7#Cd%`2.rCN1/;_@T(Q`[&Y?B]4TbNV5s+I&9f+NU@\3V/m_j;iI0P.l$fGD/`*j^6PN$;UI>PjW'<7G!?]pQTB<-WhM[&\iSAh]fd/-P9$,TTUVfu#["N6p.IB-GuA_#S`Pgs>)c2-2J=lhHf#GS_'(tB>pYWW,Wdp+n!-6`0L:R`eh9<N;`\5h!1P)[MfW,r<2L@<LBk=Vd%Rg;"d6>`YD/f'GnXNMQH2cO8UU@q4?X;$ifD1]F;Jj*,*R-(ZuLq+\RMK]9tKG+AiRD/g1C+V8OF4k=pO[7,sPZH>#I;hUV+k<oa[;TGk/7j/2_4L`EQ%'R/;7a(>I=haf.bSiP([uo\6OF/f8FH>u4"t8>O9n2HsJ[$q:?/75l0V+stSl8"KCeA5f@B5'JT$\eF8_QsLdXSu/e*"6K!=G%Wj[+hQm?0Rb4o[D`Nn@l.-m@ofS/[)NLc8fh"[Z)'2_ANN/10ooQIc"=N2mjVqh6"L5#SWg-Ebf*9HE+nXb/kP$>Lar[+2+0cj29j*6?=W'_p>W@)-^/hA,OV,g^$qV%eLe)K('?\PPXA5M\nnnS>it^'V-rV2\pDHa00$,DXYWu/V`HF_i^N2lnTTgjlTn.Z7>#:$P4cEE%LY/&VJPlFG`gdOC9FDF<7e"e0o],*k[B45?!/p#;)^m*hg#X`*As`^W2fr!p=hI*a*';!67b"5@=EGFX#A4?4@apDN086Y;4FlTM3]p^$H@p@bu&adO;VQ*So24+4[,BTiKTlJ<!BES@BI_5pu!LLM30LAMq0[PS"P?@2M'q"(i5M#(Bf`5*='Vj3YHdm9f94F^L""U\e^a3.&a1i."p=k1sK;]ZL4,q$TVhd6R9M[Ec)i*E6`3tqJf`J$^@=f1ncBD=C;hZ8d8O[5'9l&%7=V-Ru^m"<]rmR?#E@\BVoJ/=,0?%33jlk!MJ_Q9a=HZdt&.NN$40%X`2fq-aCKQ46]dB-urAS=C.]6=P`gOGlq;[_._R,7LQ+`^sob6Xr\@,<4tHQ.sX9R_Tkhl-/.`>::-rle:GA02BUn16I7tm`h<tG*$I:HJ^]>#*X"4EV]X5IG`RGM2'3HNFZ':d+E4!8$jIu'^AJd`n(0Y]8;q2PkT6#n+o37/V+1QE$tG`6ANFN,>S7A\5m8qG>u#)F91Uh+8gP+/;>aVVQM[MCK3[529HC,KR:N/"M(s,_=RNEWl&Ds(>9U%>.Wnd&)h$npbbuLBC)#ZJU%MbaPg5\;Wq1@lFAF.OW/>bcRl]J`jX7\I*]mA[2GPo*<8G_5,)@]qN23-sMB@!&^:h3`1i9tOU*=ATO\\H"MHjg`)8!_>bKCW:6R!%(W)?;1KJT:LE"!0:;R5b\42nB-M6SphX!/gST-P2JKs[;'$\bn+cRM*s]*6B0NonFHb[SSjKR$9[f[F_u0Hun0dPqt_k>iShahIZ5`:Q(S$tUc[;b*l*&CfTn/;Ee[L-jU2M6S?Hi(tAt#*XegDf>Qn#7W8pZ\LY*Fk)@7fL5PW$YUA6qABf&.2#*."S(<q%5;+oD\AbcS/UDD7YkdcE#j_&$AKbnT7cVS+%gR4<+Dg\guMt=S.3E.oPc+/U,p6<W,c/p*,P1Z\.]:>@]HH&RAf'&8O914GXFu17kR>0:b$UC5b)GS-HjGA&SBg"8]rS'd2<E+HmK0XOkJb!n7Nt,N-'cJ_hG=QaOcNHM"7nSg8$OXE/53],Ej&`og/6Scj,["6"jcl(BHK&l#qbpdu[Uo7f7Q8qm6I4m8%mJM$f1HA<+P/^2U>2"?I:]ORN-\Ei,D[#I)"[%*lTM=p.@,<;$9ET/H*:lRF-i_=:d'W5o.k*CjZ9+*$^7I7Laq#Js%<3X\8Yi",NIhdCq*9]MNem_Tk\#akG>k+!JbQ1dRc!F2U^gc1!^+;qO+-9OE#!q^kpOobnDTHZ>u/2gHd,3SEql`DEV>>H\?Omo4+>DBD4$0`GQAeC^>)+k#KQ.h25jK?L&`C-_=Op1SDd+S)5(E32KdI3Y/_/eMj=]uh(Vhup2c]+K26[Y)%+s%;ZZH2U$/;q/PHUOcglAJEL=Ii;EWO&L*=1E=l[tl>i)\2+MJoTdMIp"rml_EH,HMHNk[VG$N>e&g'eqdlbX!q(`.k?`g;^N`H36,=W5(s85XJgFZI&SMn^Q]&+Ut-kg-8_ZU%6&`Pb4cmKcmje4qXrdYeE#H=\n94B-5*e])N5&aJlL+]%b\87JnSHM7f<EG0P<b,7\LM,-o>r;`0Z\/JI^rp+dGq8e3+dZTr%C*5LlMF9n8b#r>e8A-c(G8mO!Jf)YaGk&jS'6?4QO_YnA`"!`;45C`jA_3]I5cES0CFBCJ\<J;=[K5Rhn"ZlP%<9/G=oVs'u?khfZ6s-+Oq$'5L]%>h%N]XTY'`Gu@SKMZVCE4o9#f+EBrlqN_\'gZ>.:@%VIqS7aW6=V62i6'L,.>DF8/!<,Lbi''#1Ul&)LX3`P;bAE`N1]42UtB"oXm5>(O(:br;u)@Q:N8n@XHDoFg;")`M&6\uQsso%/92Z'g[N:IA>UKC#kA8^H+1ce%a2VlID8:f0SPNY\gQMI!1g-\O6MYsdK9b<rs"nNHo6CV$1s!"+ZWE"%REKCK``7OhFb4V7Ta.UXZ<:/i<Bc)8B.ZnGi`P-hcn,6LYT<N6r98:5taVmd'>KliO\(pPA#CpKndQV-nlbta=]#r$>Zin2U)M'69q<OB^ko]#k%fm:;F'eFkM"iq"mI+`?("h'/1r07nTuVT^<#O=O;^ug)+Rj"quJ$b3^U^Fr5nAefB.!+F!0:i0C)F4_s=iC1qQX"I%0!H1UY$5b:(1)q^"[-b`JoW*PiWk.i$.(Nqp<BPObrEQ:I:on.`5<T42^)8%LYR7nhE#f@,Ri<pcM2gG#@4PPOR@S],*'LCE".\t&!;*q"0,'T4h$ud*>Dbe54q$2:[oR9:NhBap';cM4ECUdLl4fo$io-`m&14<)MMPRn)R/VK&ZqeW[L^Zq*MVLo,1['5Ua.=H+%,mrJ]X2%"'#I`kkO_$'`Z._23NW;Y5oRZS8Tl(q)]6C"iXASfG9%JS7C/_d7^a5T2TF:I3!sm1k=9R-hKX9i`8YJN8MY4SQn"1)3t,ho*k#N<A.&O?'atFBd)DELYGOaaekB#jl/B,iQ;0$a4k9sTO>n`^da2<3$P%AP$i\ngL5\a'nXqY$!K%RZ((]#,^mE>$M%);;aWJpu#jaO08u&rEpu='8`?;Dg@O3LheRf@I/IXRU3+?0n,-&#K\Z&"K9SZ&P\u4rFS6e+eQ6bD@(TSZQ0ttiW&*7#iZG_@2I\nEV_8/K9o(a&bm0V*bH2Gs\TJ*?`@ptKk#07Ei3<D2OU!f#D4ee`ZkfOU<BJ_77BQ9T"0e]JF7)`)p-u&P!:hTnQ!e:MnLL2,;/PJ]:gUBg:(bG<%EQG!.o"5i[*cUp\\Yg`iRYO!Ed$QRi+_?@#TlX&h29i&8Q=C7NeV`[1j^$CJA/_A-^q2)[L[?GW-<Bf90<3$6?WY;pUc.t^iQ7`$dA7%f470"823%7!$m!LW2cQDqm*h1iIZb]e/#-kL;9I"+B'#`"6VS'P0ji/V2q'PW18HR_6_)M:mjkl8:I3/45f&(b9/3(T_*JVu7FL;(#0\F(T\teC[`5S1Si<?6g3pAgNRI-pL#JrG;""l6mA`-UZNtY'rKKXg*`7_S38h]Og#*m`0f(JBLp60O=LX@oU-]QGg4pTjco35*)[f.69p*.37Z$,GU*bYq7T(euI8NG0";19foO3#j%dZ.m3$JY%32?=6ILpoE2mj&lCG8:GTQ`XX]`Y#('GM.B$D8=,H4bme4j#uSXsUaGZk@?;D_;UmJfVkf$gVJl0^_2lO^J`.\'0B$7L:%9,#H*F%rI,XL/marb]S]jI6K^%Af']Dp^3.'P-)]jc7QtuM7bC.!RTNTbd9#58)P4G%c/:og\6U1b%;&inNnO]0QLuQ%JM!l@Tu+=\E#T'*&N#Bl+L=*_O\DbC/Q"2$A>&6JJ=7q8JZ6*JRU#P50:(M+DIOBd9*#%>/08*#hP@+qKM)7C\I,&SE<kI-ObPpL9_V".TB8F6H4q#(AN1pnM$q(#&9giI,T>6B2r0qD^`n;K@bueSFl_c-/?)2?9<l%)iT9c]c!32[]-a"`Fnl;EQ1ueVH1`OP38\0mZc\Y.,.?GZJ)-*$6[M0/>bD"q_h`f>P42u0<ZCe*12t`ohL=9Rir(LY+j@(YEVs]ZD"k;$9n!*QDB_%;\(ldP[+b?>3C3S4c$)>N8rU:L0&euA[KSrd06IE(M7d*(<esP%MD%logG7u7F:;.7X1qZ]M#/.enF$_MFb@3jIAd3:452Vk$=01X-le.-,KIbD!-C!mg_]d:9i5\D!`t3AElMJRVkO?d7ap9#b8!@lTnAZCh;3%E+.QY/BH=NmM[Tt;d39k77*5mFZ@Z=`C65\\hL0g/[D2qC:bc+N1`fOYjX!=3'$@<VS_;e_pN\eQ#U"Y\IQ\`K?`]48'FK"mgc:iQ'?0u7@B.%!V!s`Krm>^$#NL6'beT5*Z(NC?8coId(!CVJA_HY@5:35qFi!Ri9?*N%*E+;Z"0;R+cqSJk^kRJV+tL3UBHAD^cdht&UH4++Ei@*JlSWWKqZ<9^_D>ITTF*mk([9'dP2"RNahVu1^U5+!'.hALN,`M=F2:10_1DQro-82H''mI9hnu:[QK=2`#s=5d$b46"38%6Pit)3@ZTd?bss0a`"O`!Wbe/,6D2F/`ZS(s@b<AJ^j1sM9`=:`$0\"57-O;-6.-J3j1\V=`&qQO8Q(q4Q%3J4'k'^&,Y2JHR\Z5],cZO3j5,*32nf5EGeDLn'NZFUJ$ZL?%L8_M"`R7d2`M_I,HX3nOo`#&Vr]-*h7'[50.O(I5^8&/=p[)4&c`Y*+TU:^kkmUmG<;DLE?to!dX>4=d<h/8<gjhAf@e.cikK;Y6#e?3+1`!8g1QZ0*IT"hg`=@sk]`HtJgBoNj#')nE=X<#0HqA#&!(j7XXsos94b@?;3\qhd%L1Xck@%'"^)0DrdW,(d9bSVYM%Z"`_Z$s!.Ih58JeOM'E+X+[+[f.OGjS*&.\Y,.k@eL,`G:0KM=4FJVG<ek[51K7YH=FB$<3[60Q4<E_k%IYm`!<U_nNaquFM)Buo8:,j]7gCeZ7$;f3+U.$1e%n7Rpm@QGDe#s%=?kp-_;n6`j2g,tFh[s:L4`Ql2i>\O]$cXHdBE^t0X@g2XOi"uZ4mNG$X6aT-(&LM.>:S?KbENu+X-oulEC&[aJEYM^:C`!ENgA1=R)1Re<#a,ld]#$ci1*Q8c_qb6eq%t2_F]\(:3BK#ra]^NK@\:9Qp`*$]J0/f,.S!kNFbDQ10:oh$CiL`HX`C]^Q'b>?'-4'>+<T$P$m)hr,*"@Q8e`uT`jFh0KdIg8Y_fd&NcF?m7=<+2@mV%!RBA?AecFA-4WU%&V''/V6O%@;m%86:L'!)PKpE5s#h$>#n)ohD6PO.i>WNP(K;*oG/7?@ciWjP^&Y]8`&VuREZ':t-kpUa`P@8[TbLtVZ-:q1@iCoEF4NOOn!V`0nksgod@?T-U9Kr!,`WP)GKG4SY"Nq@-6:qJng&gr_M"%GJI@r9>ZVV26,VG$F`UIMkH%oc;3p>!_e3j]VPa'N_`(7gDfUOV7d0hYA.-j>)XQ^_#Va=ltRGJSBTJI/-/V%0Ro-Qcdl[e(mfc*i;Pf@k0#6OF<cd6=I=+W(V%T\C.@LuR.5YLOR0kE_J&'#/FP!qQF#=9-*:spZ09X,lX-m'!-@0.bkTqD_sKN#XQ$a3UeqqqIP.N"nR#p+](VZ`HRaBAb_%0Jsg6OHJ88Wa5i'gYY?#M;TM9SASO$S\@g"JjC3%"q/O1e\8[1F+Nh;UH`l"H,N3,bjq.!&p%i/--$P8Gsf?+e]^."]f/"dSbVX!FJMMAqVE@p`n*)J=B/-.Zl3fT^lI=Encf1FZ#lEEqn[L2h*I4)aNq%Zos@-KAAb&3;;E(,tI/0Qd!?;gED8>!UamT`Nu=d(*T*L#gH=XqhPX^mnE5$1X.&dcI;4!NuLT[P<<aL@d,RdK4+Y)*2*QnO&V2GWo1"=+3UgfZf!Zu6(BN@Y.F/_0k%4tQN9AQA3WD?m%S7A&blDIFT)D(V]b`:fP!3h02`VEU8FUiOQNLUJ$1N&1L$1V@X3cW#(:f#W+t]t9suqTFYrQiO$I/U,s)Dq@ZSY4r&l(:kom0c_J)]&+DJ_QH_XY:FlRrK!g*UR@'+aLB%E6fZdO^RUU[tG5@[%]_T!n"1mG)9[D=rm;[p+)L!q#K/[DV<iEPbkT@8*(-Dpb"C_d?B+@ZLZL7:^e+jf,cn9n(HIOX8T8"tKO"taNC\2%h[S2fkLrYb8&(cIK)4=AY>>8W_Uro7/a9kZ_H;?N'9K7\9B;0J0Oh_]CReg,Fg@<ad!d)TX*Z)G"lS.C2n0:<1C$E+TCI\oL*R2@uCEJ"js$7UMiLo)Ib'Kd3e56b$so)KMXT@S2drQt=d[u^$d;I,8^6rD\b4W0nd@)aOn+-39h$OAqkZAUn#(OpRp;Q?Ios$`6djr2aepKguY5<Ch5i_5Tgj6a\(QU4&MhaG*BSjo:l)*$R),D9MrWOH4PlacU]j@Q,l8&4iAS3ZP,jYXhnhJtss6CU:0`U&i\m(m.$RpgC,ETQ(okQXod,ocPoCG#MA9OG8:M--Q9a4RnuQss6OpeNm-rIe/gBF5MWL.YC*/>.K.*Zs?9]Wc)F\Wj#LoXgD;.1X/iPbI4FR"dr[%4_NeV5#/u_F_(T-urk-+qu.Q0Vb9C69TanZ!aBr.'Ja5.T_$?&$a2``"(p)1S`0GX%Kup^&\7$q!F]#i]6T#Hqtp>/lk]*s+Mga6:(<C3?"`5"_)",`bbpJC$&j/JtIi1r@d9h+F;@8+FTcKWc4Il70Ol;H'J?-6WV-QY3cBBN='b^?b/P+On"UL-3,hBBY7T6nXg@&I0M.S_.Qt+$ktaG"^%'Fou3$DW,uncZNK<BZ2;A0O*`=1D[I-p1E5/7'N5H%*OQ&r%448g<F!ViN>rW'\q)RMA.^+fC,AkB.Nfr2pRe.8N!Gpl1C8RX9N[CRfOA%V6g@F++LhW>/gV?k!YMqVct'%Hm-#l1g=eYnET:ou$43Lp-((>4[]iJ*2+5CsX;O2cgUsc%cpm&3@4kid75Y`[;!dCb(c@C0fl^D.7=r>h(gKa5X$VZ*.,UF28&+BUCIBD:A7J"5E]O5u-[)=1lG[?>e1ZXe_MfO!UJNZ_e:qFbDogl&A>\(G29\K)C-h]J[D;QXF[Y453eoPRPQn+5d5@:BBEg8d9a#imA+k?NVn6GBlGRGt(<F'`%CBm<d'Ad(6di)1%%g$_$nqcT0O#D_Q:`Sc2Ful%9+&&cEj)0FnVZtqM*-Zj04M#lU/lq=r(hI4[#TB1C#_U7'@85'UgHK_HlENs0d0]"h8V"N<iJ\3$EM0%Mg6"Y_TL;7lQ82Bm"(%nBlpAD^p:mqBJkn;$/O\-KV\.;4!U;;1jGWUqUe%!&E:V59RUAm:GUP1#u>I&)Ni)MHqsjCLH%sS$X1>99hI/P0M)g@3'qa$QO.-nk:0gKlF<3D7'NpYfj22?d"1k\gs1TrPsZ*hJNBJ^;O?unOV1LMG(QY:$D'Uu.&$u].)*ta<\/nm'kHof*h;G[WYj_C5GqhsKTDRuT)?`=,rLNl&eI+>55WLfJ_7^A4mDH-Eb.US'RWlt!V*r-@-,ZJs,9DH=Gs?jP4N$E>N;:EVohF^/AoW)&gEWV#FD&9&Ir=+*mimjL]OcYR*_[0"d3.Y\"tW6J1#g8T0<iTkJ-u=664ipjIZAr%6`PueV)8[f^C*Q/I$iQ&l=t8U!S-@Z"alTOcKr4BI]r'U2Rol]*[4?(a+[0A:U=dG0'mRi5(@%#c'=d'DJFE05&B_Zo639hJ%ii8s8rSj>cj[iBs"1)O`]SPO.)6>1S`[f/B81@-^9)l#hH&kUX-24,+=>"sG%Y+Wm<s'dX+)_&dGZ6r^K,>N5rfRffB(]^@gsjGR-P=UsgjXD+?kN_GO[-9PhX#P2rpH$LH:0D=H;PWcV7UWfP\+V[=BXds)d'NWSfJ<n4.;RXAS:nU@EIkJl?FFInT4HM.F/;r/E.;8M!$5*\PofLFgm$O/*`1dhn,odfK8i`j;mcJ04rgg0JgWGLKKc<#GC,'cPg9R^)LsH,0:bYu^f;bq_dItNh7)3[@cc;DL4fp:9ZnSP4&E?D%rKpX7/X6ba80AHVU-tq5nkbm6^gE];V2Z_U$u2e\Tni"+O&osAe:YaOTE)=`+G+\Y&J,,`3!;'$:#G?LJ!BT]&teeoc)O<KHA=(LdOEfHYu]/M<>mPQ4V``oY(HFcKdZcYL<htU"4/4:BM&9$1^!Rt#f-'CU6_AU7M.?$$o3;`#tTa[LI`qiU)a;5RRK&1Ld]c91kAV^:alM]"ThL+)H>'E7T=%CVigW.JBmI$!aeGc%0enK2NPd(TVOIoEO\*l?i<Am+B9ft+Xm"SAjQbA7U9nkgM%.FP]UuNTS2uPYW*;bScWHLdLp+g.!:ciKIW9),W6[MOCg.nNf#7p5(q:pcPu?0G8m6Y"&Eg8@<_eLZlB&a<=%6NVN`Mk,,eV,PpT*iPU)t[kjLbM5i<01rdnIJIn'c+G!79^g8Jf.%M022h(O#UM[Z[@r,eLG_r#oFU\thh3B<j!^#uU_LM<oP2lT25!1q-E#=3m\[g^15?.1eB/3>XEN,Np5H7li\c#%m'iP"\.*MKMC$Nr0@pGjY4K]PX33S<9`Go2]X.*)Y,3IZEIo_krQN]1H;@E,2O*R>3P2ie%(c=Nfh=!*a(4$QL8GMG1D88t0<P]deA>mr44kEmK$+s5Z\AK@c#*M!rKq04`c?s.>4W5p\3HAleko01d!/+<6NQl22(O0/\:Se`H*rqJt",5Y0[?Zs`Mo,Sq\*2OUHVbbS58E3$frg6!E'R16)Gp*!pSq&2`L^/.]oB-4lKD5qq"XGB:2+.KW*rLH.68iiqY$+)<#I"DT^&@Mr8oEI0#AQCn<&sljG.YOOed#]0(&UO3kK#OOYJ.ZSVJ!D49FPBnUJd-k%`aD[Yf^&f))-7$ZVRX=:cSW+3YFF1k&SD0c0"#,r_Q!ErVRBF"\))(Gt9bD4g7<d5C(e&Ha^'R%o"MB:RAXW=5l9qIdCen28.&KG/9ZC9MJG:B:O[+HFTjqb(DmVT8#uk6cuc_EYl^@!C<c`*H_AsGfW1E2J)XS09X=U$u"*%^d\eVjq2Nk;FZa1;$15C9\[$n^%%uU*Ah8[hMXY(h-6]Cm'CR#E",_oDBNkE.s8;^M7"gj'dG.BoAQ;mmQ4CdFF?_;dIk2q/T\No%+(L4M@irU)b/Mql@EaU>XV9*NiQ+_K5C\1C`D(oK=XR-Dh`GOW#BmAJ]CFhS\iI1#ntTNDENe%[$k;B<'5%DY?XtX"PA>f`RHup>pXdPOq*=!U^1KS\SQ!ffS*f^TTp$+7<%6'^r@BspiN!*-FYti75ENJ<B/W:h(B0_(_n4o1h6b8B]"j!FP)h'n%kZm)B'BTgaAt,OZc4c&#Kb[ICRkpUkLh;-X'EkN4*]PM]bb46UcY=K,^R)#9N]>LJPGQ"B4Fbm[XC<TgM!H8UU>sQL#/T:mDI&O^iXrl4GkQC;880>[&,f&L-3Z5T\,7VMEb`QnAEr#Uk9tZI7GqQO^fUB&=HS'7j$q8S)Qb7>cr+\[#4'l:=&#("<p(9$o#GXc69;i\k;j"ZM2IJ]E[VBX"F/M%CjG$K/"Nc01SI8TSqRTlfcD_%5Oe%jgqe\Z<3I6k5r=Pk/7LGe\D>KV@E)J9V2['1rEO"9R!S6F7*9!>$Og5n&SQ.!-8%VtL71,n^c_8]98`LbMXm"Ysb;'7lm7M5l7R]/*P/5T8W%%+###!D&1O2!G.kQluE$`.oiC&4u6k;$^S60VAuNd4eAt5Tqn9ar#]]R2o*^Pdo?I?r?QHG&.>glg[#\pmhTf8t&he6o"bhOSSrA:VArD!Q?.[+6FCb@ph#?Ut-Z31=_Nd#X[0*@iYTu'NHVf\hE/GR"?.Xkl"'42j'D5gO[,E_#DY,kM>>d3'5M@.h0TY8WTa/a5r7I9$N#:*<J'<WMElK7Y_U'Ps'R5'_6Z?P-:hcU^ircM7o<ELf@)(1os;p8qn+XhldU`N!S[k%H<2Va<Lj2`->ZX(++SDFtbn@V-OAj4uH-<Pjj8IO'=?a<+Qi4O'i-o^2o`6j>s6L$rf9TBs^E?(`UUfRlaSWL9ksW)3/R57s+*@cP<nQ,C/Y/-!jQj4`fDT6V,ucG(6"8^PZ>jJOM?QEF)c$@ouqXaXTrmFWGU-R8SK;4eKP5H2Ei7FsNOQ`0^)u"5<gTm?-/<UmN&pPPu6Z+Hh>:H[TB\Zl]^p#_jf8Aca)$!Y=:k(a)ADW.KSn-%q'gjWJ"(PD'S]P6;T<1/'Dr/5fiUaRM<_Y:mX<:4UIh+ij<J4mDi(PTHfcnkj'Ik8,R%VZ+H=S!-nOW_ebR9$j[TM5`>t39qamZ9u3T9hWR2?[Y*B\at4C?$Y9E^%bCDh!X:=?7=Y$>O9$k[?-sF=qoI9:ofd;;-kqMSX^[>f!@'ZWm.\@eSE)ZInJm`qcVMFgL]]q%\FBr.OIiW@<&a%-CFU1<u#MmG\EZb<R)#8d>D&Sh]T`ICnRdVBTu12:t2uf]3o,J&VQ#K"nQk0JcM)kM%$W]6jU;N9bT9K[2D&d7j.B`2h2qXcNdM;,)jVEEL*==1@C<,e3J[s22eTWb&)muUW1).#uB5cg[Tjk#r54?!ON%mk42[e4`V&QE[:aPF\7@jeR1Q?EO;e7WZUWDF=MlO@i4\lI<&d2>/FU5@WA,#1_$3jOs$=mD-LK6rSSOqq&"C@d4A]4&XiuE!JR%P2_<>XodU$)W$!2"dfF-`(jQ0&#"j@7ZtrDis"9H&b8^#pm14oh/18E0Yo3($pTd5a#TAs05C[;/^s%,;fWuH';AkGSGN:4G5b<Q>h?1+=%4Ok95u]-e1GV<_<AI7$V$TFYaT5"3cqqr><D><3&.fF>8r5tK'U9A05p7dU+Z..D7&1Hj8M*b="@Of^1FWG-,_P0/TP:*o,Sknsi=k;L&%>\8#;VYDG_e`l!,;E31mniD[gh0o:P]6omiX"YBb^D[+V\TiM-<.eKd6p,qnI*[.V_RPS3u:_NJ'ZZM@"lepBVk'(b\D2&hPr7PQ_?r,uP:B#L4==Y`fJo+Z(o''dekBP#*i*8BE=q,XbR):%V:(]b?I6+Nb()K/R4MKA:f.g^gUmprID%O.gq]!'kQ`$V0PJc%4eb&oiYSegJ_+h,ILm&5"gf-A2b7rn\.K`8@^p%[ck5DX%g!7Z^'XOJuWOR7&n,!#On9Cg).%V@5jWam7XkNPP5PMF-9s"63F$B7bQ5$V5#N,WdWJc"uBPr(UTI!+Q*C9[jBX0an-.&Z:Z\GB\.*-4Rus!PqQE&dd%8S%c\R6Vr!$U0qBa6NY^&H5IX>F#b!SUIoPF=WOC!*C(;!Z?IM_ha_tORmn#<E+sPUI:_3mGs*4uk$V^SI,Qher5<EH'9fZGQZj@BR;!d?+4SAQ+a\Ro:>AeXcAr?rmYbV1'*,lk#NV?m&o**8,R?Dj&%k]L<2'[$d4+h4"057KR:r*[&&L_1d_?%D0d"$le'[f^0.#gN1IXo6<@gR4'V_r7p#]JKG3uUC+gD)QUOCt^E8)DKH1fS`C;RtqUdV0Vh,nd!/sGBOj^q_Kh*fLI_6Kja>Eghi@[^;!1*R,FckS#I`Bt6'?!KV/r%A]ngM(MZ0M--O1jeI:lMA#Vm@tMd9PU+Z`.hB6X=!`?rs&.@?d[j#_kIDYCg2;N^%N\gR"Gm7Tp9ahd2O)q2f9k!k?=^T@76pCZUB1[5pRZXMaU*W6fl6+(geYPp];Jp`Of9uSmd'CNc,#Y&)doQZW%a/%^_pF#LZ")F87fC\)q/jW,Ci\p\&Ko2#LiQPRIU,`KLT@eg`?+cZ%=+W);@-$j0?L!lbqhY7X3Dr"AGHWq?#&>">L5Y(f"g,bYN,6/re$Ts-Zd75c;i0JGjd_M8Z)onQ:lIc%:]HP[QmIH_HB"Y[Y=%=O3QZ5\e@+80+lQh%/YjXRrL>1]+JZR)?;Bnc<5#4C0ORh3T$fHFZb]KE,7*'iD>l.\?'13nC*C]L.fQ`PNKdVPMI5,SCDH3/t"=F(VR^W3nCMpDat'<d)>#Lo]@K9&<<ahAG0n`G^W?PUo/$#eYm+c-H/ml/ZKW.K&`G&eniXYbH9Vackd0m"EB_p1$[RMs+u-BN62:cT6h'g<>P_T6*P1#s?^KATXT)bphKp9N>EPaQV^qR<J*C-T$&?At9UoDDVYH8S`/[*"*.S;%gXR\*6paV]PbWlkU]brtHP_RT+gM]aKk1c4V&BT@o.olSA&\r0XBiphjT1c+)./0"s0)[;(,`_)CDbU"]s<L3!pEKD`]R@r)on4XQ$i&2BOO$e10_`]0n1ajHj#VFaeD9t1ASq^oj[@hG>PhaEu'.fs6dCJC#B=Q':pE@*KU<#V4(`EIs;[Rr!`o7=R$OQ<B^J'l&N,'qC<5Q[dH?/M1_Za$l0fMIA?'a1cN/,]l\kP!3aosZi\JC(]iF.!eQG9qlZ(jtQ_k$++^C(i%qasc?9\M<IE!YN\.uX.r$nA-W=X"]-KQeREBJ_S_nZ4>d#8.5%K[?&4%^YNUjS@m!RmR?hr4:F0HKd[oL'7D.r+1FI%T0(d<ae!^#YYh01'(k4=e$a$\&)1T7MM0k/IYuS@hI3R5hdNHF:i+XRms??W9g*\mq=?Zi!:E`M%E2pY_L#9-_9_O<^W:66QT1I4lQ_'aU&gaH2qPllaP]u(c-mS&E22*j!Uj?C<q/tMTUD2DPJ;.1@>cM*%,]M;C)KH"=I#i'>(K/\^o"85JNHt4=YAi[Hn#Z!V$%"n_%pN<:GRpIV;CmL7i&ZlY%?T#*s+6$.5UqLpYg.7.Q2ea@BgY`(3_#`D$I=%'hT57*e7T3>fS_K)un-qJ\Pr,OF85+[H\s'd,k;E=!=ORg[#(#DXqXka_b5//RbFhi&(=6\]tu$$IH8fOGJd(de]HFUZi(K+&SfGcJk'O">ok6hNi77j!GC3.MI5K[IAC;T^;b,=ou?+tjmL6)+Xgjrd^DF/fs)#hm`5g1\WnT`r\5BhkOc[8KSs)+$0qN*tHE\`7PS6mP<"S$M6lBJ@a9clX@OT"Z=i8#$m,\LuR=G4TdPJrpaHk>YhLB!.*#*(E6(`7#OF8;:*soGQ]M2N*/g^n\251$cG+8]=sNc$]u]:C@E\fVcCeK@pWpjlJu=^dHU@_FD?R+fSb<(^Ht\6fSJE[tjOsT8*Jj".nA4;T=?p>UI%LA=AV$Jf0.i=pejc1CPASlq`+,JULc(fRKuocf&5naWK%`d#4b,C`A.KU)MBZ/+(a&oo>u_MKf8f.7D?7+YZdjOr9(5$<Wj]__Mc+&jf,^f#CT=Jg..>ckP\.:Doq9=Fr+*WKp+)/RUn`$)#`Z:F#s,ONg@M9J=(jjMLCM$>\t>^!*+%/f.r%4b[?#(ltTXfjAB/$MSS-1bPZ/32<:26rCV@F68c-Q_I4/8I$C4"]%f+'7rL4ME5T&"%6OoeO`6Q[e5-bpTn.?cd[J-*5l:&Wl/SDjh\CU#Y7q"PB6TZM;d)=cY\TMW&l>P6g2LV,_=c^]OYK45m+V>JlI<"$"[Kg,UJ_+lqIf5%\Q/#Ul7lj6Rag,loZMm0REHC#Ec'\`Gb[Df)AO2INq+$-u:&.'9Jt9CoOHX-kk\4-S_>)99"b%S+9LOf86#b5HCW6BUYAu.pn"Z4P#Q?S8-.^)tfAJcRRYS]/lsr35%^2pfOK0=,VDAI21X%[[CG]jd@Id.[AobEDQ>#S>tlBe_O(d_ccM/'X/-WSZ<5'%TRDMqjb&a'.TVZkE4D82K'pRqT"sI*>?Ti)DHmfB:!@Kf<Sd'@@/?`6OY!4!(M?2m1\m+'6e(&&N567L1_AKEVPuMl3[u"7+_4ElM:<Lj+*]379X-#eQ&8odWh.t&MrY&\"Yl3BeT!N_Tgc6ZGaRj&RfbVQrgsET(C1*k(^f>I[t0N`1V)SVDuj6$#(.3f8-3oMA9Y(9Jb?K"X"HQ?ZN.X5#/04S@A)[QEWN'm;n3TR$#1!TfY7O3^nT*L8gF)s1*dn$k57+F]G4nBQeC`dBScDiuf1k-b"CL,ba`P4<t!t_E=Xpdf=&5i,-@N8FeUJ\JQrT-;48lW:h7lg,tDUdJ09D8U\Wm2Gg-"0dR#Wi_R8k-Wk7@8qg)+_W.l\$.0YaUOH_/)AG>m@/QOf)LdIM9KHf]WDcE^4q'T7r2.M:C/\Y\lhM&@:>.@L;-%HD$j;0(8P^P#=CIS!^15XFg^9XWmnl<,R7HL&=!dSp5[a=GNg*(r:D^Dn_>-W<0R4\r:OaWK3i%JL3afSW)V1+'+qUWU"OR4f'WU*o*`ZQM>Z;Eb<(%io$G^;-_*CD^56<f88F9jZXMH66SK89dkR^`($"N75RPA_`Z]r4s"q%-ur;,Hhid=3e4l#]-c?5Ur:Ec%&I)`7$&4i3P@\@YLCjBOKF;5YY4!=r?nkh6!SpE>>r-GfZRf6b8aEu?T")H]+"uC$EJHQOmPZ+8\DGm_N7KUf1%](+A1>H$^B%/6@0[IPGJbaq7l]j_75X`Cf*/A'/:KS(^E.5-g+:%I*JHS4B-a_CQ8ls4n"'\HXk[R\$LclPFZ9>*mOJ3`6'_;kHpA4^!Y3)3uZPEcu1J&XT2trm#4>gW+pMnC=WC0YJb0t,(4>4$mcJ3U$br];FL@-k-Fj?gXmq/;,f@9X&mde.Z0-JFg#E+aP9/__Gfr$\M.)LaTA0";so$Ijs&_4`6_<UjDXX3Z#6I=Rf&fr<LY\PR1i3>-WRX0*%=.X]lbSq4X(1#@r:^_t6![3L=BRbq!@JYK#J*d3PIufToPGLS7l51PG1CXIP:m8[_84q4Fr>D@Up=,jV+IZ:t_P%N0A\s^IaT""cp=TVAY@6u6M6;5ZU<>/iY$EcK=DY1Bh!<&Bof.dE8btJ',Jb^k%u$'\!qRNG8KUl!MnFk!b)<hrM2WQmlF\24AN*Xe*`<8a#t#S;(f\i3JE/1!Vh1cPWSG]$*l"KBB'/&B3Vs*bp^a8u>EcV_@6$^OM<QA)^gYb"o":l%Qj;+^i;O"//r(L`'pG)L(kPu<+1F5EMBBj-W"M\-Qp5$CcZdDTgcQ),e>R+r1D+7sfGf"@3#>\%XHGC4em()pGj+0g)l]9fd)f)>nN6euLD#.fSEmW$^LsP@CZ;>k1&,>`6FiaaoIa@&kl*c)*oj@6Ka:LtL9d\,TrHd3`1WP&1a!P.IN>q)B'fJ-#:7d_1"fetS/Co5*F5^(Y?G>obe)*Y=XKB+@$*p?&G7Lk'd=?b;mD.%%$XRZN=4/=,uO1%E[<1QK<>EHhiKmrg;:Mur%[1LZ>a6Va]jcBj#n_4mLH^9`.8HS,l<Y:8dLO\Pn-KYJ6)"f!YRj@OL-&XI/e]bV:l-9nn:s89DB.Ipgmh],F/kFK@R12\fD?L,0FiRp)WhGBY^MLPZ&trBVNh%-J6e`P6j=EnN6^kT0):hh6g"-eqI7b'fMVLF`pDKUtF<8O3l*p[SV"q*2?1p?;r:C6^)6tiZ/j)LK4CN'?^OA.MpL^n3+%Zf;s/$+'0fuDe!N'XVe?o:UmmB=Z.cU\_Da=PMoEcFp_U3`aTq^FD+?_m)*X'H;DD$+QX<saP/GHa<D0]dX[,W^[BTF1#"]@V?`-W`\b9M"+F<7e$2kM#mf2*m,;0GBd!'Y$KO#_b+<S=T"g>ndc5>"'/%^^[%!#'^,'YQoU^kJ0!5OWI^hKOnX0Ns@RWfD4cciUd6U,L\"Uj&fQVn^./slW*Y[a#g]t7UA!-:UfaS4OI)8PY!E@E5"s'n@geR#"KXG9NUn^p]+4s#75"A4sL,/ro556A52rj001?ue!A**muVDs?CBe[S)'f\"%U""38%Crh:b;IN`5:-qu%YnM*Zlj'<"s1?(Z.5eD?#%S96)?2kL1O2N:Z%,b3$O[-$+ai&M65K;9Vjd('"8ihSAYUMOTpXG'.->*7`O47EefE]-od^#BM<W^bJX33RUJJ)@9%#*(4sGJU&W*M<$<C')-&mHU]T0a)J891\KEZN/.,hM't8?ccJ^@)5n!ud,G"@*CEur$=60&*U4*78cat,j,5mPia[JQN;HY<qM&o&O>M7'-o?S?D<]tX<dhGr)-UgA%820eR%'Z2;Wm*UZ\dU!q1BrcJK_<\bLt%8=(8+ZfN<Yo8flYX_^%G]Wa.(B8Os,&B,j=e0$8t,$4n@s3)^h`bnVH,Q;I].jml\_B<@2l03QA?m7`K"n(<aMa/Jfn1C<OP/.8jd&&GYYPF3V$F3BSQY&PWs?(`7#%-]<f]V@tiZGW_"UB?<6FmarY6P._][3T0OU$qjZKaJki\(go%u\cJ\\W^<!#\qOE!gf3kkjoRsae0P`\`'L9?-4MZJ"N:X7<.r'jZQtd"[1L90"GDjIY63(sDZb/>D!a.7Z[ge&infL5eep#UL'gUd7i67m[Y'g;EE@@'.j[!K/?*2SYP*mO[u(mKMGt/Nj(5EQ9-I(&5.p[RXYb>Ok8i=5[aEHK2b3(;>Lr86mbg0-:RU'/7XAVJJ6GqaWJ+:TU5:Hf:dP4a7G9Y'3MU$=hKm4g2M]dDr"F0#iYY]BL8@[;0gV!Pq,'%)2l_g0qNhL<E?Mi"I\.[o[Em<7aZP-KY_D-?/8147W`_nt%"lY69PMn1^edGg@+a*;p1#BCB-%pEPTI,K0'.(S6]u29BEG;K&\J:6&k'N,'GQ4F)GZ>>o60I0]_!uRC1<>DCb-igJiE8Aj%d7+2,T+J`fb^65<SP38;PNqI;jaIj.EL"bZVHTZ&#q%%5<jN7/h8*"g_%hGjVl+FW73jZmsi7ALNKL6/W[bibFMeBnU-T=buEd,M9R@L_q0%;2BC'_'HBF6:jkA%<Oc?BheX<>AS=G'mVQm0(,g?9Pm7TgQ?eg@HGo%<L:kc%,%#A1G;+hj7jJ"`\\*u"FGSW,sd`rUICtWW.H0R:%!NM?kN$48ha*.%IsVeo!ucm,Rau5P<BX"[:<Q!1!tfH12%sW4'qEq%HbPKNA1E%\i;j3LC<.Pm-VbZ9$ksD4pO9OhT&:a0M?/qI?Mps:X/HOOL3,&74<$/7-^PnR>T>BW1>)HIp2A8eH_[hL0/U\[>3/-m>t-WcXFqPYi`W7f%t_Q)?4FnVM?<GjY;a?p7$hR8/PmgW1=0W6e]T+%"d%i1!%^RN$ZV/Ie,eKiJFOXC0n>?>nbPjA$?B3Yd-U2pn+`uQbQFudmJd2gk[2#OOd+"HK6fK)!ARAdo=b4I9cHqj3r`an)pf')eQJa48]?nU#k?1%,R#/.4/"r1c#eUAkt<.GEN]O@.1%$,##ona>rJ/7(^D"U+e`5INKt$8X0_n$0bE[7^&872sCDHa`n5OP7@pKN3"e\1Cl:>Yh?F\r2;>G_,H>@$afVVmfQt2)@8rf,"f^!:!'(Mb#5QAS/qOh"/JfC;XMu@a$_7,,1U<8'2%]p5$E`a,^?8QZ<U![OuLZU3Y9P(Ufa.m;>c%pkQkp6UDccBM*jX$V\rdXG:Nd%[`0mU.=s?V'M80&k+>Iu;UeDT*tj$TYu@:Nd60esa]/$;k[aMjrMLOQB?*&`3jr`9PJn"4mJoWC:uY&8_[m.6@R1;&_MTmRU?q5Y*;"5[!ukaSi$t.U_!X;.#>eD33ohoXWX[V`,Z8b&1FsB-2D[[]7QJQ^,p6)2S6JcZ6,c:!OOicZA2one'T>Tu"UPTo"K5]N!76sp$nrp^5D?$[DT7e`m:@PXU7N5s3V4.6;_hek#$bdC+><qsAO7N(YUjej8>41]R?o#IJVadVPfj/gXSl&ua%AX:$j!k1YXjTr^O0jS-+L@Im/S"9LXI4H!C8t-V%fjC"@,C@OMXj_6j+/(9gD)lT;lp4,%>+%(m-*k$47W%WE,7`(hOTtJg$9a@?HpbQ6;t)@#0\3Ja\5r&(<$:LNk*R"U]BHQj+m4N";\9rA_;\G7msTr6D$/]a+af'aSrY@Ye23-n'lUM@)m$LkN[*Qgi;hV\a1pZn)!6[Yl7epR!!kO]l")O&p+-O)#tjo^%>u9h<fH=c\(5$/dSE0B>PcUKGmWR5+g>j&.0J81-`_&<'-l$AC&aN<`'tcr,GA`=Q&u4NiO/<g97*7Hi/0<X_Mi",S`=J3=:.4(-u901?q9G0ug-@.<uIV."<mBWMoBR`Ti*IIe!T/4]OS.[I"e(mRA'P+CZ1#BK$(pFRKtp]^_PhN<Wcjc"bC5e`4#0Aeo]pBC[fYEq'RTH\KrK*s(u^q^U;'T!it(mA*iaU%Z*cGB3GND0Qr[6po-,]Z)eI1`7=8.hp!fD46=jKGkNZ/*4=YI?Gb[`YeSp1tW+BPY%>L-,PZgtWO='s#^5D"Sm-i>Z!LRP4Y*k"_@7L;0>s-p,g<=@1[N",=cej-aX&aZ?q4V,C^/66i^g..Sd\Cr3L.X4/M#A%+OZ\'F,A%[4q4j@Wfl6ks:\9cg=SXoXInJrQ&$<QHE$(/(,tjSbFJQ@)X$`=G=5XpXEVl<Uj:`\r&b,[!ImMQN$u2H$V<%5NT@/3[)*d2@qNnW7Im^>p*%68!2s(9&=ZH#(NH.GGfbeoXMhS+qs^WMk#kTZ<o3[Ek-`DBNac4Mj7e@4YD5l#W=lKPNCh^<>CFeO5uD2K/'7LE4S[EI44RbfM[P0_@KNqICp@j[4mD"&S^q91T[5)Ai5X'hbGq9I0a$<Q,CYJaPtj!9cd8[+,L?,%Lu?_%`Q).su6qd/!5@pP/e)Ba=3dPkG$VYb)lLl>[?KTrLC,5n0eF#CH^fHcoOS%M?%uI7<I;:;%^P4Rc_7B;Oi/g_=`q50Wi<JOp`n4a=c)^bOc.bb,ZC:^fTG@L.f$&b;:kXVtT2hSDiY.[LoMPJ;Y>FRD1"%#lnGa:r`.4P#*lZoSU.;2@%sEOd-$#`(Uk@mLf*"a&e5lC8H]_nC$c3A<u8^6H)uaH/+e33"Yt8oa(\Gc'uNEK5E#EHdl.F'*>LhKaaqN;#IMSH][&`"B%X'Yps$L__Ne:luk/+C$76_IE^4e`=X,k2c"sr\t+5L>!i/kR7NSihQl"&J1s?:67XaVa4<d>SW2Y7Oe_5W$4PR**q_/5u.1$`nCos1QQmp8R$j9'F&d,^`07'C^gVY`>Tg0"2d$l\)p2%[c?pA*eEOLTG-UGdZC8ZJ59HC:_42U50daZZEGG"]&S%u5B4)Hl-sM0YEYMBqID;1L`ir68G-OXOs>k]D'd[p[Ym_M`3^F@AGTgrQXU#P/0k)`j9D=GN'$-!.bmOp;,ep8/FN=S&ZkDb9cK"C0KA#:ru<Q1i86QW;\H?@E&p5hq/<:AFMgO=LD:cVLds'P2CSM`=K.868COSrbL<;Ona-88ep8CL7YZ;SJ)N%"3MFG[Z3O#5oT?F<+FdUKfE12p?qf,:&k3C;'Jt_/Y$L@p/N#]f+'s(B@`o:1@A6.<V$<Sk75SYa=R>[Qfc\U%j\d%e2&VnuDup>ucl^pBT9CGu@/#B_&#Ac'5VER6Qu:4m5K37oP?94t(qmd@gNn7]Y<UcQMKo<8=uM.b=Q-0iC1gn.H2fhpb<f.a"&/@99[s.73bPV->CEu__kdhO`@0"iZ7$\!1Gn<dOSXMalNdS?.;3IMl<kH4C^Xt\N1qXX;%NIKN4COC=_"@M8DntrLj`fIcp2ou<T#1U6i:9W2^B[%2`(_-$),6<W8NYmrJ.#1"Xh@d_;W_EJq$BDB3H`0,?QBcSXi;>KhNFp8t"$TR=W@B,kdsT#l658&C=)h3!Io:3=;rH4rat,+@FNP?@Ztqoj[m2r_aReP!H>Z$tQ%n?N`O]'-tX1`3@WD,0^Zj0MDQWJjf.6U!lF;'G+!DO8E$:d,glsjl,.XYlTCqe5InA&Ch'<&CNrd^i:R'AjsMVW+\H?"V=U90PPm(L\;aA*[D-p+TqlM$?oo>:j!6gJ[2d0p:-/+4:o:Motl88O5:2uWVrD;hOcKP.8UOXLVb6Cf3io4XsgBFLD<eIr?mg+!atd!!`23o*q.35c&t+@S:Gg15*t<kTT>&pmf.33o:Fs0A85!;&;:TTYj@"&c_MX1+GQ+f]Tdsm.Z.3!U&K!,>b3=Poo<HnI:e@$1_1H:k_ZXP1Idt0e2t$IQ]QF$*>-jDUY!#+p7VU3I6_jT%Q="%J>\;66AE?Jh72R.n$8Y/iU.rO]T#)HBcV`biN:&ko&L&>KL/R*$*"Sj80EKu#a$;2,$:*tO@!I_OED0BH!*?q!t'5&!Nscba&]:SUj-L:fnpK(/DqXl#Dl:S,^LL=[*l4=(5$f_g))/6[7)dXJV2`SD)uWpbGZ7?K>F/GA<)2Q0HP55l/OK-W7qur+V`XF."G$bg*<m=0LK>lD?=[\)tPNaZjL3$_8G1N6#WZEO96al;%cZdFEmom*\3TgYcd'p,m[mf4<_P&aEf)Q3\OS;l4'G1JGDI*h\]H7+0SEDU&N_/WHO8hhE5+lmLXm<&g2'WS>?4Ek[sfBBf68=crFD['EZ'L,>=e/*Pc.Hk@0P$b'g8Q?=85L?\CRNf@U>,6_Gm\J^a\lP2rW",e_fD3'mG<G_+<pOJpq2'`64L5/C$DK(E6+!_D$Z1'nHAF_TBugE<*';#S`PJJbGtG(Iq<V+5#ZP6(KQ:L(1JfVq5XK+jsQA@!T<8u`(!c3JWZFK#%j6mp&J]i^qSV8/%C?c9)i\Ps@3'kL7Eh$$a2Uh)F[]`n(e7"E7LbOVg2*HjiT\<RL37"k<^Bq994I3b_1MDu.=OLRCi#"3^PPT,@!KB8gRTns%c8:pe1R00Db1H.mRP'`>mJLGi)DFUY>p$k^8AK@WYZ-GH^!-=s\5q["?h*hbrkH<`*odgYGpf^Y^-UER;6nj%"np-#8O3t6I'+4KMPWg>5Bhbs*9S;b=*kbk'8Si^8*hM"4r>'_[kup[mCa&H2$d>mAZ1B"K/Hnh%Gp\7oWS@$^,h!s0l]p10Na(hGOpUWtPg=YME-hKc\!g9.OXS5s.0ln:J[*EtnTT`Y/<1iKE*3jI%LPah#_ZT:qlKkd,1bI*gu'gc)_[*7$9gQKK7JA\/*$C\n+J&V\0#(88$dm/.ai"8U),,o)"J$$M-(mEVFYke)k/#A%oN/qp5`/1*N)-/7-i\SeeSf+^`e->l@#8QTN!'UBHVWB;(5X==rneA3?&"P$IT4l*n.m86\D%SHt`r'fHk\\^?jHXO01sQB%MH<Q-+4n/csdC8*cA!_B1)qT@^P9moJ13*p9J`%VoO2&tKIQn*N5B&J\#3+KuG$CaQF;&*F@Obr'Hhj8J@]gD=-L>C<B>hm!)UVl2bp4j<L?!^L.AjojKK*iD@?q?hc9p4`Q^GW1+I+$fI#I^1<JPn8a?$<!)qfJ4p@S>'K(KH?3#p-THWhKYOa(ia[3)jqUG&H8t#4!odE!9]l?'QOd*SZ3RComAs`rn$L%m6f"VIF16rPaC?[P/u!0@tXR+kd6(1paE<DS;n<XN2a*,G)(Y<N`0^(e!^-FrB_`X9Z7-Oq0F%:J5\qt(>-l_QnUCWl@^H/DR*`':tcZYTQNq*%uLQ&aUmJg[/*U?4,u@3o>NA]XYa\<NSWAl5IKB-'`U4<aEJ,&)++OY=V0:dAl`.JQZe?(`hTV//V0^F+)hZGV'>.e0_W!>XgiqWGi1qH8N(K90snHX9.5B=<>69@9P"H,V'?:EW_=ZU%\"OnQZ#4aX37=S-hq@;BSt+A:I*6sT7U%%/;H6LBK9dBA)!VR@lQ#N[GAh!dDh'W<OK10Rd5./1M3X3'uIu5".sS`dD.\;4+,T!bZ1eoKp>o3Tk)`1iHJ-N1pMa11p6<_EJL'&UGJ'ND#/Ltm@%?Jjq#05)`iUA$gIOQ'DUpB,cL=DDR(HETXms;_or*F2%kRuBQOdmWZ)Ug6u[RghHl4H>I\@GPlRSWDfufRA@X[+@47q?b*"2i)Uo((Rugp1qQdK^Q;ThOLI3pW#<R4lWP?JEe`#D)NGU^GPZ4&9q:C1Z1fBPtIY7DA>T7],N>TPofL+g-I0UFVqoeiJ"*;.Md4^5P@SJt?3['NF`m/f"*>8+O_s@oM,1b4>.9X`o#&Zu-g?>B0)^1SN+mL^Oi7&XLZ3^QJi.8X]Qc*;(+(lbDrD36O1X8@bcaGgL6"1+0%8%.Ybj.<W%^:\_KcDg1X?'7:5):2lF.>G3"+gf2YR['YcgHhAFKF5h[M6VHE46Fu?Z=$K]9sc^FL^YR53(p>Pt9uJ-ldcd(n-E[\D]/\0H)k;"&U<U9bO^?$A\"t5aN"t4d3B:G[[AZn>jMM[T4jgnu0etZg*7,Atr'slZ0Hn.r5]N@jWPK@s9`%;"a@b(h@6T3X\f`^08Yra&dgN9cO\gfF%r-m3f7NH2=&O,qO#D@'IU,OnQG?D6-0>TIiV`QBj@F+`6!U(P`]+O]t;nF#Y%P>)!cdf*u@am+pd$,J:X,CX&P?)UjpG)S]PV/S.=5]af$N(rrU*a\5rEC3N-H^N5jLr@$WMjOf-"TE*X:dR@TbG-kho6U9\,jMUmIFnq(;AEoeU$D$"t1-:7MZFG3A5kH=H8Z@'_+%]d`'X8"FJoK$)TWk\Jm%`>iRHiYH>^*SI5DaREolZ1>WSuDkR<:c6-]InAX`9W&D45IYnE,P*,9b/"eBO8Sqd^uK=oKLc)Lk8:9N'gb$/P6%oBndc2*cgt":upYP+\0T13`ZtrRjacr(g4'0G4<f+?AWA<EC`.UhOdXns'^Y6a81n1rkEii(Kf.[jBg_<1tu^lJAKsmC22T`<FW_SToWgrt45Cr(M&GLgNf9htU[W8f?@i+ZaHcCeI^U5kmUr_ENb%W<u76N?7D@-mg,rdjtqB>KoU[&Qth$0=VX(%`N&l8;%$O0h9SUfcPe1!TiBiYfWnZ1CR905i[,1Rt#;tDa0a7#MIJpk4slui4q<*\EY*_TQq*#r7OVKp^.PX84I^h5j!m7Uis;a2u/1Q9$@!a[LZ_Q@17t\R&[M:;Z\)'Z=PZs'M5VcYSFd$@n__r"eCA=,%2<+.U%+:h+m/=`dS@`!mfRc)&/16O)ETu^Z7=J0L?c9?ljmq"*IHOBL*it%%N.h0h4J3U#(@]GU`1@%HqIt)l)N8JTCR<@OK/\s*=Vpn\O*)2X+eDc]Y;,=0/,.d!^PJS,MEFMMSrPMK/ORjMo3!!0_*50?;`^T^KuL.39'+^cT7.-oW5<lbo14dCXth+*_R.#B7Fq/MrEg"_aKrarOb86V5b3%2r`M`-udOF#5h!>#HXMFqrnCdqL#cU";.B\cn:0g+C'=^J%$$G.l:=)cAbJBo>L6@T3LJ1-jE$2T^Kq)E+uH#1"WkrY5PtfJ6,Qf";ffkM,c?S]A_'$OuE#Rk<dDFj[LWi_5<%L_*r4XHlS^iE?e4k970/lS`H#h3*R,8,EeEMu`H0@Qg/WjJ$kc\Ze.,2/6_X*'srp?(3<pDcGSGg8B^;8DB.1N!pg*/KXuhAEZfeI-]ePj&7(01!e/0*BQ,9pWgZZbiEbjI<E:.f&C.FPHMF\Fp\Q_&G-IjB?dL?T/]YlUW_F4'F]bpcc7Q_%toK_nH2EV+iD:l%1fna5hLFY_dVM6<=&d96Ot$5rA>im:6Q6I8sG20IM>JL_^=I'-Fb,S;=h]JK@kR-$6l45RVF"0[OD]n9*6n:a]2@-8Mrn(,st6<5nl^c1fP2E'%8ZMN2oBH79(c;1^+<+eP*n]9N=La:dYm"9`[YD'#bSb0a(MN3e!,[WE51>e>,N&%tc9<$3G_3j)XH#'&!m]F^jQ.22f9(:e<g4%G6!H7oRD$i8b4:6W(*Cp!H>Mmk/Rbai>6"hc[I7EfBSeH*k'ADJ3G7*(E<C^<=Wfgpnnf.1MF\gCET3Kn25'_<<*SMLk0S#!WMu_R0_Z<>Y9`M`X:Zkn.(2A3XQ6)Cr>/C(4ZZGM2Pl*(,*8i^C8iF_;\3Oh-.HDGroMeFQ^f_DJsDW'<hb+gGCq;$PdAjq*hsoi@LQ0LcdW+[Jtg3b;QQd32251qd?\naZ+P(ulUgYiAp,P`e&P;(m,^(LpNUM76C0,&/u*E7TLSk=^elEJS/L`JCN:K7.;5FOO[9K6A"<NEq9KW8O58$Q;utJX]bJQn$G'bf@mcUt\aL2b^@UWJQKFL/^Fk0<N<LjXGC+J_7sRa`sdUTA?7/[PXk]L+NiZZ.%FL-VA(Gf,)TlqSOh*SJ<<k]2C?mZk["nG@8l`aUAgo`)]Gs:QEq)]XdXZjNq1b'BB@ZMO'*eJt'Y1!KeZRe"p5O$8`5:HnZQCaS&Z!b^#C@3%kcXO'Te/.4?Bs6).PK$`^2j$#jB0(rhH;EW]ftqe.gi5+CTM#@8kIid.G@Z4qs`:4t>LCp-F(NZ]iBC)kAoP"ZEr'1q_R&en=hj=Lb.fZ^]7,a0Ar'#>B=%JO6d9WQa.D,F,rR,*`<WhD_i."@GNHE?!@\;(!+)E=Zl7p@8X#i^juD6;X0V,jP3_Qa[&'>6l_@D&`lJKe(A8+'q?!A#0laH7X5`REUQM4:6n2T6=u'ZYb/XQ23/*_*aZC82c=3l[>5iOb%PM:"c.OMfIJm.J;bJ`+OB#!3c6"K+g*GFic<p#4]P4*g"[O!BJ-Z&5!:%!_8O9FU_o`Er>^Yr7T=Gn;P?qhrrt%Ye\:QK(]I`//bU17,r>BHtYKj>\4:%HQ!3QIN2OH=Uio'LlB&S#D-X1C.SD@OPrT$&/q-YoLDBLb%u^^i'D/j3e]I'%feq0kLMSV4`Zs-3UX]_ZIcnLo'Q/#&cd8#WkZ/(-;Wg]Zh-s6g>2<_7,3]W!rjTU%gVlnnC]7`ql(?X0M+-RY0XJ(=TN7an!_fCsNW2MmE]\JsR,,RPiMdG=f(TTj#FW5U%V^(K=0/`<g\"h:lKb/Z`QY?_C7Ye"C0Z:-l`p/\7_]`@csJ!u9Yk1_do`!D<tITer,=&IDk<7@Y*X@@0K-!RcQf%rrdDf"r@L'Z1!l"jYu+DTOZOPY!Ib>oTGRg<#Hup]CU&-<WJ:#!r*B)0.?/nVE22T)oEUlF\DQ@PFFd8B#k[[T?-FZS<-):Ti5Elgjlh==n^;BXnpTUPHP4GQHa(5nk#d6pW(`Zj8E/\q@3i&>94m!\.2&hYZX"IkJ)!,I[@%a)tb]s$PNOG>SkbJ2&/bQDtjmHL1^40Tt&qd58cS&Ha:W!)kTd&<%GfIt!/`"7#"R*"uETnGe^.q:[M`?8+rY*G(IsU3N+Dbu[-TgLf'[fqBP]7HtO!Th,;V*6(K@G_4"T/,7:#VLA"-Dp4XPQt@I,c/g(:347_R$$uFn@(XJEIi!=+SNa-;U#T@N`ub0J-KEB,D%^QZU"SZoF6(ftiHEW$h8^#ln5sl%)X!&`*:R[HG=Q,^3S]B*4AN#i1_=DVWh.`,B*LV<_2_"rFDG![N1[*P%Y]p`??d>)+J5N2G:YN]bSVIQKPMJRY212/8Re#GbGHuW/1%NR%@:UZaS.W5P+*JYAY>pc`'fKK"+tL)bu(ei*N(mCON`V6b;+\OUg7GqJg1qH(W]S(G-H@DX%Ka`M[Y+>.d5f<'>2lUJ`H-\&I]0l:U5/MeUd!^eWLkgU8d,?<!2JnTP=>=DJ29r*P[)WpLA1J!<b*!)2)Aa*N4QV9",&s4&(EPMYA]P$ZS.L:ahPnE^YC=&Rnd.!Y)'np3Tp6/l\&\<A_W#0SC+JcqrpM$#!3B@L3)BD\W)*%O^Gd7nMA\as:^hg(0XUEVOjnR6r`a&s(1pWA/iPfli\2_7=4@d.?ZT6WZVVA?$3,#%B5V%O*p752W`KSac'//mIXPg)Z'nh\'t?oKJC%As)R0(*f+M?q'fLM"VqQpu74e5gkq%FViG[:FO:r+Fr3rD@WTg(lL$^Uu>Q",]1Tqmq1KH=Kku(En#6UQB0L_;f1Lj9caj^7]1C.d1)&';#Kq57!gBZDY2ro_%$eb8L^Z)USpbH'77K]8`d(/KII/gq7<PoWe_QMrs'D-B*,$3FU:TWL_-MGJtZ:4ZlU9gkm*q2358GinBEd#\K+N#^f#Nd^<,X*TuP1@SNRL^n0@A71/KeTYM#L#Y^:]V&pX\Dq.2D*:`nI4K'_t65Z0"ld6oNGP.!j@D$Zme1<CfdKc"2:L<;jM"#C!l-dhZ1>((#!LP_oVM+O$??;`5"eB4Q[:Ch2Z.tS?LfQ%K@cdX9JWt\[?<\^f]+IrI!YFoiU2;n^"J_;3nmFlZt;5Aj?=u6Kgpl#=c3G^,=!1Ga:[1rX?W0fTuTTDo=g_d*11n=AXI(P@[S&d:d8(A-/!9"6]"PB>GBPE+KX/4k'W11k[rSIj!LhRDe+?KR73Hs8;KMt;G7j@%.iA_l(RYhB:+K-K?9Fi.^OBq,oGr1Tr$A_TM]cB3;g"*]hn=QorHH0DmSfl*KJI[c(333g[&fU0Yg96rFW#uM?TMltA+\o<0:Dc3#U4=4)TAY1mr6gg+0a^a\,W3QrVeYq?Rl!DP,ON#bmIl3lLmSM(3Y<5i"ofnNM3=#OV5BW;-jYN9QmimkJ7N@_TVNK98-/Qtr8@kI_:'9[:;`mW6+.dsgb`te`0c)7CPdBTH93s,BfZa&A@)Q#K%AKBB8d\0NH1IHSEf\b(:J8n0&\dd+sV;(6Li.](`>^b<T&$71RYl:#U^#cO9H"2+\miN%*FSR!i",kdgg3rEY4`eH&9NR$W)1_M5!4:GR%Le0e8#94fGUo$pKA-(VUE/5!&S6qOn60o3]OG)>7[$AkH`TMd`h1,@E44*'o,73lC!MS7isjRHf.7oSMQ;BNF[\6nq*'/JCJm3&Uj\T-cZ0`-'%t+HF#mic>cWED7;1N[fC>L1hVPYYn.o:.0q-Td^^d-/k+8866G3&4*E'^[GLEnAeAf#;>!3174>T*.U@:c6epkdu.RRQ>JE6Z?+#sZ`I_3AHrdDNUZ)O6Pr2Xj'SFIeDk((a`lN$%V>&%994\$RiKW&iDZad??K\YCq?_]&=C&"aho&KENh_'#FagMlGT^n=_@E$lQp<V41a`93Wc#-@_3;]T'k=kgWka6M8_aa!f0sG684;!Fds4e>*Pj:&I_o4kg!C;e^lir\t\DD*&qp"U%72%]m$l,nqb6$7jQ;j6(!Hde_;b3Q;j[j:A%X]2C.Wl8'E3p2BJ[_g?Z[Y;RmeMp64Z"l)*2<RYnAIZuOPhg'#fn53'b$N*YCG_sIslY#kQ7gdu><?^t=L;;C-5[SrYY*lVlo7&:4mf-^g^BlsosZ.'k"jUEP3+D33k'/SIn.gQKm&GhX6k!k]L(,.`g4@%KkUS2DZLZ&RE*8su9_)]K]8M\$-$A'\"YbXR%18](C;V,[!iBj-!U'3(a6P`3(FWK/7RuK8@>e%s[B&s5T@haLh'HLsgg01dFl60N!O/EoBBtm5Pcd*p7XW,0AcB_[P1iMfU<U22a4*PXTf#L@K3IB>[rn]9(e)Im=gH!s#lt&*V's$oMq,YkSMS=,qo93n_n[McVTcf$f]I`!P=kCXDXs88KEO@C,n]FP!dhp!?M^J_Ypu)%;LKIJJ3omB*]:W-RgKgr,lT/[U/)3@D)Ut\Ummkb/pGuulpHn[$R!Z1.8_YEl3s:F=5@A,?7J/?_EZGp0UR1T1S@W6u3^[nI96=3%la)A_f$Qt-L<*HD_['L2;!FP^NnMu)1e)2[P_Y1g1t3cf6P`.+'2eSC8JV]I<i0Pc4'/*Mbj]GrPH$UF`g8:tbjfn*V;1$K83Y?uX1,o2(i]V[H%G1,8pb0l^KBoD)P6BHf6rQOYBn>q%R+enN%EtJc!DmaS?65YqQ,hTbJS70po_#R^:Zf!o\0ECajf1GUKMFb(G=@mA&fuSO&!t4QuTGdb4R8kZb9N*,TH,dQgJbTD#=Y4U(e&"\2L+gTtt:aCeVAapaQAPQe/Y=CRRX17l"6eRsu^+4rK,VSCI6VZ$"Bb?QCGgB1+.r5<&Blmc/5&N7AVAEJ0GUojq)../H>#;M:;@fJVFIj/4]P&Z1]Pq-aW<@'3S$ZZe"Gb=OB^a'iPn;krMSHu4IMB;5pu;2Y_7>:A$k(k#VC24haV7ad9;<(5ZWF]BYa_ATp6Y^<#!Wn%#$Nk8qbX!`^,IQd/E`jO%Fc.L>1%rFN!!tA*0BqDk)AMTd'<fD(cPPj!3'C,>^l%bJ/e$?pg@RZU7e?H<Kl9.Nd-Nr%Q'@sL(ec`l,6uQ>P)I;Qql*Z>Bm5$S.F#XeWR?cqj9'qCZZ]^p?Zl3+e['/#rV]*9iBf:+E6[[[3]LCkVadsp#fj9<tm.AK.K0#7F<NZ<@<&I8>>7"p0(9"B>0Z\RI;9,*qf1A,AL8+o.Mn(,tUlnIZ,dAF(TcSIOCQ>Bt2f*7bF,5]]X^^a,7gP?TmM1TeR\B8Ns*f>P31(83b-\s?kbLd*<>!&\26!nkTFYq(N<K7n^'!fuUHV9TWcn>h!,J6"YqDQ6=BITdPf07.LVT"3U:b$a&FtD:8rtL:T$DD4*H`kd@kCGFLm&^+;Pr1t)Bu1lXkXm5kRTo-bh0Rile]e<+uj?981#0*5<a$Ga2X$7p%FI^$qW=<!,P[:fP:j"\gIX7Rk"qhV6=+M?aG/qXfekPhf2<L]%qd\ZgZp6kftdi$_A@`JsEd1rCeY)fD=$1cDb:aEhW(dAeifmI!Ma[B]@V0o6cIF$oP?(9;75L`ND:![WfEn'n"u24OS`;fiP<-3Ku[cD6cC3;XP<fl8<1jP@O-0ae'&sm`rh2$Xoo.FqcuMGt([?K38+nF1QJQ02)jE?d7-GTujih&Wq4FE*[IS/SL0_#tVOI;.q0&1T1hb&citTS[g0$9^X9!JI\&(bEbT@Gkb=`e29/8f;>:Xj6B87VqK/u_%+<XQ1CabhN>c"mu-k.E'#8<4`Rk;m\*h]8k;,XHMlQP(olg(K4C4$(?.FLWW\8$.Q6PNX^XuKF:FC,G"4TNA!8rcgrKqhcm,^@E1<I&e68!so!OD'd*2k4;fgn7T90\!-<iS:7%%^#:Y[]BBS-jY"OTse&8mS#a=a;CPn%&C@[fGuSC`cE^MEtt6Yj*QRF6[S7j!2TpY6oQ1`d;*#n27Eo4.'1hufcCV,(!"'9rSL5[_63iE*N-&`!Te(aB%D^0fV/I;k?1i(Ic>JF(#UUr]96lq5^&lp>AF5MKWWfR;G;pkp$_F@=15GM*8GAse@*pip>lph(N=D3"d'@a/Ce,%./_hY#*!OiB6D4S"sSHKQlcB4Y-QQ#h\=FHM/1PqobaQ7oc0Fd#XcRa6hgL30AP@6/XmHj<sF.;H1_FC9LSEc`=8V_aRF-?i.oamRX2/5J#gN>j\1EVh(AT*ct=8oArTVsMnan@@/>09+[&>]]&KN];`-*q%llS.*=#nN:7A0!jc.lT'sS44e".6g33^Bm(!EA20`r*J7,8/1r6t)C%GJQUqdB@"IScb!qo"f@kUnXD&R&"K2nm<VRn^is[s'<t,SWT\jgMQ))Pq@h`Di.!IqFZnf9&idXmsB\%3*]o\*?)CN*d^bIPb_:XRBPlp;6(_[PmD*;!U9O>_UOH.,p0Q(Tu;<pW4<7<5]ndh?H7r1KIT$ai)W!4kOn/rj+V2LPmjB;PZ>,SUC1hc08_:"lG'r=.@$?AXE$p_;/_RW1<R.soAM_KU7',3KG!9GI1^ko7kO4rYX:XIaNR3]Fa:2)6qB,XI#*Z([`$3S(S0u7FSYu/`^'HbA1Rqqth2J5%i6Phb\apSD!M(b@6pZaV8[7*78l><9#MM6c4p%\XJ3TnV4F_J(*$fU!'%oKKh=cB2=Kip8)bQ_'Db0%jL7g>T_`$W.jG[R_&GIFkJ22>r]L(.u+W_h0#F\SpXPTWO7;NiXVKH>jn8<BJn1/J8-DZX`GKKpJ(L6lCT>F,?UF>l&MSq]b))_\!9Pi0',PULBj(ilL;A=\8JLkl??aX`$2aSnf/W_*sboDj8H2&*ERJP+?B!'q&"_^J331(Zb]$Ep3@Koao9Eb_\83Y:16I%*N(8<F$C@]V(=@L=X<c^(SeM\n/PSX:i\^UUkB1m8X\W.m!Z3^sf;_A#iXHd#:Di)oJhgB0MBoBV3D7O/R5Ef+&N>>@C;BB'jY^*V?o<Cma%"]hl?MQuGkrhkO)4*V`S9LMG`5Z-ucl0g`f0k2,_^2ODFN7$QQ4tK*R&kAV<K,_lk@>kf2p#^-*Y9^VE"4DB%Y".5MZRCtJPL'*N/(;O1[_nIE[iZ37"Hb*Ff,.;g,a70*'&Ld(R\F>XRQr&(2i"Srbrugbl>^M':M@S?.*nt44tu'Mni4!c.Ni>\MPp=dDVO#L9[[4:"ImVX;($7QJg79_alfmka;NYg>;7)ZS."'qE&`D@_3;7@_X4">\<0*CD4Q_k1%jp%;I3j?2dNk(@O2l/)6gB&NUG1HJ>jB>!p`:)79_4'VO=;Tmu'Z$6+$A/g1+o><(-3o,KC`BZR``LPs\MDI23e:Lrb3ck/G^0=YA`uE8lHsPN$XO+aU=:.\;.!FN.9)i^C;63f!]XML=,Cbu;)$%>PE3Z@[a,=J\WS,m?Vd+/paM%<')P7fbopK`_Hg=ib!*KKfHh57cK2WP*+F,p-JR:>&;QI1%J<KT@1udM\aCia65`U/3$gW8l_hZ&.t-Y4=0qN($^^9l0"9&5*iU=<N,<aGR2J3)7ceo)5uQ^-)0.@>o&N`i?[6a#uJEFG3)trp@>#YY;(`o.219.Rb;40r7;QFs+Yd;,_R$\MD'.MUl[]ELnHl\pNi7;N+f=a[RW%30%"h,0.[\Dj.1P'0`X$R?%fhYT!D<JdY>?a4Tbn>A2amLU%OZkk+9Y1/ds?21nHVKRqq@"*"Q1"ud._ZMHd+4!")\6QEI!!E96n\X1-0&"nAcYH\V"I35%(dS>q@iI5e>WV)$-7RRfE3J%&OF7_YsarPt;i(PP'.EWX8+Io]I#ng#`;SjKL+[o<H_dj'.6(oG-7A+fK-[Ej^JkOm$p;KK4!+QMcGS0,SO5R_]&I[+9O@gj[Ci.qXNBQ.u%iKZ8S^;fsli[@5OAA36"0gdO'u9]Cgj(P1][tJk#K$Y4)MLPcOD(:XS4C^imb[Qm[8U^[dCqUoOaG;,]X2uT_1BLZYGf"BdK]kPMb$Xl!g/\GZNX3=k%O5nN)n7\"3Su[)$(uk*gm,CSWRRifEaMZWV%iO@mL,BK?+.*49c4Jb"3KS1($=g#f+5e$&k^/:S;.+B+:BIr;VHs?t&Q@XE+9^-di/cqQL=<77HL]`f$e#QN7jM.&l@m637'-b]SHaWQ]\iOAm+-Or?5>U(.76g;B+J3Xo8QJ7$"MS(.87\FZ<OI<4GjWbFO>Vlip/2g/)EA!"h$LRBKt6fA-L,X.su]rV=dV5n@`j!a96@.",?*$s83!/1s3mX$+P\&C/O:d(I3gjkrJ!b<abe9deYGhH(SVi4;1>JrK>'V_M,@<"],K;"C4c2N]=RNf-SH#&Ch4N7ng#H>O+T;oIUXC2%+OE?+Q*,b^\n$,.JP*@.=!+qm\Tb:c@L]SCp,(LpF.Z0r=&t4ZRJUh2E!Z0p"9*t)hWRu'lH'JsO18Gd@leXp`ra?Ss7\VUb6@X-to@c1s8='l?Gh.F%m%PF![[/!q647I#Yi;>+")LA'.=S)s[`^t'5a@*p)P[.]U8)t5RO]kU5fa:T:KN`W]%$mu5R2.:]>,OO[LgQB,+<L85H`iTNnjB9RSq#mnKXKN+hYli6KB9!A@hq59lZ!ANt`r)>(gtuQt#VOZ)IDX059:V!\gLuPbZ6,V'KG'nN6-&4#R1`(4r\I@o-RL&:1fH(L]n9(a4hJ9*p+LUcAR7fPL?a\62)7^lIdrJD1]Nm'Z)u8SK=KpV]9Ml8Pt6`=g?D!?#cc-U.Gg+Y[Sc9>P^W.'j=qVV5mGOO[`,/sp"hoUejsp\TQ\D)KS*KeUcE6'+G<Tl)V%)/XO`:*ro4@Sd6J&)%m(dD)!eW*fUE9#QZZltd7]Xn@$iJ2[#bq]%<g`YaE6i6s]?(!/#?)nNli_*^J#.pB#&VVI!3_EQd&CCnftam&bBEq`3<5m_alRE'1ic<5=3.dbHU=D_=3ROF)_-u+u+A>g9lUlI'H++ST"IY12ikaB56^r.X!U"!tR[kcae7fot\'-&$4K=XT]q4/n<\_?nJB4Rs%1/(Ysg_h&W6)C:%O&L::M*tK?\:Jm28F0eQ9K-+g)MAim-s4a+mD'!a(GfeM.&UEnfOCYqU;e2bj&FYtP3JeGZDF<P)dUK#Y/QdD>rj-=7M8";o\5"Oh0f"pqWG)Dj!!K0Ig+;aoHa(NklX_O(5H6J+"QUc-'$]tlid4-?bd1J5/;F#<`-9_6/%qDV[5$_@O8MjeetDfn_9[;Tn7'UF!V8e88N*;"MJ7k4USUL*O]XP:d_F8+PK1q=?-)>JOp"a:KSZYCtp9Ke1(3"ZYMLI%CUFY_*f[GG^ipk"H.8=*B4`V)$Ym4K9.sM:uH(6Ku+92'FhbYTdhR!C6?XbF_a-eNj(.1rAC(!6eH`r&gA@qn2AckF;6)$ML]YkZ$?B@5f%Or0T[.b@bYV!HkN!>Sdn/^$`\<2+o\E+e&Dm6pF1?uQ^@WU@n&F+O6nH))RR<<(0AfI(&ZV2:+i.$:%:D_c[KM)@A^W3c<rHE'PqAaPCkm%`u<sFP*&DC]\AgK%.'a-m&fhoC2d^g=imVmW<V>@ojtMbU+^RXV#bJ;a*dC6$EU"-FTf6hZl?%1S5rfs97`a/Q3hWPUa=64X$Hh3`/71'G&]S24&*'Nj.HTIGk6-R1R!I7.52^>ENAiAi2u;?$OAR*ZS5R-NA;Om.;?&G.?&4be0=0e+%I.m@EfHRdhMo:Gb/C]hL6-'GQj&lBHq499ZIKs*F4`Wd\*ZjF^eXOAA<.0=LZV7hO"'n/o&u&K#jdQ^I(:lQebIF_da2"OT(653s3bA>?$?/;.l&#Llcj8VaF0,?GNGo.=RI<!nehjpssTaG#aX;$FYXDV]niKno/c7k8m1h$:$m;MC2ar%Nt^3JlIB?'^Q^GC?rjhLYP]U.8BW(E1^\P,;Pf/BUkt5Q?+[9'"p"TT@d?$>8=iGP$!H_X"RT";^Q^8>_HfF9nb8\>(g3E;7[qgR0t]dm,2X43#c?d=Dd#WU1?SIb<fhn&ZJ)ABJWJ'W=`@?G7b15d\A`P%*jh])5[JBaKB>YEO.6gHbQ0>VpeTK[(%-<gW!Q`!>ujZMq`J($)U(P@d\^\$475s=enK2&i5cs,RN4qGG+i8`d%2_qWC"73T?Q,&8Ps%SF@5T>kj`<Cc^HU[@j+S._$?)fs+G@6g!b_Q)OB*$[j8*p!*2]QoM>T?(:H<cX&:C\&AR)I7<,Z!I\"h$Hi,7)6Ih;00hN*CWXj==>L5E=KRq:@>Qc$[X)0_dE;i8#fPG5W_Q0>kW.J^.V,!"HNMXQ>2<XY0[LduI^Mn2m3deOT1LQAFrWr;*t6#@mn_7FQ(70K>O_\<<TYo.[`BXH!VM::bHi$pO?6,dKuln'dK[K%+hQfd@cY`MAVpjVWiP9G@\aH9;n@gcSiPmXITeht@GTG8Z;0a23[pGp_?VWi\$q\UL8eYl]8'hOc?SEJai:YB:q0K'pP#Yck*SXr&kj`8HW["=CW_p^(32]aSld3dgF5c^P%YSb,&oRri+>C,jX,JT;%qSB+^Xf\cK0GeajW32qWdAW*_CeR>s=`P2rcNNC1OJJa]qYg@=G$@H(\\/h\qi*Y&;94Uot3f9O;-aeu7P`9"K#/(EF30*'.@TLm(:4;'7h.,0=qt/apnI'L&6hT!)aj8>V]Tem6[I=$<M/i+gc?119COQ*)es:tFcfe&a6:<MI_S2bsc"Z6BL_j*RXSc0[EPh*VD>!u44]C3k)>J6bhU>C?+UbgEcuTupDh1=B,Z'ZWt,2Rs/c/'-(@9>Ra,[=d8ul<=M?=,F(:\?KeR,?4$CNL,l9#1#Y?fX<DC?pQ'.74(.,FJQ^NKJCi[%&IC\C(`iNoTalg2bE'm;-%C-qB/R,>>Fp"Wd7N&_bG)(o$hbE4.<MQjXRB6Y/X#)":[4YTj)]gnXJQ#qI^[)F,!PV2YbRQ,rX+jd@q8!-Um#A-[+s1Ll$-!-0\F(?!XJNQP.5L!e@r-'b;hPB-Ck7:McUGc%\'D?u+?"RHre?I\Fp8,DIccV^9bH]/#Xj<A*+@Cb<63pF,'CCUrDpF1iU4ZCDfUd!'ONk_/nYm*/%^D*nW@4si.b@CDA?.9t"R!,GG.62/TL2\X+HLk+k5cBHaU*\ArK"r'mg.*t^'0d\+P+Dj7FL5)`:D89hi1a'&N`A$f=N:"*2FiPl.nRo]+LY^*=!mEuH_Jh^d?Jt_Gmo$had:,V"mVGML7Bab*ZhZ,A"-+Si$*k:$B5u^>5hSWc%NKQIIpQZJ^n$MJ0EIibK`\jj6U]R[r&`cUk'lX7HJRAr8r93sMMuNHG\,=q^KOJn\;Y@BCLsdB;]8BM>%/d45]T]eQDGtS<%KZAMT=!mH3E\;AV>BY<7sYHDH;X.@Ciqo#g,RbH'jj8E^YTc"r-!dO]g\lKh48`WE6H>HI'*l'Xi*cm4/cS]64t0*CTQ6VPHaZ@TL\r/&ZWMIl3gm9%R[.h_N`:QA?Zo787<ucupCr+bKSccDjlLjC]_IO:EgpU_M<iP#kMPO?#[:T6n7h(tm[jpHYokG!5+58N\Y?4sUN`4cB_!BP#-4$7,r8+M>0R;Cql*@)0Q]#YH$iTGP1Jn@6k;YlJr6RKnB.#?,K)i5C@O0JRk`U*-+t8Pmh8m</QL\I8j8*%$9X@s0/OdbC<%.Vsj]HOUS>@DTOR,6k[k3XQ3\/I9<>jC=s4M."gCBc2f<b@)dQhtdi8/h_^Sgs*2oj=%U`=H_*e(7(0j1j_g,B/&8IGi3Dsf_jMpQuV9s+UWlpd1VN\JHb?h4GXaIoXikGP]oS/CGHE<@V(hrdALtB>N6TB6pJ^9'TB.Hs1D'l[0Kn]-p*(tR]D'm0:JuJ>@H@1qU/[/-H/J\?dEPnEaZ!:I<`R:BO08Pm8G@*f@@\b=M]5;9a7boi4ujR[?W*^#IqJ+:Xh@Yr!X;'%VXQ/;B"j_:b<g**32F:.I_X(h:]]>+Muk2bZ(\j&oB#nif=W1X4@GK<H<=D?FoVr/G@s%R1]j9.rRg[e#i"Ng[S;7@!`inZV!_4)^AK[LBA>IVVn%n8MrG?0"?^qL`2@5=VYUm@XWP5A$$,J7$66?ZQ'oiZ>0,S*7lDshDM2]\s8gq10knJ5ZblsKhgJ1Et$$nW2cVRZhEdVa)WEoE@(0i"Yu#q]\qc4@oS9BOf-:LKsQeVO,Ehn66l^s`]"YT/n`aoH3j.Rhda\Pj<t0;*Pj(XTs/Wkp2"o/$3@FI"OTXlZP6=@6rJH;!<%LjSjuKn_MkfJJ"1'45]I&u(N+ca\;pqtEMKe!0N9mNTJHm?D6;IM5i;o[RL#jR.>UMsPUNMg@.Udd8E(q@;A#>H",nK:@kp@QDB<GZ0-gPcU-3(Xeom!86_h.m.GU3;<=i?BKh8iu07<ALSaNGtgkmOJ#"YqaG82tF,LXr+gcTr,-G0sG=<P],gO_cY%o6YAB'=5$'dW&W"jQo?CF7?sN8ZWB>K9+$-(0\J:mrK%*bj>!c-6ru<60#nWN<Ue==PkXWYa<eHB3.=qflP.Bk7j;ViKqCe^=sXl:_[?PZ:>kfnPDJ6.10?f4m\;4I>bo*,*=H"6g1`!^n1?h''iL5cUplWtS)^TKj]-n:8bCfB\$E(bq.<@/r1Dk#/3s8Wq5,0bXmK3.=uZ9S\mJR%*i@#RPsQfF-%-_<*^2;B::,5Qjpm844Hq#_MWIBqcq<7!s2RZG//mm?"ioL`bK=ciLpJ1pdfY]-_6pK2b5IV$e_+1(b]4i<kpT>kETo0<&$/&5>DM+V5c6askDY_@^`0:Q0kd$/I"R6M\c='b0+gO[,oM.4BPo<JZ$R6&691d=V#Y6M;0R>[;O?TZjJPh*t[&+kn&)n&sG/nd*+;hSVg:mYA6MO?"I5h1_X8/g3-(2Ln']13!eZ:SKOd?IQ:#le6s'h^DWY_pJH-F?&#;;le!(5FiBq+4bH>/[N=%=;Pb@TT\sf>J+)0/l?S--4t=Ba5JqGC-*FIKH3P2UNm9b22]=q-/%B:ceH;^VU"b2Y0?AV_EB$>kk!as@cY6J4k[Fk9EpUHlWqCj:()Z8MG3@_-Eqs2<!3dF<<Wu[+;b)@h/HPWN"Md]is&?%1e@\O7[Y*l"6atH,FGdB"t.I'L')*?@)PpEVaV0V(m-"A%2q!3ZYg6`=kIP28-tL_r&`9JE+sP,blP66-.<C7.q"tm-a2GUO0*j!jm%#q4nZ?oL,^%_7`8b-J`G;Lol,69:U%JY@%j7uP]BhJ;roJH"$d_PB$T:p]/3^Z3/3Me?'0K@hZEo+5GQ_(<S2PLoMq]CBd>JFch_V`];t2*W9WC%@h`Z#J`rl!j\4!sJ5LDeP4si1T0/JXie1i#(eo?E(C+B>H)#LL%/uJF)BFp*14?56j53!jgISW'Vp;!q>o5:jd=1*S%J[X*#E2rOKV]2//gD]=@?"R+6?=(VEIs6@($F^MKcbjkd==M?8Kgqr'.QR:4-)S:3t+tO<8?ZWi'macLI_^^N1*FocS5$p#Ef&iLXQSOkQ:lq</G<-=HOep<2EKQZK)JhRg_lOgdL79+)AK:>C8*eb:R'j#SQYpNI_A#+fH$r4T70c<dg,i8N%,mT#JgsJq/fr_E9csP?;;-U#_A#PT=2n!KVAsprK]_:lmBL7&kVZfdLkV6`1tjmu5aPg'n:a'>P+Yr9TN#1+E(Gk+@)LWBMj85m(Z75g!">3)2Tfcd#lf-`m)C*W=LD9#=tU='.uM=>AJG.d#rhIPNd]hYrd0V2WktL`;L=.&7JlG!F8iX$eE'e(Em!)_7Q.Vl[mX35&461\WcaI9.%sJuX^@]54OJQ$$nre%XVYer*sJ$^B#Y%>/=B9G0^k6(nuSBHpQpQu/B&]Li``Yn;[=\LEp^lL'pKb:nkh.&U=W^1R8kekjrMWh=92US>b4lChpc!>*)IUO-`B=Bq&.NU<*ZiSGjJ:=]G&+S0k%g5i/ZccbdD_>-E>H95*1%%&$A.J.X[^^\Tpd"e;kmQ,6;BJcoDiXt4uk<<j^5VroNbn*j<U!V5g!s^Z#o@.N'Om=.>0-NC_.:2(uNj5Ni!'`*>QJkKr^uJii^q9r;(u'WcLl_q4G[VtMb#"Qe;+9-W6)^Ot4;+iC)ad%*;-plnRcauJ9Y3=l#<bu]21T_3G4>F*o/Q@]aRO?5T`-LeO=&/,;4*hd->'O2a!9^2nN240)!K>=QJq>g?6H&.55@M7!`5X3Le9?XOo0Cj_D6rY]`uE.*?Vs"5V`sK,m>lDRCg)%coib)N\K<cSW$Z[![l'I8I6Z+Jlmb;c&gpWAl7[t<&CkmMi%=&^#C44)=BnQ"Z0Zq4eQg,$t"#@rkFlk-9V2!gr&+:)7E3B9([!Bq+%kqE(.P6Ch6:qgjQa'dK:08ViUrZ3Y8;ZBEh%*L^>4?L'^8"5d[NPHHJ$.6D'q&`:f!7a]3P6J11e2DqdD@7S-c,JruFnVPso3OJS7N(-Xr.^coi&&)Z"YGSk^VJsfHt6@Y/u=Sa^0(U%BQi+W1C8G7i5[cBY5pQJ<++5*cs@']PuFH9Fq1`?H]O_JJ9Wa]A[V[-`4%VO#SflC/IKGl\q#RFdH@LdKpUa3DD2pA/nE93q/)o3mr(%,;f4V5L4-5/V5kHY?AZ1dC3.@7`)\eh_:W5&P43I8T%"*&mFARst9@f-NhSjE\J&9I3X-.>s/Gkb[.#V9N8jPD,3PP<jA+U.q%9RPRapi4.$JT_^?-!"dC&/8T$Y,XX7XRA(+7[i72_GIE-:H.I!9F'GiP5i4(8fqF`@#3_ihqm3=o+?).QYFRH[?/7!,tC]V#pKjG6QTB#.JS$JU5EXd'Bat^jFop2I]')2N*M;Lh(TomA`sr`lbqQE0\Tcse`uuo_k_^eapsTIHf;jf_.nQ"E:f%;2:&.[=uN:%6BHpFT7D`r#]2:q"]Z(b*bcC50Y.bseh/&%Wcn10r;ureJ"g2$s,9DFIcK9W*Tr:;9GI^s'7QJ:MGa_8pPF$u):1CDD2dLl#(i^[LitJY5Y.5N[6`O\<<eCZ,V1;-IR83eCr>Y$J!c^?+QjB5nE_"YL)Rt$!(jhpZ\0L^PIGt%f2+[i>V68qU`*p48<bPh:S.XJXN8bq!/+&u"X=UP0GLi*#nj1/5;*LQ0LkH$be]PT#Tt;t![OQ_CbO4&jpm"KA&#:a@KH*B%Ur4*,/4qV666\`>PYpO3.PZRkYL1fI6c4*cjTW1#jOct$tVHK+S&QX,q+ADe:b)::$45WO.=lp,PeVf<&@$5F7eKK1_i.2BH85[_T<Y?l-.BU7lWjDK\<;[Ahf3X&jg"E+VI=48kPXc9fNi=Ta6qs&k3.<+dAE4L4k4'#=1U#"M+ef_kRS?,Fes-!`e`DiXp^!O$eFY30Zr@:%g!*8O&Cd`L\:d2HT*mV%c7]-;R&1nhR"=La-9Y&hP'W)Q(s%,83ELk4&UDS'ZS4]Lb+0U<1=G^<8k<@J^XN$_k:s+2F"k9Xp@HVWaiXl@J@da`\d\joSV'Sl`%ZR]B*RoOZhnMO4hrl_Oe^%M0c6V$nf*n*\5CGi5k=3%f]Wm-4n1ng*'ZC?)MdZT3PFa\MAs:TS*_:`e>AUp>[b;"fa/*0:n#TIn7c9dKgESW=oj%oe'$S$"TsN>W;amr8jhfdSS)l-R0.2Y`Z-,[:mt*`g3YNl5pGD0q9Hr_30%YAReQ@tZgjr\`'rgeEU1=q"T?PS!?iFW7dL#!*d+dp8BdE6_9)>T*CI_@UnqJtd^I`"24#,oDI^-mASha74L1HElU[QE="l6NPrm6t[$+4+VsHEdZP(I1\N<;%=_Xg%!QtT5;F-IQE#G(;9B8;BR%1N+_'*`i$r;,S<kN!h*ie\(2FMQbX[7]ZcC[Se'NO2`X[ORH>M$frL]H`WkJ?K+rk*G46bAS;g'0+P_-R`IB#l=pN]!@,O"tp%gaG"n*]0"CB=k!X`+A-3h;j2@W%eo#OuebGb`7OJ3sicfb)s%<\@;l$Y>Rg%)+32:qu.](ot(k]_bVi/lrG3=RjHW**>/qgRF0p4&_6^Ure2cgL=QB@6^NGPjRQ^]#.`So=#jp9Sdgli3$rqS.ftr][OXs%i7`J%OkA5Q1Pphu3*En,IlEjm@P`J)1"3`T6bsJ=+=ecNp!EH@lo]Q&8:cHi(%XU0YO$1];tE5u@2`$!6uP=oH`t^LY"?;%]qZ'm#31gu($ZAn-qjKe._?^+oY,Nj&,-i!2eJY_P(Hl9kG9:QXfh0l_pHQjA^KICu'tjPNaX0sc]0rZMK09%G:AgT:`]BHQaEO>!&PAJ^<c)EFr#2m>,H`qdJP`P_Ulr&RRl"p,Bf4"'Pp[PMZk.#:B]MM)FSTgW*96E1=`fni'FjPE<%%fX8WG$&10(g5auBoc,KXEjk#GH5XdFq3%7;/8U"TQ9n_o3qRsaYhp[DCnh=T\DBPV*mdp:ESP3s"oeLXT*[F=5)E.Wf3gq9(u=P[m^fD_.>k%jf93>Xc,5uc9-2I(78hkZrU4LV,f)TOXi:<?hnrDE=u#[?`t8Mir(Cq'ob+En9.:+KH#b9J$_I!RcX!b/U4o,]Z+fSF@'UAs"Esp$K.L6;RLV>_1LtR,gHql<MjTd!J8Z>/7@#(WHd?l4T)J2+5i#Q<`g@R#ir)f7#,1Ogiea8f^4"F(R,3Ligi*Hg]&jeV1MCmM$rYQo%87\H9$a:ZHS+D>VEU;TaD'j$:'K3JH;bdRL2H:PTL:u%n%fA8PC99R+L]T4(8i*,GTCDgI@(SM2b/5<)D,NbN__CK!ED6H1PJDmK@;_ql4X8,oNV8Y+XBJZB=RX*ALL6?>G7fD=L$oUB5$E>TMW?g4]Yu<B4#Xs*W*LS%W6GU8Ja,[`WJX$"K[(D"MLS7<D5p]$<e>:".Q9G_[X3dA.^&74OF2bMCu@j#(kDoJ?7'nnZVeH+UYADjMf&2#B]!bq0:ip2F]o[!t2jB&#Cde=M@6WYYu6KLOBJdR-Q5GV_'Q#l.n19YNBqa0r@o[rt<kBfK;9B\7%o\ZHRrBgK)`80WZA^siE(ZP$YKH2)W=m%VLQaSS+[n'Jl&S]d$f98'6cA5Uh\M*U;9=\`e&o]<g1_Iipb&_7uHRW%mC_VfJ_"=G0cmfIU:SAg&aUU41$<+BK?pGK?HXF6,XC-k#r8W/=5<6>^O3V]4MT!JI[!JSp"S*T4Olm,1<![M08#UrnQQ38C#2VdFJQ,pfu&Re)#@_ETbrjh?iYZKa[*FAF`lihf8'gP1+6H#g9AMb7ag$\K[N&df_Igdh+`?=Q&Zo=^>Ok[QIZP6YrAqLWX$4mCg`p-.r,"[a^o)IEn)CW7l*T6#GR-[EB'@Id'+c)g?!i_uU5P\-j2uC3'7EK[K*bpJU*"3?^5]X(HhL\i=*/UWFYVmTX#hCGfO4M_Pm!`^T1LWZh-+Vh19+oiho\'1,jb!\@]h7IO.*dTOHfRDjnEJQp?9,a%cBm)]F'I[(<=;OeF'K!G8d-I\1JAs.7.!T[V[8N7oR5hZTB'c;2:J8HQ2.D,qKI#]ruH(/BJO=ER5Ca1O1$5gG_\^-F='!O)lt1On$cd=^@uO(s(6b1ruo2*k^WA?pU0`:5O2a:dm*Y!*-8FK3H^j%`R?an4S)fq)9b5iMdbHWAVe=oH+i)*MT-6^*<n]`)sq5TKE's!8>ce-&QpmNJ,
+# ===>END WOOF<===
--- a/wscript	Mon Jul 30 14:48:56 2007 +0100
+++ b/wscript	Wed Sep 05 18:35:39 2007 +0100
@@ -2,12 +2,13 @@
 import sys
 import shlex
 import shutil
+import types
+import optparse
+import os.path
 
 import Params
 import Object
 import pproc as subprocess
-import optparse
-import os.path
 
 Params.g_autoconfig = 1
 
@@ -36,7 +37,7 @@
 
     opt.add_option('-d', '--debug-level',
                    action='callback',
-                   type=str, dest='debug_level', default='debug',
+                   type="string", dest='debug_level', default='debug',
                    help=('Specify the debug level, does nothing if CFLAGS is set'
                          ' in the environment. [Allowed Values: debug, optimized].'
                          ' WARNING: this option only has effect '
@@ -135,14 +136,33 @@
     conf.sub_config('src')
 
 
+def create_ns3_program(bld, name, dependencies=('simulator',)):
+    program = bld.create_obj('cpp', 'program')
+    program.name = name
+    program.target = program.name
+    program.uselib_local = 'ns3'
+    return program
+
+
 def build(bld):
+    print "Entering directory `%s/build'" % Params.g_build.m_curdirnode.abspath()
+    Params.g_cwd_launch = Params.g_build.m_curdirnode.abspath()
+
+    bld.create_ns3_program = types.MethodType(create_ns3_program, bld)
+
     variant_name = bld.env_of_name('default')['NS3_ACTIVE_VARIANT']
     variant_env = bld.env_of_name(variant_name)
     bld.m_allenvs['default'] = variant_env # switch to the active variant
 
     if Params.g_options.shell:
         run_shell()
-        return
+        raise SystemExit(0)
+
+    if Params.g_options.doxygen:
+        doxygen()
+        raise SystemExit(0)
+
+    check_shell()
 
     if Params.g_options.doxygen:
         doxygen()
@@ -152,6 +172,11 @@
     bld.add_subdirs('src')
     bld.add_subdirs('samples utils examples')
 
+    ## Create a single ns3 library containing all modules
+    lib = bld.create_obj('cpp', 'shlib')
+    lib.name = 'ns3'
+    lib.target = 'ns3'
+    lib.add_objects = list(bld.env_of_name('default')['NS3_MODULES'])
 
 def shutdown():
     #import UnitTest
@@ -193,34 +218,32 @@
     raise ValueError("program '%s' not found; available programs are: %r"
                      % (program_name, found_programs))
 
-def _run_argv(argv):
+def _run_argv(argv, os_env=None):
     env = Params.g_build.env_of_name('default')
     if sys.platform == 'linux2':
         pathvar = 'LD_LIBRARY_PATH'
-        pathsep = ':'
     elif sys.platform == 'darwin':
         pathvar = 'DYLD_LIBRARY_PATH'
-        pathsep = ':'
     elif sys.platform == 'win32':
         pathvar = 'PATH'
-        pathsep = ';'
     elif sys.platform == 'cygwin':
         pathvar = 'PATH'
-        pathsep = ':'
     else:
         Params.warning(("Don't know how to configure "
                         "dynamic library path for the platform '%s'") % (sys.platform,))
         pathvar = None
-        pathsep = None
 
-    os_env = dict(os.environ)
+    proc_env = dict(os.environ)
+    if os_env is not None:
+        proc_env.update(os_env)
+
     if pathvar is not None:
-        if pathvar in os_env:
-            os_env[pathvar] = pathsep.join([os_env[pathvar]] + list(env['NS3_MODULE_PATH']))
+        if pathvar in proc_env:
+            proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']) + [proc_env[pathvar]])
         else:
-            os_env[pathvar] = pathsep.join(list(env['NS3_MODULE_PATH']))
+            proc_env[pathvar] = os.pathsep.join(list(env['NS3_MODULE_PATH']))
 
-    retval = subprocess.Popen(argv, env=os_env).wait()
+    retval = subprocess.Popen(argv, env=proc_env).wait()
     if retval:
         Params.fatal("Command %s exited with code %i" % (argv, retval))
 
@@ -274,13 +297,33 @@
 
     return retval
 
+def check_shell():
+    if 'NS3_MODULE_PATH' not in os.environ:
+        return
+    env = Params.g_build.env_of_name('default')
+    correct_modpath = os.pathsep.join(env['NS3_MODULE_PATH'])
+    found_modpath = os.environ['NS3_MODULE_PATH']
+    if found_modpath != correct_modpath:
+        msg = ("Detected shell (waf --shell) with incorrect configuration\n"
+               "=========================================================\n"
+               "Possible reasons for this problem:\n"
+               "  1. You switched to another ns-3 tree from inside this shell\n"
+               "  2. You switched ns-3 debug level (waf configure --debug)\n"
+               "  3. You modified the list of built ns-3 modules\n"
+               "You should correct this situation before running any program.  Possible solutions:\n"
+               "  1. Exit this shell, and start a new one\n"
+               "  2. Run a new nested shell")
+        Params.fatal(msg)
+
 
 def run_shell():
     if sys.platform == 'win32':
         shell = os.environ.get("COMSPEC", "cmd.exe")
     else:
         shell = os.environ.get("SHELL", "/bin/sh")
-    _run_argv([shell])
+
+    env = Params.g_build.env_of_name('default')
+    _run_argv([shell], {'NS3_MODULE_PATH': os.pathsep.join(env['NS3_MODULE_PATH'])})
 
 
 def doxygen():