diff --git a/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandshake.java b/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandshake.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb69b044d284a7414f74b3e58a0b5773fd1c8419
--- /dev/null
+++ b/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandshake.java
@@ -0,0 +1,36 @@
+package org.klomp.snark;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.klomp.snark.bencode.BEncoder;
+import org.klomp.snark.bencode.BEValue;
+
+/**
+ * REF: BEP 10 Extension Protocol
+ * @since 0.8.2
+ */
+class ExtensionHandshake {
+
+    private static final byte[] _payload = buildPayload();
+
+  /**
+   *  @return bencoded data
+   */
+    static byte[] getPayload() {
+        return _payload;
+    }
+
+    /** just a test for now */
+    private static byte[] buildPayload() {
+        Map<String, Object> handshake = new HashMap();
+        Map<String, Integer> m = new HashMap();
+        m.put("foo", Integer.valueOf(99));
+        m.put("bar", Integer.valueOf(101));
+        handshake.put("m", m);
+        handshake.put("p", Integer.valueOf(6881));
+        handshake.put("v", "I2PSnark");
+        handshake.put("reqq", Integer.valueOf(5));
+        return BEncoder.bencode(handshake);
+    }
+}
diff --git a/apps/i2psnark/java/src/org/klomp/snark/Peer.java b/apps/i2psnark/java/src/org/klomp/snark/Peer.java
index 257c5ff9a2c7d5fa8ac8f284dbb628b94eb6b3a3..d921f12e82b1f87e190b87e1f5ad0e88f3663be5 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/Peer.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/Peer.java
@@ -66,6 +66,7 @@ public class Peer implements Comparable
   private long options;
 
   /**
+   * Outgoing connection.
    * Creates a disconnected peer given a PeerID, your own id and the
    * relevant MetaInfo.
    */
@@ -80,6 +81,7 @@ public class Peer implements Comparable
   }
 
   /**
+   * Incoming connection.
    * Creates a unconnected peer from the input and output stream got
    * from the socket. Note that the complete handshake (which can take
    * some time or block indefinitely) is done in the calling Thread to
@@ -201,6 +203,7 @@ public class Peer implements Comparable
         // Do we need to handshake?
         if (din == null)
           {
+            // Outgoing connection
             sock = util.connect(peerID);
             if (_log.shouldLog(Log.DEBUG))
                 _log.debug("Connected to " + peerID + ": " + sock);
@@ -234,6 +237,7 @@ public class Peer implements Comparable
                                     + PeerID.idencode(expected_id) + "'");
             }
           } else {
+            // Incoming connection
             if (_log.shouldLog(Log.DEBUG))
                 _log.debug("Already have din [" + sock + "] with " + toString());
           }
@@ -242,6 +246,12 @@ public class Peer implements Comparable
         PeerConnectionOut out = new PeerConnectionOut(this, dout);
         PeerState s = new PeerState(this, listener, metainfo, in, out);
         
+        if ((options & OPTION_EXTENSION) != 0) {
+            if (_log.shouldLog(Log.DEBUG))
+                _log.debug("Peer supports extensions, sending test message");
+            out.sendExtension(0, ExtensionHandshake.getPayload());
+        }
+
         // Send our bitmap
         if (bitfield != null)
           s.out.sendBitfield(bitfield);
@@ -331,12 +341,10 @@ public class Peer implements Comparable
     if (_log.shouldLog(Log.DEBUG))
         _log.debug("Read the remote side's hash and peerID fully from " + toString());
 
-//  if ((options & OPTION_EXTENSION) != 0) {
     if (options != 0) {
         // send them something
         if (_log.shouldLog(Log.DEBUG))
-            //_log.debug("Peer supports extension message, what should we say? " + toString());
-            _log.debug("Peer supports options 0x" + Long.toString(options, 16) + ", what should we say? " + toString());
+            _log.debug("Peer supports options 0x" + Long.toString(options, 16) + ": " + toString());
     }
 
     return bs;
diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java
index 289822df82495caa73dadad73b87f8fb0c051816..aa9cf2187db0d855dd306199125d939f710ef64d 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java
@@ -114,8 +114,9 @@ class PeerCheckerTask extends TimerTask
 
             // Choke a percentage of them rather than all so it isn't so drastic...
             // unless this torrent is over the limit all by itself.
+            // choke 5/8 of the time when seeding and 3/8 when leeching
             boolean overBWLimitChoke = upload > 0 &&
-                                       ((overBWLimit && random.nextBoolean()) ||
+                                       ((overBWLimit && (random.nextInt(8) > (coordinator.completed() ? 2 : 4))) ||
                                         (coordinator.overUpBWLimit(uploaded)));
 
             // If we are at our max uploaders and we have lots of other
diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
index 12e291ea89b1c9d36a6e67cfd871eccf2fadbaa0..0967f24616646563c0f121583728c1c5dcf0a2fd 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
@@ -615,13 +615,13 @@ public class PeerCoordinator implements PeerListener
                 // share blocks rather than starting from 0 with each peer.
                 // This is where the flaws of the snark data model are really exposed.
                 // Could also randomize within the duplicate set rather than strict rarest-first
-                if (_log.shouldLog(Log.DEBUG))
-                    _log.debug("parallel request (end game?) for " + peer + ": piece = " + piece);
+                if (_log.shouldLog(Log.INFO))
+                    _log.info("parallel request (end game?) for " + peer + ": piece = " + piece);
             }
         }
         if (record) {
-            if (_log.shouldLog(Log.DEBUG))
-                _log.debug("Now requesting: piece " + piece + " priority " + piece.getPriority());
+            if (_log.shouldLog(Log.INFO))
+                _log.info(peer + " is now requesting: piece " + piece + " priority " + piece.getPriority());
             piece.setRequested(true);
         }
         return piece.getId();
@@ -945,11 +945,11 @@ public class PeerCoordinator implements PeerListener
               PartialPiece pp = iter.next();
               int savedPiece = pp.getPiece();
               if (havePieces.get(savedPiece)) {
+                 iter.remove();
                  // this is just a double-check, it should be in there
                  for(Piece piece : wantedPieces) {
                      if (piece.getId() == savedPiece) {
                          piece.setRequested(true);
-                         iter.remove();
                          if (_log.shouldLog(Log.INFO)) {
                              _log.info("Restoring orphaned partial piece " + pp +
                                        " Partial list size now: " + partialPieces.size());
@@ -957,8 +957,12 @@ public class PeerCoordinator implements PeerListener
                          return pp;
                       }
                   }
+                  if (_log.shouldLog(Log.WARN))
+                      _log.warn("Partial piece " + pp + " NOT in wantedPieces??");
               }
           }
+          if (_log.shouldLog(Log.WARN) && !partialPieces.isEmpty())
+              _log.warn("Peer " + peer + " has none of our partials " + partialPieces);
       }
       // ...and this section turns this into the general move-requests-around code!
       // Temporary? So PeerState never calls wantPiece() directly for now...
@@ -1004,7 +1008,7 @@ public class PeerCoordinator implements PeerListener
               }
           }
       }
-      return wantPiece(peer, havePieces, false) > 0;
+      return wantPiece(peer, havePieces, false) >= 0;
   }
 
   /**
diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java
index d32dc8ae52f171eed7e1960ba467152bf5df9226..38ed62029d88164a2e84d292ee920ea8f002f145 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java
@@ -609,6 +609,9 @@ class PeerState implements DataLoader
    */
   synchronized void addRequest()
   {
+    // no bitfield yet? nothing to request then.
+    if (bitfield == null)
+        return;
     boolean more_pieces = true;
     while (more_pieces)
       {