In Interest.matches_name used to match interests in the PITTable, added a check for minSuffixComponents, maxSuffixComponents and exclude.
This helps to call the correct closure callback.
diff --git a/js/Interest.js b/js/Interest.js
index 3d91de5..8c8ecf1 100644
--- a/js/Interest.js
+++ b/js/Interest.js
@@ -114,8 +114,26 @@
 
 };
 
+/*
+ * Return true if this.name.match(name) and the name conforms to the interest selectors.
+ */
 Interest.prototype.matches_name = function(/*Name*/ name) {
-    return this.name.match(name);
+    if (!this.name.match(name))
+        return false;
+    
+    if (this.minSuffixComponents != null &&
+        // Add 1 for the implicit digest.
+        !(name.components.length + 1 - this.name.components.length >= this.minSuffixComponents))
+        return false;
+    if (this.maxSuffixComponents != null &&
+        // Add 1 for the implicit digest.
+        !(name.components.length + 1 - this.name.components.length <= this.maxSuffixComponents))
+        return false;
+    if (this.exclude != null && name.components.length > this.name.components.length &&
+        this.exclude.matches(name.components[this.name.components.length]))
+        return false;
+    
+    return true;
 }
 
 /*
@@ -170,7 +188,9 @@
 	encoder.writeEndElement();
 };
 
-// Return a string with elements separated by "," and Exclude.ANY shown as "*".
+/*
+ * Return a string with elements separated by "," and Exclude.ANY shown as "*". 
+ */
 Exclude.prototype.to_uri = function() {
 	if (this.values == null || this.values.length == 0)
 		return "";
@@ -187,3 +207,78 @@
     }
     return result;
 };
+
+/*
+ * Return true if the component matches any of the exclude criteria.
+ */
+Exclude.prototype.matches = function(/*Uint8Array*/ component) {
+    for (var i = 0; i < this.values.length; ++i) {
+        if (this.values[i] == Exclude.ANY) {
+            var lowerBound = null;
+            if (i > 0)
+                lowerBound = this.values[i - 1];
+            
+            // Find the upper bound, possibly skipping over multiple ANY in a row.
+            var iUpperBound;
+            var upperBound = null;
+            for (iUpperBound = i + 1; iUpperBound < this.values.length; ++iUpperBound) {
+                if (this.values[iUpperBound] != Exclude.ANY) {
+                    upperBound = this.values[iUpperBound];
+                    break;
+                }
+            }
+            
+            // If lowerBound != null, we already checked component equals lowerBound on the last pass.
+            // If upperBound != null, we will check component equals upperBound on the next pass.
+            if (upperBound != null) {
+                if (lowerBound != null) {
+                    if (Exclude.compareComponents(component, lowerBound) > 0 &&
+                        Exclude.compareComponents(component, upperBound) < 0)
+                        return true;
+                }
+                else {
+                    if (Exclude.compareComponents(component, upperBound) < 0)
+                        return true;
+                }
+                
+                // Make i equal iUpperBound on the next pass.
+                i = iUpperBound - 1;
+            }
+            else {
+                if (lowerBound != null) {
+                    if (Exclude.compareComponents(component, lowerBound) > 0)
+                        return true;
+                }
+                else
+                    // this.values has only ANY.
+                    return true;
+            }
+        }
+        else {
+            if (DataUtils.arraysEqual(component, this.values[i]))
+                return true;
+        }
+    }
+    
+    return false;
+};
+
+/*
+ * Return -1 if component1 is less than component2, 1 if greater or 0 if equal.
+ * A component is less if it is shorter, otherwise if equal length do a byte comparison.
+ */
+Exclude.compareComponents = function(/*Uint8Array*/ component1, /*Uint8Array*/ component2) {
+    if (component1.length < component2.length)
+        return -1;
+    if (component1.length > component2.length)
+        return 1;
+    
+    for (var i = 0; i < component1.length; ++i) {
+        if (component1[i] < component2[i])
+            return -1;
+        if (component1[i] > component2[i])
+            return 1;
+    }
+
+    return 0;
+};
diff --git a/js/NDN.js b/js/NDN.js
index 9e76e4a..e6e1a37 100644
--- a/js/NDN.js
+++ b/js/NDN.js
@@ -86,10 +86,11 @@
 	this.timerID = -1;  // Timer ID
 };
 
-// Return the longest entry from NDN.PITTable that matches name.
+/*
+ * Return the entry from NDN.PITTable where the name conforms to the interest selectors, and
+ * the interest name is the longest that matches name.
+ */
 NDN.getEntryForExpressedInterest = function(/*Name*/ name) {
-    // TODO: handle multiple matches?  Maybe not from registerPrefix because multiple ContentObject
-    //   could be sent for one Interest?
     var result = null;
     
 	for (var i = 0; i < NDN.PITTable.length; i++) {
diff --git a/js/ndnProtocol.xpi b/js/ndnProtocol.xpi
index 0b7fc58..298aad1 100644
--- a/js/ndnProtocol.xpi
+++ b/js/ndnProtocol.xpi
Binary files differ
diff --git a/js/ndnProtocol/modules/ndn-js.jsm b/js/ndnProtocol/modules/ndn-js.jsm
index 200fc41..a444697 100644
--- a/js/ndnProtocol/modules/ndn-js.jsm
+++ b/js/ndnProtocol/modules/ndn-js.jsm
@@ -88,10 +88,12 @@
 a.peekStartElement(CCNProtocolDTags.InterestLifetime)&&(this.interestLifetime=1E3*DataUtils.bigEndianToUnsignedInt(a.readBinaryElement(CCNProtocolDTags.InterestLifetime))/4096);a.peekStartElement(CCNProtocolDTags.Nonce)&&(this.nonce=a.readBinaryElement(CCNProtocolDTags.Nonce));a.readEndElement()};
 Interest.prototype.to_ccnb=function(a){a.writeStartElement(CCNProtocolDTags.Interest);this.name.to_ccnb(a);null!=this.minSuffixComponents&&a.writeElement(CCNProtocolDTags.MinSuffixComponents,this.minSuffixComponents);null!=this.maxSuffixComponents&&a.writeElement(CCNProtocolDTags.MaxSuffixComponents,this.maxSuffixComponents);null!=this.publisherPublicKeyDigest&&this.publisherPublicKeyDigest.to_ccnb(a);null!=this.exclude&&this.exclude.to_ccnb(a);null!=this.childSelector&&a.writeElement(CCNProtocolDTags.ChildSelector,
 this.childSelector);this.DEFAULT_ANSWER_ORIGIN_KIND!=this.answerOriginKind&&null!=this.answerOriginKind&&a.writeElement(CCNProtocolDTags.AnswerOriginKind,this.answerOriginKind);null!=this.scope&&a.writeElement(CCNProtocolDTags.Scope,this.scope);null!=this.interestLifetime&&a.writeElement(CCNProtocolDTags.InterestLifetime,DataUtils.nonNegativeIntToBigEndian(4096*(this.interestLifetime/1E3)));null!=this.nonce&&a.writeElement(CCNProtocolDTags.Nonce,this.nonce);a.writeEndElement()};
-Interest.prototype.matches_name=function(a){return this.name.match(a)};var Exclude=function(a){this.values=a||[]};Exclude.ANY="*";
+Interest.prototype.matches_name=function(a){return!this.name.match(a)||null!=this.minSuffixComponents&&!(a.components.length+1-this.name.components.length>=this.minSuffixComponents)||null!=this.maxSuffixComponents&&!(a.components.length+1-this.name.components.length<=this.maxSuffixComponents)||null!=this.exclude&&a.components.length>this.name.components.length&&this.exclude.matches(a.components[this.name.components.length])?!1:!0};var Exclude=function(a){this.values=a||[]};Exclude.ANY="*";
 Exclude.prototype.from_ccnb=function(a){for(a.readStartElement(CCNProtocolDTags.Exclude);;)if(a.peekStartElement(CCNProtocolDTags.Component))this.values.push(a.readBinaryElement(CCNProtocolDTags.Component));else if(a.peekStartElement(CCNProtocolDTags.Any))a.readStartElement(CCNProtocolDTags.Any),a.readEndElement(),this.values.push(Exclude.ANY);else if(a.peekStartElement(CCNProtocolDTags.Bloom))a.readBinaryElement(CCNProtocolDTags.Bloom),this.values.push(Exclude.ANY);else break;a.readEndElement()};
 Exclude.prototype.to_ccnb=function(a){if(!(null==this.values||0==this.values.length)){a.writeStartElement(CCNProtocolDTags.Exclude);for(var b=0;b<this.values.length;++b)this.values[b]==Exclude.ANY?(a.writeStartElement(CCNProtocolDTags.Any),a.writeEndElement()):a.writeElement(CCNProtocolDTags.Component,this.values[b]);a.writeEndElement()}};
 Exclude.prototype.to_uri=function(){if(null==this.values||0==this.values.length)return"";for(var a="",b=0;b<this.values.length;++b)0<b&&(a+=","),a=this.values[b]==Exclude.ANY?a+"*":a+Name.toEscapedString(this.values[b]);return a};
+Exclude.prototype.matches=function(a){for(var b=0;b<this.values.length;++b)if(this.values[b]==Exclude.ANY){var c=null;0<b&&(c=this.values[b-1]);var d,e=null;for(d=b+1;d<this.values.length;++d)if(this.values[d]!=Exclude.ANY){e=this.values[d];break}if(null!=e){if(null!=c){if(0<Exclude.compareComponents(a,c)&&0>Exclude.compareComponents(a,e))return!0}else if(0>Exclude.compareComponents(a,e))return!0;b=d-1}else if(null!=c){if(0<Exclude.compareComponents(a,c))return!0}else return!0}else if(DataUtils.arraysEqual(a,
+this.values[b]))return!0;return!1};Exclude.compareComponents=function(a,b){if(a.length<b.length)return-1;if(a.length>b.length)return 1;for(var c=0;c<a.length;++c){if(a[c]<b[c])return-1;if(a[c]>b[c])return 1}return 0};
 var Key=function(){},KeyLocatorType={KEY:1,CERTIFICATE:2,KEYNAME:3},KeyLocator=function(a,b){this.type=b;b==KeyLocatorType.KEYNAME?(3<LOG&&console.log("KeyLocator: SET KEYNAME"),this.keyName=a):b==KeyLocatorType.KEY?(3<LOG&&console.log("KeyLocator: SET KEY"),this.publicKey=a):b==KeyLocatorType.CERTIFICATE&&(3<LOG&&console.log("KeyLocator: SET CERTIFICATE"),this.certificate=a)};
 KeyLocator.prototype.from_ccnb=function(a){a.readStartElement(this.getElementLabel());if(a.peekStartElement(CCNProtocolDTags.Key)){try{this.publicKey=encodedKey=a.readBinaryElement(CCNProtocolDTags.Key),this.type=KeyLocatorType.KEY,4<LOG&&console.log("PUBLIC KEY FOUND: "+this.publicKey)}catch(b){throw Error("Cannot parse key: ",b);}if(null==this.publicKey)throw Error("Cannot parse key: ");}else if(a.peekStartElement(CCNProtocolDTags.Certificate)){try{this.certificate=encodedCert=a.readBinaryElement(CCNProtocolDTags.Certificate),
 this.type=KeyLocatorType.CERTIFICATE,4<LOG&&console.log("CERTIFICATE FOUND: "+this.certificate)}catch(c){throw Error("Cannot decode certificate: "+c);}if(null==this.certificate)throw Error("Cannot parse certificate! ");}else this.type=KeyLocatorType.KEYNAME,this.keyName=new KeyName,this.keyName.from_ccnb(a);a.readEndElement()};
@@ -294,7 +296,7 @@
 NDN.makeShuffledGetHostAndPort=function(a,b){a=a.slice(0,a.length);DataUtils.shuffle(a);return function(){return 0==a.length?null:{host:a.splice(0,1)[0],port:b}}};
 NDN.prototype.expressInterest=function(a,b,c){var d=new Interest(a);null!=c?(d.minSuffixComponents=c.minSuffixComponents,d.maxSuffixComponents=c.maxSuffixComponents,d.publisherPublicKeyDigest=c.publisherPublicKeyDigest,d.exclude=c.exclude,d.childSelector=c.childSelector,d.answerOriginKind=c.answerOriginKind,d.scope=c.scope,d.interestLifetime=c.interestLifetime):d.interestLifetime=4E3;if(null==this.host||null==this.port)if(null==this.getHostAndPort)console.log("ERROR: host OR port NOT SET");else{var e=
 this;this.connectAndExecute(function(){e.reconnectAndExpressInterest(d,b)})}else this.reconnectAndExpressInterest(d,b)};NDN.prototype.reconnectAndExpressInterest=function(a,b){if(this.transport.connectedHost!=this.host||this.transport.connectedPort!=this.port){var c=this;this.transport.connect(c,function(){c.expressInterestHelper(a,b)})}else this.expressInterestHelper(a,b)};
-NDN.prototype.expressInterestHelper=function(a,b){if(null!=b){var c=new PITEntry(a,b);NDN.PITTable.push(c);b.pitEntry=c}var d=this;null!=b&&(c.timerID=setTimeout(function(){3<LOG&&console.log("Interest time out.");var e=NDN.PITTable.indexOf(c);0<=e&&NDN.PITTable.splice(e,1);b.upcall(Closure.UPCALL_INTEREST_TIMED_OUT,new UpcallInfo(d,a,0,null))},a.interestLifetime));this.transport.send(encodeToBinaryInterest(a))};
+NDN.prototype.expressInterestHelper=function(a,b){if(null!=b){var c=new PITEntry(a,b);NDN.PITTable.push(c);b.pitEntry=c}var d=this;null!=b&&(c.timerID=setTimeout(function(){3<LOG&&console.log("Interest time out.");var e=NDN.PITTable.indexOf(c);0<=e&&NDN.PITTable.splice(e,1);b.upcall(Closure.UPCALL_INTEREST_TIMED_OUT,new UpcallInfo(d,a,0,null))},a.interestLifetime||4E3));this.transport.send(encodeToBinaryInterest(a))};
 NDN.prototype.registerPrefix=function(a,b,c){var d=this,e=function(){if(null==d.ccndid){var e=new Interest(NDN.ccndIdFetcher);e.interestLifetime=4E3;3<LOG&&console.log("Expressing interest for ccndid from ccnd.");d.reconnectAndExpressInterest(e,new NDN.FetchCcndidClosure(d,a,b,c))}else d.registerPrefixHelper(a,b,c)};null==this.host||null==this.port?null==this.getHostAndPort?console.log("ERROR: host OR port NOT SET"):this.connectAndExecute(e):e()};
 NDN.FetchCcndidClosure=function(a,b,c,d){Closure.call(this);this.ndn=a;this.name=b;this.callerClosure=c;this.flag=d};
 NDN.FetchCcndidClosure.prototype.upcall=function(a,b){if(a==Closure.UPCALL_INTEREST_TIMED_OUT)return console.log("Timeout while requesting the ccndid.  Cannot registerPrefix for "+this.name.to_uri()+" ."),Closure.RESULT_OK;if(!(a==Closure.UPCALL_CONTENT||a==Closure.UPCALL_CONTENT_UNVERIFIED))return Closure.RESULT_ERR;var c=b.contentObject;!c.signedInfo||!c.signedInfo.publisher||!c.signedInfo.publisher.publisherPublicKeyDigest?console.log("ContentObject doesn't have a publisherPublicKeyDigest. Cannot set ccndid and registerPrefix for "+
diff --git a/js/testing/test-PIT-matching.html b/js/testing/test-PIT-matching.html
new file mode 100644
index 0000000..4ccac10
--- /dev/null
+++ b/js/testing/test-PIT-matching.html
@@ -0,0 +1,148 @@
+<?xml version = "1.0" encoding="utf-8" ?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

+"DTD/xhtml1-strict.dtd">

+<!-- 

+	See COPYING for copyright and distribution information.

+-->

+<html xmlns = "http://www.w3.org/1999/xhtml">

+<meta charset="UTF-8"/>

+

+<head>

+	<title>NDN PIT Matching</title>

+	

+	<script type="text/javascript" src="../Helper.js"></script>

+

+	<script type="text/javascript">

+		var ndn = new NDN({verify:false});

+        

+        var AsyncGetClosure = function AsyncGetClosure(target) {

+        	// Inherit from Closure.

+			Closure.call(this);

+            

+            this.target = target;

+		};

+		

+		AsyncGetClosure.prototype.upcall = function(kind, upcallInfo) {

+			if (kind == Closure.UPCALL_CONTENT || kind == Closure.UPCALL_CONTENT_UNVERIFIED) {

+				document.getElementById(this.target).innerHTML = 

+                    DataUtils.toString(upcallInfo.contentObject.content);

+                return Closure.RESULT_OK;

+            }

+            else

+                return Closure.RESULT_ERR;

+		};

+		

+        var name = new Name("/ndn/ucla.edu/apps/ndn-js-test/hello.txt");

+        

+        var interestSelector1 = new Interest();

+        interestSelector1.interestLifetime = 10000;

+        interestSelector1.minSuffixComponents = 3;

+        interestSelector1.maxSuffixComponents = 3;

+        

+        var interestSelector2 = new Interest();

+        interestSelector2.interestLifetime = 10000;

+        interestSelector2.minSuffixComponents = 4;

+        interestSelector2.maxSuffixComponents = 4;

+

+        var interestSelector3 = new Interest();

+        interestSelector3.interestLifetime = 10000;

+        interestSelector3.exclude = new Exclude([Exclude.ANY, DataUtils.toNumbersFromString("zzzzzz")]);

+

+        var interestSelector4 = new Interest();

+        interestSelector4.interestLifetime = 10000;

+        interestSelector4.exclude = new Exclude([DataUtils.toNumbersFromString("zzzzzz"), Exclude.ANY]);

+

+		function run() {

+            ndn.onopen = function() {

+              for (var i = 0; i < 10; ++i) {

+                // "col1Content0" is already fetched.

+                if (i != 0)

+                    ndn.expressInterest(name, new AsyncGetClosure("col1Content" + i), interestSelector1);

+                ndn.expressInterest(name, new AsyncGetClosure("col2Content" + i), interestSelector2);

+                ndn.expressInterest(name, new AsyncGetClosure("col3Content" + i), interestSelector3);

+                ndn.expressInterest(name, new AsyncGetClosure("col4Content" + i), interestSelector4);

+              }

+              // For testing, make sure we don't just process in the order returned.

+              DataUtils.shuffle(NDN.PITTable);

+            };

+            

+			ndn.expressInterest(name, new AsyncGetClosure("col1Content0"), interestSelector1);

+		}

+	</script>	

+</head>

+<body >

+  <button id="runBtn" onclick="run()">Run</button>

+  <table style="text-align: left;" border="1" cellpadding="2" cellspacing="0">

+  <tbody>

+    <tr>

+      <td style="vertical-align: top;">minSuffixComponents=3,<br/>maxSuffixComponents=3<br/>should be:<br/>

+                                       hello</td>

+      <td style="vertical-align: top;">minSuffixComponents=4,<br/>maxSuffixComponents=4<br/>should be:<br/>

+                                       hello world</td>

+      <td style="vertical-align: top;">exclude=*,zzzzzz<br/><br/>should be:<br/>hello</td>

+      <td style="vertical-align: top;">exclude=zzzzzz,*<br/><br/>should be:<br/>hello world</td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content0"/></td>

+      <td style="vertical-align: top;"><div id="col2Content0"/></td>

+      <td style="vertical-align: top;"><div id="col3Content0"/></td>

+      <td style="vertical-align: top;"><div id="col4Content0"/></td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content1"/></td>

+      <td style="vertical-align: top;"><div id="col2Content1"/></td>

+      <td style="vertical-align: top;"><div id="col3Content1"/></td>

+      <td style="vertical-align: top;"><div id="col4Content1"/></td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content2"/></td>

+      <td style="vertical-align: top;"><div id="col2Content2"/></td>

+      <td style="vertical-align: top;"><div id="col3Content2"/></td>

+      <td style="vertical-align: top;"><div id="col4Content2"/></td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content3"/></td>

+      <td style="vertical-align: top;"><div id="col2Content3"/></td>

+      <td style="vertical-align: top;"><div id="col3Content3"/></td>

+      <td style="vertical-align: top;"><div id="col4Content3"/></td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content4"/></td>

+      <td style="vertical-align: top;"><div id="col2Content4"/></td>

+      <td style="vertical-align: top;"><div id="col3Content4"/></td>

+      <td style="vertical-align: top;"><div id="col4Content4"/></td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content5"/></td>

+      <td style="vertical-align: top;"><div id="col2Content5"/></td>

+      <td style="vertical-align: top;"><div id="col3Content5"/></td>

+      <td style="vertical-align: top;"><div id="col4Content5"/></td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content6"/></td>

+      <td style="vertical-align: top;"><div id="col2Content6"/></td>

+      <td style="vertical-align: top;"><div id="col3Content6"/></td>

+      <td style="vertical-align: top;"><div id="col4Content6"/></td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content7"/></td>

+      <td style="vertical-align: top;"><div id="col2Content7"/></td>

+      <td style="vertical-align: top;"><div id="col3Content7"/></td>

+      <td style="vertical-align: top;"><div id="col4Content7"/></td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content8"/></td>

+      <td style="vertical-align: top;"><div id="col2Content8"/></td>

+      <td style="vertical-align: top;"><div id="col3Content8"/></td>

+      <td style="vertical-align: top;"><div id="col4Content8"/></td>

+    </tr>

+    <tr>

+      <td style="vertical-align: top;"><div id="col1Content9"/></td>

+      <td style="vertical-align: top;"><div id="col2Content9"/></td>

+      <td style="vertical-align: top;"><div id="col3Content9"/></td>

+      <td style="vertical-align: top;"><div id="col4Content9"/></td>

+    </tr>

+  </tbody>

+  </table>	

+</body>

+</html>

diff --git a/js/tools/build/ndn-js-uncomp.js b/js/tools/build/ndn-js-uncomp.js
index 469a0e5..bb22c6a 100644
--- a/js/tools/build/ndn-js-uncomp.js
+++ b/js/tools/build/ndn-js-uncomp.js
@@ -1431,8 +1431,26 @@
 
 };
 
+/*
+ * Return true if this.name.match(name) and the name conforms to the interest selectors.
+ */
 Interest.prototype.matches_name = function(/*Name*/ name) {
-    return this.name.match(name);
+    if (!this.name.match(name))
+        return false;
+    
+    if (this.minSuffixComponents != null &&
+        // Add 1 for the implicit digest.
+        !(name.components.length + 1 - this.name.components.length >= this.minSuffixComponents))
+        return false;
+    if (this.maxSuffixComponents != null &&
+        // Add 1 for the implicit digest.
+        !(name.components.length + 1 - this.name.components.length <= this.maxSuffixComponents))
+        return false;
+    if (this.exclude != null && name.components.length > this.name.components.length &&
+        this.exclude.matches(name.components[this.name.components.length]))
+        return false;
+    
+    return true;
 }
 
 /*
@@ -1487,7 +1505,9 @@
 	encoder.writeEndElement();
 };
 
-// Return a string with elements separated by "," and Exclude.ANY shown as "*".
+/*
+ * Return a string with elements separated by "," and Exclude.ANY shown as "*". 
+ */
 Exclude.prototype.to_uri = function() {
 	if (this.values == null || this.values.length == 0)
 		return "";
@@ -1504,6 +1524,81 @@
     }
     return result;
 };
+
+/*
+ * Return true if the component matches any of the exclude criteria.
+ */
+Exclude.prototype.matches = function(/*Uint8Array*/ component) {
+    for (var i = 0; i < this.values.length; ++i) {
+        if (this.values[i] == Exclude.ANY) {
+            var lowerBound = null;
+            if (i > 0)
+                lowerBound = this.values[i - 1];
+            
+            // Find the upper bound, possibly skipping over multiple ANY in a row.
+            var iUpperBound;
+            var upperBound = null;
+            for (iUpperBound = i + 1; iUpperBound < this.values.length; ++iUpperBound) {
+                if (this.values[iUpperBound] != Exclude.ANY) {
+                    upperBound = this.values[iUpperBound];
+                    break;
+                }
+            }
+            
+            // If lowerBound != null, we already checked component equals lowerBound on the last pass.
+            // If upperBound != null, we will check component equals upperBound on the next pass.
+            if (upperBound != null) {
+                if (lowerBound != null) {
+                    if (Exclude.compareComponents(component, lowerBound) > 0 &&
+                        Exclude.compareComponents(component, upperBound) < 0)
+                        return true;
+                }
+                else {
+                    if (Exclude.compareComponents(component, upperBound) < 0)
+                        return true;
+                }
+                
+                // Make i equal iUpperBound on the next pass.
+                i = iUpperBound - 1;
+            }
+            else {
+                if (lowerBound != null) {
+                    if (Exclude.compareComponents(component, lowerBound) > 0)
+                        return true;
+                }
+                else
+                    // this.values has only ANY.
+                    return true;
+            }
+        }
+        else {
+            if (DataUtils.arraysEqual(component, this.values[i]))
+                return true;
+        }
+    }
+    
+    return false;
+};
+
+/*
+ * Return -1 if component1 is less than component2, 1 if greater or 0 if equal.
+ * A component is less if it is shorter, otherwise if equal length do a byte comparison.
+ */
+Exclude.compareComponents = function(/*Uint8Array*/ component1, /*Uint8Array*/ component2) {
+    if (component1.length < component2.length)
+        return -1;
+    if (component1.length > component2.length)
+        return 1;
+    
+    for (var i = 0; i < component1.length; ++i) {
+        if (component1[i] < component2[i])
+            return -1;
+        if (component1[i] > component2[i])
+            return 1;
+    }
+
+    return 0;
+};
 /**
  * @author: Meki Cheraoui
  * See COPYING for copyright and distribution information.
@@ -7544,10 +7639,11 @@
 	this.timerID = -1;  // Timer ID
 };
 
-// Return the longest entry from NDN.PITTable that matches name.
+/*
+ * Return the entry from NDN.PITTable where the name conforms to the interest selectors, and
+ * the interest name is the longest that matches name.
+ */
 NDN.getEntryForExpressedInterest = function(/*Name*/ name) {
-    // TODO: handle multiple matches?  Maybe not from registerPrefix because multiple ContentObject
-    //   could be sent for one Interest?
     var result = null;
     
 	for (var i = 0; i < NDN.PITTable.length; i++) {
diff --git a/js/tools/build/ndn-js.js b/js/tools/build/ndn-js.js
index b1a9e17..e6a4ef6 100644
--- a/js/tools/build/ndn-js.js
+++ b/js/tools/build/ndn-js.js
@@ -52,10 +52,12 @@
 a.peekStartElement(CCNProtocolDTags.InterestLifetime)&&(this.interestLifetime=1E3*DataUtils.bigEndianToUnsignedInt(a.readBinaryElement(CCNProtocolDTags.InterestLifetime))/4096);a.peekStartElement(CCNProtocolDTags.Nonce)&&(this.nonce=a.readBinaryElement(CCNProtocolDTags.Nonce));a.readEndElement()};
 Interest.prototype.to_ccnb=function(a){a.writeStartElement(CCNProtocolDTags.Interest);this.name.to_ccnb(a);null!=this.minSuffixComponents&&a.writeElement(CCNProtocolDTags.MinSuffixComponents,this.minSuffixComponents);null!=this.maxSuffixComponents&&a.writeElement(CCNProtocolDTags.MaxSuffixComponents,this.maxSuffixComponents);null!=this.publisherPublicKeyDigest&&this.publisherPublicKeyDigest.to_ccnb(a);null!=this.exclude&&this.exclude.to_ccnb(a);null!=this.childSelector&&a.writeElement(CCNProtocolDTags.ChildSelector,
 this.childSelector);this.DEFAULT_ANSWER_ORIGIN_KIND!=this.answerOriginKind&&null!=this.answerOriginKind&&a.writeElement(CCNProtocolDTags.AnswerOriginKind,this.answerOriginKind);null!=this.scope&&a.writeElement(CCNProtocolDTags.Scope,this.scope);null!=this.interestLifetime&&a.writeElement(CCNProtocolDTags.InterestLifetime,DataUtils.nonNegativeIntToBigEndian(4096*(this.interestLifetime/1E3)));null!=this.nonce&&a.writeElement(CCNProtocolDTags.Nonce,this.nonce);a.writeEndElement()};
-Interest.prototype.matches_name=function(a){return this.name.match(a)};var Exclude=function(a){this.values=a||[]};Exclude.ANY="*";
+Interest.prototype.matches_name=function(a){return!this.name.match(a)||null!=this.minSuffixComponents&&!(a.components.length+1-this.name.components.length>=this.minSuffixComponents)||null!=this.maxSuffixComponents&&!(a.components.length+1-this.name.components.length<=this.maxSuffixComponents)||null!=this.exclude&&a.components.length>this.name.components.length&&this.exclude.matches(a.components[this.name.components.length])?!1:!0};var Exclude=function(a){this.values=a||[]};Exclude.ANY="*";
 Exclude.prototype.from_ccnb=function(a){for(a.readStartElement(CCNProtocolDTags.Exclude);;)if(a.peekStartElement(CCNProtocolDTags.Component))this.values.push(a.readBinaryElement(CCNProtocolDTags.Component));else if(a.peekStartElement(CCNProtocolDTags.Any))a.readStartElement(CCNProtocolDTags.Any),a.readEndElement(),this.values.push(Exclude.ANY);else if(a.peekStartElement(CCNProtocolDTags.Bloom))a.readBinaryElement(CCNProtocolDTags.Bloom),this.values.push(Exclude.ANY);else break;a.readEndElement()};
 Exclude.prototype.to_ccnb=function(a){if(!(null==this.values||0==this.values.length)){a.writeStartElement(CCNProtocolDTags.Exclude);for(var b=0;b<this.values.length;++b)this.values[b]==Exclude.ANY?(a.writeStartElement(CCNProtocolDTags.Any),a.writeEndElement()):a.writeElement(CCNProtocolDTags.Component,this.values[b]);a.writeEndElement()}};
 Exclude.prototype.to_uri=function(){if(null==this.values||0==this.values.length)return"";for(var a="",b=0;b<this.values.length;++b)0<b&&(a+=","),a=this.values[b]==Exclude.ANY?a+"*":a+Name.toEscapedString(this.values[b]);return a};
+Exclude.prototype.matches=function(a){for(var b=0;b<this.values.length;++b)if(this.values[b]==Exclude.ANY){var c=null;0<b&&(c=this.values[b-1]);var d,e=null;for(d=b+1;d<this.values.length;++d)if(this.values[d]!=Exclude.ANY){e=this.values[d];break}if(null!=e){if(null!=c){if(0<Exclude.compareComponents(a,c)&&0>Exclude.compareComponents(a,e))return!0}else if(0>Exclude.compareComponents(a,e))return!0;b=d-1}else if(null!=c){if(0<Exclude.compareComponents(a,c))return!0}else return!0}else if(DataUtils.arraysEqual(a,
+this.values[b]))return!0;return!1};Exclude.compareComponents=function(a,b){if(a.length<b.length)return-1;if(a.length>b.length)return 1;for(var c=0;c<a.length;++c){if(a[c]<b[c])return-1;if(a[c]>b[c])return 1}return 0};
 var Key=function(){},KeyLocatorType={KEY:1,CERTIFICATE:2,KEYNAME:3},KeyLocator=function(a,b){this.type=b;b==KeyLocatorType.KEYNAME?(3<LOG&&console.log("KeyLocator: SET KEYNAME"),this.keyName=a):b==KeyLocatorType.KEY?(3<LOG&&console.log("KeyLocator: SET KEY"),this.publicKey=a):b==KeyLocatorType.CERTIFICATE&&(3<LOG&&console.log("KeyLocator: SET CERTIFICATE"),this.certificate=a)};
 KeyLocator.prototype.from_ccnb=function(a){a.readStartElement(this.getElementLabel());if(a.peekStartElement(CCNProtocolDTags.Key)){try{this.publicKey=encodedKey=a.readBinaryElement(CCNProtocolDTags.Key),this.type=KeyLocatorType.KEY,4<LOG&&console.log("PUBLIC KEY FOUND: "+this.publicKey)}catch(b){throw Error("Cannot parse key: ",b);}if(null==this.publicKey)throw Error("Cannot parse key: ");}else if(a.peekStartElement(CCNProtocolDTags.Certificate)){try{this.certificate=encodedCert=a.readBinaryElement(CCNProtocolDTags.Certificate),
 this.type=KeyLocatorType.CERTIFICATE,4<LOG&&console.log("CERTIFICATE FOUND: "+this.certificate)}catch(c){throw Error("Cannot decode certificate: "+c);}if(null==this.certificate)throw Error("Cannot parse certificate! ");}else this.type=KeyLocatorType.KEYNAME,this.keyName=new KeyName,this.keyName.from_ccnb(a);a.readEndElement()};