PyNDN: Bug fixing and API unification
diff --git a/PyNDN/Data.py b/PyNDN/Data.py
index 99a3d07..5165d2c 100644
--- a/PyNDN/Data.py
+++ b/PyNDN/Data.py
@@ -19,6 +19,7 @@
 
 import ns.ndnSIM
 from Name import Name
+from SignedInfo import SignedInfo
 
 class DataError (Exception):
     pass
@@ -30,14 +31,14 @@
                  name = None, content = None, signed_info = None,
                  data = None):
         if data:
-            if type (data) is Data:
+            if isinstance (data, Data):
                 self._data = data._data
-            elif type (data) is ns.ndnSIM.ndn.ContentObject:
+            elif isinstance (data, ns.ndnSIM.ndn.Data):
                 self._data = data
             else:
                 raise TypeError ("Invalid type supplied for 'data' parameter [%s]" % type (data))
         else:
-            self._data = ns.ndnSIM.ndn.ContentObject ()
+            self._data = ns.ndnSIM.ndn.Data ()
 
             self.name = name
             self.content = content
@@ -88,9 +89,9 @@
             return object.__setattr__ (self, name, value)
 
         elif name == 'signedInfo':
-            if not value:
+            if value is None:
                 return
-            if type (value) is SignedInfo:
+            if isinstance (value, SignedInfo):
                 object.__setattr__ (self, name, value)
 
                 if value.timestamp:
@@ -103,18 +104,18 @@
             else:
                 raise TypeError ("signedInfo can be assigned either None or SignedInfo object, [%s] supplied" % type (value))
         elif name == "name":
-            if not value:
+            if value is None:
                 return self._data.SetName (ns.ndnSIM.ndn.Name ())
-            elif type (value) is Name:
+            elif isinstance (value, Name):
                 return self._data.SetName (value._name)
-            elif type (value) is ns.ndnSIM.ndn.Name:
+            elif isinstance (value, ns.ndnSIM.ndn.Name):
                 return self._data.SetName (value)
-            elif type (value) is str:
+            elif isinstance (value, str):
                 return self._data.SetName (ns.ndnSIM.ndn.Name (value))
             else:
                 raise ValueError ("Invalid name parameter")
         elif name == "content":
-            if not value:
+            if value is None:
                 pkt = ns.network.Packet ()
                 self._data.SetPayload (pkt)
             else:
@@ -125,27 +126,3 @@
 
     def __repr__(self):
         return "ndn.Data(%s)" % str (self._data)
-
-class SignedInfo (object):
-    def __init__(self, keyLocator = None, freshness = None, timestamp = None):
-
-        self.timestamp = timestamp
-        self.freshnessSeconds = freshness
-        self.keyLocator = keyLocator
-
-    def __repr__(self):
-        args = []
-
-        if self.keyLocator is not None:
-            args += ["keyLocator=%r" % self.keyLocator]
-        if self.freshnessSeconds is not None:
-            args += ["freshness=%r" % self.freshnessSeconds]
-        if self.timeStamp is not None:
-            args += ["timestamp=%r" % self.timestamp]
-
-        return "ndn.SignedInfo(%s)" % ", ".join(args)
-
-class ContentObject (Data):
-    """For backwards compatibility"""
-    pass
-
diff --git a/PyNDN/EventLoop.py b/PyNDN/EventLoop.py
new file mode 100644
index 0000000..93bd8e7
--- /dev/null
+++ b/PyNDN/EventLoop.py
@@ -0,0 +1,37 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+# 
+# Copyright (c) 2011-2013, Regents of the University of California
+#                          Alexander Afanasyev
+# 
+# GNU 3.0 license, See the LICENSE file for more information
+# 
+# Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+# 
+
+#
+# Based on PyCCN code, copyrighted and licensed as follows
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+# BSD license, See the COPYING file for more information
+# Written by: Derek Kulinski <takeda@takeda.tk>
+#             Jeff Burke <jburke@ucla.edu>
+#
+
+import ns.core
+
+class EventLoop (object):
+    """
+    Class to provide compatibility with real PyNDN implementation.
+    """
+    
+    def __init__ (self, *handlers):
+        pass
+    
+    def execute (self, event):
+        ns.core.Simulator.ScheduleNow (event)
+
+    def run (self):
+        pass
+
+    def stop (self):
+        pass
diff --git a/PyNDN/Face.py b/PyNDN/Face.py
index 6186569..3f76f5d 100644
--- a/PyNDN/Face.py
+++ b/PyNDN/Face.py
@@ -1,12 +1,12 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-# 
+#
 # Copyright (c) 2011-2013, Regents of the University of California
 #                          Alexander Afanasyev
-# 
+#
 # GNU 3.0 license, See the LICENSE file for more information
-# 
+#
 # Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
-# 
+#
 
 #
 # Based on PyCCN code, copyrighted and licensed as follows
@@ -22,6 +22,7 @@
 import ns.ndnSIM
 from Data import Data
 from Interest import Interest
+from Name import Name
 
 import functools
 
@@ -40,7 +41,7 @@
     def defer_verification (self, deferVerification = True):
         pass
 
-    def expressInterestSimple (self, name, onData, onTimeout, template = None):
+    def expressInterest (self, name, onData, onTimeout, template = None):
         """
         onData:    void <interest, name>
         onTimeout: void <interest>
@@ -55,7 +56,7 @@
             def __call__ (self, interest, data):
                 if self.onData:
                     return self.onData (Interest (interest=interest), Data (data = data))
-        
+
         class OnTimeoutConvert:
             def __init__ (self, onTimeout):
                 self.onTimeout = onTimeout
@@ -63,9 +64,9 @@
                 if self.onTimeout:
                     self.onTimeout (Interest (interest=interest))
 
-        self.ExpressInterest (interest, OnDataConvert (onData), OnTimeoutConvert (onTimeout))
+        self.ExpressInterest (interest._interest, OnDataConvert (onData), OnTimeoutConvert (onTimeout))
 
-    def setInterestFilterSimple (self, name, onInterest, flags = None):
+    def setInterestFilter (self, name, onInterest, flags = None):
         """
         onInterest: void <name, interest>
         """
@@ -77,27 +78,27 @@
                 if self.onInterest:
                     self.onInterest (Name (name = name), Interest (interest = interest))
 
+        if isinstance (name, Name):
+            name = name._name
+        elif isinstance (name, ns.ndnSIM.ndn.Name):
+            pass
+        else:
+            raise TypeError ("Wrong type for 'name' parameter [%s]" % type (name))
+
         self.SetInterestFilter (name, OnInterestConvert (onInterest))
 
     def clearInterestFilter (self, name):
-        if type (name) is Name:
-            self.ClearInterestFilter (name._name)
-        elif type (name) is ns.ndnSIM.ndn.Name:
-            self.ClearInterestFilter (name)
+        if isinstance (name, Name):
+            name = name._name
+        elif isinstance (name, ns.ndnSIM.ndn.Name):
+            pass
         else:
             raise TypeError ("Wrong type for 'name' parameter [%s]" % type (name))
 
+        self.ClearInterestFilter (name)
+
     def get (self, name, template = None, timeoutms = 3000):
         raise NotImplementedError ("NS-3 simulation cannot have syncrhonous operations")
 
     def put (self, data):
         self.Put (data)
-
-class EventLoop(object):
-    def execute (self, event):
-        ns.core.Simulator.ScheduleNow (event)
-
-    def run (self, timeoutMs):
-        ns.core.Simulator.Stop (ns.core.MilliSeconds (timeoutMs))
-        ns.core.Simulator.Run ()
-        ns.core.Simulator.Destroy ()
diff --git a/PyNDN/Interest.py b/PyNDN/Interest.py
index 571bc36..b4b5b9a 100644
--- a/PyNDN/Interest.py
+++ b/PyNDN/Interest.py
@@ -28,9 +28,9 @@
                  name = None, scope = None, interestLifetime = None,
                  interest = None):
         if interest:
-            if type (interest) is Interest:
+            if isinstance (interest, Interest):
                 self._interest = interest._interest
-            elif type (interest) is ns.ndnSIM.ndn.Interest:
+            elif isinstance (interest, ns.ndnSIM.ndn.Interest):
                 self._interest = interest
             else:
                 raise TypeError ("Invalid type supplied for 'interest' parameter [%s]" % type (interest))
@@ -66,27 +66,27 @@
             return object.__setattr__ (self, name, value)
 
         elif name == "name":
-            if not value:
+            if value is None:
                 return self._interest.SetName (ns.ndnSIM.ndn.Name ())
-            elif type (value) is Name:
+            elif isinstance (value, Name):
                 return self._interest.SetName (value._name)
-            elif type (value) is ns.ndnSIM.ndn.Name:
+            elif isinstance (value, ns.ndnSIM.ndn.Name):
                 return self._interest.SetName (value)
-            elif type (value) is str:
+            elif isinstance (value, str):
                 return self._interest.SetName (ns.ndnSIM.ndn.Name (value))
             else:
                 raise ValueError ("Invalid name parameter")
         elif name == "scope":
-            if not value:
+            if value is None:
                 return self._interest.SetScope (-1)
-            elif type (value) is int:
+            elif isinstance (value, int):
                 return self._interest.SetScope (value)
             else:
                 raise ValueError ("Scope parameter should be int, [%s] supplied" % type (value))
         elif name == "interestLifetime":
-            if not value:
+            if value is None:
                 return self._interest.SetInterestLifetime (ns.core.Time ())
-            elif type (value) is float or type (value) is int:
+            elif isinstance (value, float) or isinstance (value, int):
                 return self._interest.SetInterestLifetime (ns.core.Seconds (value))
             else:
                 raise ValueError ("interestLifetime parameter should be fload or int, [%s] supplied" % type (value))
diff --git a/PyNDN/Key.py b/PyNDN/Key.py
index b5c065b..2dc562a 100644
--- a/PyNDN/Key.py
+++ b/PyNDN/Key.py
@@ -21,7 +21,7 @@
 import ns.ndnSIM
 from Name import Name
 
-class Key(object):
+class Key (object):
     def __init__ (self):
         # self.publicKeyID = None # SHA256 hash
         self.fakeKey = None
@@ -81,18 +81,3 @@
         key = Key ()
         key.fakeKey = context
         return key
-
-
-class KeyLocator(object):
-    def __init__(self, keyName = None):
-        self.keyName = keyName
-
-    @staticmethod
-    def getDefaultKeyLocator():
-        context = ns.core.Simulator.GetContext ()
-        keyLocator = ns.ndnSIM.ndn.Name ()
-        keyLocator.\
-            append ("default-key").\
-            append (str (context))
-
-        return Name (keyLocator)
diff --git a/PyNDN/KeyLocator.py b/PyNDN/KeyLocator.py
new file mode 100644
index 0000000..331ae63
--- /dev/null
+++ b/PyNDN/KeyLocator.py
@@ -0,0 +1,36 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+# 
+# Copyright (c) 2011-2013, Regents of the University of California
+#                          Alexander Afanasyev
+# 
+# GNU 3.0 license, See the LICENSE file for more information
+# 
+# Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+# 
+
+#
+# Based on PyCCN code, copyrighted and licensed as follows
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+# BSD license, See the COPYING file for more information
+# Written by: Derek Kulinski <takeda@takeda.tk>
+#             Jeff Burke <jburke@ucla.edu>
+#
+
+import ns.core
+import ns.ndnSIM
+from Name import Name
+
+class KeyLocator (object):
+    def __init__(self, keyName = None):
+        self.keyName = keyName
+
+    @staticmethod
+    def getDefaultKeyLocator():
+        context = ns.core.Simulator.GetContext ()
+        keyLocator = ns.ndnSIM.ndn.Name ()
+        keyLocator.\
+            append ("default-key").\
+            append (str (context))
+
+        return Name (keyLocator)
diff --git a/PyNDN/Name.py b/PyNDN/Name.py
index 05c34b0..7729a25 100644
--- a/PyNDN/Name.py
+++ b/PyNDN/Name.py
@@ -19,16 +19,16 @@
 
 import ns.ndnSIM
 
-class Name ():
+class Name (object):
     _name = None
 
     def __init__ (self, 
                   value = None,
                   name = None):
         if name:
-            if type (name) is ns.ndnSIM.ndn.Name:
+            if isinstance (name, ns.ndnSIM.ndn.Name):
                 self._name = name
-            elif type (name) is Name:
+            elif isinstance (name, Name):
                 self._name = name._name
             else:
                 raise TypeError ("Incorrect type for 'name' parameter [%s]" % type (name))
@@ -44,6 +44,10 @@
 
     def toWire (self):
         return ns.ndnSIM.ndn.Wire.FromName (self._name)
+
+    def append (self, value):
+        self._name.append (value)
+        return self
     
     def __getattr__ (self, name):
         return self._name.__getattribute__ (name)
@@ -55,12 +59,12 @@
         return self._name.append (other)
 
     def __getitem__(self, key):
-        if type (key) is int:
+        if isinstance (key, int):
             if abs(key) < self._name.size ():
                 return self._name.get (key)
             else:
                 raise IndexError ("index out of range")
-        elif type (key) is slice:
+        elif isinstance (key, slice):
             name = ns.ndnSIM.ndn.Name ()
             for component in xrange (*key.indices (self.size ())):
                 name.append (self._name.get (component))
@@ -71,3 +75,5 @@
     def __repr__ (self):
         return "ndnSIM.Name('" + self._name.toUri () + "')"
 
+    def __str__ (self):
+        return self._name.toUri ()
diff --git a/PyNDN/SignedInfo.py b/PyNDN/SignedInfo.py
new file mode 100644
index 0000000..79c2f4f
--- /dev/null
+++ b/PyNDN/SignedInfo.py
@@ -0,0 +1,53 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+#                          Alexander Afanasyev
+#
+# GNU 3.0 license, See the LICENSE file for more information
+#
+# Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+#
+
+#
+# Based on PyCCN code, copyrighted and licensed as follows
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+# BSD license, See the COPYING file for more information
+# Written by: Derek Kulinski <takeda@takeda.tk>
+#             Jeff Burke <jburke@ucla.edu>
+#
+
+import utils
+
+class ContentType(utils.Enum):
+    _prefix = "ndn"
+
+CONTENT_DATA = ContentType.new_flag('CONTENT_DATA', 0x0C04C0)
+CONTENT_ENCR = ContentType.new_flag('CONTENT_ENCR', 0x10D091)
+CONTENT_GONE = ContentType.new_flag('CONTENT_GONE', 0x18E344)
+CONTENT_KEY  = ContentType.new_flag('CONTENT_KEY',  0x28463F)
+CONTENT_LINK = ContentType.new_flag('CONTENT_LINK', 0x2C834A)
+CONTENT_NACK = ContentType.new_flag('CONTENT_NACK', 0x34008A)
+
+class SignedInfo (object):
+    def __init__(self, keyLocator = None, freshness = None, timestamp = None, type = CONTENT_DATA):
+
+        self.timestamp = timestamp
+        self.freshnessSeconds = freshness
+        self.keyLocator = keyLocator
+        self.type = type
+
+    def __repr__(self):
+        args = []
+
+        if self.keyLocator is not None:
+            args += ["keyLocator=%r" % self.keyLocator]
+        if self.freshnessSeconds is not None:
+            args += ["freshness=%r" % self.freshnessSeconds]
+        if self.timeStamp is not None:
+            args += ["timestamp=%r" % self.timestamp]
+        if self.type != CONTENT_DATA:
+            args += ["type=%r" % self.type]
+
+        return "ndn.SignedInfo(%s)" % ", ".join(args)
+
diff --git a/PyNDN/__init__.py b/PyNDN/__init__.py
index 0c0e288..2054d49 100644
--- a/PyNDN/__init__.py
+++ b/PyNDN/__init__.py
@@ -1,12 +1,12 @@
 ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-# 
+#
 # Copyright (c) 2011-2013, Regents of the University of California
 #                          Alexander Afanasyev
-# 
+#
 # GNU 3.0 license, See the LICENSE file for more information
-# 
+#
 # Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
-# 
+#
 
 #
 # Based on PyCCN code, copyrighted and licensed as follows
@@ -17,7 +17,7 @@
 #             Jeff Burke <jburke@ucla.edu>
 #
 
-__all__ = ['Face', 'Name', 'Interest', 'Data', 'Key', 'ContentObject']
+__all__ = ['Face', 'Name', 'Interest', 'Data', 'Key', 'EventLoop']
 
 VERSION = 0.3
 NDNSIM = True
@@ -25,12 +25,22 @@
 import sys as _sys
 
 try:
-    from Face import Face, EventLoop
+    from Face import Face
     from Name import Name
     from Interest import Interest
-    from Data import Data, ContentObject, SignedInfo
+    from Data import Data
     from Key import Key
 
+    from EventLoop import EventLoop
+    from KeyLocator import KeyLocator
+    from SignedInfo import SignedInfo, CONTENT_DATA, CONTENT_ENCR, CONTENT_GONE, CONTENT_KEY, CONTENT_LINK, CONTENT_NACK
+    # no signature
+
+    # no NameCrypto
+    # no LocalPrefixDiscovery
+
+    import nre
+
 except ImportError:
     del _sys.modules[__name__]
     raise
diff --git a/PyNDN/impl/segmenting.py b/PyNDN/impl/segmenting.py
index fb2d253..d58b200 100644
--- a/PyNDN/impl/segmenting.py
+++ b/PyNDN/impl/segmenting.py
@@ -32,7 +32,7 @@
         name = self.name + ndn.Name.num2seg(segment)
         self.signed_info.finalBlockID = ndn.Name.num2seg(segments - 1)
 
-        co = ndn.ContentObject(name = name, content = chunk, signed_info = self.signed_info)
+        co = ndn.Data(name = name, content = chunk, signed_info = self.signed_info)
         co.sign(self.key)
 
         return co
diff --git a/PyNDN/nre.py b/PyNDN/nre.py
new file mode 100644
index 0000000..669a712
--- /dev/null
+++ b/PyNDN/nre.py
@@ -0,0 +1,631 @@
+# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (c) 2013, Regents of the University of California
+#                     Yingdi Yu, Alexander Afanasyev
+#
+# BSD license, See the doc/LICENSE file for more information
+#
+# Author: Yingdi Yu <yingdi@cs.ucla.edu>
+#         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+#
+
+import sys
+import re
+import logging
+from Name import Name
+
+_LOG = logging.getLogger ("ndn.nre")
+
+class RegexError(Exception):
+    def __init__(self, msg):
+        self.msg = msg
+    def __str__(self):
+        return self.msg
+
+class BaseMatcher(object):
+    def __init__(self, expr, backRef, exact=True):
+        _LOG.debug(self.__class__.__name__ + ".Constructor")
+        self.expr    = expr
+        self.backRef = backRef
+        self.exact   = exact
+        self.matchResult = []
+        self.matcherList = []
+
+    def match(self, name, offset, len):
+        _LOG.debug(self.__class__.__name__ + ".match(): " + "expr: " + self.expr + " offset: " + str(offset) + " length: " + str(len))
+        self.matchResult = []
+
+        if self._recursiveMatch(0, name, offset, len):
+            for i in range(offset,  offset + len):
+                self.matchResult.append(name[i])
+            return True
+        else:
+            return False
+
+    def _recursiveMatch(self, mId, name, offset, length):
+        _LOG.debug(self.__class__.__name__ + "._recursiveMatch(): " + self.expr)
+        _LOG.debug("mId: " + str(mId) + " name: " +  str(name) + " offset: " + str(offset) + " length: " + str(length) + " matcherListSize: " + str(len(self.matcherList)))
+        tried = 0
+
+        if mId >= len(self.matcherList) :
+            if length != 0 :
+                _LOG.debug("Fail " + self.__class__.__name__ + "._recursiveMatch(): no more matcher, but more components")
+                return False
+            else:
+                _LOG.debug("Succeed " + self.__class__.__name__ + "._recursiveMatch(): no more matcher, no more components")
+                return True
+
+        matcher = self.matcherList[mId]
+
+        while tried <= length:
+            if matcher.match(name, offset, tried) and self._recursiveMatch(mId + 1, name, offset + tried, length - tried) :
+                return True
+            _LOG.debug(self.__class__.__name__ + " expr: " + self.expr + " mId: " + str(mId) + " tried: " + str(tried) + " length: " + str(length))
+            tried += 1
+
+        return False
+
+
+    def aggressiveMatch(self, name, offset, len):
+        _LOG.debug(self.__class__.__name__ + ".aggressiveMatch(): " + "expr: " + self.expr + " offset: " + str(offset) + " length: " + str(len))
+        self.matchResult = []
+
+        if self._aRecursiveMatch(0, name, offset, len):
+            for i in range(offset,  offset + len):
+                self.matchResult.append(name[i])
+            return True
+        else:
+            return False
+
+    def _aRecursiveMatch(self, mId, name, offset, length):
+        _LOG.debug(self.__class__.__name__ + "._aRecursiveMatch(): " + self.expr)
+        _LOG.debug("mId: " + str(mId) + " name: " +  str(name) + " offset: " + str(offset) + " length: " + str(length) + " matcherListSize: " + str(len(self.matcherList)))
+
+        tried = length
+
+        if mId >= len(self.matcherList) :
+            if length != 0 :
+                _LOG.debug("Fail " + self.__class__.__name__ + "._recursiveMatch(): no more matcher, but more components")
+                return False
+            else:
+                _LOG.debug("Succeed " + self.__class__.__name__ + "._recursiveMatch(): no more matcher, no more components")
+                return True
+
+        matcher = self.matcherList[mId]
+
+        while tried >= 0:
+            if matcher.aggressiveMatch(name, offset, tried) and self._aRecursiveMatch(mId + 1, name, offset + tried, length - tried):
+                return True
+            _LOG.debug(self.__class__.__name__ + " expr: " + self.expr + " mId: " + str(mId) + " tried: " + str(tried) + " length: " + str(length))
+            tried -= 1
+
+        return False
+
+
+class ComponentMatcher(BaseMatcher):
+    def __init__(self, expr, backRef, exact=True):
+        _LOG.debug(self.__class__.__name__ + ".Constructor")
+        _LOG.debug("expr " + expr)
+
+        super(ComponentMatcher, self).__init__(expr, backRef, exact)
+
+        pattern = re.compile(self.expr)
+        self.pseudoBackRefMatcher = []
+        for i in range(0, pattern.groups):
+            pseudoMatcher = BaseMatcher("", self.backRef)
+            self.pseudoBackRefMatcher.append(pseudoMatcher)
+            self.backRef.append(pseudoMatcher)
+
+    def _appendBackRef(self, res):
+        if res and 0 < len(res.groups()):
+
+            group = res.groups()
+            for i in range(0, len(group)):
+                self.pseudoBackRefMatcher[i].matchResult = []
+                self.pseudoBackRefMatcher[i].matchResult.append(group[i])
+
+    def match(self, name, offset, len):
+        _LOG.debug(self.__class__.__name__ + ".match(): " + self.expr)
+        _LOG.debug("Name " + str(name) + " offset " +  str(offset) + " len " +str(len))
+
+        self.matchResult = []
+
+        if "" == self.expr:
+            res = self.matchResult.append(name[offset])
+            self._appendBackRef(res)
+            _LOG.debug("Succeed " + self.__class__.__name__ + ".match() ")
+            return True
+
+        matcher = re.compile(self.expr)
+        if self.exact:
+            res = matcher.match(name[offset])
+            if res:
+                self._appendBackRef(res)
+                self.matchResult.append(name[offset])
+                _LOG.debug("Succeed " + self.__class__.__name__ + ".match() ")
+                return True
+        else:
+            res = matcher.search(name[offset])
+            if res:
+                self._appendBackRef(res)
+                self.matchResult.append(name[offset])
+                return True
+
+        return False
+
+    def aggressiveMatch(self, name, offset, len):
+        return self.match(name, offset, len)
+
+
+class ComponentSetMatcher(BaseMatcher):
+    def __init__(self, expr, backRef, exact=True):
+        _LOG.debug(self.__class__.__name__ + ".Constructor")
+
+        errMsg = "Error: ComponentSetMatcher.Constructor: "
+        self.include = True
+
+        super(ComponentSetMatcher, self).__init__(expr, backRef, exact)
+
+        if '<' == self.expr[0]:
+            self._compileSingleComponent()
+        elif '[' == self.expr[0]:
+            lastIndex = len(self.expr) - 1
+            if ']' != self.expr[lastIndex]:
+                raise RegexError(errMsg + " No matched ']' " + self.expr)
+            if '^' == self.expr[1]:
+                self.include = False
+
+                self._compileMultipleComponents(2, lastIndex)
+            else:
+                self._compileMultipleComponents(1, lastIndex)
+
+
+    def _compileSingleComponent(self):
+        _LOG.debug(self.__class__.__name__ + "._compileSingleComponent")
+
+        errMsg = "Error: ComponentSetMatcher.CompileSingleComponent(): "
+
+        end = self._extractComponent(1)
+
+        if len(self.expr) != end:
+            raise RegexError(errMsg + "out of bound " + self.expr)
+        else:
+            self.matcherList.append(ComponentMatcher(self.expr[1:end-1], self.backRef))
+
+    def _compileMultipleComponents(self, start, lastIndex):
+        _LOG.debug(self.__class__.__name__ + "._compileMultipleComponents")
+
+        errMsg = "Error: ComponentSetMatcher.CompileMultipleComponents(): "
+
+        index = start
+        tmp_index = start
+
+        while index < lastIndex:
+            if '<' != self.expr[index]:
+                raise RegexError(errMsg + "Component expr error " + self.expr)
+            tmp_index = index + 1
+            index = self._extractComponent(tmp_index)
+            self.matcherList.append(ComponentMatcher(self.expr[tmp_index:index-1], self.backRef))
+
+        if index != lastIndex:
+           raise RegexError(errMsg + "Not sufficient expr to parse " + self.expr)
+
+    def _extractComponent(self, index):
+        _LOG.debug(self.__class__.__name__ + "._extractComponent")
+        lcount = 1
+        rcount = 0
+
+        while lcount > rcount :
+            if len(self.expr) == index:
+                break
+            elif '<' == self.expr[index]:
+                lcount += 1
+            elif '>' == self.expr[index]:
+                rcount += 1
+
+            index += 1
+
+        return index
+
+    def match(self, name, offset, len):
+        _LOG.debug(self.__class__.__name__ + ".match(): " + self.expr)
+
+        self.matchResult = []
+
+        matched = False
+
+        if 1 != len:
+            return False
+
+        for matcher in self.matcherList:
+            res = matcher.match(name, offset, len)
+            if True == res:
+                matched = True
+                break
+
+        if(matched if self.include else (not matched)):
+            self.matchResult.append(name[offset])
+            return True
+        else:
+            return False
+
+    def aggressiveMatch(self, name, offset, len):
+        return self.match(name, offset, len)
+
+class BackRefMatcher(BaseMatcher):
+    def __init__(self, expr, backRef, exact=True):
+        _LOG.debug (self.__class__.__name__ + ".Constructor")
+        super(BackRefMatcher, self).__init__(expr, backRef, exact)
+
+        errMsg = "Error: BackRefMatcher Constructor: "
+
+        _LOG.debug ("expr: " +  self.expr);
+        _LOG.debug ("backRefManager " + str(self.backRef) + " size: " + str(len(self.backRef)))
+
+        lastIndex = len(self.expr) - 1
+
+        if '(' == self.expr[0] and ')' == self.expr[lastIndex]:
+            self.backRef.append(self)
+            self.matcherList.append(PatternListMatcher(self.expr[1:lastIndex], self.backRef, self.exact))
+        else:
+            raise RegexError(errMsg + " Unrecognoized format " + self.expr)
+
+
+class PatternListMatcher(BaseMatcher):
+    def __init__(self, expr, backRef, exact=True):
+        _LOG.debug(self.__class__.__name__ + ".Constructor")
+        super(PatternListMatcher, self).__init__(expr, backRef, exact)
+        _LOG.debug("expr: " + self.expr)
+
+        exprSize = len(self.expr)
+        index = 0
+        subHead = index
+
+        while index < exprSize:
+            subHead = index
+            (r_res, r_index) = self._extractPattern(subHead, index)
+            index = r_index
+            if not r_res:
+                raise RegexError("Fail to create PatternListMatcher")
+
+
+    def _extractPattern(self, index, next):
+        _LOG.debug(self.__class__.__name__ + "._extractPattern")
+
+        errMsg = "Error: PatternListMatcher._extractPattern: "
+
+        start = index
+        End = index
+        indicator = index
+
+        _LOG.debug ("expr: " + self.expr + " index: " + str(index))
+
+        if '(' == self.expr[index]:
+            index += 1
+            index = self._extractSubPattern('(', ')', index)
+            indicator = index
+            end = self._extractRepetition(index)
+            if indicator == end:
+                self.matcherList.append(BackRefMatcher(self.expr[start:end], self.backRef, self.exact))
+            else:
+                self.matcherList.append(RepeatMatcher(self.expr[start:end], self.backRef, indicator-start, self.exact))
+        elif '<' == self.expr[index]:
+            index += 1
+            index = self._extractSubPattern('<', '>', index)
+            indicator = index
+            end = self._extractRepetition(index)
+            self.matcherList.append(RepeatMatcher(self.expr[start:end], self.backRef, indicator-start, self.exact))
+            _LOG.debug("start: " + str(start) + " end: " + str(end) + " indicator: " + str(indicator))
+        elif '[' == self.expr[index]:
+            index += 1
+            index = self._extractSubPattern('[', ']', index)
+            indicator = index
+            end = self._extractRepetition(index)
+            self.matcherList.append(RepeatMatcher(self.expr[start:end], self.backRef, indicator-start, self.exact))
+            _LOG.debug("start: " + str(start) + " end: " + str(end) + " indicator: " + str(indicator))
+        else:
+            raise RegexError(errMsg +"unexpected syntax")
+
+
+
+        return (True, end)
+
+    def _extractSubPattern(self, left, right, index):
+        _LOG.debug(self.__class__.__name__ + "._extractSubPattern")
+
+        lcount = 1
+        rcount = 0
+
+        while lcount > rcount:
+            if index >= len(self.expr):
+                raise RegexError("Error: parenthesis mismatch")
+            if left == self.expr[index]:
+                lcount += 1
+            if right == self.expr[index]:
+                rcount += 1
+            index += 1
+
+        return index
+
+    def _extractRepetition(self, index):
+        _LOG.debug(self.__class__.__name__ + "._extractRepetition")
+
+        exprSize = len(self.expr)
+
+        _LOG.debug("expr: " + self.expr + " index: " + str(index))
+
+        errMsg = "Error: PatternListMatcher._extractRepetition: "
+
+        if index == exprSize:
+            return index
+
+        if '+' == self.expr[index] or '?' == self.expr[index] or '*' == self.expr[index] :
+            index += 1
+            return index
+
+        if '{' == self.expr[index]:
+            while '}' != self.expr[index]:
+                index += 1
+                if index == exprSize:
+                    break
+            if index == exprSize:
+                raise RegexError(errMsg + "Missing right brace bracket")
+            else:
+                index += 1
+                return index
+        else:
+            _LOG.debug ("return index: " + str(index))
+            return index
+
+class RepeatMatcher(BaseMatcher):
+    def __init__(self, expr, backRef, indicator, exact=True):
+        _LOG.debug(self.__class__.__name__ + ".Constructor")
+        _LOG.debug("expr: " + expr);
+        super(RepeatMatcher, self).__init__(expr, backRef, exact)
+        self.indicator = indicator
+        if '(' == self.expr[0]:
+            self.matcherList.append(BackRefMatcher(self.expr[0:self.indicator], self.backRef))
+        else:
+            self.matcherList.append(ComponentSetMatcher(self.expr[0:self.indicator], self.backRef))
+
+        self._parseRepetition()
+        _LOG.debug("repeatMin: " + str(self.repeatMin) + " repeatMax: " + str(self.repeatMax))
+
+    def _parseRepetition(self):
+        _LOG.debug(self.__class__.__name__ + "._parseRepetition")
+
+        errMsg = "Error: RepeatMatcher._parseRepetition(): ";
+
+        exprSize = len(self.expr)
+        intMax = sys.maxint
+
+        if exprSize == self.indicator:
+            self.repeatMin = 1
+            self.repeatMax = 1
+            return
+        else:
+            if exprSize == (self.indicator + 1):
+                if '?' == self.expr[self.indicator]:
+                    self.repeatMin = 0
+                    self.repeatMax = 1
+                if '+' == self.expr[self.indicator]:
+                    self.repeatMin = 1
+                    self.repeatMax = intMax
+                if '*' == self.expr[self.indicator]:
+                    self.repeatMin = 0
+                    self.repeatMax = intMax
+                return
+            else:
+                repeatStruct = self.expr[self.indicator:exprSize]
+                min = 0
+                max = 0
+
+        if re.match('{[0-9]+,[0-9]+}$', repeatStruct):
+            repeats = repeatStruct[1:-1].split(',')
+            min = int(repeats[0])
+            max = int(repeats[1])
+        elif re.match('{[0-9]+,}$', repeatStruct):
+            repeats = repeatStruct[1:-1].split(',')
+            min = int(repeats[0])
+            max = intMax
+        elif re.match('{,[0-9]+}$', repeatStruct):
+            repeats = repeatStruct[1:-1].split(',')
+            min = 0
+            max = int(repeats[1])
+        elif re.match('{[0-9]+}$', repeatStruct):
+            min = int(repeatStruct[1:- 1])
+            max = min;
+        else:
+            raise RegexError(errMsg + "Unrecognized format "+ self.expr);
+
+        if min > intMax or max > intMax or min > max:
+            raise RegexError(errMsg + "Wrong number " + self.expr);
+
+        self.repeatMin = min
+        self.repeatMax = max
+
+    def match(self, name, offset, len):
+        _LOG.debug(self.__class__.__name__ + ".match(): " + "expr: " + self.expr + " offset: " + str(offset) + " len: " + str(len) + " repeatMin: " + str(self.repeatMin))
+        self.matchResult = []
+
+        if 0 == self.repeatMin:
+            if 0 == len:
+                return True
+
+        if self._recursiveMatch(0, name, offset, len):
+            for i in range(offset, offset+len):
+                self.matchResult.append(name[i])
+            return True
+        else:
+            return False
+
+    def _recursiveMatch(self, repeat, name, offset, len):
+        _LOG.debug (self.__class__.__name__ + "._recursiveMatch()" + " repeat: " + str(repeat) + " offset: " + str(offset) + " len: " + str(len) + " rMin: " + str(self.repeatMin) + " rMax: " + str(self.repeatMax))
+        tried = 0
+        matcher = self.matcherList[0]
+
+        if 0 < len and repeat >= self.repeatMax:
+            _LOG.debug("Match Fail: Reach m_repeatMax && More components")
+            return False
+
+        if 0 == len and repeat < self.repeatMin:
+            _LOG.debug("Match Fail: No more components && have NOT reached m_repeatMin " + str(len) + ", " + str(self.repeatMin))
+            return False
+
+        if 0 == len and repeat >= self.repeatMin:
+            _LOG.debug("Match Succeed: No more components && reach m_repeatMin")
+            return True
+
+        while tried <= len:
+            _LOG.debug("Attempt tried: " + str(tried))
+
+            if matcher.match(name, offset, tried) and self._recursiveMatch(repeat + 1, name, offset + tried, len - tried):
+                return True;
+            _LOG.debug("Failed at tried: " + str(tried));
+            tried += 1
+
+        return False
+
+
+    def aggressiveMatch(self, name, offset, len):
+        _LOG.debug(self.__class__.__name__ + ".aggressiveMatch(): " + "expr: " + self.expr + " offset: " + str(offset) + " len: " + str(len) + " repeatMin: " + str(self.repeatMin))
+        self.matchResult = []
+
+        if 0 == self.repeatMin:
+            if 0 == len:
+                return True
+
+        if self._aRecursiveMatch(0, name, offset, len):
+            for i in range(offset, offset+len):
+                self.matchResult.append(name[i])
+            return True
+        else:
+            return False
+
+    def _aRecursiveMatch(self, repeat, name, offset, len):
+        _LOG.debug (self.__class__.__name__ + "._aRecursiveMatch()" + " repeat: " + str(repeat) + " offset: " + str(offset) + " len: " + str(len) + " rMin: " + str(self.repeatMin) + " rMax: " + str(self.repeatMax))
+        tried = len
+        matcher = self.matcherList[0]
+
+        if 0 < len and repeat >= self.repeatMax:
+            _LOG.debug("Match Fail: Reach m_repeatMax && More components")
+            return False
+
+        if 0 == len and repeat < self.repeatMin:
+            _LOG.debug("Match Fail: No more components && have NOT reached m_repeatMin " + str(len) + ", " + str(self.repeatMin))
+            return False
+
+        if 0 == len and repeat >= self.repeatMin:
+            _LOG.debug("Match Succeed: No more components && reach m_repeatMin")
+            return True
+
+        while tried >= 0:
+            _LOG.debug("Attempt tried: " + str(tried))
+
+            if matcher.aggressiveMatch(name, offset, tried) and self._aRecursiveMatch(repeat + 1, name, offset + tried, len - tried):
+                return True;
+            _LOG.debug("Failed at tried: " + str(tried));
+            tried -= 1
+
+        return False
+
+
+
+class RegexMatcher(BaseMatcher):
+    def __init__(self, expr, exact=True):
+        _LOG.debug(self.__class__.__name__ + ".Constructor")
+        super(RegexMatcher, self).__init__(expr, None, exact)
+
+        self.backRef = []
+        self.second_backRef = []
+
+        self.secondaryMatcher = None
+
+
+        errMsg = "Error: RegexTopMatcher Constructor: "
+        tmp_expr = self.expr
+
+        if '$' != tmp_expr[-1]:
+            tmp_expr = tmp_expr + "<.*>*";
+        else:
+            tmp_expr = tmp_expr[0:-1]
+
+        if '^' != tmp_expr[0]:
+            self.secondaryMatcher = PatternListMatcher("<.*>*" + tmp_expr, self.second_backRef, self.exact)
+        else:
+            tmp_expr = tmp_expr[1:]
+
+        _LOG.debug ("reconstructed expr " + tmp_expr);
+
+        self.primaryMatcher = PatternListMatcher(tmp_expr, self.backRef, self.exact)
+
+
+
+    def firstMatcher():
+        return None
+
+    def matchName(self, name):
+        _LOG.debug(self.__class__.__name__ + ".matchName")
+
+        self.secondaryUsed = False
+
+        res = self.primaryMatcher.match(name, 0, len(name))
+        self.matchResult += self.primaryMatcher.matchResult
+        if False == res and None != self.secondaryMatcher:
+            res = self.secondaryMatcher.match(name, 0, len(name))
+            self.matchResult += self.secondaryMatcher.matchResult
+            self.secondaryUsed = True
+        return res
+
+    def extract(self, rule):
+        _LOG.debug(self.__class__.__name__ + ".extract")
+
+        if not re.match('(\\\\[0-9]+)+$', rule):
+            raise RegexError("Wrong format of rule")
+
+        refs = rule.split('\\')
+        refs.pop(0)
+
+        backRef = self.backRef
+        if self.secondaryUsed:
+            backRef = self.second_backRef
+
+        result = []
+        for index in refs:
+            i = int(index) - 1
+
+            if len(backRef) <= i or 0 > i:
+                raise RegexError("Wrong back reference number!")
+
+            result += backRef[i].matchResult
+
+        return result
+
+    def matchN(self, name):
+        _LOG.debug(self.__class__.__name__ + ".matchN")
+
+        self.secondaryUsed = False
+
+        res = self.primaryMatcher.aggressiveMatch(name, 0, len(name))
+        self.matchResult += self.primaryMatcher.matchResult
+        if False == res and None != self.secondaryMatcher:
+            res = self.secondaryMatcher.aggressiveMatch(name, 0, len(name))
+            self.matchResult += self.secondaryMatcher.matchResult
+            self.secondaryUsed = True
+        return res
+
+    def expand (self, rule):
+        return self.extract (rule)
+
+def match (pattern, name, flags=0):
+    """
+    If zero or more characters at the beginning of string match the regular expression pattern, return a corresponding matches as a list. Return None if the string does not match the pattern.
+"""
+    if not isinstance (name, Name):
+        raise TypeError ("name is not ndn.Name type")
+
+    m = RegexMatcher (pattern)
+    res = m.matchN (Name (name))
+    if not res:
+        return None
+    return m
diff --git a/PyNDN/utils.py b/PyNDN/utils.py
index 7cfe514..555ce80 100644
--- a/PyNDN/utils.py
+++ b/PyNDN/utils.py
@@ -96,3 +96,38 @@
     inttime = int(value * 4096 + 0.5)
     bintime = struct.pack("!Q", inttime)
     return bintime.lstrip(b'\x00')
+
+class Const (object):
+    def __init__ (self, obj):
+        object.__setattr__ (self, "__internal_object", obj)
+        object.__setattr__ (self, "__bases__", type(obj))
+
+    def __getattribute__ (self, name):
+        if name != "__bases__":
+            return object.__getattribute__ (self, "__internal_object").__getattribute__ (name)
+        else:
+            return object.__getattribute__ (self, name)
+
+    def __getitem__(self, key):
+        return object.__getattribute__ (self, "__internal_object").__getitem__ (key)
+
+    def __setattr__ (self, name, value):
+        raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))
+
+    def __repr__ (self):
+        return "const %s" % object.__getattribute__ (self, "__internal_object").__repr__ ()
+
+    def __str__(self):
+       return object.__getattribute__ (self, "__internal_object").__str__ ()
+
+    def __add__(self, other):
+        raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))
+
+    def __delattr__ (self, name, value):
+        raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))
+
+    def __setitem__(self, key, value):
+        raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))
+
+    def __delitem__(self, key):
+        raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))