Fix the bug with WebSocketTransport.send usage: will cause problem with Safari
diff --git a/js/NDN.js b/js/NDN.js
index 90d266c..3d58e1f 100644
--- a/js/NDN.js
+++ b/js/NDN.js
@@ -251,7 +251,7 @@
 				this.onclose();
 				//console.log("NDN.onclose event fired.");
 			} else {
-				//console.log('Connected to ccnd.');
+				console.log('Connected to ccnd.');
 				this.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
 				if (LOG>3) console.log(ndn.ccndid);
 						
diff --git a/js/WebSocketTransport.js b/js/WebSocketTransport.js
index 5f02803..e0c768a 100644
--- a/js/WebSocketTransport.js
+++ b/js/WebSocketTransport.js
@@ -52,7 +52,7 @@
 		// Fetch ccndid now
 		var interest = new Interest(NDN.ccndIdFetcher);
 		interest.interestLifetime = 4000; // milliseconds
-        this.send(encodeToBinaryInterest(interest));
+        self.send(encodeToBinaryInterest(interest));
 	}
 	
 	this.ws.onerror = function(ev) {
diff --git a/js/testing/test-throughput-ws-pipeline.html b/js/testing/test-throughput-ws-pipeline.html
index aa3d64f..a469b40 100644
--- a/js/testing/test-throughput-ws-pipeline.html
+++ b/js/testing/test-throughput-ws-pipeline.html
@@ -10,8 +10,8 @@
 	<script type="text/javascript" src="../tools/build/ndn-js.js"></script>

 

 	<script type="text/javascript">

-		//hostip = "131.179.196.232";

-		hostip = "localhost";

+		hostip = "131.179.196.232";

+		//hostip = "localhost";

 		//var ndncon = new NDN({port:9696,host:hostip});

 		var ndncon = new NDN({port:9696,host:hostip,verify:false});

         ndncon.transport.connectWebSocket(ndncon);

@@ -326,7 +326,7 @@
 

 	<form>

 		Please Enter an Interest:<br />

-		<input id="interest" type="text" name="INTEREST" size="50" value="/wentao.shang/mars/%00" /> 

+		<input id="interest" type="text" name="INTEREST" size="50" value="/wentao.shang/mars.jpg/%00" /> 

 	</form>

 

 	<button onclick="run()">Fetch Content</button>

diff --git a/js/testing/test-throughput-ws.html b/js/testing/test-throughput-ws.html
index 2aefc6d..b059637 100644
--- a/js/testing/test-throughput-ws.html
+++ b/js/testing/test-throughput-ws.html
@@ -10,8 +10,8 @@
 	<script type="text/javascript" src="../tools/build/ndn-js.js"></script>

 

 	<script type="text/javascript">

-		//hostip = "131.179.196.232";

-		hostip = "localhost";

+		hostip = "131.179.196.232";

+		//hostip = "localhost";

 		//var ndncon = new NDN({port:9696,host:hostip});

 		var ndncon = new NDN({port:9696,host:hostip,verify:false});

         ndncon.transport.connectWebSocket(ndncon);

diff --git a/js/tools/build/ndn-js-uncomp.js b/js/tools/build/ndn-js-uncomp.js
index b8df826..d58fb23 100644
--- a/js/tools/build/ndn-js-uncomp.js
+++ b/js/tools/build/ndn-js-uncomp.js
@@ -117,7 +117,7 @@
 		// Fetch ccndid now
 		var interest = new Interest(NDN.ccndIdFetcher);
 		interest.interestLifetime = 4000; // milliseconds
-        this.send(encodeToBinaryInterest(interest));
+        self.send(encodeToBinaryInterest(interest));
 	}
 	
 	this.ws.onerror = function(ev) {
@@ -7752,7 +7752,7 @@
 				this.onclose();
 				//console.log("NDN.onclose event fired.");
 			} else {
-				//console.log('Connected to ccnd.');
+				console.log('Connected to ccnd.');
 				this.ccndid = co.signedInfo.publisher.publisherPublicKeyDigest;
 				if (LOG>3) console.log(ndn.ccndid);
 						
diff --git a/js/tools/build/ndn-js.js b/js/tools/build/ndn-js.js
index 73d2112..e7304c3 100644
--- a/js/tools/build/ndn-js.js
+++ b/js/tools/build/ndn-js.js
@@ -2,7 +2,7 @@
 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 WebSocketTransport=function(){this.elementReader=this.ws=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","E.ws.ndn.ucla.edu"],9696)};
 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";this.elementReader=new BinaryXmlElementReader(a);var b=this;this.ws.onmessage=function(a){a=a.data;if(null==a||void 0==a||""==a)console.log("INVALID ANSWER");else if(a instanceof ArrayBuffer){a=new Uint8Array(a);3<LOG&&console.log("BINARY RESPONSE IS "+DataUtils.toHex(a));try{b.elementReader.onReceivedData(a)}catch(d){console.log("NDN.ws.onmessage exception: "+
-d)}}};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(NDN.ccndIdFetcher);a.interestLifetime=4E3;this.send(encodeToBinaryInterest(a))};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.");
+d)}}};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(NDN.ccndIdFetcher);a.interestLifetime=4E3;b.send(encodeToBinaryInterest(a))};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()}};WebSocketTransport.prototype.send=function(a){if(null!=this.ws){var b=new Uint8Array(a.length);b.set(a);this.ws.send(b.buffer);3<LOG&&console.log("ws.send() returned.")}else console.log("WebSocket connection is not established.")};
 WebSocketTransport.prototype.expressInterest=function(a,b,c){if(a.readyStatus!=NDN.OPENED)console.log("Connection is not established.");else{if(null!=c){var d=new PITEntry(b,c);NDN.PITTable.push(d);c.pitEntry=d}null!=c&&(d.timerID=setTimeout(function(){3<LOG&&console.log("Interest time out.");var e=NDN.PITTable.indexOf(d);0<=e&&NDN.PITTable.splice(e,1);c.upcall(Closure.UPCALL_INTEREST_TIMED_OUT,new UpcallInfo(a,b,0,null))},b.interestLifetime));this.send(encodeToBinaryInterest(b))}};
 var CCNProtocolDTags={Any:13,Name:14,Component:15,Certificate:16,Collection:17,CompleteName:18,Content:19,SignedInfo:20,ContentDigest:21,ContentHash:22,Count:24,Header:25,Interest:26,Key:27,KeyLocator:28,KeyName:29,Length:30,Link:31,LinkAuthenticator:32,NameComponentCount:33,RootDigest:36,Signature:37,Start:38,Timestamp:39,Type:40,Nonce:41,Scope:42,Exclude:43,Bloom:44,BloomSeed:45,AnswerOriginKind:47,InterestLifetime:48,Witness:53,SignatureBits:54,DigestAlgorithm:55,BlockSize:56,FreshnessSeconds:58,
@@ -260,12 +260,12 @@
 NDN.prototype.registerPrefix=function(a,b){if(this.readyStatus!=NDN.OPENED)return console.log("Connection is not established."),-1;if(null==this.ccndid)return console.log("ccnd node ID unkonwn. Cannot register prefix."),-1;var c=new ForwardingEntry("selfreg",a,null,null,3,2147483647),c=encodeForwardingEntry(c),d=new SignedInfo;d.setFields();c=new ContentObject(new Name,d,c,new Signature);c.sign();c=encodeToBinaryContentObject(c);c=new Name(["ccnx",this.ccndid,"selfreg",c]);c=new Interest(c);c.scope=
 1;3<LOG&&console.log("Send Interest registration packet.");d=new CSEntry(a.getName(),b);NDN.CSTable.push(d);this.transport.send(encodeToBinaryInterest(c));return 0};
 NDN.prototype.onReceivedElement=function(a){3<LOG&&console.log("Complete element received. Length "+a.length+". Start decoding.");var b=new BinaryXMLDecoder(a);if(b.peekStartElement(CCNProtocolDTags.Interest))3<LOG&&console.log("Interest packet received."),a=new Interest,a.from_ccnb(b),3<LOG&&console.log(a),b=escape(a.name.getName()),3<LOG&&console.log(b),b=getEntryForRegisteredPrefix(b),null!=b&&(a=new UpcallInfo(this,a,0,null),b.closure.upcall(Closure.UPCALL_INTEREST,a)==Closure.RESULT_INTEREST_CONSUMED&&
-null!=a.contentObject&&this.transport.send(encodeToBinaryContentObject(a.contentObject)));else if(b.peekStartElement(CCNProtocolDTags.ContentObject))if(3<LOG&&console.log("ContentObject packet received."),a=new ContentObject,a.from_ccnb(b),null==this.ccndid&&NDN.ccndIdFetcher.match(a.name))!a.signedInfo||!a.signedInfo.publisher||!a.signedInfo.publisher.publisherPublicKeyDigest?(console.log("Cannot contact router, close NDN now."),this.readyStatus=NDN.CLOSED,this.onclose()):(this.ccndid=a.signedInfo.publisher.publisherPublicKeyDigest,
-3<LOG&&console.log(ndn.ccndid),this.readyStatus=NDN.OPENED,this.onopen());else{var c=NDN.getEntryForExpressedInterest(a.name);if(null!=c)if(b=NDN.PITTable.indexOf(c),0<=b&&NDN.PITTable.splice(b,1),b=c.closure,clearTimeout(c.timerID),!1==this.verify)b.upcall(Closure.UPCALL_CONTENT_UNVERIFIED,new UpcallInfo(this,null,0,a));else{var d=function(a,b,c,d,e){this.contentObject=a;this.closure=b;this.keyName=c;this.sigHex=d;this.witness=e;Closure.call(this)},e=this;d.prototype.upcall=function(a,b){if(a==Closure.UPCALL_INTEREST_TIMED_OUT)console.log("In KeyFetchClosure.upcall: interest time out."),
-console.log(this.keyName.contentName.getName());else if(a==Closure.UPCALL_CONTENT){var c=decodeSubjectPublicKeyInfo(b.contentObject.content),d=!0==c.verifyByteArray(this.contentObject.rawSignatureData,this.witness,this.sigHex)?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD;this.closure.upcall(d,new UpcallInfo(e,null,0,this.contentObject));c=new KeyStoreEntry(g.keyName,c,(new Date).getTime());NDN.addKeyEntry(c)}else a==Closure.UPCALL_CONTENT_BAD&&console.log("In KeyFetchClosure.upcall: signature verification failed")};
-if(a.signedInfo&&a.signedInfo.locator&&a.signature){3<LOG&&console.log("Key verification...");var c=DataUtils.toHex(a.signature.signature).toLowerCase(),f=null;null!=a.signature.Witness&&(f=new Witness,f.decode(a.signature.Witness));var g=a.signedInfo.locator;if(g.type==KeyLocatorType.KEYNAME)if(3<LOG&&console.log("KeyLocator contains KEYNAME"),g.keyName.contentName.match(a.name))3<LOG&&console.log("Content is key itself"),d=decodeSubjectPublicKeyInfo(a.content),c=d.verifyByteArray(a.rawSignatureData,
-f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(c,new UpcallInfo(this,null,0,a));else{var j=NDN.getKeyByName(g.keyName);j?(3<LOG&&console.log("Local key cache hit"),d=j.rsaKey,c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(c,new UpcallInfo(this,null,0,a))):(3<LOG&&console.log("Fetch key according to keylocator"),a=new d(a,b,g.keyName,c,f),this.expressInterest(g.keyName.contentName.getPrefix(4),a))}else g.type==
-KeyLocatorType.KEY?(3<LOG&&console.log("Keylocator contains KEY"),d=decodeSubjectPublicKeyInfo(a.signedInfo.locator.publicKey),c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(Closure.UPCALL_CONTENT,new UpcallInfo(this,null,0,a))):(a=g.certificate,console.log("KeyLocator contains CERT"),console.log(a))}}}else console.log("Incoming packet is not Interest or ContentObject. Discard now.")};
+null!=a.contentObject&&this.transport.send(encodeToBinaryContentObject(a.contentObject)));else if(b.peekStartElement(CCNProtocolDTags.ContentObject))if(3<LOG&&console.log("ContentObject packet received."),a=new ContentObject,a.from_ccnb(b),null==this.ccndid&&NDN.ccndIdFetcher.match(a.name))!a.signedInfo||!a.signedInfo.publisher||!a.signedInfo.publisher.publisherPublicKeyDigest?(console.log("Cannot contact router, close NDN now."),this.readyStatus=NDN.CLOSED,this.onclose()):(console.log("Connected to ccnd."),
+this.ccndid=a.signedInfo.publisher.publisherPublicKeyDigest,3<LOG&&console.log(ndn.ccndid),this.readyStatus=NDN.OPENED,this.onopen());else{var c=NDN.getEntryForExpressedInterest(a.name);if(null!=c)if(b=NDN.PITTable.indexOf(c),0<=b&&NDN.PITTable.splice(b,1),b=c.closure,clearTimeout(c.timerID),!1==this.verify)b.upcall(Closure.UPCALL_CONTENT_UNVERIFIED,new UpcallInfo(this,null,0,a));else{var d=function(a,b,c,d,e){this.contentObject=a;this.closure=b;this.keyName=c;this.sigHex=d;this.witness=e;Closure.call(this)},
+e=this;d.prototype.upcall=function(a,b){if(a==Closure.UPCALL_INTEREST_TIMED_OUT)console.log("In KeyFetchClosure.upcall: interest time out."),console.log(this.keyName.contentName.getName());else if(a==Closure.UPCALL_CONTENT){var c=decodeSubjectPublicKeyInfo(b.contentObject.content),d=!0==c.verifyByteArray(this.contentObject.rawSignatureData,this.witness,this.sigHex)?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD;this.closure.upcall(d,new UpcallInfo(e,null,0,this.contentObject));c=new KeyStoreEntry(g.keyName,
+c,(new Date).getTime());NDN.addKeyEntry(c)}else a==Closure.UPCALL_CONTENT_BAD&&console.log("In KeyFetchClosure.upcall: signature verification failed")};if(a.signedInfo&&a.signedInfo.locator&&a.signature){3<LOG&&console.log("Key verification...");var c=DataUtils.toHex(a.signature.signature).toLowerCase(),f=null;null!=a.signature.Witness&&(f=new Witness,f.decode(a.signature.Witness));var g=a.signedInfo.locator;if(g.type==KeyLocatorType.KEYNAME)if(3<LOG&&console.log("KeyLocator contains KEYNAME"),g.keyName.contentName.match(a.name))3<
+LOG&&console.log("Content is key itself"),d=decodeSubjectPublicKeyInfo(a.content),c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(c,new UpcallInfo(this,null,0,a));else{var j=NDN.getKeyByName(g.keyName);j?(3<LOG&&console.log("Local key cache hit"),d=j.rsaKey,c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(c,new UpcallInfo(this,null,0,a))):(3<LOG&&console.log("Fetch key according to keylocator"),
+a=new d(a,b,g.keyName,c,f),this.expressInterest(g.keyName.contentName.getPrefix(4),a))}else g.type==KeyLocatorType.KEY?(3<LOG&&console.log("Keylocator contains KEY"),d=decodeSubjectPublicKeyInfo(a.signedInfo.locator.publicKey),c=d.verifyByteArray(a.rawSignatureData,f,c),c=!0==c?Closure.UPCALL_CONTENT:Closure.UPCALL_CONTENT_BAD,b.upcall(Closure.UPCALL_CONTENT,new UpcallInfo(this,null,0,a))):(a=g.certificate,console.log("KeyLocator contains CERT"),console.log(a))}}}else console.log("Incoming packet is not Interest or ContentObject. Discard now.")};
 NDN.prototype.connectAndExpressInterest=function(a,b){var c=this.getHostAndPort();if(null==c)console.log("ERROR: No more hosts from getHostAndPort"),this.host=null;else if(c.host==this.host&&c.port==this.port)console.log("ERROR: The host returned by getHostAndPort is not alive: "+this.host+":"+this.port);else{this.host=c.host;this.port=c.port;console.log("Trying host from getHostAndPort: "+this.host);c=new Interest(new Name("/"));c.interestLifetime=4E3;var d=this,e=setTimeout(function(){console.log("Timeout waiting for host "+
 d.host);d.connectAndExpressInterest(a,b)},3E3);this.transport.expressInterest(this,c,new NDN.ConnectClosure(this,a,b,e))}};NDN.ConnectClosure=function(a,b,c,d){Closure.call(this);this.ndn=a;this.callerInterest=b;this.callerClosure=c;this.timerID=d};
 NDN.ConnectClosure.prototype.upcall=function(a){if(!(a==Closure.UPCALL_CONTENT||a==Closure.UPCALL_CONTENT_UNVERIFIED))return Closure.RESULT_ERR;clearTimeout(this.timerID);console.log(this.ndn.host+": Host is alive. Fetching callerInterest.");this.ndn.transport.expressInterest(this.ndn,this.callerInterest,this.callerClosure);return Closure.RESULT_OK};var BinaryXmlElementReader=function(a){this.elementListener=a;this.dataParts=[];this.structureDecoder=new BinaryXMLStructureDecoder};