Set interest timeout with interest.interestLifetime
diff --git a/.DS_Store b/.DS_Store
index 5d54f89..1d3d442 100644
--- a/.DS_Store
+++ b/.DS_Store
Binary files differ
diff --git a/js/.DS_Store b/js/.DS_Store
index 80e2e80..4ec3fa3 100644
--- a/js/.DS_Store
+++ b/js/.DS_Store
Binary files differ
diff --git a/js/ContentObject.js b/js/ContentObject.js
index 0d6f101..9567e44 100644
--- a/js/ContentObject.js
+++ b/js/ContentObject.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents ContentObject Objects
diff --git a/js/FaceInstance.js b/js/FaceInstance.js
index fd4868a..91b8780 100644
--- a/js/FaceInstance.js
+++ b/js/FaceInstance.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Face Instances
diff --git a/js/ForwardingEntry.js b/js/ForwardingEntry.js
index b223004..baf00cb 100644
--- a/js/ForwardingEntry.js
+++ b/js/ForwardingEntry.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Forwarding Entries
diff --git a/js/Interest.js b/js/Interest.js
index 62c2e48..b227fdf 100644
--- a/js/Interest.js
+++ b/js/Interest.js
@@ -1,4 +1,4 @@
- /*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Interest Objects
diff --git a/js/Key.js b/js/Key.js
index eca05d9..d60585e 100644
--- a/js/Key.js
+++ b/js/Key.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Key Objects
diff --git a/js/NDN.js b/js/NDN.js
index f963a78..479ed30 100644
--- a/js/NDN.js
+++ b/js/NDN.js
@@ -32,8 +32,6 @@
 NDN.OPENED = 1;  // connection to ccnd opened
 NDN.CLOSED = 2;  // connection to ccnd closed
 
-NDN.InterestTimeOut = 5000; // 5000 ms timeout for pending interest
-
 /* Java Socket Bridge and XPCOM transport */
 
 NDN.prototype.createRoute = function(host,port){
@@ -70,7 +68,7 @@
 		interest.interestLifetime = template.interestLifetime;
     }
     else
-        interest.interestLifetime = 4200;
+        interest.interestLifetime = 4200;   // default interest timeout value
     
     this.transport.expressInterest(this, interest, closure);
 };
diff --git a/js/Name.js b/js/Name.js
index 1df7eab..440d685 100644
--- a/js/Name.js
+++ b/js/Name.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui, Jeff Thompson
  * See COPYING for copyright and distribution information.
  * This class represents a Name as an array of components where each is a byte array.
diff --git a/js/PublisherID.js b/js/PublisherID.js
index 31dd8a1..df4e701 100644
--- a/js/PublisherID.js
+++ b/js/PublisherID.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Publisher and PublisherType Objects
diff --git a/js/PublisherPublicKeyDigest.js b/js/PublisherPublicKeyDigest.js
index 9618f4f..2079f19 100644
--- a/js/PublisherPublicKeyDigest.js
+++ b/js/PublisherPublicKeyDigest.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents PublisherPublicKeyDigest Objects
diff --git a/js/WebSocketTransport.js b/js/WebSocketTransport.js
index 0a60c6e..034e8b8 100644
--- a/js/WebSocketTransport.js
+++ b/js/WebSocketTransport.js
@@ -119,6 +119,11 @@
 						clearTimeout(pitEntry.closure.timerID);
 						//console.log("Clear interest timer");
 						//console.log(pitEntry.closure.timerID);
+						
+						// Remove PIT entry from PITTable
+						index = PITTable.indexOf(pitEntry);
+						PITTable.splice(index, 1);
+						
 						// Raise callback
 						pitEntry.closure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
 					}
@@ -209,7 +214,7 @@
 		
 		// Set interest timer
 		closure.timerID = setTimeout(function() {
-			console.log("Interest time out.");
+			if (LOG > 3) console.log("Interest time out.");
 			
 			// Remove PIT entry from PITTable
 			index = PITTable.indexOf(pitEntry);
@@ -218,7 +223,7 @@
 			//console.log(PITTable);
 			// Raise closure callback
 			closure.upcall(Closure.UPCALL_INTEREST_TIMED_OUT, new UpcallInfo(ndn, interest, 0, null));
-		}, NDN.InterestTimeOut);
+		}, interest.interestLifetime);
 		//console.log(closure.timerID);
 	}
 	else
diff --git a/js/XpcomTransport.js b/js/XpcomTransport.js
index c017848..e686d3a 100644
--- a/js/XpcomTransport.js
+++ b/js/XpcomTransport.js
@@ -1,4 +1,4 @@
-/* 
+/** 
  * @author: Jeff Thompson
  * See COPYING for copyright and distribution information.
  * Implement getAsync and putAsync used by NDN using nsISocketTransportService.
diff --git a/js/encoding/BinaryXMLDecoder.js b/js/encoding/BinaryXMLDecoder.js
index dbe97b2..4f516d6 100644
--- a/js/encoding/BinaryXMLDecoder.js
+++ b/js/encoding/BinaryXMLDecoder.js
@@ -1,4 +1,4 @@
-/*
+/**
  * This class is used to decode ccnb binary elements (blob, type/value pairs).
  * 
  * @author: Meki Cheraoui
diff --git a/js/encoding/BinaryXMLEncoder.js b/js/encoding/BinaryXMLEncoder.js
index b76e7d5..fba9ff6 100644
--- a/js/encoding/BinaryXMLEncoder.js
+++ b/js/encoding/BinaryXMLEncoder.js
@@ -1,4 +1,4 @@
-/*
+/**
  * This class is used to encode ccnb binary elements (blob, type/value pairs).
  * 
  * @author: Meki Cheraoui
diff --git a/js/encoding/BinaryXMLStructureDecoder.js b/js/encoding/BinaryXMLStructureDecoder.js
index 6dc123f..b31050f 100644
--- a/js/encoding/BinaryXMLStructureDecoder.js
+++ b/js/encoding/BinaryXMLStructureDecoder.js
@@ -1,4 +1,4 @@
-/*
+/**
  * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to 
  * determine its end.
  * 
diff --git a/js/encoding/DataUtils.js b/js/encoding/DataUtils.js
index 39da01d..2965a9c 100644
--- a/js/encoding/DataUtils.js
+++ b/js/encoding/DataUtils.js
@@ -1,4 +1,4 @@
-/*
+/**
  * This class contains utilities to help parse the data
  * author: Meki Cheraoui, Jeff Thompson
  * See COPYING for copyright and distribution information.
diff --git a/js/encoding/EncodingUtils.js b/js/encoding/EncodingUtils.js
index 3f46204..97326e3 100644
--- a/js/encoding/EncodingUtils.js
+++ b/js/encoding/EncodingUtils.js
@@ -1,4 +1,4 @@
-/*
+/**
  * This file contains utilities to help encode and decode NDN objects.
  * author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
diff --git a/js/security/.DS_Store b/js/security/.DS_Store
index 5008ddf..3e9e22f 100644
--- a/js/security/.DS_Store
+++ b/js/security/.DS_Store
Binary files differ
diff --git a/js/security/KeyManager.js b/js/security/KeyManager.js
index 2a95114..32a7f42 100644
--- a/js/security/KeyManager.js
+++ b/js/security/KeyManager.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  */
diff --git a/js/testing/.DS_Store b/js/testing/.DS_Store
index 3f0e7ef..1f2650f 100644
--- a/js/testing/.DS_Store
+++ b/js/testing/.DS_Store
Binary files differ
diff --git a/js/tools/build/ndn-js-uncomp.js b/js/tools/build/ndn-js-uncomp.js
index fa00a92..4b62da8 100644
--- a/js/tools/build/ndn-js-uncomp.js
+++ b/js/tools/build/ndn-js-uncomp.js
@@ -98,8 +98,6 @@
 NDN.OPENED = 1;  // connection to ccnd opened
 NDN.CLOSED = 2;  // connection to ccnd closed
 
-NDN.InterestTimeOut = 5000; // 5000 ms timeout for pending interest
-
 /* Java Socket Bridge and XPCOM transport */
 
 NDN.prototype.createRoute = function(host,port){
@@ -136,7 +134,7 @@
 		interest.interestLifetime = template.interestLifetime;
     }
     else
-        interest.interestLifetime = 4200;
+        interest.interestLifetime = 4200;   // default interest timeout value
     
     this.transport.expressInterest(this, interest, closure);
 };
@@ -266,6 +264,11 @@
 						clearTimeout(pitEntry.closure.timerID);
 						//console.log("Clear interest timer");
 						//console.log(pitEntry.closure.timerID);
+						
+						// Remove PIT entry from PITTable
+						index = PITTable.indexOf(pitEntry);
+						PITTable.splice(index, 1);
+						
 						// Raise callback
 						pitEntry.closure.upcall(Closure.UPCALL_CONTENT, new UpcallInfo(ndn, null, 0, co));
 					}
@@ -356,7 +359,7 @@
 		
 		// Set interest timer
 		closure.timerID = setTimeout(function() {
-			console.log("Interest time out.");
+			if (LOG > 3) console.log("Interest time out.");
 			
 			// Remove PIT entry from PITTable
 			index = PITTable.indexOf(pitEntry);
@@ -365,7 +368,7 @@
 			//console.log(PITTable);
 			// Raise closure callback
 			closure.upcall(Closure.UPCALL_INTEREST_TIMED_OUT, new UpcallInfo(ndn, interest, 0, null));
-		}, NDN.InterestTimeOut);
+		}, interest.interestLifetime);
 		//console.log(closure.timerID);
 	}
 	else
@@ -437,7 +440,7 @@
 	}
 }
 
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class contains all CCNx tags
@@ -593,7 +596,7 @@
 //TESTING
 //console.log(exports.CCNProtocolDTagsStrings[17]);
 
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents CCNTime Objects
@@ -696,7 +699,7 @@
 	return out;
 }*/
 	
-/*
+/**
  * @author: Meki Cheraoui, Jeff Thompson
  * See COPYING for copyright and distribution information.
  * This class represents a Name as an array of components where each is a byte array.
@@ -956,7 +959,7 @@
     }
     return result;
 };
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents ContentObject Objects
@@ -1522,7 +1525,7 @@
 Date.prototype.format = function (mask, utc) {
 	return dateFormat(this, mask, utc);
 };
- /*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Interest Objects
@@ -1746,7 +1749,7 @@
 };
 
 ExcludeComponent.prototype.getElementLabel = function() { return CCNProtocolDTags.Component; };
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Key Objects
@@ -1941,7 +1944,7 @@
 		// null signedInfo ok
 		return (null != this.contentName);
 };
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Publisher and PublisherType Objects
@@ -2037,7 +2040,7 @@
 
 
 
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents PublisherPublicKeyDigest Objects
@@ -2088,7 +2091,7 @@
 PublisherPublicKeyDigest.prototype.validate =function() {
 		return (null != this.publisherPublicKeyDigest);
 };
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Face Instances
@@ -2247,7 +2250,7 @@
 
 FaceInstance.prototype.getElementLabel= function(){return CCNProtocolDTags.FaceInstance;};
 
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents Forwarding Entries
@@ -2347,7 +2350,7 @@
 		};
 
 ForwardingEntry.prototype.getElementLabel = function() { return CCNProtocolDTags.ForwardingEntry; }
-/*
+/**
  * This class is used to encode ccnb binary elements (blob, type/value pairs).
  * 
  * @author: Meki Cheraoui
@@ -2745,7 +2748,7 @@
 	return this.ostream.subarray(0, this.offset);
 };
 
-/*
+/**
  * This class is used to decode ccnb binary elements (blob, type/value pairs).
  * 
  * @author: Meki Cheraoui
@@ -3474,7 +3477,7 @@
 ContentDecodingException.prototype = new Error();
 ContentDecodingException.prototype.name = "ContentDecodingException";
 
-/*
+/**
  * This class uses BinaryXMLDecoder to follow the structure of a ccnb binary element to 
  * determine its end.
  * 
@@ -3652,7 +3655,7 @@
         this.headerBuffer = newHeaderBuffer;
     }
     this.headerBuffer.set(subarray, bufferOffset);
-}/*
+}/**
  * This class contains utilities to help parse the data
  * author: Meki Cheraoui, Jeff Thompson
  * See COPYING for copyright and distribution information.
@@ -4084,7 +4087,7 @@
     }
     return result.subarray(size - i, size);
 };
-/*
+/**
  * This file contains utilities to help encode and decode NDN objects.
  * author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
@@ -4429,7 +4432,7 @@
 
     return output;
 }
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  */
diff --git a/js/tools/build/ndn-js.js b/js/tools/build/ndn-js.js
index 77ae081..5a409ed 100644
--- a/js/tools/build/ndn-js.js
+++ b/js/tools/build/ndn-js.js
@@ -1,16 +1,16 @@
 var Closure=function(){this.ndn_data=null;this.ndn_data_dirty=!1;this.timerID=-1};Closure.RESULT_ERR=-1;Closure.RESULT_OK=0;Closure.RESULT_REEXPRESS=1;Closure.RESULT_INTEREST_CONSUMED=2;Closure.RESULT_VERIFY=3;Closure.RESULT_FETCHKEY=4;Closure.UPCALL_FINAL=0;Closure.UPCALL_INTEREST=1;Closure.UPCALL_CONSUMED_INTEREST=2;Closure.UPCALL_CONTENT=3;Closure.UPCALL_INTEREST_TIMED_OUT=4;Closure.UPCALL_CONTENT_UNVERIFIED=5;Closure.UPCALL_CONTENT_BAD=6;Closure.prototype.upcall=function(){return Closure.RESULT_OK};
 var UpcallInfo=function(a,b,c,d){this.ndn=a;this.interest=b;this.matchedComps=c;this.contentObject=d};UpcallInfo.prototype.toString=function(){var a="ndn = "+this.ndn,a=a+("\nInterest = "+this.interest),a=a+("\nmatchedComps = "+this.matchedComps);return a+="\nContentObject: "+this.contentObject};
-var LOG=0,NDN=function NDN(b){b=b||{};this.host=b.host||"localhost";this.port=b.port||9696;this.transport=(b.getTransport||function(){return new WebSocketTransport})();this.readyStatus=NDN.UNOPEN;this.onopen=b.onopen||function(){3<LOG&&console.log("NDN connection established.")};this.onclose=b.onclose||function(){3<LOG&&console.log("NDN connection closed.")}};NDN.UNOPEN=0;NDN.OPENED=1;NDN.CLOSED=2;NDN.InterestTimeOut=5E3;NDN.prototype.createRoute=function(a,b){this.host=a;this.port=b};
+var LOG=0,NDN=function NDN(b){b=b||{};this.host=b.host||"localhost";this.port=b.port||9696;this.transport=(b.getTransport||function(){return new WebSocketTransport})();this.readyStatus=NDN.UNOPEN;this.onopen=b.onopen||function(){3<LOG&&console.log("NDN connection established.")};this.onclose=b.onclose||function(){3<LOG&&console.log("NDN connection closed.")}};NDN.UNOPEN=0;NDN.OPENED=1;NDN.CLOSED=2;NDN.prototype.createRoute=function(a,b){this.host=a;this.port=b};
 NDN.prototype.expressInterest=function(a,b,c){null==this.host||null==this.port?dump("ERROR host OR port NOT SET\n"):(a=new Interest(a),null!=c?(a.minSuffixComponents=c.minSuffixComponents,a.maxSuffixComponents=c.maxSuffixComponents,a.publisherPublicKeyDigest=c.publisherPublicKeyDigest,a.exclude=c.exclude,a.childSelector=c.childSelector,a.answerOriginKind=c.answerOriginKind,a.scope=c.scope,a.interestLifetime=c.interestLifetime):a.interestLifetime=4200,this.transport.expressInterest(this,a,b))};
 NDN.prototype.registerPrefix=function(a,b,c){return this.transport.registerPrefix(this,a,b,c)};var WebSocketTransport=function(){this.ccndid=this.ws=null;this.maxBufferSize=1E4;this.buffer=new Uint8Array(this.maxBufferSize);this.structureDecoder=new BinaryXMLStructureDecoder},ccndIdFetcher="/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY";
 WebSocketTransport.prototype.connectWebSocket=function(a){null!=this.ws&&delete this.ws;this.ws=new WebSocket("ws://"+a.host+":"+a.port);0<LOG&&console.log("ws connection created.");this.ws.binaryType="arraybuffer";var b=this;this.ws.onmessage=function(c){c=c.data;if(null==c||void 0==c||""==c)console.log("INVALID ANSWER");else if(c instanceof ArrayBuffer){c=new Uint8Array(c);3<LOG&&console.log("BINARY RESPONSE IS "+DataUtils.toHex(c));try{if(c.length+b.buffer.byteOffset>=b.buffer.byteLength){console.log("NDN.ws.onmessage: buffer overflow. Accumulate received length: "+
 b.buffer.byteOffset+". Current packet length: "+c.length+".");delete b.structureDecoder;delete b.buffer;b.structureDecoder=new BinaryXMLStructureDecoder;b.buffer=new Uint8Array(b.maxBufferSize);return}b.buffer.set(c,b.buffer.byteOffset);if(!b.structureDecoder.findElementEnd(b.buffer)){console.log("Incomplete packet received. Length "+c.length+". Wait for more input.");console.log("self.buffer length: "+b.buffer.length);return}}catch(d){console.log("NDN.ws.onmessage exception: "+d);return}c=new BinaryXMLDecoder(b.buffer);
 if(c.peekStartElement(CCNProtocolDTags.Interest)){3<LOG&&console.log("Interest packet received.");var e=new Interest;e.from_ccnb(c);3<LOG&&console.log(e);var f=escape(e.name.getName());3<LOG&&console.log(f);f=getEntryForRegisteredPrefix(f);null!=f&&f.closure.upcall(Closure.UPCALL_INTEREST,new UpcallInfo(a,e,0,null))}else c.peekStartElement(CCNProtocolDTags.ContentObject)?(3<LOG&&console.log("ContentObject packet received."),e=new ContentObject,e.from_ccnb(c),3<LOG&&console.log(e),f=e.name.getName(),
-3<LOG&&console.log(f),null==b.ccndid&&null!=f.match(ccndIdFetcher)?!e.signedInfo||!e.signedInfo.publisher||!e.signedInfo.publisher.publisherPublicKeyDigest?(console.log("Cannot contact router, close NDN now."),a.readyStatus=NDN.CLOSED,a.onclose()):(b.ccndid=e.signedInfo.publisher.publisherPublicKeyDigest,3<LOG&&console.log(b.ccndid),a.readyStatus=NDN.OPENED,a.onopen()):(f=getEntryForExpressedInterest(f),null!=f&&(clearTimeout(f.closure.timerID),f.closure.upcall(Closure.UPCALL_CONTENT,new UpcallInfo(a,
-null,0,e))))):console.log("Incoming packet is not Interest or ContentObject. Discard now.");delete c;delete b.structureDecoder;delete b.buffer;b.structureDecoder=new BinaryXMLStructureDecoder;b.buffer=new Uint8Array(b.maxBufferSize)}};this.ws.onopen=function(a){3<LOG&&console.log(a);3<LOG&&console.log("ws.onopen: WebSocket connection opened.");3<LOG&&console.log("ws.onopen: ReadyState: "+this.readyState);a=new Interest(new Name(ccndIdFetcher));a.InterestLifetime=4200;var a=encodeToBinaryInterest(a),
+3<LOG&&console.log(f),null==b.ccndid&&null!=f.match(ccndIdFetcher)?!e.signedInfo||!e.signedInfo.publisher||!e.signedInfo.publisher.publisherPublicKeyDigest?(console.log("Cannot contact router, close NDN now."),a.readyStatus=NDN.CLOSED,a.onclose()):(b.ccndid=e.signedInfo.publisher.publisherPublicKeyDigest,3<LOG&&console.log(b.ccndid),a.readyStatus=NDN.OPENED,a.onopen()):(f=getEntryForExpressedInterest(f),null!=f&&(clearTimeout(f.closure.timerID),index=PITTable.indexOf(f),PITTable.splice(index,1),f.closure.upcall(Closure.UPCALL_CONTENT,
+new UpcallInfo(a,null,0,e))))):console.log("Incoming packet is not Interest or ContentObject. Discard now.");delete c;delete b.structureDecoder;delete b.buffer;b.structureDecoder=new BinaryXMLStructureDecoder;b.buffer=new Uint8Array(b.maxBufferSize)}};this.ws.onopen=function(a){3<LOG&&console.log(a);3<LOG&&console.log("ws.onopen: WebSocket connection opened.");3<LOG&&console.log("ws.onopen: ReadyState: "+this.readyState);a=new Interest(new Name(ccndIdFetcher));a.InterestLifetime=4200;var a=encodeToBinaryInterest(a),
 d=new Uint8Array(a.length);d.set(a);b.ws.send(d.buffer)};this.ws.onerror=function(a){console.log("ws.onerror: ReadyState: "+this.readyState);console.log(a);console.log("ws.onerror: WebSocket error: "+a.data)};this.ws.onclose=function(){console.log("ws.onclose: WebSocket connection closed.");b.ws=null;a.readyStatus=NDN.CLOSED;a.onclose()}};var PITTable=[],PITEntry=function(a,b){this.interest=a;this.closure=b};
 function getEntryForExpressedInterest(a){for(var b=0;b<PITTable.length;b++)if(null!=a.match(PITTable[b].interest))return PITTable[b];return null}
-WebSocketTransport.prototype.expressInterest=function(a,b,c){if(null!=this.ws){var d=encodeToBinaryInterest(b),e=new Uint8Array(d.length);e.set(d);var f=new PITEntry(b.name.getName(),c);PITTable.push(f);this.ws.send(e.buffer);3<LOG&&console.log("ws.send() returned.");c.timerID=setTimeout(function(){console.log("Interest time out.");index=PITTable.indexOf(f);PITTable.splice(index,1);c.upcall(Closure.UPCALL_INTEREST_TIMED_OUT,new UpcallInfo(a,b,0,null))},NDN.InterestTimeOut)}else console.log("WebSocket connection is not established.")};
+WebSocketTransport.prototype.expressInterest=function(a,b,c){if(null!=this.ws){var d=encodeToBinaryInterest(b),e=new Uint8Array(d.length);e.set(d);var f=new PITEntry(b.name.getName(),c);PITTable.push(f);this.ws.send(e.buffer);3<LOG&&console.log("ws.send() returned.");c.timerID=setTimeout(function(){3<LOG&&console.log("Interest time out.");index=PITTable.indexOf(f);PITTable.splice(index,1);c.upcall(Closure.UPCALL_INTEREST_TIMED_OUT,new UpcallInfo(a,b,0,null))},b.interestLifetime)}else console.log("WebSocket connection is not established.")};
 var CSTable=[],CSEntry=function(a,b){this.name=a;this.closure=b};function getEntryForRegisteredPrefix(a){for(var b=0;b<CSTable.length;b++)if(null!=CSTable[b].name.match(a))return CSTable[b];return null}
 WebSocketTransport.prototype.registerPrefix=function(a,b,c){if(null!=this.ws){if(null==this.ccndid)return console.log("ccnd node ID unkonwn. Cannot register prefix."),-1;var a=new ForwardingEntry("selfreg",b,null,null,3,2147483647),a=encodeForwardingEntry(a),d=new SignedInfo;d.setFields();a=new ContentObject(new Name,d,a,new Signature);a.sign();a=encodeToBinaryContentObject(a);a=new Name(["ccnx",this.ccndid,"selfreg",a]);a=new Interest(a);a.scope=1;d=encodeToBinaryInterest(a);a=new Uint8Array(d.length);
 a.set(d);3<LOG&&console.log("Send Interest registration packet.");b=new CSEntry(b.getName(),c);CSTable.push(b);this.ws.send(a.buffer);return 0}console.log("WebSocket connection is not established.");return-1};
diff --git a/js/tools/ndnpublish/ndn-js.js b/js/tools/ndnpublish/ndn-js.js
index 9493c9b..4274679 100644
--- a/js/tools/ndnpublish/ndn-js.js
+++ b/js/tools/ndnpublish/ndn-js.js
@@ -91,6 +91,8 @@
  *   host: 'localhost',
  *   port: 9696,
  *   getTransport: function() { return new WebSocketTransport(); }
+ *   onopen: function() { console.log("NDN connection established."); }
+ *   onclose: function() { console.log("NDN connection closed."); }
  * }
  */
 var NDN = function NDN(settings) {
@@ -98,9 +100,16 @@
 	this.host = (settings.host || "localhost");
 	this.port = (settings.port || 9696);
     var getTransport = (settings.getTransport || function() { return new WebSocketTransport(); });
-    this.transport = getTransport();    
+    this.transport = getTransport();
+    this.readyStatus = NDN.UNOPEN;
+    // Event handler
+    this.onopen = (settings.onopen || function() { console.log("NDN connection established."); });
+    this.onclose = (settings.onclose || function() { console.log("NDN connection closed."); });
 };
 
+NDN.UNOPEN = 0;  // created but not opened yet
+NDN.OPENED = 1;  // connection to ccnd opened
+NDN.CLOSED = 2;  // connection to ccnd closed
 
 /* Java Socket Bridge and XPCOM transport */
 
@@ -265,10 +274,20 @@
 					if(!co.signedInfo || !co.signedInfo.publisher 
 						|| !co.signedInfo.publisher.publisherPublicKeyDigest) {
 						console.log("Cannot contact router");
+						
+						// Close NDN if we fail to connect to a ccn router
+						ndn.readyStatus = NDN.CLOSED;
+						ndn.onclose();
+						console.log("NDN.onclose event fired.");
 					} else {
 						console.log('Connected to ccnd.');
 						self.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
 						if (LOG>3) console.log(self.ccndid);
+						
+						// Call NDN.onopen after success
+						ndn.readyStatus = NDN.OPENED;
+						ndn.onopen();
+						console.log("NDN.onopen event fired.");
 					}
 				} else {
 					var pitEntry = getEntryForExpressedInterest(nameStr);
@@ -321,6 +340,11 @@
 	this.ws.onclose = function(ev) {
 		console.log('ws.onclose: WebSocket connection closed.');
 		self.ws = null;
+		
+		// Close NDN when WebSocket is closed
+		ndn.readyStatus = NDN.CLOSED;
+		ndn.onclose();
+		console.log("NDN.onclose event fired.");
 	}
 }
 
@@ -376,9 +400,9 @@
 		co.sign();
 		var coBinary = encodeToBinaryContentObject(co);
 		
-		//var ccnxnodename = unescape('%00%88%E2%F4%9C%91%16%16%D6%21%8E%A0c%95%A5%A6r%11%E0%A0%82%89%A6%A9%85%AB%D6%E2%065%DB%AF');
-		var ccnxnodename = this.ccndid;
-		var interestName = new Name(['ccnx', ccnxnodename, 'selfreg', coBinary]);
+		//var nodename = unescape('%00%88%E2%F4%9C%91%16%16%D6%21%8E%A0c%95%A5%A6r%11%E0%A0%82%89%A6%A9%85%AB%D6%E2%065%DB%AF');
+		var nodename = this.ccndid;
+		var interestName = new Name(['ccnx', nodename, 'selfreg', coBinary]);
 
 		var interest = new Interest(interestName);
 		interest.scope = 1;
@@ -713,7 +737,7 @@
         // Make sure the colon came before a '/'.
         var iFirstSlash = name.indexOf('/');
         if (iFirstSlash < 0 || iColon < iFirstSlash)
-            // Omit the leading protocol such as ccnx:
+            // Omit the leading protocol such as ndn:
             name = name.substr(iColon + 1, name.length - iColon - 1).trim();
     }
     
@@ -743,8 +767,9 @@
                 // Zero, one or two periods is illegal.  Ignore this componenent to be
                 //   consistent with the C implmentation.
                 // This also gets rid of a trailing '/'.
-                array = array.slice(0, i).concat(array.slice(i + 1, array.length));
-                --i;                
+                array.splice(i, 1);
+                --i;  
+                continue;
             }
             else
                 // Remove 3 periods.
@@ -819,7 +844,7 @@
 	return this.components.push(result);
 };
 
-// Return the escaped name string according to "CCNx URI Scheme".  Does not include "ccnx:".
+// Return the escaped name string according to "CCNx URI Scheme".
 Name.prototype.to_uri = function() {	
 	var result = "";
 	
@@ -845,6 +870,27 @@
     return result;
 }
 
+/*
+ * The "file name" in a name is the last component that isn't blank and doesn't start with one of the
+ *   special marker octets (for version, etc.).  Return the index in this.components of
+ *   the file name, or -1 if not found.
+ */
+Name.prototype.indexOfFileName = function() {
+    for (var i = this.components.length - 1; i >= 0; --i) {
+        var component = this.components[i];
+        if (component.length <= 0)
+            continue;
+        
+        if (component[0] == 0 || component[0] == 0xC0 || component[0] == 0xC1 || 
+            (component[0] >= 0xF5 && component[0] <= 0xFF))
+            continue;
+        
+        return i;
+    }
+    
+    return -1;
+}
+
 /**
  * Return component as an escaped string according to "CCNx URI Scheme".
  * We can't use encodeURIComponent because that doesn't encode all the characters we want to.
@@ -2074,7 +2120,6 @@
 
 /**
  * Used by NetworkObject to decode the object from a network stream.
- * @see org.ccnx.ccn.impl.encoding.XMLEncodable
  */
 FaceInstance.prototype.from_ccnb = function(//XMLDecoder 
 	decoder) {
@@ -2146,7 +2191,6 @@
 
 /**
  * Used by NetworkObject to encode the object to a network stream.
- * @see org.ccnx.ccn.impl.encoding.XMLEncodable
  */
 FaceInstance.prototype.to_ccnb = function(//XMLEncoder
 	encoder){
@@ -2259,7 +2303,6 @@
 
 		/**
 		 * Used by NetworkObject to encode the object to a network stream.
-		 * @see org.ccnx.ccn.impl.encoding.XMLEncodable
 		 */
 ForwardingEntry.prototype.to_ccnb =function(
 	//XMLEncoder 
@@ -2878,7 +2921,7 @@
 			
 			
 			if ((null ==  decodedTag) || decodedTag != startTag ) {
-				console.log('expecting '+ startag + ' but got '+ decodedTag);
+				console.log('expecting '+ startTag + ' but got '+ decodedTag);
 				throw new ContentDecodingException(new Error("Expected start element: " + startTag + " got: " + decodedTag + "(" + tv.val() + ")"));
 			}
 			
@@ -3432,8 +3475,10 @@
 	this.offset = 0;
     this.level = 0;
     this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
-    this.headerStartOffset = 0;
-    this.readBytesEndOffset = 0;
+    this.headerLength = 0;
+    this.useHeaderBuffer = false;
+    this.headerBuffer = new Uint8Array(5);
+    this.nBytesToRead = 0;
 };
 
 BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE = 0;
@@ -3447,7 +3492,7 @@
  * This throws an exception for badly formed ccnb.
  */
 BinaryXMLStructureDecoder.prototype.findElementEnd = function(
-    // byte array
+    // Uint8Array
     input)
 {
     if (this.gotElementEnd)
@@ -3464,7 +3509,7 @@
         switch (this.state) {
             case BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE:               
                 // First check for XML_CLOSE.
-                if (this.offset == this.headerStartOffset && input[this.offset] == XML_CLOSE) {
+                if (this.headerLength == 0 && input[this.offset] == XML_CLOSE) {
                     ++this.offset;
                     // Close the level.
                     --this.level;
@@ -3476,46 +3521,69 @@
                             (this.offset - 1));
                     
                     // Get ready for the next header.
-                    this.headerStartOffset = this.offset;
+                    this.startHeader();
                     break;
                 }
-
+                
+                var startingHeaderLength = this.headerLength;
                 while (true) {
-                    if (this.offset >= input.length)                    
+                    if (this.offset >= input.length) {
+                        // We can't get all of the header bytes from this input. Save in headerBuffer.
+                        this.useHeaderBuffer = true;
+                        var nNewBytes = this.headerLength - startingHeaderLength;
+                        this.setHeaderBuffer
+                            (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
+                        
                         return false;
-                    if (input[this.offset++] & XML_TT_NO_MORE)
+                    }
+                    var headerByte = input[this.offset++];
+                    ++this.headerLength;
+                    if (headerByte & XML_TT_NO_MORE)
                         // Break and read the header.
                         break;
                 }
-            
-                decoder.seek(this.headerStartOffset);
-                var typeAndVal = decoder.decodeTypeAndVal();
+                
+                var typeAndVal;
+                if (this.useHeaderBuffer) {
+                    // Copy the remaining bytes into headerBuffer.
+                    nNewBytes = this.headerLength - startingHeaderLength;
+                    this.setHeaderBuffer
+                        (input.subarray(this.offset - nNewBytes, nNewBytes), startingHeaderLength);
+
+                    typeAndVal = new BinaryXMLDecoder(this.headerBuffer).decodeTypeAndVal();
+                }
+                else {
+                    // We didn't have to use the headerBuffer.
+                    decoder.seek(this.offset - this.headerLength);
+                    typeAndVal = decoder.decodeTypeAndVal();
+                }
+                
                 if (typeAndVal == null)
                     throw new Error("BinaryXMLStructureDecoder: Can't read header starting at offset " +
-                        this.headerStartOffset);
+                        (this.offset - this.headerLength));
                 
                 // Set the next state based on the type.
                 var type = typeAndVal.t;
                 if (type == XML_DATTR)
                     // We already consumed the item. READ_HEADER_OR_CLOSE again.
                     // ccnb has rules about what must follow an attribute, but we are just scanning.
-                    this.headerStartOffset = this.offset;
+                    this.startHeader();
                 else if (type == XML_DTAG || type == XML_EXT) {
                     // Start a new level and READ_HEADER_OR_CLOSE again.
                     ++this.level;
-                    this.headerStartOffset = this.offset;
+                    this.startHeader();
                 }
                 else if (type == XML_TAG || type == XML_ATTR) {
                     if (type == XML_TAG)
                         // Start a new level and read the tag.
                         ++this.level;
                     // Minimum tag or attribute length is 1.
-                    this.readBytesEndOffset = this.offset + typeAndVal.v + 1;
+                    this.nBytesToRead = typeAndVal.v + 1;
                     this.state = BinaryXMLStructureDecoder.READ_BYTES;
                     // ccnb has rules about what must follow an attribute, but we are just scanning.
                 }
                 else if (type == XML_BLOB || type == XML_UDATA) {
-                    this.readBytesEndOffset = this.offset + typeAndVal.v;
+                    this.nBytesToRead = typeAndVal.v;
                     this.state = BinaryXMLStructureDecoder.READ_BYTES;
                 }
                 else
@@ -3523,15 +3591,16 @@
                 break;
             
             case BinaryXMLStructureDecoder.READ_BYTES:
-                if (input.length < this.readBytesEndOffset) {
+                var nRemainingBytes = input.length - this.offset;
+                if (nRemainingBytes < this.nBytesToRead) {
                     // Need more.
-                    this.offset = input.length;
+                    this.offset += nRemainingBytes;
+                    this.nBytesToRead -= nRemainingBytes;
                     return false;
                 }
                 // Got the bytes.  Read a new header or close.
-                this.offset = this.readBytesEndOffset;
-                this.headerStartOffset = this.offset;
-                this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;
+                this.offset += this.nBytesToRead;
+                this.startHeader();
                 break;
             
             default:
@@ -3540,7 +3609,38 @@
         }
     }
 };
+
 /*
+ * Set the state to READ_HEADER_OR_CLOSE and set up to start reading the header
+ */
+BinaryXMLStructureDecoder.prototype.startHeader = function() {
+    this.headerLength = 0;
+    this.useHeaderBuffer = false;
+    this.state = BinaryXMLStructureDecoder.READ_HEADER_OR_CLOSE;    
+}
+
+/*
+ *  Set the offset into the input, used for the next read.
+ */
+BinaryXMLStructureDecoder.prototype.seek = function(
+        //int
+        offset) {
+    this.offset = offset;
+}
+
+/*
+ * Set call this.headerBuffer.set(subarray, bufferOffset), an reallocate the headerBuffer if needed.
+ */
+BinaryXMLStructureDecoder.prototype.setHeaderBuffer = function(subarray, bufferOffset) {
+    var size = subarray.length + bufferOffset;
+    if (size > this.headerBuffer.length) {
+        // Reallocate the buffer.
+        var newHeaderBuffer = new Uint8Array(size + 5);
+        newHeaderBuffer.set(this.headerBuffer);
+        this.headerBuffer = newHeaderBuffer;
+    }
+    this.headerBuffer.set(subarray, bufferOffset);
+}/*
  * This class contains utilities to help parse the data
  * author: Meki Cheraoui, Jeff Thompson
  * See COPYING for copyright and distribution information.
@@ -3755,12 +3855,12 @@
  * Uint8Array to Hex String
  */
 //http://ejohn.org/blog/numbers-hex-and-colors/
-DataUtils.toHex = function(arguments){
-	if (LOG>4) console.log('ABOUT TO CONVERT '+ arguments);
-	//console.log(arguments);
+DataUtils.toHex = function(args){
+	if (LOG>4) console.log('ABOUT TO CONVERT '+ args);
+	//console.log(args);
   	var ret = "";
-  	for ( var i = 0; i < arguments.length; i++ )
-    	ret += (arguments[i] < 16 ? "0" : "") + arguments[i].toString(16);
+  	for ( var i = 0; i < args.length; i++ )
+    	ret += (args[i] < 16 ? "0" : "") + args[i].toString(16);
   	if (LOG>4) console.log('Converted to: ' + ret);
   	return ret; //.toUpperCase();
 }
@@ -3768,10 +3868,10 @@
 /**
  * Raw string to hex string.
  */
-DataUtils.stringToHex = function(arguments){
+DataUtils.stringToHex = function(args){
 	var ret = "";
-	for (var i = 0; i < arguments.length; ++i) {
-		var value = arguments.charCodeAt(i);
+	for (var i = 0; i < args.length; ++i) {
+		var value = args.charCodeAt(i);
 		ret += (value < 16 ? "0" : "") + value.toString(16);
 	}
 	return ret;
@@ -3780,11 +3880,11 @@
 /**
  * Uint8Array to raw string.
  */
-DataUtils.toString = function(arguments){
+DataUtils.toString = function(args){
   //console.log(arguments);
   var ret = "";
-  for ( var i = 0; i < arguments.length; i++ )
-    ret += String.fromCharCode(arguments[i]);
+  for ( var i = 0; i < args.length; i++ )
+    ret += String.fromCharCode(args[i]);
   return ret;
 }
 
@@ -3834,14 +3934,21 @@
 }
 
 /*
- * Return a new Uint8Array which is the Uint8Array concatenated with raw String str. 
+ * arrays is an array of Uint8Array. Return a new Uint8Array which is the concatenation of all.
  */
-DataUtils.concatFromString = function(array, str) {
-	var bytes = new Uint8Array(array.length + str.length);
-    bytes.set(array);
-	for (var i = 0; i < str.length; ++i)
-		bytes[array.length + i] = str.charCodeAt(i);
-	return bytes;
+DataUtils.concatArrays = function(arrays) {
+    var totalLength = 0;
+	for (var i = 0; i < arrays.length; ++i)
+        totalLength += arrays[i].length;
+    
+    var result = new Uint8Array(totalLength);
+    var offset = 0;
+	for (var i = 0; i < arrays.length; ++i) {
+        result.set(arrays[i], offset);
+        offset += arrays[i].length;
+    }
+    return result;
+    
 }
  
 // TODO: Take Uint8Array and use TextDecoder when available.
@@ -4318,7 +4425,7 @@
 var KeyManager = function KeyManager(){
 
 	
-//Certificate from CCNx
+//Certificate
 
 this.certificate = 'MIIBmzCCAQQCCQC32FyQa61S7jANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwd'+
 
@@ -4341,7 +4448,7 @@
 
 //this.publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQAB';
 this.publicKey ='30819F300D06092A864886F70D010101050003818D0030818902818100E17D30A7D828AB1B840B17542DCAF6207AFD221E086B2A60D16CB7F54448BA9F3F08BCD099DB21DD162A779E61AA89EEE554D3A47DE230BC7AC590D524067C3898BBA6F5DC4360B845EDA48CBD9CF126A723445F0E1952D7325A75FAF556144F9A98AF7186B0278685B8E2C08BEA87171B4DEE585C1828295B5395EB4A17779F0203010001';
-//Private Key from CCNx
+//Private Key
 
 this.privateKey ='MIICXQIBAAKBgQDhfTCn2CirG4QLF1QtyvYgev0iHghrKmDRbLf1REi6nz8IvNCZ2yHdFip3nmGqie7lVNOkfeIwvHrFkNUkBnw4mLum9dxDYLhF7aSMvZzxJqcjRF8OGVLXMlp1+vVWFE+amK9xhrAnhoW44sCL6ocXG03uWFwYKClbU5XrShd3nwIDAQABAoGAGkv6T6jC3WmhFZYL6CdCWvlc6gysmKrhjarrLTxgavtFY6R5g2ft5BXAsCCVbUkWxkIFSKqxpVNl0gKZCNGEzPDN6mHJOQI/h0rlxNIHAuGfoAbCzALnqmyZivhJAPGijAyKuU9tczsst5+Kpn+bn7ehzHQuj7iwJonS5WbojqECQQD851K8TpW2GrRizNgG4dx6orZxAaon/Jnl8lS7soXhllQty7qG+oDfzznmdMsiznCqEABzHUUKOVGE9RWPN3aRAkEA5D/w9N55d0ibnChFJlc8cUAoaqH+w+U3oQP2Lb6AZHJpLptN4y4b/uf5d4wYU5/i/gC7SSBH3wFhh9bjRLUDLwJAVOx8vN0Kqt7myfKNbCo19jxjVSlA8TKCn1Oznl/BU1I+rC4oUaEW25DjmX6IpAR8kq7S59ThVSCQPjxqY/A08QJBAIRaF2zGPITQk3r/VumemCvLWiRK/yG0noc9dtibqHOWbCtcXtOm/xDWjq+lis2i3ssOvYrvrv0/HcDY+Dv1An0CQQCLJtMsfSg4kvG/FRY5UMhtMuwo8ovYcMXt4Xv/LWaMhndD67b2UGawQCRqr5ghRTABWdDD/HuuMBjrkPsX0861';
 
diff --git a/js/util/CCNProtocolDTags.js b/js/util/CCNProtocolDTags.js
index 73af55f..84cd440 100644
--- a/js/util/CCNProtocolDTags.js
+++ b/js/util/CCNProtocolDTags.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class contains all CCNx tags
diff --git a/js/util/CCNTime.js b/js/util/CCNTime.js
index 3e7be6f..e4c8afd 100644
--- a/js/util/CCNTime.js
+++ b/js/util/CCNTime.js
@@ -1,4 +1,4 @@
-/*
+/**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
  * This class represents CCNTime Objects