new_contents: #!/usr/bin/env python
  
  # Simulate a node saying bye before any of the other nodes have received all
  # it's data
  #
  # - One sender node + a number of observers is created
  # - The sender node waits untill all observers joined it's group
  # - It then sends out a number of data packets (0,1,2...)
  #     Of which the last two data packets are dropped before hitting the mesh
  # - The sender node disconnects (sends bye), causing the observers to notice
  #    that they didn't receive all previous packets. And send out repair
  #    requests for them, which need to be answered by the leaving node.
  #
  # This can yield false negatives in two cases:
  #   * None of the first two bye packets are ever received by any of the other
  #     nodes.
  #   * While the leaving node did send out (some) repairs, they never reached
  #     by any of the other nodes in time.
  #
  #   Note that  with 4 observers and 30% change of packet drop:
  #    - each packet has a 0.8% change of being missed by every observer.
  #    - All observers dropping the first two bye packets has a 0.006% chance
  
  from twisted.internet import reactor
  from mesh import Mesh, MeshNode, packet_type, BYE, DATA
  import sys
  
  NUMOBSERVERS = 4
  NUMPACKETS = 10
  DELAY = 0.1
  
  nodes = []
  # We're optimists
  success = True
  observers_done = 0
  
  class TestMeshNode(MeshNode):
    nodes = 1
    send_data = True
  
    def __init__ (self, name, mesh):
      MeshNode.__init__(self, name, mesh)
  
    def node_connected(self):
      MeshNode.node_connected(self)
      print "Connected"
  
    def push_packet(self, num):
      self.pushInput (str (num) + "\n")
      if (num >= NUMPACKETS - 3):
        self.send_data = False
  
      if num == NUMPACKETS -1:
        self.disconnect()
  
    def sendPacket (self, data):
      if (not self.send_data and packet_type(data) == DATA):
        return
      if packet_type(data) == BYE:
        self.send_data = True
      MeshNode.sendPacket (self, data)
  
  
    def newNode (self, data):
      MeshNode.newNode (self, data)
      print "node0 - Added " + data
      self.nodes += 1
      if self.nodes == NUMOBSERVERS + 1:
        print "Everybody who could joined"
        for x in xrange(0, NUMPACKETS):
          reactor.callLater(0.1 * x, (lambda y: self.push_packet(y)), x)
  
  class ObserverMeshNode(MeshNode):
    def __init__ (self, name, mesh):
      MeshNode.__init__(self, name, mesh)
  
    def leftNode (self, data):
      global observers_done
  
      MeshNode.leftNode (self, data)
      print data + " left"
  
      if (data != "node0"):
        print "Wrong node left!"
        success = False
        reactor.stop()
      if (self.mesh.done < observers_done):
        print "Observer done before getting all info"
        success = False
        reactor.stop()
  
      observers_done += 1
  
      if (observers_done == NUMOBSERVERS):
        reactor.stop()
  
  class TestMesh(Mesh):
    expected = {}
    done = 0
  
    def gotOutput(self, node, sender, data):
      global success
  
      if self.expected.get(node) == None:
        self.expected[node] = 0
  
      if (self.expected.get(node, int(data)) != int(data)):
        print "Got " + data.rstrip() + " instead of " + \
               str(self.expected[node]) + " from "  + node.name
  
        success = False
        reactor.crash()
  
      if not sender in node.peers:
        print "Sender " + sender + " not in node peers"
        success = False
        reactor.crash()
  
      self.expected[node] = int(data) + 1
  
      if self.expected[node] == 10:
        self.done += 1
  
  m = TestMesh()
  
  n = TestMeshNode("node0", m)
  nodes.append(n)
  m.addMeshNode(n)
  
  for x in xrange(0, NUMOBSERVERS):
    n = ObserverMeshNode("observer" + str(x), m)
    nodes.append(n)
    m.addMeshNode(n)
  
  # Connect all nodes to all others. 1024 bytes/s bandwidth, 50ms delay and 0%
  # packet loss.. (bandwidth and delay aren't implemented just yet)
  m.connect_full(1024, 50, 0.30)
  
  def timeout():
    global success
    print "TIMEOUT!"
    success = False
    reactor.crash()
  
  reactor.callLater(60, timeout)
  
  reactor.run()
  
  
  if not success:
    print "FAILED"
    sys.exit(-1)
  
  print "SUCCESS"
  
subject: Add a simulation to see if leaving nodes do still correctly react to repaire requests