diff --git a/install-headless.txt b/INSTALL-headless.txt
similarity index 87%
rename from install-headless.txt
rename to INSTALL-headless.txt
index 6def73d54fcd4ebe8651641b96ecdca4c4177b8d..03229c7964bd2ef66e7f161b96e343b8dcc9a4f7 100644
--- a/install-headless.txt
+++ b/INSTALL-headless.txt
@@ -1,8 +1,7 @@
-$Id: install-headless.txt,v 1.5 2005/09/29 14:19:23 jrandom Exp $
 Headless I2P installation instructions
 
 1) tar xjf i2p.tar.bz2                     (you've already done this)
-2) cd i2p ; vi install-headless.txt        (you're doing this now)
+2) cd i2p ; vi INSTALL-headless.txt        (you're doing this now)
 3) sh postinstall.sh                       (this launches the router)
 4) lynx http://localhost:7657/index.jsp    (configure the router)
 
diff --git a/install.txt b/INSTALL.txt
similarity index 100%
rename from install.txt
rename to INSTALL.txt
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
index 8e76273098154ca34df4fd706588654cc23c5847..486bcdead5cb7098ac9725c607f5b9fd70e16b81 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
@@ -75,7 +75,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
     private static long __tunnelId = 0;
     private long _tunnelId;
     private Properties _clientOptions;
-    private final List _sessions;
+    private final List<I2PSession> _sessions;
 
     public static final int PACKET_DELAY = 100;
 
@@ -179,7 +179,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
         }
     }
 
-    List getSessions() { 
+    List<I2PSession> getSessions() { 
         synchronized (_sessions) {
             return new ArrayList(_sessions); 
         }
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
index 3c571857afc506de94539133b3387243553ff729..190a4a96d6ee58b909419477a91448c4315c2f79 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
@@ -44,6 +44,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
     protected final Object sockLock = new Object(); // Guards sockMgr and mySockets
     protected I2PSocketManager sockMgr; // should be final and use a factory. LINT
     protected List mySockets = new ArrayList();
+    protected boolean _ownDest;
 
     protected Destination dest = null;
     private int localPort;
@@ -114,6 +115,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
         this.l = l;
         this.handlerName = handlerName + _clientId;
         this.privKeyFile = pkf;
+        _ownDest = ownDest; // == ! shared client
 
 
         _context = tunnel.getContext();
@@ -129,13 +131,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
         boolean openNow = !Boolean.valueOf(tunnel.getClientOptions().getProperty("i2cp.delayOpen")).booleanValue();
         if (openNow) {
             while (sockMgr == null) {
-                synchronized (sockLock) {
-                    if (ownDest) {
-                        sockMgr = buildSocketManager();
-                    } else {
-                        sockMgr = getSocketManager();
-                    }
-                }
+                verifySocketManager();
                 if (sockMgr == null) {
                     _log.log(Log.CRIT, "Unable to create socket manager (our own? " + ownDest + ")");
                     try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
@@ -209,27 +205,67 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
         }
     }
 
+    /**
+     * Sets the this.sockMgr field if it is null, or if we want a new one
+     *
+     * We need a socket manager before getDefaultOptions() and most other things
+     */
+    protected void verifySocketManager() {
+        synchronized(sockLock) {
+            boolean newManager = false;
+            if (this.sockMgr == null) {
+                newManager = true;
+            } else {
+                I2PSession sess = sockMgr.getSession();
+                if (sess == null) {
+                    newManager = true;
+                } else if (sess.isClosed() &&
+                           Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.closeOnIdle")).booleanValue() &&
+                           Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.newDestOnResume")).booleanValue()) {
+                    // build a new socket manager and a new dest if the session is closed.
+                    getTunnel().removeSession(sess);
+                    if (_log.shouldLog(Log.WARN))
+                        _log.warn(getTunnel().getClientOptions().getProperty("inbound.nickname") + ": Built a new destination on resume");
+                    newManager = true;
+                }  // else the old socket manager will reconnect the old session if necessary
+            }
+            if (newManager) {
+                if (_ownDest)
+                    this.sockMgr = buildSocketManager();
+                else
+                    this.sockMgr = getSocketManager();
+            }
+        }
+    }
+
+    /** this is ONLY for shared clients */
     private static I2PSocketManager socketManager;
 
+    /** this is ONLY for shared clients */
     protected synchronized I2PSocketManager getSocketManager() {
         return getSocketManager(getTunnel(), this.privKeyFile);
     }
+    /** this is ONLY for shared clients */
     protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel) {
         return getSocketManager(tunnel, null);
     }
+    /** this is ONLY for shared clients */
     protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) {
         if (socketManager != null) {
             I2PSession s = socketManager.getSession();
             if ( (s == null) || (s.isClosed()) ) {
-                _log.info("Building a new socket manager since the old one closed [s=" + s + "]");
+                if (_log.shouldLog(Log.INFO))
+                    _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Building a new socket manager since the old one closed [s=" + s + "]");
                 if (s != null)
                     tunnel.removeSession(s);
                 socketManager = buildSocketManager(tunnel, pkf);
             } else {
-                _log.info("Not building a new socket manager since the old one is open [s=" + s + "]");
+                if (_log.shouldLog(Log.INFO))
+                    _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Not building a new socket manager since the old one is open [s=" + s + "]");
             }
         } else {
-            _log.info("Building a new socket manager since there is no other one");
+            if (_log.shouldLog(Log.INFO))
+                _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Building a new socket manager since there is no other one");
             socketManager = buildSocketManager(tunnel, pkf);
         }
         return socketManager;
@@ -278,6 +314,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
             }
         }
         sockManager.setName("Client");
+        if (_log.shouldLog(Log.INFO))
+            _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Built a new socket manager [s=" + sockManager.getSession() + "]");
         tunnel.addSession(sockManager.getSession());
         return sockManager;
     }
@@ -343,12 +381,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
      * @return a new I2PSocket
      */
     public I2PSocket createI2PSocket(Destination dest) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
-        if (sockMgr == null) {
-            // we need this before getDefaultOptions()
-            synchronized(sockLock) {
-                sockMgr = getSocketManager();
-            }
-        }
+        verifySocketManager();
         return createI2PSocket(dest, getDefaultOptions());
     }
 
@@ -369,22 +402,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
     public I2PSocket createI2PSocket(Destination dest, I2PSocketOptions opt) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
         I2PSocket i2ps;
 
-        if (sockMgr == null) {
-            // delayed open - call get instead of build because the locking is up there
-            synchronized(sockLock) {
-                sockMgr = getSocketManager();
-            }
-        } else if (Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.closeOnIdle")).booleanValue() &&
-                   Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.newDestOnResume")).booleanValue()) {
-            synchronized(sockLock) {
-                I2PSocketManager oldSockMgr = sockMgr;
-                // This will build a new socket manager and a new dest if the session is closed.
-                sockMgr = getSocketManager();
-                if (oldSockMgr != sockMgr) {
-                    _log.warn("Built a new destination on resume");
-                }
-            }
-        }  // else the old socket manager will reconnect the old session if necessary
+        verifySocketManager();
         i2ps = sockMgr.connect(dest, opt);
         synchronized (sockLock) {
             mySockets.add(i2ps);
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
index 13906807eb3d7f32068f8390c78e3fb7b9eafc8c..59971e8f3d7b1d429928ed52a29ecc982bb12ba7 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
@@ -157,11 +157,7 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna
         if (!defaultOpts.contains("i2p.streaming.inactivityTimeout"))
             defaultOpts.setProperty("i2p.streaming.inactivityTimeout", ""+DEFAULT_READ_TIMEOUT);
         // delayed start
-        if (sockMgr == null) {
-            synchronized(sockLock) {
-                sockMgr = getSocketManager();
-            }
-        }
+        verifySocketManager();
         I2PSocketOptions opts = sockMgr.buildOptions(defaultOpts);
         if (!defaultOpts.containsKey(I2PSocketOptions.PROP_CONNECT_TIMEOUT))
             opts.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
index 316731deec7f44c57ba141d7a19c718effd467a9..7e16114adccbaa7b6e0bb4de15533c86b70beea7 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
@@ -211,11 +211,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
         if (!defaultOpts.contains("i2p.streaming.inactivityTimeout"))
             defaultOpts.setProperty("i2p.streaming.inactivityTimeout", ""+DEFAULT_READ_TIMEOUT);
         // delayed start
-        if (sockMgr == null) {
-            synchronized(sockLock) {
-                sockMgr = getSocketManager();
-            }
-        }
+        verifySocketManager();
         I2PSocketOptions opts = sockMgr.buildOptions(defaultOpts);
         if (!defaultOpts.containsKey(I2PSocketOptions.PROP_CONNECT_TIMEOUT))
             opts.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
index 419e5a899d9e262353177e6c6bd57d5020dc16c0..1f67783e9b6578db5d1d803639be99d04834f652 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
@@ -434,6 +434,16 @@ public class TunnelController implements Logging {
     
     public boolean getIsRunning() { return _running; }
     public boolean getIsStarting() { return _starting; }
+    /** if running but no open sessions, we are in standby */
+    public boolean getIsStandby() {
+        if (!_running)
+            return false;
+        for (I2PSession sess : _tunnel.getSessions()) {
+            if (!sess.isClosed())
+                return false;
+        }
+        return true;
+    }
     
     public void getSummary(StringBuffer buf) {
         String type = getType();
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
index 24bbb9119a4237c0cb546382465bc657a454ad60..4c23ced34741bf662e0a9294f9f8ebf2ee30f0af 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
@@ -77,6 +77,7 @@ public class IndexBean {
     public static final int RUNNING = 1;
     public static final int STARTING = 2;
     public static final int NOT_RUNNING = 3;
+    public static final int STANDBY = 4;
     
     public static final String PROP_TUNNEL_PASSPHRASE = "i2ptunnel.passphrase";
     static final String PROP_NONCE = IndexBean.class.getName() + ".nonce";
@@ -412,8 +413,12 @@ public class IndexBean {
     public int getTunnelStatus(int tunnel) {
         TunnelController tun = getController(tunnel);
         if (tun == null) return NOT_RUNNING;
-        if (tun.getIsRunning()) return RUNNING;
-        else if (tun.getIsStarting()) return STARTING;
+        if (tun.getIsRunning()) {
+            if (isClient(tunnel) && tun.getIsStandby())
+                return STANDBY;
+            else
+                return RUNNING;
+        } else if (tun.getIsStarting()) return STARTING;
         else return NOT_RUNNING;
     }
     
@@ -778,12 +783,6 @@ public class IndexBean {
                 config.setProperty("interface", _reachableByOther);
             else
                 config.setProperty("interface", _reachableBy);
-            config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
-            config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
-            if (_name != null && !_sharedClient) {
-                 config.setProperty("option.inbound.nickname", _name);
-                 config.setProperty("option.outbound.nickname", _name);
-            }
             config.setProperty("sharedClient", _sharedClient + "");
             for (String p : _booleanClientOpts)
                 config.setProperty("option." + p, "" + _booleanOptions.contains(p));
@@ -896,14 +895,12 @@ public class IndexBean {
             config.setProperty("option.i2p.streaming.connectDelay", "1000");
         else
             config.setProperty("option.i2p.streaming.connectDelay", "0");
-        if (_name != null) {
-            if ( (!isClient(_type)) || (!_sharedClient) ) {
-                config.setProperty("option.inbound.nickname", _name);
-                config.setProperty("option.outbound.nickname", _name);
-            } else {
-                config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
-                config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
-            }
+        if (isClient(_type) && _sharedClient) {
+            config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
+            config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
+        } else if (_name != null) {
+            config.setProperty("option.inbound.nickname", _name);
+            config.setProperty("option.outbound.nickname", _name);
         }
         if ("interactive".equals(_profile))
             // This was 1 which doesn't make much sense
diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp
index 4d9f6c57d9eac57838f96fe76ccd61503c87f672..6c89d5ff426f1a073720db13c37f6d78216e30b4 100644
--- a/apps/i2ptunnel/jsp/index.jsp
+++ b/apps/i2ptunnel/jsp/index.jsp
@@ -97,6 +97,11 @@
                 case IndexBean.STARTING:
           %><div class="statusStarting text">Starting...</div>
             <a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&amp;action=stop&amp;tunnel=<%=curClient%>">Stop</a>
+        <%
+                break;
+                case IndexBean.STANDBY:
+          %><div class="statusStarting text">Standby</div>
+            <a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&amp;action=stop&amp;tunnel=<%=curClient%>">Stop</a>
         <%
                 break;
                 case IndexBean.RUNNING:
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java
index 066cb11443c0b3d9e9bc8e22743b332e05bff58c..e701ede9954e8925d1f2018014988859e3ad0fcc 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java
@@ -91,8 +91,9 @@ public class ReseedHandler {
         public boolean isRunning() { return _isRunning; }
         public void run() {
             _isRunning = true;
+            System.out.println("Reseed start");
             reseed(false);
-            System.out.println("Reseeding complete");
+            System.out.println("Reseed complete");
             System.setProperty("net.i2p.router.web.ReseedHandler.reseedInProgress", "false");
             _isRunning = false;
         }
@@ -133,7 +134,7 @@ public class ReseedHandler {
         }
 
         /**
-         *  Fetch a directory listing and then all the routerInfo files in the listing.
+         *  Fetch a directory listing and then up to 200 routerInfo files in the listing.
          *  The listing must contain (exactly) strings that match:
          *           href="routerInfo-{hash}.dat">
          * and then it fetches the files
@@ -147,6 +148,7 @@ public class ReseedHandler {
             try {
                 System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage","");
                 System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage","Reseeding: fetching seed URL.");
+                System.err.println("Reseed from " + seedURL);
                 URL dir = new URL(seedURL);
                 byte contentRaw[] = readURL(dir);
                 if (contentRaw == null) {
@@ -160,7 +162,8 @@ public class ReseedHandler {
                 String content = new String(contentRaw);
                 Set urls = new HashSet();
                 int cur = 0;
-                while (true) {
+                int total = 0;
+                while (total++ < 1000) {
                     int start = content.indexOf("href=\"routerInfo-", cur);
                     if (start < 0)
                         break;
@@ -170,7 +173,7 @@ public class ReseedHandler {
                     urls.add(name);
                     cur = end + 1;
                 }
-                if (urls.size() <= 0) {
+                if (total <= 0) {
                     _log.error("Read " + contentRaw.length + " bytes from seed " + seedURL + ", but found no routerInfo URLs.");
                     System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
                         "Last reseed failed fully (no routerInfo URLs at seed URL). " +
@@ -178,13 +181,16 @@ public class ReseedHandler {
                     return;
                 }
 
+                List urlList = new ArrayList(urls);
+                Collections.shuffle(urlList);
                 int fetched = 0;
                 int errors = 0;
-                for (Iterator iter = urls.iterator(); iter.hasNext(); ) {
+                // 200 max from one URL
+                for (Iterator iter = urlList.iterator(); iter.hasNext() && fetched < 200; ) {
                     try {
                         System.setProperty("net.i2p.router.web.ReseedHandler.statusMessage",
                             "Reseeding: fetching router info from seed URL (" +
-                            fetched + " successful, " + errors + " errors, " + urls.size() + " total).");
+                            fetched + " successful, " + errors + " errors, " + total + " total).");
 
                         fetchSeed(seedURL, (String)iter.next());
                         fetched++;
@@ -197,24 +203,24 @@ public class ReseedHandler {
                         errors++;
                     }
                 }
-                if (echoStatus) System.out.println();
+                System.err.println("Reseed got " + fetched + " router infos from " + seedURL);
                 
-                int failPercent = 100 * errors / urls.size();
+                int failPercent = 100 * errors / total;
                 
                 // Less than 10% of failures is considered success,
                 // because some routerInfos will always fail.
                 if ((failPercent >= 10) && (failPercent < 90)) {
                     System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
-                        "Last reseed failed partly (" + failPercent + "% of " + urls.size() + "). " +
+                        "Last reseed failed partly (" + failPercent + "% of " + total + "). " +
                         RESEED_TIPS);
                 }
                 if (failPercent >= 90) {
                     System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
-                        "Last reseed failed (" + failPercent + "% of " + urls.size() + "). " +
+                        "Last reseed failed (" + failPercent + "% of " + total + "). " +
                         RESEED_TIPS);
                 }
                 // Don't go on to the next URL if we have enough
-                if (fetched > 25)
+                if (fetched >= 100)
                     _isRunning = false;
             } catch (Throwable t) {
                 System.setProperty("net.i2p.router.web.ReseedHandler.errorMessage",
diff --git a/apps/routerconsole/jsp/configservice.jsp b/apps/routerconsole/jsp/configservice.jsp
index 5d9de218abfc1eab7f820d29992abc87e5890e55..a69c112dbc11ca7d90310976567102d811b2bbe1 100644
--- a/apps/routerconsole/jsp/configservice.jsp
+++ b/apps/routerconsole/jsp/configservice.jsp
@@ -32,6 +32,7 @@
  <input type="submit" name="action" value="Shutdown immediately" />
  <input type="submit" name="action" value="Cancel graceful shutdown" />
  
+ <% if (System.getProperty("wrapper.version") != null) { %>
  <p>If you want the router to restart itself after shutting down, you can choose one of 
  the following.  This is useful in some situations - for example, if you changed
  some settings that client applications only read at startup, such as the routerconsole password
@@ -41,6 +42,7 @@
  
  <input type="submit" name="action" value="Graceful restart" />
  <input type="submit" name="action" value="Hard restart" />
+ <% } %>
  
  <% if ( (System.getProperty("os.name") != null) && (System.getProperty("os.name").startsWith("Win")) ) { %>
  <h4>Systray integration</h4>
@@ -61,11 +63,14 @@
  down your router immediately.  You may want to consider shutting down gracefully, as
  above, then running uninstall_i2p_service_winnt.bat.</p>
  <% } %>
+
+ <% if (System.getProperty("wrapper.version") != null) { %>
  <h4>Debugging</h4>
  <p>At times, it may be helpful to debug I2P by getting a thread dump.  To do so, 
  please select the following option and review the thread dumped to 
  <a href="logs.jsp#servicelogs">wrapper.log</a>.</p>
  <input type="submit" name="action" value="Dump threads" />
+ <% } %>
  
  <h4>Launch browser on router startup?</h4>
  <p>I2P's main configuration interface is this web console, so for your convenience
diff --git a/build.xml b/build.xml
index f7a7294e38d0a23c949a7f23ea3a4bf45e97b48c..8fadcf8313227c24b3d43e7c56480fe5b0bfa9c3 100644
--- a/build.xml
+++ b/build.xml
@@ -278,7 +278,7 @@
             <fileset dir="installer/lib/wrapper/win32/" />
         </copy>
         <copy file="hosts.txt" todir="pkg-temp/" />
-        <copy file="install-headless.txt" todir="pkg-temp/" />
+        <copy file="INSTALL-headless.txt" todir="pkg-temp/" />
         <copy file="history.txt" todir="pkg-temp/" />
         <mkdir dir="pkg-temp/scripts" />
         <copy file="apps/proxyscript/i2pProxy.pac" todir="pkg-temp/scripts/" />
diff --git a/checklist.txt b/checklist.txt
index fcbe65028456e096dd4d951c77d019f626670ba5..baea847b956016fbf6089eb3339909e545d62e3b 100644
--- a/checklist.txt
+++ b/checklist.txt
@@ -18,6 +18,10 @@ Review the complete diff from the last release:
         mtn diff -r t:i2p-0.7.(xx-1) > out.diff
         vi out.diff
 
+Verify that no untrusted revisions were inadvertently
+blessed by a trusted party:
+        mtn log --brief --no-graph --to t:i2p-0.7.(xx-1) | cut -d ' ' -f 2- | sort
+
 Build and tag:
 	ant pkg
 	mtn ci
diff --git a/router/java/src/net/i2p/router/RouterWatchdog.java b/router/java/src/net/i2p/router/RouterWatchdog.java
index e14331b6df2ac5fbfb0102fc3698e32f6a86e227..cb168102248a8a652cf837b16e36b1bbacb6ecf2 100644
--- a/router/java/src/net/i2p/router/RouterWatchdog.java
+++ b/router/java/src/net/i2p/router/RouterWatchdog.java
@@ -49,11 +49,15 @@ class RouterWatchdog implements Runnable {
     }
     
     private boolean shutdownOnHang() {
+        // prop default true
+        if (!Boolean.valueOf(_context.getProperty("watchdog.haltOnHang", "true")).booleanValue())
+            return false;
+
         // Client manager starts complaining after 10 minutes, and we run every minute,
-        // so this will restart 20 minutes after we lose a lease, if the wrapper is present.
-        if (_consecutiveErrors >= 10 && System.getProperty("wrapper.version") != null)
+        // so this will restart 30 minutes after we lose a lease, if the wrapper is present.
+        if (_consecutiveErrors >= 20 && System.getProperty("wrapper.version") != null)
             return true;
-        return Boolean.valueOf(_context.getProperty("watchdog.haltOnHang", "false")).booleanValue();
+        return false;
     }
     
     private void dumpStatus() {
@@ -90,13 +94,14 @@ class RouterWatchdog implements Runnable {
             long used = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
             _log.error("Memory: " + DataHelper.formatSize(used) + '/' + DataHelper.formatSize(max));
             if (_consecutiveErrors == 1) {
+                _log.log(Log.CRIT, "Router appears hung!  Will restart in 20 minutes if it doesn't fix itself");
                 // This might work on linux...
                 // It won't on windows, and we can't call i2prouter.bat either, it does something
                 // completely different...
                 ShellCommand sc = new ShellCommand();
                 boolean success = sc.executeSilentAndWaitTimed("./i2prouter dump", 10);
                 if (success)
-                    _log.error("DUMPED THREADS TO WRAPPER LOG");
+                    _log.log(Log.CRIT, "Threads dumped to wrapper log");
             }
         }
     }
@@ -127,7 +132,7 @@ class RouterWatchdog implements Runnable {
             _consecutiveErrors++;
             dumpStatus();
             if (shutdownOnHang()) {
-                _log.log(Log.CRIT, "Router hung!  hard restart!");
+                _log.log(Log.CRIT, "Router hung!  Restart forced by watchdog!");
                 try { Thread.sleep(30*1000); } catch (InterruptedException ie) {}
                 // halt and not system.exit, since some of the shutdown hooks might be misbehaving
                 Runtime.getRuntime().halt(Router.EXIT_HARD_RESTART);
diff --git a/router/java/src/net/i2p/router/StatisticsManager.java b/router/java/src/net/i2p/router/StatisticsManager.java
index d037ee300eabf11255b5e2eba528be61abdd1110..f107c5e1e9230059651be45c50a275d3616cd516 100644
--- a/router/java/src/net/i2p/router/StatisticsManager.java
+++ b/router/java/src/net/i2p/router/StatisticsManager.java
@@ -87,9 +87,14 @@ public class StatisticsManager implements Service {
         
         if (_includePeerRankings) {
             long publishedUptime = _context.router().getUptime();
+            boolean commentOutIn074 = RouterVersion.VERSION.equals("0.7.3");
             // Don't publish these for first hour
-            if (publishedUptime > 60*60*1000)
-                includeThroughput(stats);
+            if (publishedUptime > 62*60*1000) {
+                if (commentOutIn074)
+                    includeThroughput(stats);
+                else
+                    includeAverageThroughput(stats);
+            }
             //includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
             //includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 });
             //includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 });
@@ -223,16 +228,26 @@ public class StatisticsManager implements Service {
         return buf.toString();
     }
 
+    /* report the same data for tx and rx, for enhanced anonymity */
+    private void includeAverageThroughput(Properties stats) {
+        RateStat sendRate = _context.statManager().getRate("bw.sendRate");
+        RateStat recvRate = _context.statManager().getRate("bw.recvRate");
+        if (sendRate == null || recvRate == null)
+            return;
+        Rate s = sendRate.getRate(60*60*1000);
+        Rate r = recvRate.getRate(60*60*1000);
+        if (s == null || r == null)
+            return;
+        double speed = (s.getAverageValue() + r.getAverageValue()) / 2;
+        double max = Math.max(s.getExtremeAverageValue(), r.getExtremeAverageValue());
+        String str = num(speed) + ';' + num(max) + ";0;0;";
+        stats.setProperty("stat_bandwidthSendBps.60m", str);
+        stats.setProperty("stat_bandwidthReceiveBps.60m", str);
+    }
+
     private void includeThroughput(Properties stats) {
         RateStat sendRate = _context.statManager().getRate("bw.sendRate");
         if (sendRate != null) {
-            /****
-            if (_context.router().getUptime() > 5*60*1000) {
-                Rate r = sendRate.getRate(5*60*1000);
-                if (r != null)
-                    stats.setProperty("stat_bandwidthSendBps.5m", num(r.getAverageValue()) + ';' + num(r.getExtremeAverageValue()) + ";0;0;");
-            }
-            ****/
             if (_context.router().getUptime() > 60*60*1000) { 
                 Rate r = sendRate.getRate(60*60*1000);
                 if (r != null)
@@ -242,13 +257,6 @@ public class StatisticsManager implements Service {
         
         RateStat recvRate = _context.statManager().getRate("bw.recvRate");
         if (recvRate != null) {
-            /****
-            if (_context.router().getUptime() > 5*60*1000) {
-                Rate r = recvRate.getRate(5*60*1000);
-                if (r != null)
-                    stats.setProperty("stat_bandwidthReceiveBps.5m", num(r.getAverageValue()) + ';' + num(r.getExtremeAverageValue()) + ";0;0;");
-            }
-            ****/
             if (_context.router().getUptime() > 60*60*1000) {
                 Rate r = recvRate.getRate(60*60*1000);
                 if (r != null)
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlySearchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlySearchJob.java
index e5b5e962d6b076a2bde7f651b3f8ca08aef6661f..b6fec178cfeed2e0ed16a9a91bb3bd479d496c73 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlySearchJob.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodOnlySearchJob.java
@@ -100,8 +100,10 @@ class FloodOnlySearchJob extends FloodSearchJob {
         if (floodfillPeers.size() <= 3)
             _shouldProcessDSRM = true;
         if (floodfillPeers.size() <= 0) {
-            if (_log.shouldLog(Log.ERROR))
-                _log.error("Running netDb searches against the floodfill peers, but we don't know any");
+            // ask anybody, they may not return the answer but they will return a few ff peers we can go look up,
+            // so this situation should be temporary
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("Running netDb searches against the floodfill peers, but we don't know any");
             floodfillPeers = new ArrayList(_facade.getAllRouters());
             if (floodfillPeers.size() <= 0) {
                 if (_log.shouldLog(Log.ERROR))
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java
index 8c40d117b9842b434f6c1de677c1ec2aa6710f36..24c0350f92361ca0d4678dab76024132178cc125 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/SingleLookupJob.java
@@ -8,6 +8,12 @@ import net.i2p.util.Log;
 
 /**
  * Ask the peer who sent us the DSRM for the RouterInfos.
+ *
+ * If we have the routerInfo already, try to refetch it from that router itself,
+ * if we aren't already connected to that router,
+ * which will help us establish that router as a good floodfill and speed our
+ * integration into the network.
+ *
  * A simple version of SearchReplyJob in SearchJob.java.
  * Skip the profile updates - this should be rare.
  *
@@ -28,6 +34,8 @@ class SingleLookupJob extends JobImpl {
                 continue;
             if (getContext().netDb().lookupRouterInfoLocally(peer) == null)
                 getContext().jobQueue().addJob(new SingleSearchJob(getContext(), peer, from));
+            else if (!getContext().commSystem().isEstablished(peer))
+                getContext().jobQueue().addJob(new SingleSearchJob(getContext(), peer, peer));
         }
     }
     public String getName() { return "NetDb process DSRM"; }
diff --git a/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java b/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java
index 693df45b181d41b676ca49d37ad16b813df36527..b24d79a11c76d9de4c3880803b425f49b086ed6c 100644
--- a/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java
+++ b/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java
@@ -34,8 +34,14 @@ public class FIFOBandwidthRefiller implements Runnable {
     //public static final String PROP_REPLENISH_FREQUENCY = "i2np.bandwidth.replenishFrequencyMs";
 
     // no longer allow unlimited bandwidth - the user must specify a value, else use defaults below (KBps)
-    public static final int DEFAULT_INBOUND_BANDWIDTH = 64;
-    public static final int DEFAULT_OUTBOUND_BANDWIDTH = 32;
+    public static final int DEFAULT_INBOUND_BANDWIDTH = 96;
+    /**
+     *  Caution, do not make DEFAULT_OUTBOUND_BANDWIDTH * DEFAULT_SHARE_PCT > 32
+     *  without thinking about the implications (default connection limits, for example)
+     *  of moving the default bandwidth class from L to M, or maybe
+     *  adjusting bandwidth class boundaries.
+     */
+    public static final int DEFAULT_OUTBOUND_BANDWIDTH = 40;
     public static final int DEFAULT_INBOUND_BURST_BANDWIDTH = 80;
     public static final int DEFAULT_OUTBOUND_BURST_BANDWIDTH = 40;