diff --git a/router/java/src/net/i2p/router/MultiRouter.java b/router/java/src/net/i2p/router/MultiRouter.java
index 43f618bc2209725b75e6edd356fcff49cd6f2c6f..bee66b258950047a796f2abdd528977da0339e66 100644
--- a/router/java/src/net/i2p/router/MultiRouter.java
+++ b/router/java/src/net/i2p/router/MultiRouter.java
@@ -1,11 +1,18 @@
 package net.i2p.router;
 
+import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.PrintStream;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.Properties;
+import java.util.Scanner;
 
 import net.i2p.I2PAppContext;
+import net.i2p.data.DataHelper;
+import net.i2p.data.RouterInfo;
+import net.i2p.router.Router;
 import net.i2p.util.Log;
 
 /**
@@ -16,7 +23,7 @@ import net.i2p.util.Log;
  * contained in them are used for the context's getProperty(name)). <p />
  *
  * <b>Usage:</b><pre>
- *  MultiRouter globalContextFile routerContextFile[ routerContextFile]*
+ *  MultiRouter numberRouters
  * </pre>
  *
  * Each routerContext specified is used to boot up a single router.  It is HIGHLY
@@ -36,72 +43,181 @@ import net.i2p.util.Log;
  * that need the encryption enabled).  To run a client app through a router that
  * has i2p.encryption=off, you should also add that line to the client's JVM
  * (for example, <code>java -Di2p.encryption=off -jar lib/i2ptunnel.jar</code>).<p />
+ * 
+ * To make the router console work, either run from a directory containing 
+ * lib/, webapps/, docs/, etc., or point i2p.dir.base to a directory containing the
+ * above.
  *
  * The multirouter waits until all of the routers are shut down (which none will
  * do on their own, so as before, you'll want to kill the proc or ^C it).
  */
 public class MultiRouter {
-    private static Log _log;
-    private static ArrayList _routers = new ArrayList(8);
+	
+	private static final int BASE_PORT = 5000;
+
+	private static int nbrRouters;
+	
+	private static PrintStream _out;
+	private static ArrayList<Router> _routers = new ArrayList<Router>(8);
     private static I2PAppContext _defaultContext;
     
     public static void main(String args[]) {
-        if ( (args == null) || (args.length <= 1) ) {
+        if ( (args == null) || (args.length < 1) ) {
+            usage();
+            return;
+        }
+        Scanner scan = new Scanner(args[0]);
+        if (!scan.hasNextInt()) {
+            usage();
+            return;
+        }
+        nbrRouters = scan.nextInt();
+        if (nbrRouters < 0) {
             usage();
             return;
         }
-        _defaultContext = new I2PAppContext(getEnv(args[0]));
-        
-        _log = _defaultContext.logManager().getLog(MultiRouter.class);
-        try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
         
+        _out = System.out;
+
+        buildClientProps(0);
+        _defaultContext = new I2PAppContext(buildRouterProps(0));
         _defaultContext.clock().setOffset(0);
         
         Runtime.getRuntime().addShutdownHook(new Thread() {
             @Override
             public void run() {
-                Thread.currentThread().setName("Router* Shutdown");
-                try { Thread.sleep(120*1000); } catch (InterruptedException ie) {}
-                Runtime.getRuntime().halt(-1);
+            	_out.println("Shutting down in a few moments..");
+            	for(Router r : _routers) {
+            		r.shutdown(-1);
+            	}
+                try { Thread.sleep(1500); } catch (InterruptedException ie) {}
+                Runtime.getRuntime().halt(0);
             }
         });
         
-        for (int i = 1; i < args.length; i++) {
-            Router router = new Router(getEnv(args[i]));
+        for (int i = 0; i < nbrRouters; i++) {
+            Router router = new Router(buildRouterProps(i));
             router.setKillVMOnEnd(false);
             _routers.add(router);
-            _log.info("Router " + i + " created from " + args[i]);
-            //try { Thread.sleep(2*1000); } catch (InterruptedException ie) {}
+            _out.println("Router " + i + " was created");
         }
         
-        for (int i = 0; i < _routers.size(); i++) {
-            Router r = (Router)_routers.get(i);
+        for (int i = 0; i < nbrRouters; i++) {
+        	Router r = _routers.get(i);
             long offset = r.getContext().random().nextLong(Router.CLOCK_FUDGE_FACTOR/2);
             if (r.getContext().random().nextBoolean())
                 offset = 0 - offset;
             r.getContext().clock().setOffset(offset, true);
             r.runRouter();
-            _log.info("Router " + i + " started with clock offset " + offset);
-            try { Thread.sleep(2*1000 + new java.util.Random().nextInt(2)*1000); } catch (InterruptedException ie) {}
+            _out.println("Router " + i + " was started with time offset " + offset);
         }
-        _log.info("All " + _routers.size() + " routers started up");
+        _out.println("All routers have been started");
+        
+        /* Wait for routers to start services and generate keys.. */
+        try { Thread.sleep(1000); } catch (InterruptedException ie) {}   
+        internalReseed();
+        
         waitForCompletion();
     }
     
-    private static Properties getEnv(String filename) {
+    private static void internalReseed() {
+
+    	HashSet<RouterInfo> riSet = new HashSet<RouterInfo>();
+    	for(Router r : _routers) {
+    		riSet.addAll(r.getContext().netDb().getRouters());
+    	}
+		for(Router r : _routers) {
+    		for(RouterInfo ri : riSet){
+    			r.getContext().netDb().publish(ri);
+    		}
+    	}
+		_out.println(riSet.size() + " RouterInfos were reseeded");
+    }
+    
+    private static Properties buildRouterProps(int id) {
+        Properties props = getRouterProps(id);
+        File f = new File(props.getProperty("router.configLocation"));
+        f.getParentFile().mkdirs();
+        if (!f.exists()) {
+            try {
+				DataHelper.storeProps(props, f);
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+        }
+        return props;
+    }
+    
+    private static Properties getRouterProps(int id) {
         Properties props = new Properties();
-        FileInputStream in = null;
-        try {
-            in = new FileInputStream(filename);
-            props.load(in);
-            props.setProperty("time.disabled", "true");
-            return props;
-        } catch (IOException ioe) {
-            ioe.printStackTrace();
-            return null;
-        } finally {
-            if (in != null) try { in.close(); } catch (IOException ioe) {}
+
+        props.setProperty("router.profileDir", "/peerProfiles");
+        props.setProperty("router.sessionKeys.location", "/sessionKeys.dat");
+        props.setProperty("router.info.location", "/router.info");
+        props.setProperty("router.keys.location", "/router.keys");
+        props.setProperty("router.networkDatabase.dbDir", "/netDb");
+        props.setProperty("router.tunnelPoolFile", "/tunnelPool.dat");
+        props.setProperty("router.keyBackupDir", "/keyBackup");
+        props.setProperty("router.clientConfigFile", getBaseDir(id) + "/clients.config");
+        props.setProperty("router.configLocation", getBaseDir(id) + "/router.config");
+        props.setProperty("router.pingFile", getBaseDir(id) + "/router.ping");
+        props.setProperty("router.rejectStartupTime", "0");
+        props.setProperty("router.reseedDisable", "true");
+        props.setProperty("i2p.dir.app", getBaseDir(id));
+        
+        /* If MultiRouter is not run from a dir containing lib/, webapps/, docs/, etc.
+         * point i2p.dir.base to a directory containing the above. */
+        //props.setProperty("i2p.dir.base", getBaseDir(id));
+        props.setProperty("i2p.dir.config", getBaseDir(id));
+        props.setProperty("i2p.dir.log", getBaseDir(id));
+        props.setProperty("i2p.dir.router", getBaseDir(id));
+        props.setProperty("i2p.dir.pid", getBaseDir(id));
+        //props.setProperty("i2p.vmCommSystem", "true");
+        props.setProperty("i2np.ntcp.hostname", "127.0.0.1");
+        props.setProperty("i2np.udp.host", "127.0.0.1");
+        props.setProperty("i2np.ntcp.port", BASE_PORT + id + "");
+        props.setProperty("i2np.udp.port", BASE_PORT + id + "");
+        props.setProperty("i2np.ntcp.allowLocal", "true");
+        props.setProperty("i2np.udp.allowLocal", "true");
+        props.setProperty("i2np.udp.internalPort", BASE_PORT + id + "");
+        props.setProperty("i2cp.port", Integer.toString((BASE_PORT + nbrRouters + id)));   
+
+        return props;
+    }
+    
+    private static Properties buildClientProps(int id) {
+    	Properties rProps = getRouterProps(id);
+        Properties props = getClientProps();
+        File f = new File(rProps.getProperty("router.clientConfigFile"));
+        f.getParentFile().mkdirs();
+        if (!f.exists()) {
+            try {
+				DataHelper.storeProps(props, f);
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
         }
+        return props;
+    }
+    
+    private static Properties getClientProps() {
+    	Properties props = new Properties();
+    	
+    	props.setProperty("clientApp.0.args", (BASE_PORT-1) + " 127.0.0.1 ./webapps");
+        props.setProperty("clientApp.0.main", "net.i2p.router.web.RouterConsoleRunner");
+        props.setProperty("clientApp.0.name", "webconsole");
+        props.setProperty("clientApp.0.onBoot", "true");
+        props.setProperty("clientApp.1.args", "i2ptunnel.config");
+        props.setProperty("clientApp.1.main", "net.i2p.i2ptunnel.TunnelControllerGroup");
+        props.setProperty("clientApp.1.name", "tunnels");
+        props.setProperty("clientApp.1.delay", "6");
+        
+        return props;
+    }
+    
+    private static String getBaseDir(int id) {
+    	File f = new File(".");
+    	return f.getAbsoluteFile().getParentFile().toString() + "/multirouter/"+ Integer.toString(id);
     }
     
     private static void waitForCompletion() {
@@ -110,8 +226,7 @@ public class MultiRouter {
             for (int i = 0; i < _routers.size(); i++) {
                 Router r = (Router)_routers.get(i);
                 if (!r.isAlive()) {
-                    if (_log.shouldLog(Log.INFO))
-                        _log.info("Router " + i + " is dead");
+                	_out.println("Router " + i + " is dead");
                 } else {
                     alive++;
                 }
@@ -122,13 +237,11 @@ public class MultiRouter {
                 break;
             }
         }
-        _log.info("All routers shut down");
+        _out.println("All routers shut down");
     }
     
     private static void usage() {
-        System.err.println("Usage: MultiRouter globalContextFile routerContextFile[ routerContextFile]*");
-        System.err.println("       The context files contain key=value entries specifying properties");
-        System.err.println("       to load into the given context.  In addition, each routerContextFile");
-        System.err.println("       in turn is used to boot a router");
+        System.err.println("Usage: MultiRouter nbr_routers");
+        System.err.println("       Where nbr_routers > 0");
     }
 }
diff --git a/router/java/src/net/i2p/router/MultiRouterBuilder.java b/router/java/src/net/i2p/router/MultiRouterBuilder.java
deleted file mode 100644
index 6a7c635bc8a3a5731387cf02cbc0edc9b9394bd3..0000000000000000000000000000000000000000
--- a/router/java/src/net/i2p/router/MultiRouterBuilder.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package net.i2p.router;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Build a set of config files suitable for use by the multirouter as a 
- * simulation, as well as a pair of scripts for running the simulation.  
- * Usage: <pre>
- *   MultiRouterBuilder [routerDir routerPortStart]*
- * </pre>
- * 
- * Each router is configured with their own $routerDir/router.config file so
- * that all of its data is stored under the $routerDir (profiles, keys, netDb,
- * etc).  In addition, each router has the i2cp port set to $routerPortStart+1,
- * the admin port set to $routerPortStart+2, and some commented out clientApp
- * lines (configured with the SAM bridge at $routerPortStart+3 and an EepProxy at
- * $routerPortStart+4).<p />
- *
- * It then builds a $routerDir/heartbeat.config containing the following lines:<ul>
- *  <li>i2cpHost=localhost</li>
- *  <li>i2cpPort=$routerPortStart+1</li>
- *  <li>numHops=2</li>
- *  <li>privateDestinationFile=$routerDir/heartbeat.keys</li>
- *  <li>publicDestinationFile=$routerDir/heartbeat.txt</li>
- * </ul>
- *
- * Then it goes on to create the $routerDir/routerEnv.txt:<ul>
- *  <li>loggerFilenameOverride=$routerDir/logs/log-router-#.txt</li>
- *  <li>router.configLocation=$routerDir/router.config</li>
- *  <li>i2p.vmCommSystem=true</li>
- *  <li>i2p.encryption=off</li>
- * </ul>
- *
- * In addition, it creates a baseEnv.txt: <ul>
- *  <li>loggerFilenameOverride=logs/log-base-#.txt</li>
- * </ul>
- *
- * Finally, it creates the MultiRouter startup script to launch all of these
- * routers, stored at runNetSim.bat / runNetSim.sh
- *
- */
-public class MultiRouterBuilder {
-    public static void main(String args[]) {
-        if (args.length < 2) {
-            usage();
-            return;
-        }
-        for (int i = 0; i < args.length; i += 2) {
-            String dir = args[i];
-            try {
-                int basePortNum = Integer.parseInt(args[i+1]);
-                buildConfig(dir, basePortNum, i == 0);
-            } catch (NumberFormatException nfe) {
-                nfe.printStackTrace();
-            }
-        }
-        buildBaseEnv();
-        buildStartupScript(args);
-    }
-    
-    private static void buildBaseEnv() {
-        File envFile = new File("baseEnv.txt");
-        try {
-            FileOutputStream fos = new FileOutputStream(envFile);
-            fos.write(("loggerFilenameOverride=logs/log-base-#.txt\n").getBytes());
-            fos.close();
-        } catch (IOException ioe) {
-            ioe.printStackTrace();
-        }
-        File f = new File("logs");
-        f.mkdirs();
-    }
-    
-    private static void buildStartupScript(String args[]) {
-        buildStartupScriptNix(args);
-    }
-    private static void buildStartupScriptNix(String args[]) {
-        StringBuilder buf = new StringBuilder(4096);
-        buf.append("#!/bin/sh\n");
-        buf.append("export CP=.; for LIB in lib/* ; do export CP=$CP:$LIB ; done\n"); 
-        buf.append("nohup java -cp $CP ");
-        buf.append(" -Xmx1024m");
-        buf.append(" -Djava.library.path=.");
-        buf.append(" -DloggerFilenameOverride=logs/log-sim-#.txt");
-        buf.append(" -Dorg.mortbay.http.Version.paranoid=true");
-        buf.append(" -Dorg.mortbay.util.FileResource.checkAliases=false");
-        buf.append(" -verbose:gc");
-        
-        buf.append(" net.i2p.router.MultiRouter baseEnv.txt ");
-        for (int i = 0; i < args.length; i += 2) 
-            buf.append(args[i]).append("/routerEnv.txt ");
-        buf.append(" > sim.out 2>&1 &\n");
-        buf.append("echo $! > sim.pid\n");
-        buf.append("echo \"After all of the routers have started up, you should cross seed them\"\n");
-        buf.append("echo \"Simply copy */netDb/routerInfo-* to all of the various */netDb/ directories\"\n");
-        try {
-            FileOutputStream fos = new FileOutputStream("runNetSim.sh");
-            fos.write(buf.toString().getBytes());
-            fos.close();
-        } catch (IOException ioe) { ioe.printStackTrace(); }
-    }
-    
-    private static void buildConfig(String dir, int basePort, boolean isFirst) {
-        File baseDir = new File(dir);
-        baseDir.mkdirs();
-        File cfgFile = new File(baseDir, "router.config");
-        StringBuilder buf = new StringBuilder(8*1024);
-        buf.append("router.profileDir=").append(baseDir.getPath()).append("/peerProfiles\n");
-        buf.append("router.historyFilename=").append(baseDir.getPath()).append("/messageHistory.txt\n");
-        buf.append("router.sessionKeys.location=").append(baseDir.getPath()).append("/sessionKeys.dat\n");
-        buf.append("router.info.location=").append(baseDir.getPath()).append("/router.info\n");
-        buf.append("router.keys.location=").append(baseDir.getPath()).append("/router.keys\n");
-        buf.append("router.networkDatabase.dbDir=").append(baseDir.getPath()).append("/netDb\n");
-        buf.append("router.tunnelPoolFile=").append(baseDir.getPath()).append("/tunnelPool.dat\n");
-        buf.append("router.keyBackupDir=").append(baseDir.getPath()).append("/keyBackup\n");
-        buf.append("router.clientConfigFile=").append(baseDir.getPath()).append("/clients.config\n");
-        buf.append("i2np.tcp.port=").append(basePort).append('\n');
-        buf.append("i2np.tcp.hostname=localhost\n");
-        buf.append("i2np.tcp.allowLocal=true\n");
-        buf.append("i2np.tcp.disable=true\n");
-        buf.append("i2np.tcp.enable=false\n");
-        buf.append("i2np.udp.host=127.0.0.1\n");
-        buf.append("i2np.udp.port=").append(basePort).append('\n');
-        buf.append("i2np.udp.internalPort=").append(basePort).append('\n');
-        buf.append("i2cp.port=").append(basePort+1).append('\n');
-        buf.append("stat.logFile=").append(baseDir.getPath()).append("/stats.log\n");
-        buf.append("stat.logFilters=*\n");
-        
-        try {
-            FileOutputStream fos = new FileOutputStream(cfgFile);
-            fos.write(buf.toString().getBytes());
-            fos.close();
-            
-            File envFile = new File(baseDir, "routerEnv.txt");
-            fos = new FileOutputStream(envFile);
-            fos.write(("loggerFilenameOverride="+baseDir+ "/logs/log-router-#.txt\n").getBytes());
-            fos.write(("router.configLocation="+baseDir+"/router.config\n").getBytes());
-            fos.write(("router.pingFile="+baseDir+"/router.ping\n").getBytes());
-            //fos.write(("i2p.vmCommSystem=true\n").getBytes());
-            //fos.write(("i2p.encryption=off\n").getBytes());
-            fos.close();
-            
-            File f = new File(baseDir, "logs");
-            f.mkdirs();
-            
-            if (isFirst) {
-                fos = new FileOutputStream(baseDir.getPath() + "/clients.config");
-                fos.write(("clientApp.0.args=" + (basePort-1) + " 127.0.0.1 ./webapps\n").getBytes());
-                fos.write(("clientApp.0.main=net.i2p.router.web.RouterConsoleRunner\n").getBytes());
-                fos.write(("clientApp.0.name=webconsole\n").getBytes());
-                fos.write(("clientApp.0.onBoot=true\n").getBytes());
-                fos.write(("clientApp.1.args=\n").getBytes());
-                fos.write(("clientApp.1.main=net.i2p.router.Counter\n").getBytes());
-                fos.write(("clientApp.1.name=counter\n").getBytes());
-                fos.write(("clientApp.1.onBoot=true\n").getBytes());
-                fos.write(("clientApp.2.args=i2ptunnel.config\n").getBytes());
-                fos.write(("clientApp.2.main=net.i2p.i2ptunnel.TunnelControllerGroup\n").getBytes());
-                fos.write(("clientApp.2.name=tunnels\n").getBytes());
-                fos.write(("clientApp.2.delay=60\n").getBytes());
-                fos.close();
-            }
-        
-        } catch (IOException ioe) {
-            ioe.printStackTrace();
-        }
-    }
-    
-    private static void usage() {
-        System.err.println("Usage: MultiRouterBuilder [routerDir routerPortStart]*");
-    }
-}
diff --git a/router/java/src/net/i2p/router/RouterThrottleImpl.java b/router/java/src/net/i2p/router/RouterThrottleImpl.java
index dd9ef576fedfed6ebcd5af56ce91234ec488d40f..e1c76755070e4dbb40f3b562d8c9971574e8b9b6 100644
--- a/router/java/src/net/i2p/router/RouterThrottleImpl.java
+++ b/router/java/src/net/i2p/router/RouterThrottleImpl.java
@@ -27,6 +27,8 @@ class RouterThrottleImpl implements RouterThrottle {
     private static final String PROP_MAX_TUNNELS = "router.maxParticipatingTunnels";
     private static final int DEFAULT_MAX_TUNNELS = 5000;
     private static final String PROP_MAX_PROCESSINGTIME = "router.defaultProcessingTimeThrottle";
+    private static final long DEFAULT_REJECT_STARTUP_TIME = 20*60*1000;
+    private static final String PROP_REJECT_STARTUP_TIME = "router.rejectStartupTime";
 
     /**
      *  TO BE FIXED - SEE COMMENTS BELOW
@@ -39,13 +41,12 @@ class RouterThrottleImpl implements RouterThrottle {
     /** = TrivialPreprocessor.PREPROCESSED_SIZE */
     private static final int PREPROCESSED_SIZE = 1024;
 
-    private static final long REJECT_STARTUP_TIME = 20*60*1000;
     
     public RouterThrottleImpl(RouterContext context) {
         _context = context;
         _log = context.logManager().getLog(RouterThrottleImpl.class);
         setTunnelStatus();
-        _context.simpleScheduler().addEvent(new ResetStatus(), REJECT_STARTUP_TIME + 120*1000);
+        _context.simpleScheduler().addEvent(new ResetStatus(), 5*1000 + _context.getProperty(PROP_REJECT_STARTUP_TIME, DEFAULT_REJECT_STARTUP_TIME));
         _context.statManager().createRateStat("router.throttleNetworkCause", "How lagged the jobQueue was when an I2NP was throttled", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
         //_context.statManager().createRateStat("router.throttleNetDbCause", "How lagged the jobQueue was when a networkDb request was throttled", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
         //_context.statManager().createRateStat("router.throttleTunnelCause", "How lagged the jobQueue was when a tunnel request was throttled", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
@@ -114,7 +115,7 @@ class RouterThrottleImpl implements RouterThrottle {
         }
         
         // Don't use CRIT because we don't want peers to think we're failing
-        if (_context.router().getUptime() < REJECT_STARTUP_TIME) {
+        if (_context.router().getUptime() < DEFAULT_REJECT_STARTUP_TIME) {
             setTunnelStatus(_x("Rejecting tunnels: Starting up"));
             return TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
         }