public Replayer(
      final Id id,
      final InetSocketAddress addr,
      InetSocketAddress bootaddress,
      final long startTime,
      final long randSeed)
      throws Exception {
    this.bootaddress = bootaddress;
    Environment env = ReplayLayer.generateEnvironment(id.toString(), startTime, randSeed, null);

    final Parameters params = env.getParameters();

    params.setInt(
        "pastry_socket_scm_max_open_sockets",
        params.getInt(
            "org.mpisws.p2p.testing.transportlayer.replay_pastry_socket_scm_max_open_sockets"));

    params.setBoolean("pastry_socket_use_own_random", false);
    //    env.getParameters().setInt("rice.environment.random_loglevel", Logger.FINER);

    logger = env.getLogManager().getLogger(Replayer.class, null);

    //    env.getParameters().setInt("org.mpisws.p2p.transport.peerreview.replay_loglevel",
    // Logger.FINER);

    final Logger simLogger = env.getLogManager().getLogger(EventSimulator.class, null);

    final List<ReplayLayer<InetSocketAddress>> replayers =
        new ArrayList<ReplayLayer<InetSocketAddress>>();

    SocketPastryNodeFactory factory =
        new SocketPastryNodeFactory(
            new NodeIdFactory() {
              public Id generateNodeId() {
                return id;
              }
            },
            addr.getPort(),
            env) {

          //      @Override
          //      protected TransportLayer<MultiInetSocketAddress, ByteBuffer>
          // getPriorityTransportLayer(TransportLayer<MultiInetSocketAddress, ByteBuffer> trans,
          // LivenessProvider<MultiInetSocketAddress> liveness,
          // ProximityProvider<MultiInetSocketAddress> prox, PastryNode pn) {
          //        // get rid of the priorityLayer
          //        if
          // (params.getBoolean("org.mpisws.p2p.testing.transportlayer.replay.use_priority")) {
          //          return super.getPriorityTransportLayer(trans, liveness, prox, pn);
          //        } else {
          //          return trans;
          //        }
          //      }

          @Override
          public NodeHandle getLocalHandle(PastryNode pn, NodeHandleFactory nhf) {
            SocketNodeHandle ret = (SocketNodeHandle) super.getLocalHandle(pn, nhf);
            logger.log(ret.toStringFull());
            return ret;
          }

          @Override
          protected RandomSource cloneRandomSource(
              Environment rootEnvironment, Id nodeId, LogManager lman) {
            return rootEnvironment.getRandomSource();
          }

          @Override
          protected TransportLayer<InetSocketAddress, ByteBuffer> getWireTransportLayer(
              InetSocketAddress innermostAddress, PastryNode pn) throws IOException {
            Serializer<InetSocketAddress> serializer = new InetSocketAddressSerializer();

            HashProvider hashProv = new NullHashProvider();
            SecureHistoryFactory shFactory =
                new SecureHistoryFactoryImpl(hashProv, pn.getEnvironment());
            String logName = "0x" + id.toStringFull().substring(0, 6);
            SecureHistory hist = shFactory.open(logName, "r");

            ReplayLayer<InetSocketAddress> replay =
                new ReplayLayer<InetSocketAddress>(
                    serializer, hashProv, hist, addr, pn.getEnvironment());
            replay.registerEvent(Replayer.this, EVT_BOOT, EVT_SUBSCRIBE, EVT_PUBLISH);
            replayers.add(replay);
            return replay;
          }
        };

    // construct a node, passing the null boothandle on the first loop will
    // cause the node to start its own ring
    node = (PastryNode) factory.newNode();
    app = new MyScribeClient(node);

    ReplaySM sim = (ReplaySM) env.getSelectorManager();
    ReplayLayer<InetSocketAddress> replay = replayers.get(0);
    replay.makeProgress(); // get rid of INIT event
    sim.setVerifier(replay);

    sim.start();

    //    // this is an example of th enew way
    //    //PastryNode node = factory.newNode(nidFactory.generateNodeId());
    //    //node.getBootstrapper().boot(Collections.singleton(bootaddress));
    //
    //    // the node may require sending several messages to fully boot into the ring
    //    synchronized(node) {
    //      while(!node.isReady() && !node.joinFailed()) {
    //        // delay so we don't busy-wait
    //        node.wait(500);
    //
    //        // abort if can't join
    //        if (node.joinFailed()) {
    //          throw new IOException("Could not join the FreePastry ring.
    // Reason:"+node.joinFailedReason());
    //        }
    //      }
    //    }
    //
    //    System.out.println("Finished creating new node: " + node);
    //
    //    // construct a new scribe application
    //    MyScribeClient app = new MyScribeClient(node);
    //
    //    // for all the rest just subscribe
    //    app.subscribe();

    // now, print the tree
    //    env.getTimeSource().sleep(5000);

    try {
      env.getTimeSource().sleep(55000);
    } catch (InterruptedException ie) {
      return;
    }
    env.destroy();
  }