Added Closure.js.  Put expressInterest in NDN.js.  Use it in ccnxProtocolService.js.
diff --git a/js/ccnxProtocol/modules/make-ndn-js.jsm.sh b/js/ccnxProtocol/modules/make-ndn-js.jsm.sh
index 2c4209b..27749e3 100755
--- a/js/ccnxProtocol/modules/make-ndn-js.jsm.sh
+++ b/js/ccnxProtocol/modules/make-ndn-js.jsm.sh
@@ -1,5 +1,6 @@
 #!/bin/sh
 cat ndn-js-header.txt \
+  ../../Closure.js emptyLine.txt \
   ../../NDN.js emptyLine.txt \
   ../../NDNSocketTransportService.js emptyLine.txt \
   ../../util/CCNProtocolDTags.js emptyLine.txt \
diff --git a/js/ccnxProtocol/modules/ndn-js-header.txt b/js/ccnxProtocol/modules/ndn-js-header.txt
index 63c037c..967f9e2 100644
--- a/js/ccnxProtocol/modules/ndn-js-header.txt
+++ b/js/ccnxProtocol/modules/ndn-js-header.txt
@@ -5,7 +5,7 @@
  * See COPYING for copyright and distribution information.
  */
 
-var EXPORTED_SYMBOLS = ["NDN", "DataUtils", "readAllFromSocket"];
+var EXPORTED_SYMBOLS = ["NDN", "Closure", "Name", "Interest", "ContentObject", "DataUtils"];
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/NetUtil.jsm");
diff --git a/js/ccnxProtocol/modules/ndn-js.jsm b/js/ccnxProtocol/modules/ndn-js.jsm
index e5f2837..a432819 100644
--- a/js/ccnxProtocol/modules/ndn-js.jsm
+++ b/js/ccnxProtocol/modules/ndn-js.jsm
@@ -5,7 +5,7 @@
  * See COPYING for copyright and distribution information.
  */
 
-var EXPORTED_SYMBOLS = ["NDN", "DataUtils", "readAllFromSocket"];
+var EXPORTED_SYMBOLS = ["NDN", "Closure", "Name", "Interest", "ContentObject", "DataUtils"];
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/NetUtil.jsm");
@@ -25,6 +25,69 @@
     }
 };
 
+/* 
+ * @author: ucla-cs
+ * See COPYING for copyright and distribution information.
+ * Provide the callback closure for the async communication methods in the NDN class.
+ * This is a port of Closure.py from PyCCN, written by: 
+ * Derek Kulinski <takeda@takeda.tk>
+ * Jeff Burke <jburke@ucla.edu>
+ */
+
+/*
+ * Create a subclass of Closure and pass an object to async calls.
+ */
+var Closure = function Closure() {
+	// I don't think storing NDN's closure is needed
+	// and it creates a reference loop, as of now both
+	// of those variables are never set -- Derek
+	//
+	// Use instance variables to return data to callback
+	this.ndn_data = null;  // this holds the ndn_closure
+    this.ndn_data_dirty = false;
+};
+
+// Upcall result
+Closure.RESULT_ERR               = -1; // upcall detected an error
+Closure.RESULT_OK                =  0; // normal upcall return
+Closure.RESULT_REEXPRESS         =  1; // reexpress the same interest again
+Closure.RESULT_INTEREST_CONSUMED =  2; // upcall claims to consume interest
+Closure.RESULT_VERIFY            =  3; // force an unverified result to be verified
+
+// Upcall kind
+Closure.UPCALL_FINAL              = 0; // handler is about to be deregistered
+Closure.UPCALL_INTEREST           = 1; // incoming interest
+Closure.UPCALL_CONSUMED_INTEREST  = 2; // incoming interest, someone has answered
+Closure.UPCALL_CONTENT            = 3; // incoming verified content
+Closure.UPCALL_INTEREST_TIMED_OUT = 4; // interest timed out
+Closure.UPCALL_CONTENT_UNVERIFIED = 5; // content that has not been verified
+Closure.UPCALL_CONTENT_BAD        = 6; // verification failed
+
+/*
+ * Override this in your subclass.
+ * If you're getting strange errors in upcall()
+ * check your code whether you're returning a value.
+ */
+Closure.prototype.upcall = function(kind, upcallInfo) {
+	//dump('upcall ' + this + " " + kind + " " + upcallInfo + "\n");
+	return Closure.RESULT_OK;
+};
+
+var UpcallInfo = function UpcallInfo(ndn, interest, matchedComps, contentObject) {
+	this.ndn = ndn;  // NDN object (not used)
+	this.interest = interest;  // Interest object
+	this.matchedComps = matchedComps;  // int
+	this.contentObject = contentObject;  // Content object
+};
+
+UpcallInfo.prototype.toString = function() {
+	var ret = "ndn = " + this.ndn;
+	ret += "\nInterest = " + this.interest;
+	ret += "\nmatchedComps = " + this.matchedComps;
+	ret += "\nContentObject: " + this.contentObject;
+	return ret;
+}
+
 /*
  * @author: ucla-cs
  * See COPYING for copyright and distribution information.
@@ -99,7 +162,6 @@
 
 }
 
-
 NDN.prototype.put = function(name,content){
 	if(this.host!=null && this.port!=null){
 		
@@ -176,16 +238,64 @@
 	return result;
 	}
 	else{
-
-		
 		console.log('ERROR URL OR PORT NOT SET');
 
 		return null;
-
 	}
-	
-
 }
+
+/** Encode name as an Interest. If template is not null, use its attributes.
+ *  Send the interest to host:port, read the entire response and call
+ *  closure.upcall(Closure.UPCALL_CONTENT (or Closure.UPCALL_CONTENT_UNVERIFIED),
+ *                 new UpcallInfo(this, interest, 0, contentObject)).
+ */
+NDN.prototype.expressInterest = function(
+        // Name
+        name,
+        // Closure
+        closure,
+        // Interest
+        template) {
+	if (this.host == null || this.port == null) {
+		dump('ERROR host OR port NOT SET\n');
+        return;
+    }
+    
+	interest = new Interest(name);
+    if (template != null) {
+        // TODO: Exactly what do we copy from template?
+        interest.InterestLifetime = template.InterestLifetime;
+    }
+    else
+        interest.InterestLifetime = 4200;
+	var outputHex = encodeToHexInterest(interest);
+		
+	var dataListener = {
+		onReceivedData : function(result) {
+			if (result == null || result == undefined || result.length == 0)
+				listener.onReceivedContentObject(null);
+			else {
+                var decoder = new BinaryXMLDecoder(result);	
+                var co = new ContentObject();
+                co.from_ccnb(decoder);
+                   					
+				if(LOG>2) {
+					dump('DECODED CONTENT OBJECT\n');
+					dump(co);
+					dump('\n');
+				}
+					
+                // TODO: verify the content object and set kind to UPCALL_CONTENT.
+				closure.upcall(Closure.UPCALL_CONTENT_UNVERIFIED,
+                   new UpcallInfo(this, interest, 0, co))
+			}
+		}
+	}
+        
+	return getAsync(this.host, this.port, outputHex, dataListener);
+};
+
+
 /* 
  * @author: ucla-cs
  * See COPYING for copyright and distribution information.
@@ -251,7 +361,7 @@
                     // Finish.
                     this.onStopRequest();
 			} catch (ex) {
-				dump("onDataAvailable exception: " + ex + "\n");
+				dump("readAllFromSocket.onDataAvailable exception: " + ex + "\n");
 			}
 		}
     };
@@ -260,53 +370,6 @@
     pump.asyncRead(dataListener, null);
 }
 
-
-// TODO: This should be moved to the main NDN.js when we agree on how to do non-blocking get.
-// For now, assume this is included after NDN.js and modify it.
-/** Encode message as an Interest, send it to host:port, read the entire response and call
-      listener.onReceivedContentObject(contentObject).
- */
-NDN.prototype.getAsync = function(message, listener) {
-	if (this.host != null && this.port != null) {
-		var output ='';
-		message = message.trim();
-		if(message==null || message =="" ){
-			dump('INVALID INPUT TO GET\n');
-			return null;
-		}
-		
-		interest = new Interest(new Name(message));
-		interest.InterestLifetime = 4200;
-		var outputHex = encodeToHexInterest(interest);
-		
-		var dataListener = {
-			onReceivedData : function(result) {
-				if (result == null || result == undefined || result.length == 0)
-					listener.onReceivedContentObject(null);
-				else {
-                    var decoder = new BinaryXMLDecoder(result);	
-                    var co = new ContentObject();
-                    co.from_ccnb(decoder);
-					
-					if(LOG>2) {
-						dump('DECODED CONTENT OBJECT\n');
-						dump(co);
-						dump('\n');
-					}
-					
-					listener.onReceivedContentObject(co);
-				}
-			}
-		}
-        
-		return getAsync(this.host, this.port, outputHex, dataListener);
-	}
-	else {
-		dump('ERROR host OR port NOT SET\n');
-	}
-}
-
-
 /*
  * @author: ucla-cs
  * See COPYING for copyright and distribution information.
@@ -4005,6 +4068,10 @@
 	    
 	    output+= "<br />";
 	}
+	if(co.signedInfo !=null && co.signedInfo.finalBlockID!=null){
+	    output += "FinalBlockID: "+ DataUtils.toHex(co.signedInfo.finalBlockID);
+	    output+= "<br />";
+	}
 	if(co.signedInfo!=null && co.signedInfo.locator!=null && co.signedInfo.locator.certificate!=null){
 	    var tmp = DataUtils.toString(co.signedInfo.locator.certificate);
 	    var publickey = rstr2b64(tmp);