Major updates to change default behavior of NDN to connect to a random host on the testbed.
Make expressInterest and registerPrefix connect when needed.  Removed WebSocketTransport.connectWebSocket.
Also, don't fetch the ccndid until registerPrefix needs it.
diff --git a/js/tools/build/ndn-js-uncomp.js b/js/tools/build/ndn-js-uncomp.js
index b2ec4d4..a6c2c4d 100644
--- a/js/tools/build/ndn-js-uncomp.js
+++ b/js/tools/build/ndn-js-uncomp.js
@@ -70,6 +70,8 @@
 
 var WebSocketTransport = function WebSocketTransport() {    
 	this.ws = null;
+    this.connectedHost = null;
+    this.connectedPort = null;
     this.elementReader = null;
     this.defaultGetHostAndPort = NDN.makeShuffledGetHostAndPort
         (["A.ws.ndn.ucla.edu", "B.ws.ndn.ucla.edu", "C.ws.ndn.ucla.edu", "D.ws.ndn.ucla.edu", 
@@ -77,12 +79,14 @@
          9696);
 };
 
-WebSocketTransport.prototype.connectWebSocket = function(ndn) {
+WebSocketTransport.prototype.connect = function(ndn, onopenCallback) {
 	if (this.ws != null)
 		delete this.ws;
 	
 	this.ws = new WebSocket('ws://' + ndn.host + ':' + ndn.port);
 	if (LOG > 0) console.log('ws connection created.');
+    this.connectedHost = ndn.host;
+    this.connectedPort = ndn.port;
 	
 	this.ws.binaryType = "arraybuffer";
 	
@@ -113,11 +117,9 @@
 		if (LOG > 3) console.log(ev);
 		if (LOG > 3) console.log('ws.onopen: WebSocket connection opened.');
 		if (LOG > 3) console.log('ws.onopen: ReadyState: ' + this.readyState);
-
-		// Fetch ccndid now
-		var interest = new Interest(NDN.ccndIdFetcher);
-		interest.interestLifetime = 4000; // milliseconds
-        self.send(encodeToBinaryInterest(interest));
+        // NDN.registerPrefix will fetch the ccndid when needed.
+        
+        onopenCallback();
 	}
 	
 	this.ws.onerror = function(ev) {
@@ -159,11 +161,15 @@
 }
 
 WebSocketTransport.prototype.expressInterest = function(ndn, interest, closure) {
-    if (ndn.readyStatus != NDN.OPENED) {
-		console.log('Connection is not established.');
-        return;
+    if (this.ws == null || this.connectedHost != ndn.host || this.connectedPort != ndn.port) {
+        var self = this;
+        this.connect(ndn, function() { self.expressInterestHelper(ndn, interest, closure); });
     }
-    
+    else
+        this.expressInterestHelper(ndn, interest, closure);
+};
+
+WebSocketTransport.prototype.expressInterestHelper = function(ndn, interest, closure) {
 	//TODO: check local content store first
 	if (closure != null) {
 		var pitEntry = new PITEntry(interest, closure);
@@ -194,7 +200,6 @@
 
 	this.send(encodeToBinaryInterest(interest));
 };
-
 /**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
@@ -7512,7 +7517,7 @@
  * {
  *   getTransport: function() { return new WebSocketTransport(); }
  *   getHostAndPort: transport.defaultGetHostAndPort,
- *   host: 'localhost', // If null, use getHostAndPort when connecting.
+ *   host: null, // If null, use getHostAndPort when connecting.
  *   port: 9696,
  *   onopen: function() { if (LOG > 3) console.log("NDN connection established."); }
  *   onclose: function() { if (LOG > 3) console.log("NDN connection closed."); }
@@ -7526,7 +7531,7 @@
     var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
     this.transport = getTransport();
     this.getHostAndPort = (settings.getHostAndPort || this.transport.defaultGetHostAndPort);
-	this.host = (settings.host !== undefined ? settings.host : 'localhost');
+	this.host = (settings.host !== undefined ? settings.host : null);
 	this.port = (settings.port || 9696);
     this.readyStatus = NDN.UNOPEN;
     this.verify = (settings.verify !== undefined ? settings.verify : true);
@@ -7677,16 +7682,74 @@
 };
 
 NDN.prototype.registerPrefix = function(name, closure, flag) {
-    if (this.readyStatus != NDN.OPENED) {
-		console.log('Connection is not established.');
-        return -1;
-    }
+    var thisNDN = this;
+    var onConnected = function() {
+    	if (thisNDN.ccndid == null) {
+            // Fetch ccndid first, then register.
+            var interest = new Interest(NDN.ccndIdFetcher);
+    		interest.interestLifetime = 4000; // milliseconds
+            if (LOG>3) console.log('Expressing interest for ccndid from ccnd.');
+            thisNDN.transport.expressInterest
+               (thisNDN, interest, new NDN.FetchCcndidClosure(thisNDN, name, closure, flag));
+        }
+        else	
+            thisNDN.registerPrefixHelper(name, closure, flag);
+    };
 
-	if (this.ccndid == null) {
-		console.log('ccnd node ID unkonwn. Cannot register prefix.');
-		return -1;
+	if (this.host == null || this.port == null) {
+        if (this.getHostAndPort == null)
+            console.log('ERROR: host OR port NOT SET');
+        else
+            this.connectAndExecute(onConnected);
+    }
+    else
+        onConnected();
+};
+
+/*
+ * This is a closure to receive the ContentObject for NDN.ccndIdFetcher and call
+ *   registerPrefixHelper(name, callerClosure, flag).
+ */
+NDN.FetchCcndidClosure = function FetchCcndidClosure(ndn, name, callerClosure, flag) {
+    // Inherit from Closure.
+    Closure.call(this);
+    
+    this.ndn = ndn;
+    this.name = name;
+    this.callerClosure = callerClosure;
+    this.flag = flag;
+};
+
+NDN.FetchCcndidClosure.prototype.upcall = function(kind, upcallInfo) {
+    if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
+        console.log("Timeout while requesting the ccndid.  Cannot registerPrefix for " +
+            this.name.to_uri() + " .");
+        return Closure.RESULT_OK;
+    }
+    if (!(kind == Closure.UPCALL_CONTENT ||
+          kind == Closure.UPCALL_CONTENT_UNVERIFIED))
+        // The upcall is not for us.
+        return Closure.RESULT_ERR;
+       
+    var co = upcallInfo.contentObject;
+    if (!co.signedInfo || !co.signedInfo.publisher 
+		|| !co.signedInfo.publisher.publisherPublicKeyDigest)
+        console.log
+          ("ContentObject doesn't have a publisherPublicKeyDigest. Cannot set ccndid and registerPrefix for "
+           + this.name.to_uri() + " .");
+    else {
+		if (LOG>3) console.log('Got ccndid from ccnd.');
+		this.ndn.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
+		if (LOG>3) console.log(this.ndn.ccndid);
+        
+        this.ndn.registerPrefixHelper(this.name, this.callerClosure, this.flag);
 	}
-		
+    
+    return Closure.RESULT_OK;
+};
+
+// Do the work of registerPrefix once we know we are connected with a ccndid.
+NDN.prototype.registerPrefixHelper = function(name, closure, flag) {
 	var fe = new ForwardingEntry('selfreg', name, null, null, 3, 2147483647);
 	var bytes = encodeForwardingEntry(fe);
 		
@@ -7709,8 +7772,6 @@
 	NDN.CSTable.push(csEntry);
     
     this.transport.send(encodeToBinaryInterest(interest));
-		
-	return 0;
 };
 
 /*
@@ -7744,154 +7805,132 @@
 		var co = new ContentObject();
 		co.from_ccnb(decoder);
 				
-		if (this.ccndid == null && NDN.ccndIdFetcher.match(co.name)) {
-			// We are in starting phase, record publisherPublicKeyDigest in ccndid
-			if(!co.signedInfo || !co.signedInfo.publisher 
-				|| !co.signedInfo.publisher.publisherPublicKeyDigest) {
-				console.log("Cannot contact router, close NDN now.");
+		var pitEntry = NDN.getEntryForExpressedInterest(co.name);
+		if (pitEntry != null) {
+			//console.log(pitEntry);
+			// Remove PIT entry from NDN.PITTable
+			var index = NDN.PITTable.indexOf(pitEntry);
+			if (index >= 0)
+				NDN.PITTable.splice(index, 1);
 						
-				// Close NDN if we fail to connect to a ccn router
-				this.readyStatus = NDN.CLOSED;
-				this.onclose();
-				//console.log("NDN.onclose event fired.");
-			} else {
-				if (LOG>3) console.log('Connected to ccnd.');
-				this.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
-				if (LOG>3) console.log(ndn.ccndid);
+			var currentClosure = pitEntry.closure;
 						
-				// Call NDN.onopen after success
-				this.readyStatus = NDN.OPENED;
-				this.onopen();
-				//console.log("NDN.onopen event fired.");
+			// Cancel interest timer
+			clearTimeout(pitEntry.timerID);
+			//console.log("Clear interest timer");
+			//console.log(currentClosure.timerID);
+				
+			if (this.verify == false) {
+				// Pass content up without verifying the signature
+				currentClosure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED, new UpcallInfo(this, null, 0, co));
+				return;
 			}
-		} else {
-			var pitEntry = NDN.getEntryForExpressedInterest(co.name);
-			if (pitEntry != null) {
-				//console.log(pitEntry);
-				// Remove PIT entry from NDN.PITTable
-				var index = NDN.PITTable.indexOf(pitEntry);
-				if (index >= 0)
-					NDN.PITTable.splice(index, 1);
-						
-				var currentClosure = pitEntry.closure;
-						
-				// Cancel interest timer
-				clearTimeout(pitEntry.timerID);
-				//console.log("Clear interest timer");
-				//console.log(currentClosure.timerID);
 				
-				if (this.verify == false) {
-					// Pass content up without verifying the signature
-					currentClosure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED, new UpcallInfo(this, null, 0, co));
-					return;
+			// Key verification
+						
+			// Recursive key fetching & verification closure
+			var KeyFetchClosure = function KeyFetchClosure(content, closure, key, sig, wit) {
+				this.contentObject = content;  // unverified content object
+				this.closure = closure;  // closure corresponding to the contentObject
+				this.keyName = key;  // name of current key to be fetched
+				this.sigHex = sig;  // hex signature string to be verified
+				this.witness = wit;
+						
+				Closure.call(this);
+			};
+						
+            var thisNDN = this;
+			KeyFetchClosure.prototype.upcall = function(kind, upcallInfo) {
+				if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
+					console.log("In KeyFetchClosure.upcall: interest time out.");
+					console.log(this.keyName.contentName.getName());
+				} else if (kind == Closure.UPCALL_CONTENT) {
+					//console.log("In KeyFetchClosure.upcall: signature verification passed");
+								
+					var rsakey = decodeSubjectPublicKeyInfo(upcallInfo.contentObject.content);
+					var verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, this.witness, this.sigHex);
+								
+					var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+					//console.log("raise encapsulated closure");
+					this.closure.upcall(flag, new UpcallInfo(thisNDN, null, 0, this.contentObject));
+								
+					// Store key in cache
+					var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
+					NDN.addKeyEntry(keyEntry);
+					//console.log(NDN.KeyStore);
+				} else if (kind == Closure.UPCALL_CONTENT_BAD) {
+					console.log("In KeyFetchClosure.upcall: signature verification failed");
 				}
-				
-				// Key verification
+			};
 						
-				// Recursive key fetching & verification closure
-				var KeyFetchClosure = function KeyFetchClosure(content, closure, key, sig, wit) {
-					this.contentObject = content;  // unverified content object
-					this.closure = closure;  // closure corresponding to the contentObject
-					this.keyName = key;  // name of current key to be fetched
-					this.sigHex = sig;  // hex signature string to be verified
-					this.witness = wit;
-						
-					Closure.call(this);
-				};
-						
-                var thisNdn = this;
-				KeyFetchClosure.prototype.upcall = function(kind, upcallInfo) {
-					if (kind == Closure.UPCALL_INTEREST_TIMED_OUT) {
-						console.log("In KeyFetchClosure.upcall: interest time out.");
-						console.log(this.keyName.contentName.getName());
-					} else if (kind == Closure.UPCALL_CONTENT) {
-						//console.log("In KeyFetchClosure.upcall: signature verification passed");
-								
-						var rsakey = decodeSubjectPublicKeyInfo(upcallInfo.contentObject.content);
-						var verified = rsakey.verifyByteArray(this.contentObject.rawSignatureData, this.witness, this.sigHex);
-								
-						var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
-						//console.log("raise encapsulated closure");
-						this.closure.upcall(flag, new UpcallInfo(thisNdn, null, 0, this.contentObject));
-								
-						// Store key in cache
-						var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
-						NDN.addKeyEntry(keyEntry);
-						//console.log(NDN.KeyStore);
-					} else if (kind == Closure.UPCALL_CONTENT_BAD) {
-						console.log("In KeyFetchClosure.upcall: signature verification failed");
-					}
-				};
-						
-				if (co.signedInfo && co.signedInfo.locator && co.signature) {
-					if (LOG > 3) console.log("Key verification...");
-					var sigHex = DataUtils.toHex(co.signature.signature).toLowerCase();
+			if (co.signedInfo && co.signedInfo.locator && co.signature) {
+				if (LOG > 3) console.log("Key verification...");
+				var sigHex = DataUtils.toHex(co.signature.signature).toLowerCase();
 							
-					var wit = null;
-					if (co.signature.Witness != null) {
-						wit = new Witness();
-						wit.decode(co.signature.Witness);
-					}
+				var wit = null;
+				if (co.signature.Witness != null) {
+					wit = new Witness();
+					wit.decode(co.signature.Witness);
+				}
 							
-					var keylocator = co.signedInfo.locator;
-					if (keylocator.type == KeyLocatorType.KEYNAME) {
-						if (LOG > 3) console.log("KeyLocator contains KEYNAME");
-						//var keyname = keylocator.keyName.contentName.getName();
-						//console.log(nameStr);
-						//console.log(keyname);
+				var keylocator = co.signedInfo.locator;
+				if (keylocator.type == KeyLocatorType.KEYNAME) {
+					if (LOG > 3) console.log("KeyLocator contains KEYNAME");
+					//var keyname = keylocator.keyName.contentName.getName();
+					//console.log(nameStr);
+					//console.log(keyname);
 								
-						if (keylocator.keyName.contentName.match(co.name)) {
-							if (LOG > 3) console.log("Content is key itself");
+					if (keylocator.keyName.contentName.match(co.name)) {
+						if (LOG > 3) console.log("Content is key itself");
 									
-							var rsakey = decodeSubjectPublicKeyInfo(co.content);
+						var rsakey = decodeSubjectPublicKeyInfo(co.content);
+						var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
+						var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+									
+						currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
+									
+						// SWT: We don't need to store key here since the same key will be
+						//      stored again in the closure.
+						//var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
+						//NDN.addKeyEntry(keyEntry);
+						//console.log(NDN.KeyStore);
+					} else {
+						// Check local key store
+						var keyEntry = NDN.getKeyByName(keylocator.keyName);
+						if (keyEntry) {
+							// Key found, verify now
+							if (LOG > 3) console.log("Local key cache hit");
+							var rsakey = keyEntry.rsaKey;
 							var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
 							var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
-									
-							currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
-									
-							// SWT: We don't need to store key here since the same key will be
-							//      stored again in the closure.
-							//var keyEntry = new KeyStoreEntry(keylocator.keyName, rsakey, new Date().getTime());
-							//NDN.addKeyEntry(keyEntry);
-							//console.log(NDN.KeyStore);
-						} else {
-							// Check local key store
-							var keyEntry = NDN.getKeyByName(keylocator.keyName);
-							if (keyEntry) {
-								// Key found, verify now
-								if (LOG > 3) console.log("Local key cache hit");
-								var rsakey = keyEntry.rsaKey;
-								var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
-								var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
 										
-								// Raise callback
-								currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
-							} else {
-								// Not found, fetch now
-								if (LOG > 3) console.log("Fetch key according to keylocator");
-								var nextClosure = new KeyFetchClosure(co, currentClosure, keylocator.keyName, sigHex, wit);
-								this.expressInterest(keylocator.keyName.contentName.getPrefix(4), nextClosure);
-							}
+							// Raise callback
+							currentClosure.upcall(flag, new UpcallInfo(this, null, 0, co));
+						} else {
+							// Not found, fetch now
+							if (LOG > 3) console.log("Fetch key according to keylocator");
+							var nextClosure = new KeyFetchClosure(co, currentClosure, keylocator.keyName, sigHex, wit);
+							this.expressInterest(keylocator.keyName.contentName.getPrefix(4), nextClosure);
 						}
-					} else if (keylocator.type == KeyLocatorType.KEY) {
-						if (LOG > 3) console.log("Keylocator contains KEY");
-								
-						var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
-						var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
-								
-						var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
-						// Raise callback
-						currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(this, null, 0, co));
-								
-						// Since KeyLocator does not contain key name for this key,
-						// we have no way to store it as a key entry in KeyStore.
-					} else {
-						var cert = keylocator.certificate;
-						console.log("KeyLocator contains CERT");
-						console.log(cert);
-								
-						// TODO: verify certificate
 					}
+				} else if (keylocator.type == KeyLocatorType.KEY) {
+					if (LOG > 3) console.log("Keylocator contains KEY");
+								
+					var rsakey = decodeSubjectPublicKeyInfo(co.signedInfo.locator.publicKey);
+					var verified = rsakey.verifyByteArray(co.rawSignatureData, wit, sigHex);
+							
+					var flag = (verified == true) ? Closure.UPCALL_CONTENT : Closure.UPCALL_CONTENT_BAD;
+					// Raise callback
+					currentClosure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(this, null, 0, co));
+								
+					// Since KeyLocator does not contain key name for this key,
+					// we have no way to store it as a key entry in KeyStore.
+				} else {
+					var cert = keylocator.certificate;
+					console.log("KeyLocator contains CERT");
+					console.log(cert);
+								
+					// TODO: verify certificate
 				}
 			}
 		}
@@ -7953,6 +7992,11 @@
         
     // The host is alive, so cancel the timeout and continue with onConnected().
     clearTimeout(this.timerID);
+
+    // Call NDN.onopen after success
+	this.ndn.readyStatus = NDN.OPENED;
+	this.ndn.onopen();
+
     this.onConnected();
 
     return Closure.RESULT_OK;