diff --git a/core/java/src/net/i2p/crypto/AESEngine.java b/core/java/src/net/i2p/crypto/AESEngine.java
index 1cdfcff16b8aa9315f746d7eddc83491f1abd02d..c90453a37f2e4f51b46ef11829e5831589786bda 100644
--- a/core/java/src/net/i2p/crypto/AESEngine.java
+++ b/core/java/src/net/i2p/crypto/AESEngine.java
@@ -31,6 +31,8 @@ public class AESEngine {
     public AESEngine(I2PAppContext ctx) {
         _context = ctx;
         _log = _context.logManager().getLog(AESEngine.class);
+        if (getClass() == AESEngine.class)
+            _log.warn("Warning: AES is disabled");
     }
     
     /** Encrypt the payload with the session key
@@ -44,7 +46,6 @@ public class AESEngine {
             || (initializationVector.length != 16)) return null;
 
         byte cyphertext[] = new byte[payload.length + (16 - (payload.length % 16))];
-        _log.warn("Warning: AES is disabled");
         System.arraycopy(payload, 0, cyphertext, 0, payload.length);
         return cyphertext;
     }
diff --git a/core/java/src/net/i2p/crypto/DummyElGamalEngine.java b/core/java/src/net/i2p/crypto/DummyElGamalEngine.java
index 8a6376a50c4e073c9f4c91621fb0da7519847265..780288f3f8f0e9b03a33bd6b7beba9fb3025fe5b 100644
--- a/core/java/src/net/i2p/crypto/DummyElGamalEngine.java
+++ b/core/java/src/net/i2p/crypto/DummyElGamalEngine.java
@@ -25,7 +25,7 @@ import net.i2p.I2PAppContext;
  * @author jrandom
  */
 public class DummyElGamalEngine extends ElGamalEngine {
-    private final static Log _log = new Log(DummyElGamalEngine.class);
+    private Log _log;
 
     /** 
      * The ElGamal engine should only be constructed and accessed through the 
@@ -35,6 +35,7 @@ public class DummyElGamalEngine extends ElGamalEngine {
      */
     public DummyElGamalEngine(I2PAppContext context) {
         super(context);
+        _log = context.logManager().getLog(DummyElGamalEngine.class);
         _log.log(Log.CRIT, "Dummy ElGamal engine in use!  NO DATA SECURITY.  Danger Will Robinson, Danger!",
                  new Exception("I really hope you know what you're doing"));
     }
@@ -93,11 +94,13 @@ public class DummyElGamalEngine extends ElGamalEngine {
         }
         Hash calcHash = SHA256Generator.getInstance().calculateHash(rv);
         if (calcHash.equals(hash)) {
-            _log.debug("Hash matches: " + DataHelper.toString(hash.getData(), hash.getData().length));
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Hash matches: " + DataHelper.toString(hash.getData(), hash.getData().length));
             return rv;
         } else {
-            _log.debug("Doesn't match hash [calc=" + calcHash + " sent hash=" + hash + "]\ndata = " + new String(rv),
-                       new Exception("Doesn't match"));
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Doesn't match hash [calc=" + calcHash + " sent hash=" + hash + "]\ndata = " + new String(rv),
+                           new Exception("Doesn't match"));
             return null;
         }
     }
diff --git a/core/java/src/net/i2p/data/Hash.java b/core/java/src/net/i2p/data/Hash.java
index 30588551892398e2f5910d6f294b0b1bdb6145d6..8c7c3df77751a883faa1536e5f066d9542c496d6 100644
--- a/core/java/src/net/i2p/data/Hash.java
+++ b/core/java/src/net/i2p/data/Hash.java
@@ -25,6 +25,7 @@ public class Hash extends DataStructureImpl {
     private final static Log _log = new Log(Hash.class);
     private byte[] _data;
     private volatile String _stringified;
+    private volatile String _base64ed;
 
     public final static int HASH_LENGTH = 32;
     public final static Hash FAKE_HASH = new Hash(new byte[HASH_LENGTH]);
@@ -44,11 +45,13 @@ public class Hash extends DataStructureImpl {
     public void setData(byte[] data) {
         _data = data;
         _stringified = null;
+        _base64ed = null;
     }
 
     public void readBytes(InputStream in) throws DataFormatException, IOException {
         _data = new byte[HASH_LENGTH];
         _stringified = null;
+        _base64ed = null;
         int read = read(in, _data);
         if (read != HASH_LENGTH) throw new DataFormatException("Not enough bytes to read the hash");
     }
@@ -82,4 +85,11 @@ public class Hash extends DataStructureImpl {
         }
         return _stringified;
     }
+    
+    public String toBase64() {
+        if (_base64ed == null) {
+            _base64ed = super.toBase64();
+        }
+        return _base64ed;
+    }
 }
\ No newline at end of file
diff --git a/core/java/src/net/i2p/util/I2PThread.java b/core/java/src/net/i2p/util/I2PThread.java
index 4efb27de9d9c52b45a5bdca34c2744ac0d7d67f4..804ab05d39f53988b6b090bf2782451c3157b3ee 100644
--- a/core/java/src/net/i2p/util/I2PThread.java
+++ b/core/java/src/net/i2p/util/I2PThread.java
@@ -9,6 +9,11 @@ package net.i2p.util;
  *
  */
 
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+
 /**
  * In case its useful later...
  * (e.g. w/ native programatic thread dumping, etc)
@@ -16,7 +21,7 @@ package net.i2p.util;
  */
 public class I2PThread extends Thread {
     private static Log _log;
-    private static OOMEventListener _lsnr;
+    private static Set _listeners = new HashSet(4);
 
     public I2PThread() {
         super();
@@ -38,19 +43,29 @@ public class I2PThread extends Thread {
         try {
             super.run();
         } catch (Throwable t) {
-            if ((t instanceof OutOfMemoryError) && (_lsnr != null)) _lsnr.outOfMemory((OutOfMemoryError) t);
+            if (t instanceof OutOfMemoryError)
+                fireOOM((OutOfMemoryError)t);
             // we cant assume log is created
             if (_log == null) _log = new Log(I2PThread.class);
             _log.log(Log.CRIT, "Killing thread " + getName(), t);
         }
     }
+    
+    private void fireOOM(OutOfMemoryError oom) {
+        for (Iterator iter = _listeners.iterator(); iter.hasNext(); ) {
+            OOMEventListener listener = (OOMEventListener)iter.next();
+            listener.outOfMemory(oom);
+        }
+    }
 
-    public static void setOOMEventListener(OOMEventListener lsnr) {
-        _lsnr = lsnr;
+    /** register a new component that wants notification of OOM events */
+    public static void addOOMEventListener(OOMEventListener lsnr) {
+        _listeners.add(lsnr);
     }
 
-    public static OOMEventListener getOOMEventListener() {
-        return _lsnr;
+    /** unregister a component that wants notification of OOM events */    
+    public static void removeOOMEventListener(OOMEventListener lsnr) {
+        _listeners.remove(lsnr);
     }
 
     public interface OOMEventListener {
diff --git a/core/java/src/net/i2p/util/LogManager.java b/core/java/src/net/i2p/util/LogManager.java
index 5357f37a6ea5dcb8bcb701dcca5fcdeb4bec47f2..6277fce8dd8f61462012885fac6f4873d4c6d5a7 100644
--- a/core/java/src/net/i2p/util/LogManager.java
+++ b/core/java/src/net/i2p/util/LogManager.java
@@ -269,6 +269,9 @@ public class LogManager {
             _consoleBufferSize = DEFAULT_CONSOLEBUFFERSIZE;
         }
 
+        if (_log.shouldLog(Log.DEBUG))
+            _log.debug("Log set to use the base log file as " + _baseLogfilename);
+        
         parseLimits(config);
     }