Support interestLifetime in from_ccnb and to_ccnb.  Updated test script to test all fields (except Exclude).
diff --git a/js/Interest.js b/js/Interest.js
index 7e6ddc4..5f7b285 100644
--- a/js/Interest.js
+++ b/js/Interest.js
@@ -16,9 +16,8 @@
 	this.childSelector = _childSelector;
 	this.answerOriginKind = _answerOriginKind;
 	this.scope = _scope;
-	this.interestLifetime = null;		// For now we don't have the ability to set an interest lifetime
-	this.nonce = _nonce;
-	
+	this.interestLifetime = _interestLifetime;  // number of seconds
+	this.nonce = _nonce;	
 
 	this.RECURSIVE_POSTFIX = "*";
 
@@ -40,16 +39,14 @@
 		this.name = new Name();
 		this.name.from_ccnb(decoder);
 
-		if (decoder.peekStartElement(CCNProtocolDTags.MinSuffixComponents)) {
+		if (decoder.peekStartElement(CCNProtocolDTags.MinSuffixComponents))
 			this.minSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MinSuffixComponents);
-		}
 
-		if (decoder.peekStartElement(CCNProtocolDTags.MaxSuffixComponents)) {
+		if (decoder.peekStartElement(CCNProtocolDTags.MaxSuffixComponents)) 
 			this.maxSuffixComponents = decoder.readIntegerElement(CCNProtocolDTags.MaxSuffixComponents);
-		}
 			
 		if (decoder.peekStartElement(CCNProtocolDTags.PublisherPublicKeyDigest)) {
-			this.publisherPublicKeyDigest = new publisherPublicKeyDigest();
+			this.publisherPublicKeyDigest = new PublisherPublicKeyDigest();
 			this.publisherPublicKeyDigest.from_ccnb(decoder);
 		}
 
@@ -58,26 +55,21 @@
 			this.exclude.from_ccnb(decoder);
 		}
 		
-		if (decoder.peekStartElement(CCNProtocolDTags.ChildSelector)) {
+		if (decoder.peekStartElement(CCNProtocolDTags.ChildSelector))
 			this.childSelector = decoder.readIntegerElement(CCNProtocolDTags.ChildSelector);
-		}
 		
-		if (decoder.peekStartElement(CCNProtocolDTags.AnswerOriginKind)) {
-			// call setter to handle defaulting
+		if (decoder.peekStartElement(CCNProtocolDTags.AnswerOriginKind))
 			this.answerOriginKind = decoder.readIntegerElement(CCNProtocolDTags.AnswerOriginKind);
-		}
 		
-		if (decoder.peekStartElement(CCNProtocolDTags.Scope)) {
+		if (decoder.peekStartElement(CCNProtocolDTags.Scope))
 			this.scope = decoder.readIntegerElement(CCNProtocolDTags.Scope);
-		}
 
-		if (decoder.peekStartElement(CCNProtocolDTags.InterestLifetime)) {
-			this.interestLifetime = decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime);
-		}
+		if (decoder.peekStartElement(CCNProtocolDTags.InterestLifetime))
+			this.interestLifetime = DataUtils.bigEndianToUnsignedInt
+                (decoder.readBinaryElement(CCNProtocolDTags.InterestLifetime)) / 4096;
 		
-		if (decoder.peekStartElement(CCNProtocolDTags.Nonce)) {
+		if (decoder.peekStartElement(CCNProtocolDTags.Nonce))
 			this.nonce = decoder.readBinaryElement(CCNProtocolDTags.Nonce);
-		}
 		
 		decoder.readEndElement();
 };
@@ -104,13 +96,16 @@
 		if (null != this.childSelector) 
 			encoder.writeElement(CCNProtocolDTags.ChildSelector, this.childSelector);
 
-		//TODO Encode OriginKind
 		if (this.DEFAULT_ANSWER_ORIGIN_KIND != this.answerOriginKind && this.answerOriginKind!=null) 
 			encoder.writeElement(CCNProtocolDTags.AnswerOriginKind, this.answerOriginKind);
 		
 		if (null != this.scope) 
 			encoder.writeElement(CCNProtocolDTags.Scope, this.scope);
 		
+		if (null != this.interestLifetime) 
+			encoder.writeElement(CCNProtocolDTags.InterestLifetime, 
+                DataUtils.nonNegativeIntToBigEndian(this.interestLifetime * 4096));
+		
 		if (null != this.nonce)
 			encoder.writeElement(CCNProtocolDTags.Nonce, this.nonce);
 		
diff --git a/js/ccnxProtocol.xpi b/js/ccnxProtocol.xpi
index e473114..11f3ed2 100644
--- a/js/ccnxProtocol.xpi
+++ b/js/ccnxProtocol.xpi
Binary files differ
diff --git a/js/ccnxProtocol/components/ccnxProtocolService.js b/js/ccnxProtocol/components/ccnxProtocolService.js
index afd493b..ed6ea7e 100644
--- a/js/ccnxProtocol/components/ccnxProtocolService.js
+++ b/js/ccnxProtocol/components/ccnxProtocolService.js
@@ -39,15 +39,19 @@
         try {            

             var spec = aURI.spec.trim();

             var preHash = spec.split('#', 1)[0];

-            var hash = spec.substr(preHash.length, spec.length).trim();

+            var hash = spec.substr(preHash.length).trim();

             var preSearch = preHash.split('?', 1)[0];

-            var search = preHash.substr(preSearch.length, spec.length).trim();

+            var search = preHash.substr(preSearch.length).trim();

             // Set nameString to the preSearch without the protocol.

             var nameString = preSearch.trim();

             if (nameString.indexOf(':') >= 0)

-                nameString = nameString.substr(nameString.indexOf(':') + 1, spec.length).trim();

+                nameString = nameString.substr(nameString.indexOf(':') + 1).trim();

     

-            var contentChannel;

+            var template = new Interest(new Name([]));

+            // Use the same default as NDN.expressInterest.

+            template.interestLifetime = 4200;

+            var searchWithoutCcnx = extractCcnxSearch(search, template);

+    

             var requestContent = function(contentListener) {                

                 var name = new Name(nameString);

                 // TODO: Strip off an ending implicit digest before checking the last component?

@@ -56,13 +60,13 @@
                 var ndn = new NDN({ host: "lioncub.metwi.ucla.edu", port: 9695,

                       // Use the same transport object each time.

                       getTransport: function() { return thisCcnxProtocol.transport; } });

-                ndn.expressInterest(name, new ContentClosure

-                    (ndn, contentListener, uriEndsWithSegmentNumber, aURI.originCharset,

-                     search + hash));

+                ndn.expressInterest(name, 

+                    new ContentClosure(ndn, contentListener, uriEndsWithSegmentNumber, 

+                            aURI.originCharset, searchWithoutCcnx + hash),

+                    template);

             };

 

-            contentChannel = new ContentChannel(aURI, requestContent);

-            return contentChannel;

+            return new ContentChannel(aURI, requestContent);

         } catch (ex) {

             dump("CcnxProtocol.newChannel exception: " + ex + "\n");

         }

@@ -231,4 +235,55 @@
     return name.components != null && name.components.length >= 1 &&

         name.components[name.components.length - 1].length >= 1 &&

         name.components[name.components.length - 1][0] == 0;

+}

+

+/*

+ * Find all search keys starting with "ccnx." and set the attribute in template.

+ * Return the search string including the starting "?" but with the "ccnx." keys removed,

+ *   or return "" if there are no search terms left.

+ */

+function extractCcnxSearch(search, template) {

+    if (!(search.length >= 1 && search[0] == '?'))

+        return search;

+    

+    var terms = search.substr(1).split('&');

+    var i = 0;

+    while (i < terms.length) {

+        var keyValue = terms[i].split('=');

+        var key = keyValue[0].trim();

+        if (key.substr(0, 5) == "ccnx.") {

+            if (keyValue.length >= 1) {

+                var value = keyValue[1].trim;

+                var nonNegativeInt = parseInt(value);

+                

+                if (key == "ccnx.MinSuffixComponents" && nonNegativeInt >= 0)

+                    template.minSuffixComponents = nonNegativeInt;

+                if (key == "ccnx.MaxSuffixComponents" && nonNegativeInt >= 0)

+                    template.maxSuffixComponents = nonNegativeInt;

+                if (key == "ccnx.ChildSelector" && nonNegativeInt >= 0)

+                    template.childSelector = nonNegativeInt;

+                if (key == "ccnx.AnswerOriginKind" && nonNegativeInt >= 0)

+                    template.answerOriginKind = nonNegativeInt;

+                if (key == "ccnx.Scope" && nonNegativeInt >= 0)

+                    template.scope = nonNegativeInt;

+                if (key == "ccnx.InterestLifetime" && nonNegativeInt >= 0)

+                    template.interestLifetime = nonNegativeInt;

+                if (key == "ccnx.PublisherPublicKeyDigest" && nonNegativeInt >= 0)

+                    template.publisherPublicKeyDigest = DataUtils.toNumbersFromString(unescape(value));

+                if (key == "ccnx.Nonce" && nonNegativeInt >= 0)

+                    template.nonce = DataUtils.toNumbersFromString(unescape(value));

+                // TODO: handle Exclude.

+            }

+        

+            // Remove the "ccnx." term and don't advance i.

+            terms.splice(i, 1);

+        }

+        else

+            ++i;

+    }

+    

+    if (terms.length == 0)

+        return "";

+    else

+        return "?" + terms.join('&');

 }
\ No newline at end of file
diff --git a/js/testing/test-encode-decode-Interest.html b/js/testing/test-encode-decode-Interest.html
index 4cc5a92..f95ac16 100644
--- a/js/testing/test-encode-decode-Interest.html
+++ b/js/testing/test-encode-decode-Interest.html
@@ -10,88 +10,94 @@
 

 	<script type="text/javascript">

 	

-		function encode(){

+		function encode() {

 			var interest = new Interest( new Name(document.getElementById('interest').value ) );

 

-			interest.scope = 1;

-			

+            interest.minSuffixComponents = 2;

+            interest.maxSuffixComponents = 4;

+            interest.childSelector = 1;

+            interest.answerOriginKind = 4;

+            interest.scope = 2;

+            interest.interestLifetime = 30;

+            interest.nonce = new Uint8Array([0x61, 0x62, 0x61, 0x62, 0x61, 0x62]);

+            var pkd = [];

+            for (i = 0; i < 32; ++i)

+                pkd.push(i);

+			interest.publisherPublicKeyDigest = new PublisherPublicKeyDigest(new Uint8Array(pkd));

+                

 			var output = encodeToHexInterest(interest);

 			

 			document.getElementById('result').innerHTML = output;

 

 		}

 		

-		function decode(){

-			

-			

-			

+		function decode() {

 			var input = document.getElementById('result').innerHTML;

-

 			

 			var interest = decodeHexInterest(input);

 			

-			if(LOG>3)console.log('INTEREST DECODED');

-			if(LOG>3)console.log(interest);

+			if (LOG>3)console.log('INTEREST DECODED');

+			if (LOG>3)console.log(interest);

 

 			///////////////////////////////////////

 			

 			var output ="";

 			

-			if(interest.name!=null && interest.name.components!=null){

-				output+= "NAME: ";

+			if (interest.name != null && interest.name.components != null) {

+				output += "Name: ";

+				output += interest.name.getName();

+				output += "<br/>";

+			}

 				

-				

-				output+= interest.name.getName();

-				

-				/*for(var i=0;i<interest.name.components.length;i++){

-					output+= "/"+ DataUtils.toString(interest.name.Components[i]);

-				}*/

-				

-				output+= "<br />";

-				output+= "<br />";

+			if (interest.minSuffixComponents != null ) {

+				output += "MinSuffixComponents : ";

+				output +=  interest.minSuffixComponents;

+				output += "<br/>";

+			}

+			

+			if (interest.maxSuffixComponents != null ) {

+				output += "MaxSuffixComponents : ";

+				output +=  interest.maxSuffixComponents;

+				output += "<br/>";

 			}

 	

+			if (interest.publisherPublicKeyDigest != null ) {

+				output += "PublisherPublicKeyDigest: ";

+				output +=  DataUtils.toHex(interest.publisherPublicKeyDigest.publisherPublicKeyDigest);

+				output += "<br/>";

+			}

 			

-			if(interest.scope!=null ){

-				output+= "SCOPE: ";

-				

-					output+=  interest.scope;

-				

-				output+= "<br />";

-				output+= "<br />";

+			if (interest.childSelector != null ) {

+				output += "ChildSelector: ";

+				output +=  interest.childSelector;

+				output += "<br/>";

+			}

+			

+			if (interest.answerOriginKind != null ) {

+				output += "AnswerOriginKind: ";

+				output +=  interest.answerOriginKind;

+				output += "<br/>";

+			}

+			

+			if (interest.scope != null ) {

+				output += "Scope: ";

+				output +=  interest.scope;

+				output += "<br/>";

+			}

+			

+			if (interest.interestLifetime != null ) {

+				output += "InterestLifetime: ";

+				output +=  interest.interestLifetime;

+				output += "<br/>";

 			}

 	

-			if(interest.publisherID!=null ){

-				output+= "PUBLISHER ID: ";

-				

-					output+=  interest.publisherID.publisherID;

-					

-					output+= "PUBLISHER ID TYPE: ";

-					output+=  interest.publisherID.publisherType;

-				output+= "<br />";

-				output+= "<br />";

-			}

-			

-			if(interest.maxSuffixComponents!=null ){

-				output+= "MaxSuffixComponents : ";

-				

-				output+=  interest.maxSuffixComponents;

-

-				output+= "<br />";

-				output+= "<br />";

-			}

-			

-			if(interest.minSuffixComponents!=null ){

-				output+= "MinSuffixComponents : ";

-				

-				output+=  interest.minSuffixComponents;

-

-				output+= "<br />";

-				output+= "<br />";

+			if (interest.nonce != null ) {

+				output += "Nonce: ";

+				output +=  DataUtils.toHex(interest.nonce);

+				output += "<br/>";

 			}

 			

 			document.getElementById('result').innerHTML = output;

-			

 		}

 

 	</script>